WIP FPC-III support
[linux/fpc-iii.git] / drivers / net / ethernet / netronome / nfp / flower / tunnel_conf.c
blob7248d248f60416f18b7263622b2866da8627e410
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
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>
11 #include "cmsg.h"
12 #include "main.h"
13 #include "../nfp_net_repr.h"
14 #include "../nfp_net.h"
16 #define NFP_FL_MAX_ROUTES 32
18 #define NFP_TUN_PRE_TUN_RULE_LIMIT 32
19 #define NFP_TUN_PRE_TUN_RULE_DEL 0x1
20 #define NFP_TUN_PRE_TUN_IDX_BIT 0x8
22 /**
23 * struct nfp_tun_pre_run_rule - rule matched before decap
24 * @flags: options for the rule offset
25 * @port_idx: index of destination MAC address for the rule
26 * @vlan_tci: VLAN info associated with MAC
27 * @host_ctx_id: stats context of rule to update
29 struct nfp_tun_pre_tun_rule {
30 __be32 flags;
31 __be16 port_idx;
32 __be16 vlan_tci;
33 __be32 host_ctx_id;
36 /**
37 * struct nfp_tun_active_tuns - periodic message of active tunnels
38 * @seq: sequence number of the message
39 * @count: number of tunnels report in message
40 * @flags: options part of the request
41 * @tun_info.ipv4: dest IPv4 address of active route
42 * @tun_info.egress_port: port the encapsulated packet egressed
43 * @tun_info.extra: reserved for future use
44 * @tun_info: tunnels that have sent traffic in reported period
46 struct nfp_tun_active_tuns {
47 __be32 seq;
48 __be32 count;
49 __be32 flags;
50 struct route_ip_info {
51 __be32 ipv4;
52 __be32 egress_port;
53 __be32 extra[2];
54 } tun_info[];
57 /**
58 * struct nfp_tun_active_tuns_v6 - periodic message of active IPv6 tunnels
59 * @seq: sequence number of the message
60 * @count: number of tunnels report in message
61 * @flags: options part of the request
62 * @tun_info.ipv6: dest IPv6 address of active route
63 * @tun_info.egress_port: port the encapsulated packet egressed
64 * @tun_info.extra: reserved for future use
65 * @tun_info: tunnels that have sent traffic in reported period
67 struct nfp_tun_active_tuns_v6 {
68 __be32 seq;
69 __be32 count;
70 __be32 flags;
71 struct route_ip_info_v6 {
72 struct in6_addr ipv6;
73 __be32 egress_port;
74 __be32 extra[2];
75 } tun_info[];
78 /**
79 * struct nfp_tun_neigh - neighbour/route entry on the NFP
80 * @dst_ipv4: destination IPv4 address
81 * @src_ipv4: source IPv4 address
82 * @dst_addr: destination MAC address
83 * @src_addr: source MAC address
84 * @port_id: NFP port to output packet on - associated with source IPv4
86 struct nfp_tun_neigh {
87 __be32 dst_ipv4;
88 __be32 src_ipv4;
89 u8 dst_addr[ETH_ALEN];
90 u8 src_addr[ETH_ALEN];
91 __be32 port_id;
94 /**
95 * struct nfp_tun_neigh_v6 - neighbour/route entry on the NFP
96 * @dst_ipv6: destination IPv6 address
97 * @src_ipv6: source IPv6 address
98 * @dst_addr: destination MAC address
99 * @src_addr: source MAC address
100 * @port_id: NFP port to output packet on - associated with source IPv6
102 struct nfp_tun_neigh_v6 {
103 struct in6_addr dst_ipv6;
104 struct in6_addr src_ipv6;
105 u8 dst_addr[ETH_ALEN];
106 u8 src_addr[ETH_ALEN];
107 __be32 port_id;
111 * struct nfp_tun_req_route_ipv4 - NFP requests a route/neighbour lookup
112 * @ingress_port: ingress port of packet that signalled request
113 * @ipv4_addr: destination ipv4 address for route
114 * @reserved: reserved for future use
116 struct nfp_tun_req_route_ipv4 {
117 __be32 ingress_port;
118 __be32 ipv4_addr;
119 __be32 reserved[2];
123 * struct nfp_tun_req_route_ipv6 - NFP requests an IPv6 route/neighbour lookup
124 * @ingress_port: ingress port of packet that signalled request
125 * @ipv6_addr: destination ipv6 address for route
127 struct nfp_tun_req_route_ipv6 {
128 __be32 ingress_port;
129 struct in6_addr ipv6_addr;
133 * struct nfp_offloaded_route - routes that are offloaded to the NFP
134 * @list: list pointer
135 * @ip_add: destination of route - can be IPv4 or IPv6
137 struct nfp_offloaded_route {
138 struct list_head list;
139 u8 ip_add[];
142 #define NFP_FL_IPV4_ADDRS_MAX 32
145 * struct nfp_tun_ipv4_addr - set the IP address list on the NFP
146 * @count: number of IPs populated in the array
147 * @ipv4_addr: array of IPV4_ADDRS_MAX 32 bit IPv4 addresses
149 struct nfp_tun_ipv4_addr {
150 __be32 count;
151 __be32 ipv4_addr[NFP_FL_IPV4_ADDRS_MAX];
155 * struct nfp_ipv4_addr_entry - cached IPv4 addresses
156 * @ipv4_addr: IP address
157 * @ref_count: number of rules currently using this IP
158 * @list: list pointer
160 struct nfp_ipv4_addr_entry {
161 __be32 ipv4_addr;
162 int ref_count;
163 struct list_head list;
166 #define NFP_FL_IPV6_ADDRS_MAX 4
169 * struct nfp_tun_ipv6_addr - set the IP address list on the NFP
170 * @count: number of IPs populated in the array
171 * @ipv6_addr: array of IPV6_ADDRS_MAX 128 bit IPv6 addresses
173 struct nfp_tun_ipv6_addr {
174 __be32 count;
175 struct in6_addr ipv6_addr[NFP_FL_IPV6_ADDRS_MAX];
178 #define NFP_TUN_MAC_OFFLOAD_DEL_FLAG 0x2
181 * struct nfp_tun_mac_addr_offload - configure MAC address of tunnel EP on NFP
182 * @flags: MAC address offload options
183 * @count: number of MAC addresses in the message (should be 1)
184 * @index: index of MAC address in the lookup table
185 * @addr: interface MAC address
187 struct nfp_tun_mac_addr_offload {
188 __be16 flags;
189 __be16 count;
190 __be16 index;
191 u8 addr[ETH_ALEN];
194 enum nfp_flower_mac_offload_cmd {
195 NFP_TUNNEL_MAC_OFFLOAD_ADD = 0,
196 NFP_TUNNEL_MAC_OFFLOAD_DEL = 1,
197 NFP_TUNNEL_MAC_OFFLOAD_MOD = 2,
200 #define NFP_MAX_MAC_INDEX 0xff
203 * struct nfp_tun_offloaded_mac - hashtable entry for an offloaded MAC
204 * @ht_node: Hashtable entry
205 * @addr: Offloaded MAC address
206 * @index: Offloaded index for given MAC address
207 * @ref_count: Number of devs using this MAC address
208 * @repr_list: List of reprs sharing this MAC address
209 * @bridge_count: Number of bridge/internal devs with MAC
211 struct nfp_tun_offloaded_mac {
212 struct rhash_head ht_node;
213 u8 addr[ETH_ALEN];
214 u16 index;
215 int ref_count;
216 struct list_head repr_list;
217 int bridge_count;
220 static const struct rhashtable_params offloaded_macs_params = {
221 .key_offset = offsetof(struct nfp_tun_offloaded_mac, addr),
222 .head_offset = offsetof(struct nfp_tun_offloaded_mac, ht_node),
223 .key_len = ETH_ALEN,
224 .automatic_shrinking = true,
227 void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
229 struct nfp_tun_active_tuns *payload;
230 struct net_device *netdev;
231 int count, i, pay_len;
232 struct neighbour *n;
233 __be32 ipv4_addr;
234 u32 port;
236 payload = nfp_flower_cmsg_get_data(skb);
237 count = be32_to_cpu(payload->count);
238 if (count > NFP_FL_MAX_ROUTES) {
239 nfp_flower_cmsg_warn(app, "Tunnel keep-alive request exceeds max routes.\n");
240 return;
243 pay_len = nfp_flower_cmsg_get_data_len(skb);
244 if (pay_len != struct_size(payload, tun_info, count)) {
245 nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
246 return;
249 rcu_read_lock();
250 for (i = 0; i < count; i++) {
251 ipv4_addr = payload->tun_info[i].ipv4;
252 port = be32_to_cpu(payload->tun_info[i].egress_port);
253 netdev = nfp_app_dev_get(app, port, NULL);
254 if (!netdev)
255 continue;
257 n = neigh_lookup(&arp_tbl, &ipv4_addr, netdev);
258 if (!n)
259 continue;
261 /* Update the used timestamp of neighbour */
262 neigh_event_send(n, NULL);
263 neigh_release(n);
265 rcu_read_unlock();
268 void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
270 #if IS_ENABLED(CONFIG_IPV6)
271 struct nfp_tun_active_tuns_v6 *payload;
272 struct net_device *netdev;
273 int count, i, pay_len;
274 struct neighbour *n;
275 void *ipv6_add;
276 u32 port;
278 payload = nfp_flower_cmsg_get_data(skb);
279 count = be32_to_cpu(payload->count);
280 if (count > NFP_FL_IPV6_ADDRS_MAX) {
281 nfp_flower_cmsg_warn(app, "IPv6 tunnel keep-alive request exceeds max routes.\n");
282 return;
285 pay_len = nfp_flower_cmsg_get_data_len(skb);
286 if (pay_len != struct_size(payload, tun_info, count)) {
287 nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
288 return;
291 rcu_read_lock();
292 for (i = 0; i < count; i++) {
293 ipv6_add = &payload->tun_info[i].ipv6;
294 port = be32_to_cpu(payload->tun_info[i].egress_port);
295 netdev = nfp_app_dev_get(app, port, NULL);
296 if (!netdev)
297 continue;
299 n = neigh_lookup(&nd_tbl, ipv6_add, netdev);
300 if (!n)
301 continue;
303 /* Update the used timestamp of neighbour */
304 neigh_event_send(n, NULL);
305 neigh_release(n);
307 rcu_read_unlock();
308 #endif
311 static int
312 nfp_flower_xmit_tun_conf(struct nfp_app *app, u8 mtype, u16 plen, void *pdata,
313 gfp_t flag)
315 struct sk_buff *skb;
316 unsigned char *msg;
318 skb = nfp_flower_cmsg_alloc(app, plen, mtype, flag);
319 if (!skb)
320 return -ENOMEM;
322 msg = nfp_flower_cmsg_get_data(skb);
323 memcpy(msg, pdata, nfp_flower_cmsg_get_data_len(skb));
325 nfp_ctrl_tx(app->ctrl, skb);
326 return 0;
329 static bool
330 __nfp_tun_has_route(struct list_head *route_list, spinlock_t *list_lock,
331 void *add, int add_len)
333 struct nfp_offloaded_route *entry;
335 spin_lock_bh(list_lock);
336 list_for_each_entry(entry, route_list, list)
337 if (!memcmp(entry->ip_add, add, add_len)) {
338 spin_unlock_bh(list_lock);
339 return true;
341 spin_unlock_bh(list_lock);
342 return false;
345 static int
346 __nfp_tun_add_route_to_cache(struct list_head *route_list,
347 spinlock_t *list_lock, void *add, int add_len)
349 struct nfp_offloaded_route *entry;
351 spin_lock_bh(list_lock);
352 list_for_each_entry(entry, route_list, list)
353 if (!memcmp(entry->ip_add, add, add_len)) {
354 spin_unlock_bh(list_lock);
355 return 0;
358 entry = kmalloc(sizeof(*entry) + add_len, GFP_ATOMIC);
359 if (!entry) {
360 spin_unlock_bh(list_lock);
361 return -ENOMEM;
364 memcpy(entry->ip_add, add, add_len);
365 list_add_tail(&entry->list, route_list);
366 spin_unlock_bh(list_lock);
368 return 0;
371 static void
372 __nfp_tun_del_route_from_cache(struct list_head *route_list,
373 spinlock_t *list_lock, void *add, int add_len)
375 struct nfp_offloaded_route *entry;
377 spin_lock_bh(list_lock);
378 list_for_each_entry(entry, route_list, list)
379 if (!memcmp(entry->ip_add, add, add_len)) {
380 list_del(&entry->list);
381 kfree(entry);
382 break;
384 spin_unlock_bh(list_lock);
387 static bool nfp_tun_has_route_v4(struct nfp_app *app, __be32 *ipv4_addr)
389 struct nfp_flower_priv *priv = app->priv;
391 return __nfp_tun_has_route(&priv->tun.neigh_off_list_v4,
392 &priv->tun.neigh_off_lock_v4, ipv4_addr,
393 sizeof(*ipv4_addr));
396 static bool
397 nfp_tun_has_route_v6(struct nfp_app *app, struct in6_addr *ipv6_addr)
399 struct nfp_flower_priv *priv = app->priv;
401 return __nfp_tun_has_route(&priv->tun.neigh_off_list_v6,
402 &priv->tun.neigh_off_lock_v6, ipv6_addr,
403 sizeof(*ipv6_addr));
406 static void
407 nfp_tun_add_route_to_cache_v4(struct nfp_app *app, __be32 *ipv4_addr)
409 struct nfp_flower_priv *priv = app->priv;
411 __nfp_tun_add_route_to_cache(&priv->tun.neigh_off_list_v4,
412 &priv->tun.neigh_off_lock_v4, ipv4_addr,
413 sizeof(*ipv4_addr));
416 static void
417 nfp_tun_add_route_to_cache_v6(struct nfp_app *app, struct in6_addr *ipv6_addr)
419 struct nfp_flower_priv *priv = app->priv;
421 __nfp_tun_add_route_to_cache(&priv->tun.neigh_off_list_v6,
422 &priv->tun.neigh_off_lock_v6, ipv6_addr,
423 sizeof(*ipv6_addr));
426 static void
427 nfp_tun_del_route_from_cache_v4(struct nfp_app *app, __be32 *ipv4_addr)
429 struct nfp_flower_priv *priv = app->priv;
431 __nfp_tun_del_route_from_cache(&priv->tun.neigh_off_list_v4,
432 &priv->tun.neigh_off_lock_v4, ipv4_addr,
433 sizeof(*ipv4_addr));
436 static void
437 nfp_tun_del_route_from_cache_v6(struct nfp_app *app, struct in6_addr *ipv6_addr)
439 struct nfp_flower_priv *priv = app->priv;
441 __nfp_tun_del_route_from_cache(&priv->tun.neigh_off_list_v6,
442 &priv->tun.neigh_off_lock_v6, ipv6_addr,
443 sizeof(*ipv6_addr));
446 static void
447 nfp_tun_write_neigh_v4(struct net_device *netdev, struct nfp_app *app,
448 struct flowi4 *flow, struct neighbour *neigh, gfp_t flag)
450 struct nfp_tun_neigh payload;
451 u32 port_id;
453 port_id = nfp_flower_get_port_id_from_netdev(app, netdev);
454 if (!port_id)
455 return;
457 memset(&payload, 0, sizeof(struct nfp_tun_neigh));
458 payload.dst_ipv4 = flow->daddr;
460 /* If entry has expired send dst IP with all other fields 0. */
461 if (!(neigh->nud_state & NUD_VALID) || neigh->dead) {
462 nfp_tun_del_route_from_cache_v4(app, &payload.dst_ipv4);
463 /* Trigger ARP to verify invalid neighbour state. */
464 neigh_event_send(neigh, NULL);
465 goto send_msg;
468 /* Have a valid neighbour so populate rest of entry. */
469 payload.src_ipv4 = flow->saddr;
470 ether_addr_copy(payload.src_addr, netdev->dev_addr);
471 neigh_ha_snapshot(payload.dst_addr, neigh, netdev);
472 payload.port_id = cpu_to_be32(port_id);
473 /* Add destination of new route to NFP cache. */
474 nfp_tun_add_route_to_cache_v4(app, &payload.dst_ipv4);
476 send_msg:
477 nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH,
478 sizeof(struct nfp_tun_neigh),
479 (unsigned char *)&payload, flag);
482 static void
483 nfp_tun_write_neigh_v6(struct net_device *netdev, struct nfp_app *app,
484 struct flowi6 *flow, struct neighbour *neigh, gfp_t flag)
486 struct nfp_tun_neigh_v6 payload;
487 u32 port_id;
489 port_id = nfp_flower_get_port_id_from_netdev(app, netdev);
490 if (!port_id)
491 return;
493 memset(&payload, 0, sizeof(struct nfp_tun_neigh_v6));
494 payload.dst_ipv6 = flow->daddr;
496 /* If entry has expired send dst IP with all other fields 0. */
497 if (!(neigh->nud_state & NUD_VALID) || neigh->dead) {
498 nfp_tun_del_route_from_cache_v6(app, &payload.dst_ipv6);
499 /* Trigger probe to verify invalid neighbour state. */
500 neigh_event_send(neigh, NULL);
501 goto send_msg;
504 /* Have a valid neighbour so populate rest of entry. */
505 payload.src_ipv6 = flow->saddr;
506 ether_addr_copy(payload.src_addr, netdev->dev_addr);
507 neigh_ha_snapshot(payload.dst_addr, neigh, netdev);
508 payload.port_id = cpu_to_be32(port_id);
509 /* Add destination of new route to NFP cache. */
510 nfp_tun_add_route_to_cache_v6(app, &payload.dst_ipv6);
512 send_msg:
513 nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6,
514 sizeof(struct nfp_tun_neigh_v6),
515 (unsigned char *)&payload, flag);
518 static int
519 nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
520 void *ptr)
522 struct nfp_flower_priv *app_priv;
523 struct netevent_redirect *redir;
524 struct flowi4 flow4 = {};
525 struct flowi6 flow6 = {};
526 struct neighbour *n;
527 struct nfp_app *app;
528 struct rtable *rt;
529 bool ipv6 = false;
530 int err;
532 switch (event) {
533 case NETEVENT_REDIRECT:
534 redir = (struct netevent_redirect *)ptr;
535 n = redir->neigh;
536 break;
537 case NETEVENT_NEIGH_UPDATE:
538 n = (struct neighbour *)ptr;
539 break;
540 default:
541 return NOTIFY_DONE;
544 if (n->tbl->family == AF_INET6)
545 ipv6 = true;
547 if (ipv6)
548 flow6.daddr = *(struct in6_addr *)n->primary_key;
549 else
550 flow4.daddr = *(__be32 *)n->primary_key;
552 app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb);
553 app = app_priv->app;
555 if (!nfp_netdev_is_nfp_repr(n->dev) &&
556 !nfp_flower_internal_port_can_offload(app, n->dev))
557 return NOTIFY_DONE;
559 /* Only concerned with changes to routes already added to NFP. */
560 if ((ipv6 && !nfp_tun_has_route_v6(app, &flow6.daddr)) ||
561 (!ipv6 && !nfp_tun_has_route_v4(app, &flow4.daddr)))
562 return NOTIFY_DONE;
564 #if IS_ENABLED(CONFIG_INET)
565 if (ipv6) {
566 #if IS_ENABLED(CONFIG_IPV6)
567 struct dst_entry *dst;
569 dst = ipv6_stub->ipv6_dst_lookup_flow(dev_net(n->dev), NULL,
570 &flow6, NULL);
571 if (IS_ERR(dst))
572 return NOTIFY_DONE;
574 dst_release(dst);
575 flow6.flowi6_proto = IPPROTO_UDP;
576 nfp_tun_write_neigh_v6(n->dev, app, &flow6, n, GFP_ATOMIC);
577 #else
578 return NOTIFY_DONE;
579 #endif /* CONFIG_IPV6 */
580 } else {
581 /* Do a route lookup to populate flow data. */
582 rt = ip_route_output_key(dev_net(n->dev), &flow4);
583 err = PTR_ERR_OR_ZERO(rt);
584 if (err)
585 return NOTIFY_DONE;
587 ip_rt_put(rt);
589 flow4.flowi4_proto = IPPROTO_UDP;
590 nfp_tun_write_neigh_v4(n->dev, app, &flow4, n, GFP_ATOMIC);
592 #else
593 return NOTIFY_DONE;
594 #endif /* CONFIG_INET */
596 return NOTIFY_OK;
599 void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
601 struct nfp_tun_req_route_ipv4 *payload;
602 struct net_device *netdev;
603 struct flowi4 flow = {};
604 struct neighbour *n;
605 struct rtable *rt;
606 int err;
608 payload = nfp_flower_cmsg_get_data(skb);
610 rcu_read_lock();
611 netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
612 if (!netdev)
613 goto fail_rcu_unlock;
615 flow.daddr = payload->ipv4_addr;
616 flow.flowi4_proto = IPPROTO_UDP;
618 #if IS_ENABLED(CONFIG_INET)
619 /* Do a route lookup on same namespace as ingress port. */
620 rt = ip_route_output_key(dev_net(netdev), &flow);
621 err = PTR_ERR_OR_ZERO(rt);
622 if (err)
623 goto fail_rcu_unlock;
624 #else
625 goto fail_rcu_unlock;
626 #endif
628 /* Get the neighbour entry for the lookup */
629 n = dst_neigh_lookup(&rt->dst, &flow.daddr);
630 ip_rt_put(rt);
631 if (!n)
632 goto fail_rcu_unlock;
633 nfp_tun_write_neigh_v4(n->dev, app, &flow, n, GFP_ATOMIC);
634 neigh_release(n);
635 rcu_read_unlock();
636 return;
638 fail_rcu_unlock:
639 rcu_read_unlock();
640 nfp_flower_cmsg_warn(app, "Requested route not found.\n");
643 void nfp_tunnel_request_route_v6(struct nfp_app *app, struct sk_buff *skb)
645 struct nfp_tun_req_route_ipv6 *payload;
646 struct net_device *netdev;
647 struct flowi6 flow = {};
648 struct dst_entry *dst;
649 struct neighbour *n;
651 payload = nfp_flower_cmsg_get_data(skb);
653 rcu_read_lock();
654 netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
655 if (!netdev)
656 goto fail_rcu_unlock;
658 flow.daddr = payload->ipv6_addr;
659 flow.flowi6_proto = IPPROTO_UDP;
661 #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
662 dst = ipv6_stub->ipv6_dst_lookup_flow(dev_net(netdev), NULL, &flow,
663 NULL);
664 if (IS_ERR(dst))
665 goto fail_rcu_unlock;
666 #else
667 goto fail_rcu_unlock;
668 #endif
670 n = dst_neigh_lookup(dst, &flow.daddr);
671 dst_release(dst);
672 if (!n)
673 goto fail_rcu_unlock;
675 nfp_tun_write_neigh_v6(n->dev, app, &flow, n, GFP_ATOMIC);
676 neigh_release(n);
677 rcu_read_unlock();
678 return;
680 fail_rcu_unlock:
681 rcu_read_unlock();
682 nfp_flower_cmsg_warn(app, "Requested IPv6 route not found.\n");
685 static void nfp_tun_write_ipv4_list(struct nfp_app *app)
687 struct nfp_flower_priv *priv = app->priv;
688 struct nfp_ipv4_addr_entry *entry;
689 struct nfp_tun_ipv4_addr payload;
690 struct list_head *ptr, *storage;
691 int count;
693 memset(&payload, 0, sizeof(struct nfp_tun_ipv4_addr));
694 mutex_lock(&priv->tun.ipv4_off_lock);
695 count = 0;
696 list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
697 if (count >= NFP_FL_IPV4_ADDRS_MAX) {
698 mutex_unlock(&priv->tun.ipv4_off_lock);
699 nfp_flower_cmsg_warn(app, "IPv4 offload exceeds limit.\n");
700 return;
702 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
703 payload.ipv4_addr[count++] = entry->ipv4_addr;
705 payload.count = cpu_to_be32(count);
706 mutex_unlock(&priv->tun.ipv4_off_lock);
708 nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_IPS,
709 sizeof(struct nfp_tun_ipv4_addr),
710 &payload, GFP_KERNEL);
713 void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4)
715 struct nfp_flower_priv *priv = app->priv;
716 struct nfp_ipv4_addr_entry *entry;
717 struct list_head *ptr, *storage;
719 mutex_lock(&priv->tun.ipv4_off_lock);
720 list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
721 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
722 if (entry->ipv4_addr == ipv4) {
723 entry->ref_count++;
724 mutex_unlock(&priv->tun.ipv4_off_lock);
725 return;
729 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
730 if (!entry) {
731 mutex_unlock(&priv->tun.ipv4_off_lock);
732 nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
733 return;
735 entry->ipv4_addr = ipv4;
736 entry->ref_count = 1;
737 list_add_tail(&entry->list, &priv->tun.ipv4_off_list);
738 mutex_unlock(&priv->tun.ipv4_off_lock);
740 nfp_tun_write_ipv4_list(app);
743 void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4)
745 struct nfp_flower_priv *priv = app->priv;
746 struct nfp_ipv4_addr_entry *entry;
747 struct list_head *ptr, *storage;
749 mutex_lock(&priv->tun.ipv4_off_lock);
750 list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
751 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
752 if (entry->ipv4_addr == ipv4) {
753 entry->ref_count--;
754 if (!entry->ref_count) {
755 list_del(&entry->list);
756 kfree(entry);
758 break;
761 mutex_unlock(&priv->tun.ipv4_off_lock);
763 nfp_tun_write_ipv4_list(app);
766 static void nfp_tun_write_ipv6_list(struct nfp_app *app)
768 struct nfp_flower_priv *priv = app->priv;
769 struct nfp_ipv6_addr_entry *entry;
770 struct nfp_tun_ipv6_addr payload;
771 int count = 0;
773 memset(&payload, 0, sizeof(struct nfp_tun_ipv6_addr));
774 mutex_lock(&priv->tun.ipv6_off_lock);
775 list_for_each_entry(entry, &priv->tun.ipv6_off_list, list) {
776 if (count >= NFP_FL_IPV6_ADDRS_MAX) {
777 nfp_flower_cmsg_warn(app, "Too many IPv6 tunnel endpoint addresses, some cannot be offloaded.\n");
778 break;
780 payload.ipv6_addr[count++] = entry->ipv6_addr;
782 mutex_unlock(&priv->tun.ipv6_off_lock);
783 payload.count = cpu_to_be32(count);
785 nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_IPS_V6,
786 sizeof(struct nfp_tun_ipv6_addr),
787 &payload, GFP_KERNEL);
790 struct nfp_ipv6_addr_entry *
791 nfp_tunnel_add_ipv6_off(struct nfp_app *app, struct in6_addr *ipv6)
793 struct nfp_flower_priv *priv = app->priv;
794 struct nfp_ipv6_addr_entry *entry;
796 mutex_lock(&priv->tun.ipv6_off_lock);
797 list_for_each_entry(entry, &priv->tun.ipv6_off_list, list)
798 if (!memcmp(&entry->ipv6_addr, ipv6, sizeof(*ipv6))) {
799 entry->ref_count++;
800 mutex_unlock(&priv->tun.ipv6_off_lock);
801 return entry;
804 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
805 if (!entry) {
806 mutex_unlock(&priv->tun.ipv6_off_lock);
807 nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
808 return NULL;
810 entry->ipv6_addr = *ipv6;
811 entry->ref_count = 1;
812 list_add_tail(&entry->list, &priv->tun.ipv6_off_list);
813 mutex_unlock(&priv->tun.ipv6_off_lock);
815 nfp_tun_write_ipv6_list(app);
817 return entry;
820 void
821 nfp_tunnel_put_ipv6_off(struct nfp_app *app, struct nfp_ipv6_addr_entry *entry)
823 struct nfp_flower_priv *priv = app->priv;
824 bool freed = false;
826 mutex_lock(&priv->tun.ipv6_off_lock);
827 if (!--entry->ref_count) {
828 list_del(&entry->list);
829 kfree(entry);
830 freed = true;
832 mutex_unlock(&priv->tun.ipv6_off_lock);
834 if (freed)
835 nfp_tun_write_ipv6_list(app);
838 static int
839 __nfp_tunnel_offload_mac(struct nfp_app *app, u8 *mac, u16 idx, bool del)
841 struct nfp_tun_mac_addr_offload payload;
843 memset(&payload, 0, sizeof(payload));
845 if (del)
846 payload.flags = cpu_to_be16(NFP_TUN_MAC_OFFLOAD_DEL_FLAG);
848 /* FW supports multiple MACs per cmsg but restrict to single. */
849 payload.count = cpu_to_be16(1);
850 payload.index = cpu_to_be16(idx);
851 ether_addr_copy(payload.addr, mac);
853 return nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_MAC,
854 sizeof(struct nfp_tun_mac_addr_offload),
855 &payload, GFP_KERNEL);
858 static bool nfp_tunnel_port_is_phy_repr(int port)
860 if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) ==
861 NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT)
862 return true;
864 return false;
867 static u16 nfp_tunnel_get_mac_idx_from_phy_port_id(int port)
869 return port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT;
872 static u16 nfp_tunnel_get_global_mac_idx_from_ida(int id)
874 return id << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
877 static int nfp_tunnel_get_ida_from_global_mac_idx(u16 nfp_mac_idx)
879 return nfp_mac_idx >> 8;
882 static bool nfp_tunnel_is_mac_idx_global(u16 nfp_mac_idx)
884 return (nfp_mac_idx & 0xff) == NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
887 static struct nfp_tun_offloaded_mac *
888 nfp_tunnel_lookup_offloaded_macs(struct nfp_app *app, u8 *mac)
890 struct nfp_flower_priv *priv = app->priv;
892 return rhashtable_lookup_fast(&priv->tun.offloaded_macs, mac,
893 offloaded_macs_params);
896 static void
897 nfp_tunnel_offloaded_macs_inc_ref_and_link(struct nfp_tun_offloaded_mac *entry,
898 struct net_device *netdev, bool mod)
900 if (nfp_netdev_is_nfp_repr(netdev)) {
901 struct nfp_flower_repr_priv *repr_priv;
902 struct nfp_repr *repr;
904 repr = netdev_priv(netdev);
905 repr_priv = repr->app_priv;
907 /* If modifing MAC, remove repr from old list first. */
908 if (mod)
909 list_del(&repr_priv->mac_list);
911 list_add_tail(&repr_priv->mac_list, &entry->repr_list);
912 } else if (nfp_flower_is_supported_bridge(netdev)) {
913 entry->bridge_count++;
916 entry->ref_count++;
919 static int
920 nfp_tunnel_add_shared_mac(struct nfp_app *app, struct net_device *netdev,
921 int port, bool mod)
923 struct nfp_flower_priv *priv = app->priv;
924 int ida_idx = NFP_MAX_MAC_INDEX, err;
925 struct nfp_tun_offloaded_mac *entry;
926 u16 nfp_mac_idx = 0;
928 entry = nfp_tunnel_lookup_offloaded_macs(app, netdev->dev_addr);
929 if (entry && nfp_tunnel_is_mac_idx_global(entry->index)) {
930 if (entry->bridge_count ||
931 !nfp_flower_is_supported_bridge(netdev)) {
932 nfp_tunnel_offloaded_macs_inc_ref_and_link(entry,
933 netdev, mod);
934 return 0;
937 /* MAC is global but matches need to go to pre_tun table. */
938 nfp_mac_idx = entry->index | NFP_TUN_PRE_TUN_IDX_BIT;
941 if (!nfp_mac_idx) {
942 /* Assign a global index if non-repr or MAC is now shared. */
943 if (entry || !port) {
944 ida_idx = ida_simple_get(&priv->tun.mac_off_ids, 0,
945 NFP_MAX_MAC_INDEX, GFP_KERNEL);
946 if (ida_idx < 0)
947 return ida_idx;
949 nfp_mac_idx =
950 nfp_tunnel_get_global_mac_idx_from_ida(ida_idx);
952 if (nfp_flower_is_supported_bridge(netdev))
953 nfp_mac_idx |= NFP_TUN_PRE_TUN_IDX_BIT;
955 } else {
956 nfp_mac_idx =
957 nfp_tunnel_get_mac_idx_from_phy_port_id(port);
961 if (!entry) {
962 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
963 if (!entry) {
964 err = -ENOMEM;
965 goto err_free_ida;
968 ether_addr_copy(entry->addr, netdev->dev_addr);
969 INIT_LIST_HEAD(&entry->repr_list);
971 if (rhashtable_insert_fast(&priv->tun.offloaded_macs,
972 &entry->ht_node,
973 offloaded_macs_params)) {
974 err = -ENOMEM;
975 goto err_free_entry;
979 err = __nfp_tunnel_offload_mac(app, netdev->dev_addr,
980 nfp_mac_idx, false);
981 if (err) {
982 /* If not shared then free. */
983 if (!entry->ref_count)
984 goto err_remove_hash;
985 goto err_free_ida;
988 entry->index = nfp_mac_idx;
989 nfp_tunnel_offloaded_macs_inc_ref_and_link(entry, netdev, mod);
991 return 0;
993 err_remove_hash:
994 rhashtable_remove_fast(&priv->tun.offloaded_macs, &entry->ht_node,
995 offloaded_macs_params);
996 err_free_entry:
997 kfree(entry);
998 err_free_ida:
999 if (ida_idx != NFP_MAX_MAC_INDEX)
1000 ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
1002 return err;
1005 static int
1006 nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
1007 u8 *mac, bool mod)
1009 struct nfp_flower_priv *priv = app->priv;
1010 struct nfp_flower_repr_priv *repr_priv;
1011 struct nfp_tun_offloaded_mac *entry;
1012 struct nfp_repr *repr;
1013 int ida_idx;
1015 entry = nfp_tunnel_lookup_offloaded_macs(app, mac);
1016 if (!entry)
1017 return 0;
1019 entry->ref_count--;
1020 /* If del is part of a mod then mac_list is still in use elsewheree. */
1021 if (nfp_netdev_is_nfp_repr(netdev) && !mod) {
1022 repr = netdev_priv(netdev);
1023 repr_priv = repr->app_priv;
1024 list_del(&repr_priv->mac_list);
1027 if (nfp_flower_is_supported_bridge(netdev)) {
1028 entry->bridge_count--;
1030 if (!entry->bridge_count && entry->ref_count) {
1031 u16 nfp_mac_idx;
1033 nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
1034 if (__nfp_tunnel_offload_mac(app, mac, nfp_mac_idx,
1035 false)) {
1036 nfp_flower_cmsg_warn(app, "MAC offload index revert failed on %s.\n",
1037 netdev_name(netdev));
1038 return 0;
1041 entry->index = nfp_mac_idx;
1042 return 0;
1046 /* If MAC is now used by 1 repr set the offloaded MAC index to port. */
1047 if (entry->ref_count == 1 && list_is_singular(&entry->repr_list)) {
1048 u16 nfp_mac_idx;
1049 int port, err;
1051 repr_priv = list_first_entry(&entry->repr_list,
1052 struct nfp_flower_repr_priv,
1053 mac_list);
1054 repr = repr_priv->nfp_repr;
1055 port = nfp_repr_get_port_id(repr->netdev);
1056 nfp_mac_idx = nfp_tunnel_get_mac_idx_from_phy_port_id(port);
1057 err = __nfp_tunnel_offload_mac(app, mac, nfp_mac_idx, false);
1058 if (err) {
1059 nfp_flower_cmsg_warn(app, "MAC offload index revert failed on %s.\n",
1060 netdev_name(netdev));
1061 return 0;
1064 ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
1065 ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
1066 entry->index = nfp_mac_idx;
1067 return 0;
1070 if (entry->ref_count)
1071 return 0;
1073 WARN_ON_ONCE(rhashtable_remove_fast(&priv->tun.offloaded_macs,
1074 &entry->ht_node,
1075 offloaded_macs_params));
1076 /* If MAC has global ID then extract and free the ida entry. */
1077 if (nfp_tunnel_is_mac_idx_global(entry->index)) {
1078 ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
1079 ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
1082 kfree(entry);
1084 return __nfp_tunnel_offload_mac(app, mac, 0, true);
1087 static int
1088 nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev,
1089 enum nfp_flower_mac_offload_cmd cmd)
1091 struct nfp_flower_non_repr_priv *nr_priv = NULL;
1092 bool non_repr = false, *mac_offloaded;
1093 u8 *off_mac = NULL;
1094 int err, port = 0;
1096 if (nfp_netdev_is_nfp_repr(netdev)) {
1097 struct nfp_flower_repr_priv *repr_priv;
1098 struct nfp_repr *repr;
1100 repr = netdev_priv(netdev);
1101 if (repr->app != app)
1102 return 0;
1104 repr_priv = repr->app_priv;
1105 if (repr_priv->on_bridge)
1106 return 0;
1108 mac_offloaded = &repr_priv->mac_offloaded;
1109 off_mac = &repr_priv->offloaded_mac_addr[0];
1110 port = nfp_repr_get_port_id(netdev);
1111 if (!nfp_tunnel_port_is_phy_repr(port))
1112 return 0;
1113 } else if (nfp_fl_is_netdev_to_offload(netdev)) {
1114 nr_priv = nfp_flower_non_repr_priv_get(app, netdev);
1115 if (!nr_priv)
1116 return -ENOMEM;
1118 mac_offloaded = &nr_priv->mac_offloaded;
1119 off_mac = &nr_priv->offloaded_mac_addr[0];
1120 non_repr = true;
1121 } else {
1122 return 0;
1125 if (!is_valid_ether_addr(netdev->dev_addr)) {
1126 err = -EINVAL;
1127 goto err_put_non_repr_priv;
1130 if (cmd == NFP_TUNNEL_MAC_OFFLOAD_MOD && !*mac_offloaded)
1131 cmd = NFP_TUNNEL_MAC_OFFLOAD_ADD;
1133 switch (cmd) {
1134 case NFP_TUNNEL_MAC_OFFLOAD_ADD:
1135 err = nfp_tunnel_add_shared_mac(app, netdev, port, false);
1136 if (err)
1137 goto err_put_non_repr_priv;
1139 if (non_repr)
1140 __nfp_flower_non_repr_priv_get(nr_priv);
1142 *mac_offloaded = true;
1143 ether_addr_copy(off_mac, netdev->dev_addr);
1144 break;
1145 case NFP_TUNNEL_MAC_OFFLOAD_DEL:
1146 /* Only attempt delete if add was successful. */
1147 if (!*mac_offloaded)
1148 break;
1150 if (non_repr)
1151 __nfp_flower_non_repr_priv_put(nr_priv);
1153 *mac_offloaded = false;
1155 err = nfp_tunnel_del_shared_mac(app, netdev, netdev->dev_addr,
1156 false);
1157 if (err)
1158 goto err_put_non_repr_priv;
1160 break;
1161 case NFP_TUNNEL_MAC_OFFLOAD_MOD:
1162 /* Ignore if changing to the same address. */
1163 if (ether_addr_equal(netdev->dev_addr, off_mac))
1164 break;
1166 err = nfp_tunnel_add_shared_mac(app, netdev, port, true);
1167 if (err)
1168 goto err_put_non_repr_priv;
1170 /* Delete the previous MAC address. */
1171 err = nfp_tunnel_del_shared_mac(app, netdev, off_mac, true);
1172 if (err)
1173 nfp_flower_cmsg_warn(app, "Failed to remove offload of replaced MAC addr on %s.\n",
1174 netdev_name(netdev));
1176 ether_addr_copy(off_mac, netdev->dev_addr);
1177 break;
1178 default:
1179 err = -EINVAL;
1180 goto err_put_non_repr_priv;
1183 if (non_repr)
1184 __nfp_flower_non_repr_priv_put(nr_priv);
1186 return 0;
1188 err_put_non_repr_priv:
1189 if (non_repr)
1190 __nfp_flower_non_repr_priv_put(nr_priv);
1192 return err;
1195 int nfp_tunnel_mac_event_handler(struct nfp_app *app,
1196 struct net_device *netdev,
1197 unsigned long event, void *ptr)
1199 int err;
1201 if (event == NETDEV_DOWN) {
1202 err = nfp_tunnel_offload_mac(app, netdev,
1203 NFP_TUNNEL_MAC_OFFLOAD_DEL);
1204 if (err)
1205 nfp_flower_cmsg_warn(app, "Failed to delete offload MAC on %s.\n",
1206 netdev_name(netdev));
1207 } else if (event == NETDEV_UP) {
1208 err = nfp_tunnel_offload_mac(app, netdev,
1209 NFP_TUNNEL_MAC_OFFLOAD_ADD);
1210 if (err)
1211 nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n",
1212 netdev_name(netdev));
1213 } else if (event == NETDEV_CHANGEADDR) {
1214 /* Only offload addr change if netdev is already up. */
1215 if (!(netdev->flags & IFF_UP))
1216 return NOTIFY_OK;
1218 err = nfp_tunnel_offload_mac(app, netdev,
1219 NFP_TUNNEL_MAC_OFFLOAD_MOD);
1220 if (err)
1221 nfp_flower_cmsg_warn(app, "Failed to offload MAC change on %s.\n",
1222 netdev_name(netdev));
1223 } else if (event == NETDEV_CHANGEUPPER) {
1224 /* If a repr is attached to a bridge then tunnel packets
1225 * entering the physical port are directed through the bridge
1226 * datapath and cannot be directly detunneled. Therefore,
1227 * associated offloaded MACs and indexes should not be used
1228 * by fw for detunneling.
1230 struct netdev_notifier_changeupper_info *info = ptr;
1231 struct net_device *upper = info->upper_dev;
1232 struct nfp_flower_repr_priv *repr_priv;
1233 struct nfp_repr *repr;
1235 if (!nfp_netdev_is_nfp_repr(netdev) ||
1236 !nfp_flower_is_supported_bridge(upper))
1237 return NOTIFY_OK;
1239 repr = netdev_priv(netdev);
1240 if (repr->app != app)
1241 return NOTIFY_OK;
1243 repr_priv = repr->app_priv;
1245 if (info->linking) {
1246 if (nfp_tunnel_offload_mac(app, netdev,
1247 NFP_TUNNEL_MAC_OFFLOAD_DEL))
1248 nfp_flower_cmsg_warn(app, "Failed to delete offloaded MAC on %s.\n",
1249 netdev_name(netdev));
1250 repr_priv->on_bridge = true;
1251 } else {
1252 repr_priv->on_bridge = false;
1254 if (!(netdev->flags & IFF_UP))
1255 return NOTIFY_OK;
1257 if (nfp_tunnel_offload_mac(app, netdev,
1258 NFP_TUNNEL_MAC_OFFLOAD_ADD))
1259 nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n",
1260 netdev_name(netdev));
1263 return NOTIFY_OK;
1266 int nfp_flower_xmit_pre_tun_flow(struct nfp_app *app,
1267 struct nfp_fl_payload *flow)
1269 struct nfp_flower_priv *app_priv = app->priv;
1270 struct nfp_tun_offloaded_mac *mac_entry;
1271 struct nfp_tun_pre_tun_rule payload;
1272 struct net_device *internal_dev;
1273 int err;
1275 if (app_priv->pre_tun_rule_cnt == NFP_TUN_PRE_TUN_RULE_LIMIT)
1276 return -ENOSPC;
1278 memset(&payload, 0, sizeof(struct nfp_tun_pre_tun_rule));
1280 internal_dev = flow->pre_tun_rule.dev;
1281 payload.vlan_tci = flow->pre_tun_rule.vlan_tci;
1282 payload.host_ctx_id = flow->meta.host_ctx_id;
1284 /* Lookup MAC index for the pre-tunnel rule egress device.
1285 * Note that because the device is always an internal port, it will
1286 * have a constant global index so does not need to be tracked.
1288 mac_entry = nfp_tunnel_lookup_offloaded_macs(app,
1289 internal_dev->dev_addr);
1290 if (!mac_entry)
1291 return -ENOENT;
1293 payload.port_idx = cpu_to_be16(mac_entry->index);
1295 /* Copy mac id and vlan to flow - dev may not exist at delete time. */
1296 flow->pre_tun_rule.vlan_tci = payload.vlan_tci;
1297 flow->pre_tun_rule.port_idx = payload.port_idx;
1299 err = nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_PRE_TUN_RULE,
1300 sizeof(struct nfp_tun_pre_tun_rule),
1301 (unsigned char *)&payload, GFP_KERNEL);
1302 if (err)
1303 return err;
1305 app_priv->pre_tun_rule_cnt++;
1307 return 0;
1310 int nfp_flower_xmit_pre_tun_del_flow(struct nfp_app *app,
1311 struct nfp_fl_payload *flow)
1313 struct nfp_flower_priv *app_priv = app->priv;
1314 struct nfp_tun_pre_tun_rule payload;
1315 u32 tmp_flags = 0;
1316 int err;
1318 memset(&payload, 0, sizeof(struct nfp_tun_pre_tun_rule));
1320 tmp_flags |= NFP_TUN_PRE_TUN_RULE_DEL;
1321 payload.flags = cpu_to_be32(tmp_flags);
1322 payload.vlan_tci = flow->pre_tun_rule.vlan_tci;
1323 payload.port_idx = flow->pre_tun_rule.port_idx;
1325 err = nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_PRE_TUN_RULE,
1326 sizeof(struct nfp_tun_pre_tun_rule),
1327 (unsigned char *)&payload, GFP_KERNEL);
1328 if (err)
1329 return err;
1331 app_priv->pre_tun_rule_cnt--;
1333 return 0;
1336 int nfp_tunnel_config_start(struct nfp_app *app)
1338 struct nfp_flower_priv *priv = app->priv;
1339 int err;
1341 /* Initialise rhash for MAC offload tracking. */
1342 err = rhashtable_init(&priv->tun.offloaded_macs,
1343 &offloaded_macs_params);
1344 if (err)
1345 return err;
1347 ida_init(&priv->tun.mac_off_ids);
1349 /* Initialise priv data for IPv4/v6 offloading. */
1350 mutex_init(&priv->tun.ipv4_off_lock);
1351 INIT_LIST_HEAD(&priv->tun.ipv4_off_list);
1352 mutex_init(&priv->tun.ipv6_off_lock);
1353 INIT_LIST_HEAD(&priv->tun.ipv6_off_list);
1355 /* Initialise priv data for neighbour offloading. */
1356 spin_lock_init(&priv->tun.neigh_off_lock_v4);
1357 INIT_LIST_HEAD(&priv->tun.neigh_off_list_v4);
1358 spin_lock_init(&priv->tun.neigh_off_lock_v6);
1359 INIT_LIST_HEAD(&priv->tun.neigh_off_list_v6);
1360 priv->tun.neigh_nb.notifier_call = nfp_tun_neigh_event_handler;
1362 err = register_netevent_notifier(&priv->tun.neigh_nb);
1363 if (err) {
1364 rhashtable_free_and_destroy(&priv->tun.offloaded_macs,
1365 nfp_check_rhashtable_empty, NULL);
1366 return err;
1369 return 0;
1372 void nfp_tunnel_config_stop(struct nfp_app *app)
1374 struct nfp_offloaded_route *route_entry, *temp;
1375 struct nfp_flower_priv *priv = app->priv;
1376 struct nfp_ipv4_addr_entry *ip_entry;
1377 struct nfp_tun_neigh_v6 ipv6_route;
1378 struct nfp_tun_neigh ipv4_route;
1379 struct list_head *ptr, *storage;
1381 unregister_netevent_notifier(&priv->tun.neigh_nb);
1383 ida_destroy(&priv->tun.mac_off_ids);
1385 /* Free any memory that may be occupied by ipv4 list. */
1386 list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
1387 ip_entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
1388 list_del(&ip_entry->list);
1389 kfree(ip_entry);
1392 mutex_destroy(&priv->tun.ipv6_off_lock);
1394 /* Free memory in the route list and remove entries from fw cache. */
1395 list_for_each_entry_safe(route_entry, temp,
1396 &priv->tun.neigh_off_list_v4, list) {
1397 memset(&ipv4_route, 0, sizeof(ipv4_route));
1398 memcpy(&ipv4_route.dst_ipv4, &route_entry->ip_add,
1399 sizeof(ipv4_route.dst_ipv4));
1400 list_del(&route_entry->list);
1401 kfree(route_entry);
1403 nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH,
1404 sizeof(struct nfp_tun_neigh),
1405 (unsigned char *)&ipv4_route,
1406 GFP_KERNEL);
1409 list_for_each_entry_safe(route_entry, temp,
1410 &priv->tun.neigh_off_list_v6, list) {
1411 memset(&ipv6_route, 0, sizeof(ipv6_route));
1412 memcpy(&ipv6_route.dst_ipv6, &route_entry->ip_add,
1413 sizeof(ipv6_route.dst_ipv6));
1414 list_del(&route_entry->list);
1415 kfree(route_entry);
1417 nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6,
1418 sizeof(struct nfp_tun_neigh),
1419 (unsigned char *)&ipv6_route,
1420 GFP_KERNEL);
1423 /* Destroy rhash. Entries should be cleaned on netdev notifier unreg. */
1424 rhashtable_free_and_destroy(&priv->tun.offloaded_macs,
1425 nfp_check_rhashtable_empty, NULL);