diff options
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 27 | ||||
| -rwxr-xr-x | tools/testing/selftests/drivers/net/mlxsw/blackhole_routes.sh | 200 |
2 files changed, 225 insertions, 2 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 230e1f6e192b..6754061d9b72 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | |||
| @@ -364,6 +364,7 @@ enum mlxsw_sp_fib_entry_type { | |||
| 364 | MLXSW_SP_FIB_ENTRY_TYPE_REMOTE, | 364 | MLXSW_SP_FIB_ENTRY_TYPE_REMOTE, |
| 365 | MLXSW_SP_FIB_ENTRY_TYPE_LOCAL, | 365 | MLXSW_SP_FIB_ENTRY_TYPE_LOCAL, |
| 366 | MLXSW_SP_FIB_ENTRY_TYPE_TRAP, | 366 | MLXSW_SP_FIB_ENTRY_TYPE_TRAP, |
| 367 | MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE, | ||
| 367 | 368 | ||
| 368 | /* This is a special case of local delivery, where a packet should be | 369 | /* This is a special case of local delivery, where a packet should be |
| 369 | * decapsulated on reception. Note that there is no corresponding ENCAP, | 370 | * decapsulated on reception. Note that there is no corresponding ENCAP, |
| @@ -3928,6 +3929,7 @@ mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry) | |||
| 3928 | return !!nh_group->adj_index_valid; | 3929 | return !!nh_group->adj_index_valid; |
| 3929 | case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL: | 3930 | case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL: |
| 3930 | return !!nh_group->nh_rif; | 3931 | return !!nh_group->nh_rif; |
| 3932 | case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE: | ||
| 3931 | case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: | 3933 | case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: |
| 3932 | case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP: | 3934 | case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP: |
| 3933 | return true; | 3935 | return true; |
| @@ -3963,6 +3965,7 @@ mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) | |||
| 3963 | int i; | 3965 | int i; |
| 3964 | 3966 | ||
| 3965 | if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL || | 3967 | if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL || |
| 3968 | fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE || | ||
| 3966 | fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP || | 3969 | fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP || |
| 3967 | fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP) { | 3970 | fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP) { |
| 3968 | nh_grp->nexthops->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD; | 3971 | nh_grp->nexthops->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD; |
| @@ -4004,7 +4007,8 @@ mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) | |||
| 4004 | fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry, | 4007 | fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry, |
| 4005 | common); | 4008 | common); |
| 4006 | 4009 | ||
| 4007 | if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL) { | 4010 | if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL || |
| 4011 | fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE) { | ||
| 4008 | list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6, | 4012 | list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6, |
| 4009 | list)->rt->fib6_nh.nh_flags |= RTNH_F_OFFLOAD; | 4013 | list)->rt->fib6_nh.nh_flags |= RTNH_F_OFFLOAD; |
| 4010 | return; | 4014 | return; |
| @@ -4172,6 +4176,19 @@ static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp, | |||
| 4172 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); | 4176 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); |
| 4173 | } | 4177 | } |
| 4174 | 4178 | ||
| 4179 | static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp, | ||
| 4180 | struct mlxsw_sp_fib_entry *fib_entry, | ||
| 4181 | enum mlxsw_reg_ralue_op op) | ||
| 4182 | { | ||
| 4183 | enum mlxsw_reg_ralue_trap_action trap_action; | ||
| 4184 | char ralue_pl[MLXSW_REG_RALUE_LEN]; | ||
| 4185 | |||
| 4186 | trap_action = MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR; | ||
| 4187 | mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); | ||
| 4188 | mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, 0, 0); | ||
| 4189 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); | ||
| 4190 | } | ||
| 4191 | |||
| 4175 | static int | 4192 | static int |
| 4176 | mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp, | 4193 | mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp, |
| 4177 | struct mlxsw_sp_fib_entry *fib_entry, | 4194 | struct mlxsw_sp_fib_entry *fib_entry, |
| @@ -4211,6 +4228,8 @@ static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, | |||
| 4211 | return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op); | 4228 | return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op); |
| 4212 | case MLXSW_SP_FIB_ENTRY_TYPE_TRAP: | 4229 | case MLXSW_SP_FIB_ENTRY_TYPE_TRAP: |
| 4213 | return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op); | 4230 | return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op); |
| 4231 | case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE: | ||
| 4232 | return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op); | ||
| 4214 | case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: | 4233 | case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: |
| 4215 | return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, | 4234 | return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, |
| 4216 | fib_entry, op); | 4235 | fib_entry, op); |
| @@ -4279,8 +4298,10 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp, | |||
| 4279 | case RTN_BROADCAST: | 4298 | case RTN_BROADCAST: |
| 4280 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; | 4299 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; |
| 4281 | return 0; | 4300 | return 0; |
| 4301 | case RTN_BLACKHOLE: | ||
| 4302 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE; | ||
| 4303 | return 0; | ||
| 4282 | case RTN_UNREACHABLE: /* fall through */ | 4304 | case RTN_UNREACHABLE: /* fall through */ |
| 4283 | case RTN_BLACKHOLE: /* fall through */ | ||
| 4284 | case RTN_PROHIBIT: | 4305 | case RTN_PROHIBIT: |
| 4285 | /* Packets hitting these routes need to be trapped, but | 4306 | /* Packets hitting these routes need to be trapped, but |
| 4286 | * can do so with a lower priority than packets directed | 4307 | * can do so with a lower priority than packets directed |
| @@ -5229,6 +5250,8 @@ static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp, | |||
| 5229 | */ | 5250 | */ |
| 5230 | if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) | 5251 | if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) |
| 5231 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; | 5252 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP; |
| 5253 | else if (rt->fib6_type == RTN_BLACKHOLE) | ||
| 5254 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE; | ||
| 5232 | else if (rt->fib6_flags & RTF_REJECT) | 5255 | else if (rt->fib6_flags & RTF_REJECT) |
| 5233 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; | 5256 | fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; |
| 5234 | else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt)) | 5257 | else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt)) |
diff --git a/tools/testing/selftests/drivers/net/mlxsw/blackhole_routes.sh b/tools/testing/selftests/drivers/net/mlxsw/blackhole_routes.sh new file mode 100755 index 000000000000..5ba5bef44d5b --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/blackhole_routes.sh | |||
| @@ -0,0 +1,200 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | # | ||
| 4 | # Test that blackhole routes are marked as offloaded and that packets hitting | ||
| 5 | # them are dropped by the ASIC and not by the kernel. | ||
| 6 | # | ||
| 7 | # +---------------------------------+ | ||
| 8 | # | H1 (vrf) | | ||
| 9 | # | + $h1 | | ||
| 10 | # | | 192.0.2.1/24 | | ||
| 11 | # | | 2001:db8:1::1/64 | | ||
| 12 | # | | | | ||
| 13 | # | | default via 192.0.2.2 | | ||
| 14 | # | | default via 2001:db8:1::2 | | ||
| 15 | # +----|----------------------------+ | ||
| 16 | # | | ||
| 17 | # +----|----------------------------------------------------------------------+ | ||
| 18 | # | SW | | | ||
| 19 | # | + $rp1 | | ||
| 20 | # | 192.0.2.2/24 | | ||
| 21 | # | 2001:db8:1::2/64 | | ||
| 22 | # | | | ||
| 23 | # | 2001:db8:2::2/64 | | ||
| 24 | # | 198.51.100.2/24 | | ||
| 25 | # | + $rp2 | | ||
| 26 | # | | | | ||
| 27 | # +----|----------------------------------------------------------------------+ | ||
| 28 | # | | ||
| 29 | # +----|----------------------------+ | ||
| 30 | # | | default via 198.51.100.2 | | ||
| 31 | # | | default via 2001:db8:2::2 | | ||
| 32 | # | | | | ||
| 33 | # | | 2001:db8:2::1/64 | | ||
| 34 | # | | 198.51.100.1/24 | | ||
| 35 | # | + $h2 | | ||
| 36 | # | H2 (vrf) | | ||
| 37 | # +---------------------------------+ | ||
| 38 | |||
| 39 | lib_dir=$(dirname $0)/../../../net/forwarding | ||
| 40 | |||
| 41 | ALL_TESTS=" | ||
| 42 | ping_ipv4 | ||
| 43 | ping_ipv6 | ||
| 44 | blackhole_ipv4 | ||
| 45 | blackhole_ipv6 | ||
| 46 | " | ||
| 47 | NUM_NETIFS=4 | ||
| 48 | source $lib_dir/tc_common.sh | ||
| 49 | source $lib_dir/lib.sh | ||
| 50 | |||
| 51 | h1_create() | ||
| 52 | { | ||
| 53 | simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64 | ||
| 54 | |||
| 55 | ip -4 route add default vrf v$h1 nexthop via 192.0.2.2 | ||
| 56 | ip -6 route add default vrf v$h1 nexthop via 2001:db8:1::2 | ||
| 57 | } | ||
| 58 | |||
| 59 | h1_destroy() | ||
| 60 | { | ||
| 61 | ip -6 route del default vrf v$h1 nexthop via 2001:db8:1::2 | ||
| 62 | ip -4 route del default vrf v$h1 nexthop via 192.0.2.2 | ||
| 63 | |||
| 64 | simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64 | ||
| 65 | } | ||
| 66 | |||
| 67 | h2_create() | ||
| 68 | { | ||
| 69 | simple_if_init $h2 198.51.100.1/24 2001:db8:2::1/64 | ||
| 70 | |||
| 71 | ip -4 route add default vrf v$h2 nexthop via 198.51.100.2 | ||
| 72 | ip -6 route add default vrf v$h2 nexthop via 2001:db8:2::2 | ||
| 73 | } | ||
| 74 | |||
| 75 | h2_destroy() | ||
| 76 | { | ||
| 77 | ip -6 route del default vrf v$h2 nexthop via 2001:db8:2::2 | ||
| 78 | ip -4 route del default vrf v$h2 nexthop via 198.51.100.2 | ||
| 79 | |||
| 80 | simple_if_fini $h2 198.51.100.1/24 2001:db8:2::1/64 | ||
| 81 | } | ||
| 82 | |||
| 83 | router_create() | ||
| 84 | { | ||
| 85 | ip link set dev $rp1 up | ||
| 86 | ip link set dev $rp2 up | ||
| 87 | |||
| 88 | tc qdisc add dev $rp1 clsact | ||
| 89 | |||
| 90 | __addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64 | ||
| 91 | __addr_add_del $rp2 add 198.51.100.2/24 2001:db8:2::2/64 | ||
| 92 | } | ||
| 93 | |||
| 94 | router_destroy() | ||
| 95 | { | ||
| 96 | __addr_add_del $rp2 del 198.51.100.2/24 2001:db8:2::2/64 | ||
| 97 | __addr_add_del $rp1 del 192.0.2.2/24 2001:db8:1::2/64 | ||
| 98 | |||
| 99 | tc qdisc del dev $rp1 clsact | ||
| 100 | |||
| 101 | ip link set dev $rp2 down | ||
| 102 | ip link set dev $rp1 down | ||
| 103 | } | ||
| 104 | |||
| 105 | ping_ipv4() | ||
| 106 | { | ||
| 107 | ping_test $h1 198.51.100.1 ": h1->h2" | ||
| 108 | } | ||
| 109 | |||
| 110 | ping_ipv6() | ||
| 111 | { | ||
| 112 | ping6_test $h1 2001:db8:2::1 ": h1->h2" | ||
| 113 | } | ||
| 114 | |||
| 115 | blackhole_ipv4() | ||
| 116 | { | ||
| 117 | # Transmit packets from H1 to H2 and make sure they are dropped by the | ||
| 118 | # ASIC and not by the kernel | ||
| 119 | RET=0 | ||
| 120 | |||
| 121 | ip -4 route add blackhole 198.51.100.0/30 | ||
| 122 | tc filter add dev $rp1 ingress protocol ip pref 1 handle 101 flower \ | ||
| 123 | skip_hw dst_ip 198.51.100.1 src_ip 192.0.2.1 ip_proto icmp \ | ||
| 124 | action pass | ||
| 125 | |||
| 126 | ip -4 route show 198.51.100.0/30 | grep -q offload | ||
| 127 | check_err $? "route not marked as offloaded when should" | ||
| 128 | |||
| 129 | ping_do $h1 198.51.100.1 | ||
| 130 | check_fail $? "ping passed when should not" | ||
| 131 | |||
| 132 | tc_check_packets "dev $rp1 ingress" 101 0 | ||
| 133 | check_err $? "packets trapped and not dropped by ASIC" | ||
| 134 | |||
| 135 | log_test "IPv4 blackhole route" | ||
| 136 | |||
| 137 | tc filter del dev $rp1 ingress protocol ip pref 1 handle 101 flower | ||
| 138 | ip -4 route del blackhole 198.51.100.0/30 | ||
| 139 | } | ||
| 140 | |||
| 141 | blackhole_ipv6() | ||
| 142 | { | ||
| 143 | RET=0 | ||
| 144 | |||
| 145 | ip -6 route add blackhole 2001:db8:2::/120 | ||
| 146 | tc filter add dev $rp1 ingress protocol ipv6 pref 1 handle 101 flower \ | ||
| 147 | skip_hw dst_ip 2001:db8:2::1 src_ip 2001:db8:1::1 \ | ||
| 148 | ip_proto icmpv6 action pass | ||
| 149 | |||
| 150 | ip -6 route show 2001:db8:2::/120 | grep -q offload | ||
| 151 | check_err $? "route not marked as offloaded when should" | ||
| 152 | |||
| 153 | ping6_do $h1 2001:db8:2::1 | ||
| 154 | check_fail $? "ping passed when should not" | ||
| 155 | |||
| 156 | tc_check_packets "dev $rp1 ingress" 101 0 | ||
| 157 | check_err $? "packets trapped and not dropped by ASIC" | ||
| 158 | |||
| 159 | log_test "IPv6 blackhole route" | ||
| 160 | |||
| 161 | tc filter del dev $rp1 ingress protocol ipv6 pref 1 handle 101 flower | ||
| 162 | ip -6 route del blackhole 2001:db8:2::/120 | ||
| 163 | } | ||
| 164 | |||
| 165 | setup_prepare() | ||
| 166 | { | ||
| 167 | h1=${NETIFS[p1]} | ||
| 168 | rp1=${NETIFS[p2]} | ||
| 169 | |||
| 170 | rp2=${NETIFS[p3]} | ||
| 171 | h2=${NETIFS[p4]} | ||
| 172 | |||
| 173 | vrf_prepare | ||
| 174 | forwarding_enable | ||
| 175 | |||
| 176 | h1_create | ||
| 177 | h2_create | ||
| 178 | router_create | ||
| 179 | } | ||
| 180 | |||
| 181 | cleanup() | ||
| 182 | { | ||
| 183 | pre_cleanup | ||
| 184 | |||
| 185 | router_destroy | ||
| 186 | h2_destroy | ||
| 187 | h1_destroy | ||
| 188 | |||
| 189 | forwarding_restore | ||
| 190 | vrf_cleanup | ||
| 191 | } | ||
| 192 | |||
| 193 | trap cleanup EXIT | ||
| 194 | |||
| 195 | setup_prepare | ||
| 196 | setup_wait | ||
| 197 | |||
| 198 | tests_run | ||
| 199 | |||
| 200 | exit $EXIT_STATUS | ||
