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 
9 struct pedit_headers_action;
10 
11 int
12 mlx5e_tc_act_vlan_add_rewrite_action(struct mlx5e_priv *priv, int namespace,
13 				     const struct flow_action_entry *act,
14 				     struct mlx5e_tc_flow_parse_attr *parse_attr,
15 				     struct pedit_headers_action *hdrs,
16 				     u32 *action, struct netlink_ext_ack *extack)
17 {
18 	u16 mask16 = VLAN_VID_MASK;
19 	u16 val16 = act->vlan.vid & VLAN_VID_MASK;
20 	const struct flow_action_entry pedit_act = {
21 		.id = FLOW_ACTION_MANGLE,
22 		.mangle.htype = FLOW_ACT_MANGLE_HDR_TYPE_ETH,
23 		.mangle.offset = offsetof(struct vlan_ethhdr, h_vlan_TCI),
24 		.mangle.mask = ~(u32)be16_to_cpu(*(__be16 *)&mask16),
25 		.mangle.val = (u32)be16_to_cpu(*(__be16 *)&val16),
26 	};
27 	u8 match_prio_mask, match_prio_val;
28 	void *headers_c, *headers_v;
29 	int err;
30 
31 	headers_c = mlx5e_get_match_headers_criteria(*action, &parse_attr->spec);
32 	headers_v = mlx5e_get_match_headers_value(*action, &parse_attr->spec);
33 
34 	if (!(MLX5_GET(fte_match_set_lyr_2_4, headers_c, cvlan_tag) &&
35 	      MLX5_GET(fte_match_set_lyr_2_4, headers_v, cvlan_tag))) {
36 		NL_SET_ERR_MSG_MOD(extack, "VLAN rewrite action must have VLAN protocol match");
37 		return -EOPNOTSUPP;
38 	}
39 
40 	match_prio_mask = MLX5_GET(fte_match_set_lyr_2_4, headers_c, first_prio);
41 	match_prio_val = MLX5_GET(fte_match_set_lyr_2_4, headers_v, first_prio);
42 	if (act->vlan.prio != (match_prio_val & match_prio_mask)) {
43 		NL_SET_ERR_MSG_MOD(extack, "Changing VLAN prio is not supported");
44 		return -EOPNOTSUPP;
45 	}
46 
47 	err = mlx5e_tc_act_pedit_parse_action(priv, &pedit_act, namespace, parse_attr, hdrs,
48 					      NULL, extack);
49 	*action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
50 
51 	return err;
52 }
53 
54 static bool
55 tc_act_can_offload_vlan_mangle(struct mlx5e_tc_act_parse_state *parse_state,
56 			       const struct flow_action_entry *act,
57 			       int act_index)
58 {
59 	return true;
60 }
61 
62 static int
63 tc_act_parse_vlan_mangle(struct mlx5e_tc_act_parse_state *parse_state,
64 			 const struct flow_action_entry *act,
65 			 struct mlx5e_priv *priv,
66 			 struct mlx5_flow_attr *attr)
67 {
68 	enum mlx5_flow_namespace_type ns_type;
69 	int err;
70 
71 	ns_type = mlx5e_get_flow_namespace(parse_state->flow);
72 	err = mlx5e_tc_act_vlan_add_rewrite_action(priv, ns_type, act,
73 						   attr->parse_attr, parse_state->hdrs,
74 						   &attr->action, parse_state->extack);
75 	if (err)
76 		return err;
77 
78 	if (ns_type == MLX5_FLOW_NAMESPACE_FDB)
79 		attr->esw_attr->split_count = attr->esw_attr->out_count;
80 
81 	return 0;
82 }
83 
84 struct mlx5e_tc_act mlx5e_tc_act_vlan_mangle = {
85 	.can_offload = tc_act_can_offload_vlan_mangle,
86 	.parse_action = tc_act_parse_vlan_mangle,
87 };
88