Merge branch 'mlxsw-Add-layer-3-devlink-trap-support'

Ido Schimmel says:

====================
mlxsw: Add layer 3 devlink-trap support

This patch set from Amit adds support in mlxsw for layer 3 traps that
can report drops and exceptions via devlink-trap.

In a similar fashion to the existing layer 2 traps, these traps can send
packets to the CPU that were not routed as intended by the underlying
device.

The traps are divided between the two types detailed in devlink-trap
documentation: drops and exceptions. Unlike drops, packets received via
exception traps are also injected to the kernel's receive path, as they
are required for the correct functioning of the control plane. For
example, packets trapped due to TTL error must be injected to kernel's
receive path for traceroute to work properly.

Patch set overview:

Patch #1 adds the layer 3 drop traps to devlink along with their
documentation.

Patch #2 adds support for layer 3 drop traps in mlxsw.

Patches #3-#5 add selftests for layer 3 drop traps.

Patch #6 adds the layer 3 exception traps to devlink along with their
documentation.

Patches #7-#9 gradually add support for layer 3 exception traps in
mlxsw.

Patches #10-#12 add selftests for layer 3 exception traps.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-11-07 19:51:41 -08:00
commit 7b89c580fb
13 changed files with 1496 additions and 61 deletions

View File

@ -162,6 +162,67 @@ be added to the following table:
- ``drop``
- Traps packets that the device decided to drop because they could not be
enqueued to a transmission queue which is full
* - ``non_ip``
- ``drop``
- Traps packets that the device decided to drop because they need to
undergo a layer 3 lookup, but are not IP or MPLS packets
* - ``uc_dip_over_mc_dmac``
- ``drop``
- Traps packets that the device decided to drop because they need to be
routed and they have a unicast destination IP and a multicast destination
MAC
* - ``dip_is_loopback_address``
- ``drop``
- Traps packets that the device decided to drop because they need to be
routed and their destination IP is the loopback address (i.e., 127.0.0.0/8
and ::1/128)
* - ``sip_is_mc``
- ``drop``
- Traps packets that the device decided to drop because they need to be
routed and their source IP is multicast (i.e., 224.0.0.0/8 and ff::/8)
* - ``sip_is_loopback_address``
- ``drop``
- Traps packets that the device decided to drop because they need to be
routed and their source IP is the loopback address (i.e., 127.0.0.0/8 and ::1/128)
* - ``ip_header_corrupted``
- ``drop``
- Traps packets that the device decided to drop because they need to be
routed and their IP header is corrupted: wrong checksum, wrong IP version
or too short Internet Header Length (IHL)
* - ``ipv4_sip_is_limited_bc``
- ``drop``
- Traps packets that the device decided to drop because they need to be
routed and their source IP is limited broadcast (i.e., 255.255.255.255/32)
* - ``ipv6_mc_dip_reserved_scope``
- ``drop``
- Traps IPv6 packets that the device decided to drop because they need to
be routed and their IPv6 multicast destination IP has a reserved scope
(i.e., ffx0::/16)
* - ``ipv6_mc_dip_interface_local_scope``
- ``drop``
- Traps IPv6 packets that the device decided to drop because they need to
be routed and their IPv6 multicast destination IP has an interface-local scope
(i.e., ffx1::/16)
* - ``mtu_value_is_too_small``
- ``exception``
- Traps packets that should have been routed by the device, but were bigger
than the MTU of the egress interface
* - ``unresolved_neigh``
- ``exception``
- Traps packets that did not have a matching IP neighbour after routing
* - ``mc_reverse_path_forwarding``
- ``exception``
- Traps multicast IP packets that failed reverse-path forwarding (RPF)
check during multicast routing
* - ``reject_route``
- ``exception``
- Traps packets that hit reject routes (i.e., "unreachable", "prohibit")
* - ``ipv4_lpm_miss``
- ``exception``
- Traps unicast IPv4 packets that did not match any route
* - ``ipv6_lpm_miss``
- ``exception``
- Traps unicast IPv6 packets that did not match any route
Driver-specific Packet Traps
============================

View File

@ -5480,6 +5480,7 @@ enum mlxsw_reg_htgt_trap_group {
enum mlxsw_reg_htgt_discard_trap_group {
MLXSW_REG_HTGT_DISCARD_TRAP_GROUP_BASE = MLXSW_REG_HTGT_TRAP_GROUP_MAX,
MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS,
MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS,
};
/* reg_htgt_trap_group

View File

@ -4512,8 +4512,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT, TRAP_TO_CPU, IPV6_MLD,
false),
/* L3 traps */
MLXSW_SP_RXL_MARK(MTUERROR, TRAP_TO_CPU, ROUTER_EXP, false),
MLXSW_SP_RXL_MARK(TTLERROR, TRAP_TO_CPU, ROUTER_EXP, false),
MLXSW_SP_RXL_L3_MARK(LBERROR, MIRROR_TO_CPU, LBERROR, false),
MLXSW_SP_RXL_MARK(IP2ME, TRAP_TO_CPU, IP2ME, false),
MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP,
@ -4540,8 +4538,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, TRAP_TO_CPU, IPV6_ND, false),
MLXSW_SP_RXL_MARK(IPV6_MC_LINK_LOCAL_DEST, TRAP_TO_CPU, ROUTER_EXP,
false),
MLXSW_SP_RXL_MARK(HOST_MISS_IPV4, TRAP_TO_CPU, HOST_MISS, false),
MLXSW_SP_RXL_MARK(HOST_MISS_IPV6, TRAP_TO_CPU, HOST_MISS, false),
MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, TRAP_TO_CPU, ROUTER_EXP, false),
MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, TRAP_TO_CPU, ROUTER_EXP, false),
MLXSW_SP_RXL_MARK(IPIP_DECAP_ERROR, TRAP_TO_CPU, ROUTER_EXP, false),
@ -4556,7 +4552,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
/* Multicast Router Traps */
MLXSW_SP_RXL_MARK(IPV4_PIM, TRAP_TO_CPU, PIM, false),
MLXSW_SP_RXL_MARK(IPV6_PIM, TRAP_TO_CPU, PIM, false),
MLXSW_SP_RXL_MARK(RPF, TRAP_TO_CPU, RPF, false),
MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false),
MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false),
/* NVE traps */

View File

@ -77,6 +77,7 @@ struct mlxsw_sp_router {
struct notifier_block inet6addr_nb;
const struct mlxsw_sp_rif_ops **rif_ops_arr;
const struct mlxsw_sp_ipip_ops **ipip_ops_arr;
u32 adj_discard_index;
};
struct mlxsw_sp_rif {
@ -367,6 +368,7 @@ enum mlxsw_sp_fib_entry_type {
MLXSW_SP_FIB_ENTRY_TYPE_LOCAL,
MLXSW_SP_FIB_ENTRY_TYPE_TRAP,
MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE,
MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE,
/* This is a special case of local delivery, where a packet should be
* decapsulated on reception. Note that there is no corresponding ENCAP,
@ -4196,15 +4198,31 @@ mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl,
}
}
static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index)
{
u32 adj_discard_index = mlxsw_sp->router->adj_discard_index;
enum mlxsw_reg_ratr_trap_action trap_action;
char ratr_pl[MLXSW_REG_RATR_LEN];
trap_action = MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS;
mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true,
MLXSW_REG_RATR_TYPE_ETHERNET, adj_discard_index,
rif_index);
mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
}
static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op)
{
struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
char ralue_pl[MLXSW_REG_RALUE_LEN];
enum mlxsw_reg_ralue_trap_action trap_action;
u16 trap_id = 0;
u32 adjacency_index = 0;
u16 ecmp_size = 0;
int err;
/* In case the nexthop group adjacency index is valid, use it
* with provided ECMP size. Otherwise, setup trap and pass
@ -4214,6 +4232,15 @@ static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
adjacency_index = fib_entry->nh_group->adj_index;
ecmp_size = fib_entry->nh_group->ecmp_size;
} else if (!nh_group->adj_index_valid && nh_group->count &&
nh_group->nh_rif) {
err = mlxsw_sp_adj_discard_write(mlxsw_sp,
nh_group->nh_rif->rif_index);
if (err)
return err;
trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
adjacency_index = mlxsw_sp->router->adj_discard_index;
ecmp_size = 1;
} else {
trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
@ -4273,6 +4300,23 @@ static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp,
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
}
static int
mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op)
{
enum mlxsw_reg_ralue_trap_action trap_action;
char ralue_pl[MLXSW_REG_RALUE_LEN];
u16 trap_id;
trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
trap_id = MLXSW_TRAP_ID_RTR_INGRESS1;
mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, 0);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
}
static int
mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry,
@ -4314,6 +4358,9 @@ static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op);
case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE:
return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op);
case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE:
return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, fib_entry,
op);
case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp,
fib_entry, op);
@ -4391,7 +4438,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
* can do so with a lower priority than packets directed
* at the host, so use action type local instead of trap.
*/
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
return 0;
case RTN_UNICAST:
if (mlxsw_sp_fi_is_gateway(mlxsw_sp, fi))
@ -5351,7 +5398,7 @@ static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
else if (rt->fib6_type == RTN_BLACKHOLE)
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE;
else if (rt->fib6_flags & RTF_REJECT)
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt))
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
else
@ -8123,6 +8170,11 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_neigh_init;
err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
&router->adj_discard_index);
if (err)
goto err_adj_discard_index_alloc;
mlxsw_sp->router->netevent_nb.notifier_call =
mlxsw_sp_router_netevent_event;
err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb);
@ -8151,6 +8203,9 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
err_mp_hash_init:
unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
err_register_netevent_notifier:
mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
router->adj_discard_index);
err_adj_discard_index_alloc:
mlxsw_sp_neigh_fini(mlxsw_sp);
err_neigh_init:
mlxsw_sp_vrs_fini(mlxsw_sp);
@ -8182,6 +8237,8 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp),
&mlxsw_sp->router->fib_nb);
unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
mlxsw_sp->router->adj_discard_index);
mlxsw_sp_neigh_fini(mlxsw_sp);
mlxsw_sp_vrs_fini(mlxsw_sp);
mlxsw_sp_mr_fini(mlxsw_sp);

View File

@ -13,16 +13,27 @@
static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port,
void *priv);
static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port,
void *trap_ctx);
#define MLXSW_SP_TRAP_DROP(_id, _group_id) \
DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \
DEVLINK_TRAP_GROUP_GENERIC(_group_id), \
MLXSW_SP_TRAP_METADATA)
#define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id) \
DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \
DEVLINK_TRAP_GROUP_GENERIC(_group_id), \
MLXSW_SP_TRAP_METADATA)
#define MLXSW_SP_RXL_DISCARD(_id, _group_id) \
MLXSW_RXL(mlxsw_sp_rx_drop_listener, DISCARD_##_id, SET_FW_DEFAULT, \
false, SP_##_group_id, DISCARD)
#define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \
MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id, \
_action, false, SP_##_group_id, DISCARD)
static struct devlink_trap mlxsw_sp_traps_arr[] = {
MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS),
MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
@ -30,6 +41,23 @@ static struct devlink_trap mlxsw_sp_traps_arr[] = {
MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS),
MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS),
MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS),
MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS),
MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS),
MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS),
MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS),
MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, L3_DROPS),
MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DROPS),
MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_DROPS),
MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS),
MLXSW_SP_TRAP_EXCEPTION(RPF, L3_DROPS),
MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_DROPS),
MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, L3_DROPS),
MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, L3_DROPS),
MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, L3_DROPS),
};
static struct mlxsw_listener mlxsw_sp_listeners_arr[] = {
@ -40,6 +68,28 @@ static struct mlxsw_listener mlxsw_sp_listeners_arr[] = {
MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS),
MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS),
MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS),
MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, L3_DISCARDS),
MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DISCARDS),
MLXSW_SP_RXL_EXCEPTION(MTUERROR, ROUTER_EXP, TRAP_TO_CPU),
MLXSW_SP_RXL_EXCEPTION(TTLERROR, ROUTER_EXP, TRAP_TO_CPU),
MLXSW_SP_RXL_EXCEPTION(RPF, RPF, TRAP_TO_CPU),
MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, REMOTE_ROUTE, TRAP_TO_CPU),
MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, HOST_MISS, TRAP_TO_CPU),
MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, HOST_MISS, TRAP_TO_CPU),
MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, REMOTE_ROUTE,
TRAP_EXCEPTION_TO_CPU),
MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, ROUTER_EXP,
TRAP_EXCEPTION_TO_CPU),
MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, ROUTER_EXP,
TRAP_EXCEPTION_TO_CPU),
};
/* Mapping between hardware trap and devlink trap. Multiple hardware traps can
@ -54,6 +104,25 @@ static u16 mlxsw_sp_listener_devlink_map[] = {
DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST,
DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST,
DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER,
DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE,
DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET,
DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC,
DEVLINK_TRAP_GENERIC_ID_DIP_LB,
DEVLINK_TRAP_GENERIC_ID_SIP_MC,
DEVLINK_TRAP_GENERIC_ID_SIP_LB,
DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR,
DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC,
DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE,
DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
DEVLINK_TRAP_GENERIC_ID_MTU_ERROR,
DEVLINK_TRAP_GENERIC_ID_TTL_ERROR,
DEVLINK_TRAP_GENERIC_ID_RPF,
DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE,
DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS,
DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS,
};
static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
@ -104,6 +173,30 @@ static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port,
consume_skb(skb);
}
static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port,
void *trap_ctx)
{
struct devlink_port *in_devlink_port;
struct mlxsw_sp_port *mlxsw_sp_port;
struct mlxsw_sp *mlxsw_sp;
struct devlink *devlink;
mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port))
return;
devlink = priv_to_devlink(mlxsw_sp->core);
in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
local_port);
skb_push(skb, ETH_HLEN);
devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port);
skb_pull(skb, ETH_HLEN);
skb->offload_fwd_mark = 1;
netif_receive_skb(skb);
}
int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp)
{
struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
@ -211,6 +304,7 @@ mlxsw_sp_trap_group_policer_init(struct mlxsw_sp *mlxsw_sp,
u32 rate;
switch (group->id) {
case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS:/* fall through */
case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS:
policer_id = MLXSW_SP_DISCARD_POLICER_ID;
ir_units = MLXSW_REG_QPCR_IR_UNITS_M;
@ -242,6 +336,12 @@ __mlxsw_sp_trap_group_init(struct mlxsw_sp *mlxsw_sp,
priority = 0;
tc = 1;
break;
case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS:
group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS;
policer_id = MLXSW_SP_DISCARD_POLICER_ID;
priority = 0;
tc = 1;
break;
default:
return -EINVAL;
}

View File

@ -49,6 +49,7 @@ enum {
MLXSW_TRAP_ID_IPV6_DHCP = 0x69,
MLXSW_TRAP_ID_IPV6_ALL_ROUTERS_LINK = 0x6F,
MLXSW_TRAP_ID_RTR_INGRESS0 = 0x70,
MLXSW_TRAP_ID_RTR_INGRESS1 = 0x71,
MLXSW_TRAP_ID_IPV6_PIM = 0x79,
MLXSW_TRAP_ID_IPV6_VRRP = 0x7A,
MLXSW_TRAP_ID_IPV4_BGP = 0x88,
@ -66,6 +67,8 @@ enum {
MLXSW_TRAP_ID_NVE_ENCAP_ARP = 0xBD,
MLXSW_TRAP_ID_ROUTER_ALERT_IPV4 = 0xD6,
MLXSW_TRAP_ID_ROUTER_ALERT_IPV6 = 0xD7,
MLXSW_TRAP_ID_DISCARD_ROUTER2 = 0x130,
MLXSW_TRAP_ID_DISCARD_ROUTER3 = 0x131,
MLXSW_TRAP_ID_DISCARD_ING_PACKET_SMAC_MC = 0x140,
MLXSW_TRAP_ID_DISCARD_ING_SWITCH_VTAG_ALLOW = 0x148,
MLXSW_TRAP_ID_DISCARD_ING_SWITCH_VLAN = 0x149,
@ -73,6 +76,18 @@ enum {
MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_UC = 0x150,
MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_MC_NULL = 0x151,
MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_LB = 0x152,
MLXSW_TRAP_ID_DISCARD_ING_ROUTER_NON_IP_PACKET = 0x160,
MLXSW_TRAP_ID_DISCARD_ING_ROUTER_UC_DIP_MC_DMAC = 0x161,
MLXSW_TRAP_ID_DISCARD_ING_ROUTER_DIP_LB = 0x162,
MLXSW_TRAP_ID_DISCARD_ING_ROUTER_SIP_MC = 0x163,
MLXSW_TRAP_ID_DISCARD_ING_ROUTER_SIP_LB = 0x165,
MLXSW_TRAP_ID_DISCARD_ING_ROUTER_CORRUPTED_IP_HDR = 0x167,
MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_SIP_BC = 0x16A,
MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_DIP_LOCAL_NET = 0x16B,
MLXSW_TRAP_ID_DISCARD_ROUTER_LPM4 = 0x17B,
MLXSW_TRAP_ID_DISCARD_ROUTER_LPM6 = 0x17C,
MLXSW_TRAP_ID_DISCARD_IPV6_MC_DIP_RESERVED_SCOPE = 0x1B0,
MLXSW_TRAP_ID_DISCARD_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE = 0x1B1,
MLXSW_TRAP_ID_ACL0 = 0x1C0,
/* Multicast trap used for routes with trap action */
MLXSW_TRAP_ID_ACL1 = 0x1C1,

View File

@ -569,6 +569,21 @@ enum devlink_trap_generic_id {
DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE,
DEVLINK_TRAP_GENERIC_ID_TTL_ERROR,
DEVLINK_TRAP_GENERIC_ID_TAIL_DROP,
DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET,
DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC,
DEVLINK_TRAP_GENERIC_ID_DIP_LB,
DEVLINK_TRAP_GENERIC_ID_SIP_MC,
DEVLINK_TRAP_GENERIC_ID_SIP_LB,
DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR,
DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC,
DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE,
DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
DEVLINK_TRAP_GENERIC_ID_MTU_ERROR,
DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
DEVLINK_TRAP_GENERIC_ID_RPF,
DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE,
DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS,
DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS,
/* Add new generic trap IDs above */
__DEVLINK_TRAP_GENERIC_ID_MAX,
@ -607,6 +622,36 @@ enum devlink_trap_group_generic_id {
"ttl_value_is_too_small"
#define DEVLINK_TRAP_GENERIC_NAME_TAIL_DROP \
"tail_drop"
#define DEVLINK_TRAP_GENERIC_NAME_NON_IP_PACKET \
"non_ip"
#define DEVLINK_TRAP_GENERIC_NAME_UC_DIP_MC_DMAC \
"uc_dip_over_mc_dmac"
#define DEVLINK_TRAP_GENERIC_NAME_DIP_LB \
"dip_is_loopback_address"
#define DEVLINK_TRAP_GENERIC_NAME_SIP_MC \
"sip_is_mc"
#define DEVLINK_TRAP_GENERIC_NAME_SIP_LB \
"sip_is_loopback_address"
#define DEVLINK_TRAP_GENERIC_NAME_CORRUPTED_IP_HDR \
"ip_header_corrupted"
#define DEVLINK_TRAP_GENERIC_NAME_IPV4_SIP_BC \
"ipv4_sip_is_limited_bc"
#define DEVLINK_TRAP_GENERIC_NAME_IPV6_MC_DIP_RESERVED_SCOPE \
"ipv6_mc_dip_reserved_scope"
#define DEVLINK_TRAP_GENERIC_NAME_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE \
"ipv6_mc_dip_interface_local_scope"
#define DEVLINK_TRAP_GENERIC_NAME_MTU_ERROR \
"mtu_value_is_too_small"
#define DEVLINK_TRAP_GENERIC_NAME_UNRESOLVED_NEIGH \
"unresolved_neigh"
#define DEVLINK_TRAP_GENERIC_NAME_RPF \
"mc_reverse_path_forwarding"
#define DEVLINK_TRAP_GENERIC_NAME_REJECT_ROUTE \
"reject_route"
#define DEVLINK_TRAP_GENERIC_NAME_IPV4_LPM_UNICAST_MISS \
"ipv4_lpm_miss"
#define DEVLINK_TRAP_GENERIC_NAME_IPV6_LPM_UNICAST_MISS \
"ipv6_lpm_miss"
#define DEVLINK_TRAP_GROUP_GENERIC_NAME_L2_DROPS \
"l2_drops"

View File

@ -7602,6 +7602,21 @@ static const struct devlink_trap devlink_trap_generic[] = {
DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
DEVLINK_TRAP(TAIL_DROP, DROP),
DEVLINK_TRAP(NON_IP_PACKET, DROP),
DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
DEVLINK_TRAP(DIP_LB, DROP),
DEVLINK_TRAP(SIP_MC, DROP),
DEVLINK_TRAP(SIP_LB, DROP),
DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
DEVLINK_TRAP(IPV4_SIP_BC, DROP),
DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
DEVLINK_TRAP(RPF, EXCEPTION),
DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
};
#define DEVLINK_TRAP_GROUP(_id) \

View File

@ -92,46 +92,6 @@ cleanup()
vrf_cleanup
}
l2_drops_test()
{
local trap_name=$1; shift
local group_name=$1; shift
# This is the common part of all the tests. It checks that stats are
# initially idle, then non-idle after changing the trap action and
# finally idle again. It also makes sure the packets are dropped and
# never forwarded.
devlink_trap_stats_idle_test $trap_name
check_err $? "Trap stats not idle with initial drop action"
devlink_trap_group_stats_idle_test $group_name
check_err $? "Trap group stats not idle with initial drop action"
devlink_trap_action_set $trap_name "trap"
devlink_trap_stats_idle_test $trap_name
check_fail $? "Trap stats idle after setting action to trap"
devlink_trap_group_stats_idle_test $group_name
check_fail $? "Trap group stats idle after setting action to trap"
devlink_trap_action_set $trap_name "drop"
devlink_trap_stats_idle_test $trap_name
check_err $? "Trap stats not idle after setting action to drop"
devlink_trap_group_stats_idle_test $group_name
check_err $? "Trap group stats not idle after setting action to drop"
tc_check_packets "dev $swp2 egress" 101 0
check_err $? "Packets were not dropped"
}
l2_drops_cleanup()
{
local mz_pid=$1; shift
kill $mz_pid && wait $mz_pid &> /dev/null
tc filter del dev $swp2 egress protocol ip pref 1 handle 101 flower
}
source_mac_is_multicast_test()
{
local trap_name="source_mac_is_multicast"
@ -147,11 +107,11 @@ source_mac_is_multicast_test()
RET=0
l2_drops_test $trap_name $group_name
devlink_trap_drop_test $trap_name $group_name $swp2
log_test "Source MAC is multicast"
l2_drops_cleanup $mz_pid
devlink_trap_drop_cleanup $mz_pid $swp2 ip
}
__vlan_tag_mismatch_test()
@ -172,7 +132,7 @@ __vlan_tag_mismatch_test()
$MZ $h1 "$opt" -c 0 -p 100 -a own -b $dmac -t ip -d 1msec -q &
mz_pid=$!
l2_drops_test $trap_name $group_name
devlink_trap_drop_test $trap_name $group_name $swp2
# Add PVID and make sure packets are no longer dropped.
bridge vlan add vid 1 dev $swp1 pvid untagged master
@ -188,7 +148,7 @@ __vlan_tag_mismatch_test()
devlink_trap_action_set $trap_name "drop"
l2_drops_cleanup $mz_pid
devlink_trap_drop_cleanup $mz_pid $swp2 ip
}
vlan_tag_mismatch_untagged_test()
@ -233,7 +193,7 @@ ingress_vlan_filter_test()
$MZ $h1 -Q $vid -c 0 -p 100 -a own -b $dmac -t ip -d 1msec -q &
mz_pid=$!
l2_drops_test $trap_name $group_name
devlink_trap_drop_test $trap_name $group_name $swp2
# Add the VLAN on the bridge port and make sure packets are no longer
# dropped.
@ -252,7 +212,7 @@ ingress_vlan_filter_test()
log_test "Ingress VLAN filter"
l2_drops_cleanup $mz_pid
devlink_trap_drop_cleanup $mz_pid $swp2 ip
bridge vlan del vid $vid dev $swp1 master
bridge vlan del vid $vid dev $swp2 master
@ -277,7 +237,7 @@ __ingress_stp_filter_test()
$MZ $h1 -Q $vid -c 0 -p 100 -a own -b $dmac -t ip -d 1msec -q &
mz_pid=$!
l2_drops_test $trap_name $group_name
devlink_trap_drop_test $trap_name $group_name $swp2
# Change STP state to forwarding and make sure packets are no longer
# dropped.
@ -294,7 +254,7 @@ __ingress_stp_filter_test()
devlink_trap_action_set $trap_name "drop"
l2_drops_cleanup $mz_pid
devlink_trap_drop_cleanup $mz_pid $swp2 ip
bridge vlan del vid $vid dev $swp1 master
bridge vlan del vid $vid dev $swp2 master
@ -348,7 +308,7 @@ port_list_is_empty_uc_test()
$MZ $h1 -c 0 -p 100 -a own -b $dmac -t ip -d 1msec -q &
mz_pid=$!
l2_drops_test $trap_name $group_name
devlink_trap_drop_test $trap_name $group_name $swp2
# Allow packets to be flooded to one port.
ip link set dev $swp2 type bridge_slave flood on
@ -366,7 +326,7 @@ port_list_is_empty_uc_test()
log_test "Port list is empty - unicast"
l2_drops_cleanup $mz_pid
devlink_trap_drop_cleanup $mz_pid $swp2 ip
ip link set dev $swp1 type bridge_slave flood on
}
@ -394,7 +354,7 @@ port_list_is_empty_mc_test()
$MZ $h1 -c 0 -p 100 -a own -b $dmac -t ip -B $dip -d 1msec -q &
mz_pid=$!
l2_drops_test $trap_name $group_name
devlink_trap_drop_test $trap_name $group_name $swp2
# Allow packets to be flooded to one port.
ip link set dev $swp2 type bridge_slave mcast_flood on
@ -412,7 +372,7 @@ port_list_is_empty_mc_test()
log_test "Port list is empty - multicast"
l2_drops_cleanup $mz_pid
devlink_trap_drop_cleanup $mz_pid $swp2 ip
ip link set dev $swp1 type bridge_slave mcast_flood on
}
@ -441,7 +401,7 @@ port_loopback_filter_uc_test()
$MZ $h1 -c 0 -p 100 -a own -b $dmac -t ip -d 1msec -q &
mz_pid=$!
l2_drops_test $trap_name $group_name
devlink_trap_drop_test $trap_name $group_name $swp2
# Allow packets to be flooded.
ip link set dev $swp2 type bridge_slave flood on
@ -459,7 +419,7 @@ port_loopback_filter_uc_test()
log_test "Port loopback filter - unicast"
l2_drops_cleanup $mz_pid
devlink_trap_drop_cleanup $mz_pid $swp2 ip
}
port_loopback_filter_test()

View File

@ -0,0 +1,563 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Test devlink-trap L3 drops functionality over mlxsw. Each registered L3 drop
# packet trap is tested to make sure it is triggered under the right
# conditions.
# +---------------------------------+
# | H1 (vrf) |
# | + $h1 |
# | | 192.0.2.1/24 |
# | | 2001:db8:1::1/64 |
# | | |
# | | default via 192.0.2.2 |
# | | default via 2001:db8:1::2 |
# +----|----------------------------+
# |
# +----|----------------------------------------------------------------------+
# | SW | |
# | + $rp1 |
# | 192.0.2.2/24 |
# | 2001:db8:1::2/64 |
# | |
# | 2001:db8:2::2/64 |
# | 198.51.100.2/24 |
# | + $rp2 |
# | | |
# +----|----------------------------------------------------------------------+
# |
# +----|----------------------------+
# | | default via 198.51.100.2 |
# | | default via 2001:db8:2::2 |
# | | |
# | | 2001:db8:2::1/64 |
# | | 198.51.100.1/24 |
# | + $h2 |
# | H2 (vrf) |
# +---------------------------------+
lib_dir=$(dirname $0)/../../../net/forwarding
ALL_TESTS="
non_ip_test
uc_dip_over_mc_dmac_test
dip_is_loopback_test
sip_is_mc_test
sip_is_loopback_test
ip_header_corrupted_test
ipv4_sip_is_limited_bc_test
ipv6_mc_dip_reserved_scope_test
ipv6_mc_dip_interface_local_scope_test
blackhole_route_test
"
NUM_NETIFS=4
source $lib_dir/lib.sh
source $lib_dir/tc_common.sh
source $lib_dir/devlink_lib.sh
h1_create()
{
simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
ip -4 route add default vrf v$h1 nexthop via 192.0.2.2
ip -6 route add default vrf v$h1 nexthop via 2001:db8:1::2
}
h1_destroy()
{
ip -6 route del default vrf v$h1 nexthop via 2001:db8:1::2
ip -4 route del default vrf v$h1 nexthop via 192.0.2.2
simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
}
h2_create()
{
simple_if_init $h2 $h2_ipv4/24 $h2_ipv6/64
ip -4 route add default vrf v$h2 nexthop via 198.51.100.2
ip -6 route add default vrf v$h2 nexthop via 2001:db8:2::2
}
h2_destroy()
{
ip -6 route del default vrf v$h2 nexthop via 2001:db8:2::2
ip -4 route del default vrf v$h2 nexthop via 198.51.100.2
simple_if_fini $h2 $h2_ipv4/24 $h2_ipv6/64
}
router_create()
{
ip link set dev $rp1 up
ip link set dev $rp2 up
tc qdisc add dev $rp2 clsact
__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
__addr_add_del $rp2 add 198.51.100.2/24 2001:db8:2::2/64
}
router_destroy()
{
__addr_add_del $rp2 del 198.51.100.2/24 2001:db8:2::2/64
__addr_add_del $rp1 del 192.0.2.2/24 2001:db8:1::2/64
tc qdisc del dev $rp2 clsact
}
setup_prepare()
{
h1=${NETIFS[p1]}
rp1=${NETIFS[p2]}
rp2=${NETIFS[p3]}
h2=${NETIFS[p4]}
h1mac=$(mac_get $h1)
rp1mac=$(mac_get $rp1)
h1_ipv4=192.0.2.1
h2_ipv4=198.51.100.1
h1_ipv6=2001:db8:1::1
h2_ipv6=2001:db8:2::1
vrf_prepare
forwarding_enable
h1_create
h2_create
router_create
}
cleanup()
{
pre_cleanup
router_destroy
h2_destroy
h1_destroy
forwarding_restore
vrf_cleanup
}
ping_check()
{
trap_name=$1; shift
devlink_trap_action_set $trap_name "trap"
ping_do $h1 $h2_ipv4
check_err $? "Packets that should not be trapped were trapped"
devlink_trap_action_set $trap_name "drop"
}
non_ip_test()
{
local trap_name="non_ip"
local group_name="l3_drops"
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
flower dst_ip $h2_ipv4 action drop
# Generate non-IP packets to the router
$MZ $h1 -c 0 -p 100 -d 1msec -B $h2_ipv4 -q "$rp1mac $h1mac \
00:00 de:ad:be:ef" &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "Non IP"
devlink_trap_drop_cleanup $mz_pid $rp2 "ip"
}
__uc_dip_over_mc_dmac_test()
{
local desc=$1; shift
local proto=$1; shift
local dip=$1; shift
local flags=${1:-""}; shift
local trap_name="uc_dip_over_mc_dmac"
local group_name="l3_drops"
local dmac=01:02:03:04:05:06
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
flower ip_proto udp src_port 54321 dst_port 12345 action drop
# Generate IP packets with a unicast IP and a multicast destination MAC
$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $dmac \
-B $dip -d 1msec -q &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "Unicast destination IP over multicast destination MAC: $desc"
devlink_trap_drop_cleanup $mz_pid $rp2 $proto
}
uc_dip_over_mc_dmac_test()
{
__uc_dip_over_mc_dmac_test "IPv4" "ip" $h2_ipv4
__uc_dip_over_mc_dmac_test "IPv6" "ipv6" $h2_ipv6 "-6"
}
__sip_is_loopback_test()
{
local desc=$1; shift
local proto=$1; shift
local sip=$1; shift
local dip=$1; shift
local flags=${1:-""}; shift
local trap_name="sip_is_loopback_address"
local group_name="l3_drops"
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
flower src_ip $sip action drop
# Generate packets with loopback source IP
$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip \
-b $rp1mac -B $dip -d 1msec -q &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "Source IP is loopback address: $desc"
devlink_trap_drop_cleanup $mz_pid $rp2 $proto
}
sip_is_loopback_test()
{
__sip_is_loopback_test "IPv4" "ip" "127.0.0.0/8" $h2_ipv4
__sip_is_loopback_test "IPv6" "ipv6" "::1" $h2_ipv6 "-6"
}
__dip_is_loopback_test()
{
local desc=$1; shift
local proto=$1; shift
local dip=$1; shift
local flags=${1:-""}; shift
local trap_name="dip_is_loopback_address"
local group_name="l3_drops"
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
flower dst_ip $dip action drop
# Generate packets with loopback destination IP
$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \
-B $dip -d 1msec -q &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "Destination IP is loopback address: $desc"
devlink_trap_drop_cleanup $mz_pid $rp2 $proto
}
dip_is_loopback_test()
{
__dip_is_loopback_test "IPv4" "ip" "127.0.0.0/8"
__dip_is_loopback_test "IPv6" "ipv6" "::1" "-6"
}
__sip_is_mc_test()
{
local desc=$1; shift
local proto=$1; shift
local sip=$1; shift
local dip=$1; shift
local flags=${1:-""}; shift
local trap_name="sip_is_mc"
local group_name="l3_drops"
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
flower src_ip $sip action drop
# Generate packets with multicast source IP
$MZ $h1 $flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip \
-b $rp1mac -B $dip -d 1msec -q &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "Source IP is multicast: $desc"
devlink_trap_drop_cleanup $mz_pid $rp2 $proto
}
sip_is_mc_test()
{
__sip_is_mc_test "IPv4" "ip" "239.1.1.1" $h2_ipv4
__sip_is_mc_test "IPv6" "ipv6" "FF02::2" $h2_ipv6 "-6"
}
ipv4_sip_is_limited_bc_test()
{
local trap_name="ipv4_sip_is_limited_bc"
local group_name="l3_drops"
local sip=255.255.255.255
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
flower src_ip $sip action drop
# Generate packets with limited broadcast source IP
$MZ $h1 -t udp "sp=54321,dp=12345" -c 0 -p 100 -A $sip -b $rp1mac \
-B $h2_ipv4 -d 1msec -q &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "IPv4 source IP is limited broadcast"
devlink_trap_drop_cleanup $mz_pid $rp2 "ip"
}
ipv4_payload_get()
{
local ipver=$1; shift
local ihl=$1; shift
local checksum=$1; shift
p=$(:
)"08:00:"$( : ETH type
)"$ipver"$( : IP version
)"$ihl:"$( : IHL
)"00:"$( : IP TOS
)"00:F4:"$( : IP total length
)"00:00:"$( : IP identification
)"20:00:"$( : IP flags + frag off
)"30:"$( : IP TTL
)"01:"$( : IP proto
)"$checksum:"$( : IP header csum
)"$h1_ipv4:"$( : IP saddr
)"$h2_ipv4:"$( : IP daddr
)
echo $p
}
__ipv4_header_corrupted_test()
{
local desc=$1; shift
local ipver=$1; shift
local ihl=$1; shift
local checksum=$1; shift
local trap_name="ip_header_corrupted"
local group_name="l3_drops"
local payload
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
flower dst_ip $h2_ipv4 action drop
payload=$(ipv4_payload_get $ipver $ihl $checksum)
# Generate packets with corrupted IP header
$MZ $h1 -c 0 -d 1msec -a $h1mac -b $rp1mac -q p=$payload &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "IP header corrupted: $desc: IPv4"
devlink_trap_drop_cleanup $mz_pid $rp2 "ip"
}
ipv6_payload_get()
{
local ipver=$1; shift
p=$(:
)"86:DD:"$( : ETH type
)"$ipver"$( : IP version
)"0:0:"$( : Traffic class
)"0:00:00:"$( : Flow label
)"00:00:"$( : Payload length
)"01:"$( : Next header
)"04:"$( : Hop limit
)"$h1_ipv6:"$( : IP saddr
)"$h2_ipv6:"$( : IP daddr
)
echo $p
}
__ipv6_header_corrupted_test()
{
local desc=$1; shift
local ipver=$1; shift
local trap_name="ip_header_corrupted"
local group_name="l3_drops"
local payload
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol ip pref 1 handle 101 \
flower dst_ip $h2_ipv4 action drop
payload=$(ipv6_payload_get $ipver)
# Generate packets with corrupted IP header
$MZ $h1 -c 0 -d 1msec -a $h1mac -b $rp1mac -q p=$payload &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "IP header corrupted: $desc: IPv6"
devlink_trap_drop_cleanup $mz_pid $rp2 "ip"
}
ip_header_corrupted_test()
{
# Each test uses one wrong value. The three values below are correct.
local ipv="4"
local ihl="5"
local checksum="00:F4"
__ipv4_header_corrupted_test "wrong IP version" 5 $ihl $checksum
__ipv4_header_corrupted_test "wrong IHL" $ipv 4 $checksum
__ipv4_header_corrupted_test "wrong checksum" $ipv $ihl "00:00"
__ipv6_header_corrupted_test "wrong IP version" 5
}
ipv6_mc_dip_reserved_scope_test()
{
local trap_name="ipv6_mc_dip_reserved_scope"
local group_name="l3_drops"
local dip=FF00::
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol ipv6 pref 1 handle 101 \
flower dst_ip $dip action drop
# Generate packets with reserved scope destination IP
$MZ $h1 -6 -t udp "sp=54321,dp=12345" -c 0 -p 100 -b \
"33:33:00:00:00:00" -B $dip -d 1msec -q &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "IPv6 multicast destination IP reserved scope"
devlink_trap_drop_cleanup $mz_pid $rp2 "ipv6"
}
ipv6_mc_dip_interface_local_scope_test()
{
local trap_name="ipv6_mc_dip_interface_local_scope"
local group_name="l3_drops"
local dip=FF01::
local mz_pid
RET=0
ping_check $trap_name
tc filter add dev $rp2 egress protocol ipv6 pref 1 handle 101 \
flower dst_ip $dip action drop
# Generate packets with interface local scope destination IP
$MZ $h1 -6 -t udp "sp=54321,dp=12345" -c 0 -p 100 -b \
"33:33:00:00:00:00" -B $dip -d 1msec -q &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "IPv6 multicast destination IP interface-local scope"
devlink_trap_drop_cleanup $mz_pid $rp2 "ipv6"
}
__blackhole_route_test()
{
local flags=$1; shift
local subnet=$1; shift
local proto=$1; shift
local dip=$1; shift
local ip_proto=${1:-"icmp"}; shift
local trap_name="blackhole_route"
local group_name="l3_drops"
local mz_pid
RET=0
ping_check $trap_name
ip -$flags route add blackhole $subnet
tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
flower skip_hw dst_ip $dip ip_proto $ip_proto action drop
# Generate packets to the blackhole route
$MZ $h1 -$flags -t udp "sp=54321,dp=12345" -c 0 -p 100 -b $rp1mac \
-B $dip -d 1msec -q &
mz_pid=$!
devlink_trap_drop_test $trap_name $group_name $rp2
log_test "Blackhole route: IPv$flags"
devlink_trap_drop_cleanup $mz_pid $rp2 $proto
ip -$flags route del blackhole $subnet
}
blackhole_route_test()
{
__blackhole_route_test "4" "198.51.100.0/30" "ip" $h2_ipv4
__blackhole_route_test "6" "2001:db8:2::/120" "ipv6" $h2_ipv6 "icmpv6"
}
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
exit $EXIT_STATUS

View File

@ -0,0 +1,557 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Test devlink-trap L3 exceptions functionality over mlxsw.
# Check all exception traps to make sure they are triggered under the right
# conditions.
# +---------------------------------+
# | H1 (vrf) |
# | + $h1 |
# | | 192.0.2.1/24 |
# | | 2001:db8:1::1/64 |
# | | |
# | | default via 192.0.2.2 |
# | | default via 2001:db8:1::2 |
# +----|----------------------------+
# |
# +----|----------------------------------------------------------------------+
# | SW | |
# | + $rp1 |
# | 192.0.2.2/24 |
# | 2001:db8:1::2/64 |
# | |
# | 2001:db8:2::2/64 |
# | 198.51.100.2/24 |
# | + $rp2 |
# | | |
# +----|----------------------------------------------------------------------+
# |
# +----|----------------------------+
# | | default via 198.51.100.2 |
# | | default via 2001:db8:2::2 |
# | | |
# | | 2001:db8:2::1/64 |
# | | 198.51.100.1/24 |
# | + $h2 |
# | H2 (vrf) |
# +---------------------------------+
lib_dir=$(dirname $0)/../../../net/forwarding
ALL_TESTS="
mtu_value_is_too_small_test
ttl_value_is_too_small_test
mc_reverse_path_forwarding_test
reject_route_test
unresolved_neigh_test
ipv4_lpm_miss_test
ipv6_lpm_miss_test
"
NUM_NETIFS=4
source $lib_dir/lib.sh
source $lib_dir/tc_common.sh
source $lib_dir/devlink_lib.sh
require_command $MCD
require_command $MC_CLI
table_name=selftests
h1_create()
{
simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
ip -4 route add default vrf v$h1 nexthop via 192.0.2.2
ip -6 route add default vrf v$h1 nexthop via 2001:db8:1::2
tc qdisc add dev $h1 clsact
}
h1_destroy()
{
tc qdisc del dev $h1 clsact
ip -6 route del default vrf v$h1 nexthop via 2001:db8:1::2
ip -4 route del default vrf v$h1 nexthop via 192.0.2.2
simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
}
h2_create()
{
simple_if_init $h2 198.51.100.1/24 2001:db8:2::1/64
ip -4 route add default vrf v$h2 nexthop via 198.51.100.2
ip -6 route add default vrf v$h2 nexthop via 2001:db8:2::2
}
h2_destroy()
{
ip -6 route del default vrf v$h2 nexthop via 2001:db8:2::2
ip -4 route del default vrf v$h2 nexthop via 198.51.100.2
simple_if_fini $h2 198.51.100.1/24 2001:db8:2::1/64
}
router_create()
{
ip link set dev $rp1 up
ip link set dev $rp2 up
tc qdisc add dev $rp2 clsact
__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
__addr_add_del $rp2 add 198.51.100.2/24 2001:db8:2::2/64
}
router_destroy()
{
__addr_add_del $rp2 del 198.51.100.2/24 2001:db8:2::2/64
__addr_add_del $rp1 del 192.0.2.2/24 2001:db8:1::2/64
tc qdisc del dev $rp2 clsact
}
setup_prepare()
{
h1=${NETIFS[p1]}
rp1=${NETIFS[p2]}
rp2=${NETIFS[p3]}
h2=${NETIFS[p4]}
rp1mac=$(mac_get $rp1)
start_mcd
vrf_prepare
forwarding_enable
h1_create
h2_create
router_create
}
cleanup()
{
pre_cleanup
router_destroy
h2_destroy
h1_destroy
forwarding_restore
vrf_cleanup
kill_mcd
}
ping_check()
{
ping_do $h1 198.51.100.1
check_err $? "Packets that should not be trapped were trapped"
}
trap_action_check()
{
local trap_name=$1; shift
local expected_action=$1; shift
action=$(devlink_trap_action_get $trap_name)
if [ "$action" != $expected_action ]; then
check_err 1 "Trap $trap_name has wrong action: $action"
fi
}
mtu_value_is_too_small_test()
{
local trap_name="mtu_value_is_too_small"
local group_name="l3_drops"
local expected_action="trap"
local mz_pid
RET=0
ping_check $trap_name
trap_action_check $trap_name $expected_action
# type - Destination Unreachable
# code - Fragmentation Needed and Don't Fragment was Set
tc filter add dev $h1 ingress protocol ip pref 1 handle 101 \
flower skip_hw ip_proto icmp type 3 code 4 action pass
mtu_set $rp2 1300
# Generate IP packets bigger than router's MTU with don't fragment
# flag on.
$MZ $h1 -t udp "sp=54321,dp=12345,df" -p 1400 -c 0 -d 1msec -b $rp1mac \
-B 198.51.100.1 -q &
mz_pid=$!
devlink_trap_exception_test $trap_name $group_name
tc_check_packets_hitting "dev $h1 ingress" 101
check_err $? "Packets were not received to h1"
log_test "MTU value is too small"
mtu_restore $rp2
kill $mz_pid && wait $mz_pid &> /dev/null
tc filter del dev $h1 ingress protocol ip pref 1 handle 101 flower
}
__ttl_value_is_too_small_test()
{
local ttl_val=$1; shift
local trap_name="ttl_value_is_too_small"
local group_name="l3_drops"
local expected_action="trap"
local mz_pid
RET=0
ping_check $trap_name
trap_action_check $trap_name $expected_action
# type - Time Exceeded
# code - Time to Live exceeded in Transit
tc filter add dev $h1 ingress protocol ip pref 1 handle 101 \
flower skip_hw ip_proto icmp type 11 code 0 action pass
# Generate IP packets with small TTL
$MZ $h1 -t udp "ttl=$ttl_val,sp=54321,dp=12345" -c 0 -d 1msec \
-b $rp1mac -B 198.51.100.1 -q &
mz_pid=$!
devlink_trap_exception_test $trap_name $group_name
tc_check_packets_hitting "dev $h1 ingress" 101
check_err $? "Packets were not received to h1"
log_test "TTL value is too small: TTL=$ttl_val"
kill $mz_pid && wait $mz_pid &> /dev/null
tc filter del dev $h1 ingress protocol ip pref 1 handle 101 flower
}
ttl_value_is_too_small_test()
{
__ttl_value_is_too_small_test 0
__ttl_value_is_too_small_test 1
}
start_mcd()
{
SMCROUTEDIR="$(mktemp -d)"
for ((i = 1; i <= $NUM_NETIFS; ++i)); do
echo "phyint ${NETIFS[p$i]} enable" >> \
$SMCROUTEDIR/$table_name.conf
done
$MCD -N -I $table_name -f $SMCROUTEDIR/$table_name.conf \
-P $SMCROUTEDIR/$table_name.pid
}
kill_mcd()
{
pkill $MCD
rm -rf $SMCROUTEDIR
}
__mc_reverse_path_forwarding_test()
{
local desc=$1; shift
local src_ip=$1; shift
local dst_ip=$1; shift
local dst_mac=$1; shift
local proto=$1; shift
local flags=${1:-""}; shift
local trap_name="mc_reverse_path_forwarding"
local group_name="l3_drops"
local expected_action="trap"
local mz_pid
RET=0
ping_check $trap_name
trap_action_check $trap_name $expected_action
tc filter add dev $rp2 egress protocol $proto pref 1 handle 101 \
flower dst_ip $dst_ip ip_proto udp action drop
$MC_CLI -I $table_name add $rp1 $src_ip $dst_ip $rp2
# Generate packets to multicast address.
$MZ $h2 $flags -t udp "sp=54321,dp=12345" -c 0 -p 128 \
-a 00:11:22:33:44:55 -b $dst_mac \
-A $src_ip -B $dst_ip -q &
mz_pid=$!
devlink_trap_exception_test $trap_name $group_name
tc_check_packets "dev $rp2 egress" 101 0
check_err $? "Packets were not dropped"
log_test "Multicast reverse path forwarding: $desc"
kill $mz_pid && wait $mz_pid &> /dev/null
tc filter del dev $rp2 egress protocol $proto pref 1 handle 101 flower
}
mc_reverse_path_forwarding_test()
{
__mc_reverse_path_forwarding_test "IPv4" "192.0.2.1" "225.1.2.3" \
"01:00:5e:01:02:03" "ip"
__mc_reverse_path_forwarding_test "IPv6" "2001:db8:1::1" "ff0e::3" \
"33:33:00:00:00:03" "ipv6" "-6"
}
__reject_route_test()
{
local desc=$1; shift
local dst_ip=$1; shift
local proto=$1; shift
local ip_proto=$1; shift
local type=$1; shift
local code=$1; shift
local unreachable=$1; shift
local flags=${1:-""}; shift
local trap_name="reject_route"
local group_name="l3_drops"
local expected_action="trap"
local mz_pid
RET=0
ping_check $trap_name
trap_action_check $trap_name $expected_action
tc filter add dev $h1 ingress protocol $proto pref 1 handle 101 flower \
skip_hw ip_proto $ip_proto type $type code $code action pass
ip route add unreachable $unreachable
# Generate pacekts to h2. The destination IP is unreachable.
$MZ $flags $h1 -t udp "sp=54321,dp=12345" -c 0 -d 1msec -b $rp1mac \
-B $dst_ip -q &
mz_pid=$!
devlink_trap_exception_test $trap_name $group_name
tc_check_packets_hitting "dev $h1 ingress" 101
check_err $? "ICMP packet was not received to h1"
log_test "Reject route: $desc"
kill $mz_pid && wait $mz_pid &> /dev/null
ip route del unreachable $unreachable
tc filter del dev $h1 ingress protocol $proto pref 1 handle 101 flower
}
reject_route_test()
{
# type - Destination Unreachable
# code - Host Unreachable
__reject_route_test "IPv4" 198.51.100.1 "ip" "icmp" 3 1 \
"198.51.100.0/26"
# type - Destination Unreachable
# code - No Route
__reject_route_test "IPv6" 2001:db8:2::1 "ipv6" "icmpv6" 1 0 \
"2001:db8:2::0/66" "-6"
}
__host_miss_test()
{
local desc=$1; shift
local dip=$1; shift
local trap_name="unresolved_neigh"
local group_name="l3_drops"
local expected_action="trap"
local mz_pid
RET=0
ping_check $trap_name
trap_action_check $trap_name $expected_action
ip neigh flush dev $rp2
t0_packets=$(devlink_trap_rx_packets_get $trap_name)
# Generate packets to h2 (will incur a unresolved neighbor).
# The ping should pass and devlink counters should be increased.
ping_do $h1 $dip
check_err $? "ping failed: $desc"
t1_packets=$(devlink_trap_rx_packets_get $trap_name)
if [[ $t0_packets -eq $t1_packets ]]; then
check_err 1 "Trap counter did not increase"
fi
log_test "Unresolved neigh: host miss: $desc"
}
__invalid_nexthop_test()
{
local desc=$1; shift
local dip=$1; shift
local extra_add=$1; shift
local subnet=$1; shift
local via_add=$1; shift
local trap_name="unresolved_neigh"
local group_name="l3_drops"
local expected_action="trap"
local mz_pid
RET=0
ping_check $trap_name
trap_action_check $trap_name $expected_action
ip address add $extra_add/$subnet dev $h2
# Check that correct route does not trigger unresolved_neigh
ip $flags route add $dip via $extra_add dev $rp2
# Generate packets in order to discover all neighbours.
# Without it, counters of unresolved_neigh will be increased
# during neighbours discovery and the check below will fail
# for a wrong reason
ping_do $h1 $dip
t0_packets=$(devlink_trap_rx_packets_get $trap_name)
ping_do $h1 $dip
t1_packets=$(devlink_trap_rx_packets_get $trap_name)
if [[ $t0_packets -ne $t1_packets ]]; then
check_err 1 "Trap counter increased when it should not"
fi
ip $flags route del $dip via $extra_add dev $rp2
# Check that route to nexthop that does not exist trigger
# unresolved_neigh
ip $flags route add $dip via $via_add dev $h2
t0_packets=$(devlink_trap_rx_packets_get $trap_name)
ping_do $h1 $dip
t1_packets=$(devlink_trap_rx_packets_get $trap_name)
if [[ $t0_packets -eq $t1_packets ]]; then
check_err 1 "Trap counter did not increase"
fi
ip $flags route del $dip via $via_add dev $h2
ip address del $extra_add/$subnet dev $h2
log_test "Unresolved neigh: nexthop does not exist: $desc"
}
unresolved_neigh_test()
{
__host_miss_test "IPv4" 198.51.100.1
__host_miss_test "IPv6" 2001:db8:2::1
__invalid_nexthop_test "IPv4" 198.51.100.1 198.51.100.3 24 198.51.100.4
__invalid_nexthop_test "IPv6" 2001:db8:2::1 2001:db8:2::3 64 \
2001:db8:2::4
}
vrf_without_routes_create()
{
# VRF creating makes the links to be down and then up again.
# By default, IPv6 address is not saved after link becomes down.
# Save IPv6 address using sysctl configuration.
sysctl_set net.ipv6.conf.$rp1.keep_addr_on_down 1
sysctl_set net.ipv6.conf.$rp2.keep_addr_on_down 1
ip link add dev vrf1 type vrf table 101
ip link set dev $rp1 master vrf1
ip link set dev $rp2 master vrf1
ip link set dev vrf1 up
# Wait for rp1 and rp2 to be up
setup_wait
}
vrf_without_routes_destroy()
{
ip link set dev $rp1 nomaster
ip link set dev $rp2 nomaster
ip link del dev vrf1
sysctl_restore net.ipv6.conf.$rp2.keep_addr_on_down
sysctl_restore net.ipv6.conf.$rp1.keep_addr_on_down
# Wait for interfaces to be up
setup_wait
}
ipv4_lpm_miss_test()
{
local trap_name="ipv4_lpm_miss"
local group_name="l3_drops"
local expected_action="trap"
local mz_pid
RET=0
ping_check $trap_name
trap_action_check $trap_name $expected_action
# Create a VRF without a default route
vrf_without_routes_create
# Generate packets through a VRF without a matching route.
$MZ $h1 -t udp "sp=54321,dp=12345" -c 0 -d 1msec -b $rp1mac \
-B 203.0.113.1 -q &
mz_pid=$!
devlink_trap_exception_test $trap_name $group_name
log_test "LPM miss: IPv4"
kill $mz_pid && wait $mz_pid &> /dev/null
vrf_without_routes_destroy
}
ipv6_lpm_miss_test()
{
local trap_name="ipv6_lpm_miss"
local group_name="l3_drops"
local expected_action="trap"
local mz_pid
RET=0
ping_check $trap_name
trap_action_check $trap_name $expected_action
# Create a VRF without a default route
vrf_without_routes_create
# Generate packets through a VRF without a matching route.
$MZ -6 $h1 -t udp "sp=54321,dp=12345" -c 0 -d 1msec -b $rp1mac \
-B 2001:db8::1 -q &
mz_pid=$!
devlink_trap_exception_test $trap_name $group_name
log_test "LPM miss: IPv6"
kill $mz_pid && wait $mz_pid &> /dev/null
vrf_without_routes_destroy
}
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
exit $EXIT_STATUS

View File

@ -355,3 +355,58 @@ devlink_trap_group_stats_idle_test()
return 1
fi
}
devlink_trap_exception_test()
{
local trap_name=$1; shift
local group_name=$1; shift
devlink_trap_stats_idle_test $trap_name
check_fail $? "Trap stats idle when packets should have been trapped"
devlink_trap_group_stats_idle_test $group_name
check_fail $? "Trap group idle when packets should have been trapped"
}
devlink_trap_drop_test()
{
local trap_name=$1; shift
local group_name=$1; shift
local dev=$1; shift
# This is the common part of all the tests. It checks that stats are
# initially idle, then non-idle after changing the trap action and
# finally idle again. It also makes sure the packets are dropped and
# never forwarded.
devlink_trap_stats_idle_test $trap_name
check_err $? "Trap stats not idle with initial drop action"
devlink_trap_group_stats_idle_test $group_name
check_err $? "Trap group stats not idle with initial drop action"
devlink_trap_action_set $trap_name "trap"
devlink_trap_stats_idle_test $trap_name
check_fail $? "Trap stats idle after setting action to trap"
devlink_trap_group_stats_idle_test $group_name
check_fail $? "Trap group stats idle after setting action to trap"
devlink_trap_action_set $trap_name "drop"
devlink_trap_stats_idle_test $trap_name
check_err $? "Trap stats not idle after setting action to drop"
devlink_trap_group_stats_idle_test $group_name
check_err $? "Trap group stats not idle after setting action to drop"
tc_check_packets "dev $dev egress" 101 0
check_err $? "Packets were not dropped"
}
devlink_trap_drop_cleanup()
{
local mz_pid=$1; shift
local dev=$1; shift
local proto=$1; shift
kill $mz_pid && wait $mz_pid &> /dev/null
tc filter del dev $dev egress protocol $proto pref 1 handle 101 flower
}

View File

@ -14,3 +14,14 @@ tc_check_packets()
select(.options.actions[0].stats.packets == $count)" \
&> /dev/null
}
tc_check_packets_hitting()
{
local id=$1
local handle=$2
cmd_jq "tc -j -s filter show $id" \
".[] | select(.options.handle == $handle) | \
select(.options.actions[0].stats.packets > 0)" \
&> /dev/null
}