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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bridge-neigh-suppression'

Ido Schimmel says:

====================
bridge: Add per-{Port, VLAN} neighbor suppression

Background
==========

In order to minimize the flooding of ARP and ND messages in the VXLAN
network, EVPN includes provisions [1] that allow participating VTEPs to
suppress such messages in case they know the MAC-IP binding and can
reply on behalf of the remote host. In Linux, the above is implemented
in the bridge driver using a per-port option called "neigh_suppress"
that was added in kernel version 4.15 [2].

Motivation
==========

Some applications use ARP messages as keepalives between the application
nodes in the network. This works perfectly well when two nodes are
connected to the same VTEP. When a node goes down it will stop
responding to ARP requests and the other node will notice it
immediately.

However, when the two nodes are connected to different VTEPs and
neighbor suppression is enabled, the local VTEP will reply to ARP
requests even after the remote node went down, until certain timers
expire and the EVPN control plane decides to withdraw the MAC/IP
Advertisement route for the address. Therefore, some users would like to
be able to disable neighbor suppression on VLANs where such applications
reside and keep it enabled on the rest.

Implementation
==============

The proposed solution is to allow user space to control neighbor
suppression on a per-{Port, VLAN} basis, in a similar fashion to other
per-port options that gained per-{Port, VLAN} counterparts such as
"mcast_router". This allows users to benefit from the operational
simplicity and scalability associated with shared VXLAN devices (i.e.,
external / collect-metadata mode), while still allowing for per-VLAN/VNI
neighbor suppression control.

The user interface is extended with a new "neigh_vlan_suppress" bridge
port option that allows user space to enable per-{Port, VLAN} neighbor
suppression on the bridge port. When enabled, the existing
"neigh_suppress" option has no effect and neighbor suppression is
controlled using a new "neigh_suppress" VLAN option. Example usage:

# bridge link set dev vxlan0 neigh_vlan_suppress on
# bridge vlan add vid 10 dev vxlan0
# bridge vlan set vid 10 dev vxlan0 neigh_suppress on

Testing
=======

Tested using existing bridge selftests. Added a dedicated selftest in
the last patch.

Patchset overview
=================

Patches #1-#5 are preparations.

Patch #6 adds per-{Port, VLAN} neighbor suppression support to the
bridge's data path.

Patches #7-#8 add the required netlink attributes to enable the feature.

Patch #9 adds a selftest.

iproute2 patches can be found here [3].

Changelog
=========

Since RFC [4]:

No changes.

[1] https://www.rfc-editor.org/rfc/rfc7432#section-10
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a42317785c898c0ed46db45a33b0cc71b671bf29
[3] https://github.com/idosch/iproute2/tree/submit/neigh_suppress_v1
[4] https://lore.kernel.org/netdev/20230413095830.2182382-1-idosch@nvidia.com/
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+936 -19
+1
include/linux/if_bridge.h
··· 60 60 #define BR_TX_FWD_OFFLOAD BIT(20) 61 61 #define BR_PORT_LOCKED BIT(21) 62 62 #define BR_PORT_MAB BIT(22) 63 + #define BR_NEIGH_VLAN_SUPPRESS BIT(23) 63 64 64 65 #define BR_DEFAULT_AGEING_TIME (300 * HZ) 65 66
+1
include/uapi/linux/if_bridge.h
··· 525 525 BRIDGE_VLANDB_ENTRY_MCAST_ROUTER, 526 526 BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS, 527 527 BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS, 528 + BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS, 528 529 __BRIDGE_VLANDB_ENTRY_MAX, 529 530 }; 530 531 #define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
+1
include/uapi/linux/if_link.h
··· 569 569 IFLA_BRPORT_MAB, 570 570 IFLA_BRPORT_MCAST_N_GROUPS, 571 571 IFLA_BRPORT_MCAST_MAX_GROUPS, 572 + IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, 572 573 __IFLA_BRPORT_MAX 573 574 }; 574 575 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+27 -6
net/bridge/br_arp_nd_proxy.c
··· 30 30 bool neigh_suppress = false; 31 31 32 32 list_for_each_entry(p, &br->port_list, list) { 33 - if (p->flags & BR_NEIGH_SUPPRESS) { 33 + if (p->flags & (BR_NEIGH_SUPPRESS | BR_NEIGH_VLAN_SUPPRESS)) { 34 34 neigh_suppress = true; 35 35 break; 36 36 } ··· 158 158 return; 159 159 160 160 if (br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) { 161 - if (p && (p->flags & BR_NEIGH_SUPPRESS)) 161 + if (br_is_neigh_suppress_enabled(p, vid)) 162 162 return; 163 163 if (parp->ar_op != htons(ARPOP_RREQUEST) && 164 164 parp->ar_op != htons(ARPOP_RREPLY) && ··· 202 202 bool replied = false; 203 203 204 204 if ((p && (p->flags & BR_PROXYARP)) || 205 - (f->dst && (f->dst->flags & (BR_PROXYARP_WIFI | 206 - BR_NEIGH_SUPPRESS)))) { 205 + (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) || 206 + br_is_neigh_suppress_enabled(f->dst, vid)) { 207 207 if (!vid) 208 208 br_arp_send(br, p, skb->dev, sip, tip, 209 209 sha, n->ha, sha, 0, 0); ··· 407 407 408 408 BR_INPUT_SKB_CB(skb)->proxyarp_replied = 0; 409 409 410 - if (p && (p->flags & BR_NEIGH_SUPPRESS)) 410 + if (br_is_neigh_suppress_enabled(p, vid)) 411 411 return; 412 412 413 413 if (msg->icmph.icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT && ··· 461 461 if (f) { 462 462 bool replied = false; 463 463 464 - if (f->dst && (f->dst->flags & BR_NEIGH_SUPPRESS)) { 464 + if (br_is_neigh_suppress_enabled(f->dst, vid)) { 465 465 if (vid != 0) 466 466 br_nd_send(br, p, skb, n, 467 467 skb->vlan_proto, ··· 483 483 } 484 484 } 485 485 #endif 486 + 487 + bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid) 488 + { 489 + if (!p) 490 + return false; 491 + 492 + if (!vid) 493 + return !!(p->flags & BR_NEIGH_SUPPRESS); 494 + 495 + if (p->flags & BR_NEIGH_VLAN_SUPPRESS) { 496 + struct net_bridge_vlan_group *vg = nbp_vlan_group_rcu(p); 497 + struct net_bridge_vlan *v; 498 + 499 + v = br_vlan_find(vg, vid); 500 + if (!v) 501 + return false; 502 + return !!(v->priv_flags & BR_VLFLAG_NEIGH_SUPPRESS_ENABLED); 503 + } else { 504 + return !!(p->flags & BR_NEIGH_SUPPRESS); 505 + } 506 + }
+4 -4
net/bridge/br_device.c
··· 80 80 81 81 dest = eth_hdr(skb)->h_dest; 82 82 if (is_broadcast_ether_addr(dest)) { 83 - br_flood(br, skb, BR_PKT_BROADCAST, false, true); 83 + br_flood(br, skb, BR_PKT_BROADCAST, false, true, vid); 84 84 } else if (is_multicast_ether_addr(dest)) { 85 85 if (unlikely(netpoll_tx_running(dev))) { 86 - br_flood(br, skb, BR_PKT_MULTICAST, false, true); 86 + br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid); 87 87 goto out; 88 88 } 89 89 if (br_multicast_rcv(&brmctx, &pmctx_null, vlan, skb, vid)) { ··· 96 96 br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) 97 97 br_multicast_flood(mdst, skb, brmctx, false, true); 98 98 else 99 - br_flood(br, skb, BR_PKT_MULTICAST, false, true); 99 + br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid); 100 100 } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { 101 101 br_forward(dst->dst, skb, false, true); 102 102 } else { 103 - br_flood(br, skb, BR_PKT_UNICAST, false, true); 103 + br_flood(br, skb, BR_PKT_UNICAST, false, true, vid); 104 104 } 105 105 out: 106 106 rcu_read_unlock();
+5 -3
net/bridge/br_forward.c
··· 197 197 198 198 /* called under rcu_read_lock */ 199 199 void br_flood(struct net_bridge *br, struct sk_buff *skb, 200 - enum br_pkt_type pkt_type, bool local_rcv, bool local_orig) 200 + enum br_pkt_type pkt_type, bool local_rcv, bool local_orig, 201 + u16 vid) 201 202 { 202 203 struct net_bridge_port *prev = NULL; 203 204 struct net_bridge_port *p; ··· 225 224 /* Do not flood to ports that enable proxy ARP */ 226 225 if (p->flags & BR_PROXYARP) 227 226 continue; 228 - if ((p->flags & (BR_PROXYARP_WIFI | BR_NEIGH_SUPPRESS)) && 229 - BR_INPUT_SKB_CB(skb)->proxyarp_replied) 227 + if (BR_INPUT_SKB_CB(skb)->proxyarp_replied && 228 + ((p->flags & BR_PROXYARP_WIFI) || 229 + br_is_neigh_suppress_enabled(p, vid))) 230 230 continue; 231 231 232 232 prev = maybe_deliver(prev, p, skb, local_orig);
+1 -1
net/bridge/br_if.c
··· 759 759 if (mask & BR_AUTO_MASK) 760 760 nbp_update_port_count(br); 761 761 762 - if (mask & BR_NEIGH_SUPPRESS) 762 + if (mask & (BR_NEIGH_SUPPRESS | BR_NEIGH_VLAN_SUPPRESS)) 763 763 br_recalculate_neigh_suppress_enabled(br); 764 764 } 765 765
+1 -1
net/bridge/br_input.c
··· 207 207 br_forward(dst->dst, skb, local_rcv, false); 208 208 } else { 209 209 if (!mcast_hit) 210 - br_flood(br, skb, pkt_type, local_rcv, false); 210 + br_flood(br, skb, pkt_type, local_rcv, false, vid); 211 211 else 212 212 br_multicast_flood(mdst, skb, brmctx, local_rcv, false); 213 213 }
+7 -1
net/bridge/br_netlink.c
··· 189 189 + nla_total_size(1) /* IFLA_BRPORT_ISOLATED */ 190 190 + nla_total_size(1) /* IFLA_BRPORT_LOCKED */ 191 191 + nla_total_size(1) /* IFLA_BRPORT_MAB */ 192 + + nla_total_size(1) /* IFLA_BRPORT_NEIGH_VLAN_SUPPRESS */ 192 193 + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */ 193 194 + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */ 194 195 + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */ ··· 279 278 !!(p->flags & BR_MRP_LOST_IN_CONT)) || 280 279 nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)) || 281 280 nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(p->flags & BR_PORT_LOCKED)) || 282 - nla_put_u8(skb, IFLA_BRPORT_MAB, !!(p->flags & BR_PORT_MAB))) 281 + nla_put_u8(skb, IFLA_BRPORT_MAB, !!(p->flags & BR_PORT_MAB)) || 282 + nla_put_u8(skb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, 283 + !!(p->flags & BR_NEIGH_VLAN_SUPPRESS))) 283 284 return -EMSGSIZE; 284 285 285 286 timerval = br_timer_value(&p->message_age_timer); ··· 894 891 [IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT] = { .type = NLA_U32 }, 895 892 [IFLA_BRPORT_MCAST_N_GROUPS] = { .type = NLA_REJECT }, 896 893 [IFLA_BRPORT_MCAST_MAX_GROUPS] = { .type = NLA_U32 }, 894 + [IFLA_BRPORT_NEIGH_VLAN_SUPPRESS] = NLA_POLICY_MAX(NLA_U8, 1), 897 895 }; 898 896 899 897 /* Change the state of the port and notify spanning tree */ ··· 961 957 br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED); 962 958 br_set_port_flag(p, tb, IFLA_BRPORT_LOCKED, BR_PORT_LOCKED); 963 959 br_set_port_flag(p, tb, IFLA_BRPORT_MAB, BR_PORT_MAB); 960 + br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, 961 + BR_NEIGH_VLAN_SUPPRESS); 964 962 965 963 if ((p->flags & BR_PORT_MAB) && 966 964 (!(p->flags & BR_PORT_LOCKED) || !(p->flags & BR_LEARNING))) {
+4 -1
net/bridge/br_private.h
··· 178 178 BR_VLFLAG_ADDED_BY_SWITCHDEV = BIT(1), 179 179 BR_VLFLAG_MCAST_ENABLED = BIT(2), 180 180 BR_VLFLAG_GLOBAL_MCAST_ENABLED = BIT(3), 181 + BR_VLFLAG_NEIGH_SUPPRESS_ENABLED = BIT(4), 181 182 }; 182 183 183 184 /** ··· 850 849 bool local_rcv, bool local_orig); 851 850 int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb); 852 851 void br_flood(struct net_bridge *br, struct sk_buff *skb, 853 - enum br_pkt_type pkt_type, bool local_rcv, bool local_orig); 852 + enum br_pkt_type pkt_type, bool local_rcv, bool local_orig, 853 + u16 vid); 854 854 855 855 /* return true if both source port and dest port are isolated */ 856 856 static inline bool br_skb_isolated(const struct net_bridge_port *to, ··· 2220 2218 void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br, 2221 2219 u16 vid, struct net_bridge_port *p, struct nd_msg *msg); 2222 2220 struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m); 2221 + bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid); 2223 2222 #endif
+1
net/bridge/br_vlan.c
··· 2134 2134 [BRIDGE_VLANDB_ENTRY_MCAST_ROUTER] = { .type = NLA_U8 }, 2135 2135 [BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS] = { .type = NLA_REJECT }, 2136 2136 [BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS] = { .type = NLA_U32 }, 2137 + [BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS] = NLA_POLICY_MAX(NLA_U8, 1), 2137 2138 }; 2138 2139 2139 2140 static int br_vlan_rtm_process_one(struct net_device *dev,
+19 -1
net/bridge/br_vlan_options.c
··· 52 52 const struct net_bridge_port *p) 53 53 { 54 54 if (nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_STATE, br_vlan_get_state(v)) || 55 - !__vlan_tun_put(skb, v)) 55 + !__vlan_tun_put(skb, v) || 56 + nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS, 57 + !!(v->priv_flags & BR_VLFLAG_NEIGH_SUPPRESS_ENABLED))) 56 58 return false; 57 59 58 60 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING ··· 82 80 + nla_total_size(sizeof(u32)) /* BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS */ 83 81 + nla_total_size(sizeof(u32)) /* BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS */ 84 82 #endif 83 + + nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS */ 85 84 + 0; 86 85 } 87 86 ··· 241 238 *changed = true; 242 239 } 243 240 #endif 241 + 242 + if (tb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]) { 243 + bool enabled = v->priv_flags & BR_VLFLAG_NEIGH_SUPPRESS_ENABLED; 244 + bool val = nla_get_u8(tb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]); 245 + 246 + if (!p) { 247 + NL_SET_ERR_MSG_MOD(extack, "Can't set neigh_suppress for non-port vlans"); 248 + return -EINVAL; 249 + } 250 + 251 + if (val != enabled) { 252 + v->priv_flags ^= BR_VLFLAG_NEIGH_SUPPRESS_ENABLED; 253 + *changed = true; 254 + } 255 + } 244 256 245 257 return 0; 246 258 }
+1 -1
net/core/rtnetlink.c
··· 61 61 #include "dev.h" 62 62 63 63 #define RTNL_MAX_TYPE 50 64 - #define RTNL_SLAVE_MAX_TYPE 42 64 + #define RTNL_SLAVE_MAX_TYPE 43 65 65 66 66 struct rtnl_link { 67 67 rtnl_doit_func doit;
+1
tools/testing/selftests/net/Makefile
··· 83 83 TEST_GEN_FILES += ip_local_port_range 84 84 TEST_GEN_FILES += bind_wildcard 85 85 TEST_PROGS += test_vxlan_mdb.sh 86 + TEST_PROGS += test_bridge_neigh_suppress.sh 86 87 87 88 TEST_FILES := settings 88 89
+862
tools/testing/selftests/net/test_bridge_neigh_suppress.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # This test is for checking bridge neighbor suppression functionality. The 5 + # topology consists of two bridges (VTEPs) connected using VXLAN. A single 6 + # host is connected to each bridge over multiple VLANs. The test checks that 7 + # ARP/NS messages from the first host are suppressed on the VXLAN port when 8 + # should. 9 + # 10 + # +-----------------------+ +------------------------+ 11 + # | h1 | | h2 | 12 + # | | | | 13 + # | + eth0.10 | | + eth0.10 | 14 + # | | 192.0.2.1/28 | | | 192.0.2.2/28 | 15 + # | | 2001:db8:1::1/64 | | | 2001:db8:1::2/64 | 16 + # | | | | | | 17 + # | | + eth0.20 | | | + eth0.20 | 18 + # | \ | 192.0.2.17/28 | | \ | 192.0.2.18/28 | 19 + # | \ | 2001:db8:2::1/64 | | \ | 2001:db8:2::2/64 | 20 + # | \| | | \| | 21 + # | + eth0 | | + eth0 | 22 + # +----|------------------+ +----|-------------------+ 23 + # | | 24 + # | | 25 + # +----|-------------------------------+ +----|-------------------------------+ 26 + # | + swp1 + vx0 | | + swp1 + vx0 | 27 + # | | | | | | | | 28 + # | | br0 | | | | | | 29 + # | +------------+-----------+ | | +------------+-----------+ | 30 + # | | | | | | 31 + # | | | | | | 32 + # | +---+---+ | | +---+---+ | 33 + # | | | | | | | | 34 + # | | | | | | | | 35 + # | + + | | + + | 36 + # | br0.10 br0.20 | | br0.10 br0.20 | 37 + # | | | | 38 + # | 192.0.2.33 | | 192.0.2.34 | 39 + # | + lo | | + lo | 40 + # | | | | 41 + # | | | | 42 + # | 192.0.2.49/28 | | 192.0.2.50/28 | 43 + # | veth0 +-------+ veth0 | 44 + # | | | | 45 + # | sw1 | | sw2 | 46 + # +------------------------------------+ +------------------------------------+ 47 + 48 + ret=0 49 + # Kselftest framework requirement - SKIP code is 4. 50 + ksft_skip=4 51 + 52 + # All tests in this script. Can be overridden with -t option. 53 + TESTS=" 54 + neigh_suppress_arp 55 + neigh_suppress_ns 56 + neigh_vlan_suppress_arp 57 + neigh_vlan_suppress_ns 58 + " 59 + VERBOSE=0 60 + PAUSE_ON_FAIL=no 61 + PAUSE=no 62 + 63 + ################################################################################ 64 + # Utilities 65 + 66 + log_test() 67 + { 68 + local rc=$1 69 + local expected=$2 70 + local msg="$3" 71 + 72 + if [ ${rc} -eq ${expected} ]; then 73 + printf "TEST: %-60s [ OK ]\n" "${msg}" 74 + nsuccess=$((nsuccess+1)) 75 + else 76 + ret=1 77 + nfail=$((nfail+1)) 78 + printf "TEST: %-60s [FAIL]\n" "${msg}" 79 + if [ "$VERBOSE" = "1" ]; then 80 + echo " rc=$rc, expected $expected" 81 + fi 82 + 83 + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 84 + echo 85 + echo "hit enter to continue, 'q' to quit" 86 + read a 87 + [ "$a" = "q" ] && exit 1 88 + fi 89 + fi 90 + 91 + if [ "${PAUSE}" = "yes" ]; then 92 + echo 93 + echo "hit enter to continue, 'q' to quit" 94 + read a 95 + [ "$a" = "q" ] && exit 1 96 + fi 97 + 98 + [ "$VERBOSE" = "1" ] && echo 99 + } 100 + 101 + run_cmd() 102 + { 103 + local cmd="$1" 104 + local out 105 + local stderr="2>/dev/null" 106 + 107 + if [ "$VERBOSE" = "1" ]; then 108 + printf "COMMAND: $cmd\n" 109 + stderr= 110 + fi 111 + 112 + out=$(eval $cmd $stderr) 113 + rc=$? 114 + if [ "$VERBOSE" = "1" -a -n "$out" ]; then 115 + echo " $out" 116 + fi 117 + 118 + return $rc 119 + } 120 + 121 + tc_check_packets() 122 + { 123 + local ns=$1; shift 124 + local id=$1; shift 125 + local handle=$1; shift 126 + local count=$1; shift 127 + local pkts 128 + 129 + sleep 0.1 130 + pkts=$(tc -n $ns -j -s filter show $id \ 131 + | jq ".[] | select(.options.handle == $handle) | \ 132 + .options.actions[0].stats.packets") 133 + [[ $pkts == $count ]] 134 + } 135 + 136 + ################################################################################ 137 + # Setup 138 + 139 + setup_topo_ns() 140 + { 141 + local ns=$1; shift 142 + 143 + ip netns add $ns 144 + ip -n $ns link set dev lo up 145 + 146 + ip netns exec $ns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1 147 + ip netns exec $ns sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1 148 + ip netns exec $ns sysctl -qw net.ipv6.conf.all.accept_dad=0 149 + ip netns exec $ns sysctl -qw net.ipv6.conf.default.accept_dad=0 150 + } 151 + 152 + setup_topo() 153 + { 154 + local ns 155 + 156 + for ns in h1 h2 sw1 sw2; do 157 + setup_topo_ns $ns 158 + done 159 + 160 + ip link add name veth0 type veth peer name veth1 161 + ip link set dev veth0 netns h1 name eth0 162 + ip link set dev veth1 netns sw1 name swp1 163 + 164 + ip link add name veth0 type veth peer name veth1 165 + ip link set dev veth0 netns sw1 name veth0 166 + ip link set dev veth1 netns sw2 name veth0 167 + 168 + ip link add name veth0 type veth peer name veth1 169 + ip link set dev veth0 netns h2 name eth0 170 + ip link set dev veth1 netns sw2 name swp1 171 + } 172 + 173 + setup_host_common() 174 + { 175 + local ns=$1; shift 176 + local v4addr1=$1; shift 177 + local v4addr2=$1; shift 178 + local v6addr1=$1; shift 179 + local v6addr2=$1; shift 180 + 181 + ip -n $ns link set dev eth0 up 182 + ip -n $ns link add link eth0 name eth0.10 up type vlan id 10 183 + ip -n $ns link add link eth0 name eth0.20 up type vlan id 20 184 + 185 + ip -n $ns address add $v4addr1 dev eth0.10 186 + ip -n $ns address add $v4addr2 dev eth0.20 187 + ip -n $ns address add $v6addr1 dev eth0.10 188 + ip -n $ns address add $v6addr2 dev eth0.20 189 + } 190 + 191 + setup_h1() 192 + { 193 + local ns=h1 194 + local v4addr1=192.0.2.1/28 195 + local v4addr2=192.0.2.17/28 196 + local v6addr1=2001:db8:1::1/64 197 + local v6addr2=2001:db8:2::1/64 198 + 199 + setup_host_common $ns $v4addr1 $v4addr2 $v6addr1 $v6addr2 200 + } 201 + 202 + setup_h2() 203 + { 204 + local ns=h2 205 + local v4addr1=192.0.2.2/28 206 + local v4addr2=192.0.2.18/28 207 + local v6addr1=2001:db8:1::2/64 208 + local v6addr2=2001:db8:2::2/64 209 + 210 + setup_host_common $ns $v4addr1 $v4addr2 $v6addr1 $v6addr2 211 + } 212 + 213 + setup_sw_common() 214 + { 215 + local ns=$1; shift 216 + local local_addr=$1; shift 217 + local remote_addr=$1; shift 218 + local veth_addr=$1; shift 219 + local gw_addr=$1; shift 220 + 221 + ip -n $ns address add $local_addr/32 dev lo 222 + 223 + ip -n $ns link set dev veth0 up 224 + ip -n $ns address add $veth_addr/28 dev veth0 225 + ip -n $ns route add default via $gw_addr 226 + 227 + ip -n $ns link add name br0 up type bridge vlan_filtering 1 \ 228 + vlan_default_pvid 0 mcast_snooping 0 229 + 230 + ip -n $ns link add link br0 name br0.10 up type vlan id 10 231 + bridge -n $ns vlan add vid 10 dev br0 self 232 + 233 + ip -n $ns link add link br0 name br0.20 up type vlan id 20 234 + bridge -n $ns vlan add vid 20 dev br0 self 235 + 236 + ip -n $ns link set dev swp1 up master br0 237 + bridge -n $ns vlan add vid 10 dev swp1 238 + bridge -n $ns vlan add vid 20 dev swp1 239 + 240 + ip -n $ns link add name vx0 up master br0 type vxlan \ 241 + local $local_addr dstport 4789 nolearning external 242 + bridge -n $ns fdb add 00:00:00:00:00:00 dev vx0 self static \ 243 + dst $remote_addr src_vni 10010 244 + bridge -n $ns fdb add 00:00:00:00:00:00 dev vx0 self static \ 245 + dst $remote_addr src_vni 10020 246 + bridge -n $ns link set dev vx0 vlan_tunnel on learning off 247 + 248 + bridge -n $ns vlan add vid 10 dev vx0 249 + bridge -n $ns vlan add vid 10 dev vx0 tunnel_info id 10010 250 + 251 + bridge -n $ns vlan add vid 20 dev vx0 252 + bridge -n $ns vlan add vid 20 dev vx0 tunnel_info id 10020 253 + } 254 + 255 + setup_sw1() 256 + { 257 + local ns=sw1 258 + local local_addr=192.0.2.33 259 + local remote_addr=192.0.2.34 260 + local veth_addr=192.0.2.49 261 + local gw_addr=192.0.2.50 262 + 263 + setup_sw_common $ns $local_addr $remote_addr $veth_addr $gw_addr 264 + } 265 + 266 + setup_sw2() 267 + { 268 + local ns=sw2 269 + local local_addr=192.0.2.34 270 + local remote_addr=192.0.2.33 271 + local veth_addr=192.0.2.50 272 + local gw_addr=192.0.2.49 273 + 274 + setup_sw_common $ns $local_addr $remote_addr $veth_addr $gw_addr 275 + } 276 + 277 + setup() 278 + { 279 + set -e 280 + 281 + setup_topo 282 + setup_h1 283 + setup_h2 284 + setup_sw1 285 + setup_sw2 286 + 287 + sleep 5 288 + 289 + set +e 290 + } 291 + 292 + cleanup() 293 + { 294 + local ns 295 + 296 + for ns in h1 h2 sw1 sw2; do 297 + ip netns del $ns &> /dev/null 298 + done 299 + } 300 + 301 + ################################################################################ 302 + # Tests 303 + 304 + neigh_suppress_arp_common() 305 + { 306 + local vid=$1; shift 307 + local sip=$1; shift 308 + local tip=$1; shift 309 + local h2_mac 310 + 311 + echo 312 + echo "Per-port ARP suppression - VLAN $vid" 313 + echo "----------------------------------" 314 + 315 + run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" 316 + run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip arp_sip $sip arp_op request action pass" 317 + 318 + # Initial state - check that ARP requests are not suppressed and that 319 + # ARP replies are received. 320 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" 321 + log_test $? 0 "arping" 322 + tc_check_packets sw1 "dev vx0 egress" 101 1 323 + log_test $? 0 "ARP suppression" 324 + 325 + # Enable neighbor suppression and check that nothing changes compared 326 + # to the initial state. 327 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" 328 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" 329 + log_test $? 0 "\"neigh_suppress\" is on" 330 + 331 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" 332 + log_test $? 0 "arping" 333 + tc_check_packets sw1 "dev vx0 egress" 101 2 334 + log_test $? 0 "ARP suppression" 335 + 336 + # Install an FDB entry for the remote host and check that nothing 337 + # changes compared to the initial state. 338 + h2_mac=$(ip -n h2 -j -p link show eth0.$vid | jq -r '.[]["address"]') 339 + run_cmd "bridge -n sw1 fdb replace $h2_mac dev vx0 master static vlan $vid" 340 + log_test $? 0 "FDB entry installation" 341 + 342 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" 343 + log_test $? 0 "arping" 344 + tc_check_packets sw1 "dev vx0 egress" 101 3 345 + log_test $? 0 "ARP suppression" 346 + 347 + # Install a neighbor on the matching SVI interface and check that ARP 348 + # requests are suppressed. 349 + run_cmd "ip -n sw1 neigh replace $tip lladdr $h2_mac nud permanent dev br0.$vid" 350 + log_test $? 0 "Neighbor entry installation" 351 + 352 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" 353 + log_test $? 0 "arping" 354 + tc_check_packets sw1 "dev vx0 egress" 101 3 355 + log_test $? 0 "ARP suppression" 356 + 357 + # Take the second host down and check that ARP requests are suppressed 358 + # and that ARP replies are received. 359 + run_cmd "ip -n h2 link set dev eth0.$vid down" 360 + log_test $? 0 "H2 down" 361 + 362 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" 363 + log_test $? 0 "arping" 364 + tc_check_packets sw1 "dev vx0 egress" 101 3 365 + log_test $? 0 "ARP suppression" 366 + 367 + run_cmd "ip -n h2 link set dev eth0.$vid up" 368 + log_test $? 0 "H2 up" 369 + 370 + # Disable neighbor suppression and check that ARP requests are no 371 + # longer suppressed. 372 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off" 373 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" 374 + log_test $? 0 "\"neigh_suppress\" is off" 375 + 376 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" 377 + log_test $? 0 "arping" 378 + tc_check_packets sw1 "dev vx0 egress" 101 4 379 + log_test $? 0 "ARP suppression" 380 + 381 + # Take the second host down and check that ARP requests are not 382 + # suppressed and that ARP replies are not received. 383 + run_cmd "ip -n h2 link set dev eth0.$vid down" 384 + log_test $? 0 "H2 down" 385 + 386 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip -I eth0.$vid $tip" 387 + log_test $? 1 "arping" 388 + tc_check_packets sw1 "dev vx0 egress" 101 5 389 + log_test $? 0 "ARP suppression" 390 + } 391 + 392 + neigh_suppress_arp() 393 + { 394 + local vid=10 395 + local sip=192.0.2.1 396 + local tip=192.0.2.2 397 + 398 + neigh_suppress_arp_common $vid $sip $tip 399 + 400 + vid=20 401 + sip=192.0.2.17 402 + tip=192.0.2.18 403 + neigh_suppress_arp_common $vid $sip $tip 404 + } 405 + 406 + neigh_suppress_ns_common() 407 + { 408 + local vid=$1; shift 409 + local saddr=$1; shift 410 + local daddr=$1; shift 411 + local maddr=$1; shift 412 + local h2_mac 413 + 414 + echo 415 + echo "Per-port NS suppression - VLAN $vid" 416 + echo "---------------------------------" 417 + 418 + run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" 419 + run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr type 135 code 0 action pass" 420 + 421 + # Initial state - check that NS messages are not suppressed and that ND 422 + # messages are received. 423 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" 424 + log_test $? 0 "ndisc6" 425 + tc_check_packets sw1 "dev vx0 egress" 101 1 426 + log_test $? 0 "NS suppression" 427 + 428 + # Enable neighbor suppression and check that nothing changes compared 429 + # to the initial state. 430 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" 431 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" 432 + log_test $? 0 "\"neigh_suppress\" is on" 433 + 434 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" 435 + log_test $? 0 "ndisc6" 436 + tc_check_packets sw1 "dev vx0 egress" 101 2 437 + log_test $? 0 "NS suppression" 438 + 439 + # Install an FDB entry for the remote host and check that nothing 440 + # changes compared to the initial state. 441 + h2_mac=$(ip -n h2 -j -p link show eth0.$vid | jq -r '.[]["address"]') 442 + run_cmd "bridge -n sw1 fdb replace $h2_mac dev vx0 master static vlan $vid" 443 + log_test $? 0 "FDB entry installation" 444 + 445 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" 446 + log_test $? 0 "ndisc6" 447 + tc_check_packets sw1 "dev vx0 egress" 101 3 448 + log_test $? 0 "NS suppression" 449 + 450 + # Install a neighbor on the matching SVI interface and check that NS 451 + # messages are suppressed. 452 + run_cmd "ip -n sw1 neigh replace $daddr lladdr $h2_mac nud permanent dev br0.$vid" 453 + log_test $? 0 "Neighbor entry installation" 454 + 455 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" 456 + log_test $? 0 "ndisc6" 457 + tc_check_packets sw1 "dev vx0 egress" 101 3 458 + log_test $? 0 "NS suppression" 459 + 460 + # Take the second host down and check that NS messages are suppressed 461 + # and that ND messages are received. 462 + run_cmd "ip -n h2 link set dev eth0.$vid down" 463 + log_test $? 0 "H2 down" 464 + 465 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" 466 + log_test $? 0 "ndisc6" 467 + tc_check_packets sw1 "dev vx0 egress" 101 3 468 + log_test $? 0 "NS suppression" 469 + 470 + run_cmd "ip -n h2 link set dev eth0.$vid up" 471 + log_test $? 0 "H2 up" 472 + 473 + # Disable neighbor suppression and check that NS messages are no longer 474 + # suppressed. 475 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off" 476 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" 477 + log_test $? 0 "\"neigh_suppress\" is off" 478 + 479 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" 480 + log_test $? 0 "ndisc6" 481 + tc_check_packets sw1 "dev vx0 egress" 101 4 482 + log_test $? 0 "NS suppression" 483 + 484 + # Take the second host down and check that NS messages are not 485 + # suppressed and that ND messages are not received. 486 + run_cmd "ip -n h2 link set dev eth0.$vid down" 487 + log_test $? 0 "H2 down" 488 + 489 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr -w 5000 $daddr eth0.$vid" 490 + log_test $? 2 "ndisc6" 491 + tc_check_packets sw1 "dev vx0 egress" 101 5 492 + log_test $? 0 "NS suppression" 493 + } 494 + 495 + neigh_suppress_ns() 496 + { 497 + local vid=10 498 + local saddr=2001:db8:1::1 499 + local daddr=2001:db8:1::2 500 + local maddr=ff02::1:ff00:2 501 + 502 + neigh_suppress_ns_common $vid $saddr $daddr $maddr 503 + 504 + vid=20 505 + saddr=2001:db8:2::1 506 + daddr=2001:db8:2::2 507 + maddr=ff02::1:ff00:2 508 + 509 + neigh_suppress_ns_common $vid $saddr $daddr $maddr 510 + } 511 + 512 + neigh_vlan_suppress_arp() 513 + { 514 + local vid1=10 515 + local vid2=20 516 + local sip1=192.0.2.1 517 + local sip2=192.0.2.17 518 + local tip1=192.0.2.2 519 + local tip2=192.0.2.18 520 + local h2_mac1 521 + local h2_mac2 522 + 523 + echo 524 + echo "Per-{Port, VLAN} ARP suppression" 525 + echo "--------------------------------" 526 + 527 + run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" 528 + run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip1 arp_sip $sip1 arp_op request action pass" 529 + run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 102 proto 0x0806 flower indev swp1 arp_tip $tip2 arp_sip $sip2 arp_op request action pass" 530 + 531 + h2_mac1=$(ip -n h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]') 532 + h2_mac2=$(ip -n h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]') 533 + run_cmd "bridge -n sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1" 534 + run_cmd "bridge -n sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2" 535 + run_cmd "ip -n sw1 neigh replace $tip1 lladdr $h2_mac1 nud permanent dev br0.$vid1" 536 + run_cmd "ip -n sw1 neigh replace $tip2 lladdr $h2_mac2 nud permanent dev br0.$vid2" 537 + 538 + # Enable per-{Port, VLAN} neighbor suppression and check that ARP 539 + # requests are not suppressed and that ARP replies are received. 540 + run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress on" 541 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\"" 542 + log_test $? 0 "\"neigh_vlan_suppress\" is on" 543 + 544 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" 545 + log_test $? 0 "arping (VLAN $vid1)" 546 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" 547 + log_test $? 0 "arping (VLAN $vid2)" 548 + 549 + tc_check_packets sw1 "dev vx0 egress" 101 1 550 + log_test $? 0 "ARP suppression (VLAN $vid1)" 551 + tc_check_packets sw1 "dev vx0 egress" 102 1 552 + log_test $? 0 "ARP suppression (VLAN $vid2)" 553 + 554 + # Enable neighbor suppression on VLAN 10 and check that only on this 555 + # VLAN ARP requests are suppressed. 556 + run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress on" 557 + run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\"" 558 + log_test $? 0 "\"neigh_suppress\" is on (VLAN $vid1)" 559 + run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\"" 560 + log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid2)" 561 + 562 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" 563 + log_test $? 0 "arping (VLAN $vid1)" 564 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" 565 + log_test $? 0 "arping (VLAN $vid2)" 566 + 567 + tc_check_packets sw1 "dev vx0 egress" 101 1 568 + log_test $? 0 "ARP suppression (VLAN $vid1)" 569 + tc_check_packets sw1 "dev vx0 egress" 102 2 570 + log_test $? 0 "ARP suppression (VLAN $vid2)" 571 + 572 + # Enable neighbor suppression on the port and check that it has no 573 + # effect compared to previous state. 574 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" 575 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" 576 + log_test $? 0 "\"neigh_suppress\" is on" 577 + 578 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" 579 + log_test $? 0 "arping (VLAN $vid1)" 580 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" 581 + log_test $? 0 "arping (VLAN $vid2)" 582 + 583 + tc_check_packets sw1 "dev vx0 egress" 101 1 584 + log_test $? 0 "ARP suppression (VLAN $vid1)" 585 + tc_check_packets sw1 "dev vx0 egress" 102 3 586 + log_test $? 0 "ARP suppression (VLAN $vid2)" 587 + 588 + # Disable neighbor suppression on the port and check that it has no 589 + # effect compared to previous state. 590 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off" 591 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" 592 + log_test $? 0 "\"neigh_suppress\" is off" 593 + 594 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" 595 + log_test $? 0 "arping (VLAN $vid1)" 596 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" 597 + log_test $? 0 "arping (VLAN $vid2)" 598 + 599 + tc_check_packets sw1 "dev vx0 egress" 101 1 600 + log_test $? 0 "ARP suppression (VLAN $vid1)" 601 + tc_check_packets sw1 "dev vx0 egress" 102 4 602 + log_test $? 0 "ARP suppression (VLAN $vid2)" 603 + 604 + # Disable neighbor suppression on VLAN 10 and check that ARP requests 605 + # are no longer suppressed on this VLAN. 606 + run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress off" 607 + run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\"" 608 + log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid1)" 609 + 610 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" 611 + log_test $? 0 "arping (VLAN $vid1)" 612 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" 613 + log_test $? 0 "arping (VLAN $vid2)" 614 + 615 + tc_check_packets sw1 "dev vx0 egress" 101 2 616 + log_test $? 0 "ARP suppression (VLAN $vid1)" 617 + tc_check_packets sw1 "dev vx0 egress" 102 5 618 + log_test $? 0 "ARP suppression (VLAN $vid2)" 619 + 620 + # Disable per-{Port, VLAN} neighbor suppression, enable neighbor 621 + # suppression on the port and check that on both VLANs ARP requests are 622 + # suppressed. 623 + run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress off" 624 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\"" 625 + log_test $? 0 "\"neigh_vlan_suppress\" is off" 626 + 627 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" 628 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" 629 + log_test $? 0 "\"neigh_suppress\" is on" 630 + 631 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip1 -I eth0.$vid1 $tip1" 632 + log_test $? 0 "arping (VLAN $vid1)" 633 + run_cmd "ip netns exec h1 arping -q -b -c 1 -w 5 -s $sip2 -I eth0.$vid2 $tip2" 634 + log_test $? 0 "arping (VLAN $vid2)" 635 + 636 + tc_check_packets sw1 "dev vx0 egress" 101 2 637 + log_test $? 0 "ARP suppression (VLAN $vid1)" 638 + tc_check_packets sw1 "dev vx0 egress" 102 5 639 + log_test $? 0 "ARP suppression (VLAN $vid2)" 640 + } 641 + 642 + neigh_vlan_suppress_ns() 643 + { 644 + local vid1=10 645 + local vid2=20 646 + local saddr1=2001:db8:1::1 647 + local saddr2=2001:db8:2::1 648 + local daddr1=2001:db8:1::2 649 + local daddr2=2001:db8:2::2 650 + local maddr=ff02::1:ff00:2 651 + local h2_mac1 652 + local h2_mac2 653 + 654 + echo 655 + echo "Per-{Port, VLAN} NS suppression" 656 + echo "-------------------------------" 657 + 658 + run_cmd "tc -n sw1 qdisc replace dev vx0 clsact" 659 + run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr1 type 135 code 0 action pass" 660 + run_cmd "tc -n sw1 filter replace dev vx0 egress pref 1 handle 102 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $maddr src_ip $saddr2 type 135 code 0 action pass" 661 + 662 + h2_mac1=$(ip -n h2 -j -p link show eth0.$vid1 | jq -r '.[]["address"]') 663 + h2_mac2=$(ip -n h2 -j -p link show eth0.$vid2 | jq -r '.[]["address"]') 664 + run_cmd "bridge -n sw1 fdb replace $h2_mac1 dev vx0 master static vlan $vid1" 665 + run_cmd "bridge -n sw1 fdb replace $h2_mac2 dev vx0 master static vlan $vid2" 666 + run_cmd "ip -n sw1 neigh replace $daddr1 lladdr $h2_mac1 nud permanent dev br0.$vid1" 667 + run_cmd "ip -n sw1 neigh replace $daddr2 lladdr $h2_mac2 nud permanent dev br0.$vid2" 668 + 669 + # Enable per-{Port, VLAN} neighbor suppression and check that NS 670 + # messages are not suppressed and that ND messages are received. 671 + run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress on" 672 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress on\"" 673 + log_test $? 0 "\"neigh_vlan_suppress\" is on" 674 + 675 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" 676 + log_test $? 0 "ndisc6 (VLAN $vid1)" 677 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" 678 + log_test $? 0 "ndisc6 (VLAN $vid2)" 679 + 680 + tc_check_packets sw1 "dev vx0 egress" 101 1 681 + log_test $? 0 "NS suppression (VLAN $vid1)" 682 + tc_check_packets sw1 "dev vx0 egress" 102 1 683 + log_test $? 0 "NS suppression (VLAN $vid2)" 684 + 685 + # Enable neighbor suppression on VLAN 10 and check that only on this 686 + # VLAN NS messages are suppressed. 687 + run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress on" 688 + run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress on\"" 689 + log_test $? 0 "\"neigh_suppress\" is on (VLAN $vid1)" 690 + run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid2 | grep \"neigh_suppress off\"" 691 + log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid2)" 692 + 693 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" 694 + log_test $? 0 "ndisc6 (VLAN $vid1)" 695 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" 696 + log_test $? 0 "ndisc6 (VLAN $vid2)" 697 + 698 + tc_check_packets sw1 "dev vx0 egress" 101 1 699 + log_test $? 0 "NS suppression (VLAN $vid1)" 700 + tc_check_packets sw1 "dev vx0 egress" 102 2 701 + log_test $? 0 "NS suppression (VLAN $vid2)" 702 + 703 + # Enable neighbor suppression on the port and check that it has no 704 + # effect compared to previous state. 705 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" 706 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" 707 + log_test $? 0 "\"neigh_suppress\" is on" 708 + 709 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" 710 + log_test $? 0 "ndisc6 (VLAN $vid1)" 711 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" 712 + log_test $? 0 "ndisc6 (VLAN $vid2)" 713 + 714 + tc_check_packets sw1 "dev vx0 egress" 101 1 715 + log_test $? 0 "NS suppression (VLAN $vid1)" 716 + tc_check_packets sw1 "dev vx0 egress" 102 3 717 + log_test $? 0 "NS suppression (VLAN $vid2)" 718 + 719 + # Disable neighbor suppression on the port and check that it has no 720 + # effect compared to previous state. 721 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress off" 722 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress off\"" 723 + log_test $? 0 "\"neigh_suppress\" is off" 724 + 725 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" 726 + log_test $? 0 "ndisc6 (VLAN $vid1)" 727 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" 728 + log_test $? 0 "ndisc6 (VLAN $vid2)" 729 + 730 + tc_check_packets sw1 "dev vx0 egress" 101 1 731 + log_test $? 0 "NS suppression (VLAN $vid1)" 732 + tc_check_packets sw1 "dev vx0 egress" 102 4 733 + log_test $? 0 "NS suppression (VLAN $vid2)" 734 + 735 + # Disable neighbor suppression on VLAN 10 and check that NS messages 736 + # are no longer suppressed on this VLAN. 737 + run_cmd "bridge -n sw1 vlan set vid $vid1 dev vx0 neigh_suppress off" 738 + run_cmd "bridge -n sw1 -d vlan show dev vx0 vid $vid1 | grep \"neigh_suppress off\"" 739 + log_test $? 0 "\"neigh_suppress\" is off (VLAN $vid1)" 740 + 741 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" 742 + log_test $? 0 "ndisc6 (VLAN $vid1)" 743 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" 744 + log_test $? 0 "ndisc6 (VLAN $vid2)" 745 + 746 + tc_check_packets sw1 "dev vx0 egress" 101 2 747 + log_test $? 0 "NS suppression (VLAN $vid1)" 748 + tc_check_packets sw1 "dev vx0 egress" 102 5 749 + log_test $? 0 "NS suppression (VLAN $vid2)" 750 + 751 + # Disable per-{Port, VLAN} neighbor suppression, enable neighbor 752 + # suppression on the port and check that on both VLANs NS messages are 753 + # suppressed. 754 + run_cmd "bridge -n sw1 link set dev vx0 neigh_vlan_suppress off" 755 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_vlan_suppress off\"" 756 + log_test $? 0 "\"neigh_vlan_suppress\" is off" 757 + 758 + run_cmd "bridge -n sw1 link set dev vx0 neigh_suppress on" 759 + run_cmd "bridge -n sw1 -d link show dev vx0 | grep \"neigh_suppress on\"" 760 + log_test $? 0 "\"neigh_suppress\" is on" 761 + 762 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr1 -w 5000 $daddr1 eth0.$vid1" 763 + log_test $? 0 "ndisc6 (VLAN $vid1)" 764 + run_cmd "ip netns exec h1 ndisc6 -q -r 1 -s $saddr2 -w 5000 $daddr2 eth0.$vid2" 765 + log_test $? 0 "ndisc6 (VLAN $vid2)" 766 + 767 + tc_check_packets sw1 "dev vx0 egress" 101 2 768 + log_test $? 0 "NS suppression (VLAN $vid1)" 769 + tc_check_packets sw1 "dev vx0 egress" 102 5 770 + log_test $? 0 "NS suppression (VLAN $vid2)" 771 + } 772 + 773 + ################################################################################ 774 + # Usage 775 + 776 + usage() 777 + { 778 + cat <<EOF 779 + usage: ${0##*/} OPTS 780 + 781 + -t <test> Test(s) to run (default: all) 782 + (options: $TESTS) 783 + -p Pause on fail 784 + -P Pause after each test before cleanup 785 + -v Verbose mode (show commands and output) 786 + EOF 787 + } 788 + 789 + ################################################################################ 790 + # Main 791 + 792 + trap cleanup EXIT 793 + 794 + while getopts ":t:pPvh" opt; do 795 + case $opt in 796 + t) TESTS=$OPTARG;; 797 + p) PAUSE_ON_FAIL=yes;; 798 + P) PAUSE=yes;; 799 + v) VERBOSE=$(($VERBOSE + 1));; 800 + h) usage; exit 0;; 801 + *) usage; exit 1;; 802 + esac 803 + done 804 + 805 + # Make sure we don't pause twice. 806 + [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no 807 + 808 + if [ "$(id -u)" -ne 0 ];then 809 + echo "SKIP: Need root privileges" 810 + exit $ksft_skip; 811 + fi 812 + 813 + if [ ! -x "$(command -v ip)" ]; then 814 + echo "SKIP: Could not run test without ip tool" 815 + exit $ksft_skip 816 + fi 817 + 818 + if [ ! -x "$(command -v bridge)" ]; then 819 + echo "SKIP: Could not run test without bridge tool" 820 + exit $ksft_skip 821 + fi 822 + 823 + if [ ! -x "$(command -v tc)" ]; then 824 + echo "SKIP: Could not run test without tc tool" 825 + exit $ksft_skip 826 + fi 827 + 828 + if [ ! -x "$(command -v arping)" ]; then 829 + echo "SKIP: Could not run test without arping tool" 830 + exit $ksft_skip 831 + fi 832 + 833 + if [ ! -x "$(command -v ndisc6)" ]; then 834 + echo "SKIP: Could not run test without ndisc6 tool" 835 + exit $ksft_skip 836 + fi 837 + 838 + if [ ! -x "$(command -v jq)" ]; then 839 + echo "SKIP: Could not run test without jq tool" 840 + exit $ksft_skip 841 + fi 842 + 843 + bridge link help 2>&1 | grep -q "neigh_vlan_suppress" 844 + if [ $? -ne 0 ]; then 845 + echo "SKIP: iproute2 bridge too old, missing per-VLAN neighbor suppression support" 846 + exit $ksft_skip 847 + fi 848 + 849 + # Start clean. 850 + cleanup 851 + 852 + for t in $TESTS 853 + do 854 + setup; $t; cleanup; 855 + done 856 + 857 + if [ "$TESTS" != "none" ]; then 858 + printf "\nTests passed: %3d\n" ${nsuccess} 859 + printf "Tests failed: %3d\n" ${nfail} 860 + fi 861 + 862 + exit $ret