1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/etherdevice.h>
35#include <linux/inetdevice.h>
36#include <net/netevent.h>
37#include <linux/idr.h>
38#include <net/dst_metadata.h>
39#include <net/arp.h>
40
41#include "cmsg.h"
42#include "main.h"
43#include "../nfp_net_repr.h"
44#include "../nfp_net.h"
45
46#define NFP_FL_MAX_ROUTES 32
47
48
49
50
51
52
53
54
55
56
57
58struct nfp_tun_active_tuns {
59 __be32 seq;
60 __be32 count;
61 __be32 flags;
62 struct route_ip_info {
63 __be32 ipv4;
64 __be32 egress_port;
65 __be32 extra[2];
66 } tun_info[];
67};
68
69
70
71
72
73
74
75
76
77struct nfp_tun_neigh {
78 __be32 dst_ipv4;
79 __be32 src_ipv4;
80 u8 dst_addr[ETH_ALEN];
81 u8 src_addr[ETH_ALEN];
82 __be32 port_id;
83};
84
85
86
87
88
89
90
91struct nfp_tun_req_route_ipv4 {
92 __be32 ingress_port;
93 __be32 ipv4_addr;
94 __be32 reserved[2];
95};
96
97
98
99
100
101
102struct nfp_ipv4_route_entry {
103 __be32 ipv4_addr;
104 struct list_head list;
105};
106
107#define NFP_FL_IPV4_ADDRS_MAX 32
108
109
110
111
112
113
114struct nfp_tun_ipv4_addr {
115 __be32 count;
116 __be32 ipv4_addr[NFP_FL_IPV4_ADDRS_MAX];
117};
118
119
120
121
122
123
124
125struct nfp_ipv4_addr_entry {
126 __be32 ipv4_addr;
127 int ref_count;
128 struct list_head list;
129};
130
131
132
133
134
135
136
137
138
139struct nfp_tun_mac_addr {
140 __be16 reserved;
141 __be16 count;
142 struct index_mac_addr {
143 __be16 index;
144 u8 addr[ETH_ALEN];
145 } addresses[];
146};
147
148
149
150
151
152
153
154struct nfp_tun_mac_offload_entry {
155 __be16 index;
156 u8 addr[ETH_ALEN];
157 struct list_head list;
158};
159
160#define NFP_MAX_MAC_INDEX 0xff
161
162
163
164
165
166
167
168struct nfp_tun_mac_non_nfp_idx {
169 int ifindex;
170 u8 index;
171 struct list_head list;
172};
173
174void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
175{
176 struct nfp_tun_active_tuns *payload;
177 struct net_device *netdev;
178 int count, i, pay_len;
179 struct neighbour *n;
180 __be32 ipv4_addr;
181 u32 port;
182
183 payload = nfp_flower_cmsg_get_data(skb);
184 count = be32_to_cpu(payload->count);
185 if (count > NFP_FL_MAX_ROUTES) {
186 nfp_flower_cmsg_warn(app, "Tunnel keep-alive request exceeds max routes.\n");
187 return;
188 }
189
190 pay_len = nfp_flower_cmsg_get_data_len(skb);
191 if (pay_len != sizeof(struct nfp_tun_active_tuns) +
192 sizeof(struct route_ip_info) * count) {
193 nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
194 return;
195 }
196
197 for (i = 0; i < count; i++) {
198 ipv4_addr = payload->tun_info[i].ipv4;
199 port = be32_to_cpu(payload->tun_info[i].egress_port);
200 netdev = nfp_app_repr_get(app, port);
201 if (!netdev)
202 continue;
203
204 n = neigh_lookup(&arp_tbl, &ipv4_addr, netdev);
205 if (!n)
206 continue;
207
208
209 neigh_event_send(n, NULL);
210 neigh_release(n);
211 }
212}
213
214static bool nfp_tun_is_netdev_to_offload(struct net_device *netdev)
215{
216 if (!netdev->rtnl_link_ops)
217 return false;
218 if (!strcmp(netdev->rtnl_link_ops->kind, "openvswitch"))
219 return true;
220 if (!strcmp(netdev->rtnl_link_ops->kind, "vxlan"))
221 return true;
222
223 return false;
224}
225
226static int
227nfp_flower_xmit_tun_conf(struct nfp_app *app, u8 mtype, u16 plen, void *pdata,
228 gfp_t flag)
229{
230 struct sk_buff *skb;
231 unsigned char *msg;
232
233 skb = nfp_flower_cmsg_alloc(app, plen, mtype, flag);
234 if (!skb)
235 return -ENOMEM;
236
237 msg = nfp_flower_cmsg_get_data(skb);
238 memcpy(msg, pdata, nfp_flower_cmsg_get_data_len(skb));
239
240 nfp_ctrl_tx(app->ctrl, skb);
241 return 0;
242}
243
244static bool nfp_tun_has_route(struct nfp_app *app, __be32 ipv4_addr)
245{
246 struct nfp_flower_priv *priv = app->priv;
247 struct nfp_ipv4_route_entry *entry;
248 struct list_head *ptr, *storage;
249
250 spin_lock_bh(&priv->nfp_neigh_off_lock);
251 list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) {
252 entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
253 if (entry->ipv4_addr == ipv4_addr) {
254 spin_unlock_bh(&priv->nfp_neigh_off_lock);
255 return true;
256 }
257 }
258 spin_unlock_bh(&priv->nfp_neigh_off_lock);
259 return false;
260}
261
262static void nfp_tun_add_route_to_cache(struct nfp_app *app, __be32 ipv4_addr)
263{
264 struct nfp_flower_priv *priv = app->priv;
265 struct nfp_ipv4_route_entry *entry;
266 struct list_head *ptr, *storage;
267
268 spin_lock_bh(&priv->nfp_neigh_off_lock);
269 list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) {
270 entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
271 if (entry->ipv4_addr == ipv4_addr) {
272 spin_unlock_bh(&priv->nfp_neigh_off_lock);
273 return;
274 }
275 }
276 entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
277 if (!entry) {
278 spin_unlock_bh(&priv->nfp_neigh_off_lock);
279 nfp_flower_cmsg_warn(app, "Mem error when storing new route.\n");
280 return;
281 }
282
283 entry->ipv4_addr = ipv4_addr;
284 list_add_tail(&entry->list, &priv->nfp_neigh_off_list);
285 spin_unlock_bh(&priv->nfp_neigh_off_lock);
286}
287
288static void nfp_tun_del_route_from_cache(struct nfp_app *app, __be32 ipv4_addr)
289{
290 struct nfp_flower_priv *priv = app->priv;
291 struct nfp_ipv4_route_entry *entry;
292 struct list_head *ptr, *storage;
293
294 spin_lock_bh(&priv->nfp_neigh_off_lock);
295 list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) {
296 entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
297 if (entry->ipv4_addr == ipv4_addr) {
298 list_del(&entry->list);
299 kfree(entry);
300 break;
301 }
302 }
303 spin_unlock_bh(&priv->nfp_neigh_off_lock);
304}
305
306static void
307nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
308 struct flowi4 *flow, struct neighbour *neigh, gfp_t flag)
309{
310 struct nfp_tun_neigh payload;
311
312
313 if (!nfp_netdev_is_nfp_repr(netdev))
314 return;
315
316 memset(&payload, 0, sizeof(struct nfp_tun_neigh));
317 payload.dst_ipv4 = flow->daddr;
318
319
320 if (!(neigh->nud_state & NUD_VALID)) {
321 nfp_tun_del_route_from_cache(app, payload.dst_ipv4);
322
323 neigh_event_send(neigh, NULL);
324 goto send_msg;
325 }
326
327
328 payload.src_ipv4 = flow->saddr;
329 ether_addr_copy(payload.src_addr, netdev->dev_addr);
330 neigh_ha_snapshot(payload.dst_addr, neigh, netdev);
331 payload.port_id = cpu_to_be32(nfp_repr_get_port_id(netdev));
332
333 nfp_tun_add_route_to_cache(app, payload.dst_ipv4);
334
335send_msg:
336 nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH,
337 sizeof(struct nfp_tun_neigh),
338 (unsigned char *)&payload, flag);
339}
340
341static int
342nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
343 void *ptr)
344{
345 struct nfp_flower_priv *app_priv;
346 struct netevent_redirect *redir;
347 struct flowi4 flow = {};
348 struct neighbour *n;
349 struct nfp_app *app;
350 struct rtable *rt;
351 int err;
352
353 switch (event) {
354 case NETEVENT_REDIRECT:
355 redir = (struct netevent_redirect *)ptr;
356 n = redir->neigh;
357 break;
358 case NETEVENT_NEIGH_UPDATE:
359 n = (struct neighbour *)ptr;
360 break;
361 default:
362 return NOTIFY_DONE;
363 }
364
365 flow.daddr = *(__be32 *)n->primary_key;
366
367
368 if (!nfp_netdev_is_nfp_repr(n->dev))
369 return NOTIFY_DONE;
370
371 app_priv = container_of(nb, struct nfp_flower_priv, nfp_tun_neigh_nb);
372 app = app_priv->app;
373
374
375 if (!nfp_tun_has_route(app, flow.daddr))
376 return NOTIFY_DONE;
377
378#if IS_ENABLED(CONFIG_INET)
379
380 rt = ip_route_output_key(dev_net(n->dev), &flow);
381 err = PTR_ERR_OR_ZERO(rt);
382 if (err)
383 return NOTIFY_DONE;
384#else
385 return NOTIFY_DONE;
386#endif
387
388 flow.flowi4_proto = IPPROTO_UDP;
389 nfp_tun_write_neigh(n->dev, app, &flow, n, GFP_ATOMIC);
390
391 return NOTIFY_OK;
392}
393
394void nfp_tunnel_request_route(struct nfp_app *app, struct sk_buff *skb)
395{
396 struct nfp_tun_req_route_ipv4 *payload;
397 struct net_device *netdev;
398 struct flowi4 flow = {};
399 struct neighbour *n;
400 struct rtable *rt;
401 int err;
402
403 payload = nfp_flower_cmsg_get_data(skb);
404
405 netdev = nfp_app_repr_get(app, be32_to_cpu(payload->ingress_port));
406 if (!netdev)
407 goto route_fail_warning;
408
409 flow.daddr = payload->ipv4_addr;
410 flow.flowi4_proto = IPPROTO_UDP;
411
412#if IS_ENABLED(CONFIG_INET)
413
414 rt = ip_route_output_key(dev_net(netdev), &flow);
415 err = PTR_ERR_OR_ZERO(rt);
416 if (err)
417 goto route_fail_warning;
418#else
419 goto route_fail_warning;
420#endif
421
422
423 n = dst_neigh_lookup(&rt->dst, &flow.daddr);
424 ip_rt_put(rt);
425 if (!n)
426 goto route_fail_warning;
427 nfp_tun_write_neigh(n->dev, app, &flow, n, GFP_KERNEL);
428 neigh_release(n);
429 return;
430
431route_fail_warning:
432 nfp_flower_cmsg_warn(app, "Requested route not found.\n");
433}
434
435static void nfp_tun_write_ipv4_list(struct nfp_app *app)
436{
437 struct nfp_flower_priv *priv = app->priv;
438 struct nfp_ipv4_addr_entry *entry;
439 struct nfp_tun_ipv4_addr payload;
440 struct list_head *ptr, *storage;
441 int count;
442
443 memset(&payload, 0, sizeof(struct nfp_tun_ipv4_addr));
444 mutex_lock(&priv->nfp_ipv4_off_lock);
445 count = 0;
446 list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) {
447 if (count >= NFP_FL_IPV4_ADDRS_MAX) {
448 mutex_unlock(&priv->nfp_ipv4_off_lock);
449 nfp_flower_cmsg_warn(app, "IPv4 offload exceeds limit.\n");
450 return;
451 }
452 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
453 payload.ipv4_addr[count++] = entry->ipv4_addr;
454 }
455 payload.count = cpu_to_be32(count);
456 mutex_unlock(&priv->nfp_ipv4_off_lock);
457
458 nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_IPS,
459 sizeof(struct nfp_tun_ipv4_addr),
460 &payload, GFP_KERNEL);
461}
462
463void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4)
464{
465 struct nfp_flower_priv *priv = app->priv;
466 struct nfp_ipv4_addr_entry *entry;
467 struct list_head *ptr, *storage;
468
469 mutex_lock(&priv->nfp_ipv4_off_lock);
470 list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) {
471 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
472 if (entry->ipv4_addr == ipv4) {
473 entry->ref_count++;
474 mutex_unlock(&priv->nfp_ipv4_off_lock);
475 return;
476 }
477 }
478
479 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
480 if (!entry) {
481 mutex_unlock(&priv->nfp_ipv4_off_lock);
482 nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
483 return;
484 }
485 entry->ipv4_addr = ipv4;
486 entry->ref_count = 1;
487 list_add_tail(&entry->list, &priv->nfp_ipv4_off_list);
488 mutex_unlock(&priv->nfp_ipv4_off_lock);
489
490 nfp_tun_write_ipv4_list(app);
491}
492
493void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4)
494{
495 struct nfp_flower_priv *priv = app->priv;
496 struct nfp_ipv4_addr_entry *entry;
497 struct list_head *ptr, *storage;
498
499 mutex_lock(&priv->nfp_ipv4_off_lock);
500 list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) {
501 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
502 if (entry->ipv4_addr == ipv4) {
503 entry->ref_count--;
504 if (!entry->ref_count) {
505 list_del(&entry->list);
506 kfree(entry);
507 }
508 break;
509 }
510 }
511 mutex_unlock(&priv->nfp_ipv4_off_lock);
512
513 nfp_tun_write_ipv4_list(app);
514}
515
516void nfp_tunnel_write_macs(struct nfp_app *app)
517{
518 struct nfp_flower_priv *priv = app->priv;
519 struct nfp_tun_mac_offload_entry *entry;
520 struct nfp_tun_mac_addr *payload;
521 struct list_head *ptr, *storage;
522 int mac_count, err, pay_size;
523
524 mutex_lock(&priv->nfp_mac_off_lock);
525 if (!priv->nfp_mac_off_count) {
526 mutex_unlock(&priv->nfp_mac_off_lock);
527 return;
528 }
529
530 pay_size = sizeof(struct nfp_tun_mac_addr) +
531 sizeof(struct index_mac_addr) * priv->nfp_mac_off_count;
532
533 payload = kzalloc(pay_size, GFP_KERNEL);
534 if (!payload) {
535 mutex_unlock(&priv->nfp_mac_off_lock);
536 return;
537 }
538
539 payload->count = cpu_to_be16(priv->nfp_mac_off_count);
540
541 mac_count = 0;
542 list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) {
543 entry = list_entry(ptr, struct nfp_tun_mac_offload_entry,
544 list);
545 payload->addresses[mac_count].index = entry->index;
546 ether_addr_copy(payload->addresses[mac_count].addr,
547 entry->addr);
548 mac_count++;
549 }
550
551 err = nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_MAC,
552 pay_size, payload, GFP_KERNEL);
553
554 kfree(payload);
555
556 if (err) {
557 mutex_unlock(&priv->nfp_mac_off_lock);
558
559 return;
560 }
561
562
563 list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) {
564 entry = list_entry(ptr, struct nfp_tun_mac_offload_entry,
565 list);
566 list_del(&entry->list);
567 kfree(entry);
568 }
569
570 priv->nfp_mac_off_count = 0;
571 mutex_unlock(&priv->nfp_mac_off_lock);
572}
573
574static int nfp_tun_get_mac_idx(struct nfp_app *app, int ifindex)
575{
576 struct nfp_flower_priv *priv = app->priv;
577 struct nfp_tun_mac_non_nfp_idx *entry;
578 struct list_head *ptr, *storage;
579 int idx;
580
581 mutex_lock(&priv->nfp_mac_index_lock);
582 list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) {
583 entry = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list);
584 if (entry->ifindex == ifindex) {
585 idx = entry->index;
586 mutex_unlock(&priv->nfp_mac_index_lock);
587 return idx;
588 }
589 }
590
591 idx = ida_simple_get(&priv->nfp_mac_off_ids, 0,
592 NFP_MAX_MAC_INDEX, GFP_KERNEL);
593 if (idx < 0) {
594 mutex_unlock(&priv->nfp_mac_index_lock);
595 return idx;
596 }
597
598 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
599 if (!entry) {
600 mutex_unlock(&priv->nfp_mac_index_lock);
601 return -ENOMEM;
602 }
603 entry->ifindex = ifindex;
604 entry->index = idx;
605 list_add_tail(&entry->list, &priv->nfp_mac_index_list);
606 mutex_unlock(&priv->nfp_mac_index_lock);
607
608 return idx;
609}
610
611static void nfp_tun_del_mac_idx(struct nfp_app *app, int ifindex)
612{
613 struct nfp_flower_priv *priv = app->priv;
614 struct nfp_tun_mac_non_nfp_idx *entry;
615 struct list_head *ptr, *storage;
616
617 mutex_lock(&priv->nfp_mac_index_lock);
618 list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) {
619 entry = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx, list);
620 if (entry->ifindex == ifindex) {
621 ida_simple_remove(&priv->nfp_mac_off_ids,
622 entry->index);
623 list_del(&entry->list);
624 kfree(entry);
625 break;
626 }
627 }
628 mutex_unlock(&priv->nfp_mac_index_lock);
629}
630
631static void nfp_tun_add_to_mac_offload_list(struct net_device *netdev,
632 struct nfp_app *app)
633{
634 struct nfp_flower_priv *priv = app->priv;
635 struct nfp_tun_mac_offload_entry *entry;
636 u16 nfp_mac_idx;
637 int port = 0;
638
639
640 if (!is_valid_ether_addr(netdev->dev_addr))
641 return;
642
643 if (nfp_netdev_is_nfp_repr(netdev))
644 port = nfp_repr_get_port_id(netdev);
645 else if (!nfp_tun_is_netdev_to_offload(netdev))
646 return;
647
648 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
649 if (!entry) {
650 nfp_flower_cmsg_warn(app, "Mem fail when offloading MAC.\n");
651 return;
652 }
653
654 if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) ==
655 NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT) {
656 nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT;
657 } else if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) ==
658 NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT) {
659 port = FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC, port);
660 nfp_mac_idx = port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT;
661 } else {
662
663 int idx = nfp_tun_get_mac_idx(app, netdev->ifindex);
664
665 if (idx < 0) {
666 nfp_flower_cmsg_warn(app, "Can't assign non-repr MAC index.\n");
667 kfree(entry);
668 return;
669 }
670 nfp_mac_idx = idx << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
671 }
672
673 entry->index = cpu_to_be16(nfp_mac_idx);
674 ether_addr_copy(entry->addr, netdev->dev_addr);
675
676 mutex_lock(&priv->nfp_mac_off_lock);
677 priv->nfp_mac_off_count++;
678 list_add_tail(&entry->list, &priv->nfp_mac_off_list);
679 mutex_unlock(&priv->nfp_mac_off_lock);
680}
681
682static int nfp_tun_mac_event_handler(struct notifier_block *nb,
683 unsigned long event, void *ptr)
684{
685 struct nfp_flower_priv *app_priv;
686 struct net_device *netdev;
687 struct nfp_app *app;
688
689 if (event == NETDEV_DOWN || event == NETDEV_UNREGISTER) {
690 app_priv = container_of(nb, struct nfp_flower_priv,
691 nfp_tun_mac_nb);
692 app = app_priv->app;
693 netdev = netdev_notifier_info_to_dev(ptr);
694
695
696 if (nfp_tun_is_netdev_to_offload(netdev))
697 nfp_tun_del_mac_idx(app, netdev->ifindex);
698 } else if (event == NETDEV_UP || event == NETDEV_CHANGEADDR ||
699 event == NETDEV_REGISTER) {
700 app_priv = container_of(nb, struct nfp_flower_priv,
701 nfp_tun_mac_nb);
702 app = app_priv->app;
703 netdev = netdev_notifier_info_to_dev(ptr);
704
705 nfp_tun_add_to_mac_offload_list(netdev, app);
706
707
708 nfp_tunnel_write_macs(app);
709 }
710 return NOTIFY_OK;
711}
712
713int nfp_tunnel_config_start(struct nfp_app *app)
714{
715 struct nfp_flower_priv *priv = app->priv;
716 struct net_device *netdev;
717 int err;
718
719
720 priv->nfp_mac_off_count = 0;
721 mutex_init(&priv->nfp_mac_off_lock);
722 INIT_LIST_HEAD(&priv->nfp_mac_off_list);
723 priv->nfp_tun_mac_nb.notifier_call = nfp_tun_mac_event_handler;
724 mutex_init(&priv->nfp_mac_index_lock);
725 INIT_LIST_HEAD(&priv->nfp_mac_index_list);
726 ida_init(&priv->nfp_mac_off_ids);
727
728
729 mutex_init(&priv->nfp_ipv4_off_lock);
730 INIT_LIST_HEAD(&priv->nfp_ipv4_off_list);
731
732
733 spin_lock_init(&priv->nfp_neigh_off_lock);
734 INIT_LIST_HEAD(&priv->nfp_neigh_off_list);
735 priv->nfp_tun_neigh_nb.notifier_call = nfp_tun_neigh_event_handler;
736
737 err = register_netdevice_notifier(&priv->nfp_tun_mac_nb);
738 if (err)
739 goto err_free_mac_ida;
740
741 err = register_netevent_notifier(&priv->nfp_tun_neigh_nb);
742 if (err)
743 goto err_unreg_mac_nb;
744
745
746 rtnl_lock();
747 for_each_netdev(&init_net, netdev)
748 nfp_tun_add_to_mac_offload_list(netdev, app);
749 rtnl_unlock();
750
751 return 0;
752
753err_unreg_mac_nb:
754 unregister_netdevice_notifier(&priv->nfp_tun_mac_nb);
755err_free_mac_ida:
756 ida_destroy(&priv->nfp_mac_off_ids);
757 return err;
758}
759
760void nfp_tunnel_config_stop(struct nfp_app *app)
761{
762 struct nfp_tun_mac_offload_entry *mac_entry;
763 struct nfp_flower_priv *priv = app->priv;
764 struct nfp_ipv4_route_entry *route_entry;
765 struct nfp_tun_mac_non_nfp_idx *mac_idx;
766 struct nfp_ipv4_addr_entry *ip_entry;
767 struct list_head *ptr, *storage;
768
769 unregister_netdevice_notifier(&priv->nfp_tun_mac_nb);
770 unregister_netevent_notifier(&priv->nfp_tun_neigh_nb);
771
772
773 list_for_each_safe(ptr, storage, &priv->nfp_mac_off_list) {
774 mac_entry = list_entry(ptr, struct nfp_tun_mac_offload_entry,
775 list);
776 list_del(&mac_entry->list);
777 kfree(mac_entry);
778 }
779
780
781 list_for_each_safe(ptr, storage, &priv->nfp_mac_index_list) {
782 mac_idx = list_entry(ptr, struct nfp_tun_mac_non_nfp_idx,
783 list);
784 list_del(&mac_idx->list);
785 kfree(mac_idx);
786 }
787
788 ida_destroy(&priv->nfp_mac_off_ids);
789
790
791 list_for_each_safe(ptr, storage, &priv->nfp_ipv4_off_list) {
792 ip_entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
793 list_del(&ip_entry->list);
794 kfree(ip_entry);
795 }
796
797
798 list_for_each_safe(ptr, storage, &priv->nfp_neigh_off_list) {
799 route_entry = list_entry(ptr, struct nfp_ipv4_route_entry,
800 list);
801 list_del(&route_entry->list);
802 kfree(route_entry);
803 }
804}
805