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 } 898