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