1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3
4#include <linux/etherdevice.h>
5#include <linux/inetdevice.h>
6#include <net/netevent.h>
7#include <linux/idr.h>
8#include <net/dst_metadata.h>
9#include <net/arp.h>
10
11#include "cmsg.h"
12#include "main.h"
13#include "../nfp_net_repr.h"
14#include "../nfp_net.h"
15
16#define NFP_FL_MAX_ROUTES 32
17
18#define NFP_TUN_PRE_TUN_RULE_LIMIT 32
19#define NFP_TUN_PRE_TUN_RULE_DEL BIT(0)
20#define NFP_TUN_PRE_TUN_IDX_BIT BIT(3)
21#define NFP_TUN_PRE_TUN_IPV6_BIT BIT(7)
22
23/**
24 * struct nfp_tun_pre_tun_rule - rule matched before decap
25 * @flags: options for the rule offset
26 * @port_idx: index of destination MAC address for the rule
27 * @vlan_tci: VLAN info associated with MAC
28 * @host_ctx_id: stats context of rule to update
29 */
30struct nfp_tun_pre_tun_rule {
31 __be32 flags;
32 __be16 port_idx;
33 __be16 vlan_tci;
34 __be32 host_ctx_id;
35};
36
37/**
38 * struct nfp_tun_active_tuns - periodic message of active tunnels
39 * @seq: sequence number of the message
40 * @count: number of tunnels report in message
41 * @flags: options part of the request
42 * @tun_info.ipv4: dest IPv4 address of active route
43 * @tun_info.egress_port: port the encapsulated packet egressed
44 * @tun_info.extra: reserved for future use
45 * @tun_info: tunnels that have sent traffic in reported period
46 */
47struct nfp_tun_active_tuns {
48 __be32 seq;
49 __be32 count;
50 __be32 flags;
51 struct route_ip_info {
52 __be32 ipv4;
53 __be32 egress_port;
54 __be32 extra[2];
55 } tun_info[];
56};
57
58/**
59 * struct nfp_tun_active_tuns_v6 - periodic message of active IPv6 tunnels
60 * @seq: sequence number of the message
61 * @count: number of tunnels report in message
62 * @flags: options part of the request
63 * @tun_info.ipv6: dest IPv6 address of active route
64 * @tun_info.egress_port: port the encapsulated packet egressed
65 * @tun_info.extra: reserved for future use
66 * @tun_info: tunnels that have sent traffic in reported period
67 */
68struct nfp_tun_active_tuns_v6 {
69 __be32 seq;
70 __be32 count;
71 __be32 flags;
72 struct route_ip_info_v6 {
73 struct in6_addr ipv6;
74 __be32 egress_port;
75 __be32 extra[2];
76 } tun_info[];
77};
78
79/**
80 * struct nfp_tun_req_route_ipv4 - NFP requests a route/neighbour lookup
81 * @ingress_port: ingress port of packet that signalled request
82 * @ipv4_addr: destination ipv4 address for route
83 * @reserved: reserved for future use
84 */
85struct nfp_tun_req_route_ipv4 {
86 __be32 ingress_port;
87 __be32 ipv4_addr;
88 __be32 reserved[2];
89};
90
91/**
92 * struct nfp_tun_req_route_ipv6 - NFP requests an IPv6 route/neighbour lookup
93 * @ingress_port: ingress port of packet that signalled request
94 * @ipv6_addr: destination ipv6 address for route
95 */
96struct nfp_tun_req_route_ipv6 {
97 __be32 ingress_port;
98 struct in6_addr ipv6_addr;
99};
100
101/**
102 * struct nfp_offloaded_route - routes that are offloaded to the NFP
103 * @list: list pointer
104 * @ip_add: destination of route - can be IPv4 or IPv6
105 */
106struct nfp_offloaded_route {
107 struct list_head list;
108 u8 ip_add[];
109};
110
111#define NFP_FL_IPV4_ADDRS_MAX 32
112
113/**
114 * struct nfp_tun_ipv4_addr - set the IP address list on the NFP
115 * @count: number of IPs populated in the array
116 * @ipv4_addr: array of IPV4_ADDRS_MAX 32 bit IPv4 addresses
117 */
118struct nfp_tun_ipv4_addr {
119 __be32 count;
120 __be32 ipv4_addr[NFP_FL_IPV4_ADDRS_MAX];
121};
122
123/**
124 * struct nfp_ipv4_addr_entry - cached IPv4 addresses
125 * @ipv4_addr: IP address
126 * @ref_count: number of rules currently using this IP
127 * @list: list pointer
128 */
129struct nfp_ipv4_addr_entry {
130 __be32 ipv4_addr;
131 int ref_count;
132 struct list_head list;
133};
134
135#define NFP_FL_IPV6_ADDRS_MAX 4
136
137/**
138 * struct nfp_tun_ipv6_addr - set the IP address list on the NFP
139 * @count: number of IPs populated in the array
140 * @ipv6_addr: array of IPV6_ADDRS_MAX 128 bit IPv6 addresses
141 */
142struct nfp_tun_ipv6_addr {
143 __be32 count;
144 struct in6_addr ipv6_addr[NFP_FL_IPV6_ADDRS_MAX];
145};
146
147#define NFP_TUN_MAC_OFFLOAD_DEL_FLAG 0x2
148
149/**
150 * struct nfp_tun_mac_addr_offload - configure MAC address of tunnel EP on NFP
151 * @flags: MAC address offload options
152 * @count: number of MAC addresses in the message (should be 1)
153 * @index: index of MAC address in the lookup table
154 * @addr: interface MAC address
155 */
156struct nfp_tun_mac_addr_offload {
157 __be16 flags;
158 __be16 count;
159 __be16 index;
160 u8 addr[ETH_ALEN];
161};
162
163/**
164 * struct nfp_neigh_update_work - update neighbour information to nfp
165 * @work: Work queue for writing neigh to the nfp
166 * @n: neighbour entry
167 * @app: Back pointer to app
168 */
169struct nfp_neigh_update_work {
170 struct work_struct work;
171 struct neighbour *n;
172 struct nfp_app *app;
173};
174
175enum nfp_flower_mac_offload_cmd {
176 NFP_TUNNEL_MAC_OFFLOAD_ADD = 0,
177 NFP_TUNNEL_MAC_OFFLOAD_DEL = 1,
178 NFP_TUNNEL_MAC_OFFLOAD_MOD = 2,
179};
180
181#define NFP_MAX_MAC_INDEX 0xff
182
183/**
184 * struct nfp_tun_offloaded_mac - hashtable entry for an offloaded MAC
185 * @ht_node: Hashtable entry
186 * @addr: Offloaded MAC address
187 * @index: Offloaded index for given MAC address
188 * @ref_count: Number of devs using this MAC address
189 * @repr_list: List of reprs sharing this MAC address
190 * @bridge_count: Number of bridge/internal devs with MAC
191 */
192struct nfp_tun_offloaded_mac {
193 struct rhash_head ht_node;
194 u8 addr[ETH_ALEN];
195 u16 index;
196 int ref_count;
197 struct list_head repr_list;
198 int bridge_count;
199};
200
201static const struct rhashtable_params offloaded_macs_params = {
202 .key_offset = offsetof(struct nfp_tun_offloaded_mac, addr),
203 .head_offset = offsetof(struct nfp_tun_offloaded_mac, ht_node),
204 .key_len = ETH_ALEN,
205 .automatic_shrinking = true,
206};
207
208void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
209{
210 struct nfp_tun_active_tuns *payload;
211 struct net_device *netdev;
212 int count, i, pay_len;
213 struct neighbour *n;
214 __be32 ipv4_addr;
215 u32 port;
216
217 payload = nfp_flower_cmsg_get_data(skb);
218 count = be32_to_cpu(payload->count);
219 if (count > NFP_FL_MAX_ROUTES) {
220 nfp_flower_cmsg_warn(app, "Tunnel keep-alive request exceeds max routes.\n");
221 return;
222 }
223
224 pay_len = nfp_flower_cmsg_get_data_len(skb);
225 if (pay_len != struct_size(payload, tun_info, count)) {
226 nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
227 return;
228 }
229
230 rcu_read_lock();
231 for (i = 0; i < count; i++) {
232 ipv4_addr = payload->tun_info[i].ipv4;
233 port = be32_to_cpu(payload->tun_info[i].egress_port);
234 netdev = nfp_app_dev_get(app, id: port, NULL);
235 if (!netdev)
236 continue;
237
238 n = neigh_lookup(tbl: &arp_tbl, pkey: &ipv4_addr, dev: netdev);
239 if (!n)
240 continue;
241
242 /* Update the used timestamp of neighbour */
243 neigh_event_send(neigh: n, NULL);
244 neigh_release(neigh: n);
245 }
246 rcu_read_unlock();
247}
248
249void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
250{
251#if IS_ENABLED(CONFIG_IPV6)
252 struct nfp_tun_active_tuns_v6 *payload;
253 struct net_device *netdev;
254 int count, i, pay_len;
255 struct neighbour *n;
256 void *ipv6_add;
257 u32 port;
258
259 payload = nfp_flower_cmsg_get_data(skb);
260 count = be32_to_cpu(payload->count);
261 if (count > NFP_FL_IPV6_ADDRS_MAX) {
262 nfp_flower_cmsg_warn(app, "IPv6 tunnel keep-alive request exceeds max routes.\n");
263 return;
264 }
265
266 pay_len = nfp_flower_cmsg_get_data_len(skb);
267 if (pay_len != struct_size(payload, tun_info, count)) {
268 nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
269 return;
270 }
271
272 rcu_read_lock();
273 for (i = 0; i < count; i++) {
274 ipv6_add = &payload->tun_info[i].ipv6;
275 port = be32_to_cpu(payload->tun_info[i].egress_port);
276 netdev = nfp_app_dev_get(app, id: port, NULL);
277 if (!netdev)
278 continue;
279
280 n = neigh_lookup(tbl: &nd_tbl, pkey: ipv6_add, dev: netdev);
281 if (!n)
282 continue;
283
284 /* Update the used timestamp of neighbour */
285 neigh_event_send(neigh: n, NULL);
286 neigh_release(neigh: n);
287 }
288 rcu_read_unlock();
289#endif
290}
291
292static int
293nfp_flower_xmit_tun_conf(struct nfp_app *app, u8 mtype, u16 plen, void *pdata,
294 gfp_t flag)
295{
296 struct nfp_flower_priv *priv = app->priv;
297 struct sk_buff *skb;
298 unsigned char *msg;
299
300 if (!(priv->flower_ext_feats & NFP_FL_FEATS_DECAP_V2) &&
301 (mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH ||
302 mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6))
303 plen -= sizeof(struct nfp_tun_neigh_ext);
304
305 if (!(priv->flower_ext_feats & NFP_FL_FEATS_TUNNEL_NEIGH_LAG) &&
306 (mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH ||
307 mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6))
308 plen -= sizeof(struct nfp_tun_neigh_lag);
309
310 skb = nfp_flower_cmsg_alloc(app, size: plen, type: mtype, flag);
311 if (!skb)
312 return -ENOMEM;
313
314 msg = nfp_flower_cmsg_get_data(skb);
315 memcpy(msg, pdata, nfp_flower_cmsg_get_data_len(skb));
316
317 nfp_ctrl_tx(nn: app->ctrl, skb);
318 return 0;
319}
320
321static void
322nfp_tun_mutual_link(struct nfp_predt_entry *predt,
323 struct nfp_neigh_entry *neigh)
324{
325 struct nfp_fl_payload *flow_pay = predt->flow_pay;
326 struct nfp_tun_neigh_ext *ext;
327 struct nfp_tun_neigh *common;
328
329 if (flow_pay->pre_tun_rule.is_ipv6 != neigh->is_ipv6)
330 return;
331
332 /* In the case of bonding it is possible that there might already
333 * be a flow linked (as the MAC address gets shared). If a flow
334 * is already linked just return.
335 */
336 if (neigh->flow)
337 return;
338
339 common = neigh->is_ipv6 ?
340 &((struct nfp_tun_neigh_v6 *)neigh->payload)->common :
341 &((struct nfp_tun_neigh_v4 *)neigh->payload)->common;
342 ext = neigh->is_ipv6 ?
343 &((struct nfp_tun_neigh_v6 *)neigh->payload)->ext :
344 &((struct nfp_tun_neigh_v4 *)neigh->payload)->ext;
345
346 if (memcmp(p: flow_pay->pre_tun_rule.loc_mac,
347 q: common->src_addr, ETH_ALEN) ||
348 memcmp(p: flow_pay->pre_tun_rule.rem_mac,
349 q: common->dst_addr, ETH_ALEN))
350 return;
351
352 list_add(new: &neigh->list_head, head: &predt->nn_list);
353 neigh->flow = predt;
354 ext->host_ctx = flow_pay->meta.host_ctx_id;
355 ext->vlan_tci = flow_pay->pre_tun_rule.vlan_tci;
356 ext->vlan_tpid = flow_pay->pre_tun_rule.vlan_tpid;
357}
358
359static void
360nfp_tun_link_predt_entries(struct nfp_app *app,
361 struct nfp_neigh_entry *nn_entry)
362{
363 struct nfp_flower_priv *priv = app->priv;
364 struct nfp_predt_entry *predt, *tmp;
365
366 list_for_each_entry_safe(predt, tmp, &priv->predt_list, list_head) {
367 nfp_tun_mutual_link(predt, neigh: nn_entry);
368 }
369}
370
371void nfp_tun_link_and_update_nn_entries(struct nfp_app *app,
372 struct nfp_predt_entry *predt)
373{
374 struct nfp_flower_priv *priv = app->priv;
375 struct nfp_neigh_entry *nn_entry;
376 struct rhashtable_iter iter;
377 size_t neigh_size;
378 u8 type;
379
380 rhashtable_walk_enter(ht: &priv->neigh_table, iter: &iter);
381 rhashtable_walk_start(iter: &iter);
382 while ((nn_entry = rhashtable_walk_next(iter: &iter)) != NULL) {
383 if (IS_ERR(ptr: nn_entry))
384 continue;
385 nfp_tun_mutual_link(predt, neigh: nn_entry);
386 neigh_size = nn_entry->is_ipv6 ?
387 sizeof(struct nfp_tun_neigh_v6) :
388 sizeof(struct nfp_tun_neigh_v4);
389 type = nn_entry->is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
390 NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
391 nfp_flower_xmit_tun_conf(app, mtype: type, plen: neigh_size,
392 pdata: nn_entry->payload,
393 GFP_ATOMIC);
394 }
395 rhashtable_walk_stop(iter: &iter);
396 rhashtable_walk_exit(iter: &iter);
397}
398
399static void nfp_tun_cleanup_nn_entries(struct nfp_app *app)
400{
401 struct nfp_flower_priv *priv = app->priv;
402 struct nfp_neigh_entry *neigh;
403 struct nfp_tun_neigh_ext *ext;
404 struct rhashtable_iter iter;
405 size_t neigh_size;
406 u8 type;
407
408 rhashtable_walk_enter(ht: &priv->neigh_table, iter: &iter);
409 rhashtable_walk_start(iter: &iter);
410 while ((neigh = rhashtable_walk_next(iter: &iter)) != NULL) {
411 if (IS_ERR(ptr: neigh))
412 continue;
413 ext = neigh->is_ipv6 ?
414 &((struct nfp_tun_neigh_v6 *)neigh->payload)->ext :
415 &((struct nfp_tun_neigh_v4 *)neigh->payload)->ext;
416 ext->host_ctx = cpu_to_be32(U32_MAX);
417 ext->vlan_tpid = cpu_to_be16(U16_MAX);
418 ext->vlan_tci = cpu_to_be16(U16_MAX);
419
420 neigh_size = neigh->is_ipv6 ?
421 sizeof(struct nfp_tun_neigh_v6) :
422 sizeof(struct nfp_tun_neigh_v4);
423 type = neigh->is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
424 NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
425 nfp_flower_xmit_tun_conf(app, mtype: type, plen: neigh_size, pdata: neigh->payload,
426 GFP_ATOMIC);
427
428 rhashtable_remove_fast(ht: &priv->neigh_table, obj: &neigh->ht_node,
429 params: neigh_table_params);
430 if (neigh->flow)
431 list_del(entry: &neigh->list_head);
432 kfree(objp: neigh);
433 }
434 rhashtable_walk_stop(iter: &iter);
435 rhashtable_walk_exit(iter: &iter);
436}
437
438void nfp_tun_unlink_and_update_nn_entries(struct nfp_app *app,
439 struct nfp_predt_entry *predt)
440{
441 struct nfp_neigh_entry *neigh, *tmp;
442 struct nfp_tun_neigh_ext *ext;
443 size_t neigh_size;
444 u8 type;
445
446 list_for_each_entry_safe(neigh, tmp, &predt->nn_list, list_head) {
447 ext = neigh->is_ipv6 ?
448 &((struct nfp_tun_neigh_v6 *)neigh->payload)->ext :
449 &((struct nfp_tun_neigh_v4 *)neigh->payload)->ext;
450 neigh->flow = NULL;
451 ext->host_ctx = cpu_to_be32(U32_MAX);
452 ext->vlan_tpid = cpu_to_be16(U16_MAX);
453 ext->vlan_tci = cpu_to_be16(U16_MAX);
454 list_del(entry: &neigh->list_head);
455 neigh_size = neigh->is_ipv6 ?
456 sizeof(struct nfp_tun_neigh_v6) :
457 sizeof(struct nfp_tun_neigh_v4);
458 type = neigh->is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
459 NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
460 nfp_flower_xmit_tun_conf(app, mtype: type, plen: neigh_size, pdata: neigh->payload,
461 GFP_ATOMIC);
462 }
463}
464
465static void
466nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
467 void *flow, struct neighbour *neigh, bool is_ipv6,
468 bool override)
469{
470 bool neigh_invalid = !(neigh->nud_state & NUD_VALID) || neigh->dead;
471 size_t neigh_size = is_ipv6 ? sizeof(struct nfp_tun_neigh_v6) :
472 sizeof(struct nfp_tun_neigh_v4);
473 unsigned long cookie = (unsigned long)neigh;
474 struct nfp_flower_priv *priv = app->priv;
475 struct nfp_tun_neigh_lag lag_info;
476 struct nfp_neigh_entry *nn_entry;
477 u32 port_id;
478 u8 mtype;
479
480 port_id = nfp_flower_get_port_id_from_netdev(app, netdev);
481 if (!port_id)
482 return;
483
484 if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT) {
485 memset(&lag_info, 0, sizeof(struct nfp_tun_neigh_lag));
486 nfp_flower_lag_get_info_from_netdev(app, netdev, lag: &lag_info);
487 }
488
489 spin_lock_bh(lock: &priv->predt_lock);
490 nn_entry = rhashtable_lookup_fast(ht: &priv->neigh_table, key: &cookie,
491 params: neigh_table_params);
492 if (!nn_entry && !neigh_invalid) {
493 struct nfp_tun_neigh_ext *ext;
494 struct nfp_tun_neigh_lag *lag;
495 struct nfp_tun_neigh *common;
496
497 nn_entry = kzalloc(size: sizeof(*nn_entry) + neigh_size,
498 GFP_ATOMIC);
499 if (!nn_entry)
500 goto err;
501
502 nn_entry->payload = (char *)&nn_entry[1];
503 nn_entry->neigh_cookie = cookie;
504 nn_entry->is_ipv6 = is_ipv6;
505 nn_entry->flow = NULL;
506 if (is_ipv6) {
507 struct flowi6 *flowi6 = (struct flowi6 *)flow;
508 struct nfp_tun_neigh_v6 *payload;
509
510 payload = (struct nfp_tun_neigh_v6 *)nn_entry->payload;
511 payload->src_ipv6 = flowi6->saddr;
512 payload->dst_ipv6 = flowi6->daddr;
513 common = &payload->common;
514 ext = &payload->ext;
515 lag = &payload->lag;
516 mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6;
517 } else {
518 struct flowi4 *flowi4 = (struct flowi4 *)flow;
519 struct nfp_tun_neigh_v4 *payload;
520
521 payload = (struct nfp_tun_neigh_v4 *)nn_entry->payload;
522 payload->src_ipv4 = flowi4->saddr;
523 payload->dst_ipv4 = flowi4->daddr;
524 common = &payload->common;
525 ext = &payload->ext;
526 lag = &payload->lag;
527 mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
528 }
529 ext->host_ctx = cpu_to_be32(U32_MAX);
530 ext->vlan_tpid = cpu_to_be16(U16_MAX);
531 ext->vlan_tci = cpu_to_be16(U16_MAX);
532 ether_addr_copy(dst: common->src_addr, src: netdev->dev_addr);
533 neigh_ha_snapshot(dst: common->dst_addr, n: neigh, dev: netdev);
534
535 if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT)
536 memcpy(lag, &lag_info, sizeof(struct nfp_tun_neigh_lag));
537 common->port_id = cpu_to_be32(port_id);
538
539 if (rhashtable_insert_fast(ht: &priv->neigh_table,
540 obj: &nn_entry->ht_node,
541 params: neigh_table_params))
542 goto err;
543
544 nfp_tun_link_predt_entries(app, nn_entry);
545 nfp_flower_xmit_tun_conf(app, mtype, plen: neigh_size,
546 pdata: nn_entry->payload,
547 GFP_ATOMIC);
548 } else if (nn_entry && neigh_invalid) {
549 if (is_ipv6) {
550 struct flowi6 *flowi6 = (struct flowi6 *)flow;
551 struct nfp_tun_neigh_v6 *payload;
552
553 payload = (struct nfp_tun_neigh_v6 *)nn_entry->payload;
554 memset(payload, 0, sizeof(struct nfp_tun_neigh_v6));
555 payload->dst_ipv6 = flowi6->daddr;
556 mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6;
557 } else {
558 struct flowi4 *flowi4 = (struct flowi4 *)flow;
559 struct nfp_tun_neigh_v4 *payload;
560
561 payload = (struct nfp_tun_neigh_v4 *)nn_entry->payload;
562 memset(payload, 0, sizeof(struct nfp_tun_neigh_v4));
563 payload->dst_ipv4 = flowi4->daddr;
564 mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
565 }
566 /* Trigger ARP to verify invalid neighbour state. */
567 neigh_event_send(neigh, NULL);
568 rhashtable_remove_fast(ht: &priv->neigh_table,
569 obj: &nn_entry->ht_node,
570 params: neigh_table_params);
571
572 nfp_flower_xmit_tun_conf(app, mtype, plen: neigh_size,
573 pdata: nn_entry->payload,
574 GFP_ATOMIC);
575
576 if (nn_entry->flow)
577 list_del(entry: &nn_entry->list_head);
578 kfree(objp: nn_entry);
579 } else if (nn_entry && !neigh_invalid) {
580 struct nfp_tun_neigh *common;
581 u8 dst_addr[ETH_ALEN];
582 bool is_mac_change;
583
584 if (is_ipv6) {
585 struct nfp_tun_neigh_v6 *payload;
586
587 payload = (struct nfp_tun_neigh_v6 *)nn_entry->payload;
588 common = &payload->common;
589 mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6;
590 } else {
591 struct nfp_tun_neigh_v4 *payload;
592
593 payload = (struct nfp_tun_neigh_v4 *)nn_entry->payload;
594 common = &payload->common;
595 mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
596 }
597
598 ether_addr_copy(dst: dst_addr, src: common->dst_addr);
599 neigh_ha_snapshot(dst: common->dst_addr, n: neigh, dev: netdev);
600 is_mac_change = !ether_addr_equal(addr1: dst_addr, addr2: common->dst_addr);
601 if (override || is_mac_change) {
602 if (is_mac_change && nn_entry->flow) {
603 list_del(entry: &nn_entry->list_head);
604 nn_entry->flow = NULL;
605 }
606 nfp_tun_link_predt_entries(app, nn_entry);
607 nfp_flower_xmit_tun_conf(app, mtype, plen: neigh_size,
608 pdata: nn_entry->payload,
609 GFP_ATOMIC);
610 }
611 }
612
613 spin_unlock_bh(lock: &priv->predt_lock);
614 return;
615
616err:
617 kfree(objp: nn_entry);
618 spin_unlock_bh(lock: &priv->predt_lock);
619 nfp_flower_cmsg_warn(app, "Neighbour configuration failed.\n");
620}
621
622static void
623nfp_tun_release_neigh_update_work(struct nfp_neigh_update_work *update_work)
624{
625 neigh_release(neigh: update_work->n);
626 kfree(objp: update_work);
627}
628
629static void nfp_tun_neigh_update(struct work_struct *work)
630{
631 struct nfp_neigh_update_work *update_work;
632 struct nfp_app *app;
633 struct neighbour *n;
634 bool neigh_invalid;
635 int err;
636
637 update_work = container_of(work, struct nfp_neigh_update_work, work);
638 app = update_work->app;
639 n = update_work->n;
640
641 if (!nfp_flower_get_port_id_from_netdev(app, netdev: n->dev))
642 goto out;
643
644#if IS_ENABLED(CONFIG_INET)
645 neigh_invalid = !(n->nud_state & NUD_VALID) || n->dead;
646 if (n->tbl->family == AF_INET6) {
647#if IS_ENABLED(CONFIG_IPV6)
648 struct flowi6 flow6 = {};
649
650 flow6.daddr = *(struct in6_addr *)n->primary_key;
651 if (!neigh_invalid) {
652 struct dst_entry *dst;
653 /* Use ipv6_dst_lookup_flow to populate flow6->saddr
654 * and other fields. This information is only needed
655 * for new entries, lookup can be skipped when an entry
656 * gets invalidated - as only the daddr is needed for
657 * deleting.
658 */
659 dst = ip6_dst_lookup_flow(net: dev_net(dev: n->dev), NULL,
660 fl6: &flow6, NULL);
661 if (IS_ERR(ptr: dst))
662 goto out;
663
664 dst_release(dst);
665 }
666 nfp_tun_write_neigh(netdev: n->dev, app, flow: &flow6, neigh: n, is_ipv6: true, override: false);
667#endif /* CONFIG_IPV6 */
668 } else {
669 struct flowi4 flow4 = {};
670
671 flow4.daddr = *(__be32 *)n->primary_key;
672 if (!neigh_invalid) {
673 struct rtable *rt;
674 /* Use ip_route_output_key to populate flow4->saddr and
675 * other fields. This information is only needed for
676 * new entries, lookup can be skipped when an entry
677 * gets invalidated - as only the daddr is needed for
678 * deleting.
679 */
680 rt = ip_route_output_key(net: dev_net(dev: n->dev), flp: &flow4);
681 err = PTR_ERR_OR_ZERO(ptr: rt);
682 if (err)
683 goto out;
684
685 ip_rt_put(rt);
686 }
687 nfp_tun_write_neigh(netdev: n->dev, app, flow: &flow4, neigh: n, is_ipv6: false, override: false);
688 }
689#endif /* CONFIG_INET */
690out:
691 nfp_tun_release_neigh_update_work(update_work);
692}
693
694static struct nfp_neigh_update_work *
695nfp_tun_alloc_neigh_update_work(struct nfp_app *app, struct neighbour *n)
696{
697 struct nfp_neigh_update_work *update_work;
698
699 update_work = kzalloc(size: sizeof(*update_work), GFP_ATOMIC);
700 if (!update_work)
701 return NULL;
702
703 INIT_WORK(&update_work->work, nfp_tun_neigh_update);
704 neigh_hold(n);
705 update_work->n = n;
706 update_work->app = app;
707
708 return update_work;
709}
710
711static int
712nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
713 void *ptr)
714{
715 struct nfp_neigh_update_work *update_work;
716 struct nfp_flower_priv *app_priv;
717 struct netevent_redirect *redir;
718 struct neighbour *n;
719 struct nfp_app *app;
720
721 switch (event) {
722 case NETEVENT_REDIRECT:
723 redir = (struct netevent_redirect *)ptr;
724 n = redir->neigh;
725 break;
726 case NETEVENT_NEIGH_UPDATE:
727 n = (struct neighbour *)ptr;
728 break;
729 default:
730 return NOTIFY_DONE;
731 }
732#if IS_ENABLED(CONFIG_IPV6)
733 if (n->tbl != ipv6_stub->nd_tbl && n->tbl != &arp_tbl)
734#else
735 if (n->tbl != &arp_tbl)
736#endif
737 return NOTIFY_DONE;
738
739 app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb);
740 app = app_priv->app;
741 update_work = nfp_tun_alloc_neigh_update_work(app, n);
742 if (!update_work)
743 return NOTIFY_DONE;
744
745 queue_work(wq: system_highpri_wq, work: &update_work->work);
746
747 return NOTIFY_DONE;
748}
749
750void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
751{
752 struct nfp_tun_req_route_ipv4 *payload;
753 struct net_device *netdev;
754 struct flowi4 flow = {};
755 struct neighbour *n;
756 struct rtable *rt;
757 int err;
758
759 payload = nfp_flower_cmsg_get_data(skb);
760
761 rcu_read_lock();
762 netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
763 if (!netdev)
764 goto fail_rcu_unlock;
765 dev_hold(dev: netdev);
766
767 flow.daddr = payload->ipv4_addr;
768 flow.flowi4_proto = IPPROTO_UDP;
769
770#if IS_ENABLED(CONFIG_INET)
771 /* Do a route lookup on same namespace as ingress port. */
772 rt = ip_route_output_key(net: dev_net(dev: netdev), flp: &flow);
773 err = PTR_ERR_OR_ZERO(ptr: rt);
774 if (err)
775 goto fail_rcu_unlock;
776#else
777 goto fail_rcu_unlock;
778#endif
779
780 /* Get the neighbour entry for the lookup */
781 n = dst_neigh_lookup(dst: &rt->dst, daddr: &flow.daddr);
782 ip_rt_put(rt);
783 if (!n)
784 goto fail_rcu_unlock;
785 rcu_read_unlock();
786
787 nfp_tun_write_neigh(netdev: n->dev, app, flow: &flow, neigh: n, is_ipv6: false, override: true);
788 neigh_release(neigh: n);
789 dev_put(dev: netdev);
790 return;
791
792fail_rcu_unlock:
793 rcu_read_unlock();
794 dev_put(dev: netdev);
795 nfp_flower_cmsg_warn(app, "Requested route not found.\n");
796}
797
798void nfp_tunnel_request_route_v6(struct nfp_app *app, struct sk_buff *skb)
799{
800 struct nfp_tun_req_route_ipv6 *payload;
801 struct net_device *netdev;
802 struct flowi6 flow = {};
803 struct dst_entry *dst;
804 struct neighbour *n;
805
806 payload = nfp_flower_cmsg_get_data(skb);
807
808 rcu_read_lock();
809 netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
810 if (!netdev)
811 goto fail_rcu_unlock;
812 dev_hold(dev: netdev);
813
814 flow.daddr = payload->ipv6_addr;
815 flow.flowi6_proto = IPPROTO_UDP;
816
817#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
818 dst = ipv6_stub->ipv6_dst_lookup_flow(dev_net(dev: netdev), NULL, &flow,
819 NULL);
820 if (IS_ERR(ptr: dst))
821 goto fail_rcu_unlock;
822#else
823 goto fail_rcu_unlock;
824#endif
825
826 n = dst_neigh_lookup(dst, daddr: &flow.daddr);
827 dst_release(dst);
828 if (!n)
829 goto fail_rcu_unlock;
830 rcu_read_unlock();
831
832 nfp_tun_write_neigh(netdev: n->dev, app, flow: &flow, neigh: n, is_ipv6: true, override: true);
833 neigh_release(neigh: n);
834 dev_put(dev: netdev);
835 return;
836
837fail_rcu_unlock:
838 rcu_read_unlock();
839 dev_put(dev: netdev);
840 nfp_flower_cmsg_warn(app, "Requested IPv6 route not found.\n");
841}
842
843static void nfp_tun_write_ipv4_list(struct nfp_app *app)
844{
845 struct nfp_flower_priv *priv = app->priv;
846 struct nfp_ipv4_addr_entry *entry;
847 struct nfp_tun_ipv4_addr payload;
848 struct list_head *ptr, *storage;
849 int count;
850
851 memset(&payload, 0, sizeof(struct nfp_tun_ipv4_addr));
852 mutex_lock(&priv->tun.ipv4_off_lock);
853 count = 0;
854 list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
855 if (count >= NFP_FL_IPV4_ADDRS_MAX) {
856 mutex_unlock(lock: &priv->tun.ipv4_off_lock);
857 nfp_flower_cmsg_warn(app, "IPv4 offload exceeds limit.\n");
858 return;
859 }
860 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
861 payload.ipv4_addr[count++] = entry->ipv4_addr;
862 }
863 payload.count = cpu_to_be32(count);
864 mutex_unlock(lock: &priv->tun.ipv4_off_lock);
865
866 nfp_flower_xmit_tun_conf(app, mtype: NFP_FLOWER_CMSG_TYPE_TUN_IPS,
867 plen: sizeof(struct nfp_tun_ipv4_addr),
868 pdata: &payload, GFP_KERNEL);
869}
870
871void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4)
872{
873 struct nfp_flower_priv *priv = app->priv;
874 struct nfp_ipv4_addr_entry *entry;
875 struct list_head *ptr, *storage;
876
877 mutex_lock(&priv->tun.ipv4_off_lock);
878 list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
879 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
880 if (entry->ipv4_addr == ipv4) {
881 entry->ref_count++;
882 mutex_unlock(lock: &priv->tun.ipv4_off_lock);
883 return;
884 }
885 }
886
887 entry = kmalloc(size: sizeof(*entry), GFP_KERNEL);
888 if (!entry) {
889 mutex_unlock(lock: &priv->tun.ipv4_off_lock);
890 nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
891 return;
892 }
893 entry->ipv4_addr = ipv4;
894 entry->ref_count = 1;
895 list_add_tail(new: &entry->list, head: &priv->tun.ipv4_off_list);
896 mutex_unlock(lock: &priv->tun.ipv4_off_lock);
897
898 nfp_tun_write_ipv4_list(app);
899}
900
901void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4)
902{
903 struct nfp_flower_priv *priv = app->priv;
904 struct nfp_ipv4_addr_entry *entry;
905 struct list_head *ptr, *storage;
906
907 mutex_lock(&priv->tun.ipv4_off_lock);
908 list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
909 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
910 if (entry->ipv4_addr == ipv4) {
911 entry->ref_count--;
912 if (!entry->ref_count) {
913 list_del(entry: &entry->list);
914 kfree(objp: entry);
915 }
916 break;
917 }
918 }
919 mutex_unlock(lock: &priv->tun.ipv4_off_lock);
920
921 nfp_tun_write_ipv4_list(app);
922}
923
924static void nfp_tun_write_ipv6_list(struct nfp_app *app)
925{
926 struct nfp_flower_priv *priv = app->priv;
927 struct nfp_ipv6_addr_entry *entry;
928 struct nfp_tun_ipv6_addr payload;
929 int count = 0;
930
931 memset(&payload, 0, sizeof(struct nfp_tun_ipv6_addr));
932 mutex_lock(&priv->tun.ipv6_off_lock);
933 list_for_each_entry(entry, &priv->tun.ipv6_off_list, list) {
934 if (count >= NFP_FL_IPV6_ADDRS_MAX) {
935 nfp_flower_cmsg_warn(app, "Too many IPv6 tunnel endpoint addresses, some cannot be offloaded.\n");
936 break;
937 }
938 payload.ipv6_addr[count++] = entry->ipv6_addr;
939 }
940 mutex_unlock(lock: &priv->tun.ipv6_off_lock);
941 payload.count = cpu_to_be32(count);
942
943 nfp_flower_xmit_tun_conf(app, mtype: NFP_FLOWER_CMSG_TYPE_TUN_IPS_V6,
944 plen: sizeof(struct nfp_tun_ipv6_addr),
945 pdata: &payload, GFP_KERNEL);
946}
947
948struct nfp_ipv6_addr_entry *
949nfp_tunnel_add_ipv6_off(struct nfp_app *app, struct in6_addr *ipv6)
950{
951 struct nfp_flower_priv *priv = app->priv;
952 struct nfp_ipv6_addr_entry *entry;
953
954 mutex_lock(&priv->tun.ipv6_off_lock);
955 list_for_each_entry(entry, &priv->tun.ipv6_off_list, list)
956 if (!memcmp(p: &entry->ipv6_addr, q: ipv6, size: sizeof(*ipv6))) {
957 entry->ref_count++;
958 mutex_unlock(lock: &priv->tun.ipv6_off_lock);
959 return entry;
960 }
961
962 entry = kmalloc(size: sizeof(*entry), GFP_KERNEL);
963 if (!entry) {
964 mutex_unlock(lock: &priv->tun.ipv6_off_lock);
965 nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
966 return NULL;
967 }
968 entry->ipv6_addr = *ipv6;
969 entry->ref_count = 1;
970 list_add_tail(new: &entry->list, head: &priv->tun.ipv6_off_list);
971 mutex_unlock(lock: &priv->tun.ipv6_off_lock);
972
973 nfp_tun_write_ipv6_list(app);
974
975 return entry;
976}
977
978void
979nfp_tunnel_put_ipv6_off(struct nfp_app *app, struct nfp_ipv6_addr_entry *entry)
980{
981 struct nfp_flower_priv *priv = app->priv;
982 bool freed = false;
983
984 mutex_lock(&priv->tun.ipv6_off_lock);
985 if (!--entry->ref_count) {
986 list_del(entry: &entry->list);
987 kfree(objp: entry);
988 freed = true;
989 }
990 mutex_unlock(lock: &priv->tun.ipv6_off_lock);
991
992 if (freed)
993 nfp_tun_write_ipv6_list(app);
994}
995
996static int
997__nfp_tunnel_offload_mac(struct nfp_app *app, const u8 *mac, u16 idx, bool del)
998{
999 struct nfp_tun_mac_addr_offload payload;
1000
1001 memset(&payload, 0, sizeof(payload));
1002
1003 if (del)
1004 payload.flags = cpu_to_be16(NFP_TUN_MAC_OFFLOAD_DEL_FLAG);
1005
1006 /* FW supports multiple MACs per cmsg but restrict to single. */
1007 payload.count = cpu_to_be16(1);
1008 payload.index = cpu_to_be16(idx);
1009 ether_addr_copy(dst: payload.addr, src: mac);
1010
1011 return nfp_flower_xmit_tun_conf(app, mtype: NFP_FLOWER_CMSG_TYPE_TUN_MAC,
1012 plen: sizeof(struct nfp_tun_mac_addr_offload),
1013 pdata: &payload, GFP_KERNEL);
1014}
1015
1016static bool nfp_tunnel_port_is_phy_repr(int port)
1017{
1018 if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) ==
1019 NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT)
1020 return true;
1021
1022 return false;
1023}
1024
1025static u16 nfp_tunnel_get_mac_idx_from_phy_port_id(int port)
1026{
1027 return port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT;
1028}
1029
1030static u16 nfp_tunnel_get_global_mac_idx_from_ida(int id)
1031{
1032 return id << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
1033}
1034
1035static int nfp_tunnel_get_ida_from_global_mac_idx(u16 nfp_mac_idx)
1036{
1037 return nfp_mac_idx >> 8;
1038}
1039
1040static bool nfp_tunnel_is_mac_idx_global(u16 nfp_mac_idx)
1041{
1042 return (nfp_mac_idx & 0xff) == NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
1043}
1044
1045static struct nfp_tun_offloaded_mac *
1046nfp_tunnel_lookup_offloaded_macs(struct nfp_app *app, const u8 *mac)
1047{
1048 struct nfp_flower_priv *priv = app->priv;
1049
1050 return rhashtable_lookup_fast(ht: &priv->tun.offloaded_macs, key: mac,
1051 params: offloaded_macs_params);
1052}
1053
1054static void
1055nfp_tunnel_offloaded_macs_inc_ref_and_link(struct nfp_tun_offloaded_mac *entry,
1056 struct net_device *netdev, bool mod)
1057{
1058 if (nfp_netdev_is_nfp_repr(netdev)) {
1059 struct nfp_flower_repr_priv *repr_priv;
1060 struct nfp_repr *repr;
1061
1062 repr = netdev_priv(dev: netdev);
1063 repr_priv = repr->app_priv;
1064
1065 /* If modifing MAC, remove repr from old list first. */
1066 if (mod)
1067 list_del(entry: &repr_priv->mac_list);
1068
1069 list_add_tail(new: &repr_priv->mac_list, head: &entry->repr_list);
1070 } else if (nfp_flower_is_supported_bridge(netdev)) {
1071 entry->bridge_count++;
1072 }
1073
1074 entry->ref_count++;
1075}
1076
1077static int
1078nfp_tunnel_add_shared_mac(struct nfp_app *app, struct net_device *netdev,
1079 int port, bool mod)
1080{
1081 struct nfp_flower_priv *priv = app->priv;
1082 struct nfp_tun_offloaded_mac *entry;
1083 int ida_idx = -1, err;
1084 u16 nfp_mac_idx = 0;
1085
1086 entry = nfp_tunnel_lookup_offloaded_macs(app, mac: netdev->dev_addr);
1087 if (entry && (nfp_tunnel_is_mac_idx_global(nfp_mac_idx: entry->index) || netif_is_lag_port(dev: netdev))) {
1088 if (entry->bridge_count ||
1089 !nfp_flower_is_supported_bridge(netdev)) {
1090 nfp_tunnel_offloaded_macs_inc_ref_and_link(entry,
1091 netdev, mod);
1092 return 0;
1093 }
1094
1095 /* MAC is global but matches need to go to pre_tun table. */
1096 nfp_mac_idx = entry->index | NFP_TUN_PRE_TUN_IDX_BIT;
1097 }
1098
1099 if (!nfp_mac_idx) {
1100 /* Assign a global index if non-repr or MAC is now shared. */
1101 if (entry || !port) {
1102 ida_idx = ida_alloc_max(ida: &priv->tun.mac_off_ids,
1103 NFP_MAX_MAC_INDEX, GFP_KERNEL);
1104 if (ida_idx < 0)
1105 return ida_idx;
1106
1107 nfp_mac_idx =
1108 nfp_tunnel_get_global_mac_idx_from_ida(id: ida_idx);
1109
1110 if (nfp_flower_is_supported_bridge(netdev))
1111 nfp_mac_idx |= NFP_TUN_PRE_TUN_IDX_BIT;
1112
1113 } else {
1114 nfp_mac_idx =
1115 nfp_tunnel_get_mac_idx_from_phy_port_id(port);
1116 }
1117 }
1118
1119 if (!entry) {
1120 entry = kzalloc(size: sizeof(*entry), GFP_KERNEL);
1121 if (!entry) {
1122 err = -ENOMEM;
1123 goto err_free_ida;
1124 }
1125
1126 ether_addr_copy(dst: entry->addr, src: netdev->dev_addr);
1127 INIT_LIST_HEAD(list: &entry->repr_list);
1128
1129 if (rhashtable_insert_fast(ht: &priv->tun.offloaded_macs,
1130 obj: &entry->ht_node,
1131 params: offloaded_macs_params)) {
1132 err = -ENOMEM;
1133 goto err_free_entry;
1134 }
1135 }
1136
1137 err = __nfp_tunnel_offload_mac(app, mac: netdev->dev_addr,
1138 idx: nfp_mac_idx, del: false);
1139 if (err) {
1140 /* If not shared then free. */
1141 if (!entry->ref_count)
1142 goto err_remove_hash;
1143 goto err_free_ida;
1144 }
1145
1146 entry->index = nfp_mac_idx;
1147 nfp_tunnel_offloaded_macs_inc_ref_and_link(entry, netdev, mod);
1148
1149 return 0;
1150
1151err_remove_hash:
1152 rhashtable_remove_fast(ht: &priv->tun.offloaded_macs, obj: &entry->ht_node,
1153 params: offloaded_macs_params);
1154err_free_entry:
1155 kfree(objp: entry);
1156err_free_ida:
1157 if (ida_idx != -1)
1158 ida_free(&priv->tun.mac_off_ids, id: ida_idx);
1159
1160 return err;
1161}
1162
1163static int
1164nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
1165 const u8 *mac, bool mod)
1166{
1167 struct nfp_flower_priv *priv = app->priv;
1168 struct nfp_flower_repr_priv *repr_priv;
1169 struct nfp_tun_offloaded_mac *entry;
1170 struct nfp_repr *repr;
1171 u16 nfp_mac_idx;
1172 int ida_idx;
1173
1174 entry = nfp_tunnel_lookup_offloaded_macs(app, mac);
1175 if (!entry)
1176 return 0;
1177
1178 entry->ref_count--;
1179 /* If del is part of a mod then mac_list is still in use elsewhere. */
1180 if (nfp_netdev_is_nfp_repr(netdev) && !mod) {
1181 repr = netdev_priv(dev: netdev);
1182 repr_priv = repr->app_priv;
1183 list_del(entry: &repr_priv->mac_list);
1184 }
1185
1186 if (nfp_flower_is_supported_bridge(netdev)) {
1187 entry->bridge_count--;
1188
1189 if (!entry->bridge_count && entry->ref_count) {
1190 nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
1191 if (__nfp_tunnel_offload_mac(app, mac, idx: nfp_mac_idx,
1192 del: false)) {
1193 nfp_flower_cmsg_warn(app, "MAC offload index revert failed on %s.\n",
1194 netdev_name(netdev));
1195 return 0;
1196 }
1197
1198 entry->index = nfp_mac_idx;
1199 return 0;
1200 }
1201 }
1202
1203 /* If MAC is now used by 1 repr set the offloaded MAC index to port. */
1204 if (entry->ref_count == 1 && list_is_singular(head: &entry->repr_list)) {
1205 int port, err;
1206
1207 repr_priv = list_first_entry(&entry->repr_list,
1208 struct nfp_flower_repr_priv,
1209 mac_list);
1210 repr = repr_priv->nfp_repr;
1211 port = nfp_repr_get_port_id(netdev: repr->netdev);
1212 nfp_mac_idx = nfp_tunnel_get_mac_idx_from_phy_port_id(port);
1213 err = __nfp_tunnel_offload_mac(app, mac, idx: nfp_mac_idx, del: false);
1214 if (err) {
1215 nfp_flower_cmsg_warn(app, "MAC offload index revert failed on %s.\n",
1216 netdev_name(netdev));
1217 return 0;
1218 }
1219
1220 ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(nfp_mac_idx: entry->index);
1221 ida_free(&priv->tun.mac_off_ids, id: ida_idx);
1222 entry->index = nfp_mac_idx;
1223 return 0;
1224 }
1225
1226 if (entry->ref_count)
1227 return 0;
1228
1229 WARN_ON_ONCE(rhashtable_remove_fast(&priv->tun.offloaded_macs,
1230 &entry->ht_node,
1231 offloaded_macs_params));
1232
1233 if (nfp_flower_is_supported_bridge(netdev))
1234 nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
1235 else
1236 nfp_mac_idx = entry->index;
1237
1238 /* If MAC has global ID then extract and free the ida entry. */
1239 if (nfp_tunnel_is_mac_idx_global(nfp_mac_idx)) {
1240 ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(nfp_mac_idx: entry->index);
1241 ida_free(&priv->tun.mac_off_ids, id: ida_idx);
1242 }
1243
1244 kfree(objp: entry);
1245
1246 return __nfp_tunnel_offload_mac(app, mac, idx: 0, del: true);
1247}
1248
1249static int
1250nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev,
1251 enum nfp_flower_mac_offload_cmd cmd)
1252{
1253 struct nfp_flower_non_repr_priv *nr_priv = NULL;
1254 bool non_repr = false, *mac_offloaded;
1255 u8 *off_mac = NULL;
1256 int err, port = 0;
1257
1258 if (nfp_netdev_is_nfp_repr(netdev)) {
1259 struct nfp_flower_repr_priv *repr_priv;
1260 struct nfp_repr *repr;
1261
1262 repr = netdev_priv(dev: netdev);
1263 if (repr->app != app)
1264 return 0;
1265
1266 repr_priv = repr->app_priv;
1267 if (repr_priv->on_bridge)
1268 return 0;
1269
1270 mac_offloaded = &repr_priv->mac_offloaded;
1271 off_mac = &repr_priv->offloaded_mac_addr[0];
1272 port = nfp_repr_get_port_id(netdev);
1273 if (!nfp_tunnel_port_is_phy_repr(port))
1274 return 0;
1275 } else if (nfp_fl_is_netdev_to_offload(netdev)) {
1276 nr_priv = nfp_flower_non_repr_priv_get(app, netdev);
1277 if (!nr_priv)
1278 return -ENOMEM;
1279
1280 mac_offloaded = &nr_priv->mac_offloaded;
1281 off_mac = &nr_priv->offloaded_mac_addr[0];
1282 non_repr = true;
1283 } else {
1284 return 0;
1285 }
1286
1287 if (!is_valid_ether_addr(addr: netdev->dev_addr)) {
1288 err = -EINVAL;
1289 goto err_put_non_repr_priv;
1290 }
1291
1292 if (cmd == NFP_TUNNEL_MAC_OFFLOAD_MOD && !*mac_offloaded)
1293 cmd = NFP_TUNNEL_MAC_OFFLOAD_ADD;
1294
1295 switch (cmd) {
1296 case NFP_TUNNEL_MAC_OFFLOAD_ADD:
1297 err = nfp_tunnel_add_shared_mac(app, netdev, port, mod: false);
1298 if (err)
1299 goto err_put_non_repr_priv;
1300
1301 if (non_repr)
1302 __nfp_flower_non_repr_priv_get(non_repr_priv: nr_priv);
1303
1304 *mac_offloaded = true;
1305 ether_addr_copy(dst: off_mac, src: netdev->dev_addr);
1306 break;
1307 case NFP_TUNNEL_MAC_OFFLOAD_DEL:
1308 /* Only attempt delete if add was successful. */
1309 if (!*mac_offloaded)
1310 break;
1311
1312 if (non_repr)
1313 __nfp_flower_non_repr_priv_put(non_repr_priv: nr_priv);
1314
1315 *mac_offloaded = false;
1316
1317 err = nfp_tunnel_del_shared_mac(app, netdev, mac: netdev->dev_addr,
1318 mod: false);
1319 if (err)
1320 goto err_put_non_repr_priv;
1321
1322 break;
1323 case NFP_TUNNEL_MAC_OFFLOAD_MOD:
1324 /* Ignore if changing to the same address. */
1325 if (ether_addr_equal(addr1: netdev->dev_addr, addr2: off_mac))
1326 break;
1327
1328 err = nfp_tunnel_add_shared_mac(app, netdev, port, mod: true);
1329 if (err)
1330 goto err_put_non_repr_priv;
1331
1332 /* Delete the previous MAC address. */
1333 err = nfp_tunnel_del_shared_mac(app, netdev, mac: off_mac, mod: true);
1334 if (err)
1335 nfp_flower_cmsg_warn(app, "Failed to remove offload of replaced MAC addr on %s.\n",
1336 netdev_name(netdev));
1337
1338 ether_addr_copy(dst: off_mac, src: netdev->dev_addr);
1339 break;
1340 default:
1341 err = -EINVAL;
1342 goto err_put_non_repr_priv;
1343 }
1344
1345 if (non_repr)
1346 __nfp_flower_non_repr_priv_put(non_repr_priv: nr_priv);
1347
1348 return 0;
1349
1350err_put_non_repr_priv:
1351 if (non_repr)
1352 __nfp_flower_non_repr_priv_put(non_repr_priv: nr_priv);
1353
1354 return err;
1355}
1356
1357int nfp_tunnel_mac_event_handler(struct nfp_app *app,
1358 struct net_device *netdev,
1359 unsigned long event, void *ptr)
1360{
1361 int err;
1362
1363 if (event == NETDEV_DOWN) {
1364 err = nfp_tunnel_offload_mac(app, netdev,
1365 cmd: NFP_TUNNEL_MAC_OFFLOAD_DEL);
1366 if (err)
1367 nfp_flower_cmsg_warn(app, "Failed to delete offload MAC on %s.\n",
1368 netdev_name(netdev));
1369 } else if (event == NETDEV_UP) {
1370 err = nfp_tunnel_offload_mac(app, netdev,
1371 cmd: NFP_TUNNEL_MAC_OFFLOAD_ADD);
1372 if (err)
1373 nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n",
1374 netdev_name(netdev));
1375 } else if (event == NETDEV_CHANGEADDR) {
1376 /* Only offload addr change if netdev is already up. */
1377 if (!(netdev->flags & IFF_UP))
1378 return NOTIFY_OK;
1379
1380 err = nfp_tunnel_offload_mac(app, netdev,
1381 cmd: NFP_TUNNEL_MAC_OFFLOAD_MOD);
1382 if (err)
1383 nfp_flower_cmsg_warn(app, "Failed to offload MAC change on %s.\n",
1384 netdev_name(netdev));
1385 } else if (event == NETDEV_CHANGEUPPER) {
1386 /* If a repr is attached to a bridge then tunnel packets
1387 * entering the physical port are directed through the bridge
1388 * datapath and cannot be directly detunneled. Therefore,
1389 * associated offloaded MACs and indexes should not be used
1390 * by fw for detunneling.
1391 */
1392 struct netdev_notifier_changeupper_info *info = ptr;
1393 struct net_device *upper = info->upper_dev;
1394 struct nfp_flower_repr_priv *repr_priv;
1395 struct nfp_repr *repr;
1396
1397 if (!nfp_netdev_is_nfp_repr(netdev) ||
1398 !nfp_flower_is_supported_bridge(netdev: upper))
1399 return NOTIFY_OK;
1400
1401 repr = netdev_priv(dev: netdev);
1402 if (repr->app != app)
1403 return NOTIFY_OK;
1404
1405 repr_priv = repr->app_priv;
1406
1407 if (info->linking) {
1408 if (nfp_tunnel_offload_mac(app, netdev,
1409 cmd: NFP_TUNNEL_MAC_OFFLOAD_DEL))
1410 nfp_flower_cmsg_warn(app, "Failed to delete offloaded MAC on %s.\n",
1411 netdev_name(netdev));
1412 repr_priv->on_bridge = true;
1413 } else {
1414 repr_priv->on_bridge = false;
1415
1416 if (!(netdev->flags & IFF_UP))
1417 return NOTIFY_OK;
1418
1419 if (nfp_tunnel_offload_mac(app, netdev,
1420 cmd: NFP_TUNNEL_MAC_OFFLOAD_ADD))
1421 nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n",
1422 netdev_name(netdev));
1423 }
1424 }
1425 return NOTIFY_OK;
1426}
1427
1428int nfp_flower_xmit_pre_tun_flow(struct nfp_app *app,
1429 struct nfp_fl_payload *flow)
1430{
1431 struct nfp_flower_priv *app_priv = app->priv;
1432 struct nfp_tun_offloaded_mac *mac_entry;
1433 struct nfp_flower_meta_tci *key_meta;
1434 struct nfp_tun_pre_tun_rule payload;
1435 struct net_device *internal_dev;
1436 int err;
1437
1438 if (app_priv->pre_tun_rule_cnt == NFP_TUN_PRE_TUN_RULE_LIMIT)
1439 return -ENOSPC;
1440
1441 memset(&payload, 0, sizeof(struct nfp_tun_pre_tun_rule));
1442
1443 internal_dev = flow->pre_tun_rule.dev;
1444 payload.vlan_tci = flow->pre_tun_rule.vlan_tci;
1445 payload.host_ctx_id = flow->meta.host_ctx_id;
1446
1447 /* Lookup MAC index for the pre-tunnel rule egress device.
1448 * Note that because the device is always an internal port, it will
1449 * have a constant global index so does not need to be tracked.
1450 */
1451 mac_entry = nfp_tunnel_lookup_offloaded_macs(app,
1452 mac: internal_dev->dev_addr);
1453 if (!mac_entry)
1454 return -ENOENT;
1455
1456 /* Set/clear IPV6 bit. cpu_to_be16() swap will lead to MSB being
1457 * set/clear for port_idx.
1458 */
1459 key_meta = (struct nfp_flower_meta_tci *)flow->unmasked_data;
1460 if (key_meta->nfp_flow_key_layer & NFP_FLOWER_LAYER_IPV6)
1461 mac_entry->index |= NFP_TUN_PRE_TUN_IPV6_BIT;
1462 else
1463 mac_entry->index &= ~NFP_TUN_PRE_TUN_IPV6_BIT;
1464
1465 payload.port_idx = cpu_to_be16(mac_entry->index);
1466
1467 /* Copy mac id and vlan to flow - dev may not exist at delete time. */
1468 flow->pre_tun_rule.vlan_tci = payload.vlan_tci;
1469 flow->pre_tun_rule.port_idx = payload.port_idx;
1470
1471 err = nfp_flower_xmit_tun_conf(app, mtype: NFP_FLOWER_CMSG_TYPE_PRE_TUN_RULE,
1472 plen: sizeof(struct nfp_tun_pre_tun_rule),
1473 pdata: (unsigned char *)&payload, GFP_KERNEL);
1474 if (err)
1475 return err;
1476
1477 app_priv->pre_tun_rule_cnt++;
1478
1479 return 0;
1480}
1481
1482int nfp_flower_xmit_pre_tun_del_flow(struct nfp_app *app,
1483 struct nfp_fl_payload *flow)
1484{
1485 struct nfp_flower_priv *app_priv = app->priv;
1486 struct nfp_tun_pre_tun_rule payload;
1487 u32 tmp_flags = 0;
1488 int err;
1489
1490 memset(&payload, 0, sizeof(struct nfp_tun_pre_tun_rule));
1491
1492 tmp_flags |= NFP_TUN_PRE_TUN_RULE_DEL;
1493 payload.flags = cpu_to_be32(tmp_flags);
1494 payload.vlan_tci = flow->pre_tun_rule.vlan_tci;
1495 payload.port_idx = flow->pre_tun_rule.port_idx;
1496
1497 err = nfp_flower_xmit_tun_conf(app, mtype: NFP_FLOWER_CMSG_TYPE_PRE_TUN_RULE,
1498 plen: sizeof(struct nfp_tun_pre_tun_rule),
1499 pdata: (unsigned char *)&payload, GFP_KERNEL);
1500 if (err)
1501 return err;
1502
1503 app_priv->pre_tun_rule_cnt--;
1504
1505 return 0;
1506}
1507
1508int nfp_tunnel_config_start(struct nfp_app *app)
1509{
1510 struct nfp_flower_priv *priv = app->priv;
1511 int err;
1512
1513 /* Initialise rhash for MAC offload tracking. */
1514 err = rhashtable_init(ht: &priv->tun.offloaded_macs,
1515 params: &offloaded_macs_params);
1516 if (err)
1517 return err;
1518
1519 ida_init(ida: &priv->tun.mac_off_ids);
1520
1521 /* Initialise priv data for IPv4/v6 offloading. */
1522 mutex_init(&priv->tun.ipv4_off_lock);
1523 INIT_LIST_HEAD(list: &priv->tun.ipv4_off_list);
1524 mutex_init(&priv->tun.ipv6_off_lock);
1525 INIT_LIST_HEAD(list: &priv->tun.ipv6_off_list);
1526
1527 /* Initialise priv data for neighbour offloading. */
1528 priv->tun.neigh_nb.notifier_call = nfp_tun_neigh_event_handler;
1529
1530 err = register_netevent_notifier(nb: &priv->tun.neigh_nb);
1531 if (err) {
1532 rhashtable_free_and_destroy(ht: &priv->tun.offloaded_macs,
1533 free_fn: nfp_check_rhashtable_empty, NULL);
1534 return err;
1535 }
1536
1537 return 0;
1538}
1539
1540void nfp_tunnel_config_stop(struct nfp_app *app)
1541{
1542 struct nfp_flower_priv *priv = app->priv;
1543 struct nfp_ipv4_addr_entry *ip_entry;
1544 struct list_head *ptr, *storage;
1545
1546 unregister_netevent_notifier(nb: &priv->tun.neigh_nb);
1547
1548 ida_destroy(ida: &priv->tun.mac_off_ids);
1549
1550 /* Free any memory that may be occupied by ipv4 list. */
1551 list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
1552 ip_entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
1553 list_del(entry: &ip_entry->list);
1554 kfree(objp: ip_entry);
1555 }
1556
1557 mutex_destroy(lock: &priv->tun.ipv6_off_lock);
1558
1559 /* Destroy rhash. Entries should be cleaned on netdev notifier unreg. */
1560 rhashtable_free_and_destroy(ht: &priv->tun.offloaded_macs,
1561 free_fn: nfp_check_rhashtable_empty, NULL);
1562
1563 nfp_tun_cleanup_nn_entries(app);
1564}
1565

source code of linux/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c