Commit 7b89c580 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents c55b810a 83b2b61e
......@@ -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
============================
......
......@@ -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
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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,
......
......@@ -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"
......
......@@ -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) \
......
......@@ -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()
......
......@@ -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
}
......@@ -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
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment