File Index
Files and directories
Sign in
FILE

vlan.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/vlan.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  3
  4#include <linux/if_vlan.h>
  5#include "act.h"
  6#include "vlan.h"
  7#include "en/tc_priv.h"
  8
  9static int
 10add_vlan_prio_tag_rewrite_action(struct mlx5e_priv *priv,
 11				 struct mlx5e_tc_flow_parse_attr *parse_attr,
 12				 u32 *action, struct netlink_ext_ack *extack)
 13{
 14	const struct flow_action_entry prio_tag_act = {
 15		.vlan.vid = 0,
 16		.vlan.prio =
 17			MLX5_GET(fte_match_set_lyr_2_4,
 18				 mlx5e_get_match_headers_value(*action,
 19							       &parse_attr->spec),
 20				 first_prio) &
 21			MLX5_GET(fte_match_set_lyr_2_4,
 22				 mlx5e_get_match_headers_criteria(*action,
 23								  &parse_attr->spec),
 24				 first_prio),
 25	};
 26
 27	return mlx5e_tc_act_vlan_add_rewrite_action(priv, MLX5_FLOW_NAMESPACE_FDB,
 28						    &prio_tag_act, parse_attr, action,
 29						    extack);
 30}
 31
 32static int
 33parse_tc_vlan_action(struct mlx5e_priv *priv,
 34		     const struct flow_action_entry *act,
 35		     struct mlx5_esw_flow_attr *attr,
 36		     u32 *action,
 37		     struct netlink_ext_ack *extack,
 38		     struct mlx5e_tc_act_parse_state *parse_state)
 39{
 40	u8 vlan_idx = attr->total_vlan;
 41
 42	if (vlan_idx >= MLX5_FS_VLAN_DEPTH) {
 43		NL_SET_ERR_MSG_MOD(extack, "Total vlans used is greater than supported");
 44		return -EOPNOTSUPP;
 45	}
 46
 47	if (!mlx5_eswitch_vlan_actions_supported(priv->mdev, vlan_idx)) {
 48		NL_SET_ERR_MSG_MOD(extack, "firmware vlan actions is not supported");
 49		return -EOPNOTSUPP;
 50	}
 51
 52	switch (act->id) {
 53	case FLOW_ACTION_VLAN_POP:
 54		if (vlan_idx)
 55			*action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP_2;
 56		else
 57			*action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
 58		break;
 59	case FLOW_ACTION_VLAN_PUSH:
 60		attr->vlan_vid[vlan_idx] = act->vlan.vid;
 61		attr->vlan_prio[vlan_idx] = act->vlan.prio;
 62		attr->vlan_proto[vlan_idx] = act->vlan.proto;
 63		if (!attr->vlan_proto[vlan_idx])
 64			attr->vlan_proto[vlan_idx] = htons(ETH_P_8021Q);
 65
 66		if (vlan_idx)
 67			*action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2;
 68		else
 69			*action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
 70		break;
 71	case FLOW_ACTION_VLAN_POP_ETH:
 72		parse_state->eth_pop = true;
 73		break;
 74	case FLOW_ACTION_VLAN_PUSH_ETH:
 75		if (!flow_flag_test(parse_state->flow, L3_TO_L2_DECAP))
 76			return -EOPNOTSUPP;
 77		parse_state->eth_push = true;
 78		memcpy(attr->eth.h_dest, act->vlan_push_eth.dst, ETH_ALEN);
 79		memcpy(attr->eth.h_source, act->vlan_push_eth.src, ETH_ALEN);
 80		break;
 81	default:
 82		NL_SET_ERR_MSG_MOD(extack, "Unexpected action id for VLAN");
 83		return -EINVAL;
 84	}
 85
 86	attr->total_vlan = vlan_idx + 1;
 87
 88	return 0;
 89}
 90
 91int
 92mlx5e_tc_act_vlan_add_push_action(struct mlx5e_priv *priv,
 93				  struct mlx5_flow_attr *attr,
 94				  struct net_device **out_dev,
 95				  struct netlink_ext_ack *extack)
 96{
 97	do {
 98		struct net_device *vlan_dev = *out_dev;
 99		struct flow_action_entry vlan_act = {
100			.id = FLOW_ACTION_VLAN_PUSH,
101			.vlan.vid = vlan_dev_vlan_id(vlan_dev),
102			.vlan.proto = vlan_dev_vlan_proto(vlan_dev),
103			.vlan.prio = 0,
104		};
105		int err;
106
107		err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr,
108					   &attr->action, extack, NULL);
109		if (err)
110			return err;
111
112		rcu_read_lock();
113		*out_dev = dev_get_by_index_rcu(dev_net(vlan_dev),
114						dev_get_iflink(vlan_dev));
115		rcu_read_unlock();
116		if (!*out_dev)
117			return -ENODEV;
118	} while (is_vlan_dev(*out_dev));
119
120	return 0;
121}
122
123int
124mlx5e_tc_act_vlan_add_pop_action(struct mlx5e_priv *priv,
125				 struct mlx5_flow_attr *attr,
126				 struct netlink_ext_ack *extack)
127{
128	struct flow_action_entry vlan_act = {
129		.id = FLOW_ACTION_VLAN_POP,
130	};
131	int nest_level, err = 0;
132
133	nest_level = attr->parse_attr->filter_dev->lower_level -
134						priv->netdev->lower_level;
135	while (nest_level--) {
136		err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action,
137					   extack, NULL);
138		if (err)
139			return err;
140	}
141
142	return err;
143}
144
145static int
146tc_act_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state,
147		  const struct flow_action_entry *act,
148		  struct mlx5e_priv *priv,
149		  struct mlx5_flow_attr *attr)
150{
151	struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
152	int err;
153
154	if (act->id == FLOW_ACTION_VLAN_PUSH &&
155	    (attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP)) {
156		/* Replace vlan pop+push with vlan modify */
157		attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
158		err = mlx5e_tc_act_vlan_add_rewrite_action(priv, MLX5_FLOW_NAMESPACE_FDB, act,
159							   attr->parse_attr, &attr->action,
160							   parse_state->extack);
161	} else {
162		err = parse_tc_vlan_action(priv, act, esw_attr, &attr->action,
163					   parse_state->extack, parse_state);
164	}
165
166	if (err)
167		return err;
168
169	esw_attr->split_count = esw_attr->out_count;
170	parse_state->if_count = 0;
171
172	return 0;
173}
174
175static int
176tc_act_post_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state,
177		       struct mlx5e_priv *priv,
178		       struct mlx5_flow_attr *attr)
179{
180	struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
181	struct netlink_ext_ack *extack = parse_state->extack;
182	struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
183	int err;
184
185	if (MLX5_CAP_GEN(esw->dev, prio_tag_required) &&
186	    attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) {
187		/* For prio tag mode, replace vlan pop with rewrite vlan prio
188		 * tag rewrite.
189		 */
190		attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
191		err = add_vlan_prio_tag_rewrite_action(priv, parse_attr,
192						       &attr->action, extack);
193		if (err)
194			return err;
195	}
196
197	return 0;
198}
199
200struct mlx5e_tc_act mlx5e_tc_act_vlan = {
201	.parse_action = tc_act_parse_vlan,
202	.post_parse = tc_act_post_parse_vlan,
203};
~/ Read-only file preview.