Commit 717f1019 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'flow_offload-add-tc-vlan-push_eth-and-pop_eth-actions'

Roi Dayan says:

====================
flow_offload: add tc vlan push_eth and pop_eth actions

Offloading vlan push_eth and pop_eth actions is needed in order to
correctly offload MPLSoUDP encap and decap flows, this series extends
the flow offload API to support these actions and updates mlx5 to
parse them.
====================

Link: https://lore.kernel.org/r/20220315110211.1581468-1-roid@nvidia.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents a860352e 725726fd
...@@ -35,6 +35,13 @@ static struct mlx5e_tc_act *tc_acts_fdb[NUM_FLOW_ACTIONS] = { ...@@ -35,6 +35,13 @@ static struct mlx5e_tc_act *tc_acts_fdb[NUM_FLOW_ACTIONS] = {
NULL, /* FLOW_ACTION_CT_METADATA, */ NULL, /* FLOW_ACTION_CT_METADATA, */
&mlx5e_tc_act_mpls_push, &mlx5e_tc_act_mpls_push,
&mlx5e_tc_act_mpls_pop, &mlx5e_tc_act_mpls_pop,
NULL, /* FLOW_ACTION_MPLS_MANGLE, */
NULL, /* FLOW_ACTION_GATE, */
NULL, /* FLOW_ACTION_PPPOE_PUSH, */
NULL, /* FLOW_ACTION_JUMP, */
NULL, /* FLOW_ACTION_PIPE, */
&mlx5e_tc_act_vlan,
&mlx5e_tc_act_vlan,
}; };
/* Must be aligned with enum flow_action_id. */ /* Must be aligned with enum flow_action_id. */
......
...@@ -22,6 +22,8 @@ struct mlx5e_tc_act_parse_state { ...@@ -22,6 +22,8 @@ struct mlx5e_tc_act_parse_state {
bool encap; bool encap;
bool decap; bool decap;
bool mpls_push; bool mpls_push;
bool eth_push;
bool eth_pop;
bool ptype_host; bool ptype_host;
const struct ip_tunnel_info *tun_info; const struct ip_tunnel_info *tun_info;
struct mlx5e_mpls_info mpls_info; struct mlx5e_mpls_info mpls_info;
......
...@@ -125,6 +125,16 @@ tc_act_can_offload_mirred(struct mlx5e_tc_act_parse_state *parse_state, ...@@ -125,6 +125,16 @@ tc_act_can_offload_mirred(struct mlx5e_tc_act_parse_state *parse_state,
return false; return false;
} }
if (parse_state->eth_pop && !parse_state->mpls_push) {
NL_SET_ERR_MSG_MOD(extack, "vlan pop eth is supported only with mpls push");
return false;
}
if (flow_flag_test(parse_state->flow, L3_TO_L2_DECAP) && !parse_state->eth_push) {
NL_SET_ERR_MSG_MOD(extack, "mpls pop is only supported with vlan eth push");
return false;
}
if (mlx5e_is_ft_flow(flow) && out_dev == priv->netdev) { if (mlx5e_is_ft_flow(flow) && out_dev == priv->netdev) {
/* Ignore forward to self rules generated /* Ignore forward to self rules generated
* by adding both mlx5 devs to the flow table * by adding both mlx5 devs to the flow table
......
...@@ -57,12 +57,13 @@ tc_act_can_offload_mpls_pop(struct mlx5e_tc_act_parse_state *parse_state, ...@@ -57,12 +57,13 @@ tc_act_can_offload_mpls_pop(struct mlx5e_tc_act_parse_state *parse_state,
filter_dev = attr->parse_attr->filter_dev; filter_dev = attr->parse_attr->filter_dev;
/* we only support mpls pop if it is the first action /* we only support mpls pop if it is the first action
* or it is second action after tunnel key unset
* and the filter net device is bareudp. Subsequent * and the filter net device is bareudp. Subsequent
* actions can be pedit and the last can be mirred * actions can be pedit and the last can be mirred
* egress redirect. * egress redirect.
*/ */
if (act_index) { if ((act_index == 1 && !parse_state->decap) || act_index > 1) {
NL_SET_ERR_MSG_MOD(extack, "mpls pop supported only as first action"); NL_SET_ERR_MSG_MOD(extack, "mpls pop supported only as first action or with decap");
return false; return false;
} }
...@@ -80,7 +81,7 @@ tc_act_parse_mpls_pop(struct mlx5e_tc_act_parse_state *parse_state, ...@@ -80,7 +81,7 @@ tc_act_parse_mpls_pop(struct mlx5e_tc_act_parse_state *parse_state,
struct mlx5e_priv *priv, struct mlx5e_priv *priv,
struct mlx5_flow_attr *attr) struct mlx5_flow_attr *attr)
{ {
attr->parse_attr->eth.h_proto = act->mpls_pop.proto; attr->esw_attr->eth.h_proto = act->mpls_pop.proto;
attr->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; attr->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
flow_flag_set(parse_state->flow, L3_TO_L2_DECAP); flow_flag_set(parse_state->flow, L3_TO_L2_DECAP);
......
...@@ -42,13 +42,12 @@ set_pedit_val(u8 hdr_type, u32 mask, u32 val, u32 offset, ...@@ -42,13 +42,12 @@ set_pedit_val(u8 hdr_type, u32 mask, u32 val, u32 offset,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int int
parse_pedit_to_modify_hdr(struct mlx5e_priv *priv, mlx5e_tc_act_pedit_parse_action(struct mlx5e_priv *priv,
const struct flow_action_entry *act, int namespace, const struct flow_action_entry *act, int namespace,
struct mlx5e_tc_flow_parse_attr *parse_attr, struct pedit_headers_action *hdrs,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct pedit_headers_action *hdrs = parse_attr->hdrs;
u8 cmd = (act->id == FLOW_ACTION_MANGLE) ? 0 : 1; u8 cmd = (act->id == FLOW_ACTION_MANGLE) ? 0 : 1;
u8 htype = act->mangle.htype; u8 htype = act->mangle.htype;
int err = -EOPNOTSUPP; int err = -EOPNOTSUPP;
...@@ -79,46 +78,6 @@ parse_pedit_to_modify_hdr(struct mlx5e_priv *priv, ...@@ -79,46 +78,6 @@ parse_pedit_to_modify_hdr(struct mlx5e_priv *priv,
return err; return err;
} }
static int
parse_pedit_to_reformat(const struct flow_action_entry *act,
struct mlx5e_tc_flow_parse_attr *parse_attr,
struct netlink_ext_ack *extack)
{
u32 mask, val, offset;
u32 *p;
if (act->id != FLOW_ACTION_MANGLE) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported action id");
return -EOPNOTSUPP;
}
if (act->mangle.htype != FLOW_ACT_MANGLE_HDR_TYPE_ETH) {
NL_SET_ERR_MSG_MOD(extack, "Only Ethernet modification is supported");
return -EOPNOTSUPP;
}
mask = ~act->mangle.mask;
val = act->mangle.val;
offset = act->mangle.offset;
p = (u32 *)&parse_attr->eth;
*(p + (offset >> 2)) |= (val & mask);
return 0;
}
int
mlx5e_tc_act_pedit_parse_action(struct mlx5e_priv *priv,
const struct flow_action_entry *act, int namespace,
struct mlx5e_tc_flow_parse_attr *parse_attr,
struct mlx5e_tc_flow *flow,
struct netlink_ext_ack *extack)
{
if (flow && flow_flag_test(flow, L3_TO_L2_DECAP))
return parse_pedit_to_reformat(act, parse_attr, extack);
return parse_pedit_to_modify_hdr(priv, act, namespace, parse_attr, extack);
}
static bool static bool
tc_act_can_offload_pedit(struct mlx5e_tc_act_parse_state *parse_state, tc_act_can_offload_pedit(struct mlx5e_tc_act_parse_state *parse_state,
const struct flow_action_entry *act, const struct flow_action_entry *act,
...@@ -141,20 +100,16 @@ tc_act_parse_pedit(struct mlx5e_tc_act_parse_state *parse_state, ...@@ -141,20 +100,16 @@ tc_act_parse_pedit(struct mlx5e_tc_act_parse_state *parse_state,
ns_type = mlx5e_get_flow_namespace(flow); ns_type = mlx5e_get_flow_namespace(flow);
err = mlx5e_tc_act_pedit_parse_action(flow->priv, act, ns_type, attr->parse_attr, err = mlx5e_tc_act_pedit_parse_action(flow->priv, act, ns_type, attr->parse_attr->hdrs,
flow, parse_state->extack); parse_state->extack);
if (err) if (err)
return err; return err;
if (flow_flag_test(flow, L3_TO_L2_DECAP))
goto out;
attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
if (ns_type == MLX5_FLOW_NAMESPACE_FDB) if (ns_type == MLX5_FLOW_NAMESPACE_FDB)
esw_attr->split_count = esw_attr->out_count; esw_attr->split_count = esw_attr->out_count;
out:
return 0; return 0;
} }
......
...@@ -24,8 +24,7 @@ struct pedit_headers_action { ...@@ -24,8 +24,7 @@ struct pedit_headers_action {
int int
mlx5e_tc_act_pedit_parse_action(struct mlx5e_priv *priv, mlx5e_tc_act_pedit_parse_action(struct mlx5e_priv *priv,
const struct flow_action_entry *act, int namespace, const struct flow_action_entry *act, int namespace,
struct mlx5e_tc_flow_parse_attr *parse_attr, struct pedit_headers_action *hdrs,
struct mlx5e_tc_flow *flow,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
#endif /* __MLX5_EN_TC_ACT_PEDIT_H__ */ #endif /* __MLX5_EN_TC_ACT_PEDIT_H__ */
...@@ -34,7 +34,8 @@ parse_tc_vlan_action(struct mlx5e_priv *priv, ...@@ -34,7 +34,8 @@ parse_tc_vlan_action(struct mlx5e_priv *priv,
const struct flow_action_entry *act, const struct flow_action_entry *act,
struct mlx5_esw_flow_attr *attr, struct mlx5_esw_flow_attr *attr,
u32 *action, u32 *action,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack,
struct mlx5e_tc_act_parse_state *parse_state)
{ {
u8 vlan_idx = attr->total_vlan; u8 vlan_idx = attr->total_vlan;
...@@ -84,6 +85,16 @@ parse_tc_vlan_action(struct mlx5e_priv *priv, ...@@ -84,6 +85,16 @@ parse_tc_vlan_action(struct mlx5e_priv *priv,
*action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; *action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
} }
break; break;
case FLOW_ACTION_VLAN_POP_ETH:
parse_state->eth_pop = true;
break;
case FLOW_ACTION_VLAN_PUSH_ETH:
if (!flow_flag_test(parse_state->flow, L3_TO_L2_DECAP))
return -EOPNOTSUPP;
parse_state->eth_push = true;
memcpy(attr->eth.h_dest, act->vlan_push_eth.dst, ETH_ALEN);
memcpy(attr->eth.h_source, act->vlan_push_eth.src, ETH_ALEN);
break;
default: default:
NL_SET_ERR_MSG_MOD(extack, "Unexpected action id for VLAN"); NL_SET_ERR_MSG_MOD(extack, "Unexpected action id for VLAN");
return -EINVAL; return -EINVAL;
...@@ -109,7 +120,7 @@ mlx5e_tc_act_vlan_add_push_action(struct mlx5e_priv *priv, ...@@ -109,7 +120,7 @@ mlx5e_tc_act_vlan_add_push_action(struct mlx5e_priv *priv,
}; };
int err; int err;
err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action, extack); err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action, extack, NULL);
if (err) if (err)
return err; return err;
...@@ -139,7 +150,7 @@ mlx5e_tc_act_vlan_add_pop_action(struct mlx5e_priv *priv, ...@@ -139,7 +150,7 @@ mlx5e_tc_act_vlan_add_pop_action(struct mlx5e_priv *priv,
priv->netdev->lower_level; priv->netdev->lower_level;
while (nest_level--) { while (nest_level--) {
err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action, err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action,
extack); extack, NULL);
if (err) if (err)
return err; return err;
} }
...@@ -174,7 +185,7 @@ tc_act_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state, ...@@ -174,7 +185,7 @@ tc_act_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state,
parse_state->extack); parse_state->extack);
} else { } else {
err = parse_tc_vlan_action(priv, act, esw_attr, &attr->action, err = parse_tc_vlan_action(priv, act, esw_attr, &attr->action,
parse_state->extack); parse_state->extack, parse_state);
} }
if (err) if (err)
......
...@@ -43,8 +43,8 @@ mlx5e_tc_act_vlan_add_rewrite_action(struct mlx5e_priv *priv, int namespace, ...@@ -43,8 +43,8 @@ mlx5e_tc_act_vlan_add_rewrite_action(struct mlx5e_priv *priv, int namespace,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
err = mlx5e_tc_act_pedit_parse_action(priv, &pedit_act, namespace, parse_attr, err = mlx5e_tc_act_pedit_parse_action(priv, &pedit_act, namespace, parse_attr->hdrs,
NULL, extack); extack);
*action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; *action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
return err; return err;
......
...@@ -41,7 +41,6 @@ struct mlx5e_tc_flow_parse_attr { ...@@ -41,7 +41,6 @@ struct mlx5e_tc_flow_parse_attr {
struct pedit_headers_action hdrs[__PEDIT_CMD_MAX]; struct pedit_headers_action hdrs[__PEDIT_CMD_MAX];
struct mlx5e_tc_mod_hdr_acts mod_hdr_acts; struct mlx5e_tc_mod_hdr_acts mod_hdr_acts;
int mirred_ifindex[MLX5_MAX_FLOW_FWD_VPORTS]; int mirred_ifindex[MLX5_MAX_FLOW_FWD_VPORTS];
struct ethhdr eth;
struct mlx5e_tc_act_parse_state parse_state; struct mlx5e_tc_act_parse_state parse_state;
}; };
......
...@@ -906,20 +906,18 @@ int mlx5e_attach_decap(struct mlx5e_priv *priv, ...@@ -906,20 +906,18 @@ int mlx5e_attach_decap(struct mlx5e_priv *priv,
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr; struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr;
struct mlx5_pkt_reformat_params reformat_params; struct mlx5_pkt_reformat_params reformat_params;
struct mlx5e_tc_flow_parse_attr *parse_attr;
struct mlx5e_decap_entry *d; struct mlx5e_decap_entry *d;
struct mlx5e_decap_key key; struct mlx5e_decap_key key;
uintptr_t hash_key; uintptr_t hash_key;
int err = 0; int err = 0;
parse_attr = flow->attr->parse_attr; if (sizeof(attr->eth) > MLX5_CAP_ESW(priv->mdev, max_encap_header_size)) {
if (sizeof(parse_attr->eth) > MLX5_CAP_ESW(priv->mdev, max_encap_header_size)) {
NL_SET_ERR_MSG_MOD(extack, NL_SET_ERR_MSG_MOD(extack,
"encap header larger than max supported"); "encap header larger than max supported");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
key.key = parse_attr->eth; key.key = attr->eth;
hash_key = hash_decap_info(&key); hash_key = hash_decap_info(&key);
mutex_lock(&esw->offloads.decap_tbl_lock); mutex_lock(&esw->offloads.decap_tbl_lock);
d = mlx5e_decap_get(priv, &key, hash_key); d = mlx5e_decap_get(priv, &key, hash_key);
...@@ -949,8 +947,8 @@ int mlx5e_attach_decap(struct mlx5e_priv *priv, ...@@ -949,8 +947,8 @@ int mlx5e_attach_decap(struct mlx5e_priv *priv,
memset(&reformat_params, 0, sizeof(reformat_params)); memset(&reformat_params, 0, sizeof(reformat_params));
reformat_params.type = MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2; reformat_params.type = MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
reformat_params.size = sizeof(parse_attr->eth); reformat_params.size = sizeof(attr->eth);
reformat_params.data = &parse_attr->eth; reformat_params.data = &attr->eth;
d->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, d->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
&reformat_params, &reformat_params,
MLX5_FLOW_NAMESPACE_FDB); MLX5_FLOW_NAMESPACE_FDB);
......
...@@ -474,6 +474,7 @@ struct mlx5_esw_flow_attr { ...@@ -474,6 +474,7 @@ struct mlx5_esw_flow_attr {
int src_port_rewrite_act_id; int src_port_rewrite_act_id;
} dests[MLX5_MAX_FLOW_FWD_VPORTS]; } dests[MLX5_MAX_FLOW_FWD_VPORTS];
struct mlx5_rx_tun_attr *rx_tun_attr; struct mlx5_rx_tun_attr *rx_tun_attr;
struct ethhdr eth;
struct mlx5_pkt_reformat *decap_pkt_reformat; struct mlx5_pkt_reformat *decap_pkt_reformat;
}; };
......
...@@ -150,6 +150,8 @@ enum flow_action_id { ...@@ -150,6 +150,8 @@ enum flow_action_id {
FLOW_ACTION_PPPOE_PUSH, FLOW_ACTION_PPPOE_PUSH,
FLOW_ACTION_JUMP, FLOW_ACTION_JUMP,
FLOW_ACTION_PIPE, FLOW_ACTION_PIPE,
FLOW_ACTION_VLAN_PUSH_ETH,
FLOW_ACTION_VLAN_POP_ETH,
NUM_FLOW_ACTIONS, NUM_FLOW_ACTIONS,
}; };
...@@ -211,6 +213,10 @@ struct flow_action_entry { ...@@ -211,6 +213,10 @@ struct flow_action_entry {
__be16 proto; __be16 proto;
u8 prio; u8 prio;
} vlan; } vlan;
struct { /* FLOW_ACTION_VLAN_PUSH_ETH */
unsigned char dst[ETH_ALEN];
unsigned char src[ETH_ALEN];
} vlan_push_eth;
struct { /* FLOW_ACTION_MANGLE */ struct { /* FLOW_ACTION_MANGLE */
/* FLOW_ACTION_ADD */ /* FLOW_ACTION_ADD */
enum flow_action_mangle_base htype; enum flow_action_mangle_base htype;
......
...@@ -78,4 +78,14 @@ static inline u8 tcf_vlan_push_prio(const struct tc_action *a) ...@@ -78,4 +78,14 @@ static inline u8 tcf_vlan_push_prio(const struct tc_action *a)
return tcfv_push_prio; return tcfv_push_prio;
} }
static inline void tcf_vlan_push_eth(unsigned char *src, unsigned char *dest,
const struct tc_action *a)
{
rcu_read_lock();
memcpy(dest, rcu_dereference(to_vlan(a)->vlan_p)->tcfv_push_dst, ETH_ALEN);
memcpy(dest, rcu_dereference(to_vlan(a)->vlan_p)->tcfv_push_src, ETH_ALEN);
rcu_read_unlock();
}
#endif /* __NET_TC_VLAN_H */ #endif /* __NET_TC_VLAN_H */
...@@ -390,6 +390,13 @@ static int tcf_vlan_offload_act_setup(struct tc_action *act, void *entry_data, ...@@ -390,6 +390,13 @@ static int tcf_vlan_offload_act_setup(struct tc_action *act, void *entry_data,
entry->vlan.proto = tcf_vlan_push_proto(act); entry->vlan.proto = tcf_vlan_push_proto(act);
entry->vlan.prio = tcf_vlan_push_prio(act); entry->vlan.prio = tcf_vlan_push_prio(act);
break; break;
case TCA_VLAN_ACT_POP_ETH:
entry->id = FLOW_ACTION_VLAN_POP_ETH;
break;
case TCA_VLAN_ACT_PUSH_ETH:
entry->id = FLOW_ACTION_VLAN_PUSH_ETH;
tcf_vlan_push_eth(entry->vlan_push_eth.src, entry->vlan_push_eth.dst, act);
break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -407,6 +414,12 @@ static int tcf_vlan_offload_act_setup(struct tc_action *act, void *entry_data, ...@@ -407,6 +414,12 @@ static int tcf_vlan_offload_act_setup(struct tc_action *act, void *entry_data,
case TCA_VLAN_ACT_MODIFY: case TCA_VLAN_ACT_MODIFY:
fl_action->id = FLOW_ACTION_VLAN_MANGLE; fl_action->id = FLOW_ACTION_VLAN_MANGLE;
break; break;
case TCA_VLAN_ACT_POP_ETH:
fl_action->id = FLOW_ACTION_VLAN_POP_ETH;
break;
case TCA_VLAN_ACT_PUSH_ETH:
fl_action->id = FLOW_ACTION_VLAN_PUSH_ETH;
break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
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