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

Merge branch 'mlxsw-Add-VxLAN-support-with-VLAN-aware-bridges'

Ido Schimmel says:

====================
mlxsw: Add VxLAN support with VLAN-aware bridges

Commit 53e50a6ec24d ("Merge branch 'mlxsw-Add-VxLAN-support'") added
mlxsw support for VxLAN when the VxLAN device was enslaved to
VLAN-unaware bridges. This patchset extends mlxsw to also support VxLAN
with VLAN-aware bridges.

With VLAN-aware bridges, the VxLAN device's VNI is mapped to the VLAN
that is configured as 'pvid untagged' on the corresponding bridge port.
To prevent ambiguity, mlxsw forbids configurations in which the same
VLAN is configured as 'pvid untagged' on multiple VxLAN devices.

Patches #1-#2 add the necessary APIs in mlxsw and the bridge driver.

Patches #3-#4 perform small refactoring in order to prepare mlxsw for
VLAN-aware support.

Patch #5 finally enables the enslavement of VxLAN devices to a
VLAN-aware bridge. Among other things, it extends mlxsw to handle
switchdev notifications about VLAN add / delete on a VxLAN device
enslaved to an offloaded VLAN-aware bridge.

Patches #6-#8 add selftests to test the new functionality.
====================

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

+1441 -63
+45 -8
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
··· 4782 4782 return num_vxlans > 1; 4783 4783 } 4784 4784 4785 + static bool mlxsw_sp_bridge_vxlan_vlan_is_valid(struct net_device *br_dev) 4786 + { 4787 + DECLARE_BITMAP(vlans, VLAN_N_VID) = {0}; 4788 + struct net_device *dev; 4789 + struct list_head *iter; 4790 + 4791 + netdev_for_each_lower_dev(br_dev, dev, iter) { 4792 + u16 pvid; 4793 + int err; 4794 + 4795 + if (!netif_is_vxlan(dev)) 4796 + continue; 4797 + 4798 + err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid); 4799 + if (err || !pvid) 4800 + continue; 4801 + 4802 + if (test_and_set_bit(pvid, vlans)) 4803 + return false; 4804 + } 4805 + 4806 + return true; 4807 + } 4808 + 4785 4809 static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev, 4786 4810 struct netlink_ext_ack *extack) 4787 4811 { ··· 4814 4790 return false; 4815 4791 } 4816 4792 4817 - if (br_vlan_enabled(br_dev)) { 4818 - NL_SET_ERR_MSG_MOD(extack, "VLAN filtering can not be enabled on a bridge with a VxLAN device"); 4793 + if (!br_vlan_enabled(br_dev) && 4794 + mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) { 4795 + NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge"); 4819 4796 return false; 4820 4797 } 4821 4798 4822 - if (mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) { 4823 - NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge"); 4799 + if (br_vlan_enabled(br_dev) && 4800 + !mlxsw_sp_bridge_vxlan_vlan_is_valid(br_dev)) { 4801 + NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices cannot have the same VLAN as PVID and egress untagged"); 4824 4802 return false; 4825 4803 } 4826 4804 ··· 5197 5171 if (cu_info->linking) { 5198 5172 if (!netif_running(dev)) 5199 5173 return 0; 5174 + /* When the bridge is VLAN-aware, the VNI of the VxLAN 5175 + * device needs to be mapped to a VLAN, but at this 5176 + * point no VLANs are configured on the VxLAN device 5177 + */ 5178 + if (br_vlan_enabled(upper_dev)) 5179 + return 0; 5200 5180 return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, 5201 - dev, extack); 5181 + dev, 0, extack); 5202 5182 } else { 5203 - mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev); 5183 + /* VLANs were already flushed, which triggered the 5184 + * necessary cleanup 5185 + */ 5186 + if (br_vlan_enabled(upper_dev)) 5187 + return 0; 5188 + mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev); 5204 5189 } 5205 5190 break; 5206 5191 case NETDEV_PRE_UP: ··· 5222 5185 return 0; 5223 5186 if (!mlxsw_sp_lower_get(upper_dev)) 5224 5187 return 0; 5225 - return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, 5188 + return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, 0, 5226 5189 extack); 5227 5190 case NETDEV_DOWN: 5228 5191 upper_dev = netdev_master_upper_dev_get(dev); ··· 5232 5195 return 0; 5233 5196 if (!mlxsw_sp_lower_get(upper_dev)) 5234 5197 return 0; 5235 - mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev); 5198 + mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev); 5236 5199 break; 5237 5200 } 5238 5201
+24 -2
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
··· 8 8 #include <linux/netdevice.h> 9 9 #include <linux/rhashtable.h> 10 10 #include <linux/bitops.h> 11 + #include <linux/if_bridge.h> 11 12 #include <linux/if_vlan.h> 12 13 #include <linux/list.h> 13 14 #include <linux/dcbnl.h> ··· 262 261 return !!mlxsw_sp_bridge_vxlan_dev_find(br_dev); 263 262 } 264 263 264 + static inline int 265 + mlxsw_sp_vxlan_mapped_vid(const struct net_device *vxlan_dev, u16 *p_vid) 266 + { 267 + struct bridge_vlan_info vinfo; 268 + u16 vid = 0; 269 + int err; 270 + 271 + err = br_vlan_get_pvid(vxlan_dev, &vid); 272 + if (err || !vid) 273 + goto out; 274 + 275 + err = br_vlan_get_info(vxlan_dev, vid, &vinfo); 276 + if (err || !(vinfo.flags & BRIDGE_VLAN_INFO_UNTAGGED)) 277 + vid = 0; 278 + 279 + out: 280 + *p_vid = vid; 281 + return err; 282 + } 283 + 265 284 static inline bool 266 285 mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port) 267 286 { ··· 379 358 const struct net_device *br_dev); 380 359 int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp, 381 360 const struct net_device *br_dev, 382 - const struct net_device *vxlan_dev, 361 + const struct net_device *vxlan_dev, u16 vid, 383 362 struct netlink_ext_ack *extack); 384 363 void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp, 385 - const struct net_device *br_dev, 386 364 const struct net_device *vxlan_dev); 387 365 388 366 /* spectrum.c */ ··· 773 753 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid); 774 754 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, 775 755 int br_ifindex); 756 + struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp, 757 + u16 vid); 776 758 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp, 777 759 int br_ifindex); 778 760 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
+6
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
··· 1068 1068 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); 1069 1069 } 1070 1070 1071 + struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp, 1072 + u16 vid) 1073 + { 1074 + return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); 1075 + } 1076 + 1071 1077 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp, 1072 1078 int br_ifindex) 1073 1079 {
+357 -50
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
··· 85 85 struct mlxsw_sp_bridge_port *bridge_port, 86 86 struct mlxsw_sp_port *mlxsw_sp_port); 87 87 int (*vxlan_join)(struct mlxsw_sp_bridge_device *bridge_device, 88 - const struct net_device *vxlan_dev, 88 + const struct net_device *vxlan_dev, u16 vid, 89 89 struct netlink_ext_ack *extack); 90 - void (*vxlan_leave)(struct mlxsw_sp_bridge_device *bridge_device, 91 - const struct net_device *vxlan_dev); 92 90 struct mlxsw_sp_fid * 93 91 (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device, 94 92 u16 vid); ··· 2003 2005 2004 2006 static int 2005 2007 mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, 2006 - const struct net_device *vxlan_dev, 2008 + const struct net_device *vxlan_dev, u16 vid, 2007 2009 struct netlink_ext_ack *extack) 2008 2010 { 2009 - WARN_ON(1); 2010 - return -EINVAL; 2011 + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); 2012 + struct vxlan_dev *vxlan = netdev_priv(vxlan_dev); 2013 + struct mlxsw_sp_nve_params params = { 2014 + .type = MLXSW_SP_NVE_TYPE_VXLAN, 2015 + .vni = vxlan->cfg.vni, 2016 + .dev = vxlan_dev, 2017 + }; 2018 + struct mlxsw_sp_fid *fid; 2019 + int err; 2020 + 2021 + /* If the VLAN is 0, we need to find the VLAN that is configured as 2022 + * PVID and egress untagged on the bridge port of the VxLAN device. 2023 + * It is possible no such VLAN exists 2024 + */ 2025 + if (!vid) { 2026 + err = mlxsw_sp_vxlan_mapped_vid(vxlan_dev, &vid); 2027 + if (err || !vid) 2028 + return err; 2029 + } 2030 + 2031 + /* If no other port is member in the VLAN, then the FID does not exist. 2032 + * NVE will be enabled on the FID once a port joins the VLAN 2033 + */ 2034 + fid = mlxsw_sp_fid_8021q_lookup(mlxsw_sp, vid); 2035 + if (!fid) 2036 + return 0; 2037 + 2038 + if (mlxsw_sp_fid_vni_is_set(fid)) { 2039 + err = -EINVAL; 2040 + goto err_vni_exists; 2041 + } 2042 + 2043 + err = mlxsw_sp_nve_fid_enable(mlxsw_sp, fid, &params, extack); 2044 + if (err) 2045 + goto err_nve_fid_enable; 2046 + 2047 + /* The tunnel port does not hold a reference on the FID. Only 2048 + * local ports and the router port 2049 + */ 2050 + mlxsw_sp_fid_put(fid); 2051 + 2052 + return 0; 2053 + 2054 + err_nve_fid_enable: 2055 + err_vni_exists: 2056 + mlxsw_sp_fid_put(fid); 2057 + return err; 2011 2058 } 2012 2059 2013 - static void 2014 - mlxsw_sp_bridge_8021q_vxlan_leave(struct mlxsw_sp_bridge_device *bridge_device, 2015 - const struct net_device *vxlan_dev) 2060 + static struct net_device * 2061 + mlxsw_sp_bridge_8021q_vxlan_dev_find(struct net_device *br_dev, u16 vid) 2016 2062 { 2063 + struct net_device *dev; 2064 + struct list_head *iter; 2065 + 2066 + netdev_for_each_lower_dev(br_dev, dev, iter) { 2067 + u16 pvid; 2068 + int err; 2069 + 2070 + if (!netif_is_vxlan(dev)) 2071 + continue; 2072 + 2073 + err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid); 2074 + if (err || pvid != vid) 2075 + continue; 2076 + 2077 + return dev; 2078 + } 2079 + 2080 + return NULL; 2017 2081 } 2018 2082 2019 2083 static struct mlxsw_sp_fid * ··· 2083 2023 u16 vid) 2084 2024 { 2085 2025 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); 2026 + struct net_device *vxlan_dev; 2027 + struct mlxsw_sp_fid *fid; 2028 + int err; 2086 2029 2087 - return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); 2030 + fid = mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); 2031 + if (IS_ERR(fid)) 2032 + return fid; 2033 + 2034 + if (mlxsw_sp_fid_vni_is_set(fid)) 2035 + return fid; 2036 + 2037 + /* Find the VxLAN device that has the specified VLAN configured as 2038 + * PVID and egress untagged. There can be at most one such device 2039 + */ 2040 + vxlan_dev = mlxsw_sp_bridge_8021q_vxlan_dev_find(bridge_device->dev, 2041 + vid); 2042 + if (!vxlan_dev) 2043 + return fid; 2044 + 2045 + if (!netif_running(vxlan_dev)) 2046 + return fid; 2047 + 2048 + err = mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, vxlan_dev, vid, 2049 + NULL); 2050 + if (err) 2051 + goto err_vxlan_join; 2052 + 2053 + return fid; 2054 + 2055 + err_vxlan_join: 2056 + mlxsw_sp_fid_put(fid); 2057 + return ERR_PTR(err); 2088 2058 } 2089 2059 2090 2060 static struct mlxsw_sp_fid * 2091 2061 mlxsw_sp_bridge_8021q_fid_lookup(struct mlxsw_sp_bridge_device *bridge_device, 2092 2062 u16 vid) 2093 2063 { 2094 - WARN_ON(1); 2095 - return NULL; 2064 + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); 2065 + 2066 + return mlxsw_sp_fid_8021q_lookup(mlxsw_sp, vid); 2096 2067 } 2097 2068 2098 2069 static u16 ··· 2137 2046 .port_join = mlxsw_sp_bridge_8021q_port_join, 2138 2047 .port_leave = mlxsw_sp_bridge_8021q_port_leave, 2139 2048 .vxlan_join = mlxsw_sp_bridge_8021q_vxlan_join, 2140 - .vxlan_leave = mlxsw_sp_bridge_8021q_vxlan_leave, 2141 2049 .fid_get = mlxsw_sp_bridge_8021q_fid_get, 2142 2050 .fid_lookup = mlxsw_sp_bridge_8021q_fid_lookup, 2143 2051 .fid_vid = mlxsw_sp_bridge_8021q_fid_vid, ··· 2205 2115 2206 2116 static int 2207 2117 mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, 2208 - const struct net_device *vxlan_dev, 2118 + const struct net_device *vxlan_dev, u16 vid, 2209 2119 struct netlink_ext_ack *extack) 2210 2120 { 2211 2121 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); ··· 2241 2151 return err; 2242 2152 } 2243 2153 2244 - static void 2245 - mlxsw_sp_bridge_8021d_vxlan_leave(struct mlxsw_sp_bridge_device *bridge_device, 2246 - const struct net_device *vxlan_dev) 2247 - { 2248 - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); 2249 - struct mlxsw_sp_fid *fid; 2250 - 2251 - fid = mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex); 2252 - if (WARN_ON(!fid)) 2253 - return; 2254 - 2255 - /* If the VxLAN device is down, then the FID does not have a VNI */ 2256 - if (!mlxsw_sp_fid_vni_is_set(fid)) 2257 - goto out; 2258 - 2259 - mlxsw_sp_nve_fid_disable(mlxsw_sp, fid); 2260 - out: 2261 - mlxsw_sp_fid_put(fid); 2262 - } 2263 - 2264 2154 static struct mlxsw_sp_fid * 2265 2155 mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device, 2266 2156 u16 vid) ··· 2264 2194 if (!netif_running(vxlan_dev)) 2265 2195 return fid; 2266 2196 2267 - err = mlxsw_sp_bridge_8021d_vxlan_join(bridge_device, vxlan_dev, NULL); 2197 + err = mlxsw_sp_bridge_8021d_vxlan_join(bridge_device, vxlan_dev, 0, 2198 + NULL); 2268 2199 if (err) 2269 2200 goto err_vxlan_join; 2270 2201 ··· 2300 2229 .port_join = mlxsw_sp_bridge_8021d_port_join, 2301 2230 .port_leave = mlxsw_sp_bridge_8021d_port_leave, 2302 2231 .vxlan_join = mlxsw_sp_bridge_8021d_vxlan_join, 2303 - .vxlan_leave = mlxsw_sp_bridge_8021d_vxlan_leave, 2304 2232 .fid_get = mlxsw_sp_bridge_8021d_fid_get, 2305 2233 .fid_lookup = mlxsw_sp_bridge_8021d_fid_lookup, 2306 2234 .fid_vid = mlxsw_sp_bridge_8021d_fid_vid, ··· 2354 2284 2355 2285 int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp, 2356 2286 const struct net_device *br_dev, 2357 - const struct net_device *vxlan_dev, 2287 + const struct net_device *vxlan_dev, u16 vid, 2358 2288 struct netlink_ext_ack *extack) 2359 2289 { 2360 2290 struct mlxsw_sp_bridge_device *bridge_device; ··· 2363 2293 if (WARN_ON(!bridge_device)) 2364 2294 return -EINVAL; 2365 2295 2366 - return bridge_device->ops->vxlan_join(bridge_device, vxlan_dev, extack); 2296 + return bridge_device->ops->vxlan_join(bridge_device, vxlan_dev, vid, 2297 + extack); 2367 2298 } 2368 2299 2369 2300 void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp, 2370 - const struct net_device *br_dev, 2371 2301 const struct net_device *vxlan_dev) 2372 2302 { 2373 - struct mlxsw_sp_bridge_device *bridge_device; 2303 + struct vxlan_dev *vxlan = netdev_priv(vxlan_dev); 2304 + struct mlxsw_sp_fid *fid; 2374 2305 2375 - bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); 2376 - if (WARN_ON(!bridge_device)) 2306 + /* If the VxLAN device is down, then the FID does not have a VNI */ 2307 + fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan->cfg.vni); 2308 + if (!fid) 2377 2309 return; 2378 2310 2379 - bridge_device->ops->vxlan_leave(bridge_device, vxlan_dev); 2311 + mlxsw_sp_nve_fid_disable(mlxsw_sp, fid); 2312 + mlxsw_sp_fid_put(fid); 2380 2313 } 2381 2314 2382 2315 static void ··· 3190 3117 .notifier_call = mlxsw_sp_switchdev_event, 3191 3118 }; 3192 3119 3120 + static int 3121 + mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp, 3122 + struct mlxsw_sp_bridge_device *bridge_device, 3123 + const struct net_device *vxlan_dev, u16 vid, 3124 + bool flag_untagged, bool flag_pvid, 3125 + struct switchdev_trans *trans) 3126 + { 3127 + struct vxlan_dev *vxlan = netdev_priv(vxlan_dev); 3128 + __be32 vni = vxlan->cfg.vni; 3129 + struct mlxsw_sp_fid *fid; 3130 + u16 old_vid; 3131 + int err; 3132 + 3133 + /* We cannot have the same VLAN as PVID and egress untagged on multiple 3134 + * VxLAN devices. Note that we get this notification before the VLAN is 3135 + * actually added to the bridge's database, so it is not possible for 3136 + * the lookup function to return 'vxlan_dev' 3137 + */ 3138 + if (flag_untagged && flag_pvid && 3139 + mlxsw_sp_bridge_8021q_vxlan_dev_find(bridge_device->dev, vid)) 3140 + return -EINVAL; 3141 + 3142 + if (switchdev_trans_ph_prepare(trans)) 3143 + return 0; 3144 + 3145 + if (!netif_running(vxlan_dev)) 3146 + return 0; 3147 + 3148 + /* First case: FID is not associated with this VNI, but the new VLAN 3149 + * is both PVID and egress untagged. Need to enable NVE on the FID, if 3150 + * it exists 3151 + */ 3152 + fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vni); 3153 + if (!fid) { 3154 + if (!flag_untagged || !flag_pvid) 3155 + return 0; 3156 + return mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, 3157 + vxlan_dev, vid, NULL); 3158 + } 3159 + 3160 + /* Second case: FID is associated with the VNI and the VLAN associated 3161 + * with the FID is the same as the notified VLAN. This means the flags 3162 + * (PVID / egress untagged) were toggled and that NVE should be 3163 + * disabled on the FID 3164 + */ 3165 + old_vid = mlxsw_sp_fid_8021q_vid(fid); 3166 + if (vid == old_vid) { 3167 + if (WARN_ON(flag_untagged && flag_pvid)) { 3168 + mlxsw_sp_fid_put(fid); 3169 + return -EINVAL; 3170 + } 3171 + mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, vxlan_dev); 3172 + mlxsw_sp_fid_put(fid); 3173 + return 0; 3174 + } 3175 + 3176 + /* Third case: A new VLAN was configured on the VxLAN device, but this 3177 + * VLAN is not PVID, so there is nothing to do. 3178 + */ 3179 + if (!flag_pvid) { 3180 + mlxsw_sp_fid_put(fid); 3181 + return 0; 3182 + } 3183 + 3184 + /* Fourth case: Thew new VLAN is PVID, which means the VLAN currently 3185 + * mapped to the VNI should be unmapped 3186 + */ 3187 + mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, vxlan_dev); 3188 + mlxsw_sp_fid_put(fid); 3189 + 3190 + /* Fifth case: The new VLAN is also egress untagged, which means the 3191 + * VLAN needs to be mapped to the VNI 3192 + */ 3193 + if (!flag_untagged) 3194 + return 0; 3195 + 3196 + err = mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, vxlan_dev, vid, 3197 + NULL); 3198 + if (err) 3199 + goto err_vxlan_join; 3200 + 3201 + return 0; 3202 + 3203 + err_vxlan_join: 3204 + mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, vxlan_dev, old_vid, 3205 + NULL); 3206 + return err; 3207 + } 3208 + 3209 + static void 3210 + mlxsw_sp_switchdev_vxlan_vlan_del(struct mlxsw_sp *mlxsw_sp, 3211 + struct mlxsw_sp_bridge_device *bridge_device, 3212 + const struct net_device *vxlan_dev, u16 vid) 3213 + { 3214 + struct vxlan_dev *vxlan = netdev_priv(vxlan_dev); 3215 + __be32 vni = vxlan->cfg.vni; 3216 + struct mlxsw_sp_fid *fid; 3217 + 3218 + if (!netif_running(vxlan_dev)) 3219 + return; 3220 + 3221 + fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vni); 3222 + if (!fid) 3223 + return; 3224 + 3225 + /* A different VLAN than the one mapped to the VNI is deleted */ 3226 + if (mlxsw_sp_fid_8021q_vid(fid) != vid) 3227 + goto out; 3228 + 3229 + mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, vxlan_dev); 3230 + 3231 + out: 3232 + mlxsw_sp_fid_put(fid); 3233 + } 3234 + 3235 + static int 3236 + mlxsw_sp_switchdev_vxlan_vlans_add(struct net_device *vxlan_dev, 3237 + struct switchdev_notifier_port_obj_info * 3238 + port_obj_info) 3239 + { 3240 + struct switchdev_obj_port_vlan *vlan = 3241 + SWITCHDEV_OBJ_PORT_VLAN(port_obj_info->obj); 3242 + bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; 3243 + bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 3244 + struct switchdev_trans *trans = port_obj_info->trans; 3245 + struct mlxsw_sp_bridge_device *bridge_device; 3246 + struct mlxsw_sp *mlxsw_sp; 3247 + struct net_device *br_dev; 3248 + u16 vid; 3249 + 3250 + br_dev = netdev_master_upper_dev_get(vxlan_dev); 3251 + if (!br_dev) 3252 + return 0; 3253 + 3254 + mlxsw_sp = mlxsw_sp_lower_get(br_dev); 3255 + if (!mlxsw_sp) 3256 + return 0; 3257 + 3258 + port_obj_info->handled = true; 3259 + 3260 + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); 3261 + if (!bridge_device) 3262 + return -EINVAL; 3263 + 3264 + if (!bridge_device->vlan_enabled) 3265 + return 0; 3266 + 3267 + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { 3268 + int err; 3269 + 3270 + err = mlxsw_sp_switchdev_vxlan_vlan_add(mlxsw_sp, bridge_device, 3271 + vxlan_dev, vid, 3272 + flag_untagged, 3273 + flag_pvid, trans); 3274 + if (err) 3275 + return err; 3276 + } 3277 + 3278 + return 0; 3279 + } 3280 + 3281 + static void 3282 + mlxsw_sp_switchdev_vxlan_vlans_del(struct net_device *vxlan_dev, 3283 + struct switchdev_notifier_port_obj_info * 3284 + port_obj_info) 3285 + { 3286 + struct switchdev_obj_port_vlan *vlan = 3287 + SWITCHDEV_OBJ_PORT_VLAN(port_obj_info->obj); 3288 + struct mlxsw_sp_bridge_device *bridge_device; 3289 + struct mlxsw_sp *mlxsw_sp; 3290 + struct net_device *br_dev; 3291 + u16 vid; 3292 + 3293 + br_dev = netdev_master_upper_dev_get(vxlan_dev); 3294 + if (!br_dev) 3295 + return; 3296 + 3297 + mlxsw_sp = mlxsw_sp_lower_get(br_dev); 3298 + if (!mlxsw_sp) 3299 + return; 3300 + 3301 + port_obj_info->handled = true; 3302 + 3303 + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); 3304 + if (!bridge_device) 3305 + return; 3306 + 3307 + if (!bridge_device->vlan_enabled) 3308 + return; 3309 + 3310 + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) 3311 + mlxsw_sp_switchdev_vxlan_vlan_del(mlxsw_sp, bridge_device, 3312 + vxlan_dev, vid); 3313 + } 3314 + 3315 + static int 3316 + mlxsw_sp_switchdev_handle_vxlan_obj_add(struct net_device *vxlan_dev, 3317 + struct switchdev_notifier_port_obj_info * 3318 + port_obj_info) 3319 + { 3320 + int err = 0; 3321 + 3322 + switch (port_obj_info->obj->id) { 3323 + case SWITCHDEV_OBJ_ID_PORT_VLAN: 3324 + err = mlxsw_sp_switchdev_vxlan_vlans_add(vxlan_dev, 3325 + port_obj_info); 3326 + break; 3327 + default: 3328 + break; 3329 + } 3330 + 3331 + return err; 3332 + } 3333 + 3334 + static void 3335 + mlxsw_sp_switchdev_handle_vxlan_obj_del(struct net_device *vxlan_dev, 3336 + struct switchdev_notifier_port_obj_info * 3337 + port_obj_info) 3338 + { 3339 + switch (port_obj_info->obj->id) { 3340 + case SWITCHDEV_OBJ_ID_PORT_VLAN: 3341 + mlxsw_sp_switchdev_vxlan_vlans_del(vxlan_dev, port_obj_info); 3342 + break; 3343 + default: 3344 + break; 3345 + } 3346 + } 3347 + 3193 3348 static int mlxsw_sp_switchdev_blocking_event(struct notifier_block *unused, 3194 3349 unsigned long event, void *ptr) 3195 3350 { 3196 3351 struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 3197 - int err; 3352 + int err = 0; 3198 3353 3199 3354 switch (event) { 3200 3355 case SWITCHDEV_PORT_OBJ_ADD: 3201 - err = switchdev_handle_port_obj_add(dev, ptr, 3202 - mlxsw_sp_port_dev_check, 3203 - mlxsw_sp_port_obj_add); 3356 + if (netif_is_vxlan(dev)) 3357 + err = mlxsw_sp_switchdev_handle_vxlan_obj_add(dev, ptr); 3358 + else 3359 + err = switchdev_handle_port_obj_add(dev, ptr, 3360 + mlxsw_sp_port_dev_check, 3361 + mlxsw_sp_port_obj_add); 3204 3362 return notifier_from_errno(err); 3205 3363 case SWITCHDEV_PORT_OBJ_DEL: 3206 - err = switchdev_handle_port_obj_del(dev, ptr, 3207 - mlxsw_sp_port_dev_check, 3208 - mlxsw_sp_port_obj_del); 3364 + if (netif_is_vxlan(dev)) 3365 + mlxsw_sp_switchdev_handle_vxlan_obj_del(dev, ptr); 3366 + else 3367 + err = switchdev_handle_port_obj_del(dev, ptr, 3368 + mlxsw_sp_port_dev_check, 3369 + mlxsw_sp_port_obj_del); 3209 3370 return notifier_from_errno(err); 3210 3371 } 3211 3372
+5 -1
net/bridge/br_vlan.c
··· 1217 1217 int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid) 1218 1218 { 1219 1219 struct net_bridge_vlan_group *vg; 1220 + struct net_bridge_port *p; 1220 1221 1221 1222 ASSERT_RTNL(); 1222 - if (netif_is_bridge_master(dev)) 1223 + p = br_port_get_check_rtnl(dev); 1224 + if (p) 1225 + vg = nbp_vlan_group(p); 1226 + else if (netif_is_bridge_master(dev)) 1223 1227 vg = br_vlan_group(netdev_priv(dev)); 1224 1228 else 1225 1229 return -EINVAL;
+204 -2
tools/testing/selftests/drivers/net/mlxsw/vxlan.sh
··· 6 6 7 7 lib_dir=$(dirname $0)/../../../net/forwarding 8 8 9 - ALL_TESTS="sanitization_test offload_indication_test" 9 + ALL_TESTS="sanitization_test offload_indication_test \ 10 + sanitization_vlan_aware_test offload_indication_vlan_aware_test" 10 11 NUM_NETIFS=2 11 12 source $lib_dir/lib.sh 12 13 ··· 82 81 ip link add name vxlan0 up type vxlan id 10 nolearning noudpcsum \ 83 82 ttl 20 tos inherit local 198.51.100.1 dstport 4789 84 83 85 - sanitization_single_dev_test_fail 84 + sanitization_single_dev_test_pass 86 85 87 86 ip link del dev vxlan0 88 87 ip link del dev br0 ··· 653 652 offload_indication_fdb_test 654 653 offload_indication_decap_route_test 655 654 offload_indication_setup_destroy 655 + } 656 + 657 + sanitization_vlan_aware_test() 658 + { 659 + RET=0 660 + 661 + ip link add dev br0 type bridge mcast_snooping 0 vlan_filtering 1 662 + 663 + ip link add name vxlan10 up master br0 type vxlan id 10 nolearning \ 664 + noudpcsum ttl 20 tos inherit local 198.51.100.1 dstport 4789 665 + 666 + ip link add name vxlan20 up master br0 type vxlan id 20 nolearning \ 667 + noudpcsum ttl 20 tos inherit local 198.51.100.1 dstport 4789 668 + 669 + # Test that when each VNI is mapped to a different VLAN we can enslave 670 + # a port to the bridge 671 + bridge vlan add vid 10 dev vxlan10 pvid untagged 672 + bridge vlan add vid 20 dev vxlan20 pvid untagged 673 + 674 + ip link set dev $swp1 master br0 675 + check_err $? 676 + 677 + log_test "vlan-aware - enslavement to vlan-aware bridge" 678 + 679 + # Try to map both VNIs to the same VLAN and make sure configuration 680 + # fails 681 + RET=0 682 + 683 + bridge vlan add vid 10 dev vxlan20 pvid untagged &> /dev/null 684 + check_fail $? 685 + 686 + log_test "vlan-aware - two vnis mapped to the same vlan" 687 + 688 + # Test that enslavement of a port to a bridge fails when two VNIs 689 + # are mapped to the same VLAN 690 + RET=0 691 + 692 + ip link set dev $swp1 nomaster 693 + 694 + bridge vlan del vid 20 dev vxlan20 pvid untagged 695 + bridge vlan add vid 10 dev vxlan20 pvid untagged 696 + 697 + ip link set dev $swp1 master br0 &> /dev/null 698 + check_fail $? 699 + 700 + log_test "vlan-aware - failed enslavement to vlan-aware bridge" 701 + 702 + ip link del dev vxlan20 703 + ip link del dev vxlan10 704 + ip link del dev br0 705 + } 706 + 707 + offload_indication_vlan_aware_setup_create() 708 + { 709 + # Create a simple setup with two VxLAN devices and a single VLAN-aware 710 + # bridge 711 + ip link add name br0 up type bridge mcast_snooping 0 vlan_filtering 1 \ 712 + vlan_default_pvid 0 713 + 714 + ip link set dev $swp1 master br0 715 + 716 + bridge vlan add vid 10 dev $swp1 717 + bridge vlan add vid 20 dev $swp1 718 + 719 + ip address add 198.51.100.1/32 dev lo 720 + 721 + ip link add name vxlan10 up master br0 type vxlan id 10 nolearning \ 722 + noudpcsum ttl 20 tos inherit local 198.51.100.1 dstport 4789 723 + ip link add name vxlan20 up master br0 type vxlan id 20 nolearning \ 724 + noudpcsum ttl 20 tos inherit local 198.51.100.1 dstport 4789 725 + 726 + bridge vlan add vid 10 dev vxlan10 pvid untagged 727 + bridge vlan add vid 20 dev vxlan20 pvid untagged 728 + } 729 + 730 + offload_indication_vlan_aware_setup_destroy() 731 + { 732 + bridge vlan del vid 20 dev vxlan20 733 + bridge vlan del vid 10 dev vxlan10 734 + 735 + ip link del dev vxlan20 736 + ip link del dev vxlan10 737 + 738 + ip address del 198.51.100.1/32 dev lo 739 + 740 + bridge vlan del vid 20 dev $swp1 741 + bridge vlan del vid 10 dev $swp1 742 + 743 + ip link set dev $swp1 nomaster 744 + 745 + ip link del dev br0 746 + } 747 + 748 + offload_indication_vlan_aware_fdb_test() 749 + { 750 + RET=0 751 + 752 + log_info "vxlan entry offload indication - vlan-aware" 753 + 754 + bridge fdb add de:ad:be:ef:13:37 dev vxlan10 self master static \ 755 + dst 198.51.100.2 vlan 10 756 + 757 + bridge fdb show brport vxlan10 | grep de:ad:be:ef:13:37 | grep self \ 758 + | grep -q offload 759 + check_err $? 760 + bridge fdb show brport vxlan10 | grep de:ad:be:ef:13:37 | grep -v self \ 761 + | grep -q offload 762 + check_err $? 763 + 764 + log_test "vxlan entry offload indication - initial state" 765 + 766 + # Remove FDB entry from the bridge driver and check that corresponding 767 + # entry in the VxLAN driver is not marked as offloaded 768 + RET=0 769 + 770 + bridge fdb del de:ad:be:ef:13:37 dev vxlan10 master vlan 10 771 + bridge fdb show brport vxlan10 | grep de:ad:be:ef:13:37 | grep self \ 772 + | grep -q offload 773 + check_fail $? 774 + 775 + log_test "vxlan entry offload indication - after removal from bridge" 776 + 777 + # Add the FDB entry back to the bridge driver and make sure it is 778 + # marked as offloaded in both drivers 779 + RET=0 780 + 781 + bridge fdb add de:ad:be:ef:13:37 dev vxlan10 master static vlan 10 782 + bridge fdb show brport vxlan10 | grep de:ad:be:ef:13:37 | grep self \ 783 + | grep -q offload 784 + check_err $? 785 + bridge fdb show brport vxlan10 | grep de:ad:be:ef:13:37 | grep -v self \ 786 + | grep -q offload 787 + check_err $? 788 + 789 + log_test "vxlan entry offload indication - after re-add to bridge" 790 + 791 + # Remove FDB entry from the VxLAN driver and check that corresponding 792 + # entry in the bridge driver is not marked as offloaded 793 + RET=0 794 + 795 + bridge fdb del de:ad:be:ef:13:37 dev vxlan10 self 796 + bridge fdb show brport vxlan10 | grep de:ad:be:ef:13:37 | grep -v self \ 797 + | grep -q offload 798 + check_fail $? 799 + 800 + log_test "vxlan entry offload indication - after removal from vxlan" 801 + 802 + # Add the FDB entry back to the VxLAN driver and make sure it is 803 + # marked as offloaded in both drivers 804 + RET=0 805 + 806 + bridge fdb add de:ad:be:ef:13:37 dev vxlan10 self dst 198.51.100.2 807 + bridge fdb show brport vxlan10 | grep de:ad:be:ef:13:37 | grep self \ 808 + | grep -q offload 809 + check_err $? 810 + bridge fdb show brport vxlan10 | grep de:ad:be:ef:13:37 | grep -v self \ 811 + | grep -q offload 812 + check_err $? 813 + 814 + log_test "vxlan entry offload indication - after re-add to vxlan" 815 + 816 + bridge fdb del de:ad:be:ef:13:37 dev vxlan10 self master vlan 10 817 + } 818 + 819 + offload_indication_vlan_aware_decap_route_test() 820 + { 821 + RET=0 822 + 823 + ip route show table local | grep 198.51.100.1 | grep -q offload 824 + check_err $? 825 + 826 + # Toggle PVID flag on one VxLAN device and make sure route is still 827 + # marked as offloaded 828 + bridge vlan add vid 10 dev vxlan10 untagged 829 + 830 + ip route show table local | grep 198.51.100.1 | grep -q offload 831 + check_err $? 832 + 833 + # Toggle PVID flag on second VxLAN device and make sure route is no 834 + # longer marked as offloaded 835 + bridge vlan add vid 20 dev vxlan20 untagged 836 + 837 + ip route show table local | grep 198.51.100.1 | grep -q offload 838 + check_fail $? 839 + 840 + # Toggle PVID flag back and make sure route is marked as offloaded 841 + bridge vlan add vid 10 dev vxlan10 pvid untagged 842 + bridge vlan add vid 20 dev vxlan20 pvid untagged 843 + 844 + ip route show table local | grep 198.51.100.1 | grep -q offload 845 + check_err $? 846 + 847 + log_test "vxlan decap route - vni map/unmap" 848 + } 849 + 850 + offload_indication_vlan_aware_test() 851 + { 852 + offload_indication_vlan_aware_setup_create 853 + offload_indication_vlan_aware_fdb_test 854 + offload_indication_vlan_aware_decap_route_test 855 + offload_indication_vlan_aware_setup_destroy 656 856 } 657 857 658 858 trap cleanup EXIT
+790
tools/testing/selftests/net/forwarding/vxlan_bridge_1q.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + # +-----------------------+ +------------------------+ 5 + # | H1 (vrf) | | H2 (vrf) | 6 + # | + $h1.10 | | + $h2.10 | 7 + # | | 192.0.2.1/28 | | | 192.0.2.2/28 | 8 + # | | | | | | 9 + # | | + $h1.20 | | | + $h2.20 | 10 + # | \ | 198.51.100.1/24 | | \ | 198.51.100.2/24 | 11 + # | \| | | \| | 12 + # | + $h1 | | + $h2 | 13 + # +----|------------------+ +----|-------------------+ 14 + # | | 15 + # +----|--------------------------------------------------|-------------------+ 16 + # | SW | | | 17 + # | +--|--------------------------------------------------|-----------------+ | 18 + # | | + $swp1 BR1 (802.1q) + $swp2 | | 19 + # | | vid 10 vid 10 | | 20 + # | | vid 20 vid 20 | | 21 + # | | | | 22 + # | | + vx10 (vxlan) + vx20 (vxlan) | | 23 + # | | local 192.0.2.17 local 192.0.2.17 | | 24 + # | | remote 192.0.2.34 192.0.2.50 remote 192.0.2.34 192.0.2.50 | | 25 + # | | id 1000 dstport $VXPORT id 2000 dstport $VXPORT | | 26 + # | | vid 10 pvid untagged vid 20 pvid untagged | | 27 + # | +-----------------------------------------------------------------------+ | 28 + # | | 29 + # | 192.0.2.32/28 via 192.0.2.18 | 30 + # | 192.0.2.48/28 via 192.0.2.18 | 31 + # | | 32 + # | + $rp1 | 33 + # | | 192.0.2.17/28 | 34 + # +----|----------------------------------------------------------------------+ 35 + # | 36 + # +----|--------------------------------------------------------+ 37 + # | | VRP2 (vrf) | 38 + # | + $rp2 | 39 + # | 192.0.2.18/28 | 40 + # | | (maybe) HW 41 + # ============================================================================= 42 + # | | (likely) SW 43 + # | + v1 (veth) + v3 (veth) | 44 + # | | 192.0.2.33/28 | 192.0.2.49/28 | 45 + # +----|---------------------------------------|----------------+ 46 + # | | 47 + # +----|------------------------------+ +----|------------------------------+ 48 + # | + v2 (veth) NS1 (netns) | | + v4 (veth) NS2 (netns) | 49 + # | 192.0.2.34/28 | | 192.0.2.50/28 | 50 + # | | | | 51 + # | 192.0.2.16/28 via 192.0.2.33 | | 192.0.2.16/28 via 192.0.2.49 | 52 + # | 192.0.2.50/32 via 192.0.2.33 | | 192.0.2.34/32 via 192.0.2.49 | 53 + # | | | | 54 + # | +-------------------------------+ | | +-------------------------------+ | 55 + # | | BR2 (802.1q) | | | | BR2 (802.1q) | | 56 + # | | + vx10 (vxlan) | | | | + vx10 (vxlan) | | 57 + # | | local 192.0.2.34 | | | | local 192.0.2.50 | | 58 + # | | remote 192.0.2.17 | | | | remote 192.0.2.17 | | 59 + # | | remote 192.0.2.50 | | | | remote 192.0.2.34 | | 60 + # | | id 1000 dstport $VXPORT | | | | id 1000 dstport $VXPORT | | 61 + # | | vid 10 pvid untagged | | | | vid 10 pvid untagged | | 62 + # | | | | | | | | 63 + # | | + vx20 (vxlan) | | | | + vx20 (vxlan) | | 64 + # | | local 192.0.2.34 | | | | local 192.0.2.50 | | 65 + # | | remote 192.0.2.17 | | | | remote 192.0.2.17 | | 66 + # | | remote 192.0.2.50 | | | | remote 192.0.2.34 | | 67 + # | | id 2000 dstport $VXPORT | | | | id 2000 dstport $VXPORT | | 68 + # | | vid 20 pvid untagged | | | | vid 20 pvid untagged | | 69 + # | | | | | | | | 70 + # | | + w1 (veth) | | | | + w1 (veth) | | 71 + # | | | vid 10 | | | | | vid 10 | | 72 + # | | | vid 20 | | | | | vid 20 | | 73 + # | +--|----------------------------+ | | +--|----------------------------+ | 74 + # | | | | | | 75 + # | +--|----------------------------+ | | +--|----------------------------+ | 76 + # | | + w2 (veth) VW2 (vrf) | | | | + w2 (veth) VW2 (vrf) | | 77 + # | | |\ | | | | |\ | | 78 + # | | | + w2.10 | | | | | + w2.10 | | 79 + # | | | 192.0.2.3/28 | | | | | 192.0.2.4/28 | | 80 + # | | | | | | | | | | 81 + # | | + w2.20 | | | | + w2.20 | | 82 + # | | 198.51.100.3/24 | | | | 198.51.100.4/24 | | 83 + # | +-------------------------------+ | | +-------------------------------+ | 84 + # +-----------------------------------+ +-----------------------------------+ 85 + 86 + : ${VXPORT:=4789} 87 + export VXPORT 88 + 89 + : ${ALL_TESTS:=" 90 + ping_ipv4 91 + test_flood 92 + test_unicast 93 + reapply_config 94 + ping_ipv4 95 + test_flood 96 + test_unicast 97 + test_learning 98 + "} 99 + 100 + NUM_NETIFS=6 101 + source lib.sh 102 + 103 + h1_create() 104 + { 105 + simple_if_init $h1 106 + tc qdisc add dev $h1 clsact 107 + vlan_create $h1 10 v$h1 192.0.2.1/28 108 + vlan_create $h1 20 v$h1 198.51.100.1/24 109 + } 110 + 111 + h1_destroy() 112 + { 113 + vlan_destroy $h1 20 114 + vlan_destroy $h1 10 115 + tc qdisc del dev $h1 clsact 116 + simple_if_fini $h1 117 + } 118 + 119 + h2_create() 120 + { 121 + simple_if_init $h2 122 + tc qdisc add dev $h2 clsact 123 + vlan_create $h2 10 v$h2 192.0.2.2/28 124 + vlan_create $h2 20 v$h2 198.51.100.2/24 125 + } 126 + 127 + h2_destroy() 128 + { 129 + vlan_destroy $h2 20 130 + vlan_destroy $h2 10 131 + tc qdisc del dev $h2 clsact 132 + simple_if_fini $h2 133 + } 134 + 135 + rp1_set_addr() 136 + { 137 + ip address add dev $rp1 192.0.2.17/28 138 + 139 + ip route add 192.0.2.32/28 nexthop via 192.0.2.18 140 + ip route add 192.0.2.48/28 nexthop via 192.0.2.18 141 + } 142 + 143 + rp1_unset_addr() 144 + { 145 + ip route del 192.0.2.48/28 nexthop via 192.0.2.18 146 + ip route del 192.0.2.32/28 nexthop via 192.0.2.18 147 + 148 + ip address del dev $rp1 192.0.2.17/28 149 + } 150 + 151 + switch_create() 152 + { 153 + ip link add name br1 type bridge vlan_filtering 1 vlan_default_pvid 0 \ 154 + mcast_snooping 0 155 + # Make sure the bridge uses the MAC address of the local port and not 156 + # that of the VxLAN's device. 157 + ip link set dev br1 address $(mac_get $swp1) 158 + ip link set dev br1 up 159 + 160 + ip link set dev $rp1 up 161 + rp1_set_addr 162 + 163 + ip link add name vx10 type vxlan id 1000 \ 164 + local 192.0.2.17 dstport "$VXPORT" \ 165 + nolearning noudpcsum tos inherit ttl 100 166 + ip link set dev vx10 up 167 + 168 + ip link set dev vx10 master br1 169 + bridge vlan add vid 10 dev vx10 pvid untagged 170 + 171 + ip link add name vx20 type vxlan id 2000 \ 172 + local 192.0.2.17 dstport "$VXPORT" \ 173 + nolearning noudpcsum tos inherit ttl 100 174 + ip link set dev vx20 up 175 + 176 + ip link set dev vx20 master br1 177 + bridge vlan add vid 20 dev vx20 pvid untagged 178 + 179 + ip link set dev $swp1 master br1 180 + ip link set dev $swp1 up 181 + bridge vlan add vid 10 dev $swp1 182 + bridge vlan add vid 20 dev $swp1 183 + 184 + ip link set dev $swp2 master br1 185 + ip link set dev $swp2 up 186 + bridge vlan add vid 10 dev $swp2 187 + bridge vlan add vid 20 dev $swp2 188 + 189 + bridge fdb append dev vx10 00:00:00:00:00:00 dst 192.0.2.34 self 190 + bridge fdb append dev vx10 00:00:00:00:00:00 dst 192.0.2.50 self 191 + 192 + bridge fdb append dev vx20 00:00:00:00:00:00 dst 192.0.2.34 self 193 + bridge fdb append dev vx20 00:00:00:00:00:00 dst 192.0.2.50 self 194 + } 195 + 196 + switch_destroy() 197 + { 198 + bridge fdb del dev vx20 00:00:00:00:00:00 dst 192.0.2.50 self 199 + bridge fdb del dev vx20 00:00:00:00:00:00 dst 192.0.2.34 self 200 + 201 + bridge fdb del dev vx10 00:00:00:00:00:00 dst 192.0.2.50 self 202 + bridge fdb del dev vx10 00:00:00:00:00:00 dst 192.0.2.34 self 203 + 204 + bridge vlan del vid 20 dev $swp2 205 + bridge vlan del vid 10 dev $swp2 206 + ip link set dev $swp2 down 207 + ip link set dev $swp2 nomaster 208 + 209 + bridge vlan del vid 20 dev $swp1 210 + bridge vlan del vid 10 dev $swp1 211 + ip link set dev $swp1 down 212 + ip link set dev $swp1 nomaster 213 + 214 + bridge vlan del vid 20 dev vx20 215 + ip link set dev vx20 nomaster 216 + 217 + ip link set dev vx20 down 218 + ip link del dev vx20 219 + 220 + bridge vlan del vid 10 dev vx10 221 + ip link set dev vx10 nomaster 222 + 223 + ip link set dev vx10 down 224 + ip link del dev vx10 225 + 226 + rp1_unset_addr 227 + ip link set dev $rp1 down 228 + 229 + ip link set dev br1 down 230 + ip link del dev br1 231 + } 232 + 233 + vrp2_create() 234 + { 235 + simple_if_init $rp2 192.0.2.18/28 236 + __simple_if_init v1 v$rp2 192.0.2.33/28 237 + __simple_if_init v3 v$rp2 192.0.2.49/28 238 + tc qdisc add dev v1 clsact 239 + } 240 + 241 + vrp2_destroy() 242 + { 243 + tc qdisc del dev v1 clsact 244 + __simple_if_fini v3 192.0.2.49/28 245 + __simple_if_fini v1 192.0.2.33/28 246 + simple_if_fini $rp2 192.0.2.18/28 247 + } 248 + 249 + ns_init_common() 250 + { 251 + local in_if=$1; shift 252 + local in_addr=$1; shift 253 + local other_in_addr=$1; shift 254 + local nh_addr=$1; shift 255 + local host_addr1=$1; shift 256 + local host_addr2=$1; shift 257 + 258 + ip link set dev $in_if up 259 + ip address add dev $in_if $in_addr/28 260 + tc qdisc add dev $in_if clsact 261 + 262 + ip link add name br2 type bridge vlan_filtering 1 vlan_default_pvid 0 263 + ip link set dev br2 up 264 + 265 + ip link add name w1 type veth peer name w2 266 + 267 + ip link set dev w1 master br2 268 + ip link set dev w1 up 269 + 270 + bridge vlan add vid 10 dev w1 271 + bridge vlan add vid 20 dev w1 272 + 273 + ip link add name vx10 type vxlan id 1000 local $in_addr \ 274 + dstport "$VXPORT" 275 + ip link set dev vx10 up 276 + bridge fdb append dev vx10 00:00:00:00:00:00 dst 192.0.2.17 self 277 + bridge fdb append dev vx10 00:00:00:00:00:00 dst $other_in_addr self 278 + 279 + ip link set dev vx10 master br2 280 + tc qdisc add dev vx10 clsact 281 + 282 + bridge vlan add vid 10 dev vx10 pvid untagged 283 + 284 + ip link add name vx20 type vxlan id 2000 local $in_addr \ 285 + dstport "$VXPORT" 286 + ip link set dev vx20 up 287 + bridge fdb append dev vx20 00:00:00:00:00:00 dst 192.0.2.17 self 288 + bridge fdb append dev vx20 00:00:00:00:00:00 dst $other_in_addr self 289 + 290 + ip link set dev vx20 master br2 291 + tc qdisc add dev vx20 clsact 292 + 293 + bridge vlan add vid 20 dev vx20 pvid untagged 294 + 295 + simple_if_init w2 296 + vlan_create w2 10 vw2 $host_addr1/28 297 + vlan_create w2 20 vw2 $host_addr2/24 298 + 299 + ip route add 192.0.2.16/28 nexthop via $nh_addr 300 + ip route add $other_in_addr/32 nexthop via $nh_addr 301 + } 302 + export -f ns_init_common 303 + 304 + ns1_create() 305 + { 306 + ip netns add ns1 307 + ip link set dev v2 netns ns1 308 + in_ns ns1 \ 309 + ns_init_common v2 192.0.2.34 192.0.2.50 192.0.2.33 192.0.2.3 \ 310 + 198.51.100.3 311 + } 312 + 313 + ns1_destroy() 314 + { 315 + ip netns exec ns1 ip link set dev v2 netns 1 316 + ip netns del ns1 317 + } 318 + 319 + ns2_create() 320 + { 321 + ip netns add ns2 322 + ip link set dev v4 netns ns2 323 + in_ns ns2 \ 324 + ns_init_common v4 192.0.2.50 192.0.2.34 192.0.2.49 192.0.2.4 \ 325 + 198.51.100.4 326 + } 327 + 328 + ns2_destroy() 329 + { 330 + ip netns exec ns2 ip link set dev v4 netns 1 331 + ip netns del ns2 332 + } 333 + 334 + setup_prepare() 335 + { 336 + h1=${NETIFS[p1]} 337 + swp1=${NETIFS[p2]} 338 + 339 + swp2=${NETIFS[p3]} 340 + h2=${NETIFS[p4]} 341 + 342 + rp1=${NETIFS[p5]} 343 + rp2=${NETIFS[p6]} 344 + 345 + vrf_prepare 346 + forwarding_enable 347 + 348 + h1_create 349 + h2_create 350 + switch_create 351 + 352 + ip link add name v1 type veth peer name v2 353 + ip link add name v3 type veth peer name v4 354 + vrp2_create 355 + ns1_create 356 + ns2_create 357 + 358 + r1_mac=$(in_ns ns1 mac_get w2) 359 + r2_mac=$(in_ns ns2 mac_get w2) 360 + h2_mac=$(mac_get $h2) 361 + } 362 + 363 + cleanup() 364 + { 365 + pre_cleanup 366 + 367 + ns2_destroy 368 + ns1_destroy 369 + vrp2_destroy 370 + ip link del dev v3 371 + ip link del dev v1 372 + 373 + switch_destroy 374 + h2_destroy 375 + h1_destroy 376 + 377 + forwarding_restore 378 + vrf_cleanup 379 + } 380 + 381 + # For the first round of tests, vx10 and vx20 were the first devices to get 382 + # attached to the bridge, and that at the point that the local IP is already 383 + # configured. Try the other scenario of attaching these devices to a bridge 384 + # that already has local ports members, and only then assign the local IP. 385 + reapply_config() 386 + { 387 + log_info "Reapplying configuration" 388 + 389 + bridge fdb del dev vx20 00:00:00:00:00:00 dst 192.0.2.50 self 390 + bridge fdb del dev vx20 00:00:00:00:00:00 dst 192.0.2.34 self 391 + 392 + bridge fdb del dev vx10 00:00:00:00:00:00 dst 192.0.2.50 self 393 + bridge fdb del dev vx10 00:00:00:00:00:00 dst 192.0.2.34 self 394 + 395 + ip link set dev vx20 nomaster 396 + ip link set dev vx10 nomaster 397 + 398 + rp1_unset_addr 399 + sleep 5 400 + 401 + ip link set dev vx10 master br1 402 + bridge vlan add vid 10 dev vx10 pvid untagged 403 + 404 + ip link set dev vx20 master br1 405 + bridge vlan add vid 20 dev vx20 pvid untagged 406 + 407 + bridge fdb append dev vx10 00:00:00:00:00:00 dst 192.0.2.34 self 408 + bridge fdb append dev vx10 00:00:00:00:00:00 dst 192.0.2.50 self 409 + 410 + bridge fdb append dev vx20 00:00:00:00:00:00 dst 192.0.2.34 self 411 + bridge fdb append dev vx20 00:00:00:00:00:00 dst 192.0.2.50 self 412 + 413 + rp1_set_addr 414 + sleep 5 415 + } 416 + 417 + ping_ipv4() 418 + { 419 + ping_test $h1.10 192.0.2.2 ": local->local vid 10" 420 + ping_test $h1.20 198.51.100.2 ": local->local vid 20" 421 + ping_test $h1.10 192.0.2.3 ": local->remote 1 vid 10" 422 + ping_test $h1.10 192.0.2.4 ": local->remote 2 vid 10" 423 + ping_test $h1.20 198.51.100.3 ": local->remote 1 vid 20" 424 + ping_test $h1.20 198.51.100.4 ": local->remote 2 vid 20" 425 + } 426 + 427 + maybe_in_ns() 428 + { 429 + echo ${1:+in_ns} $1 430 + } 431 + 432 + __flood_counter_add_del() 433 + { 434 + local add_del=$1; shift 435 + local dev=$1; shift 436 + local ns=$1; shift 437 + 438 + # Putting the ICMP capture both to HW and to SW will end up 439 + # double-counting the packets that are trapped to slow path, such as for 440 + # the unicast test. Adding either skip_hw or skip_sw fixes this problem, 441 + # but with skip_hw, the flooded packets are not counted at all, because 442 + # those are dropped due to MAC address mismatch; and skip_sw is a no-go 443 + # for veth-based topologies. 444 + # 445 + # So try to install with skip_sw and fall back to skip_sw if that fails. 446 + 447 + $(maybe_in_ns $ns) __icmp_capture_add_del \ 448 + $add_del 100 "" $dev skip_sw 2>/dev/null || \ 449 + $(maybe_in_ns $ns) __icmp_capture_add_del \ 450 + $add_del 100 "" $dev skip_hw 451 + } 452 + 453 + flood_counter_install() 454 + { 455 + __flood_counter_add_del add "$@" 456 + } 457 + 458 + flood_counter_uninstall() 459 + { 460 + __flood_counter_add_del del "$@" 461 + } 462 + 463 + flood_fetch_stat() 464 + { 465 + local dev=$1; shift 466 + local ns=$1; shift 467 + 468 + $(maybe_in_ns $ns) tc_rule_stats_get $dev 100 ingress 469 + } 470 + 471 + flood_fetch_stats() 472 + { 473 + local counters=("${@}") 474 + local counter 475 + 476 + for counter in "${counters[@]}"; do 477 + flood_fetch_stat $counter 478 + done 479 + } 480 + 481 + vxlan_flood_test() 482 + { 483 + local mac=$1; shift 484 + local dst=$1; shift 485 + local vid=$1; shift 486 + local -a expects=("${@}") 487 + 488 + local -a counters=($h2 "vx10 ns1" "vx20 ns1" "vx10 ns2" "vx20 ns2") 489 + local counter 490 + local key 491 + 492 + # Packets reach the local host tagged whereas they reach the VxLAN 493 + # devices untagged. In order to be able to use the same filter for 494 + # all counters, make sure the packets also reach the local host 495 + # untagged 496 + bridge vlan add vid $vid dev $swp2 untagged 497 + for counter in "${counters[@]}"; do 498 + flood_counter_install $counter 499 + done 500 + 501 + local -a t0s=($(flood_fetch_stats "${counters[@]}")) 502 + $MZ $h1 -Q $vid -c 10 -d 100msec -p 64 -b $mac -B $dst -t icmp -q 503 + sleep 1 504 + local -a t1s=($(flood_fetch_stats "${counters[@]}")) 505 + 506 + for key in ${!t0s[@]}; do 507 + local delta=$((t1s[$key] - t0s[$key])) 508 + local expect=${expects[$key]} 509 + 510 + ((expect == delta)) 511 + check_err $? "${counters[$key]}: Expected to capture $expect packets, got $delta." 512 + done 513 + 514 + for counter in "${counters[@]}"; do 515 + flood_counter_uninstall $counter 516 + done 517 + bridge vlan add vid $vid dev $swp2 518 + } 519 + 520 + __test_flood() 521 + { 522 + local mac=$1; shift 523 + local dst=$1; shift 524 + local vid=$1; shift 525 + local what=$1; shift 526 + local -a expects=("${@}") 527 + 528 + RET=0 529 + 530 + vxlan_flood_test $mac $dst $vid "${expects[@]}" 531 + 532 + log_test "VXLAN: $what" 533 + } 534 + 535 + test_flood() 536 + { 537 + __test_flood de:ad:be:ef:13:37 192.0.2.100 10 "flood vlan 10" \ 538 + 10 10 0 10 0 539 + __test_flood ca:fe:be:ef:13:37 198.51.100.100 20 "flood vlan 20" \ 540 + 10 0 10 0 10 541 + } 542 + 543 + vxlan_fdb_add_del() 544 + { 545 + local add_del=$1; shift 546 + local vid=$1; shift 547 + local mac=$1; shift 548 + local dev=$1; shift 549 + local dst=$1; shift 550 + 551 + bridge fdb $add_del dev $dev $mac self static permanent \ 552 + ${dst:+dst} $dst 2>/dev/null 553 + bridge fdb $add_del dev $dev $mac master static vlan $vid 2>/dev/null 554 + } 555 + 556 + __test_unicast() 557 + { 558 + local mac=$1; shift 559 + local dst=$1; shift 560 + local hit_idx=$1; shift 561 + local vid=$1; shift 562 + local what=$1; shift 563 + 564 + RET=0 565 + 566 + local -a expects=(0 0 0 0 0) 567 + expects[$hit_idx]=10 568 + 569 + vxlan_flood_test $mac $dst $vid "${expects[@]}" 570 + 571 + log_test "VXLAN: $what" 572 + } 573 + 574 + test_unicast() 575 + { 576 + local -a targets=("$h2_mac $h2" 577 + "$r1_mac vx10 192.0.2.34" 578 + "$r2_mac vx10 192.0.2.50") 579 + local target 580 + 581 + log_info "unicast vlan 10" 582 + 583 + for target in "${targets[@]}"; do 584 + vxlan_fdb_add_del add 10 $target 585 + done 586 + 587 + __test_unicast $h2_mac 192.0.2.2 0 10 "local MAC unicast" 588 + __test_unicast $r1_mac 192.0.2.3 1 10 "remote MAC 1 unicast" 589 + __test_unicast $r2_mac 192.0.2.4 3 10 "remote MAC 2 unicast" 590 + 591 + for target in "${targets[@]}"; do 592 + vxlan_fdb_add_del del 10 $target 593 + done 594 + 595 + log_info "unicast vlan 20" 596 + 597 + targets=("$h2_mac $h2" "$r1_mac vx20 192.0.2.34" \ 598 + "$r2_mac vx20 192.0.2.50") 599 + 600 + for target in "${targets[@]}"; do 601 + vxlan_fdb_add_del add 20 $target 602 + done 603 + 604 + __test_unicast $h2_mac 198.51.100.2 0 20 "local MAC unicast" 605 + __test_unicast $r1_mac 198.51.100.3 2 20 "remote MAC 1 unicast" 606 + __test_unicast $r2_mac 198.51.100.4 4 20 "remote MAC 2 unicast" 607 + 608 + for target in "${targets[@]}"; do 609 + vxlan_fdb_add_del del 20 $target 610 + done 611 + } 612 + 613 + vxlan_ping_test() 614 + { 615 + local ping_dev=$1; shift 616 + local ping_dip=$1; shift 617 + local ping_args=$1; shift 618 + local capture_dev=$1; shift 619 + local capture_dir=$1; shift 620 + local capture_pref=$1; shift 621 + local expect=$1; shift 622 + 623 + local t0=$(tc_rule_stats_get $capture_dev $capture_pref $capture_dir) 624 + ping_do $ping_dev $ping_dip "$ping_args" 625 + local t1=$(tc_rule_stats_get $capture_dev $capture_pref $capture_dir) 626 + local delta=$((t1 - t0)) 627 + 628 + # Tolerate a couple stray extra packets. 629 + ((expect <= delta && delta <= expect + 2)) 630 + check_err $? "$capture_dev: Expected to capture $expect packets, got $delta." 631 + } 632 + 633 + __test_learning() 634 + { 635 + local -a expects=(0 0 0 0 0) 636 + local mac=$1; shift 637 + local dst=$1; shift 638 + local vid=$1; shift 639 + local idx1=$1; shift 640 + local idx2=$1; shift 641 + local vx=vx$vid 642 + 643 + # Check that flooding works 644 + RET=0 645 + 646 + expects[0]=10; expects[$idx1]=10; expects[$idx2]=10 647 + vxlan_flood_test $mac $dst $vid "${expects[@]}" 648 + 649 + log_test "VXLAN: flood before learning" 650 + 651 + # Send a packet with source mac set to $mac from host w2 and check that 652 + # a corresponding entry is created in the VxLAN device 653 + RET=0 654 + 655 + in_ns ns1 $MZ w2 -Q $vid -c 1 -p 64 -a $mac -b ff:ff:ff:ff:ff:ff \ 656 + -B $dst -t icmp -q 657 + sleep 1 658 + 659 + bridge fdb show brport $vx | grep $mac | grep -q self 660 + check_err $? 661 + bridge fdb show brport $vx | grep $mac | grep "vlan $vid" \ 662 + | grep -q -v self 663 + check_err $? 664 + 665 + log_test "VXLAN: show learned FDB entry" 666 + 667 + # Repeat first test and check that packets only reach host w2 in ns1 668 + RET=0 669 + 670 + expects[0]=0; expects[$idx1]=10; expects[$idx2]=0 671 + vxlan_flood_test $mac $dst $vid "${expects[@]}" 672 + 673 + log_test "VXLAN: learned FDB entry" 674 + 675 + # Delete the learned FDB entry from the VxLAN and bridge devices and 676 + # check that packets are flooded 677 + RET=0 678 + 679 + bridge fdb del dev $vx $mac master self vlan $vid 680 + sleep 1 681 + 682 + expects[0]=10; expects[$idx1]=10; expects[$idx2]=10 683 + vxlan_flood_test $mac $dst $vid "${expects[@]}" 684 + 685 + log_test "VXLAN: deletion of learned FDB entry" 686 + 687 + # Re-learn the first FDB entry and check that it is correctly aged-out 688 + RET=0 689 + 690 + in_ns ns1 $MZ w2 -Q $vid -c 1 -p 64 -a $mac -b ff:ff:ff:ff:ff:ff \ 691 + -B $dst -t icmp -q 692 + sleep 1 693 + 694 + bridge fdb show brport $vx | grep $mac | grep -q self 695 + check_err $? 696 + bridge fdb show brport $vx | grep $mac | grep "vlan $vid" \ 697 + | grep -q -v self 698 + check_err $? 699 + 700 + expects[0]=0; expects[$idx1]=10; expects[$idx2]=0 701 + vxlan_flood_test $mac $dst $vid "${expects[@]}" 702 + 703 + sleep 20 704 + 705 + bridge fdb show brport $vx | grep $mac | grep -q self 706 + check_fail $? 707 + bridge fdb show brport $vx | grep $mac | grep "vlan $vid" \ 708 + | grep -q -v self 709 + check_fail $? 710 + 711 + expects[0]=10; expects[$idx1]=10; expects[$idx2]=10 712 + vxlan_flood_test $mac $dst $vid "${expects[@]}" 713 + 714 + log_test "VXLAN: Ageing of learned FDB entry" 715 + 716 + # Toggle learning on the bridge port and check that the bridge's FDB 717 + # is populated only when it should 718 + RET=0 719 + 720 + ip link set dev $vx type bridge_slave learning off 721 + 722 + in_ns ns1 $MZ w2 -Q $vid -c 1 -p 64 -a $mac -b ff:ff:ff:ff:ff:ff \ 723 + -B $dst -t icmp -q 724 + sleep 1 725 + 726 + bridge fdb show brport $vx | grep $mac | grep "vlan $vid" \ 727 + | grep -q -v self 728 + check_fail $? 729 + 730 + ip link set dev $vx type bridge_slave learning on 731 + 732 + in_ns ns1 $MZ w2 -Q $vid -c 1 -p 64 -a $mac -b ff:ff:ff:ff:ff:ff \ 733 + -B $dst -t icmp -q 734 + sleep 1 735 + 736 + bridge fdb show brport $vx | grep $mac | grep "vlan $vid" \ 737 + | grep -q -v self 738 + check_err $? 739 + 740 + log_test "VXLAN: learning toggling on bridge port" 741 + } 742 + 743 + test_learning() 744 + { 745 + local mac=de:ad:be:ef:13:37 746 + local dst=192.0.2.100 747 + local vid=10 748 + 749 + # Enable learning on the VxLAN devices and set ageing time to 10 seconds 750 + ip link set dev br1 type bridge ageing_time 1000 751 + ip link set dev vx10 type vxlan ageing 10 752 + ip link set dev vx10 type vxlan learning 753 + ip link set dev vx20 type vxlan ageing 10 754 + ip link set dev vx20 type vxlan learning 755 + reapply_config 756 + 757 + log_info "learning vlan 10" 758 + 759 + __test_learning $mac $dst $vid 1 3 760 + 761 + log_info "learning vlan 20" 762 + 763 + mac=ca:fe:be:ef:13:37 764 + dst=198.51.100.100 765 + vid=20 766 + 767 + __test_learning $mac $dst $vid 2 4 768 + 769 + # Restore previous settings 770 + ip link set dev vx20 type vxlan nolearning 771 + ip link set dev vx20 type vxlan ageing 300 772 + ip link set dev vx10 type vxlan nolearning 773 + ip link set dev vx10 type vxlan ageing 300 774 + ip link set dev br1 type bridge ageing_time 30000 775 + reapply_config 776 + } 777 + 778 + test_all() 779 + { 780 + log_info "Running tests with UDP port $VXPORT" 781 + tests_run 782 + } 783 + 784 + trap cleanup EXIT 785 + 786 + setup_prepare 787 + setup_wait 788 + test_all 789 + 790 + exit $EXIT_STATUS
+10
tools/testing/selftests/net/forwarding/vxlan_bridge_1q_port_8472.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + # A wrapper to run VXLAN tests with an unusual port number. 5 + 6 + VXPORT=8472 7 + ALL_TESTS=" 8 + ping_ipv4 9 + " 10 + source vxlan_bridge_1q.sh