Merge branch 'drm-next' of git://anongit.freedesktop.org/drm/drm into msm-next-lumag...
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / en / tc / act / vlan_mangle.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
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                                      u32 *action, struct netlink_ext_ack *extack)
16 {
17         u16 mask16 = VLAN_VID_MASK;
18         u16 val16 = act->vlan.vid & VLAN_VID_MASK;
19         const struct flow_action_entry pedit_act = {
20                 .id = FLOW_ACTION_MANGLE,
21                 .mangle.htype = FLOW_ACT_MANGLE_HDR_TYPE_ETH,
22                 .mangle.offset = offsetof(struct vlan_ethhdr, h_vlan_TCI),
23                 .mangle.mask = ~(u32)be16_to_cpu(*(__be16 *)&mask16),
24                 .mangle.val = (u32)be16_to_cpu(*(__be16 *)&val16),
25         };
26         u8 match_prio_mask, match_prio_val;
27         void *headers_c, *headers_v;
28         int err;
29
30         headers_c = mlx5e_get_match_headers_criteria(*action, &parse_attr->spec);
31         headers_v = mlx5e_get_match_headers_value(*action, &parse_attr->spec);
32
33         if (!(MLX5_GET(fte_match_set_lyr_2_4, headers_c, cvlan_tag) &&
34               MLX5_GET(fte_match_set_lyr_2_4, headers_v, cvlan_tag))) {
35                 NL_SET_ERR_MSG_MOD(extack, "VLAN rewrite action must have VLAN protocol match");
36                 return -EOPNOTSUPP;
37         }
38
39         match_prio_mask = MLX5_GET(fte_match_set_lyr_2_4, headers_c, first_prio);
40         match_prio_val = MLX5_GET(fte_match_set_lyr_2_4, headers_v, first_prio);
41         if (act->vlan.prio != (match_prio_val & match_prio_mask)) {
42                 NL_SET_ERR_MSG_MOD(extack, "Changing VLAN prio is not supported");
43                 return -EOPNOTSUPP;
44         }
45
46         err = mlx5e_tc_act_pedit_parse_action(priv, &pedit_act, namespace, parse_attr->hdrs,
47                                               extack);
48         *action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
49
50         return err;
51 }
52
53 static int
54 tc_act_parse_vlan_mangle(struct mlx5e_tc_act_parse_state *parse_state,
55                          const struct flow_action_entry *act,
56                          struct mlx5e_priv *priv,
57                          struct mlx5_flow_attr *attr)
58 {
59         enum mlx5_flow_namespace_type ns_type;
60         int err;
61
62         ns_type = mlx5e_get_flow_namespace(parse_state->flow);
63         err = mlx5e_tc_act_vlan_add_rewrite_action(priv, ns_type, act, attr->parse_attr,
64                                                    &attr->action, parse_state->extack);
65         if (err)
66                 return err;
67
68         if (ns_type == MLX5_FLOW_NAMESPACE_FDB)
69                 attr->esw_attr->split_count = attr->esw_attr->out_count;
70
71         return 0;
72 }
73
74 struct mlx5e_tc_act mlx5e_tc_act_vlan_mangle = {
75         .parse_action = tc_act_parse_vlan_mangle,
76 };