| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Handle bridge arp/nd proxy/suppress |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * |
|---|
| 7 | 8 | * Authors: |
|---|
| 8 | 9 | * Roopa Prabhu <roopa@cumulusnetworks.com> |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or |
|---|
| 11 | | - * modify it under the terms of the GNU General Public License |
|---|
| 12 | | - * as published by the Free Software Foundation; either version |
|---|
| 13 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 14 | 10 | */ |
|---|
| 15 | 11 | |
|---|
| 16 | 12 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 21 | 17 | #include <linux/if_vlan.h> |
|---|
| 22 | 18 | #include <linux/inetdevice.h> |
|---|
| 23 | 19 | #include <net/addrconf.h> |
|---|
| 20 | +#include <net/ipv6_stubs.h> |
|---|
| 24 | 21 | #if IS_ENABLED(CONFIG_IPV6) |
|---|
| 25 | 22 | #include <net/ip6_checksum.h> |
|---|
| 26 | 23 | #endif |
|---|
| .. | .. |
|---|
| 39 | 36 | } |
|---|
| 40 | 37 | } |
|---|
| 41 | 38 | |
|---|
| 42 | | - br->neigh_suppress_enabled = neigh_suppress; |
|---|
| 39 | + br_opt_toggle(br, BROPT_NEIGH_SUPPRESS_ENABLED, neigh_suppress); |
|---|
| 43 | 40 | } |
|---|
| 44 | 41 | |
|---|
| 45 | 42 | #if IS_ENABLED(CONFIG_INET) |
|---|
| .. | .. |
|---|
| 91 | 88 | } |
|---|
| 92 | 89 | } |
|---|
| 93 | 90 | |
|---|
| 94 | | -static int br_chk_addr_ip(struct net_device *dev, void *data) |
|---|
| 91 | +static int br_chk_addr_ip(struct net_device *dev, |
|---|
| 92 | + struct netdev_nested_priv *priv) |
|---|
| 95 | 93 | { |
|---|
| 96 | | - __be32 ip = *(__be32 *)data; |
|---|
| 94 | + __be32 ip = *(__be32 *)priv->data; |
|---|
| 97 | 95 | struct in_device *in_dev; |
|---|
| 98 | 96 | __be32 addr = 0; |
|---|
| 99 | 97 | |
|---|
| .. | .. |
|---|
| 110 | 108 | |
|---|
| 111 | 109 | static bool br_is_local_ip(struct net_device *dev, __be32 ip) |
|---|
| 112 | 110 | { |
|---|
| 113 | | - if (br_chk_addr_ip(dev, &ip)) |
|---|
| 111 | + struct netdev_nested_priv priv = { |
|---|
| 112 | + .data = (void *)&ip, |
|---|
| 113 | + }; |
|---|
| 114 | + |
|---|
| 115 | + if (br_chk_addr_ip(dev, &priv)) |
|---|
| 114 | 116 | return true; |
|---|
| 115 | 117 | |
|---|
| 116 | 118 | /* check if ip is configured on upper dev */ |
|---|
| 117 | | - if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &ip)) |
|---|
| 119 | + if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &priv)) |
|---|
| 118 | 120 | return true; |
|---|
| 119 | 121 | |
|---|
| 120 | 122 | return false; |
|---|
| .. | .. |
|---|
| 130 | 132 | u8 *arpptr, *sha; |
|---|
| 131 | 133 | __be32 sip, tip; |
|---|
| 132 | 134 | |
|---|
| 133 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = false; |
|---|
| 135 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 0; |
|---|
| 134 | 136 | |
|---|
| 135 | 137 | if ((dev->flags & IFF_NOARP) || |
|---|
| 136 | 138 | !pskb_may_pull(skb, arp_hdr_len(dev))) |
|---|
| .. | .. |
|---|
| 155 | 157 | ipv4_is_multicast(tip)) |
|---|
| 156 | 158 | return; |
|---|
| 157 | 159 | |
|---|
| 158 | | - if (br->neigh_suppress_enabled) { |
|---|
| 160 | + if (br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) { |
|---|
| 159 | 161 | if (p && (p->flags & BR_NEIGH_SUPPRESS)) |
|---|
| 160 | 162 | return; |
|---|
| 161 | 163 | if (parp->ar_op != htons(ARPOP_RREQUEST) && |
|---|
| 162 | 164 | parp->ar_op != htons(ARPOP_RREPLY) && |
|---|
| 163 | 165 | (ipv4_is_zeronet(sip) || sip == tip)) { |
|---|
| 164 | 166 | /* prevent flooding to neigh suppress ports */ |
|---|
| 165 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; |
|---|
| 167 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; |
|---|
| 166 | 168 | return; |
|---|
| 167 | 169 | } |
|---|
| 168 | 170 | } |
|---|
| .. | .. |
|---|
| 177 | 179 | return; |
|---|
| 178 | 180 | } |
|---|
| 179 | 181 | |
|---|
| 180 | | - if (br->neigh_suppress_enabled && br_is_local_ip(vlandev, tip)) { |
|---|
| 182 | + if (br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) && |
|---|
| 183 | + br_is_local_ip(vlandev, tip)) { |
|---|
| 181 | 184 | /* its our local ip, so don't proxy reply |
|---|
| 182 | 185 | * and don't forward to neigh suppress ports |
|---|
| 183 | 186 | */ |
|---|
| 184 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; |
|---|
| 187 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; |
|---|
| 185 | 188 | return; |
|---|
| 186 | 189 | } |
|---|
| 187 | 190 | |
|---|
| .. | .. |
|---|
| 215 | 218 | /* If we have replied or as long as we know the |
|---|
| 216 | 219 | * mac, indicate to arp replied |
|---|
| 217 | 220 | */ |
|---|
| 218 | | - if (replied || br->neigh_suppress_enabled) |
|---|
| 219 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; |
|---|
| 221 | + if (replied || |
|---|
| 222 | + br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) |
|---|
| 223 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; |
|---|
| 220 | 224 | } |
|---|
| 221 | 225 | |
|---|
| 222 | 226 | neigh_release(n); |
|---|
| .. | .. |
|---|
| 364 | 368 | } |
|---|
| 365 | 369 | } |
|---|
| 366 | 370 | |
|---|
| 367 | | -static int br_chk_addr_ip6(struct net_device *dev, void *data) |
|---|
| 371 | +static int br_chk_addr_ip6(struct net_device *dev, |
|---|
| 372 | + struct netdev_nested_priv *priv) |
|---|
| 368 | 373 | { |
|---|
| 369 | | - struct in6_addr *addr = (struct in6_addr *)data; |
|---|
| 374 | + struct in6_addr *addr = (struct in6_addr *)priv->data; |
|---|
| 370 | 375 | |
|---|
| 371 | 376 | if (ipv6_chk_addr(dev_net(dev), addr, dev, 0)) |
|---|
| 372 | 377 | return 1; |
|---|
| .. | .. |
|---|
| 377 | 382 | static bool br_is_local_ip6(struct net_device *dev, struct in6_addr *addr) |
|---|
| 378 | 383 | |
|---|
| 379 | 384 | { |
|---|
| 380 | | - if (br_chk_addr_ip6(dev, addr)) |
|---|
| 385 | + struct netdev_nested_priv priv = { |
|---|
| 386 | + .data = (void *)addr, |
|---|
| 387 | + }; |
|---|
| 388 | + |
|---|
| 389 | + if (br_chk_addr_ip6(dev, &priv)) |
|---|
| 381 | 390 | return true; |
|---|
| 382 | 391 | |
|---|
| 383 | 392 | /* check if ip is configured on upper dev */ |
|---|
| 384 | | - if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip6, addr)) |
|---|
| 393 | + if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip6, &priv)) |
|---|
| 385 | 394 | return true; |
|---|
| 386 | 395 | |
|---|
| 387 | 396 | return false; |
|---|
| .. | .. |
|---|
| 396 | 405 | struct ipv6hdr *iphdr; |
|---|
| 397 | 406 | struct neighbour *n; |
|---|
| 398 | 407 | |
|---|
| 399 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = false; |
|---|
| 408 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 0; |
|---|
| 400 | 409 | |
|---|
| 401 | 410 | if (p && (p->flags & BR_NEIGH_SUPPRESS)) |
|---|
| 402 | 411 | return; |
|---|
| .. | .. |
|---|
| 404 | 413 | if (msg->icmph.icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT && |
|---|
| 405 | 414 | !msg->icmph.icmp6_solicited) { |
|---|
| 406 | 415 | /* prevent flooding to neigh suppress ports */ |
|---|
| 407 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; |
|---|
| 416 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; |
|---|
| 408 | 417 | return; |
|---|
| 409 | 418 | } |
|---|
| 410 | 419 | |
|---|
| .. | .. |
|---|
| 417 | 426 | |
|---|
| 418 | 427 | if (ipv6_addr_any(saddr) || !ipv6_addr_cmp(saddr, daddr)) { |
|---|
| 419 | 428 | /* prevent flooding to neigh suppress ports */ |
|---|
| 420 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; |
|---|
| 429 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; |
|---|
| 421 | 430 | return; |
|---|
| 422 | 431 | } |
|---|
| 423 | 432 | |
|---|
| .. | .. |
|---|
| 435 | 444 | /* its our own ip, so don't proxy reply |
|---|
| 436 | 445 | * and don't forward to arp suppress ports |
|---|
| 437 | 446 | */ |
|---|
| 438 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; |
|---|
| 447 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; |
|---|
| 439 | 448 | return; |
|---|
| 440 | 449 | } |
|---|
| 441 | 450 | |
|---|
| .. | .. |
|---|
| 466 | 475 | * mac, indicate to NEIGH_SUPPRESS ports that we |
|---|
| 467 | 476 | * have replied |
|---|
| 468 | 477 | */ |
|---|
| 469 | | - if (replied || br->neigh_suppress_enabled) |
|---|
| 470 | | - BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; |
|---|
| 478 | + if (replied || |
|---|
| 479 | + br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) |
|---|
| 480 | + BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1; |
|---|
| 471 | 481 | } |
|---|
| 472 | 482 | neigh_release(n); |
|---|
| 473 | 483 | } |
|---|