Commit b2492d50 authored by David S. Miller's avatar David S. Miller

Merge branch 'dpaa2-switch-add-mirroring-support'

Ioana Ciornei says:

====================
dpaa2-switch: add mirroring support

This patch set adds per port and per VLAN mirroring in dpaa2-switch.

The first 4 patches are just cosmetic changes. We renamed the
dpaa2_switch_acl_tbl structure into dpaa2_switch_filter_block so that we
can reuse it for filters that do not use the ACL table and reorganized
the addition of trap, redirect and drop filters into a separate
function. All this just to make for a more streamlined addition of the
support for mirroring.

The next 4 patches are actually adding the advertised support. Mirroring
rules can be added in shared blocks, the driver will replicate the same
configuration on all the switch ports part of the same block.

The last patch documents the feature, presents its behavior and
limitations and gives a couple of examples.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 88ea96f8 d1626a1c
...@@ -172,3 +172,46 @@ Example 4: Use a single shared filter block on both eth5 and eth6:: ...@@ -172,3 +172,46 @@ Example 4: Use a single shared filter block on both eth5 and eth6::
action trap action trap
$ tc filter add block 1 ingress protocol ipv4 flower src_ip 192.168.1.1 skip_sw \ $ tc filter add block 1 ingress protocol ipv4 flower src_ip 192.168.1.1 skip_sw \
action mirred egress redirect dev eth3 action mirred egress redirect dev eth3
Mirroring
~~~~~~~~~
The DPAA2 switch supports only per port mirroring and per VLAN mirroring.
Adding mirroring filters in shared blocks is also supported.
When using the tc-flower classifier with the 802.1q protocol, only the
''vlan_id'' key will be accepted. Mirroring based on any other fields from the
802.1q protocol will be rejected::
$ tc qdisc add dev eth8 ingress_block 1 clsact
$ tc filter add block 1 ingress protocol 802.1q flower skip_sw vlan_prio 3 action mirred egress mirror dev eth6
Error: fsl_dpaa2_switch: Only matching on VLAN ID supported.
We have an error talking to the kernel
If a mirroring VLAN filter is requested on a port, the VLAN must to be
installed on the switch port in question either using ''bridge'' or by creating
a VLAN upper device if the switch port is used as a standalone interface::
$ tc qdisc add dev eth8 ingress_block 1 clsact
$ tc filter add block 1 ingress protocol 802.1q flower skip_sw vlan_id 200 action mirred egress mirror dev eth6
Error: VLAN must be installed on the switch port.
We have an error talking to the kernel
$ bridge vlan add vid 200 dev eth8
$ tc filter add block 1 ingress protocol 802.1q flower skip_sw vlan_id 200 action mirred egress mirror dev eth6
$ ip link add link eth8 name eth8.200 type vlan id 200
$ tc filter add block 1 ingress protocol 802.1q flower skip_sw vlan_id 200 action mirred egress mirror dev eth6
Also, it should be noted that the mirrored traffic will be subject to the same
egress restrictions as any other traffic. This means that when a mirrored
packet will reach the mirror port, if the VLAN found in the packet is not
installed on the port it will get dropped.
The DPAA2 switch supports only a single mirroring destination, thus multiple
mirror rules can be installed but their ''to'' port has to be the same::
$ tc filter add block 1 ingress protocol 802.1q flower skip_sw vlan_id 200 action mirred egress mirror dev eth6
$ tc filter add block 1 ingress protocol 802.1q flower skip_sw vlan_id 100 action mirred egress mirror dev eth7
Error: fsl_dpaa2_switch: Multiple mirror ports not supported.
We have an error talking to the kernel
...@@ -113,20 +113,29 @@ struct dpaa2_switch_acl_entry { ...@@ -113,20 +113,29 @@ struct dpaa2_switch_acl_entry {
struct dpsw_acl_key key; struct dpsw_acl_key key;
}; };
struct dpaa2_switch_acl_tbl { struct dpaa2_switch_mirror_entry {
struct list_head entries; struct list_head list;
struct dpsw_reflection_cfg cfg;
unsigned long cookie;
u16 if_id;
};
struct dpaa2_switch_filter_block {
struct ethsw_core *ethsw; struct ethsw_core *ethsw;
u64 ports; u64 ports;
u16 id;
u8 num_rules;
bool in_use; bool in_use;
struct list_head acl_entries;
u16 acl_id;
u8 num_acl_rules;
struct list_head mirror_entries;
}; };
static inline bool static inline bool
dpaa2_switch_acl_tbl_is_full(struct dpaa2_switch_acl_tbl *acl_tbl) dpaa2_switch_acl_tbl_is_full(struct dpaa2_switch_filter_block *filter_block)
{ {
if ((acl_tbl->num_rules + DPAA2_ETHSW_PORT_DEFAULT_TRAPS) >= if ((filter_block->num_acl_rules + DPAA2_ETHSW_PORT_DEFAULT_TRAPS) >=
DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES) DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES)
return true; return true;
return false; return false;
...@@ -149,7 +158,7 @@ struct ethsw_port_priv { ...@@ -149,7 +158,7 @@ struct ethsw_port_priv {
bool ucast_flood; bool ucast_flood;
bool learn_ena; bool learn_ena;
struct dpaa2_switch_acl_tbl *acl_tbl; struct dpaa2_switch_filter_block *filter_block;
}; };
/* Switch data */ /* Switch data */
...@@ -175,7 +184,8 @@ struct ethsw_core { ...@@ -175,7 +184,8 @@ struct ethsw_core {
int napi_users; int napi_users;
struct dpaa2_switch_fdb *fdbs; struct dpaa2_switch_fdb *fdbs;
struct dpaa2_switch_acl_tbl *acls; struct dpaa2_switch_filter_block *filter_blocks;
u16 mirror_port;
}; };
static inline int dpaa2_switch_get_index(struct ethsw_core *ethsw, static inline int dpaa2_switch_get_index(struct ethsw_core *ethsw,
...@@ -229,18 +239,24 @@ typedef int dpaa2_switch_fdb_cb_t(struct ethsw_port_priv *port_priv, ...@@ -229,18 +239,24 @@ typedef int dpaa2_switch_fdb_cb_t(struct ethsw_port_priv *port_priv,
/* TC offload */ /* TC offload */
int dpaa2_switch_cls_flower_replace(struct dpaa2_switch_acl_tbl *acl_tbl, int dpaa2_switch_cls_flower_replace(struct dpaa2_switch_filter_block *block,
struct flow_cls_offload *cls); struct flow_cls_offload *cls);
int dpaa2_switch_cls_flower_destroy(struct dpaa2_switch_acl_tbl *acl_tbl, int dpaa2_switch_cls_flower_destroy(struct dpaa2_switch_filter_block *block,
struct flow_cls_offload *cls); struct flow_cls_offload *cls);
int dpaa2_switch_cls_matchall_replace(struct dpaa2_switch_acl_tbl *acl_tbl, int dpaa2_switch_cls_matchall_replace(struct dpaa2_switch_filter_block *block,
struct tc_cls_matchall_offload *cls); struct tc_cls_matchall_offload *cls);
int dpaa2_switch_cls_matchall_destroy(struct dpaa2_switch_acl_tbl *acl_tbl, int dpaa2_switch_cls_matchall_destroy(struct dpaa2_switch_filter_block *block,
struct tc_cls_matchall_offload *cls); struct tc_cls_matchall_offload *cls);
int dpaa2_switch_acl_entry_add(struct dpaa2_switch_acl_tbl *acl_tbl, int dpaa2_switch_acl_entry_add(struct dpaa2_switch_filter_block *block,
struct dpaa2_switch_acl_entry *entry); struct dpaa2_switch_acl_entry *entry);
int dpaa2_switch_block_offload_mirror(struct dpaa2_switch_filter_block *block,
struct ethsw_port_priv *port_priv);
int dpaa2_switch_block_unoffload_mirror(struct dpaa2_switch_filter_block *block,
struct ethsw_port_priv *port_priv);
#endif /* __ETHSW_H */ #endif /* __ETHSW_H */
...@@ -39,11 +39,16 @@ ...@@ -39,11 +39,16 @@
#define DPSW_CMDID_GET_IRQ_STATUS DPSW_CMD_ID(0x016) #define DPSW_CMDID_GET_IRQ_STATUS DPSW_CMD_ID(0x016)
#define DPSW_CMDID_CLEAR_IRQ_STATUS DPSW_CMD_ID(0x017) #define DPSW_CMDID_CLEAR_IRQ_STATUS DPSW_CMD_ID(0x017)
#define DPSW_CMDID_SET_REFLECTION_IF DPSW_CMD_ID(0x022)
#define DPSW_CMDID_IF_SET_TCI DPSW_CMD_ID(0x030) #define DPSW_CMDID_IF_SET_TCI DPSW_CMD_ID(0x030)
#define DPSW_CMDID_IF_SET_STP DPSW_CMD_ID(0x031) #define DPSW_CMDID_IF_SET_STP DPSW_CMD_ID(0x031)
#define DPSW_CMDID_IF_GET_COUNTER DPSW_CMD_V2(0x034) #define DPSW_CMDID_IF_GET_COUNTER DPSW_CMD_V2(0x034)
#define DPSW_CMDID_IF_ADD_REFLECTION DPSW_CMD_ID(0x037)
#define DPSW_CMDID_IF_REMOVE_REFLECTION DPSW_CMD_ID(0x038)
#define DPSW_CMDID_IF_ENABLE DPSW_CMD_ID(0x03D) #define DPSW_CMDID_IF_ENABLE DPSW_CMD_ID(0x03D)
#define DPSW_CMDID_IF_DISABLE DPSW_CMD_ID(0x03E) #define DPSW_CMDID_IF_DISABLE DPSW_CMD_ID(0x03E)
...@@ -533,5 +538,19 @@ struct dpsw_cmd_acl_entry { ...@@ -533,5 +538,19 @@ struct dpsw_cmd_acl_entry {
__le64 pad2[4]; __le64 pad2[4];
__le64 key_iova; __le64 key_iova;
}; };
struct dpsw_cmd_set_reflection_if {
__le16 if_id;
};
#define DPSW_FILTER_SHIFT 0
#define DPSW_FILTER_SIZE 2
struct dpsw_cmd_if_reflection {
__le16 if_id;
__le16 vlan_id;
/* only 2 bits from the LSB */
u8 filter;
};
#pragma pack(pop) #pragma pack(pop)
#endif /* __FSL_DPSW_CMD_H */ #endif /* __FSL_DPSW_CMD_H */
...@@ -1579,3 +1579,83 @@ int dpsw_acl_remove_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ...@@ -1579,3 +1579,83 @@ int dpsw_acl_remove_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
/* send command to mc*/ /* send command to mc*/
return mc_send_command(mc_io, &cmd); return mc_send_command(mc_io, &cmd);
} }
/**
* dpsw_set_reflection_if() - Set target interface for traffic mirrored
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
* @token: Token of DPSW object
* @if_id: Interface Id
*
* Only one mirroring destination is allowed per switch
*
* Return: Completion status. '0' on Success; Error code otherwise.
*/
int dpsw_set_reflection_if(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id)
{
struct dpsw_cmd_set_reflection_if *cmd_params;
struct fsl_mc_command cmd = { 0 };
cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_REFLECTION_IF,
cmd_flags,
token);
cmd_params = (struct dpsw_cmd_set_reflection_if *)cmd.params;
cmd_params->if_id = cpu_to_le16(if_id);
return mc_send_command(mc_io, &cmd);
}
/**
* dpsw_if_add_reflection() - Setup mirroring rule
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
* @token: Token of DPSW object
* @if_id: Interface Identifier
* @cfg: Reflection configuration
*
* Return: Completion status. '0' on Success; Error code otherwise.
*/
int dpsw_if_add_reflection(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id, const struct dpsw_reflection_cfg *cfg)
{
struct dpsw_cmd_if_reflection *cmd_params;
struct fsl_mc_command cmd = { 0 };
cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_ADD_REFLECTION,
cmd_flags,
token);
cmd_params = (struct dpsw_cmd_if_reflection *)cmd.params;
cmd_params->if_id = cpu_to_le16(if_id);
cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id);
dpsw_set_field(cmd_params->filter, FILTER, cfg->filter);
return mc_send_command(mc_io, &cmd);
}
/**
* dpsw_if_remove_reflection() - Remove mirroring rule
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
* @token: Token of DPSW object
* @if_id: Interface Identifier
* @cfg: Reflection configuration
*
* Return: Completion status. '0' on Success; Error code otherwise.
*/
int dpsw_if_remove_reflection(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id, const struct dpsw_reflection_cfg *cfg)
{
struct dpsw_cmd_if_reflection *cmd_params;
struct fsl_mc_command cmd = { 0 };
cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_REMOVE_REFLECTION,
cmd_flags,
token);
cmd_params = (struct dpsw_cmd_if_reflection *)cmd.params;
cmd_params->if_id = cpu_to_le16(if_id);
cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id);
dpsw_set_field(cmd_params->filter, FILTER, cfg->filter);
return mc_send_command(mc_io, &cmd);
}
...@@ -752,4 +752,35 @@ int dpsw_acl_add_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ...@@ -752,4 +752,35 @@ int dpsw_acl_add_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
int dpsw_acl_remove_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, int dpsw_acl_remove_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 acl_id, const struct dpsw_acl_entry_cfg *cfg); u16 acl_id, const struct dpsw_acl_entry_cfg *cfg);
/**
* enum dpsw_reflection_filter - Filter type for frames to be reflected
* @DPSW_REFLECTION_FILTER_INGRESS_ALL: Reflect all frames
* @DPSW_REFLECTION_FILTER_INGRESS_VLAN: Reflect only frames that belong to
* the particular VLAN defined by vid parameter
*
*/
enum dpsw_reflection_filter {
DPSW_REFLECTION_FILTER_INGRESS_ALL = 0,
DPSW_REFLECTION_FILTER_INGRESS_VLAN = 1
};
/**
* struct dpsw_reflection_cfg - Structure representing the mirroring config
* @filter: Filter type for frames to be mirrored
* @vlan_id: VLAN ID to mirror; valid only when the type is DPSW_INGRESS_VLAN
*/
struct dpsw_reflection_cfg {
enum dpsw_reflection_filter filter;
u16 vlan_id;
};
int dpsw_set_reflection_if(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id);
int dpsw_if_add_reflection(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id, const struct dpsw_reflection_cfg *cfg);
int dpsw_if_remove_reflection(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id, const struct dpsw_reflection_cfg *cfg);
#endif /* __FSL_DPSW_H */ #endif /* __FSL_DPSW_H */
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