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

Merge branch 'mlxsw-redirection'

Petr Machata says:

====================
mlxsw: Support traffic redirection from a locked bridge port

Ido Schimmel writes:

It is possible to add a filter that redirects traffic from the ingress
of a bridge port that is locked (i.e., performs security / SMAC lookup)
and has learning enabled. For example:

# ip link add name br0 type bridge
# ip link set dev swp1 master br0
# bridge link set dev swp1 learning on locked on mab on
# tc qdisc add dev swp1 clsact
# tc filter add dev swp1 ingress pref 1 proto ip flower skip_sw src_ip 192.0.2.1 action mirred egress redirect dev swp2

In the kernel's Rx path, this filter is evaluated before the Rx handler
of the bridge, which means that redirected traffic should not be
affected by bridge port configuration such as learning.

However, the hardware data path is a bit different and the redirect
action (FORWARDING_ACTION in hardware) merely attaches a pointer to the
packet, which is later used by the L2 lookup stage to understand how to
forward the packet. Between both stages - ingress ACL and L2 lookup -
learning and security lookup are performed, which means that redirected
traffic is affected by bridge port configuration, unlike in the kernel's
data path.

The learning discrepancy was handled in commit 577fa14d2100 ("mlxsw:
spectrum: Do not process learned records with a dummy FID") by simply
ignoring learning notifications generated by the redirected traffic. A
similar solution is not possible for the security / SMAC lookup since
- unlike learning - the CPU is not involved and packets that failed the
lookup are dropped by the device.

Instead, solve this by prepending the ignore action to the redirect
action and use it to instruct the device to disable both learning and
the security / SMAC lookup for redirected traffic.

Patch #1 adds the ignore action.

Patch #2 prepends the action to the redirect action in flower offload
code.

Patch #3 removes the workaround in commit 577fa14d2100 ("mlxsw:
spectrum: Do not process learned records with a dummy FID") since it is
no longer needed.

Patch #4 adds a test case.
====================

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

+100 -17
+40
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
··· 1887 1887 } 1888 1888 EXPORT_SYMBOL(mlxsw_afa_block_append_fid_set); 1889 1889 1890 + /* Ignore Action 1891 + * ------------- 1892 + * The ignore action is used to ignore basic switching functions such as 1893 + * learning on a per-packet basis. 1894 + */ 1895 + 1896 + #define MLXSW_AFA_IGNORE_CODE 0x0F 1897 + #define MLXSW_AFA_IGNORE_SIZE 1 1898 + 1899 + /* afa_ignore_disable_learning 1900 + * Disable learning on ingress. 1901 + */ 1902 + MLXSW_ITEM32(afa, ignore, disable_learning, 0x00, 29, 1); 1903 + 1904 + /* afa_ignore_disable_security 1905 + * Disable security lookup on ingress. 1906 + * Reserved when Spectrum-1. 1907 + */ 1908 + MLXSW_ITEM32(afa, ignore, disable_security, 0x00, 28, 1); 1909 + 1910 + static void mlxsw_afa_ignore_pack(char *payload, bool disable_learning, 1911 + bool disable_security) 1912 + { 1913 + mlxsw_afa_ignore_disable_learning_set(payload, disable_learning); 1914 + mlxsw_afa_ignore_disable_security_set(payload, disable_security); 1915 + } 1916 + 1917 + int mlxsw_afa_block_append_ignore(struct mlxsw_afa_block *block, 1918 + bool disable_learning, bool disable_security) 1919 + { 1920 + char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_IGNORE_CODE, 1921 + MLXSW_AFA_IGNORE_SIZE); 1922 + 1923 + if (IS_ERR(act)) 1924 + return PTR_ERR(act); 1925 + mlxsw_afa_ignore_pack(act, disable_learning, disable_security); 1926 + return 0; 1927 + } 1928 + EXPORT_SYMBOL(mlxsw_afa_block_append_ignore); 1929 + 1890 1930 /* MC Routing Action 1891 1931 * ----------------- 1892 1932 * The Multicast router action. Can be used by RMFT_V2 - Router Multicast
+2
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
··· 89 89 struct netlink_ext_ack *extack); 90 90 int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block *block, u16 fid, 91 91 struct netlink_ext_ack *extack); 92 + int mlxsw_afa_block_append_ignore(struct mlxsw_afa_block *block, 93 + bool disable_learning, bool disable_security); 92 94 int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block *block, 93 95 u16 expected_irif, u16 min_mtu, 94 96 bool rmid_valid, u32 kvdl_index);
+3 -1
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
··· 1050 1050 int mlxsw_sp_acl_rulei_act_fid_set(struct mlxsw_sp *mlxsw_sp, 1051 1051 struct mlxsw_sp_acl_rule_info *rulei, 1052 1052 u16 fid, struct netlink_ext_ack *extack); 1053 + int mlxsw_sp_acl_rulei_act_ignore(struct mlxsw_sp *mlxsw_sp, 1054 + struct mlxsw_sp_acl_rule_info *rulei, 1055 + bool disable_learning, bool disable_security); 1053 1056 int mlxsw_sp_acl_rulei_act_sample(struct mlxsw_sp *mlxsw_sp, 1054 1057 struct mlxsw_sp_acl_rule_info *rulei, 1055 1058 struct mlxsw_sp_flow_block *block, ··· 1271 1268 struct flow_block_offload *f); 1272 1269 1273 1270 /* spectrum_fid.c */ 1274 - bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index); 1275 1271 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, 1276 1272 u16 fid_index); 1277 1273 int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex);
+9
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
··· 775 775 return mlxsw_afa_block_append_fid_set(rulei->act_block, fid, extack); 776 776 } 777 777 778 + int mlxsw_sp_acl_rulei_act_ignore(struct mlxsw_sp *mlxsw_sp, 779 + struct mlxsw_sp_acl_rule_info *rulei, 780 + bool disable_learning, bool disable_security) 781 + { 782 + return mlxsw_afa_block_append_ignore(rulei->act_block, 783 + disable_learning, 784 + disable_security); 785 + } 786 + 778 787 int mlxsw_sp_acl_rulei_act_sample(struct mlxsw_sp *mlxsw_sp, 779 788 struct mlxsw_sp_acl_rule_info *rulei, 780 789 struct mlxsw_sp_flow_block *block,
-10
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
··· 137 137 [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, 138 138 }; 139 139 140 - bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index) 141 - { 142 - enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY; 143 - struct mlxsw_sp_fid_family *fid_family; 144 - 145 - fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type]; 146 - 147 - return fid_family->start_index == fid_index; 148 - } 149 - 150 140 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, 151 141 u16 fid_index) 152 142 {
+10
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
··· 160 160 */ 161 161 rulei->egress_bind_blocker = 1; 162 162 163 + /* Ignore learning and security lookup as redirection 164 + * using ingress filters happens before the bridge. 165 + */ 166 + err = mlxsw_sp_acl_rulei_act_ignore(mlxsw_sp, rulei, 167 + true, true); 168 + if (err) { 169 + NL_SET_ERR_MSG_MOD(extack, "Cannot append ignore action"); 170 + return err; 171 + } 172 + 163 173 fid = mlxsw_sp_acl_dummy_fid(mlxsw_sp); 164 174 fid_index = mlxsw_sp_fid_index(fid); 165 175 err = mlxsw_sp_acl_rulei_act_fid_set(mlxsw_sp, rulei,
-6
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
··· 3066 3066 goto just_remove; 3067 3067 } 3068 3068 3069 - if (mlxsw_sp_fid_is_dummy(mlxsw_sp, fid)) 3070 - goto just_remove; 3071 - 3072 3069 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid); 3073 3070 if (!mlxsw_sp_port_vlan) { 3074 3071 netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n"); ··· 3132 3135 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Cannot find port representor for LAG\n"); 3133 3136 goto just_remove; 3134 3137 } 3135 - 3136 - if (mlxsw_sp_fid_is_dummy(mlxsw_sp, fid)) 3137 - goto just_remove; 3138 3138 3139 3139 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid); 3140 3140 if (!mlxsw_sp_port_vlan) {
+36
tools/testing/selftests/net/forwarding/bridge_locked_port.sh
··· 9 9 locked_port_mab_roam 10 10 locked_port_mab_config 11 11 locked_port_mab_flush 12 + locked_port_mab_redirect 12 13 " 13 14 14 15 NUM_NETIFS=4 ··· 318 317 bridge link set dev $swp1 learning off locked off mab off 319 318 320 319 log_test "Locked port MAB FDB flush" 320 + } 321 + 322 + # Check that traffic can be redirected from a locked bridge port and that it 323 + # does not create locked FDB entries. 324 + locked_port_mab_redirect() 325 + { 326 + RET=0 327 + check_port_mab_support || return 0 328 + 329 + bridge link set dev $swp1 learning on locked on mab on 330 + tc qdisc add dev $swp1 clsact 331 + tc filter add dev $swp1 ingress protocol all pref 1 handle 101 flower \ 332 + action mirred egress redirect dev $swp2 333 + 334 + ping_do $h1 192.0.2.2 335 + check_err $? "Ping did not work with redirection" 336 + 337 + bridge fdb get `mac_get $h1` br br0 vlan 1 2> /dev/null | \ 338 + grep "dev $swp1" | grep -q "locked" 339 + check_fail $? "Locked entry created for redirected traffic" 340 + 341 + tc filter del dev $swp1 ingress protocol all pref 1 handle 101 flower 342 + 343 + ping_do $h1 192.0.2.2 344 + check_fail $? "Ping worked without redirection" 345 + 346 + bridge fdb get `mac_get $h1` br br0 vlan 1 2> /dev/null | \ 347 + grep "dev $swp1" | grep -q "locked" 348 + check_err $? "Locked entry not created after deleting filter" 349 + 350 + bridge fdb del `mac_get $h1` vlan 1 dev $swp1 master 351 + tc qdisc del dev $swp1 clsact 352 + bridge link set dev $swp1 learning off locked off mab off 353 + 354 + log_test "Locked port MAB redirect" 321 355 } 322 356 323 357 trap cleanup EXIT