]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c
Add mlx5 and mlx5en driver(s) for ConnectX-4 and ConnectX-4LX cards
[FreeBSD/FreeBSD.git] / sys / dev / mlx5 / mlx5_en / mlx5_en_flow_table.c
1 /*-
2  * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 #include "en.h"
29
30 #include <linux/list.h>
31 #include <dev/mlx5/flow_table.h>
32
33 enum {
34         MLX5E_FULLMATCH = 0,
35         MLX5E_ALLMULTI = 1,
36         MLX5E_PROMISC = 2,
37 };
38
39 enum {
40         MLX5E_UC = 0,
41         MLX5E_MC_IPV4 = 1,
42         MLX5E_MC_IPV6 = 2,
43         MLX5E_MC_OTHER = 3,
44 };
45
46 enum {
47         MLX5E_ACTION_NONE = 0,
48         MLX5E_ACTION_ADD = 1,
49         MLX5E_ACTION_DEL = 2,
50 };
51
52 struct mlx5e_eth_addr_hash_node {
53         LIST_ENTRY(mlx5e_eth_addr_hash_node) hlist;
54         u8      action;
55         struct mlx5e_eth_addr_info ai;
56 };
57
58 static inline int
59 mlx5e_hash_eth_addr(const u8 * addr)
60 {
61         return (addr[5]);
62 }
63
64 static void
65 mlx5e_add_eth_addr_to_hash(struct mlx5e_eth_addr_hash_head *hash,
66     const u8 * addr)
67 {
68         struct mlx5e_eth_addr_hash_node *hn;
69         int ix = mlx5e_hash_eth_addr(addr);
70
71         LIST_FOREACH(hn, &hash[ix], hlist) {
72                 if (bcmp(hn->ai.addr, addr, ETHER_ADDR_LEN) == 0) {
73                         if (hn->action == MLX5E_ACTION_DEL)
74                                 hn->action = MLX5E_ACTION_NONE;
75                         return;
76                 }
77         }
78
79         hn = malloc(sizeof(*hn), M_MLX5EN, M_NOWAIT | M_ZERO);
80         if (hn == NULL)
81                 return;
82
83         ether_addr_copy(hn->ai.addr, addr);
84         hn->action = MLX5E_ACTION_ADD;
85
86         LIST_INSERT_HEAD(&hash[ix], hn, hlist);
87 }
88
89 static void
90 mlx5e_del_eth_addr_from_hash(struct mlx5e_eth_addr_hash_node *hn)
91 {
92         LIST_REMOVE(hn, hlist);
93         free(hn, M_MLX5EN);
94 }
95
96 static void
97 mlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv,
98     struct mlx5e_eth_addr_info *ai)
99 {
100         void *ft = priv->ft.main;
101
102         if (ai->tt_vec & (1 << MLX5E_TT_IPV6_TCP))
103                 mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]);
104
105         if (ai->tt_vec & (1 << MLX5E_TT_IPV4_TCP))
106                 mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_TCP]);
107
108         if (ai->tt_vec & (1 << MLX5E_TT_IPV6_UDP))
109                 mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_UDP]);
110
111         if (ai->tt_vec & (1 << MLX5E_TT_IPV4_UDP))
112                 mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_UDP]);
113
114         if (ai->tt_vec & (1 << MLX5E_TT_IPV6))
115                 mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6]);
116
117         if (ai->tt_vec & (1 << MLX5E_TT_IPV4))
118                 mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4]);
119
120         if (ai->tt_vec & (1 << MLX5E_TT_ANY))
121                 mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_ANY]);
122 }
123
124 static int
125 mlx5e_get_eth_addr_type(const u8 * addr)
126 {
127         if (ETHER_IS_MULTICAST(addr) == 0)
128                 return (MLX5E_UC);
129
130         if ((addr[0] == 0x01) &&
131             (addr[1] == 0x00) &&
132             (addr[2] == 0x5e) &&
133             !(addr[3] & 0x80))
134                 return (MLX5E_MC_IPV4);
135
136         if ((addr[0] == 0x33) &&
137             (addr[1] == 0x33))
138                 return (MLX5E_MC_IPV6);
139
140         return (MLX5E_MC_OTHER);
141 }
142
143 static  u32
144 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type)
145 {
146         int eth_addr_type;
147         u32 ret;
148
149         switch (type) {
150         case MLX5E_FULLMATCH:
151                 eth_addr_type = mlx5e_get_eth_addr_type(ai->addr);
152                 switch (eth_addr_type) {
153                 case MLX5E_UC:
154                         ret =
155                             (1 << MLX5E_TT_IPV4_TCP) |
156                             (1 << MLX5E_TT_IPV6_TCP) |
157                             (1 << MLX5E_TT_IPV4_UDP) |
158                             (1 << MLX5E_TT_IPV6_UDP) |
159                             (1 << MLX5E_TT_IPV4) |
160                             (1 << MLX5E_TT_IPV6) |
161                             (1 << MLX5E_TT_ANY) |
162                             0;
163                         break;
164
165                 case MLX5E_MC_IPV4:
166                         ret =
167                             (1 << MLX5E_TT_IPV4_UDP) |
168                             (1 << MLX5E_TT_IPV4) |
169                             0;
170                         break;
171
172                 case MLX5E_MC_IPV6:
173                         ret =
174                             (1 << MLX5E_TT_IPV6_UDP) |
175                             (1 << MLX5E_TT_IPV6) |
176                             0;
177                         break;
178
179                 default:
180                         ret =
181                             (1 << MLX5E_TT_ANY) |
182                             0;
183                         break;
184                 }
185                 break;
186
187         case MLX5E_ALLMULTI:
188                 ret =
189                     (1 << MLX5E_TT_IPV4_UDP) |
190                     (1 << MLX5E_TT_IPV6_UDP) |
191                     (1 << MLX5E_TT_IPV4) |
192                     (1 << MLX5E_TT_IPV6) |
193                     (1 << MLX5E_TT_ANY) |
194                     0;
195                 break;
196
197         default:                        /* MLX5E_PROMISC */
198                 ret =
199                     (1 << MLX5E_TT_IPV4_TCP) |
200                     (1 << MLX5E_TT_IPV6_TCP) |
201                     (1 << MLX5E_TT_IPV4_UDP) |
202                     (1 << MLX5E_TT_IPV6_UDP) |
203                     (1 << MLX5E_TT_IPV4) |
204                     (1 << MLX5E_TT_IPV6) |
205                     (1 << MLX5E_TT_ANY) |
206                     0;
207                 break;
208         }
209
210         return (ret);
211 }
212
213 static int
214 mlx5e_add_eth_addr_rule_sub(struct mlx5e_priv *priv,
215     struct mlx5e_eth_addr_info *ai, int type,
216     void *flow_context, void *match_criteria)
217 {
218         u8 match_criteria_enable = 0;
219         void *match_value;
220         void *dest;
221         u8 *dmac;
222         u8 *match_criteria_dmac;
223         void *ft = priv->ft.main;
224         u32 *tirn = priv->tirn;
225         u32 tt_vec;
226         int err;
227
228         match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
229         dmac = MLX5_ADDR_OF(fte_match_param, match_value,
230             outer_headers.dmac_47_16);
231         match_criteria_dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
232             outer_headers.dmac_47_16);
233         dest = MLX5_ADDR_OF(flow_context, flow_context, destination);
234
235         MLX5_SET(flow_context, flow_context, action,
236             MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
237         MLX5_SET(flow_context, flow_context, destination_list_size, 1);
238         MLX5_SET(dest_format_struct, dest, destination_type,
239             MLX5_FLOW_CONTEXT_DEST_TYPE_TIR);
240
241         switch (type) {
242         case MLX5E_FULLMATCH:
243                 match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
244                 memset(match_criteria_dmac, 0xff, ETH_ALEN);
245                 ether_addr_copy(dmac, ai->addr);
246                 break;
247
248         case MLX5E_ALLMULTI:
249                 match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
250                 match_criteria_dmac[0] = 0x01;
251                 dmac[0] = 0x01;
252                 break;
253
254         case MLX5E_PROMISC:
255                 break;
256         default:
257                 break;
258         }
259
260         tt_vec = mlx5e_get_tt_vec(ai, type);
261
262         if (tt_vec & (1 << MLX5E_TT_ANY)) {
263                 MLX5_SET(dest_format_struct, dest, destination_id,
264                     tirn[MLX5E_TT_ANY]);
265                 err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
266                     match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_ANY]);
267                 if (err) {
268                         mlx5e_del_eth_addr_from_flow_table(priv, ai);
269                         return (err);
270                 }
271                 ai->tt_vec |= (1 << MLX5E_TT_ANY);
272         }
273
274         match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
275         MLX5_SET_TO_ONES(fte_match_param, match_criteria,
276             outer_headers.ethertype);
277
278         if (tt_vec & (1 << MLX5E_TT_IPV4)) {
279                 MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
280                     ETHERTYPE_IP);
281                 MLX5_SET(dest_format_struct, dest, destination_id,
282                     tirn[MLX5E_TT_IPV4]);
283                 err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
284                     match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4]);
285                 if (err) {
286                         mlx5e_del_eth_addr_from_flow_table(priv, ai);
287                         return (err);
288                 }
289                 ai->tt_vec |= (1 << MLX5E_TT_IPV4);
290         }
291
292         if (tt_vec & (1 << MLX5E_TT_IPV6)) {
293                 MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
294                     ETHERTYPE_IPV6);
295                 MLX5_SET(dest_format_struct, dest, destination_id,
296                     tirn[MLX5E_TT_IPV6]);
297                 err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
298                     match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6]);
299                 if (err) {
300                         mlx5e_del_eth_addr_from_flow_table(priv, ai);
301                         return (err);
302                 }
303                 ai->tt_vec |= (1 << MLX5E_TT_IPV6);
304         }
305         MLX5_SET_TO_ONES(fte_match_param, match_criteria,
306             outer_headers.ip_protocol);
307         MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol,
308             IPPROTO_UDP);
309
310         if (tt_vec & (1 << MLX5E_TT_IPV4_UDP)) {
311                 MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
312                     ETHERTYPE_IP);
313                 MLX5_SET(dest_format_struct, dest, destination_id,
314                     tirn[MLX5E_TT_IPV4_UDP]);
315                 err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
316                     match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4_UDP]);
317                 if (err) {
318                         mlx5e_del_eth_addr_from_flow_table(priv, ai);
319                         return (err);
320                 }
321                 ai->tt_vec |= (1 << MLX5E_TT_IPV4_UDP);
322         }
323         if (tt_vec & (1 << MLX5E_TT_IPV6_UDP)) {
324                 MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
325                     ETHERTYPE_IPV6);
326                 MLX5_SET(dest_format_struct, dest, destination_id,
327                     tirn[MLX5E_TT_IPV6_UDP]);
328                 err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
329                     match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6_UDP]);
330                 if (err) {
331                         mlx5e_del_eth_addr_from_flow_table(priv, ai);
332                         return (err);
333                 }
334                 ai->tt_vec |= (1 << MLX5E_TT_IPV6_UDP);
335         }
336         MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol,
337             IPPROTO_TCP);
338
339         if (tt_vec & (1 << MLX5E_TT_IPV4_TCP)) {
340                 MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
341                     ETHERTYPE_IP);
342                 MLX5_SET(dest_format_struct, dest, destination_id,
343                     tirn[MLX5E_TT_IPV4_TCP]);
344                 err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
345                     match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4_TCP]);
346                 if (err) {
347                         mlx5e_del_eth_addr_from_flow_table(priv, ai);
348                         return (err);
349                 }
350                 ai->tt_vec |= (1 << MLX5E_TT_IPV4_TCP);
351         }
352         if (tt_vec & (1 << MLX5E_TT_IPV6_TCP)) {
353                 MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
354                     ETHERTYPE_IPV6);
355                 MLX5_SET(dest_format_struct, dest, destination_id,
356                     tirn[MLX5E_TT_IPV6_TCP]);
357                 err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
358                     match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6_TCP]);
359                 if (err) {
360                         mlx5e_del_eth_addr_from_flow_table(priv, ai);
361                         return (err);
362                 }
363                 ai->tt_vec |= (1 << MLX5E_TT_IPV6_TCP);
364         }
365         return (0);
366 }
367
368 static int
369 mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv,
370     struct mlx5e_eth_addr_info *ai, int type)
371 {
372         u32 *flow_context;
373         u32 *match_criteria;
374         int err;
375
376         flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) +
377             MLX5_ST_SZ_BYTES(dest_format_struct));
378         match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
379         if (!flow_context || !match_criteria) {
380                 if_printf(priv->ifp, "%s: alloc failed\n", __func__);
381                 err = -ENOMEM;
382                 goto add_eth_addr_rule_out;
383         }
384
385         err = mlx5e_add_eth_addr_rule_sub(priv, ai, type, flow_context,
386             match_criteria);
387         if (err)
388                 if_printf(priv->ifp, "%s: failed\n", __func__);
389
390 add_eth_addr_rule_out:
391         kvfree(match_criteria);
392         kvfree(flow_context);
393         return (err);
394 }
395
396 enum mlx5e_vlan_rule_type {
397         MLX5E_VLAN_RULE_TYPE_UNTAGGED,
398         MLX5E_VLAN_RULE_TYPE_ANY_VID,
399         MLX5E_VLAN_RULE_TYPE_MATCH_VID,
400 };
401
402 static int
403 mlx5e_add_vlan_rule(struct mlx5e_priv *priv,
404     enum mlx5e_vlan_rule_type rule_type, u16 vid)
405 {
406         u8 match_criteria_enable = 0;
407         u32 *flow_context;
408         void *match_value;
409         void *dest;
410         u32 *match_criteria;
411         u32 *ft_ix;
412         int err;
413
414         flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) +
415             MLX5_ST_SZ_BYTES(dest_format_struct));
416         match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
417         if (!flow_context || !match_criteria) {
418                 if_printf(priv->ifp, "%s: alloc failed\n", __func__);
419                 err = -ENOMEM;
420                 goto add_vlan_rule_out;
421         }
422         match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
423         dest = MLX5_ADDR_OF(flow_context, flow_context, destination);
424
425         MLX5_SET(flow_context, flow_context, action,
426                  MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
427         MLX5_SET(flow_context, flow_context, destination_list_size, 1);
428         MLX5_SET(dest_format_struct, dest, destination_type,
429                  MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE);
430         MLX5_SET(dest_format_struct, dest, destination_id,
431                  mlx5_get_flow_table_id(priv->ft.main));
432
433         match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
434         MLX5_SET_TO_ONES(fte_match_param, match_criteria,
435             outer_headers.vlan_tag);
436
437         switch (rule_type) {
438         case MLX5E_VLAN_RULE_TYPE_UNTAGGED:
439                 ft_ix = &priv->vlan.untagged_rule_ft_ix;
440                 break;
441         case MLX5E_VLAN_RULE_TYPE_ANY_VID:
442                 ft_ix = &priv->vlan.any_vlan_rule_ft_ix;
443                 MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag,
444                     1);
445                 break;
446         default:                        /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */
447                 ft_ix = &priv->vlan.active_vlans_ft_ix[vid];
448                 MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag,
449                     1);
450                 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
451                     outer_headers.first_vid);
452                 MLX5_SET(fte_match_param, match_value, outer_headers.first_vid,
453                     vid);
454                 break;
455         }
456
457         err = mlx5_add_flow_table_entry(priv->ft.vlan, match_criteria_enable,
458             match_criteria, flow_context, ft_ix);
459         if (err)
460                 if_printf(priv->ifp, "%s: failed\n", __func__);
461
462 add_vlan_rule_out:
463         kvfree(match_criteria);
464         kvfree(flow_context);
465         return (err);
466 }
467
468 static void
469 mlx5e_del_vlan_rule(struct mlx5e_priv *priv,
470     enum mlx5e_vlan_rule_type rule_type, u16 vid)
471 {
472         switch (rule_type) {
473         case MLX5E_VLAN_RULE_TYPE_UNTAGGED:
474                 mlx5_del_flow_table_entry(priv->ft.vlan,
475                     priv->vlan.untagged_rule_ft_ix);
476                 break;
477         case MLX5E_VLAN_RULE_TYPE_ANY_VID:
478                 mlx5_del_flow_table_entry(priv->ft.vlan,
479                     priv->vlan.any_vlan_rule_ft_ix);
480                 break;
481         case MLX5E_VLAN_RULE_TYPE_MATCH_VID:
482                 mlx5_del_flow_table_entry(priv->ft.vlan,
483                     priv->vlan.active_vlans_ft_ix[vid]);
484                 break;
485         }
486 }
487
488 void
489 mlx5e_enable_vlan_filter(struct mlx5e_priv *priv)
490 {
491         if (priv->vlan.filter_disabled) {
492                 priv->vlan.filter_disabled = false;
493                 if (test_bit(MLX5E_STATE_OPENED, &priv->state))
494                         mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
495                             0);
496         }
497 }
498
499 void
500 mlx5e_disable_vlan_filter(struct mlx5e_priv *priv)
501 {
502         if (!priv->vlan.filter_disabled) {
503                 priv->vlan.filter_disabled = true;
504                 if (test_bit(MLX5E_STATE_OPENED, &priv->state))
505                         mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
506                             0);
507         }
508 }
509
510 void
511 mlx5e_vlan_rx_add_vid(void *arg, struct ifnet *ifp, u16 vid)
512 {
513         struct mlx5e_priv *priv = arg;
514
515         if (ifp != priv->ifp)
516                 return;
517
518         PRIV_LOCK(priv);
519         set_bit(vid, priv->vlan.active_vlans);
520         if (test_bit(MLX5E_STATE_OPENED, &priv->state))
521                 mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
522         PRIV_UNLOCK(priv);
523 }
524
525 void
526 mlx5e_vlan_rx_kill_vid(void *arg, struct ifnet *ifp, u16 vid)
527 {
528         struct mlx5e_priv *priv = arg;
529
530         if (ifp != priv->ifp)
531                 return;
532
533         PRIV_LOCK(priv);
534         clear_bit(vid, priv->vlan.active_vlans);
535         if (test_bit(MLX5E_STATE_OPENED, &priv->state))
536                 mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
537         PRIV_UNLOCK(priv);
538 }
539
540 int
541 mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv)
542 {
543         u16 vid;
544         int err;
545
546         for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) {
547                 err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID,
548                     vid);
549                 if (err)
550                         return (err);
551         }
552
553         err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
554         if (err)
555                 return (err);
556
557         if (priv->vlan.filter_disabled) {
558                 err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
559                     0);
560                 if (err)
561                         return (err);
562         }
563         return (0);
564 }
565
566 void
567 mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv)
568 {
569         u16 vid;
570
571         if (priv->vlan.filter_disabled)
572                 mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0);
573
574         mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
575
576         for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID)
577             mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
578 }
579
580 #define mlx5e_for_each_hash_node(hn, tmp, hash, i) \
581         for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \
582                 LIST_FOREACH_SAFE(hn, &(hash)[i], hlist, tmp)
583
584 static void
585 mlx5e_execute_action(struct mlx5e_priv *priv,
586     struct mlx5e_eth_addr_hash_node *hn)
587 {
588         switch (hn->action) {
589         case MLX5E_ACTION_ADD:
590                 mlx5e_add_eth_addr_rule(priv, &hn->ai, MLX5E_FULLMATCH);
591                 hn->action = MLX5E_ACTION_NONE;
592                 break;
593
594         case MLX5E_ACTION_DEL:
595                 mlx5e_del_eth_addr_from_flow_table(priv, &hn->ai);
596                 mlx5e_del_eth_addr_from_hash(hn);
597                 break;
598
599         default:
600                 break;
601         }
602 }
603
604 static void
605 mlx5e_sync_ifp_addr(struct mlx5e_priv *priv)
606 {
607         struct ifnet *ifp = priv->ifp;
608         struct ifaddr *ifa;
609         struct ifmultiaddr *ifma;
610
611         /* XXX adding this entry might not be needed */
612         mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_uc,
613             LLADDR((struct sockaddr_dl *)(ifp->if_addr->ifa_addr)));
614
615         if_addr_rlock(ifp);
616         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
617                 if (ifa->ifa_addr->sa_family != AF_LINK)
618                         continue;
619                 mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_uc,
620                     LLADDR((struct sockaddr_dl *)ifa->ifa_addr));
621         }
622         if_addr_runlock(ifp);
623
624         if_maddr_rlock(ifp);
625         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
626                 if (ifma->ifma_addr->sa_family != AF_LINK)
627                         continue;
628                 mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_mc,
629                     LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
630         }
631         if_maddr_runlock(ifp);
632 }
633
634 static void
635 mlx5e_apply_ifp_addr(struct mlx5e_priv *priv)
636 {
637         struct mlx5e_eth_addr_hash_node *hn;
638         struct mlx5e_eth_addr_hash_node *tmp;
639         int i;
640
641         mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_uc, i)
642             mlx5e_execute_action(priv, hn);
643
644         mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_mc, i)
645             mlx5e_execute_action(priv, hn);
646 }
647
648 static void
649 mlx5e_handle_ifp_addr(struct mlx5e_priv *priv)
650 {
651         struct mlx5e_eth_addr_hash_node *hn;
652         struct mlx5e_eth_addr_hash_node *tmp;
653         int i;
654
655         mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_uc, i)
656             hn->action = MLX5E_ACTION_DEL;
657         mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_mc, i)
658             hn->action = MLX5E_ACTION_DEL;
659
660         if (test_bit(MLX5E_STATE_OPENED, &priv->state))
661                 mlx5e_sync_ifp_addr(priv);
662
663         mlx5e_apply_ifp_addr(priv);
664 }
665
666 void
667 mlx5e_set_rx_mode_core(struct mlx5e_priv *priv)
668 {
669         struct mlx5e_eth_addr_db *ea = &priv->eth_addr;
670         struct ifnet *ndev = priv->ifp;
671
672         bool rx_mode_enable = test_bit(MLX5E_STATE_OPENED, &priv->state);
673         bool promisc_enabled = rx_mode_enable && (ndev->if_flags & IFF_PROMISC);
674         bool allmulti_enabled = rx_mode_enable && (ndev->if_flags & IFF_ALLMULTI);
675         bool broadcast_enabled = rx_mode_enable;
676
677         bool enable_promisc = !ea->promisc_enabled && promisc_enabled;
678         bool disable_promisc = ea->promisc_enabled && !promisc_enabled;
679         bool enable_allmulti = !ea->allmulti_enabled && allmulti_enabled;
680         bool disable_allmulti = ea->allmulti_enabled && !allmulti_enabled;
681         bool enable_broadcast = !ea->broadcast_enabled && broadcast_enabled;
682         bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled;
683
684         /* update broadcast address */
685         ether_addr_copy(priv->eth_addr.broadcast.addr,
686             priv->ifp->if_broadcastaddr);
687
688         if (enable_promisc)
689                 mlx5e_add_eth_addr_rule(priv, &ea->promisc, MLX5E_PROMISC);
690         if (enable_allmulti)
691                 mlx5e_add_eth_addr_rule(priv, &ea->allmulti, MLX5E_ALLMULTI);
692         if (enable_broadcast)
693                 mlx5e_add_eth_addr_rule(priv, &ea->broadcast, MLX5E_FULLMATCH);
694
695         mlx5e_handle_ifp_addr(priv);
696
697         if (disable_broadcast)
698                 mlx5e_del_eth_addr_from_flow_table(priv, &ea->broadcast);
699         if (disable_allmulti)
700                 mlx5e_del_eth_addr_from_flow_table(priv, &ea->allmulti);
701         if (disable_promisc)
702                 mlx5e_del_eth_addr_from_flow_table(priv, &ea->promisc);
703
704         ea->promisc_enabled = promisc_enabled;
705         ea->allmulti_enabled = allmulti_enabled;
706         ea->broadcast_enabled = broadcast_enabled;
707 }
708
709 void
710 mlx5e_set_rx_mode_work(struct work_struct *work)
711 {
712         struct mlx5e_priv *priv =
713             container_of(work, struct mlx5e_priv, set_rx_mode_work);
714
715         PRIV_LOCK(priv);
716         if (test_bit(MLX5E_STATE_OPENED, &priv->state))
717                 mlx5e_set_rx_mode_core(priv);
718         PRIV_UNLOCK(priv);
719 }
720
721 static int
722 mlx5e_create_main_flow_table(struct mlx5e_priv *priv)
723 {
724         struct mlx5_flow_table_group *g;
725         u8 *dmac;
726
727         g = malloc(9 * sizeof(*g), M_MLX5EN, M_WAITOK | M_ZERO);
728         if (g == NULL)
729                 return (-ENOMEM);
730
731         g[0].log_sz = 2;
732         g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
733         MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
734             outer_headers.ethertype);
735         MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
736             outer_headers.ip_protocol);
737
738         g[1].log_sz = 1;
739         g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
740         MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria,
741             outer_headers.ethertype);
742
743         g[2].log_sz = 0;
744
745         g[3].log_sz = 14;
746         g[3].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
747         dmac = MLX5_ADDR_OF(fte_match_param, g[3].match_criteria,
748             outer_headers.dmac_47_16);
749         memset(dmac, 0xff, ETH_ALEN);
750         MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria,
751             outer_headers.ethertype);
752         MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria,
753             outer_headers.ip_protocol);
754
755         g[4].log_sz = 13;
756         g[4].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
757         dmac = MLX5_ADDR_OF(fte_match_param, g[4].match_criteria,
758             outer_headers.dmac_47_16);
759         memset(dmac, 0xff, ETH_ALEN);
760         MLX5_SET_TO_ONES(fte_match_param, g[4].match_criteria,
761             outer_headers.ethertype);
762
763         g[5].log_sz = 11;
764         g[5].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
765         dmac = MLX5_ADDR_OF(fte_match_param, g[5].match_criteria,
766             outer_headers.dmac_47_16);
767         memset(dmac, 0xff, ETH_ALEN);
768
769         g[6].log_sz = 2;
770         g[6].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
771         dmac = MLX5_ADDR_OF(fte_match_param, g[6].match_criteria,
772             outer_headers.dmac_47_16);
773         dmac[0] = 0x01;
774         MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria,
775             outer_headers.ethertype);
776         MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria,
777             outer_headers.ip_protocol);
778
779         g[7].log_sz = 1;
780         g[7].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
781         dmac = MLX5_ADDR_OF(fte_match_param, g[7].match_criteria,
782             outer_headers.dmac_47_16);
783         dmac[0] = 0x01;
784         MLX5_SET_TO_ONES(fte_match_param, g[7].match_criteria,
785             outer_headers.ethertype);
786
787         g[8].log_sz = 0;
788         g[8].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
789         dmac = MLX5_ADDR_OF(fte_match_param, g[8].match_criteria,
790             outer_headers.dmac_47_16);
791         dmac[0] = 0x01;
792         priv->ft.main = mlx5_create_flow_table(priv->mdev, 1,
793             MLX5_FLOW_TABLE_TYPE_NIC_RCV,
794             0, 9, g);
795         free(g, M_MLX5EN);
796
797         return (priv->ft.main ? 0 : -ENOMEM);
798 }
799
800 static void
801 mlx5e_destroy_main_flow_table(struct mlx5e_priv *priv)
802 {
803         mlx5_destroy_flow_table(priv->ft.main);
804         priv->ft.main = NULL;
805 }
806
807 static int
808 mlx5e_create_vlan_flow_table(struct mlx5e_priv *priv)
809 {
810         struct mlx5_flow_table_group *g;
811
812         g = malloc(2 * sizeof(*g), M_MLX5EN, M_WAITOK | M_ZERO);
813         if (g == NULL)
814                 return (-ENOMEM);
815
816         g[0].log_sz = 12;
817         g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
818         MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
819             outer_headers.vlan_tag);
820         MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
821             outer_headers.first_vid);
822
823         /* untagged + any vlan id */
824         g[1].log_sz = 1;
825         g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
826         MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria,
827             outer_headers.vlan_tag);
828
829         priv->ft.vlan = mlx5_create_flow_table(priv->mdev, 0,
830             MLX5_FLOW_TABLE_TYPE_NIC_RCV,
831             0, 2, g);
832         free(g, M_MLX5EN);
833
834         return (priv->ft.vlan ? 0 : -ENOMEM);
835 }
836
837 static void
838 mlx5e_destroy_vlan_flow_table(struct mlx5e_priv *priv)
839 {
840         mlx5_destroy_flow_table(priv->ft.vlan);
841         priv->ft.vlan = NULL;
842 }
843
844 int
845 mlx5e_open_flow_table(struct mlx5e_priv *priv)
846 {
847         int err;
848
849         err = mlx5e_create_main_flow_table(priv);
850         if (err)
851                 return (err);
852
853         err = mlx5e_create_vlan_flow_table(priv);
854         if (err)
855                 goto err_destroy_main_flow_table;
856
857         return (0);
858
859 err_destroy_main_flow_table:
860         mlx5e_destroy_main_flow_table(priv);
861
862         return (err);
863 }
864
865 void
866 mlx5e_close_flow_table(struct mlx5e_priv *priv)
867 {
868         mlx5e_destroy_vlan_flow_table(priv);
869         mlx5e_destroy_main_flow_table(priv);
870 }