18ee72638SRoi Dayan // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
28ee72638SRoi Dayan // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
38ee72638SRoi Dayan 
48ee72638SRoi Dayan #include <linux/if_vlan.h>
58ee72638SRoi Dayan #include "act.h"
68ee72638SRoi Dayan #include "vlan.h"
78ee72638SRoi Dayan #include "en/tc_priv.h"
88ee72638SRoi Dayan 
98ee72638SRoi Dayan struct pedit_headers_action;
108ee72638SRoi Dayan 
118ee72638SRoi Dayan int
mlx5e_tc_act_vlan_add_rewrite_action(struct mlx5e_priv * priv,int namespace,const struct flow_action_entry * act,struct mlx5e_tc_flow_parse_attr * parse_attr,u32 * action,struct netlink_ext_ack * extack)128ee72638SRoi Dayan mlx5e_tc_act_vlan_add_rewrite_action(struct mlx5e_priv *priv, int namespace,
138ee72638SRoi Dayan 				     const struct flow_action_entry *act,
148ee72638SRoi Dayan 				     struct mlx5e_tc_flow_parse_attr *parse_attr,
158ee72638SRoi Dayan 				     u32 *action, struct netlink_ext_ack *extack)
168ee72638SRoi Dayan {
178ee72638SRoi Dayan 	u16 mask16 = VLAN_VID_MASK;
188ee72638SRoi Dayan 	u16 val16 = act->vlan.vid & VLAN_VID_MASK;
198ee72638SRoi Dayan 	const struct flow_action_entry pedit_act = {
208ee72638SRoi Dayan 		.id = FLOW_ACTION_MANGLE,
218ee72638SRoi Dayan 		.mangle.htype = FLOW_ACT_MANGLE_HDR_TYPE_ETH,
228ee72638SRoi Dayan 		.mangle.offset = offsetof(struct vlan_ethhdr, h_vlan_TCI),
238ee72638SRoi Dayan 		.mangle.mask = ~(u32)be16_to_cpu(*(__be16 *)&mask16),
248ee72638SRoi Dayan 		.mangle.val = (u32)be16_to_cpu(*(__be16 *)&val16),
258ee72638SRoi Dayan 	};
268ee72638SRoi Dayan 	u8 match_prio_mask, match_prio_val;
278ee72638SRoi Dayan 	void *headers_c, *headers_v;
288ee72638SRoi Dayan 	int err;
298ee72638SRoi Dayan 
308ee72638SRoi Dayan 	headers_c = mlx5e_get_match_headers_criteria(*action, &parse_attr->spec);
318ee72638SRoi Dayan 	headers_v = mlx5e_get_match_headers_value(*action, &parse_attr->spec);
328ee72638SRoi Dayan 
338ee72638SRoi Dayan 	if (!(MLX5_GET(fte_match_set_lyr_2_4, headers_c, cvlan_tag) &&
348ee72638SRoi Dayan 	      MLX5_GET(fte_match_set_lyr_2_4, headers_v, cvlan_tag))) {
358ee72638SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack, "VLAN rewrite action must have VLAN protocol match");
368ee72638SRoi Dayan 		return -EOPNOTSUPP;
378ee72638SRoi Dayan 	}
388ee72638SRoi Dayan 
398ee72638SRoi Dayan 	match_prio_mask = MLX5_GET(fte_match_set_lyr_2_4, headers_c, first_prio);
408ee72638SRoi Dayan 	match_prio_val = MLX5_GET(fte_match_set_lyr_2_4, headers_v, first_prio);
418ee72638SRoi Dayan 	if (act->vlan.prio != (match_prio_val & match_prio_mask)) {
428ee72638SRoi Dayan 		NL_SET_ERR_MSG_MOD(extack, "Changing VLAN prio is not supported");
438ee72638SRoi Dayan 		return -EOPNOTSUPP;
448ee72638SRoi Dayan 	}
458ee72638SRoi Dayan 
46697319b2SMaor Dickman 	err = mlx5e_tc_act_pedit_parse_action(priv, &pedit_act, namespace, parse_attr->hdrs,
47697319b2SMaor Dickman 					      extack);
488ee72638SRoi Dayan 	*action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
498ee72638SRoi Dayan 
508ee72638SRoi Dayan 	return err;
518ee72638SRoi Dayan }
528ee72638SRoi Dayan 
538ee72638SRoi Dayan static int
tc_act_parse_vlan_mangle(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)548ee72638SRoi Dayan tc_act_parse_vlan_mangle(struct mlx5e_tc_act_parse_state *parse_state,
558ee72638SRoi Dayan 			 const struct flow_action_entry *act,
568ee72638SRoi Dayan 			 struct mlx5e_priv *priv,
578ee72638SRoi Dayan 			 struct mlx5_flow_attr *attr)
588ee72638SRoi Dayan {
598ee72638SRoi Dayan 	enum mlx5_flow_namespace_type ns_type;
608ee72638SRoi Dayan 	int err;
618ee72638SRoi Dayan 
628ee72638SRoi Dayan 	ns_type = mlx5e_get_flow_namespace(parse_state->flow);
6309bf9792SRoi Dayan 	err = mlx5e_tc_act_vlan_add_rewrite_action(priv, ns_type, act, attr->parse_attr,
648ee72638SRoi Dayan 						   &attr->action, parse_state->extack);
658ee72638SRoi Dayan 	if (err)
668ee72638SRoi Dayan 		return err;
678ee72638SRoi Dayan 
68*b7558a77SJianbo Liu 	if (ns_type == MLX5_FLOW_NAMESPACE_FDB) {
698ee72638SRoi Dayan 		attr->esw_attr->split_count = attr->esw_attr->out_count;
70*b7558a77SJianbo Liu 		parse_state->if_count = 0;
71*b7558a77SJianbo Liu 	}
728ee72638SRoi Dayan 
738ee72638SRoi Dayan 	return 0;
748ee72638SRoi Dayan }
758ee72638SRoi Dayan 
768ee72638SRoi Dayan struct mlx5e_tc_act mlx5e_tc_act_vlan_mangle = {
778ee72638SRoi Dayan 	.parse_action = tc_act_parse_vlan_mangle,
788ee72638SRoi Dayan };
79