Commit | Line | Data |
---|---|---|
afb736e9 AV |
1 | /* |
2 | * Copyright (c) 2015, Mellanox Technologies. All rights reserved. | |
3 | * | |
4 | * This software is available to you under a choice of one of two | |
5 | * licenses. You may choose to be licensed under the terms of the GNU | |
6 | * General Public License (GPL) Version 2, available from the file | |
7 | * COPYING in the main directory of this source tree, or the | |
8 | * OpenIB.org BSD license below: | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or | |
11 | * without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistributions of source code must retain the above | |
15 | * copyright notice, this list of conditions and the following | |
16 | * disclaimer. | |
17 | * | |
18 | * - Redistributions in binary form must reproduce the above | |
19 | * copyright notice, this list of conditions and the following | |
20 | * disclaimer in the documentation and/or other materials | |
21 | * provided with the distribution. | |
22 | * | |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
30 | * SOFTWARE. | |
31 | */ | |
32 | ||
33 | #include <linux/list.h> | |
34 | #include <linux/ip.h> | |
35 | #include <linux/ipv6.h> | |
36 | #include <linux/tcp.h> | |
86d722ad | 37 | #include <linux/mlx5/fs.h> |
afb736e9 AV |
38 | #include "en.h" |
39 | ||
33cfaaa8 MG |
40 | static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, |
41 | struct mlx5e_l2_rule *ai, int type); | |
42 | static void mlx5e_del_l2_flow_rule(struct mlx5e_priv *priv, | |
43 | struct mlx5e_l2_rule *ai); | |
44 | ||
afb736e9 AV |
45 | enum { |
46 | MLX5E_FULLMATCH = 0, | |
47 | MLX5E_ALLMULTI = 1, | |
48 | MLX5E_PROMISC = 2, | |
49 | }; | |
50 | ||
51 | enum { | |
52 | MLX5E_UC = 0, | |
53 | MLX5E_MC_IPV4 = 1, | |
54 | MLX5E_MC_IPV6 = 2, | |
55 | MLX5E_MC_OTHER = 3, | |
56 | }; | |
57 | ||
58 | enum { | |
59 | MLX5E_ACTION_NONE = 0, | |
60 | MLX5E_ACTION_ADD = 1, | |
61 | MLX5E_ACTION_DEL = 2, | |
62 | }; | |
63 | ||
33cfaaa8 | 64 | struct mlx5e_l2_hash_node { |
afb736e9 AV |
65 | struct hlist_node hlist; |
66 | u8 action; | |
33cfaaa8 | 67 | struct mlx5e_l2_rule ai; |
afb736e9 AV |
68 | }; |
69 | ||
33cfaaa8 | 70 | static inline int mlx5e_hash_l2(u8 *addr) |
afb736e9 AV |
71 | { |
72 | return addr[5]; | |
73 | } | |
74 | ||
33cfaaa8 | 75 | static void mlx5e_add_l2_to_hash(struct hlist_head *hash, u8 *addr) |
afb736e9 | 76 | { |
33cfaaa8 MG |
77 | struct mlx5e_l2_hash_node *hn; |
78 | int ix = mlx5e_hash_l2(addr); | |
afb736e9 AV |
79 | int found = 0; |
80 | ||
81 | hlist_for_each_entry(hn, &hash[ix], hlist) | |
82 | if (ether_addr_equal_64bits(hn->ai.addr, addr)) { | |
83 | found = 1; | |
84 | break; | |
85 | } | |
86 | ||
87 | if (found) { | |
88 | hn->action = MLX5E_ACTION_NONE; | |
89 | return; | |
90 | } | |
91 | ||
92 | hn = kzalloc(sizeof(*hn), GFP_ATOMIC); | |
93 | if (!hn) | |
94 | return; | |
95 | ||
96 | ether_addr_copy(hn->ai.addr, addr); | |
97 | hn->action = MLX5E_ACTION_ADD; | |
98 | ||
99 | hlist_add_head(&hn->hlist, &hash[ix]); | |
100 | } | |
101 | ||
33cfaaa8 | 102 | static void mlx5e_del_l2_from_hash(struct mlx5e_l2_hash_node *hn) |
afb736e9 AV |
103 | { |
104 | hlist_del(&hn->hlist); | |
105 | kfree(hn); | |
106 | } | |
107 | ||
aad9e6e4 SM |
108 | static int mlx5e_vport_context_update_vlans(struct mlx5e_priv *priv) |
109 | { | |
110 | struct net_device *ndev = priv->netdev; | |
111 | int max_list_size; | |
112 | int list_size; | |
113 | u16 *vlans; | |
114 | int vlan; | |
115 | int err; | |
116 | int i; | |
117 | ||
118 | list_size = 0; | |
acff797c | 119 | for_each_set_bit(vlan, priv->fs.vlan.active_vlans, VLAN_N_VID) |
aad9e6e4 SM |
120 | list_size++; |
121 | ||
122 | max_list_size = 1 << MLX5_CAP_GEN(priv->mdev, log_max_vlan_list); | |
123 | ||
124 | if (list_size > max_list_size) { | |
125 | netdev_warn(ndev, | |
126 | "netdev vlans list size (%d) > (%d) max vport list size, some vlans will be dropped\n", | |
127 | list_size, max_list_size); | |
128 | list_size = max_list_size; | |
129 | } | |
130 | ||
131 | vlans = kcalloc(list_size, sizeof(*vlans), GFP_KERNEL); | |
132 | if (!vlans) | |
133 | return -ENOMEM; | |
134 | ||
135 | i = 0; | |
acff797c | 136 | for_each_set_bit(vlan, priv->fs.vlan.active_vlans, VLAN_N_VID) { |
aad9e6e4 SM |
137 | if (i >= list_size) |
138 | break; | |
139 | vlans[i++] = vlan; | |
140 | } | |
141 | ||
142 | err = mlx5_modify_nic_vport_vlans(priv->mdev, vlans, list_size); | |
143 | if (err) | |
144 | netdev_err(ndev, "Failed to modify vport vlans list err(%d)\n", | |
145 | err); | |
146 | ||
147 | kfree(vlans); | |
148 | return err; | |
149 | } | |
150 | ||
afb736e9 AV |
151 | enum mlx5e_vlan_rule_type { |
152 | MLX5E_VLAN_RULE_TYPE_UNTAGGED, | |
153 | MLX5E_VLAN_RULE_TYPE_ANY_VID, | |
154 | MLX5E_VLAN_RULE_TYPE_MATCH_VID, | |
155 | }; | |
156 | ||
86d722ad MG |
157 | static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, |
158 | enum mlx5e_vlan_rule_type rule_type, | |
c5bb1730 | 159 | u16 vid, struct mlx5_flow_spec *spec) |
afb736e9 | 160 | { |
acff797c | 161 | struct mlx5_flow_table *ft = priv->fs.vlan.ft.t; |
86d722ad | 162 | struct mlx5_flow_destination dest; |
74491de9 | 163 | struct mlx5_flow_handle **rule_p; |
86d722ad | 164 | int err = 0; |
afb736e9 | 165 | |
86d722ad | 166 | dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; |
33cfaaa8 | 167 | dest.ft = priv->fs.l2.ft.t; |
afb736e9 | 168 | |
c5bb1730 MG |
169 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
170 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.vlan_tag); | |
afb736e9 AV |
171 | |
172 | switch (rule_type) { | |
173 | case MLX5E_VLAN_RULE_TYPE_UNTAGGED: | |
acff797c | 174 | rule_p = &priv->fs.vlan.untagged_rule; |
afb736e9 AV |
175 | break; |
176 | case MLX5E_VLAN_RULE_TYPE_ANY_VID: | |
acff797c | 177 | rule_p = &priv->fs.vlan.any_vlan_rule; |
c5bb1730 | 178 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.vlan_tag, 1); |
afb736e9 AV |
179 | break; |
180 | default: /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */ | |
acff797c | 181 | rule_p = &priv->fs.vlan.active_vlans_rule[vid]; |
c5bb1730 MG |
182 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.vlan_tag, 1); |
183 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, | |
184 | outer_headers.first_vid); | |
185 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, | |
186 | vid); | |
afb736e9 AV |
187 | break; |
188 | } | |
189 | ||
74491de9 MB |
190 | *rule_p = mlx5_add_flow_rules(ft, spec, |
191 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, | |
192 | MLX5_FS_DEFAULT_FLOW_TAG, | |
193 | &dest, 1); | |
86d722ad MG |
194 | |
195 | if (IS_ERR(*rule_p)) { | |
196 | err = PTR_ERR(*rule_p); | |
197 | *rule_p = NULL; | |
198 | netdev_err(priv->netdev, "%s: add rule failed\n", __func__); | |
199 | } | |
200 | ||
201 | return err; | |
202 | } | |
203 | ||
204 | static int mlx5e_add_vlan_rule(struct mlx5e_priv *priv, | |
205 | enum mlx5e_vlan_rule_type rule_type, u16 vid) | |
206 | { | |
c5bb1730 | 207 | struct mlx5_flow_spec *spec; |
86d722ad MG |
208 | int err = 0; |
209 | ||
c5bb1730 MG |
210 | spec = mlx5_vzalloc(sizeof(*spec)); |
211 | if (!spec) { | |
86d722ad | 212 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); |
c5bb1730 | 213 | return -ENOMEM; |
86d722ad MG |
214 | } |
215 | ||
216 | if (rule_type == MLX5E_VLAN_RULE_TYPE_MATCH_VID) | |
217 | mlx5e_vport_context_update_vlans(priv); | |
218 | ||
c5bb1730 | 219 | err = __mlx5e_add_vlan_rule(priv, rule_type, vid, spec); |
afb736e9 | 220 | |
c5bb1730 | 221 | kvfree(spec); |
86d722ad | 222 | |
afb736e9 AV |
223 | return err; |
224 | } | |
225 | ||
226 | static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv, | |
227 | enum mlx5e_vlan_rule_type rule_type, u16 vid) | |
228 | { | |
229 | switch (rule_type) { | |
230 | case MLX5E_VLAN_RULE_TYPE_UNTAGGED: | |
acff797c | 231 | if (priv->fs.vlan.untagged_rule) { |
74491de9 | 232 | mlx5_del_flow_rules(priv->fs.vlan.untagged_rule); |
acff797c | 233 | priv->fs.vlan.untagged_rule = NULL; |
86d722ad | 234 | } |
afb736e9 AV |
235 | break; |
236 | case MLX5E_VLAN_RULE_TYPE_ANY_VID: | |
acff797c | 237 | if (priv->fs.vlan.any_vlan_rule) { |
74491de9 | 238 | mlx5_del_flow_rules(priv->fs.vlan.any_vlan_rule); |
acff797c | 239 | priv->fs.vlan.any_vlan_rule = NULL; |
86d722ad | 240 | } |
afb736e9 AV |
241 | break; |
242 | case MLX5E_VLAN_RULE_TYPE_MATCH_VID: | |
86d722ad | 243 | mlx5e_vport_context_update_vlans(priv); |
acff797c | 244 | if (priv->fs.vlan.active_vlans_rule[vid]) { |
74491de9 | 245 | mlx5_del_flow_rules(priv->fs.vlan.active_vlans_rule[vid]); |
acff797c | 246 | priv->fs.vlan.active_vlans_rule[vid] = NULL; |
86d722ad | 247 | } |
aad9e6e4 | 248 | mlx5e_vport_context_update_vlans(priv); |
afb736e9 AV |
249 | break; |
250 | } | |
251 | } | |
252 | ||
253 | void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv) | |
254 | { | |
acff797c | 255 | if (!priv->fs.vlan.filter_disabled) |
9b37b07f | 256 | return; |
afb736e9 | 257 | |
acff797c | 258 | priv->fs.vlan.filter_disabled = false; |
c0754343 AS |
259 | if (priv->netdev->flags & IFF_PROMISC) |
260 | return; | |
9b37b07f | 261 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); |
afb736e9 AV |
262 | } |
263 | ||
264 | void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv) | |
265 | { | |
acff797c | 266 | if (priv->fs.vlan.filter_disabled) |
9b37b07f | 267 | return; |
afb736e9 | 268 | |
acff797c | 269 | priv->fs.vlan.filter_disabled = true; |
c0754343 AS |
270 | if (priv->netdev->flags & IFF_PROMISC) |
271 | return; | |
9b37b07f | 272 | mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); |
afb736e9 AV |
273 | } |
274 | ||
275 | int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, | |
276 | u16 vid) | |
277 | { | |
278 | struct mlx5e_priv *priv = netdev_priv(dev); | |
afb736e9 | 279 | |
acff797c | 280 | set_bit(vid, priv->fs.vlan.active_vlans); |
aad9e6e4 | 281 | |
9b37b07f | 282 | return mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); |
afb736e9 AV |
283 | } |
284 | ||
285 | int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, | |
286 | u16 vid) | |
287 | { | |
288 | struct mlx5e_priv *priv = netdev_priv(dev); | |
289 | ||
acff797c | 290 | clear_bit(vid, priv->fs.vlan.active_vlans); |
aad9e6e4 | 291 | |
9b37b07f | 292 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); |
afb736e9 AV |
293 | |
294 | return 0; | |
295 | } | |
296 | ||
9df30601 MHY |
297 | static void mlx5e_add_vlan_rules(struct mlx5e_priv *priv) |
298 | { | |
299 | int i; | |
300 | ||
301 | mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); | |
302 | ||
303 | for_each_set_bit(i, priv->fs.vlan.active_vlans, VLAN_N_VID) { | |
304 | mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, i); | |
305 | } | |
306 | ||
307 | if (priv->fs.vlan.filter_disabled && | |
308 | !(priv->netdev->flags & IFF_PROMISC)) | |
309 | mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); | |
310 | } | |
311 | ||
312 | static void mlx5e_del_vlan_rules(struct mlx5e_priv *priv) | |
313 | { | |
314 | int i; | |
315 | ||
316 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); | |
317 | ||
318 | for_each_set_bit(i, priv->fs.vlan.active_vlans, VLAN_N_VID) { | |
319 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, i); | |
320 | } | |
321 | ||
322 | if (priv->fs.vlan.filter_disabled && | |
323 | !(priv->netdev->flags & IFF_PROMISC)) | |
324 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); | |
325 | } | |
326 | ||
afb736e9 | 327 | #define mlx5e_for_each_hash_node(hn, tmp, hash, i) \ |
33cfaaa8 | 328 | for (i = 0; i < MLX5E_L2_ADDR_HASH_SIZE; i++) \ |
afb736e9 AV |
329 | hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist) |
330 | ||
33cfaaa8 MG |
331 | static void mlx5e_execute_l2_action(struct mlx5e_priv *priv, |
332 | struct mlx5e_l2_hash_node *hn) | |
afb736e9 AV |
333 | { |
334 | switch (hn->action) { | |
335 | case MLX5E_ACTION_ADD: | |
33cfaaa8 | 336 | mlx5e_add_l2_flow_rule(priv, &hn->ai, MLX5E_FULLMATCH); |
afb736e9 AV |
337 | hn->action = MLX5E_ACTION_NONE; |
338 | break; | |
339 | ||
340 | case MLX5E_ACTION_DEL: | |
33cfaaa8 MG |
341 | mlx5e_del_l2_flow_rule(priv, &hn->ai); |
342 | mlx5e_del_l2_from_hash(hn); | |
afb736e9 AV |
343 | break; |
344 | } | |
345 | } | |
346 | ||
347 | static void mlx5e_sync_netdev_addr(struct mlx5e_priv *priv) | |
348 | { | |
349 | struct net_device *netdev = priv->netdev; | |
350 | struct netdev_hw_addr *ha; | |
351 | ||
352 | netif_addr_lock_bh(netdev); | |
353 | ||
33cfaaa8 MG |
354 | mlx5e_add_l2_to_hash(priv->fs.l2.netdev_uc, |
355 | priv->netdev->dev_addr); | |
afb736e9 AV |
356 | |
357 | netdev_for_each_uc_addr(ha, netdev) | |
33cfaaa8 | 358 | mlx5e_add_l2_to_hash(priv->fs.l2.netdev_uc, ha->addr); |
afb736e9 AV |
359 | |
360 | netdev_for_each_mc_addr(ha, netdev) | |
33cfaaa8 | 361 | mlx5e_add_l2_to_hash(priv->fs.l2.netdev_mc, ha->addr); |
afb736e9 AV |
362 | |
363 | netif_addr_unlock_bh(netdev); | |
364 | } | |
365 | ||
5e55da1d SM |
366 | static void mlx5e_fill_addr_array(struct mlx5e_priv *priv, int list_type, |
367 | u8 addr_array[][ETH_ALEN], int size) | |
368 | { | |
369 | bool is_uc = (list_type == MLX5_NVPRT_LIST_TYPE_UC); | |
370 | struct net_device *ndev = priv->netdev; | |
33cfaaa8 | 371 | struct mlx5e_l2_hash_node *hn; |
5e55da1d SM |
372 | struct hlist_head *addr_list; |
373 | struct hlist_node *tmp; | |
374 | int i = 0; | |
375 | int hi; | |
376 | ||
33cfaaa8 | 377 | addr_list = is_uc ? priv->fs.l2.netdev_uc : priv->fs.l2.netdev_mc; |
5e55da1d SM |
378 | |
379 | if (is_uc) /* Make sure our own address is pushed first */ | |
380 | ether_addr_copy(addr_array[i++], ndev->dev_addr); | |
33cfaaa8 | 381 | else if (priv->fs.l2.broadcast_enabled) |
5e55da1d SM |
382 | ether_addr_copy(addr_array[i++], ndev->broadcast); |
383 | ||
384 | mlx5e_for_each_hash_node(hn, tmp, addr_list, hi) { | |
385 | if (ether_addr_equal(ndev->dev_addr, hn->ai.addr)) | |
386 | continue; | |
387 | if (i >= size) | |
388 | break; | |
389 | ether_addr_copy(addr_array[i++], hn->ai.addr); | |
390 | } | |
391 | } | |
392 | ||
393 | static void mlx5e_vport_context_update_addr_list(struct mlx5e_priv *priv, | |
394 | int list_type) | |
395 | { | |
396 | bool is_uc = (list_type == MLX5_NVPRT_LIST_TYPE_UC); | |
33cfaaa8 | 397 | struct mlx5e_l2_hash_node *hn; |
5e55da1d SM |
398 | u8 (*addr_array)[ETH_ALEN] = NULL; |
399 | struct hlist_head *addr_list; | |
400 | struct hlist_node *tmp; | |
401 | int max_size; | |
402 | int size; | |
403 | int err; | |
404 | int hi; | |
405 | ||
33cfaaa8 | 406 | size = is_uc ? 0 : (priv->fs.l2.broadcast_enabled ? 1 : 0); |
5e55da1d SM |
407 | max_size = is_uc ? |
408 | 1 << MLX5_CAP_GEN(priv->mdev, log_max_current_uc_list) : | |
409 | 1 << MLX5_CAP_GEN(priv->mdev, log_max_current_mc_list); | |
410 | ||
33cfaaa8 | 411 | addr_list = is_uc ? priv->fs.l2.netdev_uc : priv->fs.l2.netdev_mc; |
5e55da1d SM |
412 | mlx5e_for_each_hash_node(hn, tmp, addr_list, hi) |
413 | size++; | |
414 | ||
415 | if (size > max_size) { | |
416 | netdev_warn(priv->netdev, | |
417 | "netdev %s list size (%d) > (%d) max vport list size, some addresses will be dropped\n", | |
418 | is_uc ? "UC" : "MC", size, max_size); | |
419 | size = max_size; | |
420 | } | |
421 | ||
422 | if (size) { | |
423 | addr_array = kcalloc(size, ETH_ALEN, GFP_KERNEL); | |
424 | if (!addr_array) { | |
425 | err = -ENOMEM; | |
426 | goto out; | |
427 | } | |
428 | mlx5e_fill_addr_array(priv, list_type, addr_array, size); | |
429 | } | |
430 | ||
431 | err = mlx5_modify_nic_vport_mac_list(priv->mdev, list_type, addr_array, size); | |
432 | out: | |
433 | if (err) | |
434 | netdev_err(priv->netdev, | |
435 | "Failed to modify vport %s list err(%d)\n", | |
436 | is_uc ? "UC" : "MC", err); | |
437 | kfree(addr_array); | |
438 | } | |
439 | ||
440 | static void mlx5e_vport_context_update(struct mlx5e_priv *priv) | |
441 | { | |
33cfaaa8 | 442 | struct mlx5e_l2_table *ea = &priv->fs.l2; |
5e55da1d SM |
443 | |
444 | mlx5e_vport_context_update_addr_list(priv, MLX5_NVPRT_LIST_TYPE_UC); | |
445 | mlx5e_vport_context_update_addr_list(priv, MLX5_NVPRT_LIST_TYPE_MC); | |
446 | mlx5_modify_nic_vport_promisc(priv->mdev, 0, | |
33cfaaa8 MG |
447 | ea->allmulti_enabled, |
448 | ea->promisc_enabled); | |
5e55da1d SM |
449 | } |
450 | ||
afb736e9 AV |
451 | static void mlx5e_apply_netdev_addr(struct mlx5e_priv *priv) |
452 | { | |
33cfaaa8 | 453 | struct mlx5e_l2_hash_node *hn; |
afb736e9 AV |
454 | struct hlist_node *tmp; |
455 | int i; | |
456 | ||
33cfaaa8 MG |
457 | mlx5e_for_each_hash_node(hn, tmp, priv->fs.l2.netdev_uc, i) |
458 | mlx5e_execute_l2_action(priv, hn); | |
afb736e9 | 459 | |
33cfaaa8 MG |
460 | mlx5e_for_each_hash_node(hn, tmp, priv->fs.l2.netdev_mc, i) |
461 | mlx5e_execute_l2_action(priv, hn); | |
afb736e9 AV |
462 | } |
463 | ||
464 | static void mlx5e_handle_netdev_addr(struct mlx5e_priv *priv) | |
465 | { | |
33cfaaa8 | 466 | struct mlx5e_l2_hash_node *hn; |
afb736e9 AV |
467 | struct hlist_node *tmp; |
468 | int i; | |
469 | ||
33cfaaa8 | 470 | mlx5e_for_each_hash_node(hn, tmp, priv->fs.l2.netdev_uc, i) |
afb736e9 | 471 | hn->action = MLX5E_ACTION_DEL; |
33cfaaa8 | 472 | mlx5e_for_each_hash_node(hn, tmp, priv->fs.l2.netdev_mc, i) |
afb736e9 AV |
473 | hn->action = MLX5E_ACTION_DEL; |
474 | ||
9b37b07f | 475 | if (!test_bit(MLX5E_STATE_DESTROYING, &priv->state)) |
afb736e9 AV |
476 | mlx5e_sync_netdev_addr(priv); |
477 | ||
478 | mlx5e_apply_netdev_addr(priv); | |
479 | } | |
480 | ||
9b37b07f | 481 | void mlx5e_set_rx_mode_work(struct work_struct *work) |
afb736e9 | 482 | { |
9b37b07f AS |
483 | struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, |
484 | set_rx_mode_work); | |
485 | ||
33cfaaa8 | 486 | struct mlx5e_l2_table *ea = &priv->fs.l2; |
afb736e9 AV |
487 | struct net_device *ndev = priv->netdev; |
488 | ||
9b37b07f | 489 | bool rx_mode_enable = !test_bit(MLX5E_STATE_DESTROYING, &priv->state); |
afb736e9 AV |
490 | bool promisc_enabled = rx_mode_enable && (ndev->flags & IFF_PROMISC); |
491 | bool allmulti_enabled = rx_mode_enable && (ndev->flags & IFF_ALLMULTI); | |
492 | bool broadcast_enabled = rx_mode_enable; | |
493 | ||
33cfaaa8 MG |
494 | bool enable_promisc = !ea->promisc_enabled && promisc_enabled; |
495 | bool disable_promisc = ea->promisc_enabled && !promisc_enabled; | |
496 | bool enable_allmulti = !ea->allmulti_enabled && allmulti_enabled; | |
497 | bool disable_allmulti = ea->allmulti_enabled && !allmulti_enabled; | |
498 | bool enable_broadcast = !ea->broadcast_enabled && broadcast_enabled; | |
499 | bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled; | |
afb736e9 | 500 | |
c0754343 | 501 | if (enable_promisc) { |
33cfaaa8 | 502 | mlx5e_add_l2_flow_rule(priv, &ea->promisc, MLX5E_PROMISC); |
acff797c | 503 | if (!priv->fs.vlan.filter_disabled) |
c0754343 AS |
504 | mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, |
505 | 0); | |
506 | } | |
afb736e9 | 507 | if (enable_allmulti) |
33cfaaa8 | 508 | mlx5e_add_l2_flow_rule(priv, &ea->allmulti, MLX5E_ALLMULTI); |
afb736e9 | 509 | if (enable_broadcast) |
33cfaaa8 | 510 | mlx5e_add_l2_flow_rule(priv, &ea->broadcast, MLX5E_FULLMATCH); |
afb736e9 AV |
511 | |
512 | mlx5e_handle_netdev_addr(priv); | |
513 | ||
514 | if (disable_broadcast) | |
33cfaaa8 | 515 | mlx5e_del_l2_flow_rule(priv, &ea->broadcast); |
afb736e9 | 516 | if (disable_allmulti) |
33cfaaa8 | 517 | mlx5e_del_l2_flow_rule(priv, &ea->allmulti); |
c0754343 | 518 | if (disable_promisc) { |
acff797c | 519 | if (!priv->fs.vlan.filter_disabled) |
c0754343 AS |
520 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, |
521 | 0); | |
33cfaaa8 | 522 | mlx5e_del_l2_flow_rule(priv, &ea->promisc); |
c0754343 | 523 | } |
afb736e9 | 524 | |
33cfaaa8 MG |
525 | ea->promisc_enabled = promisc_enabled; |
526 | ea->allmulti_enabled = allmulti_enabled; | |
527 | ea->broadcast_enabled = broadcast_enabled; | |
5e55da1d SM |
528 | |
529 | mlx5e_vport_context_update(priv); | |
afb736e9 AV |
530 | } |
531 | ||
86d722ad MG |
532 | static void mlx5e_destroy_groups(struct mlx5e_flow_table *ft) |
533 | { | |
534 | int i; | |
535 | ||
536 | for (i = ft->num_groups - 1; i >= 0; i--) { | |
537 | if (!IS_ERR_OR_NULL(ft->g[i])) | |
538 | mlx5_destroy_flow_group(ft->g[i]); | |
539 | ft->g[i] = NULL; | |
540 | } | |
541 | ft->num_groups = 0; | |
542 | } | |
543 | ||
33cfaaa8 | 544 | void mlx5e_init_l2_addr(struct mlx5e_priv *priv) |
afb736e9 | 545 | { |
33cfaaa8 | 546 | ether_addr_copy(priv->fs.l2.broadcast.addr, priv->netdev->broadcast); |
afb736e9 AV |
547 | } |
548 | ||
1cabe6b0 | 549 | void mlx5e_destroy_flow_table(struct mlx5e_flow_table *ft) |
afb736e9 | 550 | { |
33cfaaa8 MG |
551 | mlx5e_destroy_groups(ft); |
552 | kfree(ft->g); | |
553 | mlx5_destroy_flow_table(ft->t); | |
554 | ft->t = NULL; | |
555 | } | |
556 | ||
557 | static void mlx5e_cleanup_ttc_rules(struct mlx5e_ttc_table *ttc) | |
558 | { | |
559 | int i; | |
560 | ||
561 | for (i = 0; i < MLX5E_NUM_TT; i++) { | |
562 | if (!IS_ERR_OR_NULL(ttc->rules[i])) { | |
74491de9 | 563 | mlx5_del_flow_rules(ttc->rules[i]); |
33cfaaa8 MG |
564 | ttc->rules[i] = NULL; |
565 | } | |
566 | } | |
567 | } | |
568 | ||
569 | static struct { | |
570 | u16 etype; | |
571 | u8 proto; | |
572 | } ttc_rules[] = { | |
573 | [MLX5E_TT_IPV4_TCP] = { | |
574 | .etype = ETH_P_IP, | |
575 | .proto = IPPROTO_TCP, | |
576 | }, | |
577 | [MLX5E_TT_IPV6_TCP] = { | |
578 | .etype = ETH_P_IPV6, | |
579 | .proto = IPPROTO_TCP, | |
580 | }, | |
581 | [MLX5E_TT_IPV4_UDP] = { | |
582 | .etype = ETH_P_IP, | |
583 | .proto = IPPROTO_UDP, | |
584 | }, | |
585 | [MLX5E_TT_IPV6_UDP] = { | |
586 | .etype = ETH_P_IPV6, | |
587 | .proto = IPPROTO_UDP, | |
588 | }, | |
589 | [MLX5E_TT_IPV4_IPSEC_AH] = { | |
590 | .etype = ETH_P_IP, | |
591 | .proto = IPPROTO_AH, | |
592 | }, | |
593 | [MLX5E_TT_IPV6_IPSEC_AH] = { | |
594 | .etype = ETH_P_IPV6, | |
595 | .proto = IPPROTO_AH, | |
596 | }, | |
597 | [MLX5E_TT_IPV4_IPSEC_ESP] = { | |
598 | .etype = ETH_P_IP, | |
599 | .proto = IPPROTO_ESP, | |
600 | }, | |
601 | [MLX5E_TT_IPV6_IPSEC_ESP] = { | |
602 | .etype = ETH_P_IPV6, | |
603 | .proto = IPPROTO_ESP, | |
604 | }, | |
605 | [MLX5E_TT_IPV4] = { | |
606 | .etype = ETH_P_IP, | |
607 | .proto = 0, | |
608 | }, | |
609 | [MLX5E_TT_IPV6] = { | |
610 | .etype = ETH_P_IPV6, | |
611 | .proto = 0, | |
612 | }, | |
613 | [MLX5E_TT_ANY] = { | |
614 | .etype = 0, | |
615 | .proto = 0, | |
616 | }, | |
617 | }; | |
618 | ||
74491de9 MB |
619 | static struct mlx5_flow_handle * |
620 | mlx5e_generate_ttc_rule(struct mlx5e_priv *priv, | |
621 | struct mlx5_flow_table *ft, | |
622 | struct mlx5_flow_destination *dest, | |
623 | u16 etype, | |
624 | u8 proto) | |
33cfaaa8 | 625 | { |
74491de9 | 626 | struct mlx5_flow_handle *rule; |
c5bb1730 | 627 | struct mlx5_flow_spec *spec; |
33cfaaa8 MG |
628 | int err = 0; |
629 | ||
c5bb1730 MG |
630 | spec = mlx5_vzalloc(sizeof(*spec)); |
631 | if (!spec) { | |
33cfaaa8 | 632 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); |
c5bb1730 | 633 | return ERR_PTR(-ENOMEM); |
33cfaaa8 MG |
634 | } |
635 | ||
636 | if (proto) { | |
c5bb1730 MG |
637 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
638 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); | |
639 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, proto); | |
33cfaaa8 MG |
640 | } |
641 | if (etype) { | |
c5bb1730 MG |
642 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
643 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype); | |
644 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, etype); | |
33cfaaa8 MG |
645 | } |
646 | ||
74491de9 MB |
647 | rule = mlx5_add_flow_rules(ft, spec, |
648 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, | |
649 | MLX5_FS_DEFAULT_FLOW_TAG, | |
650 | dest, 1); | |
33cfaaa8 MG |
651 | if (IS_ERR(rule)) { |
652 | err = PTR_ERR(rule); | |
653 | netdev_err(priv->netdev, "%s: add rule failed\n", __func__); | |
654 | } | |
c5bb1730 MG |
655 | |
656 | kvfree(spec); | |
33cfaaa8 MG |
657 | return err ? ERR_PTR(err) : rule; |
658 | } | |
659 | ||
660 | static int mlx5e_generate_ttc_table_rules(struct mlx5e_priv *priv) | |
661 | { | |
662 | struct mlx5_flow_destination dest; | |
663 | struct mlx5e_ttc_table *ttc; | |
74491de9 | 664 | struct mlx5_flow_handle **rules; |
33cfaaa8 MG |
665 | struct mlx5_flow_table *ft; |
666 | int tt; | |
86d722ad | 667 | int err; |
33cfaaa8 MG |
668 | |
669 | ttc = &priv->fs.ttc; | |
670 | ft = ttc->ft.t; | |
671 | rules = ttc->rules; | |
672 | ||
673 | dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; | |
674 | for (tt = 0; tt < MLX5E_NUM_TT; tt++) { | |
675 | if (tt == MLX5E_TT_ANY) | |
676 | dest.tir_num = priv->direct_tir[0].tirn; | |
677 | else | |
724b2aa1 | 678 | dest.tir_num = priv->indir_tir[tt].tirn; |
33cfaaa8 MG |
679 | rules[tt] = mlx5e_generate_ttc_rule(priv, ft, &dest, |
680 | ttc_rules[tt].etype, | |
681 | ttc_rules[tt].proto); | |
682 | if (IS_ERR(rules[tt])) | |
683 | goto del_rules; | |
684 | } | |
685 | ||
686 | return 0; | |
687 | ||
688 | del_rules: | |
689 | err = PTR_ERR(rules[tt]); | |
690 | rules[tt] = NULL; | |
691 | mlx5e_cleanup_ttc_rules(ttc); | |
692 | return err; | |
693 | } | |
694 | ||
695 | #define MLX5E_TTC_NUM_GROUPS 3 | |
696 | #define MLX5E_TTC_GROUP1_SIZE BIT(3) | |
697 | #define MLX5E_TTC_GROUP2_SIZE BIT(1) | |
698 | #define MLX5E_TTC_GROUP3_SIZE BIT(0) | |
699 | #define MLX5E_TTC_TABLE_SIZE (MLX5E_TTC_GROUP1_SIZE +\ | |
700 | MLX5E_TTC_GROUP2_SIZE +\ | |
701 | MLX5E_TTC_GROUP3_SIZE) | |
702 | static int mlx5e_create_ttc_table_groups(struct mlx5e_ttc_table *ttc) | |
703 | { | |
704 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
705 | struct mlx5e_flow_table *ft = &ttc->ft; | |
86d722ad | 706 | int ix = 0; |
33cfaaa8 MG |
707 | u32 *in; |
708 | int err; | |
709 | u8 *mc; | |
86d722ad | 710 | |
33cfaaa8 MG |
711 | ft->g = kcalloc(MLX5E_TTC_NUM_GROUPS, |
712 | sizeof(*ft->g), GFP_KERNEL); | |
713 | if (!ft->g) | |
714 | return -ENOMEM; | |
715 | in = mlx5_vzalloc(inlen); | |
716 | if (!in) { | |
717 | kfree(ft->g); | |
718 | return -ENOMEM; | |
719 | } | |
86d722ad | 720 | |
33cfaaa8 MG |
721 | /* L4 Group */ |
722 | mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
723 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ip_protocol); | |
86d722ad | 724 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype); |
33cfaaa8 | 725 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); |
86d722ad | 726 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 727 | ix += MLX5E_TTC_GROUP1_SIZE; |
86d722ad MG |
728 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
729 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
730 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 731 | goto err; |
86d722ad MG |
732 | ft->num_groups++; |
733 | ||
33cfaaa8 MG |
734 | /* L3 Group */ |
735 | MLX5_SET(fte_match_param, mc, outer_headers.ip_protocol, 0); | |
86d722ad | 736 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 737 | ix += MLX5E_TTC_GROUP2_SIZE; |
86d722ad MG |
738 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
739 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
740 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 741 | goto err; |
86d722ad MG |
742 | ft->num_groups++; |
743 | ||
33cfaaa8 | 744 | /* Any Group */ |
86d722ad | 745 | memset(in, 0, inlen); |
86d722ad | 746 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 747 | ix += MLX5E_TTC_GROUP3_SIZE; |
86d722ad MG |
748 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
749 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
750 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 751 | goto err; |
86d722ad MG |
752 | ft->num_groups++; |
753 | ||
33cfaaa8 MG |
754 | kvfree(in); |
755 | return 0; | |
86d722ad | 756 | |
33cfaaa8 MG |
757 | err: |
758 | err = PTR_ERR(ft->g[ft->num_groups]); | |
759 | ft->g[ft->num_groups] = NULL; | |
760 | kvfree(in); | |
86d722ad | 761 | |
33cfaaa8 MG |
762 | return err; |
763 | } | |
764 | ||
765 | static void mlx5e_destroy_ttc_table(struct mlx5e_priv *priv) | |
766 | { | |
767 | struct mlx5e_ttc_table *ttc = &priv->fs.ttc; | |
768 | ||
769 | mlx5e_cleanup_ttc_rules(ttc); | |
770 | mlx5e_destroy_flow_table(&ttc->ft); | |
771 | } | |
772 | ||
773 | static int mlx5e_create_ttc_table(struct mlx5e_priv *priv) | |
774 | { | |
775 | struct mlx5e_ttc_table *ttc = &priv->fs.ttc; | |
776 | struct mlx5e_flow_table *ft = &ttc->ft; | |
777 | int err; | |
778 | ||
779 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, | |
780 | MLX5E_TTC_TABLE_SIZE, MLX5E_TTC_FT_LEVEL); | |
781 | if (IS_ERR(ft->t)) { | |
782 | err = PTR_ERR(ft->t); | |
783 | ft->t = NULL; | |
784 | return err; | |
785 | } | |
786 | ||
787 | err = mlx5e_create_ttc_table_groups(ttc); | |
788 | if (err) | |
789 | goto err; | |
790 | ||
791 | err = mlx5e_generate_ttc_table_rules(priv); | |
792 | if (err) | |
793 | goto err; | |
794 | ||
795 | return 0; | |
796 | err: | |
797 | mlx5e_destroy_flow_table(ft); | |
798 | return err; | |
799 | } | |
800 | ||
801 | static void mlx5e_del_l2_flow_rule(struct mlx5e_priv *priv, | |
802 | struct mlx5e_l2_rule *ai) | |
803 | { | |
804 | if (!IS_ERR_OR_NULL(ai->rule)) { | |
74491de9 | 805 | mlx5_del_flow_rules(ai->rule); |
33cfaaa8 MG |
806 | ai->rule = NULL; |
807 | } | |
808 | } | |
809 | ||
810 | static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, | |
811 | struct mlx5e_l2_rule *ai, int type) | |
812 | { | |
813 | struct mlx5_flow_table *ft = priv->fs.l2.ft.t; | |
814 | struct mlx5_flow_destination dest; | |
c5bb1730 | 815 | struct mlx5_flow_spec *spec; |
33cfaaa8 MG |
816 | int err = 0; |
817 | u8 *mc_dmac; | |
818 | u8 *mv_dmac; | |
819 | ||
c5bb1730 MG |
820 | spec = mlx5_vzalloc(sizeof(*spec)); |
821 | if (!spec) { | |
33cfaaa8 | 822 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); |
c5bb1730 | 823 | return -ENOMEM; |
33cfaaa8 MG |
824 | } |
825 | ||
c5bb1730 | 826 | mc_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, |
33cfaaa8 | 827 | outer_headers.dmac_47_16); |
c5bb1730 | 828 | mv_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_value, |
33cfaaa8 MG |
829 | outer_headers.dmac_47_16); |
830 | ||
831 | dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; | |
832 | dest.ft = priv->fs.ttc.ft.t; | |
833 | ||
834 | switch (type) { | |
835 | case MLX5E_FULLMATCH: | |
c5bb1730 | 836 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
33cfaaa8 MG |
837 | eth_broadcast_addr(mc_dmac); |
838 | ether_addr_copy(mv_dmac, ai->addr); | |
839 | break; | |
840 | ||
841 | case MLX5E_ALLMULTI: | |
c5bb1730 | 842 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
33cfaaa8 MG |
843 | mc_dmac[0] = 0x01; |
844 | mv_dmac[0] = 0x01; | |
845 | break; | |
846 | ||
847 | case MLX5E_PROMISC: | |
848 | break; | |
849 | } | |
850 | ||
74491de9 MB |
851 | ai->rule = mlx5_add_flow_rules(ft, spec, |
852 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, | |
853 | MLX5_FS_DEFAULT_FLOW_TAG, &dest, 1); | |
33cfaaa8 MG |
854 | if (IS_ERR(ai->rule)) { |
855 | netdev_err(priv->netdev, "%s: add l2 rule(mac:%pM) failed\n", | |
856 | __func__, mv_dmac); | |
857 | err = PTR_ERR(ai->rule); | |
858 | ai->rule = NULL; | |
859 | } | |
860 | ||
c5bb1730 | 861 | kvfree(spec); |
33cfaaa8 MG |
862 | |
863 | return err; | |
864 | } | |
865 | ||
866 | #define MLX5E_NUM_L2_GROUPS 3 | |
867 | #define MLX5E_L2_GROUP1_SIZE BIT(0) | |
868 | #define MLX5E_L2_GROUP2_SIZE BIT(15) | |
869 | #define MLX5E_L2_GROUP3_SIZE BIT(0) | |
870 | #define MLX5E_L2_TABLE_SIZE (MLX5E_L2_GROUP1_SIZE +\ | |
871 | MLX5E_L2_GROUP2_SIZE +\ | |
872 | MLX5E_L2_GROUP3_SIZE) | |
873 | static int mlx5e_create_l2_table_groups(struct mlx5e_l2_table *l2_table) | |
874 | { | |
875 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
876 | struct mlx5e_flow_table *ft = &l2_table->ft; | |
877 | int ix = 0; | |
878 | u8 *mc_dmac; | |
879 | u32 *in; | |
880 | int err; | |
881 | u8 *mc; | |
882 | ||
883 | ft->g = kcalloc(MLX5E_NUM_L2_GROUPS, sizeof(*ft->g), GFP_KERNEL); | |
884 | if (!ft->g) | |
885 | return -ENOMEM; | |
886 | in = mlx5_vzalloc(inlen); | |
887 | if (!in) { | |
888 | kfree(ft->g); | |
889 | return -ENOMEM; | |
890 | } | |
891 | ||
892 | mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
893 | mc_dmac = MLX5_ADDR_OF(fte_match_param, mc, | |
894 | outer_headers.dmac_47_16); | |
895 | /* Flow Group for promiscuous */ | |
86d722ad | 896 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 897 | ix += MLX5E_L2_GROUP1_SIZE; |
86d722ad MG |
898 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
899 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
900 | if (IS_ERR(ft->g[ft->num_groups])) | |
901 | goto err_destroy_groups; | |
902 | ft->num_groups++; | |
903 | ||
33cfaaa8 MG |
904 | /* Flow Group for full match */ |
905 | eth_broadcast_addr(mc_dmac); | |
86d722ad | 906 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); |
86d722ad | 907 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 908 | ix += MLX5E_L2_GROUP2_SIZE; |
86d722ad MG |
909 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
910 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
911 | if (IS_ERR(ft->g[ft->num_groups])) | |
912 | goto err_destroy_groups; | |
913 | ft->num_groups++; | |
914 | ||
33cfaaa8 MG |
915 | /* Flow Group for allmulti */ |
916 | eth_zero_addr(mc_dmac); | |
917 | mc_dmac[0] = 0x01; | |
86d722ad | 918 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 919 | ix += MLX5E_L2_GROUP3_SIZE; |
86d722ad MG |
920 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
921 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
922 | if (IS_ERR(ft->g[ft->num_groups])) | |
923 | goto err_destroy_groups; | |
924 | ft->num_groups++; | |
925 | ||
33cfaaa8 | 926 | kvfree(in); |
86d722ad MG |
927 | return 0; |
928 | ||
929 | err_destroy_groups: | |
930 | err = PTR_ERR(ft->g[ft->num_groups]); | |
931 | ft->g[ft->num_groups] = NULL; | |
932 | mlx5e_destroy_groups(ft); | |
33cfaaa8 | 933 | kvfree(in); |
86d722ad MG |
934 | |
935 | return err; | |
936 | } | |
afb736e9 | 937 | |
33cfaaa8 | 938 | static void mlx5e_destroy_l2_table(struct mlx5e_priv *priv) |
86d722ad | 939 | { |
33cfaaa8 | 940 | mlx5e_destroy_flow_table(&priv->fs.l2.ft); |
86d722ad | 941 | } |
afb736e9 | 942 | |
33cfaaa8 | 943 | static int mlx5e_create_l2_table(struct mlx5e_priv *priv) |
86d722ad | 944 | { |
33cfaaa8 MG |
945 | struct mlx5e_l2_table *l2_table = &priv->fs.l2; |
946 | struct mlx5e_flow_table *ft = &l2_table->ft; | |
86d722ad MG |
947 | int err; |
948 | ||
949 | ft->num_groups = 0; | |
acff797c | 950 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, |
33cfaaa8 | 951 | MLX5E_L2_TABLE_SIZE, MLX5E_L2_FT_LEVEL); |
86d722ad MG |
952 | |
953 | if (IS_ERR(ft->t)) { | |
954 | err = PTR_ERR(ft->t); | |
955 | ft->t = NULL; | |
956 | return err; | |
957 | } | |
86d722ad | 958 | |
33cfaaa8 | 959 | err = mlx5e_create_l2_table_groups(l2_table); |
86d722ad | 960 | if (err) |
33cfaaa8 | 961 | goto err_destroy_flow_table; |
86d722ad | 962 | |
33cfaaa8 | 963 | return 0; |
86d722ad | 964 | |
33cfaaa8 | 965 | err_destroy_flow_table: |
86d722ad MG |
966 | mlx5_destroy_flow_table(ft->t); |
967 | ft->t = NULL; | |
968 | ||
969 | return err; | |
970 | } | |
971 | ||
86d722ad MG |
972 | #define MLX5E_NUM_VLAN_GROUPS 2 |
973 | #define MLX5E_VLAN_GROUP0_SIZE BIT(12) | |
974 | #define MLX5E_VLAN_GROUP1_SIZE BIT(1) | |
975 | #define MLX5E_VLAN_TABLE_SIZE (MLX5E_VLAN_GROUP0_SIZE +\ | |
976 | MLX5E_VLAN_GROUP1_SIZE) | |
977 | ||
acff797c MG |
978 | static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in, |
979 | int inlen) | |
86d722ad MG |
980 | { |
981 | int err; | |
982 | int ix = 0; | |
983 | u8 *mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
984 | ||
985 | memset(in, 0, inlen); | |
986 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); | |
987 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.vlan_tag); | |
988 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.first_vid); | |
989 | MLX5_SET_CFG(in, start_flow_index, ix); | |
990 | ix += MLX5E_VLAN_GROUP0_SIZE; | |
991 | MLX5_SET_CFG(in, end_flow_index, ix - 1); | |
992 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
993 | if (IS_ERR(ft->g[ft->num_groups])) | |
994 | goto err_destroy_groups; | |
995 | ft->num_groups++; | |
996 | ||
997 | memset(in, 0, inlen); | |
998 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); | |
999 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.vlan_tag); | |
1000 | MLX5_SET_CFG(in, start_flow_index, ix); | |
1001 | ix += MLX5E_VLAN_GROUP1_SIZE; | |
1002 | MLX5_SET_CFG(in, end_flow_index, ix - 1); | |
1003 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
1004 | if (IS_ERR(ft->g[ft->num_groups])) | |
1005 | goto err_destroy_groups; | |
1006 | ft->num_groups++; | |
1007 | ||
1008 | return 0; | |
1009 | ||
1010 | err_destroy_groups: | |
1011 | err = PTR_ERR(ft->g[ft->num_groups]); | |
1012 | ft->g[ft->num_groups] = NULL; | |
1013 | mlx5e_destroy_groups(ft); | |
1014 | ||
1015 | return err; | |
1016 | } | |
1017 | ||
acff797c | 1018 | static int mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft) |
afb736e9 | 1019 | { |
86d722ad MG |
1020 | u32 *in; |
1021 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
1022 | int err; | |
afb736e9 | 1023 | |
86d722ad MG |
1024 | in = mlx5_vzalloc(inlen); |
1025 | if (!in) | |
afb736e9 AV |
1026 | return -ENOMEM; |
1027 | ||
acff797c | 1028 | err = __mlx5e_create_vlan_table_groups(ft, in, inlen); |
86d722ad MG |
1029 | |
1030 | kvfree(in); | |
1031 | return err; | |
1032 | } | |
1033 | ||
acff797c | 1034 | static int mlx5e_create_vlan_table(struct mlx5e_priv *priv) |
86d722ad | 1035 | { |
acff797c | 1036 | struct mlx5e_flow_table *ft = &priv->fs.vlan.ft; |
86d722ad MG |
1037 | int err; |
1038 | ||
1039 | ft->num_groups = 0; | |
acff797c MG |
1040 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, |
1041 | MLX5E_VLAN_TABLE_SIZE, MLX5E_VLAN_FT_LEVEL); | |
86d722ad MG |
1042 | |
1043 | if (IS_ERR(ft->t)) { | |
1044 | err = PTR_ERR(ft->t); | |
1045 | ft->t = NULL; | |
1046 | return err; | |
1047 | } | |
1048 | ft->g = kcalloc(MLX5E_NUM_VLAN_GROUPS, sizeof(*ft->g), GFP_KERNEL); | |
1049 | if (!ft->g) { | |
1050 | err = -ENOMEM; | |
acff797c | 1051 | goto err_destroy_vlan_table; |
86d722ad MG |
1052 | } |
1053 | ||
acff797c | 1054 | err = mlx5e_create_vlan_table_groups(ft); |
86d722ad MG |
1055 | if (err) |
1056 | goto err_free_g; | |
1057 | ||
9df30601 | 1058 | mlx5e_add_vlan_rules(priv); |
d63cd286 | 1059 | |
86d722ad MG |
1060 | return 0; |
1061 | ||
1062 | err_free_g: | |
1063 | kfree(ft->g); | |
acff797c | 1064 | err_destroy_vlan_table: |
86d722ad MG |
1065 | mlx5_destroy_flow_table(ft->t); |
1066 | ft->t = NULL; | |
1067 | ||
1068 | return err; | |
afb736e9 AV |
1069 | } |
1070 | ||
acff797c | 1071 | static void mlx5e_destroy_vlan_table(struct mlx5e_priv *priv) |
afb736e9 | 1072 | { |
9df30601 | 1073 | mlx5e_del_vlan_rules(priv); |
acff797c | 1074 | mlx5e_destroy_flow_table(&priv->fs.vlan.ft); |
afb736e9 AV |
1075 | } |
1076 | ||
acff797c | 1077 | int mlx5e_create_flow_steering(struct mlx5e_priv *priv) |
afb736e9 AV |
1078 | { |
1079 | int err; | |
1080 | ||
acff797c | 1081 | priv->fs.ns = mlx5_get_flow_namespace(priv->mdev, |
86d722ad MG |
1082 | MLX5_FLOW_NAMESPACE_KERNEL); |
1083 | ||
acff797c | 1084 | if (!priv->fs.ns) |
86d722ad MG |
1085 | return -EINVAL; |
1086 | ||
1cabe6b0 MG |
1087 | err = mlx5e_arfs_create_tables(priv); |
1088 | if (err) { | |
1089 | netdev_err(priv->netdev, "Failed to create arfs tables, err=%d\n", | |
1090 | err); | |
1091 | priv->netdev->hw_features &= ~NETIF_F_NTUPLE; | |
1092 | } | |
1093 | ||
33cfaaa8 MG |
1094 | err = mlx5e_create_ttc_table(priv); |
1095 | if (err) { | |
1096 | netdev_err(priv->netdev, "Failed to create ttc table, err=%d\n", | |
1097 | err); | |
1cabe6b0 | 1098 | goto err_destroy_arfs_tables; |
33cfaaa8 MG |
1099 | } |
1100 | ||
1101 | err = mlx5e_create_l2_table(priv); | |
1102 | if (err) { | |
1103 | netdev_err(priv->netdev, "Failed to create l2 table, err=%d\n", | |
1104 | err); | |
1105 | goto err_destroy_ttc_table; | |
1106 | } | |
afb736e9 | 1107 | |
acff797c | 1108 | err = mlx5e_create_vlan_table(priv); |
33cfaaa8 MG |
1109 | if (err) { |
1110 | netdev_err(priv->netdev, "Failed to create vlan table, err=%d\n", | |
1111 | err); | |
1112 | goto err_destroy_l2_table; | |
1113 | } | |
9b37b07f | 1114 | |
6dc6071c MG |
1115 | mlx5e_ethtool_init_steering(priv); |
1116 | ||
afb736e9 AV |
1117 | return 0; |
1118 | ||
33cfaaa8 MG |
1119 | err_destroy_l2_table: |
1120 | mlx5e_destroy_l2_table(priv); | |
1121 | err_destroy_ttc_table: | |
1122 | mlx5e_destroy_ttc_table(priv); | |
1cabe6b0 MG |
1123 | err_destroy_arfs_tables: |
1124 | mlx5e_arfs_destroy_tables(priv); | |
afb736e9 AV |
1125 | |
1126 | return err; | |
1127 | } | |
1128 | ||
acff797c | 1129 | void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv) |
afb736e9 | 1130 | { |
acff797c | 1131 | mlx5e_destroy_vlan_table(priv); |
33cfaaa8 MG |
1132 | mlx5e_destroy_l2_table(priv); |
1133 | mlx5e_destroy_ttc_table(priv); | |
1cabe6b0 | 1134 | mlx5e_arfs_destroy_tables(priv); |
6dc6071c | 1135 | mlx5e_ethtool_cleanup_steering(priv); |
afb736e9 | 1136 | } |