Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bridge: suppress arp pkts on BR_NEIGH_SUPPRESS ports

This patch avoids flooding and proxies arp packets
for BR_NEIGH_SUPPRESS ports.

Moves existing br_do_proxy_arp to br_do_proxy_suppress_arp
to support both proxy arp and neigh suppress.

Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Roopa Prabhu and committed by
David S. Miller
057658cb 821f1b21

+205 -58
+188
net/bridge/br_arp_nd_proxy.c
··· 14 14 */ 15 15 16 16 #include <linux/kernel.h> 17 + #include <linux/netdevice.h> 18 + #include <linux/etherdevice.h> 19 + #include <linux/neighbour.h> 20 + #include <net/arp.h> 21 + #include <linux/if_vlan.h> 22 + #include <linux/inetdevice.h> 23 + #include <net/addrconf.h> 24 + 17 25 #include "br_private.h" 18 26 19 27 void br_recalculate_neigh_suppress_enabled(struct net_bridge *br) ··· 38 30 39 31 br->neigh_suppress_enabled = neigh_suppress; 40 32 } 33 + 34 + #if IS_ENABLED(CONFIG_INET) 35 + static void br_arp_send(struct net_bridge *br, struct net_bridge_port *p, 36 + struct net_device *dev, __be32 dest_ip, __be32 src_ip, 37 + const unsigned char *dest_hw, 38 + const unsigned char *src_hw, 39 + const unsigned char *target_hw, 40 + __be16 vlan_proto, u16 vlan_tci) 41 + { 42 + struct net_bridge_vlan_group *vg; 43 + struct sk_buff *skb; 44 + u16 pvid; 45 + 46 + netdev_dbg(dev, "arp send dev %s dst %pI4 dst_hw %pM src %pI4 src_hw %pM\n", 47 + dev->name, &dest_ip, dest_hw, &src_ip, src_hw); 48 + 49 + if (!vlan_tci) { 50 + arp_send(ARPOP_REPLY, ETH_P_ARP, dest_ip, dev, src_ip, 51 + dest_hw, src_hw, target_hw); 52 + return; 53 + } 54 + 55 + skb = arp_create(ARPOP_REPLY, ETH_P_ARP, dest_ip, dev, src_ip, 56 + dest_hw, src_hw, target_hw); 57 + if (!skb) 58 + return; 59 + 60 + if (p) 61 + vg = nbp_vlan_group_rcu(p); 62 + else 63 + vg = br_vlan_group_rcu(br); 64 + pvid = br_get_pvid(vg); 65 + if (pvid == (vlan_tci & VLAN_VID_MASK)) 66 + vlan_tci = 0; 67 + 68 + if (vlan_tci) 69 + __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci); 70 + 71 + if (p) { 72 + arp_xmit(skb); 73 + } else { 74 + skb_reset_mac_header(skb); 75 + __skb_pull(skb, skb_network_offset(skb)); 76 + skb->ip_summed = CHECKSUM_UNNECESSARY; 77 + skb->pkt_type = PACKET_HOST; 78 + 79 + netif_rx_ni(skb); 80 + } 81 + } 82 + 83 + static int br_chk_addr_ip(struct net_device *dev, void *data) 84 + { 85 + __be32 ip = *(__be32 *)data; 86 + struct in_device *in_dev; 87 + __be32 addr = 0; 88 + 89 + in_dev = __in_dev_get_rcu(dev); 90 + if (in_dev) 91 + addr = inet_confirm_addr(dev_net(dev), in_dev, 0, ip, 92 + RT_SCOPE_HOST); 93 + 94 + if (addr == ip) 95 + return 1; 96 + 97 + return 0; 98 + } 99 + 100 + static bool br_is_local_ip(struct net_device *dev, __be32 ip) 101 + { 102 + if (br_chk_addr_ip(dev, &ip)) 103 + return true; 104 + 105 + /* check if ip is configured on upper dev */ 106 + if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &ip)) 107 + return true; 108 + 109 + return false; 110 + } 111 + 112 + void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, 113 + u16 vid, struct net_bridge_port *p) 114 + { 115 + struct net_device *dev = br->dev; 116 + struct net_device *vlandev = dev; 117 + struct neighbour *n; 118 + struct arphdr *parp; 119 + u8 *arpptr, *sha; 120 + __be32 sip, tip; 121 + 122 + BR_INPUT_SKB_CB(skb)->proxyarp_replied = false; 123 + 124 + if ((dev->flags & IFF_NOARP) || 125 + !pskb_may_pull(skb, arp_hdr_len(dev))) 126 + return; 127 + 128 + parp = arp_hdr(skb); 129 + 130 + if (parp->ar_pro != htons(ETH_P_IP) || 131 + parp->ar_hln != dev->addr_len || 132 + parp->ar_pln != 4) 133 + return; 134 + 135 + arpptr = (u8 *)parp + sizeof(struct arphdr); 136 + sha = arpptr; 137 + arpptr += dev->addr_len; /* sha */ 138 + memcpy(&sip, arpptr, sizeof(sip)); 139 + arpptr += sizeof(sip); 140 + arpptr += dev->addr_len; /* tha */ 141 + memcpy(&tip, arpptr, sizeof(tip)); 142 + 143 + if (ipv4_is_loopback(tip) || 144 + ipv4_is_multicast(tip)) 145 + return; 146 + 147 + if (br->neigh_suppress_enabled) { 148 + if (p && (p->flags & BR_NEIGH_SUPPRESS)) 149 + return; 150 + if (ipv4_is_zeronet(sip) || sip == tip) { 151 + /* prevent flooding to neigh suppress ports */ 152 + BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; 153 + return; 154 + } 155 + } 156 + 157 + if (parp->ar_op != htons(ARPOP_REQUEST)) 158 + return; 159 + 160 + if (vid != 0) { 161 + vlandev = __vlan_find_dev_deep_rcu(br->dev, skb->vlan_proto, 162 + vid); 163 + if (!vlandev) 164 + return; 165 + } 166 + 167 + if (br->neigh_suppress_enabled && br_is_local_ip(vlandev, tip)) { 168 + /* its our local ip, so don't proxy reply 169 + * and don't forward to neigh suppress ports 170 + */ 171 + BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; 172 + return; 173 + } 174 + 175 + n = neigh_lookup(&arp_tbl, &tip, vlandev); 176 + if (n) { 177 + struct net_bridge_fdb_entry *f; 178 + 179 + if (!(n->nud_state & NUD_VALID)) { 180 + neigh_release(n); 181 + return; 182 + } 183 + 184 + f = br_fdb_find_rcu(br, n->ha, vid); 185 + if (f) { 186 + bool replied = false; 187 + 188 + if ((p && (p->flags & BR_PROXYARP)) || 189 + (f->dst && (f->dst->flags & (BR_PROXYARP_WIFI | 190 + BR_NEIGH_SUPPRESS)))) { 191 + if (!vid) 192 + br_arp_send(br, p, skb->dev, sip, tip, 193 + sha, n->ha, sha, 0, 0); 194 + else 195 + br_arp_send(br, p, skb->dev, sip, tip, 196 + sha, n->ha, sha, 197 + skb->vlan_proto, 198 + skb_vlan_tag_get(skb)); 199 + replied = true; 200 + } 201 + 202 + /* If we have replied or as long as we know the 203 + * mac, indicate to arp replied 204 + */ 205 + if (replied || br->neigh_suppress_enabled) 206 + BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; 207 + } 208 + 209 + neigh_release(n); 210 + } 211 + } 212 + #endif
+9
net/bridge/br_device.c
··· 39 39 struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats); 40 40 const struct nf_br_ops *nf_ops; 41 41 const unsigned char *dest; 42 + struct ethhdr *eth; 42 43 u16 vid = 0; 43 44 44 45 rcu_read_lock(); ··· 58 57 BR_INPUT_SKB_CB(skb)->brdev = dev; 59 58 60 59 skb_reset_mac_header(skb); 60 + eth = eth_hdr(skb); 61 61 skb_pull(skb, ETH_HLEN); 62 62 63 63 if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid)) 64 64 goto out; 65 + 66 + if (IS_ENABLED(CONFIG_INET) && 67 + (eth->h_proto == htons(ETH_P_ARP) || 68 + eth->h_proto == htons(ETH_P_RARP)) && 69 + br->neigh_suppress_enabled) { 70 + br_do_proxy_suppress_arp(skb, br, vid, NULL); 71 + } 65 72 66 73 dest = eth_hdr(skb)->h_dest; 67 74 if (is_broadcast_ether_addr(dest)) {
+5 -58
net/bridge/br_input.c
··· 71 71 br_netif_receive_skb); 72 72 } 73 73 74 - static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, 75 - u16 vid, struct net_bridge_port *p) 76 - { 77 - struct net_device *dev = br->dev; 78 - struct neighbour *n; 79 - struct arphdr *parp; 80 - u8 *arpptr, *sha; 81 - __be32 sip, tip; 82 - 83 - BR_INPUT_SKB_CB(skb)->proxyarp_replied = false; 84 - 85 - if ((dev->flags & IFF_NOARP) || 86 - !pskb_may_pull(skb, arp_hdr_len(dev))) 87 - return; 88 - 89 - parp = arp_hdr(skb); 90 - 91 - if (parp->ar_pro != htons(ETH_P_IP) || 92 - parp->ar_op != htons(ARPOP_REQUEST) || 93 - parp->ar_hln != dev->addr_len || 94 - parp->ar_pln != 4) 95 - return; 96 - 97 - arpptr = (u8 *)parp + sizeof(struct arphdr); 98 - sha = arpptr; 99 - arpptr += dev->addr_len; /* sha */ 100 - memcpy(&sip, arpptr, sizeof(sip)); 101 - arpptr += sizeof(sip); 102 - arpptr += dev->addr_len; /* tha */ 103 - memcpy(&tip, arpptr, sizeof(tip)); 104 - 105 - if (ipv4_is_loopback(tip) || 106 - ipv4_is_multicast(tip)) 107 - return; 108 - 109 - n = neigh_lookup(&arp_tbl, &tip, dev); 110 - if (n) { 111 - struct net_bridge_fdb_entry *f; 112 - 113 - if (!(n->nud_state & NUD_VALID)) { 114 - neigh_release(n); 115 - return; 116 - } 117 - 118 - f = br_fdb_find_rcu(br, n->ha, vid); 119 - if (f && ((p->flags & BR_PROXYARP) || 120 - (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)))) { 121 - arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip, 122 - sha, n->ha, sha); 123 - BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; 124 - } 125 - 126 - neigh_release(n); 127 - } 128 - } 129 - 130 74 /* note: already called with rcu_read_lock */ 131 75 int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 132 76 { ··· 115 171 116 172 BR_INPUT_SKB_CB(skb)->brdev = br->dev; 117 173 118 - if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP)) 119 - br_do_proxy_arp(skb, br, vid, p); 174 + if (IS_ENABLED(CONFIG_INET) && 175 + (skb->protocol == htons(ETH_P_ARP) || 176 + skb->protocol == htons(ETH_P_RARP))) { 177 + br_do_proxy_suppress_arp(skb, br, vid, p); 178 + } 120 179 121 180 switch (pkt_type) { 122 181 case BR_PKT_MULTICAST:
+3
net/bridge/br_private.h
··· 1140 1140 } 1141 1141 #endif /* CONFIG_NET_SWITCHDEV */ 1142 1142 1143 + /* br_arp_nd_proxy.c */ 1143 1144 void br_recalculate_neigh_suppress_enabled(struct net_bridge *br); 1145 + void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, 1146 + u16 vid, struct net_bridge_port *p); 1144 1147 #endif