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

Merge branch 'mlxsw-Implement-flower-ingress-device-matching-offload'

Ido Schimmel says:

====================
mlxsw: Implement flower ingress device matching offload

Jiri says:

In case of using shared block, user might find it handy to be able to insert
filters to match on particular ingress device. This patchset exposes the
ingress ifindex through flow_dissector and flow_offload so mlxsw can use it to
push down to HW. See the selftests for examples of usage.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 39f58860 dcc5e1f9
...@@ -30,8 +30,9 @@ static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk) ...@@ -30,8 +30,9 @@ static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk)
elinst = &block->instances[j]; elinst = &block->instances[j];
if (elinst->type != elinst->info->type || if (elinst->type != elinst->info->type ||
elinst->item.size.bits != (!elinst->avoid_size_check &&
elinst->info->item.size.bits) elinst->item.size.bits !=
elinst->info->item.size.bits))
return false; return false;
} }
} }
...@@ -385,12 +386,12 @@ EXPORT_SYMBOL(mlxsw_afk_values_add_buf); ...@@ -385,12 +386,12 @@ EXPORT_SYMBOL(mlxsw_afk_values_add_buf);
static void mlxsw_sp_afk_encode_u32(const struct mlxsw_item *storage_item, static void mlxsw_sp_afk_encode_u32(const struct mlxsw_item *storage_item,
const struct mlxsw_item *output_item, const struct mlxsw_item *output_item,
char *storage, char *output) char *storage, char *output, int diff)
{ {
u32 value; u32 value;
value = __mlxsw_item_get32(storage, storage_item, 0); value = __mlxsw_item_get32(storage, storage_item, 0);
__mlxsw_item_set32(output, output_item, 0, value); __mlxsw_item_set32(output, output_item, 0, value + diff);
} }
static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item, static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item,
...@@ -406,14 +407,14 @@ static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item, ...@@ -406,14 +407,14 @@ static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item,
static void static void
mlxsw_sp_afk_encode_one(const struct mlxsw_afk_element_inst *elinst, mlxsw_sp_afk_encode_one(const struct mlxsw_afk_element_inst *elinst,
char *output, char *storage) char *output, char *storage, int u32_diff)
{ {
const struct mlxsw_item *storage_item = &elinst->info->item; const struct mlxsw_item *storage_item = &elinst->info->item;
const struct mlxsw_item *output_item = &elinst->item; const struct mlxsw_item *output_item = &elinst->item;
if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_U32) if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_U32)
mlxsw_sp_afk_encode_u32(storage_item, output_item, mlxsw_sp_afk_encode_u32(storage_item, output_item,
storage, output); storage, output, u32_diff);
else if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_BUF) else if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_BUF)
mlxsw_sp_afk_encode_buf(storage_item, output_item, mlxsw_sp_afk_encode_buf(storage_item, output_item,
storage, output); storage, output);
...@@ -446,9 +447,10 @@ void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk, ...@@ -446,9 +447,10 @@ void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk,
continue; continue;
mlxsw_sp_afk_encode_one(elinst, block_key, mlxsw_sp_afk_encode_one(elinst, block_key,
values->storage.key); values->storage.key,
elinst->u32_key_diff);
mlxsw_sp_afk_encode_one(elinst, block_mask, mlxsw_sp_afk_encode_one(elinst, block_mask,
values->storage.mask); values->storage.mask, 0);
} }
mlxsw_afk->ops->encode_block(key, i, block_key); mlxsw_afk->ops->encode_block(key, i, block_key);
......
...@@ -74,7 +74,7 @@ struct mlxsw_afk_element_info { ...@@ -74,7 +74,7 @@ struct mlxsw_afk_element_info {
* define an internal storage geometry. * define an internal storage geometry.
*/ */
static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
MLXSW_AFK_ELEMENT_INFO_U32(SRC_SYS_PORT, 0x00, 16, 8), MLXSW_AFK_ELEMENT_INFO_U32(SRC_SYS_PORT, 0x00, 16, 16),
MLXSW_AFK_ELEMENT_INFO_BUF(DMAC_32_47, 0x04, 2), MLXSW_AFK_ELEMENT_INFO_BUF(DMAC_32_47, 0x04, 2),
MLXSW_AFK_ELEMENT_INFO_BUF(DMAC_0_31, 0x06, 4), MLXSW_AFK_ELEMENT_INFO_BUF(DMAC_0_31, 0x06, 4),
MLXSW_AFK_ELEMENT_INFO_BUF(SMAC_32_47, 0x0A, 2), MLXSW_AFK_ELEMENT_INFO_BUF(SMAC_32_47, 0x0A, 2),
...@@ -107,9 +107,14 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */ ...@@ -107,9 +107,14 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */
const struct mlxsw_afk_element_info *info; const struct mlxsw_afk_element_info *info;
enum mlxsw_afk_element_type type; enum mlxsw_afk_element_type type;
struct mlxsw_item item; /* element geometry in block */ struct mlxsw_item item; /* element geometry in block */
int u32_key_diff; /* in case value needs to be adjusted before write
* this diff is here to handle that
*/
bool avoid_size_check;
}; };
#define MLXSW_AFK_ELEMENT_INST(_type, _element, _offset, _shift, _size) \ #define MLXSW_AFK_ELEMENT_INST(_type, _element, _offset, \
_shift, _size, _u32_key_diff, _avoid_size_check) \
{ \ { \
.info = &mlxsw_afk_element_infos[MLXSW_AFK_ELEMENT_##_element], \ .info = &mlxsw_afk_element_infos[MLXSW_AFK_ELEMENT_##_element], \
.type = _type, \ .type = _type, \
...@@ -119,15 +124,24 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */ ...@@ -119,15 +124,24 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */
.size = {.bits = _size}, \ .size = {.bits = _size}, \
.name = #_element, \ .name = #_element, \
}, \ }, \
.u32_key_diff = _u32_key_diff, \
.avoid_size_check = _avoid_size_check, \
} }
#define MLXSW_AFK_ELEMENT_INST_U32(_element, _offset, _shift, _size) \ #define MLXSW_AFK_ELEMENT_INST_U32(_element, _offset, _shift, _size) \
MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_U32, \ MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_U32, \
_element, _offset, _shift, _size) _element, _offset, _shift, _size, 0, false)
#define MLXSW_AFK_ELEMENT_INST_EXT_U32(_element, _offset, \
_shift, _size, _key_diff, \
_avoid_size_check) \
MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_U32, \
_element, _offset, _shift, _size, \
_key_diff, _avoid_size_check)
#define MLXSW_AFK_ELEMENT_INST_BUF(_element, _offset, _size) \ #define MLXSW_AFK_ELEMENT_INST_BUF(_element, _offset, _size) \
MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_BUF, \ MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_BUF, \
_element, _offset, 0, _size) _element, _offset, 0, _size, 0, false)
struct mlxsw_afk_block { struct mlxsw_afk_block {
u16 encoding; /* block ID */ u16 encoding; /* block ID */
......
...@@ -623,6 +623,15 @@ enum mlxsw_sp_acl_profile { ...@@ -623,6 +623,15 @@ enum mlxsw_sp_acl_profile {
MLXSW_SP_ACL_PROFILE_MR, MLXSW_SP_ACL_PROFILE_MR,
}; };
struct mlxsw_sp_acl_block {
struct list_head binding_list;
struct mlxsw_sp_acl_ruleset *ruleset_zero;
struct mlxsw_sp *mlxsw_sp;
unsigned int rule_count;
unsigned int disable_count;
struct net *net;
};
struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl); struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl);
struct mlxsw_sp *mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block *block); struct mlxsw_sp *mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block *block);
unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block *block); unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block *block);
......
...@@ -45,14 +45,6 @@ struct mlxsw_sp_acl_block_binding { ...@@ -45,14 +45,6 @@ struct mlxsw_sp_acl_block_binding {
bool ingress; bool ingress;
}; };
struct mlxsw_sp_acl_block {
struct list_head binding_list;
struct mlxsw_sp_acl_ruleset *ruleset_zero;
struct mlxsw_sp *mlxsw_sp;
unsigned int rule_count;
unsigned int disable_count;
};
struct mlxsw_sp_acl_ruleset_ht_key { struct mlxsw_sp_acl_ruleset_ht_key {
struct mlxsw_sp_acl_block *block; struct mlxsw_sp_acl_block *block;
u32 chain_index; u32 chain_index;
...@@ -221,6 +213,7 @@ struct mlxsw_sp_acl_block *mlxsw_sp_acl_block_create(struct mlxsw_sp *mlxsw_sp, ...@@ -221,6 +213,7 @@ struct mlxsw_sp_acl_block *mlxsw_sp_acl_block_create(struct mlxsw_sp *mlxsw_sp,
return NULL; return NULL;
INIT_LIST_HEAD(&block->binding_list); INIT_LIST_HEAD(&block->binding_list);
block->mlxsw_sp = mlxsw_sp; block->mlxsw_sp = mlxsw_sp;
block->net = net;
return block; return block;
} }
......
...@@ -12,7 +12,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = { ...@@ -12,7 +12,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = {
MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x02, 4), MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x02, 4),
MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3), MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3),
MLXSW_AFK_ELEMENT_INST_U32(VID, 0x08, 0, 12), MLXSW_AFK_ELEMENT_INST_U32(VID, 0x08, 0, 12),
MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 8), MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
}; };
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = { static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = {
...@@ -20,7 +20,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = { ...@@ -20,7 +20,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = {
MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x02, 4), MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x02, 4),
MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3), MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3),
MLXSW_AFK_ELEMENT_INST_U32(VID, 0x08, 0, 12), MLXSW_AFK_ELEMENT_INST_U32(VID, 0x08, 0, 12),
MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 8), MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
}; };
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = { static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = {
...@@ -32,13 +32,13 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = { ...@@ -32,13 +32,13 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = {
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = { static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = {
MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4), MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4),
MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8), MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8),
MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 8), MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
}; };
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = { static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = {
MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x00, 4), MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x00, 4),
MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8), MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8),
MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 8), MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
}; };
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = {
...@@ -149,7 +149,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = { ...@@ -149,7 +149,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = {
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = { static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = {
MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12), MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12),
MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x04, 0, 8), /* RX_ACL_SYSTEM_PORT */ MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 8, -1, true), /* RX_ACL_SYSTEM_PORT */
}; };
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = { static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = {
......
...@@ -120,6 +120,49 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, ...@@ -120,6 +120,49 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
return 0; return 0;
} }
static int mlxsw_sp_flower_parse_meta(struct mlxsw_sp_acl_rule_info *rulei,
struct tc_cls_flower_offload *f,
struct mlxsw_sp_acl_block *block)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
struct mlxsw_sp_port *mlxsw_sp_port;
struct net_device *ingress_dev;
struct flow_match_meta match;
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META))
return 0;
flow_rule_match_meta(rule, &match);
if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported ingress ifindex mask");
return -EINVAL;
}
ingress_dev = __dev_get_by_index(block->net,
match.key->ingress_ifindex);
if (!ingress_dev) {
NL_SET_ERR_MSG_MOD(f->common.extack, "Can't find specified ingress port to match on");
return -EINVAL;
}
if (!mlxsw_sp_port_dev_check(ingress_dev)) {
NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on non-mlxsw ingress port");
return -EINVAL;
}
mlxsw_sp_port = netdev_priv(ingress_dev);
if (mlxsw_sp_port->mlxsw_sp != block->mlxsw_sp) {
NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on a port from different device");
return -EINVAL;
}
mlxsw_sp_acl_rulei_keymask_u32(rulei,
MLXSW_AFK_ELEMENT_SRC_SYS_PORT,
mlxsw_sp_port->local_port,
0xFFFFFFFF);
return 0;
}
static void mlxsw_sp_flower_parse_ipv4(struct mlxsw_sp_acl_rule_info *rulei, static void mlxsw_sp_flower_parse_ipv4(struct mlxsw_sp_acl_rule_info *rulei,
struct tc_cls_flower_offload *f) struct tc_cls_flower_offload *f)
{ {
...@@ -267,7 +310,8 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, ...@@ -267,7 +310,8 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
int err; int err;
if (dissector->used_keys & if (dissector->used_keys &
~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | ~(BIT(FLOW_DISSECTOR_KEY_META) |
BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_BASIC) | BIT(FLOW_DISSECTOR_KEY_BASIC) |
BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
...@@ -283,6 +327,10 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, ...@@ -283,6 +327,10 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_acl_rulei_priority(rulei, f->common.prio); mlxsw_sp_acl_rulei_priority(rulei, f->common.prio);
err = mlxsw_sp_flower_parse_meta(rulei, f, block);
if (err)
return err;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_match_control match; struct flow_match_control match;
......
...@@ -1320,6 +1320,10 @@ skb_flow_dissect_flow_keys_basic(const struct net *net, ...@@ -1320,6 +1320,10 @@ skb_flow_dissect_flow_keys_basic(const struct net *net,
data, proto, nhoff, hlen, flags); data, proto, nhoff, hlen, flags);
} }
void skb_flow_dissect_meta(const struct sk_buff *skb,
struct flow_dissector *flow_dissector,
void *target_container);
void void
skb_flow_dissect_tunnel_info(const struct sk_buff *skb, skb_flow_dissect_tunnel_info(const struct sk_buff *skb,
struct flow_dissector *flow_dissector, struct flow_dissector *flow_dissector,
......
...@@ -200,6 +200,14 @@ struct flow_dissector_key_ip { ...@@ -200,6 +200,14 @@ struct flow_dissector_key_ip {
__u8 ttl; __u8 ttl;
}; };
/**
* struct flow_dissector_key_meta:
* @ingress_ifindex: ingress ifindex
*/
struct flow_dissector_key_meta {
int ingress_ifindex;
};
enum flow_dissector_key_id { enum flow_dissector_key_id {
FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */
FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */
...@@ -225,6 +233,7 @@ enum flow_dissector_key_id { ...@@ -225,6 +233,7 @@ enum flow_dissector_key_id {
FLOW_DISSECTOR_KEY_CVLAN, /* struct flow_dissector_key_vlan */ FLOW_DISSECTOR_KEY_CVLAN, /* struct flow_dissector_key_vlan */
FLOW_DISSECTOR_KEY_ENC_IP, /* struct flow_dissector_key_ip */ FLOW_DISSECTOR_KEY_ENC_IP, /* struct flow_dissector_key_ip */
FLOW_DISSECTOR_KEY_ENC_OPTS, /* struct flow_dissector_key_enc_opts */ FLOW_DISSECTOR_KEY_ENC_OPTS, /* struct flow_dissector_key_enc_opts */
FLOW_DISSECTOR_KEY_META, /* struct flow_dissector_key_meta */
FLOW_DISSECTOR_KEY_MAX, FLOW_DISSECTOR_KEY_MAX,
}; };
......
...@@ -10,6 +10,10 @@ struct flow_match { ...@@ -10,6 +10,10 @@ struct flow_match {
void *key; void *key;
}; };
struct flow_match_meta {
struct flow_dissector_key_meta *key, *mask;
};
struct flow_match_basic { struct flow_match_basic {
struct flow_dissector_key_basic *key, *mask; struct flow_dissector_key_basic *key, *mask;
}; };
...@@ -64,6 +68,8 @@ struct flow_match_enc_opts { ...@@ -64,6 +68,8 @@ struct flow_match_enc_opts {
struct flow_rule; struct flow_rule;
void flow_rule_match_meta(const struct flow_rule *rule,
struct flow_match_meta *out);
void flow_rule_match_basic(const struct flow_rule *rule, void flow_rule_match_basic(const struct flow_rule *rule,
struct flow_match_basic *out); struct flow_match_basic *out);
void flow_rule_match_control(const struct flow_rule *rule, void flow_rule_match_control(const struct flow_rule *rule,
......
...@@ -199,6 +199,22 @@ __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, ...@@ -199,6 +199,22 @@ __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
} }
EXPORT_SYMBOL(__skb_flow_get_ports); EXPORT_SYMBOL(__skb_flow_get_ports);
void skb_flow_dissect_meta(const struct sk_buff *skb,
struct flow_dissector *flow_dissector,
void *target_container)
{
struct flow_dissector_key_meta *meta;
if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_META))
return;
meta = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_META,
target_container);
meta->ingress_ifindex = skb->skb_iif;
}
EXPORT_SYMBOL(skb_flow_dissect_meta);
static void static void
skb_flow_dissect_set_enc_addr_type(enum flow_dissector_key_id type, skb_flow_dissect_set_enc_addr_type(enum flow_dissector_key_id type,
struct flow_dissector *flow_dissector, struct flow_dissector *flow_dissector,
......
...@@ -25,6 +25,13 @@ EXPORT_SYMBOL(flow_rule_alloc); ...@@ -25,6 +25,13 @@ EXPORT_SYMBOL(flow_rule_alloc);
(__out)->key = skb_flow_dissector_target(__d, __type, (__m)->key); \ (__out)->key = skb_flow_dissector_target(__d, __type, (__m)->key); \
(__out)->mask = skb_flow_dissector_target(__d, __type, (__m)->mask); \ (__out)->mask = skb_flow_dissector_target(__d, __type, (__m)->mask); \
void flow_rule_match_meta(const struct flow_rule *rule,
struct flow_match_meta *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_META, out);
}
EXPORT_SYMBOL(flow_rule_match_meta);
void flow_rule_match_basic(const struct flow_rule *rule, void flow_rule_match_basic(const struct flow_rule *rule,
struct flow_match_basic *out) struct flow_match_basic *out)
{ {
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <net/dst_metadata.h> #include <net/dst_metadata.h>
struct fl_flow_key { struct fl_flow_key {
int indev_ifindex; struct flow_dissector_key_meta meta;
struct flow_dissector_key_control control; struct flow_dissector_key_control control;
struct flow_dissector_key_control enc_control; struct flow_dissector_key_control enc_control;
struct flow_dissector_key_basic basic; struct flow_dissector_key_basic basic;
...@@ -284,7 +284,7 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, ...@@ -284,7 +284,7 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
list_for_each_entry_rcu(mask, &head->masks, list) { list_for_each_entry_rcu(mask, &head->masks, list) {
fl_clear_masked_range(&skb_key, mask); fl_clear_masked_range(&skb_key, mask);
skb_key.indev_ifindex = skb->skb_iif; skb_flow_dissect_meta(skb, &mask->dissector, &skb_key);
/* skb_flow_dissect() does not set n_proto in case an unknown /* skb_flow_dissect() does not set n_proto in case an unknown
* protocol, so do it rather here. * protocol, so do it rather here.
*/ */
...@@ -1026,8 +1026,8 @@ static int fl_set_key(struct net *net, struct nlattr **tb, ...@@ -1026,8 +1026,8 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack); int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
if (err < 0) if (err < 0)
return err; return err;
key->indev_ifindex = err; key->meta.ingress_ifindex = err;
mask->indev_ifindex = 0xffffffff; mask->meta.ingress_ifindex = 0xffffffff;
} }
fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
...@@ -1281,6 +1281,8 @@ static void fl_init_dissector(struct flow_dissector *dissector, ...@@ -1281,6 +1281,8 @@ static void fl_init_dissector(struct flow_dissector *dissector,
struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
size_t cnt = 0; size_t cnt = 0;
FL_KEY_SET_IF_MASKED(mask, keys, cnt,
FLOW_DISSECTOR_KEY_META, meta);
FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
FL_KEY_SET_IF_MASKED(mask, keys, cnt, FL_KEY_SET_IF_MASKED(mask, keys, cnt,
...@@ -2122,10 +2124,10 @@ static int fl_dump_key_enc_opt(struct sk_buff *skb, ...@@ -2122,10 +2124,10 @@ static int fl_dump_key_enc_opt(struct sk_buff *skb,
static int fl_dump_key(struct sk_buff *skb, struct net *net, static int fl_dump_key(struct sk_buff *skb, struct net *net,
struct fl_flow_key *key, struct fl_flow_key *mask) struct fl_flow_key *key, struct fl_flow_key *mask)
{ {
if (mask->indev_ifindex) { if (mask->meta.ingress_ifindex) {
struct net_device *dev; struct net_device *dev;
dev = __dev_get_by_index(net, key->indev_ifindex); dev = __dev_get_by_index(net, key->meta.ingress_ifindex);
if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
goto nla_put_failure; goto nla_put_failure;
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
ALL_TESTS="match_dst_mac_test match_src_mac_test match_dst_ip_test \ ALL_TESTS="match_dst_mac_test match_src_mac_test match_dst_ip_test \
match_src_ip_test match_ip_flags_test match_pcp_test match_vlan_test \ match_src_ip_test match_ip_flags_test match_pcp_test match_vlan_test \
match_ip_tos_test" match_ip_tos_test match_indev_test"
NUM_NETIFS=2 NUM_NETIFS=2
source tc_common.sh source tc_common.sh
source lib.sh source lib.sh
...@@ -310,6 +310,30 @@ match_ip_tos_test() ...@@ -310,6 +310,30 @@ match_ip_tos_test()
log_test "ip_tos match ($tcflags)" log_test "ip_tos match ($tcflags)"
} }
match_indev_test()
{
RET=0
tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
$tcflags indev $h1 dst_mac $h2mac action drop
tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
$tcflags indev $h2 dst_mac $h2mac action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "dev $h2 ingress" 101 1
check_fail $? "Matched on a wrong filter"
tc_check_packets "dev $h2 ingress" 102 1
check_err $? "Did not match on correct filter"
tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
log_test "indev match ($tcflags)"
}
setup_prepare() setup_prepare()
{ {
h1=${NETIFS[p1]} h1=${NETIFS[p1]}
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
ALL_TESTS="match_indev_egress_test"
NUM_NETIFS=6
source tc_common.sh
source lib.sh
h1_create()
{
simple_if_init $h1 192.0.1.1/24
ip route add 192.0.2.0/24 vrf v$h1 nexthop via 192.0.1.2
ip route add 192.0.3.0/24 vrf v$h1 nexthop via 192.0.1.2
}
h1_destroy()
{
ip route del 192.0.3.0/24 vrf v$h1
ip route del 192.0.2.0/24 vrf v$h1
simple_if_fini $h1 192.0.1.1/24
}
h2_create()
{
simple_if_init $h2 192.0.2.1/24
ip route add 192.0.1.0/24 vrf v$h2 nexthop via 192.0.2.2
ip route add 192.0.3.0/24 vrf v$h2 nexthop via 192.0.2.2
}
h2_destroy()
{
ip route del 192.0.3.0/24 vrf v$h2
ip route del 192.0.1.0/24 vrf v$h2
simple_if_fini $h2 192.0.2.1/24
}
h3_create()
{
simple_if_init $h3 192.0.3.1/24
ip route add 192.0.1.0/24 vrf v$h3 nexthop via 192.0.3.2
ip route add 192.0.2.0/24 vrf v$h3 nexthop via 192.0.3.2
}
h3_destroy()
{
ip route del 192.0.2.0/24 vrf v$h3
ip route del 192.0.1.0/24 vrf v$h3
simple_if_fini $h3 192.0.3.1/24
}
router_create()
{
ip link set dev $rp1 up
ip link set dev $rp2 up
ip link set dev $rp3 up
tc qdisc add dev $rp3 clsact
ip address add 192.0.1.2/24 dev $rp1
ip address add 192.0.2.2/24 dev $rp2
ip address add 192.0.3.2/24 dev $rp3
}
router_destroy()
{
ip address del 192.0.3.2/24 dev $rp3
ip address del 192.0.2.2/24 dev $rp2
ip address del 192.0.1.2/24 dev $rp1
tc qdisc del dev $rp3 clsact
ip link set dev $rp3 down
ip link set dev $rp2 down
ip link set dev $rp1 down
}
match_indev_egress_test()
{
RET=0
tc filter add dev $rp3 egress protocol ip pref 1 handle 101 flower \
$tcflags indev $rp1 dst_ip 192.0.3.1 action drop
tc filter add dev $rp3 egress protocol ip pref 2 handle 102 flower \
$tcflags indev $rp2 dst_ip 192.0.3.1 action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $rp1mac -A 192.0.1.1 -B 192.0.3.1 \
-t ip -q
tc_check_packets "dev $rp3 egress" 102 1
check_fail $? "Matched on a wrong filter"
tc_check_packets "dev $rp3 egress" 101 1
check_err $? "Did not match on correct filter"
$MZ $h2 -c 1 -p 64 -a $h2mac -b $rp2mac -A 192.0.2.1 -B 192.0.3.1 \
-t ip -q
tc_check_packets "dev $rp3 egress" 101 2
check_fail $? "Matched on a wrong filter"
tc_check_packets "dev $rp3 egress" 102 1
check_err $? "Did not match on correct filter"
tc filter del dev $rp3 egress protocol ip pref 2 handle 102 flower
tc filter del dev $rp3 egress protocol ip pref 1 handle 101 flower
log_test "indev egress match ($tcflags)"
}
setup_prepare()
{
h1=${NETIFS[p1]}
rp1=${NETIFS[p2]}
h2=${NETIFS[p3]}
rp2=${NETIFS[p4]}
h3=${NETIFS[p5]}
rp3=${NETIFS[p6]}
h1mac=$(mac_get $h1)
rp1mac=$(mac_get $rp1)
h2mac=$(mac_get $h2)
rp2mac=$(mac_get $rp2)
vrf_prepare
h1_create
h2_create
h3_create
router_create
forwarding_enable
}
cleanup()
{
pre_cleanup
forwarding_restore
router_destroy
h3_destroy
h2_destroy
h1_destroy
vrf_cleanup
}
trap cleanup EXIT
setup_prepare
setup_wait
tc_offload_check
if [[ $? -ne 0 ]]; then
log_info "Could not test offloaded functionality"
else
tcflags="skip_sw"
tests_run
fi
exit $EXIT_STATUS
#!/bin/bash #!/bin/bash
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
ALL_TESTS="shared_block_test" ALL_TESTS="shared_block_test match_indev_test"
NUM_NETIFS=4 NUM_NETIFS=4
source tc_common.sh source tc_common.sh
source lib.sh source lib.sh
...@@ -70,6 +70,33 @@ shared_block_test() ...@@ -70,6 +70,33 @@ shared_block_test()
log_test "shared block ($tcflags)" log_test "shared block ($tcflags)"
} }
match_indev_test()
{
RET=0
tc filter add block 22 protocol ip pref 1 handle 101 flower \
$tcflags indev $swp1 dst_mac $swmac action drop
tc filter add block 22 protocol ip pref 2 handle 102 flower \
$tcflags indev $swp2 dst_mac $swmac action drop
$MZ $h1 -c 1 -p 64 -a $h1mac -b $swmac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "block 22" 101 1
check_err $? "Did not match first incoming packet on a block"
$MZ $h2 -c 1 -p 64 -a $h2mac -b $swmac -A 192.0.2.1 -B 192.0.2.2 \
-t ip -q
tc_check_packets "block 22" 102 1
check_err $? "Did not match second incoming packet on a block"
tc filter del block 22 protocol ip pref 1 handle 101 flower
tc filter del block 22 protocol ip pref 2 handle 102 flower
log_test "indev match ($tcflags)"
}
setup_prepare() setup_prepare()
{ {
h1=${NETIFS[p1]} h1=${NETIFS[p1]}
......
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