rte_flow has 'group' attribute and 'jump' action in order to support
multiple groups. This feature is known as multi-table support ('chain' in
linux TC flower) in general because a group means a table of flows. Example
commands are:
flow create 0 transfer priority 1 ingress
pattern eth / vlan vid is 100 / end
actions jump group 1 / end
flow create 0 transfer priority 1 ingress
pattern eth / vlan vid is 200 / end
actions jump group 2 / end
flow create 0 transfer group 1 priority 2 ingress
pattern eth / vlan vid is 100 /
ipv4 dst spec 192.168.40.0 dst prefix 24 / end
actions drop / end
flow create 0 transfer group 1 priority 2 ingress
pattern end
actions of_pop_vlan / port_id id 1 / end
flow create 0 transfer group 2 priority 2 ingress
pattern eth / vlan vid is 200 /
ipv4 dst spec 192.168.40.0 dst prefix 24 / end
actions of_pop_vlan / port_id id 2 / end
flow create 0 transfer group 2 priority 2 ingress
pattern end
actions port_id id 2 / end
With theses flows, if a packet having vlan 200 and src_ip as 192.168.40.1,
this packet will firstly hit the 1st flow. Then it will hit the 5th flow
because of the 'jump' action. As a result, the packet will be forwarded to
port 2 (VF representor) with vlan tag being stripped off. If the packet had
vlan 100 instead, it would be dropped by the 3rd flow.
Signed-off-by: Yongseok Koh <yskoh@mellanox.com>
linux/if_link.h \
enum IFLA_PHYS_PORT_NAME \
$(AUTOCONF_OUTPUT)
linux/if_link.h \
enum IFLA_PHYS_PORT_NAME \
$(AUTOCONF_OUTPUT)
+ $Q sh -- '$<' '$@' \
+ HAVE_TCA_CHAIN \
+ linux/rtnetlink.h \
+ enum TCA_CHAIN \
+ $(AUTOCONF_OUTPUT)
$Q sh -- '$<' '$@' \
HAVE_TCA_FLOWER_ACT \
linux/pkt_cls.h \
$Q sh -- '$<' '$@' \
HAVE_TCA_FLOWER_ACT \
linux/pkt_cls.h \
linux/pkt_cls.h \
enum TCA_FLOWER_KEY_TCP_FLAGS_MASK \
$(AUTOCONF_OUTPUT)
linux/pkt_cls.h \
enum TCA_FLOWER_KEY_TCP_FLAGS_MASK \
$(AUTOCONF_OUTPUT)
+ $Q sh -- '$<' '$@' \
+ HAVE_TC_ACT_GOTO_CHAIN \
+ linux/pkt_cls.h \
+ define TC_ACT_GOTO_CHAIN \
+ $(AUTOCONF_OUTPUT)
$Q sh -- '$<' '$@' \
HAVE_TC_ACT_VLAN \
linux/tc_act/tc_vlan.h \
$Q sh -- '$<' '$@' \
HAVE_TC_ACT_VLAN \
linux/tc_act/tc_vlan.h \
'IFLA_PHYS_SWITCH_ID' ],
[ 'HAVE_IFLA_PHYS_PORT_NAME', 'linux/if_link.h',
'IFLA_PHYS_PORT_NAME' ],
'IFLA_PHYS_SWITCH_ID' ],
[ 'HAVE_IFLA_PHYS_PORT_NAME', 'linux/if_link.h',
'IFLA_PHYS_PORT_NAME' ],
+ [ 'HAVE_TCA_CHAIN', 'linux/rtnetlink.h',
+ 'TCA_CHAIN' ],
[ 'HAVE_TCA_FLOWER_ACT', 'linux/pkt_cls.h',
'TCA_FLOWER_ACT' ],
[ 'HAVE_TCA_FLOWER_FLAGS', 'linux/pkt_cls.h',
[ 'HAVE_TCA_FLOWER_ACT', 'linux/pkt_cls.h',
'TCA_FLOWER_ACT' ],
[ 'HAVE_TCA_FLOWER_FLAGS', 'linux/pkt_cls.h',
'TCA_FLOWER_KEY_TCP_FLAGS' ],
[ 'HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK', 'linux/pkt_cls.h',
'TCA_FLOWER_KEY_TCP_FLAGS_MASK' ],
'TCA_FLOWER_KEY_TCP_FLAGS' ],
[ 'HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK', 'linux/pkt_cls.h',
'TCA_FLOWER_KEY_TCP_FLAGS_MASK' ],
+ [ 'HAVE_TC_ACT_GOTO_CHAIN', 'linux/pkt_cls.h',
+ 'TC_ACT_GOTO_CHAIN' ],
[ 'HAVE_TC_ACT_VLAN', 'linux/tc_act/tc_vlan.h',
'TCA_VLAN_PUSH_VLAN_PRIORITY' ],
[ 'HAVE_TC_ACT_PEDIT', 'linux/tc_act/tc_pedit.h',
[ 'HAVE_TC_ACT_VLAN', 'linux/tc_act/tc_vlan.h',
'TCA_VLAN_PUSH_VLAN_PRIORITY' ],
[ 'HAVE_TC_ACT_PEDIT', 'linux/tc_act/tc_pedit.h',
#define MLX5_FLOW_ACTION_SET_IPV6_DST (1u << 14)
#define MLX5_FLOW_ACTION_SET_TP_SRC (1u << 15)
#define MLX5_FLOW_ACTION_SET_TP_DST (1u << 16)
#define MLX5_FLOW_ACTION_SET_IPV6_DST (1u << 14)
#define MLX5_FLOW_ACTION_SET_TP_SRC (1u << 15)
#define MLX5_FLOW_ACTION_SET_TP_DST (1u << 16)
+#define MLX5_FLOW_ACTION_JUMP (1u << 17)
#define MLX5_FLOW_FATE_ACTIONS \
(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)
#define MLX5_FLOW_FATE_ACTIONS \
(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)
#ifndef TCA_CLS_FLAGS_SKIP_SW
#define TCA_CLS_FLAGS_SKIP_SW (1 << 1)
#endif
#ifndef TCA_CLS_FLAGS_SKIP_SW
#define TCA_CLS_FLAGS_SKIP_SW (1 << 1)
#endif
+#ifndef HAVE_TCA_CHAIN
+#define TCA_CHAIN 11
+#endif
#ifndef HAVE_TCA_FLOWER_ACT
#define TCA_FLOWER_ACT 3
#endif
#ifndef HAVE_TCA_FLOWER_ACT
#define TCA_FLOWER_ACT 3
#endif
#ifndef HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK
#define TCA_FLOWER_KEY_TCP_FLAGS_MASK 72
#endif
#ifndef HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK
#define TCA_FLOWER_KEY_TCP_FLAGS_MASK 72
#endif
+#ifndef HAVE_TC_ACT_GOTO_CHAIN
+#define TC_ACT_GOTO_CHAIN 0x20000000
+#endif
#ifndef IPV6_ADDR_LEN
#define IPV6_ADDR_LEN 16
#ifndef IPV6_ADDR_LEN
#define IPV6_ADDR_LEN 16
unsigned int ifindex; /**< Network interface index. */
};
unsigned int ifindex; /**< Network interface index. */
};
-#define MLX5_TCF_FATE_ACTIONS (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID)
+/* Due to a limitation on driver/FW. */
+#define MLX5_TCF_GROUP_ID_MAX 3
+#define MLX5_TCF_GROUP_PRIORITY_MAX 14
+
+#define MLX5_TCF_FATE_ACTIONS \
+ (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \
+ MLX5_FLOW_ACTION_JUMP)
+
#define MLX5_TCF_VLAN_ACTIONS \
(MLX5_FLOW_ACTION_OF_POP_VLAN | MLX5_FLOW_ACTION_OF_PUSH_VLAN | \
MLX5_FLOW_ACTION_OF_SET_VLAN_VID | MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
#define MLX5_TCF_VLAN_ACTIONS \
(MLX5_FLOW_ACTION_OF_POP_VLAN | MLX5_FLOW_ACTION_OF_PUSH_VLAN | \
MLX5_FLOW_ACTION_OF_SET_VLAN_VID | MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
MLX5_FLOW_ACTION_SET_TP_SRC | MLX5_FLOW_ACTION_SET_TP_DST)
#define MLX5_TCF_CONFIG_ACTIONS \
MLX5_FLOW_ACTION_SET_TP_SRC | MLX5_FLOW_ACTION_SET_TP_DST)
#define MLX5_TCF_CONFIG_ACTIONS \
- (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_OF_PUSH_VLAN | \
- MLX5_FLOW_ACTION_OF_SET_VLAN_VID | MLX5_FLOW_ACTION_OF_SET_VLAN_PCP | \
- MLX5_TCF_PEDIT_ACTIONS)
+ (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_JUMP | \
+ MLX5_FLOW_ACTION_OF_PUSH_VLAN | MLX5_FLOW_ACTION_OF_SET_VLAN_VID | \
+ MLX5_FLOW_ACTION_OF_SET_VLAN_PCP | MLX5_TCF_PEDIT_ACTIONS)
#define MAX_PEDIT_KEYS 128
#define SZ_PEDIT_KEY_VAL 4
#define MAX_PEDIT_KEYS 128
#define SZ_PEDIT_KEY_VAL 4
struct rte_flow_error *error)
{
/*
struct rte_flow_error *error)
{
/*
- * Supported attributes: no groups, some priorities and ingress only.
- * Don't care about transfer as it is the caller's problem.
+ * Supported attributes: groups, some priorities and ingress only.
+ * group is supported only if kernel supports chain. Don't care about
+ * transfer as it is the caller's problem.
+ if (attr->group > MLX5_TCF_GROUP_ID_MAX)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,
- "groups are not supported");
- if (attr->priority > 0xfffe)
+ "group ID larger than "
+ RTE_STR(MLX5_TCF_GROUP_ID_MAX)
+ " isn't supported");
+ else if (attr->group > 0 &&
+ attr->priority > MLX5_TCF_GROUP_PRIORITY_MAX)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+ attr,
+ "lowest priority level is "
+ RTE_STR(MLX5_TCF_GROUP_PRIORITY_MAX)
+ " when group is configured");
+ else if (attr->priority > 0xfffe)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
attr,
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
attr,
} spec, mask;
union {
const struct rte_flow_action_port_id *port_id;
} spec, mask;
union {
const struct rte_flow_action_port_id *port_id;
+ const struct rte_flow_action_jump *jump;
const struct rte_flow_action_of_push_vlan *of_push_vlan;
const struct rte_flow_action_of_set_vlan_vid *
of_set_vlan_vid;
const struct rte_flow_action_of_push_vlan *of_push_vlan;
const struct rte_flow_action_of_set_vlan_vid *
of_set_vlan_vid;
break;
case RTE_FLOW_ACTION_TYPE_PORT_ID:
current_action_flag = MLX5_FLOW_ACTION_PORT_ID;
break;
case RTE_FLOW_ACTION_TYPE_PORT_ID:
current_action_flag = MLX5_FLOW_ACTION_PORT_ID;
- if (action_flags & MLX5_TCF_FATE_ACTIONS)
- return rte_flow_error_set
- (error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION, actions,
- "can't have multiple fate actions");
if (!actions->conf)
break;
conf.port_id = actions->conf;
if (!actions->conf)
break;
conf.port_id = actions->conf;
" ifindex");
port_id_dev = &rte_eth_devices[conf.port_id->id];
break;
" ifindex");
port_id_dev = &rte_eth_devices[conf.port_id->id];
break;
- case RTE_FLOW_ACTION_TYPE_DROP:
- if (action_flags & MLX5_TCF_FATE_ACTIONS)
+ case RTE_FLOW_ACTION_TYPE_JUMP:
+ current_action_flag = MLX5_FLOW_ACTION_JUMP;
+ if (!actions->conf)
+ break;
+ conf.jump = actions->conf;
+ if (attr->group >= conf.jump->group)
return rte_flow_error_set
return rte_flow_error_set
- (error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION, actions,
- "can't have multiple fate actions");
+ (error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ actions,
+ "can jump only to a group forward");
+ break;
+ case RTE_FLOW_ACTION_TYPE_DROP:
current_action_flag = MLX5_FLOW_ACTION_DROP;
break;
case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
current_action_flag = MLX5_FLOW_ACTION_DROP;
break;
case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
"action configuration not set");
}
if ((current_action_flag & MLX5_TCF_PEDIT_ACTIONS) &&
"action configuration not set");
}
if ((current_action_flag & MLX5_TCF_PEDIT_ACTIONS) &&
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION,
actions,
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ACTION,
actions,
if ((current_action_flag & ~MLX5_TCF_PEDIT_ACTIONS) &&
(action_flags & MLX5_TCF_PEDIT_ACTIONS))
pedit_validated = 1;
if ((current_action_flag & ~MLX5_TCF_PEDIT_ACTIONS) &&
(action_flags & MLX5_TCF_PEDIT_ACTIONS))
pedit_validated = 1;
+ if ((current_action_flag & MLX5_TCF_FATE_ACTIONS) &&
+ (action_flags & MLX5_TCF_FATE_ACTIONS))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ actions,
+ "can't have multiple fate"
+ " actions");
action_flags |= current_action_flag;
}
if ((action_flags & MLX5_TCF_PEDIT_ACTIONS) &&
action_flags |= current_action_flag;
}
if ((action_flags & MLX5_TCF_PEDIT_ACTIONS) &&
* Maximum size of memory for items.
*/
static int
* Maximum size of memory for items.
*/
static int
-flow_tcf_get_items_and_size(const struct rte_flow_item items[],
+flow_tcf_get_items_and_size(const struct rte_flow_attr *attr,
+ const struct rte_flow_item items[],
uint64_t *item_flags)
{
int size = 0;
uint64_t *item_flags)
{
int size = 0;
size += SZ_NLATTR_STRZ_OF("flower") +
SZ_NLATTR_NEST + /* TCA_OPTIONS. */
SZ_NLATTR_TYPE_OF(uint32_t); /* TCA_CLS_FLAGS_SKIP_SW. */
size += SZ_NLATTR_STRZ_OF("flower") +
SZ_NLATTR_NEST + /* TCA_OPTIONS. */
SZ_NLATTR_TYPE_OF(uint32_t); /* TCA_CLS_FLAGS_SKIP_SW. */
+ if (attr->group > 0)
+ size += SZ_NLATTR_TYPE_OF(uint32_t); /* TCA_CHAIN. */
for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
switch (items->type) {
case RTE_FLOW_ITEM_TYPE_VOID:
for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
switch (items->type) {
case RTE_FLOW_ITEM_TYPE_VOID:
SZ_NLATTR_TYPE_OF(struct tc_mirred);
flags |= MLX5_FLOW_ACTION_PORT_ID;
break;
SZ_NLATTR_TYPE_OF(struct tc_mirred);
flags |= MLX5_FLOW_ACTION_PORT_ID;
break;
+ case RTE_FLOW_ACTION_TYPE_JUMP:
+ size += SZ_NLATTR_NEST + /* na_act_index. */
+ SZ_NLATTR_STRZ_OF("gact") +
+ SZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. */
+ SZ_NLATTR_TYPE_OF(struct tc_gact);
+ flags |= MLX5_FLOW_ACTION_JUMP;
+ break;
case RTE_FLOW_ACTION_TYPE_DROP:
size += SZ_NLATTR_NEST + /* na_act_index. */
SZ_NLATTR_STRZ_OF("gact") +
case RTE_FLOW_ACTION_TYPE_DROP:
size += SZ_NLATTR_NEST + /* na_act_index. */
SZ_NLATTR_STRZ_OF("gact") +
* otherwise NULL and rte_ernno is set.
*/
static struct mlx5_flow *
* otherwise NULL and rte_ernno is set.
*/
static struct mlx5_flow *
-flow_tcf_prepare(const struct rte_flow_attr *attr __rte_unused,
+flow_tcf_prepare(const struct rte_flow_attr *attr,
const struct rte_flow_item items[],
const struct rte_flow_action actions[],
uint64_t *item_flags, uint64_t *action_flags,
const struct rte_flow_item items[],
const struct rte_flow_action actions[],
uint64_t *item_flags, uint64_t *action_flags,
struct nlmsghdr *nlh;
struct tcmsg *tcm;
struct nlmsghdr *nlh;
struct tcmsg *tcm;
- size += flow_tcf_get_items_and_size(items, item_flags);
+ size += flow_tcf_get_items_and_size(attr, items, item_flags);
size += flow_tcf_get_actions_and_size(actions, action_flags);
dev_flow = rte_zmalloc(__func__, size, MNL_ALIGNTO);
if (!dev_flow) {
size += flow_tcf_get_actions_and_size(actions, action_flags);
dev_flow = rte_zmalloc(__func__, size, MNL_ALIGNTO);
if (!dev_flow) {
} spec, mask;
union {
const struct rte_flow_action_port_id *port_id;
} spec, mask;
union {
const struct rte_flow_action_port_id *port_id;
+ const struct rte_flow_action_jump *jump;
const struct rte_flow_action_of_push_vlan *of_push_vlan;
const struct rte_flow_action_of_set_vlan_vid *
of_set_vlan_vid;
const struct rte_flow_action_of_push_vlan *of_push_vlan;
const struct rte_flow_action_of_set_vlan_vid *
of_set_vlan_vid;
*/
tcm->tcm_info = TC_H_MAKE((attr->priority + 1) << 16,
RTE_BE16(ETH_P_ALL));
*/
tcm->tcm_info = TC_H_MAKE((attr->priority + 1) << 16,
RTE_BE16(ETH_P_ALL));
+ if (attr->group > 0)
+ mnl_attr_put_u32(nlh, TCA_CHAIN, attr->group);
mnl_attr_put_strz(nlh, TCA_KIND, "flower");
na_flower = mnl_attr_nest_start(nlh, TCA_OPTIONS);
mnl_attr_put_u32(nlh, TCA_FLOWER_FLAGS, TCA_CLS_FLAGS_SKIP_SW);
mnl_attr_put_strz(nlh, TCA_KIND, "flower");
na_flower = mnl_attr_nest_start(nlh, TCA_OPTIONS);
mnl_attr_put_u32(nlh, TCA_FLOWER_FLAGS, TCA_CLS_FLAGS_SKIP_SW);
mnl_attr_nest_end(nlh, na_act);
mnl_attr_nest_end(nlh, na_act_index);
break;
mnl_attr_nest_end(nlh, na_act);
mnl_attr_nest_end(nlh, na_act_index);
break;
+ case RTE_FLOW_ACTION_TYPE_JUMP:
+ conf.jump = actions->conf;
+ na_act_index =
+ mnl_attr_nest_start(nlh, na_act_index_cur++);
+ assert(na_act_index);
+ mnl_attr_put_strz(nlh, TCA_ACT_KIND, "gact");
+ na_act = mnl_attr_nest_start(nlh, TCA_ACT_OPTIONS);
+ assert(na_act);
+ mnl_attr_put(nlh, TCA_GACT_PARMS,
+ sizeof(struct tc_gact),
+ &(struct tc_gact){
+ .action = TC_ACT_GOTO_CHAIN |
+ conf.jump->group,
+ });
+ mnl_attr_nest_end(nlh, na_act);
+ mnl_attr_nest_end(nlh, na_act_index);
+ break;
case RTE_FLOW_ACTION_TYPE_DROP:
na_act_index =
mnl_attr_nest_start(nlh, na_act_index_cur++);
case RTE_FLOW_ACTION_TYPE_DROP:
na_act_index =
mnl_attr_nest_start(nlh, na_act_index_cur++);