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; |
86d722ad MG |
163 | struct mlx5_flow_rule **rule_p; |
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 | ||
c5bb1730 | 190 | *rule_p = mlx5_add_flow_rule(ft, spec, |
86d722ad MG |
191 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, |
192 | MLX5_FS_DEFAULT_FLOW_TAG, | |
193 | &dest); | |
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 MG |
231 | if (priv->fs.vlan.untagged_rule) { |
232 | mlx5_del_flow_rule(priv->fs.vlan.untagged_rule); | |
233 | priv->fs.vlan.untagged_rule = NULL; | |
86d722ad | 234 | } |
afb736e9 AV |
235 | break; |
236 | case MLX5E_VLAN_RULE_TYPE_ANY_VID: | |
acff797c MG |
237 | if (priv->fs.vlan.any_vlan_rule) { |
238 | mlx5_del_flow_rule(priv->fs.vlan.any_vlan_rule); | |
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 MG |
244 | if (priv->fs.vlan.active_vlans_rule[vid]) { |
245 | mlx5_del_flow_rule(priv->fs.vlan.active_vlans_rule[vid]); | |
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])) { | |
563 | mlx5_del_flow_rule(ttc->rules[i]); | |
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 | ||
619 | static struct mlx5_flow_rule *mlx5e_generate_ttc_rule(struct mlx5e_priv *priv, | |
620 | struct mlx5_flow_table *ft, | |
621 | struct mlx5_flow_destination *dest, | |
622 | u16 etype, | |
623 | u8 proto) | |
624 | { | |
625 | struct mlx5_flow_rule *rule; | |
c5bb1730 | 626 | struct mlx5_flow_spec *spec; |
33cfaaa8 MG |
627 | int err = 0; |
628 | ||
c5bb1730 MG |
629 | spec = mlx5_vzalloc(sizeof(*spec)); |
630 | if (!spec) { | |
33cfaaa8 | 631 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); |
c5bb1730 | 632 | return ERR_PTR(-ENOMEM); |
33cfaaa8 MG |
633 | } |
634 | ||
635 | if (proto) { | |
c5bb1730 MG |
636 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
637 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); | |
638 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, proto); | |
33cfaaa8 MG |
639 | } |
640 | if (etype) { | |
c5bb1730 MG |
641 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
642 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype); | |
643 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, etype); | |
33cfaaa8 MG |
644 | } |
645 | ||
c5bb1730 | 646 | rule = mlx5_add_flow_rule(ft, spec, |
33cfaaa8 MG |
647 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, |
648 | MLX5_FS_DEFAULT_FLOW_TAG, | |
649 | dest); | |
650 | if (IS_ERR(rule)) { | |
651 | err = PTR_ERR(rule); | |
652 | netdev_err(priv->netdev, "%s: add rule failed\n", __func__); | |
653 | } | |
c5bb1730 MG |
654 | |
655 | kvfree(spec); | |
33cfaaa8 MG |
656 | return err ? ERR_PTR(err) : rule; |
657 | } | |
658 | ||
659 | static int mlx5e_generate_ttc_table_rules(struct mlx5e_priv *priv) | |
660 | { | |
661 | struct mlx5_flow_destination dest; | |
662 | struct mlx5e_ttc_table *ttc; | |
663 | struct mlx5_flow_rule **rules; | |
664 | struct mlx5_flow_table *ft; | |
665 | int tt; | |
86d722ad | 666 | int err; |
33cfaaa8 MG |
667 | |
668 | ttc = &priv->fs.ttc; | |
669 | ft = ttc->ft.t; | |
670 | rules = ttc->rules; | |
671 | ||
672 | dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; | |
673 | for (tt = 0; tt < MLX5E_NUM_TT; tt++) { | |
674 | if (tt == MLX5E_TT_ANY) | |
675 | dest.tir_num = priv->direct_tir[0].tirn; | |
676 | else | |
724b2aa1 | 677 | dest.tir_num = priv->indir_tir[tt].tirn; |
33cfaaa8 MG |
678 | rules[tt] = mlx5e_generate_ttc_rule(priv, ft, &dest, |
679 | ttc_rules[tt].etype, | |
680 | ttc_rules[tt].proto); | |
681 | if (IS_ERR(rules[tt])) | |
682 | goto del_rules; | |
683 | } | |
684 | ||
685 | return 0; | |
686 | ||
687 | del_rules: | |
688 | err = PTR_ERR(rules[tt]); | |
689 | rules[tt] = NULL; | |
690 | mlx5e_cleanup_ttc_rules(ttc); | |
691 | return err; | |
692 | } | |
693 | ||
694 | #define MLX5E_TTC_NUM_GROUPS 3 | |
695 | #define MLX5E_TTC_GROUP1_SIZE BIT(3) | |
696 | #define MLX5E_TTC_GROUP2_SIZE BIT(1) | |
697 | #define MLX5E_TTC_GROUP3_SIZE BIT(0) | |
698 | #define MLX5E_TTC_TABLE_SIZE (MLX5E_TTC_GROUP1_SIZE +\ | |
699 | MLX5E_TTC_GROUP2_SIZE +\ | |
700 | MLX5E_TTC_GROUP3_SIZE) | |
701 | static int mlx5e_create_ttc_table_groups(struct mlx5e_ttc_table *ttc) | |
702 | { | |
703 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
704 | struct mlx5e_flow_table *ft = &ttc->ft; | |
86d722ad | 705 | int ix = 0; |
33cfaaa8 MG |
706 | u32 *in; |
707 | int err; | |
708 | u8 *mc; | |
86d722ad | 709 | |
33cfaaa8 MG |
710 | ft->g = kcalloc(MLX5E_TTC_NUM_GROUPS, |
711 | sizeof(*ft->g), GFP_KERNEL); | |
712 | if (!ft->g) | |
713 | return -ENOMEM; | |
714 | in = mlx5_vzalloc(inlen); | |
715 | if (!in) { | |
716 | kfree(ft->g); | |
717 | return -ENOMEM; | |
718 | } | |
86d722ad | 719 | |
33cfaaa8 MG |
720 | /* L4 Group */ |
721 | mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
722 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ip_protocol); | |
86d722ad | 723 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype); |
33cfaaa8 | 724 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); |
86d722ad | 725 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 726 | ix += MLX5E_TTC_GROUP1_SIZE; |
86d722ad MG |
727 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
728 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
729 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 730 | goto err; |
86d722ad MG |
731 | ft->num_groups++; |
732 | ||
33cfaaa8 MG |
733 | /* L3 Group */ |
734 | MLX5_SET(fte_match_param, mc, outer_headers.ip_protocol, 0); | |
86d722ad | 735 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 736 | ix += MLX5E_TTC_GROUP2_SIZE; |
86d722ad MG |
737 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
738 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
739 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 740 | goto err; |
86d722ad MG |
741 | ft->num_groups++; |
742 | ||
33cfaaa8 | 743 | /* Any Group */ |
86d722ad | 744 | memset(in, 0, inlen); |
86d722ad | 745 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 746 | ix += MLX5E_TTC_GROUP3_SIZE; |
86d722ad MG |
747 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
748 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
749 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 750 | goto err; |
86d722ad MG |
751 | ft->num_groups++; |
752 | ||
33cfaaa8 MG |
753 | kvfree(in); |
754 | return 0; | |
86d722ad | 755 | |
33cfaaa8 MG |
756 | err: |
757 | err = PTR_ERR(ft->g[ft->num_groups]); | |
758 | ft->g[ft->num_groups] = NULL; | |
759 | kvfree(in); | |
86d722ad | 760 | |
33cfaaa8 MG |
761 | return err; |
762 | } | |
763 | ||
764 | static void mlx5e_destroy_ttc_table(struct mlx5e_priv *priv) | |
765 | { | |
766 | struct mlx5e_ttc_table *ttc = &priv->fs.ttc; | |
767 | ||
768 | mlx5e_cleanup_ttc_rules(ttc); | |
769 | mlx5e_destroy_flow_table(&ttc->ft); | |
770 | } | |
771 | ||
772 | static int mlx5e_create_ttc_table(struct mlx5e_priv *priv) | |
773 | { | |
774 | struct mlx5e_ttc_table *ttc = &priv->fs.ttc; | |
775 | struct mlx5e_flow_table *ft = &ttc->ft; | |
776 | int err; | |
777 | ||
778 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, | |
779 | MLX5E_TTC_TABLE_SIZE, MLX5E_TTC_FT_LEVEL); | |
780 | if (IS_ERR(ft->t)) { | |
781 | err = PTR_ERR(ft->t); | |
782 | ft->t = NULL; | |
783 | return err; | |
784 | } | |
785 | ||
786 | err = mlx5e_create_ttc_table_groups(ttc); | |
787 | if (err) | |
788 | goto err; | |
789 | ||
790 | err = mlx5e_generate_ttc_table_rules(priv); | |
791 | if (err) | |
792 | goto err; | |
793 | ||
794 | return 0; | |
795 | err: | |
796 | mlx5e_destroy_flow_table(ft); | |
797 | return err; | |
798 | } | |
799 | ||
800 | static void mlx5e_del_l2_flow_rule(struct mlx5e_priv *priv, | |
801 | struct mlx5e_l2_rule *ai) | |
802 | { | |
803 | if (!IS_ERR_OR_NULL(ai->rule)) { | |
804 | mlx5_del_flow_rule(ai->rule); | |
805 | ai->rule = NULL; | |
806 | } | |
807 | } | |
808 | ||
809 | static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, | |
810 | struct mlx5e_l2_rule *ai, int type) | |
811 | { | |
812 | struct mlx5_flow_table *ft = priv->fs.l2.ft.t; | |
813 | struct mlx5_flow_destination dest; | |
c5bb1730 | 814 | struct mlx5_flow_spec *spec; |
33cfaaa8 MG |
815 | int err = 0; |
816 | u8 *mc_dmac; | |
817 | u8 *mv_dmac; | |
818 | ||
c5bb1730 MG |
819 | spec = mlx5_vzalloc(sizeof(*spec)); |
820 | if (!spec) { | |
33cfaaa8 | 821 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); |
c5bb1730 | 822 | return -ENOMEM; |
33cfaaa8 MG |
823 | } |
824 | ||
c5bb1730 | 825 | mc_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, |
33cfaaa8 | 826 | outer_headers.dmac_47_16); |
c5bb1730 | 827 | mv_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_value, |
33cfaaa8 MG |
828 | outer_headers.dmac_47_16); |
829 | ||
830 | dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; | |
831 | dest.ft = priv->fs.ttc.ft.t; | |
832 | ||
833 | switch (type) { | |
834 | case MLX5E_FULLMATCH: | |
c5bb1730 | 835 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
33cfaaa8 MG |
836 | eth_broadcast_addr(mc_dmac); |
837 | ether_addr_copy(mv_dmac, ai->addr); | |
838 | break; | |
839 | ||
840 | case MLX5E_ALLMULTI: | |
c5bb1730 | 841 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
33cfaaa8 MG |
842 | mc_dmac[0] = 0x01; |
843 | mv_dmac[0] = 0x01; | |
844 | break; | |
845 | ||
846 | case MLX5E_PROMISC: | |
847 | break; | |
848 | } | |
849 | ||
c5bb1730 | 850 | ai->rule = mlx5_add_flow_rule(ft, spec, |
33cfaaa8 MG |
851 | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, |
852 | MLX5_FS_DEFAULT_FLOW_TAG, &dest); | |
853 | if (IS_ERR(ai->rule)) { | |
854 | netdev_err(priv->netdev, "%s: add l2 rule(mac:%pM) failed\n", | |
855 | __func__, mv_dmac); | |
856 | err = PTR_ERR(ai->rule); | |
857 | ai->rule = NULL; | |
858 | } | |
859 | ||
c5bb1730 | 860 | kvfree(spec); |
33cfaaa8 MG |
861 | |
862 | return err; | |
863 | } | |
864 | ||
865 | #define MLX5E_NUM_L2_GROUPS 3 | |
866 | #define MLX5E_L2_GROUP1_SIZE BIT(0) | |
867 | #define MLX5E_L2_GROUP2_SIZE BIT(15) | |
868 | #define MLX5E_L2_GROUP3_SIZE BIT(0) | |
869 | #define MLX5E_L2_TABLE_SIZE (MLX5E_L2_GROUP1_SIZE +\ | |
870 | MLX5E_L2_GROUP2_SIZE +\ | |
871 | MLX5E_L2_GROUP3_SIZE) | |
872 | static int mlx5e_create_l2_table_groups(struct mlx5e_l2_table *l2_table) | |
873 | { | |
874 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
875 | struct mlx5e_flow_table *ft = &l2_table->ft; | |
876 | int ix = 0; | |
877 | u8 *mc_dmac; | |
878 | u32 *in; | |
879 | int err; | |
880 | u8 *mc; | |
881 | ||
882 | ft->g = kcalloc(MLX5E_NUM_L2_GROUPS, sizeof(*ft->g), GFP_KERNEL); | |
883 | if (!ft->g) | |
884 | return -ENOMEM; | |
885 | in = mlx5_vzalloc(inlen); | |
886 | if (!in) { | |
887 | kfree(ft->g); | |
888 | return -ENOMEM; | |
889 | } | |
890 | ||
891 | mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
892 | mc_dmac = MLX5_ADDR_OF(fte_match_param, mc, | |
893 | outer_headers.dmac_47_16); | |
894 | /* Flow Group for promiscuous */ | |
86d722ad | 895 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 896 | ix += MLX5E_L2_GROUP1_SIZE; |
86d722ad MG |
897 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
898 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
899 | if (IS_ERR(ft->g[ft->num_groups])) | |
900 | goto err_destroy_groups; | |
901 | ft->num_groups++; | |
902 | ||
33cfaaa8 MG |
903 | /* Flow Group for full match */ |
904 | eth_broadcast_addr(mc_dmac); | |
86d722ad | 905 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); |
86d722ad | 906 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 907 | ix += MLX5E_L2_GROUP2_SIZE; |
86d722ad MG |
908 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
909 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
910 | if (IS_ERR(ft->g[ft->num_groups])) | |
911 | goto err_destroy_groups; | |
912 | ft->num_groups++; | |
913 | ||
33cfaaa8 MG |
914 | /* Flow Group for allmulti */ |
915 | eth_zero_addr(mc_dmac); | |
916 | mc_dmac[0] = 0x01; | |
86d722ad | 917 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 918 | ix += MLX5E_L2_GROUP3_SIZE; |
86d722ad MG |
919 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
920 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
921 | if (IS_ERR(ft->g[ft->num_groups])) | |
922 | goto err_destroy_groups; | |
923 | ft->num_groups++; | |
924 | ||
33cfaaa8 | 925 | kvfree(in); |
86d722ad MG |
926 | return 0; |
927 | ||
928 | err_destroy_groups: | |
929 | err = PTR_ERR(ft->g[ft->num_groups]); | |
930 | ft->g[ft->num_groups] = NULL; | |
931 | mlx5e_destroy_groups(ft); | |
33cfaaa8 | 932 | kvfree(in); |
86d722ad MG |
933 | |
934 | return err; | |
935 | } | |
afb736e9 | 936 | |
33cfaaa8 | 937 | static void mlx5e_destroy_l2_table(struct mlx5e_priv *priv) |
86d722ad | 938 | { |
33cfaaa8 | 939 | mlx5e_destroy_flow_table(&priv->fs.l2.ft); |
86d722ad | 940 | } |
afb736e9 | 941 | |
33cfaaa8 | 942 | static int mlx5e_create_l2_table(struct mlx5e_priv *priv) |
86d722ad | 943 | { |
33cfaaa8 MG |
944 | struct mlx5e_l2_table *l2_table = &priv->fs.l2; |
945 | struct mlx5e_flow_table *ft = &l2_table->ft; | |
86d722ad MG |
946 | int err; |
947 | ||
948 | ft->num_groups = 0; | |
acff797c | 949 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, |
33cfaaa8 | 950 | MLX5E_L2_TABLE_SIZE, MLX5E_L2_FT_LEVEL); |
86d722ad MG |
951 | |
952 | if (IS_ERR(ft->t)) { | |
953 | err = PTR_ERR(ft->t); | |
954 | ft->t = NULL; | |
955 | return err; | |
956 | } | |
86d722ad | 957 | |
33cfaaa8 | 958 | err = mlx5e_create_l2_table_groups(l2_table); |
86d722ad | 959 | if (err) |
33cfaaa8 | 960 | goto err_destroy_flow_table; |
86d722ad | 961 | |
33cfaaa8 | 962 | return 0; |
86d722ad | 963 | |
33cfaaa8 | 964 | err_destroy_flow_table: |
86d722ad MG |
965 | mlx5_destroy_flow_table(ft->t); |
966 | ft->t = NULL; | |
967 | ||
968 | return err; | |
969 | } | |
970 | ||
86d722ad MG |
971 | #define MLX5E_NUM_VLAN_GROUPS 2 |
972 | #define MLX5E_VLAN_GROUP0_SIZE BIT(12) | |
973 | #define MLX5E_VLAN_GROUP1_SIZE BIT(1) | |
974 | #define MLX5E_VLAN_TABLE_SIZE (MLX5E_VLAN_GROUP0_SIZE +\ | |
975 | MLX5E_VLAN_GROUP1_SIZE) | |
976 | ||
acff797c MG |
977 | static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in, |
978 | int inlen) | |
86d722ad MG |
979 | { |
980 | int err; | |
981 | int ix = 0; | |
982 | u8 *mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
983 | ||
984 | memset(in, 0, inlen); | |
985 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); | |
986 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.vlan_tag); | |
987 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.first_vid); | |
988 | MLX5_SET_CFG(in, start_flow_index, ix); | |
989 | ix += MLX5E_VLAN_GROUP0_SIZE; | |
990 | MLX5_SET_CFG(in, end_flow_index, ix - 1); | |
991 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
992 | if (IS_ERR(ft->g[ft->num_groups])) | |
993 | goto err_destroy_groups; | |
994 | ft->num_groups++; | |
995 | ||
996 | memset(in, 0, inlen); | |
997 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); | |
998 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.vlan_tag); | |
999 | MLX5_SET_CFG(in, start_flow_index, ix); | |
1000 | ix += MLX5E_VLAN_GROUP1_SIZE; | |
1001 | MLX5_SET_CFG(in, end_flow_index, ix - 1); | |
1002 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
1003 | if (IS_ERR(ft->g[ft->num_groups])) | |
1004 | goto err_destroy_groups; | |
1005 | ft->num_groups++; | |
1006 | ||
1007 | return 0; | |
1008 | ||
1009 | err_destroy_groups: | |
1010 | err = PTR_ERR(ft->g[ft->num_groups]); | |
1011 | ft->g[ft->num_groups] = NULL; | |
1012 | mlx5e_destroy_groups(ft); | |
1013 | ||
1014 | return err; | |
1015 | } | |
1016 | ||
acff797c | 1017 | static int mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft) |
afb736e9 | 1018 | { |
86d722ad MG |
1019 | u32 *in; |
1020 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
1021 | int err; | |
afb736e9 | 1022 | |
86d722ad MG |
1023 | in = mlx5_vzalloc(inlen); |
1024 | if (!in) | |
afb736e9 AV |
1025 | return -ENOMEM; |
1026 | ||
acff797c | 1027 | err = __mlx5e_create_vlan_table_groups(ft, in, inlen); |
86d722ad MG |
1028 | |
1029 | kvfree(in); | |
1030 | return err; | |
1031 | } | |
1032 | ||
acff797c | 1033 | static int mlx5e_create_vlan_table(struct mlx5e_priv *priv) |
86d722ad | 1034 | { |
acff797c | 1035 | struct mlx5e_flow_table *ft = &priv->fs.vlan.ft; |
86d722ad MG |
1036 | int err; |
1037 | ||
1038 | ft->num_groups = 0; | |
acff797c MG |
1039 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, |
1040 | MLX5E_VLAN_TABLE_SIZE, MLX5E_VLAN_FT_LEVEL); | |
86d722ad MG |
1041 | |
1042 | if (IS_ERR(ft->t)) { | |
1043 | err = PTR_ERR(ft->t); | |
1044 | ft->t = NULL; | |
1045 | return err; | |
1046 | } | |
1047 | ft->g = kcalloc(MLX5E_NUM_VLAN_GROUPS, sizeof(*ft->g), GFP_KERNEL); | |
1048 | if (!ft->g) { | |
1049 | err = -ENOMEM; | |
acff797c | 1050 | goto err_destroy_vlan_table; |
86d722ad MG |
1051 | } |
1052 | ||
acff797c | 1053 | err = mlx5e_create_vlan_table_groups(ft); |
86d722ad MG |
1054 | if (err) |
1055 | goto err_free_g; | |
1056 | ||
9df30601 | 1057 | mlx5e_add_vlan_rules(priv); |
d63cd286 | 1058 | |
86d722ad MG |
1059 | return 0; |
1060 | ||
1061 | err_free_g: | |
1062 | kfree(ft->g); | |
acff797c | 1063 | err_destroy_vlan_table: |
86d722ad MG |
1064 | mlx5_destroy_flow_table(ft->t); |
1065 | ft->t = NULL; | |
1066 | ||
1067 | return err; | |
afb736e9 AV |
1068 | } |
1069 | ||
acff797c | 1070 | static void mlx5e_destroy_vlan_table(struct mlx5e_priv *priv) |
afb736e9 | 1071 | { |
9df30601 | 1072 | mlx5e_del_vlan_rules(priv); |
acff797c | 1073 | mlx5e_destroy_flow_table(&priv->fs.vlan.ft); |
afb736e9 AV |
1074 | } |
1075 | ||
acff797c | 1076 | int mlx5e_create_flow_steering(struct mlx5e_priv *priv) |
afb736e9 AV |
1077 | { |
1078 | int err; | |
1079 | ||
acff797c | 1080 | priv->fs.ns = mlx5_get_flow_namespace(priv->mdev, |
86d722ad MG |
1081 | MLX5_FLOW_NAMESPACE_KERNEL); |
1082 | ||
acff797c | 1083 | if (!priv->fs.ns) |
86d722ad MG |
1084 | return -EINVAL; |
1085 | ||
1cabe6b0 MG |
1086 | err = mlx5e_arfs_create_tables(priv); |
1087 | if (err) { | |
1088 | netdev_err(priv->netdev, "Failed to create arfs tables, err=%d\n", | |
1089 | err); | |
1090 | priv->netdev->hw_features &= ~NETIF_F_NTUPLE; | |
1091 | } | |
1092 | ||
33cfaaa8 MG |
1093 | err = mlx5e_create_ttc_table(priv); |
1094 | if (err) { | |
1095 | netdev_err(priv->netdev, "Failed to create ttc table, err=%d\n", | |
1096 | err); | |
1cabe6b0 | 1097 | goto err_destroy_arfs_tables; |
33cfaaa8 MG |
1098 | } |
1099 | ||
1100 | err = mlx5e_create_l2_table(priv); | |
1101 | if (err) { | |
1102 | netdev_err(priv->netdev, "Failed to create l2 table, err=%d\n", | |
1103 | err); | |
1104 | goto err_destroy_ttc_table; | |
1105 | } | |
afb736e9 | 1106 | |
acff797c | 1107 | err = mlx5e_create_vlan_table(priv); |
33cfaaa8 MG |
1108 | if (err) { |
1109 | netdev_err(priv->netdev, "Failed to create vlan table, err=%d\n", | |
1110 | err); | |
1111 | goto err_destroy_l2_table; | |
1112 | } | |
9b37b07f | 1113 | |
6dc6071c MG |
1114 | mlx5e_ethtool_init_steering(priv); |
1115 | ||
afb736e9 AV |
1116 | return 0; |
1117 | ||
33cfaaa8 MG |
1118 | err_destroy_l2_table: |
1119 | mlx5e_destroy_l2_table(priv); | |
1120 | err_destroy_ttc_table: | |
1121 | mlx5e_destroy_ttc_table(priv); | |
1cabe6b0 MG |
1122 | err_destroy_arfs_tables: |
1123 | mlx5e_arfs_destroy_tables(priv); | |
afb736e9 AV |
1124 | |
1125 | return err; | |
1126 | } | |
1127 | ||
acff797c | 1128 | void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv) |
afb736e9 | 1129 | { |
acff797c | 1130 | mlx5e_destroy_vlan_table(priv); |
33cfaaa8 MG |
1131 | mlx5e_destroy_l2_table(priv); |
1132 | mlx5e_destroy_ttc_table(priv); | |
1cabe6b0 | 1133 | mlx5e_arfs_destroy_tables(priv); |
6dc6071c | 1134 | mlx5e_ethtool_cleanup_steering(priv); |
afb736e9 | 1135 | } |