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, | |
8a271746 MHY |
153 | MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID, |
154 | MLX5E_VLAN_RULE_TYPE_ANY_STAG_VID, | |
afb736e9 AV |
155 | MLX5E_VLAN_RULE_TYPE_MATCH_VID, |
156 | }; | |
157 | ||
86d722ad MG |
158 | static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, |
159 | enum mlx5e_vlan_rule_type rule_type, | |
c5bb1730 | 160 | u16 vid, struct mlx5_flow_spec *spec) |
afb736e9 | 161 | { |
acff797c | 162 | struct mlx5_flow_table *ft = priv->fs.vlan.ft.t; |
86d722ad | 163 | struct mlx5_flow_destination dest; |
74491de9 | 164 | struct mlx5_flow_handle **rule_p; |
e753b2b5 | 165 | MLX5_DECLARE_FLOW_ACT(flow_act); |
86d722ad | 166 | int err = 0; |
afb736e9 | 167 | |
86d722ad | 168 | dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; |
33cfaaa8 | 169 | dest.ft = priv->fs.l2.ft.t; |
afb736e9 | 170 | |
c5bb1730 | 171 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
8a271746 | 172 | |
afb736e9 AV |
173 | |
174 | switch (rule_type) { | |
175 | case MLX5E_VLAN_RULE_TYPE_UNTAGGED: | |
acff797c | 176 | rule_p = &priv->fs.vlan.untagged_rule; |
8a271746 MHY |
177 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, |
178 | outer_headers.cvlan_tag); | |
afb736e9 | 179 | break; |
8a271746 MHY |
180 | case MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID: |
181 | rule_p = &priv->fs.vlan.any_cvlan_rule; | |
182 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, | |
183 | outer_headers.cvlan_tag); | |
10543365 | 184 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.cvlan_tag, 1); |
afb736e9 | 185 | break; |
8a271746 MHY |
186 | case MLX5E_VLAN_RULE_TYPE_ANY_STAG_VID: |
187 | rule_p = &priv->fs.vlan.any_svlan_rule; | |
188 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, | |
189 | outer_headers.svlan_tag); | |
190 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.svlan_tag, 1); | |
191 | break; | |
afb736e9 | 192 | default: /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */ |
acff797c | 193 | rule_p = &priv->fs.vlan.active_vlans_rule[vid]; |
8a271746 MHY |
194 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, |
195 | outer_headers.cvlan_tag); | |
10543365 | 196 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.cvlan_tag, 1); |
c5bb1730 MG |
197 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, |
198 | outer_headers.first_vid); | |
199 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, | |
200 | vid); | |
afb736e9 AV |
201 | break; |
202 | } | |
203 | ||
66958ed9 | 204 | *rule_p = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1); |
86d722ad MG |
205 | |
206 | if (IS_ERR(*rule_p)) { | |
207 | err = PTR_ERR(*rule_p); | |
208 | *rule_p = NULL; | |
209 | netdev_err(priv->netdev, "%s: add rule failed\n", __func__); | |
210 | } | |
211 | ||
212 | return err; | |
213 | } | |
214 | ||
215 | static int mlx5e_add_vlan_rule(struct mlx5e_priv *priv, | |
216 | enum mlx5e_vlan_rule_type rule_type, u16 vid) | |
217 | { | |
c5bb1730 | 218 | struct mlx5_flow_spec *spec; |
86d722ad MG |
219 | int err = 0; |
220 | ||
c5bb1730 MG |
221 | spec = mlx5_vzalloc(sizeof(*spec)); |
222 | if (!spec) { | |
86d722ad | 223 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); |
c5bb1730 | 224 | return -ENOMEM; |
86d722ad MG |
225 | } |
226 | ||
227 | if (rule_type == MLX5E_VLAN_RULE_TYPE_MATCH_VID) | |
228 | mlx5e_vport_context_update_vlans(priv); | |
229 | ||
c5bb1730 | 230 | err = __mlx5e_add_vlan_rule(priv, rule_type, vid, spec); |
afb736e9 | 231 | |
c5bb1730 | 232 | kvfree(spec); |
86d722ad | 233 | |
afb736e9 AV |
234 | return err; |
235 | } | |
236 | ||
237 | static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv, | |
238 | enum mlx5e_vlan_rule_type rule_type, u16 vid) | |
239 | { | |
240 | switch (rule_type) { | |
241 | case MLX5E_VLAN_RULE_TYPE_UNTAGGED: | |
acff797c | 242 | if (priv->fs.vlan.untagged_rule) { |
74491de9 | 243 | mlx5_del_flow_rules(priv->fs.vlan.untagged_rule); |
acff797c | 244 | priv->fs.vlan.untagged_rule = NULL; |
86d722ad | 245 | } |
afb736e9 | 246 | break; |
8a271746 MHY |
247 | case MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID: |
248 | if (priv->fs.vlan.any_cvlan_rule) { | |
249 | mlx5_del_flow_rules(priv->fs.vlan.any_cvlan_rule); | |
250 | priv->fs.vlan.any_cvlan_rule = NULL; | |
251 | } | |
252 | break; | |
253 | case MLX5E_VLAN_RULE_TYPE_ANY_STAG_VID: | |
254 | if (priv->fs.vlan.any_svlan_rule) { | |
255 | mlx5_del_flow_rules(priv->fs.vlan.any_svlan_rule); | |
256 | priv->fs.vlan.any_svlan_rule = NULL; | |
86d722ad | 257 | } |
afb736e9 AV |
258 | break; |
259 | case MLX5E_VLAN_RULE_TYPE_MATCH_VID: | |
86d722ad | 260 | mlx5e_vport_context_update_vlans(priv); |
acff797c | 261 | if (priv->fs.vlan.active_vlans_rule[vid]) { |
74491de9 | 262 | mlx5_del_flow_rules(priv->fs.vlan.active_vlans_rule[vid]); |
acff797c | 263 | priv->fs.vlan.active_vlans_rule[vid] = NULL; |
86d722ad | 264 | } |
aad9e6e4 | 265 | mlx5e_vport_context_update_vlans(priv); |
afb736e9 AV |
266 | break; |
267 | } | |
268 | } | |
269 | ||
8a271746 MHY |
270 | static void mlx5e_del_any_vid_rules(struct mlx5e_priv *priv) |
271 | { | |
272 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID, 0); | |
273 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_STAG_VID, 0); | |
274 | } | |
275 | ||
276 | static int mlx5e_add_any_vid_rules(struct mlx5e_priv *priv) | |
277 | { | |
278 | int err; | |
279 | ||
280 | err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_CTAG_VID, 0); | |
281 | if (err) | |
282 | return err; | |
283 | ||
284 | return mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_STAG_VID, 0); | |
285 | } | |
286 | ||
afb736e9 AV |
287 | void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv) |
288 | { | |
acff797c | 289 | if (!priv->fs.vlan.filter_disabled) |
9b37b07f | 290 | return; |
afb736e9 | 291 | |
acff797c | 292 | priv->fs.vlan.filter_disabled = false; |
c0754343 AS |
293 | if (priv->netdev->flags & IFF_PROMISC) |
294 | return; | |
8a271746 | 295 | mlx5e_del_any_vid_rules(priv); |
afb736e9 AV |
296 | } |
297 | ||
298 | void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv) | |
299 | { | |
acff797c | 300 | if (priv->fs.vlan.filter_disabled) |
9b37b07f | 301 | return; |
afb736e9 | 302 | |
acff797c | 303 | priv->fs.vlan.filter_disabled = true; |
c0754343 AS |
304 | if (priv->netdev->flags & IFF_PROMISC) |
305 | return; | |
8a271746 | 306 | mlx5e_add_any_vid_rules(priv); |
afb736e9 AV |
307 | } |
308 | ||
309 | int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, | |
310 | u16 vid) | |
311 | { | |
312 | struct mlx5e_priv *priv = netdev_priv(dev); | |
afb736e9 | 313 | |
acff797c | 314 | set_bit(vid, priv->fs.vlan.active_vlans); |
aad9e6e4 | 315 | |
9b37b07f | 316 | return mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); |
afb736e9 AV |
317 | } |
318 | ||
319 | int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, | |
320 | u16 vid) | |
321 | { | |
322 | struct mlx5e_priv *priv = netdev_priv(dev); | |
323 | ||
acff797c | 324 | clear_bit(vid, priv->fs.vlan.active_vlans); |
aad9e6e4 | 325 | |
9b37b07f | 326 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); |
afb736e9 AV |
327 | |
328 | return 0; | |
329 | } | |
330 | ||
9df30601 MHY |
331 | static void mlx5e_add_vlan_rules(struct mlx5e_priv *priv) |
332 | { | |
333 | int i; | |
334 | ||
335 | mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); | |
336 | ||
337 | for_each_set_bit(i, priv->fs.vlan.active_vlans, VLAN_N_VID) { | |
338 | mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, i); | |
339 | } | |
340 | ||
341 | if (priv->fs.vlan.filter_disabled && | |
342 | !(priv->netdev->flags & IFF_PROMISC)) | |
8a271746 | 343 | mlx5e_add_any_vid_rules(priv); |
9df30601 MHY |
344 | } |
345 | ||
346 | static void mlx5e_del_vlan_rules(struct mlx5e_priv *priv) | |
347 | { | |
348 | int i; | |
349 | ||
350 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); | |
351 | ||
352 | for_each_set_bit(i, priv->fs.vlan.active_vlans, VLAN_N_VID) { | |
353 | mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, i); | |
354 | } | |
355 | ||
356 | if (priv->fs.vlan.filter_disabled && | |
357 | !(priv->netdev->flags & IFF_PROMISC)) | |
8a271746 | 358 | mlx5e_del_any_vid_rules(priv); |
9df30601 MHY |
359 | } |
360 | ||
afb736e9 | 361 | #define mlx5e_for_each_hash_node(hn, tmp, hash, i) \ |
33cfaaa8 | 362 | for (i = 0; i < MLX5E_L2_ADDR_HASH_SIZE; i++) \ |
afb736e9 AV |
363 | hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist) |
364 | ||
33cfaaa8 MG |
365 | static void mlx5e_execute_l2_action(struct mlx5e_priv *priv, |
366 | struct mlx5e_l2_hash_node *hn) | |
afb736e9 AV |
367 | { |
368 | switch (hn->action) { | |
369 | case MLX5E_ACTION_ADD: | |
33cfaaa8 | 370 | mlx5e_add_l2_flow_rule(priv, &hn->ai, MLX5E_FULLMATCH); |
afb736e9 AV |
371 | hn->action = MLX5E_ACTION_NONE; |
372 | break; | |
373 | ||
374 | case MLX5E_ACTION_DEL: | |
33cfaaa8 MG |
375 | mlx5e_del_l2_flow_rule(priv, &hn->ai); |
376 | mlx5e_del_l2_from_hash(hn); | |
afb736e9 AV |
377 | break; |
378 | } | |
379 | } | |
380 | ||
381 | static void mlx5e_sync_netdev_addr(struct mlx5e_priv *priv) | |
382 | { | |
383 | struct net_device *netdev = priv->netdev; | |
384 | struct netdev_hw_addr *ha; | |
385 | ||
386 | netif_addr_lock_bh(netdev); | |
387 | ||
33cfaaa8 MG |
388 | mlx5e_add_l2_to_hash(priv->fs.l2.netdev_uc, |
389 | priv->netdev->dev_addr); | |
afb736e9 AV |
390 | |
391 | netdev_for_each_uc_addr(ha, netdev) | |
33cfaaa8 | 392 | mlx5e_add_l2_to_hash(priv->fs.l2.netdev_uc, ha->addr); |
afb736e9 AV |
393 | |
394 | netdev_for_each_mc_addr(ha, netdev) | |
33cfaaa8 | 395 | mlx5e_add_l2_to_hash(priv->fs.l2.netdev_mc, ha->addr); |
afb736e9 AV |
396 | |
397 | netif_addr_unlock_bh(netdev); | |
398 | } | |
399 | ||
5e55da1d SM |
400 | static void mlx5e_fill_addr_array(struct mlx5e_priv *priv, int list_type, |
401 | u8 addr_array[][ETH_ALEN], int size) | |
402 | { | |
403 | bool is_uc = (list_type == MLX5_NVPRT_LIST_TYPE_UC); | |
404 | struct net_device *ndev = priv->netdev; | |
33cfaaa8 | 405 | struct mlx5e_l2_hash_node *hn; |
5e55da1d SM |
406 | struct hlist_head *addr_list; |
407 | struct hlist_node *tmp; | |
408 | int i = 0; | |
409 | int hi; | |
410 | ||
33cfaaa8 | 411 | addr_list = is_uc ? priv->fs.l2.netdev_uc : priv->fs.l2.netdev_mc; |
5e55da1d SM |
412 | |
413 | if (is_uc) /* Make sure our own address is pushed first */ | |
414 | ether_addr_copy(addr_array[i++], ndev->dev_addr); | |
33cfaaa8 | 415 | else if (priv->fs.l2.broadcast_enabled) |
5e55da1d SM |
416 | ether_addr_copy(addr_array[i++], ndev->broadcast); |
417 | ||
418 | mlx5e_for_each_hash_node(hn, tmp, addr_list, hi) { | |
419 | if (ether_addr_equal(ndev->dev_addr, hn->ai.addr)) | |
420 | continue; | |
421 | if (i >= size) | |
422 | break; | |
423 | ether_addr_copy(addr_array[i++], hn->ai.addr); | |
424 | } | |
425 | } | |
426 | ||
427 | static void mlx5e_vport_context_update_addr_list(struct mlx5e_priv *priv, | |
428 | int list_type) | |
429 | { | |
430 | bool is_uc = (list_type == MLX5_NVPRT_LIST_TYPE_UC); | |
33cfaaa8 | 431 | struct mlx5e_l2_hash_node *hn; |
5e55da1d SM |
432 | u8 (*addr_array)[ETH_ALEN] = NULL; |
433 | struct hlist_head *addr_list; | |
434 | struct hlist_node *tmp; | |
435 | int max_size; | |
436 | int size; | |
437 | int err; | |
438 | int hi; | |
439 | ||
33cfaaa8 | 440 | size = is_uc ? 0 : (priv->fs.l2.broadcast_enabled ? 1 : 0); |
5e55da1d SM |
441 | max_size = is_uc ? |
442 | 1 << MLX5_CAP_GEN(priv->mdev, log_max_current_uc_list) : | |
443 | 1 << MLX5_CAP_GEN(priv->mdev, log_max_current_mc_list); | |
444 | ||
33cfaaa8 | 445 | addr_list = is_uc ? priv->fs.l2.netdev_uc : priv->fs.l2.netdev_mc; |
5e55da1d SM |
446 | mlx5e_for_each_hash_node(hn, tmp, addr_list, hi) |
447 | size++; | |
448 | ||
449 | if (size > max_size) { | |
450 | netdev_warn(priv->netdev, | |
451 | "netdev %s list size (%d) > (%d) max vport list size, some addresses will be dropped\n", | |
452 | is_uc ? "UC" : "MC", size, max_size); | |
453 | size = max_size; | |
454 | } | |
455 | ||
456 | if (size) { | |
457 | addr_array = kcalloc(size, ETH_ALEN, GFP_KERNEL); | |
458 | if (!addr_array) { | |
459 | err = -ENOMEM; | |
460 | goto out; | |
461 | } | |
462 | mlx5e_fill_addr_array(priv, list_type, addr_array, size); | |
463 | } | |
464 | ||
465 | err = mlx5_modify_nic_vport_mac_list(priv->mdev, list_type, addr_array, size); | |
466 | out: | |
467 | if (err) | |
468 | netdev_err(priv->netdev, | |
469 | "Failed to modify vport %s list err(%d)\n", | |
470 | is_uc ? "UC" : "MC", err); | |
471 | kfree(addr_array); | |
472 | } | |
473 | ||
474 | static void mlx5e_vport_context_update(struct mlx5e_priv *priv) | |
475 | { | |
33cfaaa8 | 476 | struct mlx5e_l2_table *ea = &priv->fs.l2; |
5e55da1d SM |
477 | |
478 | mlx5e_vport_context_update_addr_list(priv, MLX5_NVPRT_LIST_TYPE_UC); | |
479 | mlx5e_vport_context_update_addr_list(priv, MLX5_NVPRT_LIST_TYPE_MC); | |
480 | mlx5_modify_nic_vport_promisc(priv->mdev, 0, | |
33cfaaa8 MG |
481 | ea->allmulti_enabled, |
482 | ea->promisc_enabled); | |
5e55da1d SM |
483 | } |
484 | ||
afb736e9 AV |
485 | static void mlx5e_apply_netdev_addr(struct mlx5e_priv *priv) |
486 | { | |
33cfaaa8 | 487 | struct mlx5e_l2_hash_node *hn; |
afb736e9 AV |
488 | struct hlist_node *tmp; |
489 | int i; | |
490 | ||
33cfaaa8 MG |
491 | mlx5e_for_each_hash_node(hn, tmp, priv->fs.l2.netdev_uc, i) |
492 | mlx5e_execute_l2_action(priv, hn); | |
afb736e9 | 493 | |
33cfaaa8 MG |
494 | mlx5e_for_each_hash_node(hn, tmp, priv->fs.l2.netdev_mc, i) |
495 | mlx5e_execute_l2_action(priv, hn); | |
afb736e9 AV |
496 | } |
497 | ||
498 | static void mlx5e_handle_netdev_addr(struct mlx5e_priv *priv) | |
499 | { | |
33cfaaa8 | 500 | struct mlx5e_l2_hash_node *hn; |
afb736e9 AV |
501 | struct hlist_node *tmp; |
502 | int i; | |
503 | ||
33cfaaa8 | 504 | mlx5e_for_each_hash_node(hn, tmp, priv->fs.l2.netdev_uc, i) |
afb736e9 | 505 | hn->action = MLX5E_ACTION_DEL; |
33cfaaa8 | 506 | mlx5e_for_each_hash_node(hn, tmp, priv->fs.l2.netdev_mc, i) |
afb736e9 AV |
507 | hn->action = MLX5E_ACTION_DEL; |
508 | ||
9b37b07f | 509 | if (!test_bit(MLX5E_STATE_DESTROYING, &priv->state)) |
afb736e9 AV |
510 | mlx5e_sync_netdev_addr(priv); |
511 | ||
512 | mlx5e_apply_netdev_addr(priv); | |
513 | } | |
514 | ||
9b37b07f | 515 | void mlx5e_set_rx_mode_work(struct work_struct *work) |
afb736e9 | 516 | { |
9b37b07f AS |
517 | struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, |
518 | set_rx_mode_work); | |
519 | ||
33cfaaa8 | 520 | struct mlx5e_l2_table *ea = &priv->fs.l2; |
afb736e9 AV |
521 | struct net_device *ndev = priv->netdev; |
522 | ||
9b37b07f | 523 | bool rx_mode_enable = !test_bit(MLX5E_STATE_DESTROYING, &priv->state); |
afb736e9 AV |
524 | bool promisc_enabled = rx_mode_enable && (ndev->flags & IFF_PROMISC); |
525 | bool allmulti_enabled = rx_mode_enable && (ndev->flags & IFF_ALLMULTI); | |
526 | bool broadcast_enabled = rx_mode_enable; | |
527 | ||
33cfaaa8 MG |
528 | bool enable_promisc = !ea->promisc_enabled && promisc_enabled; |
529 | bool disable_promisc = ea->promisc_enabled && !promisc_enabled; | |
530 | bool enable_allmulti = !ea->allmulti_enabled && allmulti_enabled; | |
531 | bool disable_allmulti = ea->allmulti_enabled && !allmulti_enabled; | |
532 | bool enable_broadcast = !ea->broadcast_enabled && broadcast_enabled; | |
533 | bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled; | |
afb736e9 | 534 | |
c0754343 | 535 | if (enable_promisc) { |
33cfaaa8 | 536 | mlx5e_add_l2_flow_rule(priv, &ea->promisc, MLX5E_PROMISC); |
acff797c | 537 | if (!priv->fs.vlan.filter_disabled) |
8a271746 | 538 | mlx5e_add_any_vid_rules(priv); |
c0754343 | 539 | } |
afb736e9 | 540 | if (enable_allmulti) |
33cfaaa8 | 541 | mlx5e_add_l2_flow_rule(priv, &ea->allmulti, MLX5E_ALLMULTI); |
afb736e9 | 542 | if (enable_broadcast) |
33cfaaa8 | 543 | mlx5e_add_l2_flow_rule(priv, &ea->broadcast, MLX5E_FULLMATCH); |
afb736e9 AV |
544 | |
545 | mlx5e_handle_netdev_addr(priv); | |
546 | ||
547 | if (disable_broadcast) | |
33cfaaa8 | 548 | mlx5e_del_l2_flow_rule(priv, &ea->broadcast); |
afb736e9 | 549 | if (disable_allmulti) |
33cfaaa8 | 550 | mlx5e_del_l2_flow_rule(priv, &ea->allmulti); |
c0754343 | 551 | if (disable_promisc) { |
acff797c | 552 | if (!priv->fs.vlan.filter_disabled) |
8a271746 | 553 | mlx5e_del_any_vid_rules(priv); |
33cfaaa8 | 554 | mlx5e_del_l2_flow_rule(priv, &ea->promisc); |
c0754343 | 555 | } |
afb736e9 | 556 | |
33cfaaa8 MG |
557 | ea->promisc_enabled = promisc_enabled; |
558 | ea->allmulti_enabled = allmulti_enabled; | |
559 | ea->broadcast_enabled = broadcast_enabled; | |
5e55da1d SM |
560 | |
561 | mlx5e_vport_context_update(priv); | |
afb736e9 AV |
562 | } |
563 | ||
86d722ad MG |
564 | static void mlx5e_destroy_groups(struct mlx5e_flow_table *ft) |
565 | { | |
566 | int i; | |
567 | ||
568 | for (i = ft->num_groups - 1; i >= 0; i--) { | |
569 | if (!IS_ERR_OR_NULL(ft->g[i])) | |
570 | mlx5_destroy_flow_group(ft->g[i]); | |
571 | ft->g[i] = NULL; | |
572 | } | |
573 | ft->num_groups = 0; | |
574 | } | |
575 | ||
33cfaaa8 | 576 | void mlx5e_init_l2_addr(struct mlx5e_priv *priv) |
afb736e9 | 577 | { |
33cfaaa8 | 578 | ether_addr_copy(priv->fs.l2.broadcast.addr, priv->netdev->broadcast); |
afb736e9 AV |
579 | } |
580 | ||
1cabe6b0 | 581 | void mlx5e_destroy_flow_table(struct mlx5e_flow_table *ft) |
afb736e9 | 582 | { |
33cfaaa8 MG |
583 | mlx5e_destroy_groups(ft); |
584 | kfree(ft->g); | |
585 | mlx5_destroy_flow_table(ft->t); | |
586 | ft->t = NULL; | |
587 | } | |
588 | ||
589 | static void mlx5e_cleanup_ttc_rules(struct mlx5e_ttc_table *ttc) | |
590 | { | |
591 | int i; | |
592 | ||
593 | for (i = 0; i < MLX5E_NUM_TT; i++) { | |
594 | if (!IS_ERR_OR_NULL(ttc->rules[i])) { | |
74491de9 | 595 | mlx5_del_flow_rules(ttc->rules[i]); |
33cfaaa8 MG |
596 | ttc->rules[i] = NULL; |
597 | } | |
598 | } | |
599 | } | |
600 | ||
601 | static struct { | |
602 | u16 etype; | |
603 | u8 proto; | |
604 | } ttc_rules[] = { | |
605 | [MLX5E_TT_IPV4_TCP] = { | |
606 | .etype = ETH_P_IP, | |
607 | .proto = IPPROTO_TCP, | |
608 | }, | |
609 | [MLX5E_TT_IPV6_TCP] = { | |
610 | .etype = ETH_P_IPV6, | |
611 | .proto = IPPROTO_TCP, | |
612 | }, | |
613 | [MLX5E_TT_IPV4_UDP] = { | |
614 | .etype = ETH_P_IP, | |
615 | .proto = IPPROTO_UDP, | |
616 | }, | |
617 | [MLX5E_TT_IPV6_UDP] = { | |
618 | .etype = ETH_P_IPV6, | |
619 | .proto = IPPROTO_UDP, | |
620 | }, | |
621 | [MLX5E_TT_IPV4_IPSEC_AH] = { | |
622 | .etype = ETH_P_IP, | |
623 | .proto = IPPROTO_AH, | |
624 | }, | |
625 | [MLX5E_TT_IPV6_IPSEC_AH] = { | |
626 | .etype = ETH_P_IPV6, | |
627 | .proto = IPPROTO_AH, | |
628 | }, | |
629 | [MLX5E_TT_IPV4_IPSEC_ESP] = { | |
630 | .etype = ETH_P_IP, | |
631 | .proto = IPPROTO_ESP, | |
632 | }, | |
633 | [MLX5E_TT_IPV6_IPSEC_ESP] = { | |
634 | .etype = ETH_P_IPV6, | |
635 | .proto = IPPROTO_ESP, | |
636 | }, | |
637 | [MLX5E_TT_IPV4] = { | |
638 | .etype = ETH_P_IP, | |
639 | .proto = 0, | |
640 | }, | |
641 | [MLX5E_TT_IPV6] = { | |
642 | .etype = ETH_P_IPV6, | |
643 | .proto = 0, | |
644 | }, | |
645 | [MLX5E_TT_ANY] = { | |
646 | .etype = 0, | |
647 | .proto = 0, | |
648 | }, | |
649 | }; | |
650 | ||
74491de9 MB |
651 | static struct mlx5_flow_handle * |
652 | mlx5e_generate_ttc_rule(struct mlx5e_priv *priv, | |
653 | struct mlx5_flow_table *ft, | |
654 | struct mlx5_flow_destination *dest, | |
655 | u16 etype, | |
656 | u8 proto) | |
33cfaaa8 | 657 | { |
e753b2b5 | 658 | MLX5_DECLARE_FLOW_ACT(flow_act); |
74491de9 | 659 | struct mlx5_flow_handle *rule; |
c5bb1730 | 660 | struct mlx5_flow_spec *spec; |
33cfaaa8 MG |
661 | int err = 0; |
662 | ||
c5bb1730 MG |
663 | spec = mlx5_vzalloc(sizeof(*spec)); |
664 | if (!spec) { | |
33cfaaa8 | 665 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); |
c5bb1730 | 666 | return ERR_PTR(-ENOMEM); |
33cfaaa8 MG |
667 | } |
668 | ||
669 | if (proto) { | |
c5bb1730 MG |
670 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
671 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); | |
672 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, proto); | |
33cfaaa8 MG |
673 | } |
674 | if (etype) { | |
c5bb1730 MG |
675 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
676 | MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype); | |
677 | MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, etype); | |
33cfaaa8 MG |
678 | } |
679 | ||
66958ed9 | 680 | rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, 1); |
33cfaaa8 MG |
681 | if (IS_ERR(rule)) { |
682 | err = PTR_ERR(rule); | |
683 | netdev_err(priv->netdev, "%s: add rule failed\n", __func__); | |
684 | } | |
c5bb1730 MG |
685 | |
686 | kvfree(spec); | |
33cfaaa8 MG |
687 | return err ? ERR_PTR(err) : rule; |
688 | } | |
689 | ||
690 | static int mlx5e_generate_ttc_table_rules(struct mlx5e_priv *priv) | |
691 | { | |
692 | struct mlx5_flow_destination dest; | |
693 | struct mlx5e_ttc_table *ttc; | |
74491de9 | 694 | struct mlx5_flow_handle **rules; |
33cfaaa8 MG |
695 | struct mlx5_flow_table *ft; |
696 | int tt; | |
86d722ad | 697 | int err; |
33cfaaa8 MG |
698 | |
699 | ttc = &priv->fs.ttc; | |
700 | ft = ttc->ft.t; | |
701 | rules = ttc->rules; | |
702 | ||
703 | dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; | |
704 | for (tt = 0; tt < MLX5E_NUM_TT; tt++) { | |
705 | if (tt == MLX5E_TT_ANY) | |
706 | dest.tir_num = priv->direct_tir[0].tirn; | |
707 | else | |
724b2aa1 | 708 | dest.tir_num = priv->indir_tir[tt].tirn; |
33cfaaa8 MG |
709 | rules[tt] = mlx5e_generate_ttc_rule(priv, ft, &dest, |
710 | ttc_rules[tt].etype, | |
711 | ttc_rules[tt].proto); | |
712 | if (IS_ERR(rules[tt])) | |
713 | goto del_rules; | |
714 | } | |
715 | ||
716 | return 0; | |
717 | ||
718 | del_rules: | |
719 | err = PTR_ERR(rules[tt]); | |
720 | rules[tt] = NULL; | |
721 | mlx5e_cleanup_ttc_rules(ttc); | |
722 | return err; | |
723 | } | |
724 | ||
725 | #define MLX5E_TTC_NUM_GROUPS 3 | |
726 | #define MLX5E_TTC_GROUP1_SIZE BIT(3) | |
727 | #define MLX5E_TTC_GROUP2_SIZE BIT(1) | |
728 | #define MLX5E_TTC_GROUP3_SIZE BIT(0) | |
729 | #define MLX5E_TTC_TABLE_SIZE (MLX5E_TTC_GROUP1_SIZE +\ | |
730 | MLX5E_TTC_GROUP2_SIZE +\ | |
731 | MLX5E_TTC_GROUP3_SIZE) | |
732 | static int mlx5e_create_ttc_table_groups(struct mlx5e_ttc_table *ttc) | |
733 | { | |
734 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
735 | struct mlx5e_flow_table *ft = &ttc->ft; | |
86d722ad | 736 | int ix = 0; |
33cfaaa8 MG |
737 | u32 *in; |
738 | int err; | |
739 | u8 *mc; | |
86d722ad | 740 | |
33cfaaa8 MG |
741 | ft->g = kcalloc(MLX5E_TTC_NUM_GROUPS, |
742 | sizeof(*ft->g), GFP_KERNEL); | |
743 | if (!ft->g) | |
744 | return -ENOMEM; | |
745 | in = mlx5_vzalloc(inlen); | |
746 | if (!in) { | |
747 | kfree(ft->g); | |
748 | return -ENOMEM; | |
749 | } | |
86d722ad | 750 | |
33cfaaa8 MG |
751 | /* L4 Group */ |
752 | mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
753 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ip_protocol); | |
86d722ad | 754 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype); |
33cfaaa8 | 755 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); |
86d722ad | 756 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 757 | ix += MLX5E_TTC_GROUP1_SIZE; |
86d722ad MG |
758 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
759 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
760 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 761 | goto err; |
86d722ad MG |
762 | ft->num_groups++; |
763 | ||
33cfaaa8 MG |
764 | /* L3 Group */ |
765 | MLX5_SET(fte_match_param, mc, outer_headers.ip_protocol, 0); | |
86d722ad | 766 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 767 | ix += MLX5E_TTC_GROUP2_SIZE; |
86d722ad MG |
768 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
769 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
770 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 771 | goto err; |
86d722ad MG |
772 | ft->num_groups++; |
773 | ||
33cfaaa8 | 774 | /* Any Group */ |
86d722ad | 775 | memset(in, 0, inlen); |
86d722ad | 776 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 777 | ix += MLX5E_TTC_GROUP3_SIZE; |
86d722ad MG |
778 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
779 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
780 | if (IS_ERR(ft->g[ft->num_groups])) | |
33cfaaa8 | 781 | goto err; |
86d722ad MG |
782 | ft->num_groups++; |
783 | ||
33cfaaa8 MG |
784 | kvfree(in); |
785 | return 0; | |
86d722ad | 786 | |
33cfaaa8 MG |
787 | err: |
788 | err = PTR_ERR(ft->g[ft->num_groups]); | |
789 | ft->g[ft->num_groups] = NULL; | |
790 | kvfree(in); | |
86d722ad | 791 | |
33cfaaa8 MG |
792 | return err; |
793 | } | |
794 | ||
795 | static void mlx5e_destroy_ttc_table(struct mlx5e_priv *priv) | |
796 | { | |
797 | struct mlx5e_ttc_table *ttc = &priv->fs.ttc; | |
798 | ||
799 | mlx5e_cleanup_ttc_rules(ttc); | |
800 | mlx5e_destroy_flow_table(&ttc->ft); | |
801 | } | |
802 | ||
803 | static int mlx5e_create_ttc_table(struct mlx5e_priv *priv) | |
804 | { | |
805 | struct mlx5e_ttc_table *ttc = &priv->fs.ttc; | |
806 | struct mlx5e_flow_table *ft = &ttc->ft; | |
807 | int err; | |
808 | ||
809 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, | |
c9f1b073 | 810 | MLX5E_TTC_TABLE_SIZE, MLX5E_TTC_FT_LEVEL, 0); |
33cfaaa8 MG |
811 | if (IS_ERR(ft->t)) { |
812 | err = PTR_ERR(ft->t); | |
813 | ft->t = NULL; | |
814 | return err; | |
815 | } | |
816 | ||
817 | err = mlx5e_create_ttc_table_groups(ttc); | |
818 | if (err) | |
819 | goto err; | |
820 | ||
821 | err = mlx5e_generate_ttc_table_rules(priv); | |
822 | if (err) | |
823 | goto err; | |
824 | ||
825 | return 0; | |
826 | err: | |
827 | mlx5e_destroy_flow_table(ft); | |
828 | return err; | |
829 | } | |
830 | ||
831 | static void mlx5e_del_l2_flow_rule(struct mlx5e_priv *priv, | |
832 | struct mlx5e_l2_rule *ai) | |
833 | { | |
834 | if (!IS_ERR_OR_NULL(ai->rule)) { | |
74491de9 | 835 | mlx5_del_flow_rules(ai->rule); |
33cfaaa8 MG |
836 | ai->rule = NULL; |
837 | } | |
838 | } | |
839 | ||
840 | static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, | |
841 | struct mlx5e_l2_rule *ai, int type) | |
842 | { | |
843 | struct mlx5_flow_table *ft = priv->fs.l2.ft.t; | |
844 | struct mlx5_flow_destination dest; | |
e753b2b5 | 845 | MLX5_DECLARE_FLOW_ACT(flow_act); |
c5bb1730 | 846 | struct mlx5_flow_spec *spec; |
33cfaaa8 MG |
847 | int err = 0; |
848 | u8 *mc_dmac; | |
849 | u8 *mv_dmac; | |
850 | ||
c5bb1730 MG |
851 | spec = mlx5_vzalloc(sizeof(*spec)); |
852 | if (!spec) { | |
33cfaaa8 | 853 | netdev_err(priv->netdev, "%s: alloc failed\n", __func__); |
c5bb1730 | 854 | return -ENOMEM; |
33cfaaa8 MG |
855 | } |
856 | ||
c5bb1730 | 857 | mc_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, |
33cfaaa8 | 858 | outer_headers.dmac_47_16); |
c5bb1730 | 859 | mv_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_value, |
33cfaaa8 MG |
860 | outer_headers.dmac_47_16); |
861 | ||
862 | dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; | |
863 | dest.ft = priv->fs.ttc.ft.t; | |
864 | ||
865 | switch (type) { | |
866 | case MLX5E_FULLMATCH: | |
c5bb1730 | 867 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
33cfaaa8 MG |
868 | eth_broadcast_addr(mc_dmac); |
869 | ether_addr_copy(mv_dmac, ai->addr); | |
870 | break; | |
871 | ||
872 | case MLX5E_ALLMULTI: | |
c5bb1730 | 873 | spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; |
33cfaaa8 MG |
874 | mc_dmac[0] = 0x01; |
875 | mv_dmac[0] = 0x01; | |
876 | break; | |
877 | ||
878 | case MLX5E_PROMISC: | |
879 | break; | |
880 | } | |
881 | ||
66958ed9 | 882 | ai->rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1); |
33cfaaa8 MG |
883 | if (IS_ERR(ai->rule)) { |
884 | netdev_err(priv->netdev, "%s: add l2 rule(mac:%pM) failed\n", | |
885 | __func__, mv_dmac); | |
886 | err = PTR_ERR(ai->rule); | |
887 | ai->rule = NULL; | |
888 | } | |
889 | ||
c5bb1730 | 890 | kvfree(spec); |
33cfaaa8 MG |
891 | |
892 | return err; | |
893 | } | |
894 | ||
895 | #define MLX5E_NUM_L2_GROUPS 3 | |
896 | #define MLX5E_L2_GROUP1_SIZE BIT(0) | |
897 | #define MLX5E_L2_GROUP2_SIZE BIT(15) | |
898 | #define MLX5E_L2_GROUP3_SIZE BIT(0) | |
899 | #define MLX5E_L2_TABLE_SIZE (MLX5E_L2_GROUP1_SIZE +\ | |
900 | MLX5E_L2_GROUP2_SIZE +\ | |
901 | MLX5E_L2_GROUP3_SIZE) | |
902 | static int mlx5e_create_l2_table_groups(struct mlx5e_l2_table *l2_table) | |
903 | { | |
904 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
905 | struct mlx5e_flow_table *ft = &l2_table->ft; | |
906 | int ix = 0; | |
907 | u8 *mc_dmac; | |
908 | u32 *in; | |
909 | int err; | |
910 | u8 *mc; | |
911 | ||
912 | ft->g = kcalloc(MLX5E_NUM_L2_GROUPS, sizeof(*ft->g), GFP_KERNEL); | |
913 | if (!ft->g) | |
914 | return -ENOMEM; | |
915 | in = mlx5_vzalloc(inlen); | |
916 | if (!in) { | |
917 | kfree(ft->g); | |
918 | return -ENOMEM; | |
919 | } | |
920 | ||
921 | mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
922 | mc_dmac = MLX5_ADDR_OF(fte_match_param, mc, | |
923 | outer_headers.dmac_47_16); | |
924 | /* Flow Group for promiscuous */ | |
86d722ad | 925 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 926 | ix += MLX5E_L2_GROUP1_SIZE; |
86d722ad MG |
927 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
928 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
929 | if (IS_ERR(ft->g[ft->num_groups])) | |
930 | goto err_destroy_groups; | |
931 | ft->num_groups++; | |
932 | ||
33cfaaa8 MG |
933 | /* Flow Group for full match */ |
934 | eth_broadcast_addr(mc_dmac); | |
86d722ad | 935 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); |
86d722ad | 936 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 937 | ix += MLX5E_L2_GROUP2_SIZE; |
86d722ad MG |
938 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
939 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
940 | if (IS_ERR(ft->g[ft->num_groups])) | |
941 | goto err_destroy_groups; | |
942 | ft->num_groups++; | |
943 | ||
33cfaaa8 MG |
944 | /* Flow Group for allmulti */ |
945 | eth_zero_addr(mc_dmac); | |
946 | mc_dmac[0] = 0x01; | |
86d722ad | 947 | MLX5_SET_CFG(in, start_flow_index, ix); |
33cfaaa8 | 948 | ix += MLX5E_L2_GROUP3_SIZE; |
86d722ad MG |
949 | MLX5_SET_CFG(in, end_flow_index, ix - 1); |
950 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
951 | if (IS_ERR(ft->g[ft->num_groups])) | |
952 | goto err_destroy_groups; | |
953 | ft->num_groups++; | |
954 | ||
33cfaaa8 | 955 | kvfree(in); |
86d722ad MG |
956 | return 0; |
957 | ||
958 | err_destroy_groups: | |
959 | err = PTR_ERR(ft->g[ft->num_groups]); | |
960 | ft->g[ft->num_groups] = NULL; | |
961 | mlx5e_destroy_groups(ft); | |
33cfaaa8 | 962 | kvfree(in); |
86d722ad MG |
963 | |
964 | return err; | |
965 | } | |
afb736e9 | 966 | |
33cfaaa8 | 967 | static void mlx5e_destroy_l2_table(struct mlx5e_priv *priv) |
86d722ad | 968 | { |
33cfaaa8 | 969 | mlx5e_destroy_flow_table(&priv->fs.l2.ft); |
86d722ad | 970 | } |
afb736e9 | 971 | |
33cfaaa8 | 972 | static int mlx5e_create_l2_table(struct mlx5e_priv *priv) |
86d722ad | 973 | { |
33cfaaa8 MG |
974 | struct mlx5e_l2_table *l2_table = &priv->fs.l2; |
975 | struct mlx5e_flow_table *ft = &l2_table->ft; | |
86d722ad MG |
976 | int err; |
977 | ||
978 | ft->num_groups = 0; | |
acff797c | 979 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, |
c9f1b073 | 980 | MLX5E_L2_TABLE_SIZE, MLX5E_L2_FT_LEVEL, 0); |
86d722ad MG |
981 | |
982 | if (IS_ERR(ft->t)) { | |
983 | err = PTR_ERR(ft->t); | |
984 | ft->t = NULL; | |
985 | return err; | |
986 | } | |
86d722ad | 987 | |
33cfaaa8 | 988 | err = mlx5e_create_l2_table_groups(l2_table); |
86d722ad | 989 | if (err) |
33cfaaa8 | 990 | goto err_destroy_flow_table; |
86d722ad | 991 | |
33cfaaa8 | 992 | return 0; |
86d722ad | 993 | |
33cfaaa8 | 994 | err_destroy_flow_table: |
86d722ad MG |
995 | mlx5_destroy_flow_table(ft->t); |
996 | ft->t = NULL; | |
997 | ||
998 | return err; | |
999 | } | |
1000 | ||
8a271746 | 1001 | #define MLX5E_NUM_VLAN_GROUPS 3 |
86d722ad MG |
1002 | #define MLX5E_VLAN_GROUP0_SIZE BIT(12) |
1003 | #define MLX5E_VLAN_GROUP1_SIZE BIT(1) | |
8a271746 | 1004 | #define MLX5E_VLAN_GROUP2_SIZE BIT(0) |
86d722ad | 1005 | #define MLX5E_VLAN_TABLE_SIZE (MLX5E_VLAN_GROUP0_SIZE +\ |
8a271746 MHY |
1006 | MLX5E_VLAN_GROUP1_SIZE +\ |
1007 | MLX5E_VLAN_GROUP2_SIZE) | |
86d722ad | 1008 | |
acff797c MG |
1009 | static int __mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft, u32 *in, |
1010 | int inlen) | |
86d722ad MG |
1011 | { |
1012 | int err; | |
1013 | int ix = 0; | |
1014 | u8 *mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); | |
1015 | ||
1016 | memset(in, 0, inlen); | |
1017 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); | |
10543365 | 1018 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.cvlan_tag); |
86d722ad MG |
1019 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.first_vid); |
1020 | MLX5_SET_CFG(in, start_flow_index, ix); | |
1021 | ix += MLX5E_VLAN_GROUP0_SIZE; | |
1022 | MLX5_SET_CFG(in, end_flow_index, ix - 1); | |
1023 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
1024 | if (IS_ERR(ft->g[ft->num_groups])) | |
1025 | goto err_destroy_groups; | |
1026 | ft->num_groups++; | |
1027 | ||
1028 | memset(in, 0, inlen); | |
1029 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); | |
10543365 | 1030 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.cvlan_tag); |
86d722ad MG |
1031 | MLX5_SET_CFG(in, start_flow_index, ix); |
1032 | ix += MLX5E_VLAN_GROUP1_SIZE; | |
1033 | MLX5_SET_CFG(in, end_flow_index, ix - 1); | |
1034 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
1035 | if (IS_ERR(ft->g[ft->num_groups])) | |
1036 | goto err_destroy_groups; | |
1037 | ft->num_groups++; | |
1038 | ||
8a271746 MHY |
1039 | memset(in, 0, inlen); |
1040 | MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); | |
1041 | MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.svlan_tag); | |
1042 | MLX5_SET_CFG(in, start_flow_index, ix); | |
1043 | ix += MLX5E_VLAN_GROUP2_SIZE; | |
1044 | MLX5_SET_CFG(in, end_flow_index, ix - 1); | |
1045 | ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); | |
1046 | if (IS_ERR(ft->g[ft->num_groups])) | |
1047 | goto err_destroy_groups; | |
1048 | ft->num_groups++; | |
1049 | ||
86d722ad MG |
1050 | return 0; |
1051 | ||
1052 | err_destroy_groups: | |
1053 | err = PTR_ERR(ft->g[ft->num_groups]); | |
1054 | ft->g[ft->num_groups] = NULL; | |
1055 | mlx5e_destroy_groups(ft); | |
1056 | ||
1057 | return err; | |
1058 | } | |
1059 | ||
acff797c | 1060 | static int mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft) |
afb736e9 | 1061 | { |
86d722ad MG |
1062 | u32 *in; |
1063 | int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); | |
1064 | int err; | |
afb736e9 | 1065 | |
86d722ad MG |
1066 | in = mlx5_vzalloc(inlen); |
1067 | if (!in) | |
afb736e9 AV |
1068 | return -ENOMEM; |
1069 | ||
acff797c | 1070 | err = __mlx5e_create_vlan_table_groups(ft, in, inlen); |
86d722ad MG |
1071 | |
1072 | kvfree(in); | |
1073 | return err; | |
1074 | } | |
1075 | ||
acff797c | 1076 | static int mlx5e_create_vlan_table(struct mlx5e_priv *priv) |
86d722ad | 1077 | { |
acff797c | 1078 | struct mlx5e_flow_table *ft = &priv->fs.vlan.ft; |
86d722ad MG |
1079 | int err; |
1080 | ||
1081 | ft->num_groups = 0; | |
acff797c | 1082 | ft->t = mlx5_create_flow_table(priv->fs.ns, MLX5E_NIC_PRIO, |
c9f1b073 | 1083 | MLX5E_VLAN_TABLE_SIZE, MLX5E_VLAN_FT_LEVEL, 0); |
86d722ad MG |
1084 | |
1085 | if (IS_ERR(ft->t)) { | |
1086 | err = PTR_ERR(ft->t); | |
1087 | ft->t = NULL; | |
1088 | return err; | |
1089 | } | |
1090 | ft->g = kcalloc(MLX5E_NUM_VLAN_GROUPS, sizeof(*ft->g), GFP_KERNEL); | |
1091 | if (!ft->g) { | |
1092 | err = -ENOMEM; | |
acff797c | 1093 | goto err_destroy_vlan_table; |
86d722ad MG |
1094 | } |
1095 | ||
acff797c | 1096 | err = mlx5e_create_vlan_table_groups(ft); |
86d722ad MG |
1097 | if (err) |
1098 | goto err_free_g; | |
1099 | ||
9df30601 | 1100 | mlx5e_add_vlan_rules(priv); |
d63cd286 | 1101 | |
86d722ad MG |
1102 | return 0; |
1103 | ||
1104 | err_free_g: | |
1105 | kfree(ft->g); | |
acff797c | 1106 | err_destroy_vlan_table: |
86d722ad MG |
1107 | mlx5_destroy_flow_table(ft->t); |
1108 | ft->t = NULL; | |
1109 | ||
1110 | return err; | |
afb736e9 AV |
1111 | } |
1112 | ||
acff797c | 1113 | static void mlx5e_destroy_vlan_table(struct mlx5e_priv *priv) |
afb736e9 | 1114 | { |
9df30601 | 1115 | mlx5e_del_vlan_rules(priv); |
acff797c | 1116 | mlx5e_destroy_flow_table(&priv->fs.vlan.ft); |
afb736e9 AV |
1117 | } |
1118 | ||
acff797c | 1119 | int mlx5e_create_flow_steering(struct mlx5e_priv *priv) |
afb736e9 AV |
1120 | { |
1121 | int err; | |
1122 | ||
acff797c | 1123 | priv->fs.ns = mlx5_get_flow_namespace(priv->mdev, |
86d722ad MG |
1124 | MLX5_FLOW_NAMESPACE_KERNEL); |
1125 | ||
acff797c | 1126 | if (!priv->fs.ns) |
eff596da | 1127 | return -EOPNOTSUPP; |
86d722ad | 1128 | |
1cabe6b0 MG |
1129 | err = mlx5e_arfs_create_tables(priv); |
1130 | if (err) { | |
1131 | netdev_err(priv->netdev, "Failed to create arfs tables, err=%d\n", | |
1132 | err); | |
1133 | priv->netdev->hw_features &= ~NETIF_F_NTUPLE; | |
1134 | } | |
1135 | ||
33cfaaa8 MG |
1136 | err = mlx5e_create_ttc_table(priv); |
1137 | if (err) { | |
1138 | netdev_err(priv->netdev, "Failed to create ttc table, err=%d\n", | |
1139 | err); | |
1cabe6b0 | 1140 | goto err_destroy_arfs_tables; |
33cfaaa8 MG |
1141 | } |
1142 | ||
1143 | err = mlx5e_create_l2_table(priv); | |
1144 | if (err) { | |
1145 | netdev_err(priv->netdev, "Failed to create l2 table, err=%d\n", | |
1146 | err); | |
1147 | goto err_destroy_ttc_table; | |
1148 | } | |
afb736e9 | 1149 | |
acff797c | 1150 | err = mlx5e_create_vlan_table(priv); |
33cfaaa8 MG |
1151 | if (err) { |
1152 | netdev_err(priv->netdev, "Failed to create vlan table, err=%d\n", | |
1153 | err); | |
1154 | goto err_destroy_l2_table; | |
1155 | } | |
9b37b07f | 1156 | |
6dc6071c MG |
1157 | mlx5e_ethtool_init_steering(priv); |
1158 | ||
afb736e9 AV |
1159 | return 0; |
1160 | ||
33cfaaa8 MG |
1161 | err_destroy_l2_table: |
1162 | mlx5e_destroy_l2_table(priv); | |
1163 | err_destroy_ttc_table: | |
1164 | mlx5e_destroy_ttc_table(priv); | |
1cabe6b0 MG |
1165 | err_destroy_arfs_tables: |
1166 | mlx5e_arfs_destroy_tables(priv); | |
afb736e9 AV |
1167 | |
1168 | return err; | |
1169 | } | |
1170 | ||
acff797c | 1171 | void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv) |
afb736e9 | 1172 | { |
acff797c | 1173 | mlx5e_destroy_vlan_table(priv); |
33cfaaa8 MG |
1174 | mlx5e_destroy_l2_table(priv); |
1175 | mlx5e_destroy_ttc_table(priv); | |
1cabe6b0 | 1176 | mlx5e_arfs_destroy_tables(priv); |
6dc6071c | 1177 | mlx5e_ethtool_cleanup_steering(priv); |
afb736e9 | 1178 | } |