Merge tag 'for-linus-20190524' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / drivers / net / ethernet / netronome / nfp / flower / tunnel_conf.c
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 /**
19  * struct nfp_tun_active_tuns - periodic message of active tunnels
20  * @seq:                sequence number of the message
21  * @count:              number of tunnels report in message
22  * @flags:              options part of the request
23  * @tun_info.ipv4:              dest IPv4 address of active route
24  * @tun_info.egress_port:       port the encapsulated packet egressed
25  * @tun_info.extra:             reserved for future use
26  * @tun_info:           tunnels that have sent traffic in reported period
27  */
28 struct nfp_tun_active_tuns {
29         __be32 seq;
30         __be32 count;
31         __be32 flags;
32         struct route_ip_info {
33                 __be32 ipv4;
34                 __be32 egress_port;
35                 __be32 extra[2];
36         } tun_info[];
37 };
38
39 /**
40  * struct nfp_tun_neigh - neighbour/route entry on the NFP
41  * @dst_ipv4:   destination IPv4 address
42  * @src_ipv4:   source IPv4 address
43  * @dst_addr:   destination MAC address
44  * @src_addr:   source MAC address
45  * @port_id:    NFP port to output packet on - associated with source IPv4
46  */
47 struct nfp_tun_neigh {
48         __be32 dst_ipv4;
49         __be32 src_ipv4;
50         u8 dst_addr[ETH_ALEN];
51         u8 src_addr[ETH_ALEN];
52         __be32 port_id;
53 };
54
55 /**
56  * struct nfp_tun_req_route_ipv4 - NFP requests a route/neighbour lookup
57  * @ingress_port:       ingress port of packet that signalled request
58  * @ipv4_addr:          destination ipv4 address for route
59  * @reserved:           reserved for future use
60  */
61 struct nfp_tun_req_route_ipv4 {
62         __be32 ingress_port;
63         __be32 ipv4_addr;
64         __be32 reserved[2];
65 };
66
67 /**
68  * struct nfp_ipv4_route_entry - routes that are offloaded to the NFP
69  * @ipv4_addr:  destination of route
70  * @list:       list pointer
71  */
72 struct nfp_ipv4_route_entry {
73         __be32 ipv4_addr;
74         struct list_head list;
75 };
76
77 #define NFP_FL_IPV4_ADDRS_MAX        32
78
79 /**
80  * struct nfp_tun_ipv4_addr - set the IP address list on the NFP
81  * @count:      number of IPs populated in the array
82  * @ipv4_addr:  array of IPV4_ADDRS_MAX 32 bit IPv4 addresses
83  */
84 struct nfp_tun_ipv4_addr {
85         __be32 count;
86         __be32 ipv4_addr[NFP_FL_IPV4_ADDRS_MAX];
87 };
88
89 /**
90  * struct nfp_ipv4_addr_entry - cached IPv4 addresses
91  * @ipv4_addr:  IP address
92  * @ref_count:  number of rules currently using this IP
93  * @list:       list pointer
94  */
95 struct nfp_ipv4_addr_entry {
96         __be32 ipv4_addr;
97         int ref_count;
98         struct list_head list;
99 };
100
101 #define NFP_TUN_MAC_OFFLOAD_DEL_FLAG    0x2
102
103 /**
104  * struct nfp_tun_mac_addr_offload - configure MAC address of tunnel EP on NFP
105  * @flags:      MAC address offload options
106  * @count:      number of MAC addresses in the message (should be 1)
107  * @index:      index of MAC address in the lookup table
108  * @addr:       interface MAC address
109  */
110 struct nfp_tun_mac_addr_offload {
111         __be16 flags;
112         __be16 count;
113         __be16 index;
114         u8 addr[ETH_ALEN];
115 };
116
117 enum nfp_flower_mac_offload_cmd {
118         NFP_TUNNEL_MAC_OFFLOAD_ADD =            0,
119         NFP_TUNNEL_MAC_OFFLOAD_DEL =            1,
120         NFP_TUNNEL_MAC_OFFLOAD_MOD =            2,
121 };
122
123 #define NFP_MAX_MAC_INDEX       0xff
124
125 /**
126  * struct nfp_tun_offloaded_mac - hashtable entry for an offloaded MAC
127  * @ht_node:    Hashtable entry
128  * @addr:       Offloaded MAC address
129  * @index:      Offloaded index for given MAC address
130  * @ref_count:  Number of devs using this MAC address
131  * @repr_list:  List of reprs sharing this MAC address
132  */
133 struct nfp_tun_offloaded_mac {
134         struct rhash_head ht_node;
135         u8 addr[ETH_ALEN];
136         u16 index;
137         int ref_count;
138         struct list_head repr_list;
139 };
140
141 static const struct rhashtable_params offloaded_macs_params = {
142         .key_offset     = offsetof(struct nfp_tun_offloaded_mac, addr),
143         .head_offset    = offsetof(struct nfp_tun_offloaded_mac, ht_node),
144         .key_len        = ETH_ALEN,
145         .automatic_shrinking    = true,
146 };
147
148 void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
149 {
150         struct nfp_tun_active_tuns *payload;
151         struct net_device *netdev;
152         int count, i, pay_len;
153         struct neighbour *n;
154         __be32 ipv4_addr;
155         u32 port;
156
157         payload = nfp_flower_cmsg_get_data(skb);
158         count = be32_to_cpu(payload->count);
159         if (count > NFP_FL_MAX_ROUTES) {
160                 nfp_flower_cmsg_warn(app, "Tunnel keep-alive request exceeds max routes.\n");
161                 return;
162         }
163
164         pay_len = nfp_flower_cmsg_get_data_len(skb);
165         if (pay_len != sizeof(struct nfp_tun_active_tuns) +
166             sizeof(struct route_ip_info) * count) {
167                 nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
168                 return;
169         }
170
171         rcu_read_lock();
172         for (i = 0; i < count; i++) {
173                 ipv4_addr = payload->tun_info[i].ipv4;
174                 port = be32_to_cpu(payload->tun_info[i].egress_port);
175                 netdev = nfp_app_dev_get(app, port, NULL);
176                 if (!netdev)
177                         continue;
178
179                 n = neigh_lookup(&arp_tbl, &ipv4_addr, netdev);
180                 if (!n)
181                         continue;
182
183                 /* Update the used timestamp of neighbour */
184                 neigh_event_send(n, NULL);
185                 neigh_release(n);
186         }
187         rcu_read_unlock();
188 }
189
190 static int
191 nfp_flower_xmit_tun_conf(struct nfp_app *app, u8 mtype, u16 plen, void *pdata,
192                          gfp_t flag)
193 {
194         struct sk_buff *skb;
195         unsigned char *msg;
196
197         skb = nfp_flower_cmsg_alloc(app, plen, mtype, flag);
198         if (!skb)
199                 return -ENOMEM;
200
201         msg = nfp_flower_cmsg_get_data(skb);
202         memcpy(msg, pdata, nfp_flower_cmsg_get_data_len(skb));
203
204         nfp_ctrl_tx(app->ctrl, skb);
205         return 0;
206 }
207
208 static bool nfp_tun_has_route(struct nfp_app *app, __be32 ipv4_addr)
209 {
210         struct nfp_flower_priv *priv = app->priv;
211         struct nfp_ipv4_route_entry *entry;
212         struct list_head *ptr, *storage;
213
214         spin_lock_bh(&priv->tun.neigh_off_lock);
215         list_for_each_safe(ptr, storage, &priv->tun.neigh_off_list) {
216                 entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
217                 if (entry->ipv4_addr == ipv4_addr) {
218                         spin_unlock_bh(&priv->tun.neigh_off_lock);
219                         return true;
220                 }
221         }
222         spin_unlock_bh(&priv->tun.neigh_off_lock);
223         return false;
224 }
225
226 static void nfp_tun_add_route_to_cache(struct nfp_app *app, __be32 ipv4_addr)
227 {
228         struct nfp_flower_priv *priv = app->priv;
229         struct nfp_ipv4_route_entry *entry;
230         struct list_head *ptr, *storage;
231
232         spin_lock_bh(&priv->tun.neigh_off_lock);
233         list_for_each_safe(ptr, storage, &priv->tun.neigh_off_list) {
234                 entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
235                 if (entry->ipv4_addr == ipv4_addr) {
236                         spin_unlock_bh(&priv->tun.neigh_off_lock);
237                         return;
238                 }
239         }
240         entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
241         if (!entry) {
242                 spin_unlock_bh(&priv->tun.neigh_off_lock);
243                 nfp_flower_cmsg_warn(app, "Mem error when storing new route.\n");
244                 return;
245         }
246
247         entry->ipv4_addr = ipv4_addr;
248         list_add_tail(&entry->list, &priv->tun.neigh_off_list);
249         spin_unlock_bh(&priv->tun.neigh_off_lock);
250 }
251
252 static void nfp_tun_del_route_from_cache(struct nfp_app *app, __be32 ipv4_addr)
253 {
254         struct nfp_flower_priv *priv = app->priv;
255         struct nfp_ipv4_route_entry *entry;
256         struct list_head *ptr, *storage;
257
258         spin_lock_bh(&priv->tun.neigh_off_lock);
259         list_for_each_safe(ptr, storage, &priv->tun.neigh_off_list) {
260                 entry = list_entry(ptr, struct nfp_ipv4_route_entry, list);
261                 if (entry->ipv4_addr == ipv4_addr) {
262                         list_del(&entry->list);
263                         kfree(entry);
264                         break;
265                 }
266         }
267         spin_unlock_bh(&priv->tun.neigh_off_lock);
268 }
269
270 static void
271 nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
272                     struct flowi4 *flow, struct neighbour *neigh, gfp_t flag)
273 {
274         struct nfp_tun_neigh payload;
275         u32 port_id;
276
277         port_id = nfp_flower_get_port_id_from_netdev(app, netdev);
278         if (!port_id)
279                 return;
280
281         memset(&payload, 0, sizeof(struct nfp_tun_neigh));
282         payload.dst_ipv4 = flow->daddr;
283
284         /* If entry has expired send dst IP with all other fields 0. */
285         if (!(neigh->nud_state & NUD_VALID) || neigh->dead) {
286                 nfp_tun_del_route_from_cache(app, payload.dst_ipv4);
287                 /* Trigger ARP to verify invalid neighbour state. */
288                 neigh_event_send(neigh, NULL);
289                 goto send_msg;
290         }
291
292         /* Have a valid neighbour so populate rest of entry. */
293         payload.src_ipv4 = flow->saddr;
294         ether_addr_copy(payload.src_addr, netdev->dev_addr);
295         neigh_ha_snapshot(payload.dst_addr, neigh, netdev);
296         payload.port_id = cpu_to_be32(port_id);
297         /* Add destination of new route to NFP cache. */
298         nfp_tun_add_route_to_cache(app, payload.dst_ipv4);
299
300 send_msg:
301         nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_NEIGH,
302                                  sizeof(struct nfp_tun_neigh),
303                                  (unsigned char *)&payload, flag);
304 }
305
306 static int
307 nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
308                             void *ptr)
309 {
310         struct nfp_flower_priv *app_priv;
311         struct netevent_redirect *redir;
312         struct flowi4 flow = {};
313         struct neighbour *n;
314         struct nfp_app *app;
315         struct rtable *rt;
316         int err;
317
318         switch (event) {
319         case NETEVENT_REDIRECT:
320                 redir = (struct netevent_redirect *)ptr;
321                 n = redir->neigh;
322                 break;
323         case NETEVENT_NEIGH_UPDATE:
324                 n = (struct neighbour *)ptr;
325                 break;
326         default:
327                 return NOTIFY_DONE;
328         }
329
330         flow.daddr = *(__be32 *)n->primary_key;
331
332         /* Only concerned with route changes for representors. */
333         if (!nfp_netdev_is_nfp_repr(n->dev))
334                 return NOTIFY_DONE;
335
336         app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb);
337         app = app_priv->app;
338
339         /* Only concerned with changes to routes already added to NFP. */
340         if (!nfp_tun_has_route(app, flow.daddr))
341                 return NOTIFY_DONE;
342
343 #if IS_ENABLED(CONFIG_INET)
344         /* Do a route lookup to populate flow data. */
345         rt = ip_route_output_key(dev_net(n->dev), &flow);
346         err = PTR_ERR_OR_ZERO(rt);
347         if (err)
348                 return NOTIFY_DONE;
349
350         ip_rt_put(rt);
351 #else
352         return NOTIFY_DONE;
353 #endif
354
355         flow.flowi4_proto = IPPROTO_UDP;
356         nfp_tun_write_neigh(n->dev, app, &flow, n, GFP_ATOMIC);
357
358         return NOTIFY_OK;
359 }
360
361 void nfp_tunnel_request_route(struct nfp_app *app, struct sk_buff *skb)
362 {
363         struct nfp_tun_req_route_ipv4 *payload;
364         struct net_device *netdev;
365         struct flowi4 flow = {};
366         struct neighbour *n;
367         struct rtable *rt;
368         int err;
369
370         payload = nfp_flower_cmsg_get_data(skb);
371
372         rcu_read_lock();
373         netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
374         if (!netdev)
375                 goto fail_rcu_unlock;
376
377         flow.daddr = payload->ipv4_addr;
378         flow.flowi4_proto = IPPROTO_UDP;
379
380 #if IS_ENABLED(CONFIG_INET)
381         /* Do a route lookup on same namespace as ingress port. */
382         rt = ip_route_output_key(dev_net(netdev), &flow);
383         err = PTR_ERR_OR_ZERO(rt);
384         if (err)
385                 goto fail_rcu_unlock;
386 #else
387         goto fail_rcu_unlock;
388 #endif
389
390         /* Get the neighbour entry for the lookup */
391         n = dst_neigh_lookup(&rt->dst, &flow.daddr);
392         ip_rt_put(rt);
393         if (!n)
394                 goto fail_rcu_unlock;
395         nfp_tun_write_neigh(n->dev, app, &flow, n, GFP_ATOMIC);
396         neigh_release(n);
397         rcu_read_unlock();
398         return;
399
400 fail_rcu_unlock:
401         rcu_read_unlock();
402         nfp_flower_cmsg_warn(app, "Requested route not found.\n");
403 }
404
405 static void nfp_tun_write_ipv4_list(struct nfp_app *app)
406 {
407         struct nfp_flower_priv *priv = app->priv;
408         struct nfp_ipv4_addr_entry *entry;
409         struct nfp_tun_ipv4_addr payload;
410         struct list_head *ptr, *storage;
411         int count;
412
413         memset(&payload, 0, sizeof(struct nfp_tun_ipv4_addr));
414         mutex_lock(&priv->tun.ipv4_off_lock);
415         count = 0;
416         list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
417                 if (count >= NFP_FL_IPV4_ADDRS_MAX) {
418                         mutex_unlock(&priv->tun.ipv4_off_lock);
419                         nfp_flower_cmsg_warn(app, "IPv4 offload exceeds limit.\n");
420                         return;
421                 }
422                 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
423                 payload.ipv4_addr[count++] = entry->ipv4_addr;
424         }
425         payload.count = cpu_to_be32(count);
426         mutex_unlock(&priv->tun.ipv4_off_lock);
427
428         nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_IPS,
429                                  sizeof(struct nfp_tun_ipv4_addr),
430                                  &payload, GFP_KERNEL);
431 }
432
433 void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4)
434 {
435         struct nfp_flower_priv *priv = app->priv;
436         struct nfp_ipv4_addr_entry *entry;
437         struct list_head *ptr, *storage;
438
439         mutex_lock(&priv->tun.ipv4_off_lock);
440         list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
441                 entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
442                 if (entry->ipv4_addr == ipv4) {
443                         entry->ref_count++;
444                         mutex_unlock(&priv->tun.ipv4_off_lock);
445                         return;
446                 }
447         }
448
449         entry = kmalloc(sizeof(*entry), GFP_KERNEL);
450         if (!entry) {
451                 mutex_unlock(&priv->tun.ipv4_off_lock);
452                 nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
453                 return;
454         }
455         entry->ipv4_addr = ipv4;
456         entry->ref_count = 1;
457         list_add_tail(&entry->list, &priv->tun.ipv4_off_list);
458         mutex_unlock(&priv->tun.ipv4_off_lock);
459
460         nfp_tun_write_ipv4_list(app);
461 }
462
463 void nfp_tunnel_del_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->tun.ipv4_off_lock);
470         list_for_each_safe(ptr, storage, &priv->tun.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                         if (!entry->ref_count) {
475                                 list_del(&entry->list);
476                                 kfree(entry);
477                         }
478                         break;
479                 }
480         }
481         mutex_unlock(&priv->tun.ipv4_off_lock);
482
483         nfp_tun_write_ipv4_list(app);
484 }
485
486 static int
487 __nfp_tunnel_offload_mac(struct nfp_app *app, u8 *mac, u16 idx, bool del)
488 {
489         struct nfp_tun_mac_addr_offload payload;
490
491         memset(&payload, 0, sizeof(payload));
492
493         if (del)
494                 payload.flags = cpu_to_be16(NFP_TUN_MAC_OFFLOAD_DEL_FLAG);
495
496         /* FW supports multiple MACs per cmsg but restrict to single. */
497         payload.count = cpu_to_be16(1);
498         payload.index = cpu_to_be16(idx);
499         ether_addr_copy(payload.addr, mac);
500
501         return nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_MAC,
502                                         sizeof(struct nfp_tun_mac_addr_offload),
503                                         &payload, GFP_KERNEL);
504 }
505
506 static bool nfp_tunnel_port_is_phy_repr(int port)
507 {
508         if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) ==
509             NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT)
510                 return true;
511
512         return false;
513 }
514
515 static u16 nfp_tunnel_get_mac_idx_from_phy_port_id(int port)
516 {
517         return port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT;
518 }
519
520 static u16 nfp_tunnel_get_global_mac_idx_from_ida(int id)
521 {
522         return id << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
523 }
524
525 static int nfp_tunnel_get_ida_from_global_mac_idx(u16 nfp_mac_idx)
526 {
527         return nfp_mac_idx >> 8;
528 }
529
530 static bool nfp_tunnel_is_mac_idx_global(u16 nfp_mac_idx)
531 {
532         return (nfp_mac_idx & 0xff) == NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
533 }
534
535 static struct nfp_tun_offloaded_mac *
536 nfp_tunnel_lookup_offloaded_macs(struct nfp_app *app, u8 *mac)
537 {
538         struct nfp_flower_priv *priv = app->priv;
539
540         return rhashtable_lookup_fast(&priv->tun.offloaded_macs, mac,
541                                       offloaded_macs_params);
542 }
543
544 static void
545 nfp_tunnel_offloaded_macs_inc_ref_and_link(struct nfp_tun_offloaded_mac *entry,
546                                            struct net_device *netdev, bool mod)
547 {
548         if (nfp_netdev_is_nfp_repr(netdev)) {
549                 struct nfp_flower_repr_priv *repr_priv;
550                 struct nfp_repr *repr;
551
552                 repr = netdev_priv(netdev);
553                 repr_priv = repr->app_priv;
554
555                 /* If modifing MAC, remove repr from old list first. */
556                 if (mod)
557                         list_del(&repr_priv->mac_list);
558
559                 list_add_tail(&repr_priv->mac_list, &entry->repr_list);
560         }
561
562         entry->ref_count++;
563 }
564
565 static int
566 nfp_tunnel_add_shared_mac(struct nfp_app *app, struct net_device *netdev,
567                           int port, bool mod)
568 {
569         struct nfp_flower_priv *priv = app->priv;
570         int ida_idx = NFP_MAX_MAC_INDEX, err;
571         struct nfp_tun_offloaded_mac *entry;
572         u16 nfp_mac_idx = 0;
573
574         entry = nfp_tunnel_lookup_offloaded_macs(app, netdev->dev_addr);
575         if (entry && nfp_tunnel_is_mac_idx_global(entry->index)) {
576                 nfp_tunnel_offloaded_macs_inc_ref_and_link(entry, netdev, mod);
577                 return 0;
578         }
579
580         /* Assign a global index if non-repr or MAC address is now shared. */
581         if (entry || !port) {
582                 ida_idx = ida_simple_get(&priv->tun.mac_off_ids, 0,
583                                          NFP_MAX_MAC_INDEX, GFP_KERNEL);
584                 if (ida_idx < 0)
585                         return ida_idx;
586
587                 nfp_mac_idx = nfp_tunnel_get_global_mac_idx_from_ida(ida_idx);
588         } else {
589                 nfp_mac_idx = nfp_tunnel_get_mac_idx_from_phy_port_id(port);
590         }
591
592         if (!entry) {
593                 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
594                 if (!entry) {
595                         err = -ENOMEM;
596                         goto err_free_ida;
597                 }
598
599                 ether_addr_copy(entry->addr, netdev->dev_addr);
600                 INIT_LIST_HEAD(&entry->repr_list);
601
602                 if (rhashtable_insert_fast(&priv->tun.offloaded_macs,
603                                            &entry->ht_node,
604                                            offloaded_macs_params)) {
605                         err = -ENOMEM;
606                         goto err_free_entry;
607                 }
608         }
609
610         err = __nfp_tunnel_offload_mac(app, netdev->dev_addr,
611                                        nfp_mac_idx, false);
612         if (err) {
613                 /* If not shared then free. */
614                 if (!entry->ref_count)
615                         goto err_remove_hash;
616                 goto err_free_ida;
617         }
618
619         entry->index = nfp_mac_idx;
620         nfp_tunnel_offloaded_macs_inc_ref_and_link(entry, netdev, mod);
621
622         return 0;
623
624 err_remove_hash:
625         rhashtable_remove_fast(&priv->tun.offloaded_macs, &entry->ht_node,
626                                offloaded_macs_params);
627 err_free_entry:
628         kfree(entry);
629 err_free_ida:
630         if (ida_idx != NFP_MAX_MAC_INDEX)
631                 ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
632
633         return err;
634 }
635
636 static int
637 nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
638                           u8 *mac, bool mod)
639 {
640         struct nfp_flower_priv *priv = app->priv;
641         struct nfp_flower_repr_priv *repr_priv;
642         struct nfp_tun_offloaded_mac *entry;
643         struct nfp_repr *repr;
644         int ida_idx;
645
646         entry = nfp_tunnel_lookup_offloaded_macs(app, mac);
647         if (!entry)
648                 return 0;
649
650         entry->ref_count--;
651         /* If del is part of a mod then mac_list is still in use elsewheree. */
652         if (nfp_netdev_is_nfp_repr(netdev) && !mod) {
653                 repr = netdev_priv(netdev);
654                 repr_priv = repr->app_priv;
655                 list_del(&repr_priv->mac_list);
656         }
657
658         /* If MAC is now used by 1 repr set the offloaded MAC index to port. */
659         if (entry->ref_count == 1 && list_is_singular(&entry->repr_list)) {
660                 u16 nfp_mac_idx;
661                 int port, err;
662
663                 repr_priv = list_first_entry(&entry->repr_list,
664                                              struct nfp_flower_repr_priv,
665                                              mac_list);
666                 repr = repr_priv->nfp_repr;
667                 port = nfp_repr_get_port_id(repr->netdev);
668                 nfp_mac_idx = nfp_tunnel_get_mac_idx_from_phy_port_id(port);
669                 err = __nfp_tunnel_offload_mac(app, mac, nfp_mac_idx, false);
670                 if (err) {
671                         nfp_flower_cmsg_warn(app, "MAC offload index revert failed on %s.\n",
672                                              netdev_name(netdev));
673                         return 0;
674                 }
675
676                 ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
677                 ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
678                 entry->index = nfp_mac_idx;
679                 return 0;
680         }
681
682         if (entry->ref_count)
683                 return 0;
684
685         WARN_ON_ONCE(rhashtable_remove_fast(&priv->tun.offloaded_macs,
686                                             &entry->ht_node,
687                                             offloaded_macs_params));
688         /* If MAC has global ID then extract and free the ida entry. */
689         if (nfp_tunnel_is_mac_idx_global(entry->index)) {
690                 ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
691                 ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
692         }
693
694         kfree(entry);
695
696         return __nfp_tunnel_offload_mac(app, mac, 0, true);
697 }
698
699 static int
700 nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev,
701                        enum nfp_flower_mac_offload_cmd cmd)
702 {
703         struct nfp_flower_non_repr_priv *nr_priv = NULL;
704         bool non_repr = false, *mac_offloaded;
705         u8 *off_mac = NULL;
706         int err, port = 0;
707
708         if (nfp_netdev_is_nfp_repr(netdev)) {
709                 struct nfp_flower_repr_priv *repr_priv;
710                 struct nfp_repr *repr;
711
712                 repr = netdev_priv(netdev);
713                 if (repr->app != app)
714                         return 0;
715
716                 repr_priv = repr->app_priv;
717                 mac_offloaded = &repr_priv->mac_offloaded;
718                 off_mac = &repr_priv->offloaded_mac_addr[0];
719                 port = nfp_repr_get_port_id(netdev);
720                 if (!nfp_tunnel_port_is_phy_repr(port))
721                         return 0;
722         } else if (nfp_fl_is_netdev_to_offload(netdev)) {
723                 nr_priv = nfp_flower_non_repr_priv_get(app, netdev);
724                 if (!nr_priv)
725                         return -ENOMEM;
726
727                 mac_offloaded = &nr_priv->mac_offloaded;
728                 off_mac = &nr_priv->offloaded_mac_addr[0];
729                 non_repr = true;
730         } else {
731                 return 0;
732         }
733
734         if (!is_valid_ether_addr(netdev->dev_addr)) {
735                 err = -EINVAL;
736                 goto err_put_non_repr_priv;
737         }
738
739         if (cmd == NFP_TUNNEL_MAC_OFFLOAD_MOD && !*mac_offloaded)
740                 cmd = NFP_TUNNEL_MAC_OFFLOAD_ADD;
741
742         switch (cmd) {
743         case NFP_TUNNEL_MAC_OFFLOAD_ADD:
744                 err = nfp_tunnel_add_shared_mac(app, netdev, port, false);
745                 if (err)
746                         goto err_put_non_repr_priv;
747
748                 if (non_repr)
749                         __nfp_flower_non_repr_priv_get(nr_priv);
750
751                 *mac_offloaded = true;
752                 ether_addr_copy(off_mac, netdev->dev_addr);
753                 break;
754         case NFP_TUNNEL_MAC_OFFLOAD_DEL:
755                 /* Only attempt delete if add was successful. */
756                 if (!*mac_offloaded)
757                         break;
758
759                 if (non_repr)
760                         __nfp_flower_non_repr_priv_put(nr_priv);
761
762                 *mac_offloaded = false;
763
764                 err = nfp_tunnel_del_shared_mac(app, netdev, netdev->dev_addr,
765                                                 false);
766                 if (err)
767                         goto err_put_non_repr_priv;
768
769                 break;
770         case NFP_TUNNEL_MAC_OFFLOAD_MOD:
771                 /* Ignore if changing to the same address. */
772                 if (ether_addr_equal(netdev->dev_addr, off_mac))
773                         break;
774
775                 err = nfp_tunnel_add_shared_mac(app, netdev, port, true);
776                 if (err)
777                         goto err_put_non_repr_priv;
778
779                 /* Delete the previous MAC address. */
780                 err = nfp_tunnel_del_shared_mac(app, netdev, off_mac, true);
781                 if (err)
782                         nfp_flower_cmsg_warn(app, "Failed to remove offload of replaced MAC addr on %s.\n",
783                                              netdev_name(netdev));
784
785                 ether_addr_copy(off_mac, netdev->dev_addr);
786                 break;
787         default:
788                 err = -EINVAL;
789                 goto err_put_non_repr_priv;
790         }
791
792         if (non_repr)
793                 __nfp_flower_non_repr_priv_put(nr_priv);
794
795         return 0;
796
797 err_put_non_repr_priv:
798         if (non_repr)
799                 __nfp_flower_non_repr_priv_put(nr_priv);
800
801         return err;
802 }
803
804 int nfp_tunnel_mac_event_handler(struct nfp_app *app,
805                                  struct net_device *netdev,
806                                  unsigned long event, void *ptr)
807 {
808         int err;
809
810         if (event == NETDEV_DOWN) {
811                 err = nfp_tunnel_offload_mac(app, netdev,
812                                              NFP_TUNNEL_MAC_OFFLOAD_DEL);
813                 if (err)
814                         nfp_flower_cmsg_warn(app, "Failed to delete offload MAC on %s.\n",
815                                              netdev_name(netdev));
816         } else if (event == NETDEV_UP) {
817                 err = nfp_tunnel_offload_mac(app, netdev,
818                                              NFP_TUNNEL_MAC_OFFLOAD_ADD);
819                 if (err)
820                         nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n",
821                                              netdev_name(netdev));
822         } else if (event == NETDEV_CHANGEADDR) {
823                 /* Only offload addr change if netdev is already up. */
824                 if (!(netdev->flags & IFF_UP))
825                         return NOTIFY_OK;
826
827                 err = nfp_tunnel_offload_mac(app, netdev,
828                                              NFP_TUNNEL_MAC_OFFLOAD_MOD);
829                 if (err)
830                         nfp_flower_cmsg_warn(app, "Failed to offload MAC change on %s.\n",
831                                              netdev_name(netdev));
832         }
833         return NOTIFY_OK;
834 }
835
836 int nfp_tunnel_config_start(struct nfp_app *app)
837 {
838         struct nfp_flower_priv *priv = app->priv;
839         int err;
840
841         /* Initialise rhash for MAC offload tracking. */
842         err = rhashtable_init(&priv->tun.offloaded_macs,
843                               &offloaded_macs_params);
844         if (err)
845                 return err;
846
847         ida_init(&priv->tun.mac_off_ids);
848
849         /* Initialise priv data for IPv4 offloading. */
850         mutex_init(&priv->tun.ipv4_off_lock);
851         INIT_LIST_HEAD(&priv->tun.ipv4_off_list);
852
853         /* Initialise priv data for neighbour offloading. */
854         spin_lock_init(&priv->tun.neigh_off_lock);
855         INIT_LIST_HEAD(&priv->tun.neigh_off_list);
856         priv->tun.neigh_nb.notifier_call = nfp_tun_neigh_event_handler;
857
858         err = register_netevent_notifier(&priv->tun.neigh_nb);
859         if (err) {
860                 rhashtable_free_and_destroy(&priv->tun.offloaded_macs,
861                                             nfp_check_rhashtable_empty, NULL);
862                 return err;
863         }
864
865         return 0;
866 }
867
868 void nfp_tunnel_config_stop(struct nfp_app *app)
869 {
870         struct nfp_flower_priv *priv = app->priv;
871         struct nfp_ipv4_route_entry *route_entry;
872         struct nfp_ipv4_addr_entry *ip_entry;
873         struct list_head *ptr, *storage;
874
875         unregister_netevent_notifier(&priv->tun.neigh_nb);
876
877         ida_destroy(&priv->tun.mac_off_ids);
878
879         /* Free any memory that may be occupied by ipv4 list. */
880         list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
881                 ip_entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
882                 list_del(&ip_entry->list);
883                 kfree(ip_entry);
884         }
885
886         /* Free any memory that may be occupied by the route list. */
887         list_for_each_safe(ptr, storage, &priv->tun.neigh_off_list) {
888                 route_entry = list_entry(ptr, struct nfp_ipv4_route_entry,
889                                          list);
890                 list_del(&route_entry->list);
891                 kfree(route_entry);
892         }
893
894         /* Destroy rhash. Entries should be cleaned on netdev notifier unreg. */
895         rhashtable_free_and_destroy(&priv->tun.offloaded_macs,
896                                     nfp_check_rhashtable_empty, NULL);
897 }