OSDN Git Service

Merge tag 'perf-urgent-2023-09-10' of git://git.kernel.org/pub/scm/linux/kernel/git...
[tomoyo/tomoyo-test1.git] / drivers / net / ethernet / mellanox / mlx5 / core / en / tc / act / vlan.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 static int
10 add_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
32 static int
33 parse_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
91 int
92 mlx5e_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         struct net_device *vlan_dev = *out_dev;
98         struct flow_action_entry vlan_act = {
99                 .id = FLOW_ACTION_VLAN_PUSH,
100                 .vlan.vid = vlan_dev_vlan_id(vlan_dev),
101                 .vlan.proto = vlan_dev_vlan_proto(vlan_dev),
102                 .vlan.prio = 0,
103         };
104         int err;
105
106         err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action, extack, NULL);
107         if (err)
108                 return err;
109
110         rcu_read_lock();
111         *out_dev = dev_get_by_index_rcu(dev_net(vlan_dev), dev_get_iflink(vlan_dev));
112         rcu_read_unlock();
113         if (!*out_dev)
114                 return -ENODEV;
115
116         if (is_vlan_dev(*out_dev))
117                 err = mlx5e_tc_act_vlan_add_push_action(priv, attr, out_dev, extack);
118
119         return err;
120 }
121
122 int
123 mlx5e_tc_act_vlan_add_pop_action(struct mlx5e_priv *priv,
124                                  struct mlx5_flow_attr *attr,
125                                  struct netlink_ext_ack *extack)
126 {
127         struct flow_action_entry vlan_act = {
128                 .id = FLOW_ACTION_VLAN_POP,
129         };
130         int nest_level, err = 0;
131
132         nest_level = attr->parse_attr->filter_dev->lower_level -
133                                                 priv->netdev->lower_level;
134         while (nest_level--) {
135                 err = parse_tc_vlan_action(priv, &vlan_act, attr->esw_attr, &attr->action,
136                                            extack, NULL);
137                 if (err)
138                         return err;
139         }
140
141         return err;
142 }
143
144 static int
145 tc_act_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state,
146                   const struct flow_action_entry *act,
147                   struct mlx5e_priv *priv,
148                   struct mlx5_flow_attr *attr)
149 {
150         struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
151         int err;
152
153         if (act->id == FLOW_ACTION_VLAN_PUSH &&
154             (attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP)) {
155                 /* Replace vlan pop+push with vlan modify */
156                 attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
157                 err = mlx5e_tc_act_vlan_add_rewrite_action(priv, MLX5_FLOW_NAMESPACE_FDB, act,
158                                                            attr->parse_attr, &attr->action,
159                                                            parse_state->extack);
160         } else {
161                 err = parse_tc_vlan_action(priv, act, esw_attr, &attr->action,
162                                            parse_state->extack, parse_state);
163         }
164
165         if (err)
166                 return err;
167
168         esw_attr->split_count = esw_attr->out_count;
169         parse_state->if_count = 0;
170
171         return 0;
172 }
173
174 static int
175 tc_act_post_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state,
176                        struct mlx5e_priv *priv,
177                        struct mlx5_flow_attr *attr)
178 {
179         struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
180         struct netlink_ext_ack *extack = parse_state->extack;
181         struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
182         int err;
183
184         if (MLX5_CAP_GEN(esw->dev, prio_tag_required) &&
185             attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) {
186                 /* For prio tag mode, replace vlan pop with rewrite vlan prio
187                  * tag rewrite.
188                  */
189                 attr->action &= ~MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
190                 err = add_vlan_prio_tag_rewrite_action(priv, parse_attr,
191                                                        &attr->action, extack);
192                 if (err)
193                         return err;
194         }
195
196         return 0;
197 }
198
199 struct mlx5e_tc_act mlx5e_tc_act_vlan = {
200         .parse_action = tc_act_parse_vlan,
201         .post_parse = tc_act_post_parse_vlan,
202 };