net/mlx5: E-Switch, Add promiscuous and allmulti FDB flowtable groups
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch.c
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/etherdevice.h>
34 #include <linux/mlx5/driver.h>
35 #include <linux/mlx5/mlx5_ifc.h>
36 #include <linux/mlx5/vport.h>
37 #include <linux/mlx5/fs.h>
38 #include "mlx5_core.h"
39 #include "eswitch.h"
40
41 #define UPLINK_VPORT 0xFFFF
42
43 #define MLX5_DEBUG_ESWITCH_MASK BIT(3)
44
45 #define esw_info(dev, format, ...)                              \
46         pr_info("(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
47
48 #define esw_warn(dev, format, ...)                              \
49         pr_warn("(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
50
51 #define esw_debug(dev, format, ...)                             \
52         mlx5_core_dbg_mask(dev, MLX5_DEBUG_ESWITCH_MASK, format, ##__VA_ARGS__)
53
54 enum {
55         MLX5_ACTION_NONE = 0,
56         MLX5_ACTION_ADD  = 1,
57         MLX5_ACTION_DEL  = 2,
58 };
59
60 /* E-Switch UC L2 table hash node */
61 struct esw_uc_addr {
62         struct l2addr_node node;
63         u32                table_index;
64         u32                vport;
65 };
66
67 /* E-Switch MC FDB table hash node */
68 struct esw_mc_addr { /* SRIOV only */
69         struct l2addr_node     node;
70         struct mlx5_flow_rule *uplink_rule; /* Forward to uplink rule */
71         u32                    refcnt;
72 };
73
74 /* Vport UC/MC hash node */
75 struct vport_addr {
76         struct l2addr_node     node;
77         u8                     action;
78         u32                    vport;
79         struct mlx5_flow_rule *flow_rule; /* SRIOV only */
80 };
81
82 enum {
83         UC_ADDR_CHANGE = BIT(0),
84         MC_ADDR_CHANGE = BIT(1),
85 };
86
87 /* Vport context events */
88 #define SRIOV_VPORT_EVENTS (UC_ADDR_CHANGE | \
89                             MC_ADDR_CHANGE)
90
91 static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,
92                                         u32 events_mask)
93 {
94         int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)];
95         int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)];
96         void *nic_vport_ctx;
97         int err;
98
99         memset(out, 0, sizeof(out));
100         memset(in, 0, sizeof(in));
101
102         MLX5_SET(modify_nic_vport_context_in, in,
103                  opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
104         MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1);
105         MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
106         if (vport)
107                 MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
108         nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
109                                      in, nic_vport_context);
110
111         MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1);
112
113         if (events_mask & UC_ADDR_CHANGE)
114                 MLX5_SET(nic_vport_context, nic_vport_ctx,
115                          event_on_uc_address_change, 1);
116         if (events_mask & MC_ADDR_CHANGE)
117                 MLX5_SET(nic_vport_context, nic_vport_ctx,
118                          event_on_mc_address_change, 1);
119
120         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
121         if (err)
122                 goto ex;
123         err = mlx5_cmd_status_to_err_v2(out);
124         if (err)
125                 goto ex;
126         return 0;
127 ex:
128         return err;
129 }
130
131 /* E-Switch vport context HW commands */
132 static int query_esw_vport_context_cmd(struct mlx5_core_dev *mdev, u32 vport,
133                                        u32 *out, int outlen)
134 {
135         u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)];
136
137         memset(in, 0, sizeof(in));
138
139         MLX5_SET(query_nic_vport_context_in, in, opcode,
140                  MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
141
142         MLX5_SET(query_esw_vport_context_in, in, vport_number, vport);
143         if (vport)
144                 MLX5_SET(query_esw_vport_context_in, in, other_vport, 1);
145
146         return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen);
147 }
148
149 static int query_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
150                                  u16 *vlan, u8 *qos)
151 {
152         u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)];
153         int err;
154         bool cvlan_strip;
155         bool cvlan_insert;
156
157         memset(out, 0, sizeof(out));
158
159         *vlan = 0;
160         *qos = 0;
161
162         if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
163             !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
164                 return -ENOTSUPP;
165
166         err = query_esw_vport_context_cmd(dev, vport, out, sizeof(out));
167         if (err)
168                 goto out;
169
170         cvlan_strip = MLX5_GET(query_esw_vport_context_out, out,
171                                esw_vport_context.vport_cvlan_strip);
172
173         cvlan_insert = MLX5_GET(query_esw_vport_context_out, out,
174                                 esw_vport_context.vport_cvlan_insert);
175
176         if (cvlan_strip || cvlan_insert) {
177                 *vlan = MLX5_GET(query_esw_vport_context_out, out,
178                                  esw_vport_context.cvlan_id);
179                 *qos = MLX5_GET(query_esw_vport_context_out, out,
180                                 esw_vport_context.cvlan_pcp);
181         }
182
183         esw_debug(dev, "Query Vport[%d] cvlan: VLAN %d qos=%d\n",
184                   vport, *vlan, *qos);
185 out:
186         return err;
187 }
188
189 static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport,
190                                         void *in, int inlen)
191 {
192         u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)];
193
194         memset(out, 0, sizeof(out));
195
196         MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
197         if (vport)
198                 MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1);
199
200         MLX5_SET(modify_esw_vport_context_in, in, opcode,
201                  MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);
202
203         return mlx5_cmd_exec_check_status(dev, in, inlen,
204                                           out, sizeof(out));
205 }
206
207 static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
208                                   u16 vlan, u8 qos, bool set)
209 {
210         u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)];
211
212         memset(in, 0, sizeof(in));
213
214         if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
215             !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
216                 return -ENOTSUPP;
217
218         esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%d\n",
219                   vport, vlan, qos, set);
220
221         if (set) {
222                 MLX5_SET(modify_esw_vport_context_in, in,
223                          esw_vport_context.vport_cvlan_strip, 1);
224                 /* insert only if no vlan in packet */
225                 MLX5_SET(modify_esw_vport_context_in, in,
226                          esw_vport_context.vport_cvlan_insert, 1);
227                 MLX5_SET(modify_esw_vport_context_in, in,
228                          esw_vport_context.cvlan_pcp, qos);
229                 MLX5_SET(modify_esw_vport_context_in, in,
230                          esw_vport_context.cvlan_id, vlan);
231         }
232
233         MLX5_SET(modify_esw_vport_context_in, in,
234                  field_select.vport_cvlan_strip, 1);
235         MLX5_SET(modify_esw_vport_context_in, in,
236                  field_select.vport_cvlan_insert, 1);
237
238         return modify_esw_vport_context_cmd(dev, vport, in, sizeof(in));
239 }
240
241 /* HW L2 Table (MPFS) management */
242 static int set_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index,
243                                   u8 *mac, u8 vlan_valid, u16 vlan)
244 {
245         u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)];
246         u32 out[MLX5_ST_SZ_DW(set_l2_table_entry_out)];
247         u8 *in_mac_addr;
248
249         memset(in, 0, sizeof(in));
250         memset(out, 0, sizeof(out));
251
252         MLX5_SET(set_l2_table_entry_in, in, opcode,
253                  MLX5_CMD_OP_SET_L2_TABLE_ENTRY);
254         MLX5_SET(set_l2_table_entry_in, in, table_index, index);
255         MLX5_SET(set_l2_table_entry_in, in, vlan_valid, vlan_valid);
256         MLX5_SET(set_l2_table_entry_in, in, vlan, vlan);
257
258         in_mac_addr = MLX5_ADDR_OF(set_l2_table_entry_in, in, mac_address);
259         ether_addr_copy(&in_mac_addr[2], mac);
260
261         return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
262                                           out, sizeof(out));
263 }
264
265 static int del_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index)
266 {
267         u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)];
268         u32 out[MLX5_ST_SZ_DW(delete_l2_table_entry_out)];
269
270         memset(in, 0, sizeof(in));
271         memset(out, 0, sizeof(out));
272
273         MLX5_SET(delete_l2_table_entry_in, in, opcode,
274                  MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY);
275         MLX5_SET(delete_l2_table_entry_in, in, table_index, index);
276         return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
277                                           out, sizeof(out));
278 }
279
280 static int alloc_l2_table_index(struct mlx5_l2_table *l2_table, u32 *ix)
281 {
282         int err = 0;
283
284         *ix = find_first_zero_bit(l2_table->bitmap, l2_table->size);
285         if (*ix >= l2_table->size)
286                 err = -ENOSPC;
287         else
288                 __set_bit(*ix, l2_table->bitmap);
289
290         return err;
291 }
292
293 static void free_l2_table_index(struct mlx5_l2_table *l2_table, u32 ix)
294 {
295         __clear_bit(ix, l2_table->bitmap);
296 }
297
298 static int set_l2_table_entry(struct mlx5_core_dev *dev, u8 *mac,
299                               u8 vlan_valid, u16 vlan,
300                               u32 *index)
301 {
302         struct mlx5_l2_table *l2_table = &dev->priv.eswitch->l2_table;
303         int err;
304
305         err = alloc_l2_table_index(l2_table, index);
306         if (err)
307                 return err;
308
309         err = set_l2_table_entry_cmd(dev, *index, mac, vlan_valid, vlan);
310         if (err)
311                 free_l2_table_index(l2_table, *index);
312
313         return err;
314 }
315
316 static void del_l2_table_entry(struct mlx5_core_dev *dev, u32 index)
317 {
318         struct mlx5_l2_table *l2_table = &dev->priv.eswitch->l2_table;
319
320         del_l2_table_entry_cmd(dev, index);
321         free_l2_table_index(l2_table, index);
322 }
323
324 /* E-Switch FDB */
325 static struct mlx5_flow_rule *
326 __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport,
327                          u8 mac_c[ETH_ALEN], u8 mac_v[ETH_ALEN])
328 {
329         int match_header = (is_zero_ether_addr(mac_c) ? 0 :
330                             MLX5_MATCH_OUTER_HEADERS);
331         struct mlx5_flow_rule *flow_rule = NULL;
332         struct mlx5_flow_destination dest;
333         u8 *dmac_v = NULL;
334         u8 *dmac_c = NULL;
335         u32 *match_v;
336         u32 *match_c;
337
338         match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
339         match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
340         if (!match_v || !match_c) {
341                 pr_warn("FDB: Failed to alloc match parameters\n");
342                 goto out;
343         }
344
345         dmac_v = MLX5_ADDR_OF(fte_match_param, match_v,
346                               outer_headers.dmac_47_16);
347         dmac_c = MLX5_ADDR_OF(fte_match_param, match_c,
348                               outer_headers.dmac_47_16);
349
350         if (match_header == MLX5_MATCH_OUTER_HEADERS) {
351                 ether_addr_copy(dmac_v, mac_v);
352                 ether_addr_copy(dmac_c, mac_c);
353         }
354
355         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
356         dest.vport_num = vport;
357
358         esw_debug(esw->dev,
359                   "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",
360                   dmac_v, dmac_c, vport);
361         flow_rule =
362                 mlx5_add_flow_rule(esw->fdb_table.fdb,
363                                    match_header,
364                                    match_c,
365                                    match_v,
366                                    MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
367                                    0, &dest);
368         if (IS_ERR_OR_NULL(flow_rule)) {
369                 pr_warn(
370                         "FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n",
371                          dmac_v, dmac_c, vport, PTR_ERR(flow_rule));
372                 flow_rule = NULL;
373         }
374 out:
375         kfree(match_v);
376         kfree(match_c);
377         return flow_rule;
378 }
379
380 static struct mlx5_flow_rule *
381 esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u8 mac[ETH_ALEN], u32 vport)
382 {
383         u8 mac_c[ETH_ALEN];
384
385         eth_broadcast_addr(mac_c);
386         return __esw_fdb_set_vport_rule(esw, vport, mac_c, mac);
387 }
388
389 static int esw_create_fdb_table(struct mlx5_eswitch *esw, int nvports)
390 {
391         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
392         struct mlx5_core_dev *dev = esw->dev;
393         struct mlx5_flow_namespace *root_ns;
394         struct mlx5_flow_table *fdb;
395         struct mlx5_flow_group *g;
396         void *match_criteria;
397         int table_size;
398         u32 *flow_group_in;
399         u8 *dmac;
400         int err = 0;
401
402         esw_debug(dev, "Create FDB log_max_size(%d)\n",
403                   MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
404
405         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
406         if (!root_ns) {
407                 esw_warn(dev, "Failed to get FDB flow namespace\n");
408                 return -ENOMEM;
409         }
410
411         flow_group_in = mlx5_vzalloc(inlen);
412         if (!flow_group_in)
413                 return -ENOMEM;
414         memset(flow_group_in, 0, inlen);
415
416         table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
417         fdb = mlx5_create_flow_table(root_ns, 0, table_size, 0);
418         if (IS_ERR_OR_NULL(fdb)) {
419                 err = PTR_ERR(fdb);
420                 esw_warn(dev, "Failed to create FDB Table err %d\n", err);
421                 goto out;
422         }
423         esw->fdb_table.fdb = fdb;
424
425         /* Addresses group : Full match unicast/multicast addresses */
426         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
427                  MLX5_MATCH_OUTER_HEADERS);
428         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
429         dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, outer_headers.dmac_47_16);
430         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
431         /* Preserve 2 entries for allmulti and promisc rules*/
432         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 3);
433         eth_broadcast_addr(dmac);
434         g = mlx5_create_flow_group(fdb, flow_group_in);
435         if (IS_ERR_OR_NULL(g)) {
436                 err = PTR_ERR(g);
437                 esw_warn(dev, "Failed to create flow group err(%d)\n", err);
438                 goto out;
439         }
440         esw->fdb_table.addr_grp = g;
441
442         /* Allmulti group : One rule that forwards any mcast traffic */
443         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
444                  MLX5_MATCH_OUTER_HEADERS);
445         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, table_size - 2);
446         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 2);
447         eth_zero_addr(dmac);
448         dmac[0] = 0x01;
449         g = mlx5_create_flow_group(fdb, flow_group_in);
450         if (IS_ERR_OR_NULL(g)) {
451                 err = PTR_ERR(g);
452                 esw_warn(dev, "Failed to create allmulti flow group err(%d)\n", err);
453                 goto out;
454         }
455         esw->fdb_table.allmulti_grp = g;
456
457         /* Promiscuous group :
458          * One rule that forward all unmatched traffic from previous groups
459          */
460         eth_zero_addr(dmac);
461         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
462                  MLX5_MATCH_MISC_PARAMETERS);
463         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
464         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, table_size - 1);
465         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 1);
466         g = mlx5_create_flow_group(fdb, flow_group_in);
467         if (IS_ERR_OR_NULL(g)) {
468                 err = PTR_ERR(g);
469                 esw_warn(dev, "Failed to create promisc flow group err(%d)\n", err);
470                 goto out;
471         }
472         esw->fdb_table.promisc_grp = g;
473
474 out:
475         if (err) {
476                 if (!IS_ERR_OR_NULL(esw->fdb_table.allmulti_grp)) {
477                         mlx5_destroy_flow_group(esw->fdb_table.allmulti_grp);
478                         esw->fdb_table.allmulti_grp = NULL;
479                 }
480                 if (!IS_ERR_OR_NULL(esw->fdb_table.addr_grp)) {
481                         mlx5_destroy_flow_group(esw->fdb_table.addr_grp);
482                         esw->fdb_table.addr_grp = NULL;
483                 }
484                 if (!IS_ERR_OR_NULL(esw->fdb_table.fdb)) {
485                         mlx5_destroy_flow_table(esw->fdb_table.fdb);
486                         esw->fdb_table.fdb = NULL;
487                 }
488         }
489
490         kfree(flow_group_in);
491         return err;
492 }
493
494 static void esw_destroy_fdb_table(struct mlx5_eswitch *esw)
495 {
496         if (!esw->fdb_table.fdb)
497                 return;
498
499         esw_debug(esw->dev, "Destroy FDB Table\n");
500         mlx5_destroy_flow_group(esw->fdb_table.promisc_grp);
501         mlx5_destroy_flow_group(esw->fdb_table.allmulti_grp);
502         mlx5_destroy_flow_group(esw->fdb_table.addr_grp);
503         mlx5_destroy_flow_table(esw->fdb_table.fdb);
504         esw->fdb_table.fdb = NULL;
505         esw->fdb_table.addr_grp = NULL;
506         esw->fdb_table.allmulti_grp = NULL;
507         esw->fdb_table.promisc_grp = NULL;
508 }
509
510 /* E-Switch vport UC/MC lists management */
511 typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,
512                                  struct vport_addr *vaddr);
513
514 static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
515 {
516         struct hlist_head *hash = esw->l2_table.l2_hash;
517         struct esw_uc_addr *esw_uc;
518         u8 *mac = vaddr->node.addr;
519         u32 vport = vaddr->vport;
520         int err;
521
522         esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr);
523         if (esw_uc) {
524                 esw_warn(esw->dev,
525                          "Failed to set L2 mac(%pM) for vport(%d), mac is already in use by vport(%d)\n",
526                          mac, vport, esw_uc->vport);
527                 return -EEXIST;
528         }
529
530         esw_uc = l2addr_hash_add(hash, mac, struct esw_uc_addr, GFP_KERNEL);
531         if (!esw_uc)
532                 return -ENOMEM;
533         esw_uc->vport = vport;
534
535         err = set_l2_table_entry(esw->dev, mac, 0, 0, &esw_uc->table_index);
536         if (err)
537                 goto abort;
538
539         if (esw->fdb_table.fdb) /* SRIOV is enabled: Forward UC MAC to vport */
540                 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
541
542         esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM index:%d fr(%p)\n",
543                   vport, mac, esw_uc->table_index, vaddr->flow_rule);
544         return err;
545 abort:
546         l2addr_hash_del(esw_uc);
547         return err;
548 }
549
550 static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
551 {
552         struct hlist_head *hash = esw->l2_table.l2_hash;
553         struct esw_uc_addr *esw_uc;
554         u8 *mac = vaddr->node.addr;
555         u32 vport = vaddr->vport;
556
557         esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr);
558         if (!esw_uc || esw_uc->vport != vport) {
559                 esw_debug(esw->dev,
560                           "MAC(%pM) doesn't belong to vport (%d)\n",
561                           mac, vport);
562                 return -EINVAL;
563         }
564         esw_debug(esw->dev, "\tDELETE UC MAC: vport[%d] %pM index:%d fr(%p)\n",
565                   vport, mac, esw_uc->table_index, vaddr->flow_rule);
566
567         del_l2_table_entry(esw->dev, esw_uc->table_index);
568
569         if (vaddr->flow_rule)
570                 mlx5_del_flow_rule(vaddr->flow_rule);
571         vaddr->flow_rule = NULL;
572
573         l2addr_hash_del(esw_uc);
574         return 0;
575 }
576
577 static int esw_add_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
578 {
579         struct hlist_head *hash = esw->mc_table;
580         struct esw_mc_addr *esw_mc;
581         u8 *mac = vaddr->node.addr;
582         u32 vport = vaddr->vport;
583
584         if (!esw->fdb_table.fdb)
585                 return 0;
586
587         esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
588         if (esw_mc)
589                 goto add;
590
591         esw_mc = l2addr_hash_add(hash, mac, struct esw_mc_addr, GFP_KERNEL);
592         if (!esw_mc)
593                 return -ENOMEM;
594
595         esw_mc->uplink_rule = /* Forward MC MAC to Uplink */
596                 esw_fdb_set_vport_rule(esw, mac, UPLINK_VPORT);
597 add:
598         esw_mc->refcnt++;
599         /* Forward MC MAC to vport */
600         vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
601         esw_debug(esw->dev,
602                   "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
603                   vport, mac, vaddr->flow_rule,
604                   esw_mc->refcnt, esw_mc->uplink_rule);
605         return 0;
606 }
607
608 static int esw_del_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
609 {
610         struct hlist_head *hash = esw->mc_table;
611         struct esw_mc_addr *esw_mc;
612         u8 *mac = vaddr->node.addr;
613         u32 vport = vaddr->vport;
614
615         if (!esw->fdb_table.fdb)
616                 return 0;
617
618         esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
619         if (!esw_mc) {
620                 esw_warn(esw->dev,
621                          "Failed to find eswitch MC addr for MAC(%pM) vport(%d)",
622                          mac, vport);
623                 return -EINVAL;
624         }
625         esw_debug(esw->dev,
626                   "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
627                   vport, mac, vaddr->flow_rule, esw_mc->refcnt,
628                   esw_mc->uplink_rule);
629
630         if (vaddr->flow_rule)
631                 mlx5_del_flow_rule(vaddr->flow_rule);
632         vaddr->flow_rule = NULL;
633
634         if (--esw_mc->refcnt)
635                 return 0;
636
637         if (esw_mc->uplink_rule)
638                 mlx5_del_flow_rule(esw_mc->uplink_rule);
639
640         l2addr_hash_del(esw_mc);
641         return 0;
642 }
643
644 /* Apply vport UC/MC list to HW l2 table and FDB table */
645 static void esw_apply_vport_addr_list(struct mlx5_eswitch *esw,
646                                       u32 vport_num, int list_type)
647 {
648         struct mlx5_vport *vport = &esw->vports[vport_num];
649         bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
650         vport_addr_action vport_addr_add;
651         vport_addr_action vport_addr_del;
652         struct vport_addr *addr;
653         struct l2addr_node *node;
654         struct hlist_head *hash;
655         struct hlist_node *tmp;
656         int hi;
657
658         vport_addr_add = is_uc ? esw_add_uc_addr :
659                                  esw_add_mc_addr;
660         vport_addr_del = is_uc ? esw_del_uc_addr :
661                                  esw_del_mc_addr;
662
663         hash = is_uc ? vport->uc_list : vport->mc_list;
664         for_each_l2hash_node(node, tmp, hash, hi) {
665                 addr = container_of(node, struct vport_addr, node);
666                 switch (addr->action) {
667                 case MLX5_ACTION_ADD:
668                         vport_addr_add(esw, addr);
669                         addr->action = MLX5_ACTION_NONE;
670                         break;
671                 case MLX5_ACTION_DEL:
672                         vport_addr_del(esw, addr);
673                         l2addr_hash_del(addr);
674                         break;
675                 }
676         }
677 }
678
679 /* Sync vport UC/MC list from vport context */
680 static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
681                                        u32 vport_num, int list_type)
682 {
683         struct mlx5_vport *vport = &esw->vports[vport_num];
684         bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
685         u8 (*mac_list)[ETH_ALEN];
686         struct l2addr_node *node;
687         struct vport_addr *addr;
688         struct hlist_head *hash;
689         struct hlist_node *tmp;
690         int size;
691         int err;
692         int hi;
693         int i;
694
695         size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :
696                        MLX5_MAX_MC_PER_VPORT(esw->dev);
697
698         mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
699         if (!mac_list)
700                 return;
701
702         hash = is_uc ? vport->uc_list : vport->mc_list;
703
704         for_each_l2hash_node(node, tmp, hash, hi) {
705                 addr = container_of(node, struct vport_addr, node);
706                 addr->action = MLX5_ACTION_DEL;
707         }
708
709         if (!vport->enabled)
710                 goto out;
711
712         err = mlx5_query_nic_vport_mac_list(esw->dev, vport_num, list_type,
713                                             mac_list, &size);
714         if (err)
715                 goto out;
716         esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
717                   vport_num, is_uc ? "UC" : "MC", size);
718
719         for (i = 0; i < size; i++) {
720                 if (is_uc && !is_valid_ether_addr(mac_list[i]))
721                         continue;
722
723                 if (!is_uc && !is_multicast_ether_addr(mac_list[i]))
724                         continue;
725
726                 addr = l2addr_hash_find(hash, mac_list[i], struct vport_addr);
727                 if (addr) {
728                         addr->action = MLX5_ACTION_NONE;
729                         continue;
730                 }
731
732                 addr = l2addr_hash_add(hash, mac_list[i], struct vport_addr,
733                                        GFP_KERNEL);
734                 if (!addr) {
735                         esw_warn(esw->dev,
736                                  "Failed to add MAC(%pM) to vport[%d] DB\n",
737                                  mac_list[i], vport_num);
738                         continue;
739                 }
740                 addr->vport = vport_num;
741                 addr->action = MLX5_ACTION_ADD;
742         }
743 out:
744         kfree(mac_list);
745 }
746
747 static void esw_vport_change_handler(struct work_struct *work)
748 {
749         struct mlx5_vport *vport =
750                 container_of(work, struct mlx5_vport, vport_change_handler);
751         struct mlx5_core_dev *dev = vport->dev;
752         struct mlx5_eswitch *esw = dev->priv.eswitch;
753         u8 mac[ETH_ALEN];
754
755         mlx5_query_nic_vport_mac_address(dev, vport->vport, mac);
756         esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",
757                   vport->vport, mac);
758
759         if (vport->enabled_events & UC_ADDR_CHANGE) {
760                 esw_update_vport_addr_list(esw, vport->vport,
761                                            MLX5_NVPRT_LIST_TYPE_UC);
762                 esw_apply_vport_addr_list(esw, vport->vport,
763                                           MLX5_NVPRT_LIST_TYPE_UC);
764         }
765
766         if (vport->enabled_events & MC_ADDR_CHANGE) {
767                 esw_update_vport_addr_list(esw, vport->vport,
768                                            MLX5_NVPRT_LIST_TYPE_MC);
769                 esw_apply_vport_addr_list(esw, vport->vport,
770                                           MLX5_NVPRT_LIST_TYPE_MC);
771         }
772
773         esw_debug(esw->dev, "vport[%d] Context Changed: Done\n", vport->vport);
774         if (vport->enabled)
775                 arm_vport_context_events_cmd(dev, vport->vport,
776                                              vport->enabled_events);
777 }
778
779 static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
780                                         struct mlx5_vport *vport)
781 {
782         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
783         struct mlx5_flow_group *vlan_grp = NULL;
784         struct mlx5_flow_group *drop_grp = NULL;
785         struct mlx5_core_dev *dev = esw->dev;
786         struct mlx5_flow_namespace *root_ns;
787         struct mlx5_flow_table *acl;
788         void *match_criteria;
789         u32 *flow_group_in;
790         /* The egress acl table contains 2 rules:
791          * 1)Allow traffic with vlan_tag=vst_vlan_id
792          * 2)Drop all other traffic.
793          */
794         int table_size = 2;
795         int err = 0;
796
797         if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support) ||
798             !IS_ERR_OR_NULL(vport->egress.acl))
799                 return;
800
801         esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n",
802                   vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size));
803
804         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS);
805         if (!root_ns) {
806                 esw_warn(dev, "Failed to get E-Switch egress flow namespace\n");
807                 return;
808         }
809
810         flow_group_in = mlx5_vzalloc(inlen);
811         if (!flow_group_in)
812                 return;
813
814         acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
815         if (IS_ERR_OR_NULL(acl)) {
816                 err = PTR_ERR(acl);
817                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress flow Table, err(%d)\n",
818                          vport->vport, err);
819                 goto out;
820         }
821
822         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
823         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
824         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.vlan_tag);
825         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.first_vid);
826         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
827         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
828
829         vlan_grp = mlx5_create_flow_group(acl, flow_group_in);
830         if (IS_ERR_OR_NULL(vlan_grp)) {
831                 err = PTR_ERR(vlan_grp);
832                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress allowed vlans flow group, err(%d)\n",
833                          vport->vport, err);
834                 goto out;
835         }
836
837         memset(flow_group_in, 0, inlen);
838         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
839         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
840         drop_grp = mlx5_create_flow_group(acl, flow_group_in);
841         if (IS_ERR_OR_NULL(drop_grp)) {
842                 err = PTR_ERR(drop_grp);
843                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n",
844                          vport->vport, err);
845                 goto out;
846         }
847
848         vport->egress.acl = acl;
849         vport->egress.drop_grp = drop_grp;
850         vport->egress.allowed_vlans_grp = vlan_grp;
851 out:
852         kfree(flow_group_in);
853         if (err && !IS_ERR_OR_NULL(vlan_grp))
854                 mlx5_destroy_flow_group(vlan_grp);
855         if (err && !IS_ERR_OR_NULL(acl))
856                 mlx5_destroy_flow_table(acl);
857 }
858
859 static void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw,
860                                            struct mlx5_vport *vport)
861 {
862         if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan))
863                 mlx5_del_flow_rule(vport->egress.allowed_vlan);
864
865         if (!IS_ERR_OR_NULL(vport->egress.drop_rule))
866                 mlx5_del_flow_rule(vport->egress.drop_rule);
867
868         vport->egress.allowed_vlan = NULL;
869         vport->egress.drop_rule = NULL;
870 }
871
872 static void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw,
873                                          struct mlx5_vport *vport)
874 {
875         if (IS_ERR_OR_NULL(vport->egress.acl))
876                 return;
877
878         esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport);
879
880         esw_vport_cleanup_egress_rules(esw, vport);
881         mlx5_destroy_flow_group(vport->egress.allowed_vlans_grp);
882         mlx5_destroy_flow_group(vport->egress.drop_grp);
883         mlx5_destroy_flow_table(vport->egress.acl);
884         vport->egress.allowed_vlans_grp = NULL;
885         vport->egress.drop_grp = NULL;
886         vport->egress.acl = NULL;
887 }
888
889 static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
890                                          struct mlx5_vport *vport)
891 {
892         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
893         struct mlx5_core_dev *dev = esw->dev;
894         struct mlx5_flow_namespace *root_ns;
895         struct mlx5_flow_table *acl;
896         struct mlx5_flow_group *g;
897         void *match_criteria;
898         u32 *flow_group_in;
899         /* The ingress acl table contains 4 groups
900          * (2 active rules at the same time -
901          *      1 allow rule from one of the first 3 groups.
902          *      1 drop rule from the last group):
903          * 1)Allow untagged traffic with smac=original mac.
904          * 2)Allow untagged traffic.
905          * 3)Allow traffic with smac=original mac.
906          * 4)Drop all other traffic.
907          */
908         int table_size = 4;
909         int err = 0;
910
911         if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support) ||
912             !IS_ERR_OR_NULL(vport->ingress.acl))
913                 return;
914
915         esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n",
916                   vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size));
917
918         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS);
919         if (!root_ns) {
920                 esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n");
921                 return;
922         }
923
924         flow_group_in = mlx5_vzalloc(inlen);
925         if (!flow_group_in)
926                 return;
927
928         acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
929         if (IS_ERR_OR_NULL(acl)) {
930                 err = PTR_ERR(acl);
931                 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress flow Table, err(%d)\n",
932                          vport->vport, err);
933                 goto out;
934         }
935         vport->ingress.acl = acl;
936
937         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
938
939         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
940         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.vlan_tag);
941         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_47_16);
942         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_15_0);
943         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
944         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
945
946         g = mlx5_create_flow_group(acl, flow_group_in);
947         if (IS_ERR_OR_NULL(g)) {
948                 err = PTR_ERR(g);
949                 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress untagged spoofchk flow group, err(%d)\n",
950                          vport->vport, err);
951                 goto out;
952         }
953         vport->ingress.allow_untagged_spoofchk_grp = g;
954
955         memset(flow_group_in, 0, inlen);
956         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
957         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.vlan_tag);
958         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
959         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
960
961         g = mlx5_create_flow_group(acl, flow_group_in);
962         if (IS_ERR_OR_NULL(g)) {
963                 err = PTR_ERR(g);
964                 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress untagged flow group, err(%d)\n",
965                          vport->vport, err);
966                 goto out;
967         }
968         vport->ingress.allow_untagged_only_grp = g;
969
970         memset(flow_group_in, 0, inlen);
971         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
972         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_47_16);
973         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_15_0);
974         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 2);
975         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 2);
976
977         g = mlx5_create_flow_group(acl, flow_group_in);
978         if (IS_ERR_OR_NULL(g)) {
979                 err = PTR_ERR(g);
980                 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress spoofchk flow group, err(%d)\n",
981                          vport->vport, err);
982                 goto out;
983         }
984         vport->ingress.allow_spoofchk_only_grp = g;
985
986         memset(flow_group_in, 0, inlen);
987         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 3);
988         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 3);
989
990         g = mlx5_create_flow_group(acl, flow_group_in);
991         if (IS_ERR_OR_NULL(g)) {
992                 err = PTR_ERR(g);
993                 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress drop flow group, err(%d)\n",
994                          vport->vport, err);
995                 goto out;
996         }
997         vport->ingress.drop_grp = g;
998
999 out:
1000         if (err) {
1001                 if (!IS_ERR_OR_NULL(vport->ingress.allow_spoofchk_only_grp))
1002                         mlx5_destroy_flow_group(
1003                                         vport->ingress.allow_spoofchk_only_grp);
1004                 if (!IS_ERR_OR_NULL(vport->ingress.allow_untagged_only_grp))
1005                         mlx5_destroy_flow_group(
1006                                         vport->ingress.allow_untagged_only_grp);
1007                 if (!IS_ERR_OR_NULL(vport->ingress.allow_untagged_spoofchk_grp))
1008                         mlx5_destroy_flow_group(
1009                                 vport->ingress.allow_untagged_spoofchk_grp);
1010                 if (!IS_ERR_OR_NULL(vport->ingress.acl))
1011                         mlx5_destroy_flow_table(vport->ingress.acl);
1012         }
1013
1014         kfree(flow_group_in);
1015 }
1016
1017 static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
1018                                             struct mlx5_vport *vport)
1019 {
1020         if (!IS_ERR_OR_NULL(vport->ingress.drop_rule))
1021                 mlx5_del_flow_rule(vport->ingress.drop_rule);
1022
1023         if (!IS_ERR_OR_NULL(vport->ingress.allow_rule))
1024                 mlx5_del_flow_rule(vport->ingress.allow_rule);
1025
1026         vport->ingress.drop_rule = NULL;
1027         vport->ingress.allow_rule = NULL;
1028 }
1029
1030 static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
1031                                           struct mlx5_vport *vport)
1032 {
1033         if (IS_ERR_OR_NULL(vport->ingress.acl))
1034                 return;
1035
1036         esw_debug(esw->dev, "Destroy vport[%d] E-Switch ingress ACL\n", vport->vport);
1037
1038         esw_vport_cleanup_ingress_rules(esw, vport);
1039         mlx5_destroy_flow_group(vport->ingress.allow_spoofchk_only_grp);
1040         mlx5_destroy_flow_group(vport->ingress.allow_untagged_only_grp);
1041         mlx5_destroy_flow_group(vport->ingress.allow_untagged_spoofchk_grp);
1042         mlx5_destroy_flow_group(vport->ingress.drop_grp);
1043         mlx5_destroy_flow_table(vport->ingress.acl);
1044         vport->ingress.acl = NULL;
1045         vport->ingress.drop_grp = NULL;
1046         vport->ingress.allow_spoofchk_only_grp = NULL;
1047         vport->ingress.allow_untagged_only_grp = NULL;
1048         vport->ingress.allow_untagged_spoofchk_grp = NULL;
1049 }
1050
1051 static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
1052                                     struct mlx5_vport *vport)
1053 {
1054         u8 smac[ETH_ALEN];
1055         u32 *match_v;
1056         u32 *match_c;
1057         int err = 0;
1058         u8 *smac_v;
1059
1060         if (vport->spoofchk) {
1061                 err = mlx5_query_nic_vport_mac_address(esw->dev, vport->vport, smac);
1062                 if (err) {
1063                         esw_warn(esw->dev,
1064                                  "vport[%d] configure ingress rules failed, query smac failed, err(%d)\n",
1065                                  vport->vport, err);
1066                         return err;
1067                 }
1068
1069                 if (!is_valid_ether_addr(smac)) {
1070                         mlx5_core_warn(esw->dev,
1071                                        "vport[%d] configure ingress rules failed, illegal mac with spoofchk\n",
1072                                        vport->vport);
1073                         return -EPERM;
1074                 }
1075         }
1076
1077         esw_vport_cleanup_ingress_rules(esw, vport);
1078
1079         if (!vport->vlan && !vport->qos && !vport->spoofchk) {
1080                 esw_vport_disable_ingress_acl(esw, vport);
1081                 return 0;
1082         }
1083
1084         esw_vport_enable_ingress_acl(esw, vport);
1085
1086         esw_debug(esw->dev,
1087                   "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n",
1088                   vport->vport, vport->vlan, vport->qos);
1089
1090         match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
1091         match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
1092         if (!match_v || !match_c) {
1093                 err = -ENOMEM;
1094                 esw_warn(esw->dev, "vport[%d] configure ingress rules failed, err(%d)\n",
1095                          vport->vport, err);
1096                 goto out;
1097         }
1098
1099         if (vport->vlan || vport->qos)
1100                 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.vlan_tag);
1101
1102         if (vport->spoofchk) {
1103                 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.smac_47_16);
1104                 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.smac_15_0);
1105                 smac_v = MLX5_ADDR_OF(fte_match_param,
1106                                       match_v,
1107                                       outer_headers.smac_47_16);
1108                 ether_addr_copy(smac_v, smac);
1109         }
1110
1111         vport->ingress.allow_rule =
1112                 mlx5_add_flow_rule(vport->ingress.acl,
1113                                    MLX5_MATCH_OUTER_HEADERS,
1114                                    match_c,
1115                                    match_v,
1116                                    MLX5_FLOW_CONTEXT_ACTION_ALLOW,
1117                                    0, NULL);
1118         if (IS_ERR_OR_NULL(vport->ingress.allow_rule)) {
1119                 err = PTR_ERR(vport->ingress.allow_rule);
1120                 pr_warn("vport[%d] configure ingress allow rule, err(%d)\n",
1121                         vport->vport, err);
1122                 vport->ingress.allow_rule = NULL;
1123                 goto out;
1124         }
1125
1126         memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param));
1127         memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param));
1128         vport->ingress.drop_rule =
1129                 mlx5_add_flow_rule(vport->ingress.acl,
1130                                    0,
1131                                    match_c,
1132                                    match_v,
1133                                    MLX5_FLOW_CONTEXT_ACTION_DROP,
1134                                    0, NULL);
1135         if (IS_ERR_OR_NULL(vport->ingress.drop_rule)) {
1136                 err = PTR_ERR(vport->ingress.drop_rule);
1137                 pr_warn("vport[%d] configure ingress drop rule, err(%d)\n",
1138                         vport->vport, err);
1139                 vport->ingress.drop_rule = NULL;
1140                 goto out;
1141         }
1142
1143 out:
1144         if (err)
1145                 esw_vport_cleanup_ingress_rules(esw, vport);
1146
1147         kfree(match_v);
1148         kfree(match_c);
1149         return err;
1150 }
1151
1152 static int esw_vport_egress_config(struct mlx5_eswitch *esw,
1153                                    struct mlx5_vport *vport)
1154 {
1155         u32 *match_v;
1156         u32 *match_c;
1157         int err = 0;
1158
1159         esw_vport_cleanup_egress_rules(esw, vport);
1160
1161         if (!vport->vlan && !vport->qos) {
1162                 esw_vport_disable_egress_acl(esw, vport);
1163                 return 0;
1164         }
1165
1166         esw_vport_enable_egress_acl(esw, vport);
1167
1168         esw_debug(esw->dev,
1169                   "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
1170                   vport->vport, vport->vlan, vport->qos);
1171
1172         match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
1173         match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
1174         if (!match_v || !match_c) {
1175                 err = -ENOMEM;
1176                 esw_warn(esw->dev, "vport[%d] configure egress rules failed, err(%d)\n",
1177                          vport->vport, err);
1178                 goto out;
1179         }
1180
1181         /* Allowed vlan rule */
1182         MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.vlan_tag);
1183         MLX5_SET_TO_ONES(fte_match_param, match_v, outer_headers.vlan_tag);
1184         MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.first_vid);
1185         MLX5_SET(fte_match_param, match_v, outer_headers.first_vid, vport->vlan);
1186
1187         vport->egress.allowed_vlan =
1188                 mlx5_add_flow_rule(vport->egress.acl,
1189                                    MLX5_MATCH_OUTER_HEADERS,
1190                                    match_c,
1191                                    match_v,
1192                                    MLX5_FLOW_CONTEXT_ACTION_ALLOW,
1193                                    0, NULL);
1194         if (IS_ERR_OR_NULL(vport->egress.allowed_vlan)) {
1195                 err = PTR_ERR(vport->egress.allowed_vlan);
1196                 pr_warn("vport[%d] configure egress allowed vlan rule failed, err(%d)\n",
1197                         vport->vport, err);
1198                 vport->egress.allowed_vlan = NULL;
1199                 goto out;
1200         }
1201
1202         /* Drop others rule (star rule) */
1203         memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param));
1204         memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param));
1205         vport->egress.drop_rule =
1206                 mlx5_add_flow_rule(vport->egress.acl,
1207                                    0,
1208                                    match_c,
1209                                    match_v,
1210                                    MLX5_FLOW_CONTEXT_ACTION_DROP,
1211                                    0, NULL);
1212         if (IS_ERR_OR_NULL(vport->egress.drop_rule)) {
1213                 err = PTR_ERR(vport->egress.drop_rule);
1214                 pr_warn("vport[%d] configure egress drop rule failed, err(%d)\n",
1215                         vport->vport, err);
1216                 vport->egress.drop_rule = NULL;
1217         }
1218 out:
1219         kfree(match_v);
1220         kfree(match_c);
1221         return err;
1222 }
1223
1224 static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
1225                              int enable_events)
1226 {
1227         struct mlx5_vport *vport = &esw->vports[vport_num];
1228
1229         mutex_lock(&esw->state_lock);
1230         WARN_ON(vport->enabled);
1231
1232         esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
1233
1234         if (vport_num) { /* Only VFs need ACLs for VST and spoofchk filtering */
1235                 esw_vport_ingress_config(esw, vport);
1236                 esw_vport_egress_config(esw, vport);
1237         }
1238
1239         mlx5_modify_vport_admin_state(esw->dev,
1240                                       MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
1241                                       vport_num,
1242                                       MLX5_ESW_VPORT_ADMIN_STATE_AUTO);
1243
1244         /* Sync with current vport context */
1245         vport->enabled_events = enable_events;
1246         esw_vport_change_handler(&vport->vport_change_handler);
1247
1248         vport->enabled = true;
1249
1250         arm_vport_context_events_cmd(esw->dev, vport_num, enable_events);
1251
1252         esw->enabled_vports++;
1253         esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num);
1254         mutex_unlock(&esw->state_lock);
1255 }
1256
1257 static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
1258 {
1259         struct mlx5_vport *vport = &esw->vports[vport_num];
1260
1261         if (!vport->enabled)
1262                 return;
1263
1264         esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num);
1265         /* Mark this vport as disabled to discard new events */
1266         vport->enabled = false;
1267
1268         synchronize_irq(mlx5_get_msix_vec(esw->dev, MLX5_EQ_VEC_ASYNC));
1269
1270         mlx5_modify_vport_admin_state(esw->dev,
1271                                       MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
1272                                       vport_num,
1273                                       MLX5_ESW_VPORT_ADMIN_STATE_DOWN);
1274         /* Wait for current already scheduled events to complete */
1275         flush_workqueue(esw->work_queue);
1276         /* Disable events from this vport */
1277         arm_vport_context_events_cmd(esw->dev, vport->vport, 0);
1278         mutex_lock(&esw->state_lock);
1279         /* We don't assume VFs will cleanup after themselves.
1280          * Calling vport change handler while vport is disabled will cleanup
1281          * the vport resources.
1282          */
1283         esw_vport_change_handler(&vport->vport_change_handler);
1284         vport->enabled_events = 0;
1285         if (vport_num) {
1286                 esw_vport_disable_egress_acl(esw, vport);
1287                 esw_vport_disable_ingress_acl(esw, vport);
1288         }
1289         esw->enabled_vports--;
1290         mutex_unlock(&esw->state_lock);
1291 }
1292
1293 /* Public E-Switch API */
1294 int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs)
1295 {
1296         int err;
1297         int i;
1298
1299         if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
1300             MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1301                 return 0;
1302
1303         if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) ||
1304             !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
1305                 esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n");
1306                 return -ENOTSUPP;
1307         }
1308
1309         if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support))
1310                 esw_warn(esw->dev, "E-Switch ingress ACL is not supported by FW\n");
1311
1312         if (!MLX5_CAP_ESW_EGRESS_ACL(esw->dev, ft_support))
1313                 esw_warn(esw->dev, "E-Switch engress ACL is not supported by FW\n");
1314
1315         esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d)\n", nvfs);
1316
1317         esw_disable_vport(esw, 0);
1318
1319         err = esw_create_fdb_table(esw, nvfs + 1);
1320         if (err)
1321                 goto abort;
1322
1323         for (i = 0; i <= nvfs; i++)
1324                 esw_enable_vport(esw, i, SRIOV_VPORT_EVENTS);
1325
1326         esw_info(esw->dev, "SRIOV enabled: active vports(%d)\n",
1327                  esw->enabled_vports);
1328         return 0;
1329
1330 abort:
1331         esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
1332         return err;
1333 }
1334
1335 void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
1336 {
1337         int i;
1338
1339         if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
1340             MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1341                 return;
1342
1343         esw_info(esw->dev, "disable SRIOV: active vports(%d)\n",
1344                  esw->enabled_vports);
1345
1346         for (i = 0; i < esw->total_vports; i++)
1347                 esw_disable_vport(esw, i);
1348
1349         esw_destroy_fdb_table(esw);
1350
1351         /* VPORT 0 (PF) must be enabled back with non-sriov configuration */
1352         esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
1353 }
1354
1355 int mlx5_eswitch_init(struct mlx5_core_dev *dev)
1356 {
1357         int l2_table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table);
1358         int total_vports = MLX5_TOTAL_VPORTS(dev);
1359         struct mlx5_eswitch *esw;
1360         int vport_num;
1361         int err;
1362
1363         if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
1364             MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1365                 return 0;
1366
1367         esw_info(dev,
1368                  "Total vports %d, l2 table size(%d), per vport: max uc(%d) max mc(%d)\n",
1369                  total_vports, l2_table_size,
1370                  MLX5_MAX_UC_PER_VPORT(dev),
1371                  MLX5_MAX_MC_PER_VPORT(dev));
1372
1373         esw = kzalloc(sizeof(*esw), GFP_KERNEL);
1374         if (!esw)
1375                 return -ENOMEM;
1376
1377         esw->dev = dev;
1378
1379         esw->l2_table.bitmap = kcalloc(BITS_TO_LONGS(l2_table_size),
1380                                    sizeof(uintptr_t), GFP_KERNEL);
1381         if (!esw->l2_table.bitmap) {
1382                 err = -ENOMEM;
1383                 goto abort;
1384         }
1385         esw->l2_table.size = l2_table_size;
1386
1387         esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
1388         if (!esw->work_queue) {
1389                 err = -ENOMEM;
1390                 goto abort;
1391         }
1392
1393         esw->vports = kcalloc(total_vports, sizeof(struct mlx5_vport),
1394                               GFP_KERNEL);
1395         if (!esw->vports) {
1396                 err = -ENOMEM;
1397                 goto abort;
1398         }
1399
1400         mutex_init(&esw->state_lock);
1401
1402         for (vport_num = 0; vport_num < total_vports; vport_num++) {
1403                 struct mlx5_vport *vport = &esw->vports[vport_num];
1404
1405                 vport->vport = vport_num;
1406                 vport->dev = dev;
1407                 INIT_WORK(&vport->vport_change_handler,
1408                           esw_vport_change_handler);
1409         }
1410
1411         esw->total_vports = total_vports;
1412         esw->enabled_vports = 0;
1413
1414         dev->priv.eswitch = esw;
1415         esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
1416         /* VF Vports will be enabled when SRIOV is enabled */
1417         return 0;
1418 abort:
1419         if (esw->work_queue)
1420                 destroy_workqueue(esw->work_queue);
1421         kfree(esw->l2_table.bitmap);
1422         kfree(esw->vports);
1423         kfree(esw);
1424         return err;
1425 }
1426
1427 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
1428 {
1429         if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
1430             MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1431                 return;
1432
1433         esw_info(esw->dev, "cleanup\n");
1434         esw_disable_vport(esw, 0);
1435
1436         esw->dev->priv.eswitch = NULL;
1437         destroy_workqueue(esw->work_queue);
1438         kfree(esw->l2_table.bitmap);
1439         kfree(esw->vports);
1440         kfree(esw);
1441 }
1442
1443 void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe)
1444 {
1445         struct mlx5_eqe_vport_change *vc_eqe = &eqe->data.vport_change;
1446         u16 vport_num = be16_to_cpu(vc_eqe->vport_num);
1447         struct mlx5_vport *vport;
1448
1449         if (!esw) {
1450                 pr_warn("MLX5 E-Switch: vport %d got an event while eswitch is not initialized\n",
1451                         vport_num);
1452                 return;
1453         }
1454
1455         vport = &esw->vports[vport_num];
1456         if (vport->enabled)
1457                 queue_work(esw->work_queue, &vport->vport_change_handler);
1458 }
1459
1460 /* Vport Administration */
1461 #define ESW_ALLOWED(esw) \
1462         (esw && MLX5_CAP_GEN(esw->dev, vport_group_manager) && mlx5_core_is_pf(esw->dev))
1463 #define LEGAL_VPORT(esw, vport) (vport >= 0 && vport < esw->total_vports)
1464
1465 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
1466                                int vport, u8 mac[ETH_ALEN])
1467 {
1468         int err = 0;
1469         struct mlx5_vport *evport;
1470
1471         if (!ESW_ALLOWED(esw))
1472                 return -EPERM;
1473         if (!LEGAL_VPORT(esw, vport))
1474                 return -EINVAL;
1475
1476         evport = &esw->vports[vport];
1477
1478         if (evport->spoofchk && !is_valid_ether_addr(mac)) {
1479                 mlx5_core_warn(esw->dev,
1480                                "MAC invalidation is not allowed when spoofchk is on, vport(%d)\n",
1481                                vport);
1482                 return -EPERM;
1483         }
1484
1485         err = mlx5_modify_nic_vport_mac_address(esw->dev, vport, mac);
1486         if (err) {
1487                 mlx5_core_warn(esw->dev,
1488                                "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n",
1489                                vport, err);
1490                 return err;
1491         }
1492
1493         mutex_lock(&esw->state_lock);
1494         if (evport->enabled)
1495                 err = esw_vport_ingress_config(esw, evport);
1496         mutex_unlock(&esw->state_lock);
1497
1498         return err;
1499 }
1500
1501 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
1502                                  int vport, int link_state)
1503 {
1504         if (!ESW_ALLOWED(esw))
1505                 return -EPERM;
1506         if (!LEGAL_VPORT(esw, vport))
1507                 return -EINVAL;
1508
1509         return mlx5_modify_vport_admin_state(esw->dev,
1510                                              MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
1511                                              vport, link_state);
1512 }
1513
1514 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
1515                                   int vport, struct ifla_vf_info *ivi)
1516 {
1517         struct mlx5_vport *evport;
1518         u16 vlan;
1519         u8 qos;
1520
1521         if (!ESW_ALLOWED(esw))
1522                 return -EPERM;
1523         if (!LEGAL_VPORT(esw, vport))
1524                 return -EINVAL;
1525
1526         evport = &esw->vports[vport];
1527
1528         memset(ivi, 0, sizeof(*ivi));
1529         ivi->vf = vport - 1;
1530
1531         mlx5_query_nic_vport_mac_address(esw->dev, vport, ivi->mac);
1532         ivi->linkstate = mlx5_query_vport_admin_state(esw->dev,
1533                                                       MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
1534                                                       vport);
1535         query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos);
1536         ivi->vlan = vlan;
1537         ivi->qos = qos;
1538         ivi->spoofchk = evport->spoofchk;
1539
1540         return 0;
1541 }
1542
1543 int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
1544                                 int vport, u16 vlan, u8 qos)
1545 {
1546         struct mlx5_vport *evport;
1547         int err = 0;
1548         int set = 0;
1549
1550         if (!ESW_ALLOWED(esw))
1551                 return -EPERM;
1552         if (!LEGAL_VPORT(esw, vport) || (vlan > 4095) || (qos > 7))
1553                 return -EINVAL;
1554
1555         if (vlan || qos)
1556                 set = 1;
1557
1558         evport = &esw->vports[vport];
1559
1560         err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set);
1561         if (err)
1562                 return err;
1563
1564         mutex_lock(&esw->state_lock);
1565         evport->vlan = vlan;
1566         evport->qos = qos;
1567         if (evport->enabled) {
1568                 err = esw_vport_ingress_config(esw, evport);
1569                 if (err)
1570                         goto out;
1571                 err = esw_vport_egress_config(esw, evport);
1572         }
1573
1574 out:
1575         mutex_unlock(&esw->state_lock);
1576         return err;
1577 }
1578
1579 int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
1580                                     int vport, bool spoofchk)
1581 {
1582         struct mlx5_vport *evport;
1583         bool pschk;
1584         int err = 0;
1585
1586         if (!ESW_ALLOWED(esw))
1587                 return -EPERM;
1588         if (!LEGAL_VPORT(esw, vport))
1589                 return -EINVAL;
1590
1591         evport = &esw->vports[vport];
1592
1593         mutex_lock(&esw->state_lock);
1594         pschk = evport->spoofchk;
1595         evport->spoofchk = spoofchk;
1596         if (evport->enabled)
1597                 err = esw_vport_ingress_config(esw, evport);
1598         if (err)
1599                 evport->spoofchk = pschk;
1600         mutex_unlock(&esw->state_lock);
1601
1602         return err;
1603 }
1604
1605 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
1606                                  int vport,
1607                                  struct ifla_vf_stats *vf_stats)
1608 {
1609         int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
1610         u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)];
1611         int err = 0;
1612         u32 *out;
1613
1614         if (!ESW_ALLOWED(esw))
1615                 return -EPERM;
1616         if (!LEGAL_VPORT(esw, vport))
1617                 return -EINVAL;
1618
1619         out = mlx5_vzalloc(outlen);
1620         if (!out)
1621                 return -ENOMEM;
1622
1623         memset(in, 0, sizeof(in));
1624
1625         MLX5_SET(query_vport_counter_in, in, opcode,
1626                  MLX5_CMD_OP_QUERY_VPORT_COUNTER);
1627         MLX5_SET(query_vport_counter_in, in, op_mod, 0);
1628         MLX5_SET(query_vport_counter_in, in, vport_number, vport);
1629         if (vport)
1630                 MLX5_SET(query_vport_counter_in, in, other_vport, 1);
1631
1632         memset(out, 0, outlen);
1633         err = mlx5_cmd_exec(esw->dev, in, sizeof(in), out, outlen);
1634         if (err)
1635                 goto free_out;
1636
1637         #define MLX5_GET_CTR(p, x) \
1638                 MLX5_GET64(query_vport_counter_out, p, x)
1639
1640         memset(vf_stats, 0, sizeof(*vf_stats));
1641         vf_stats->rx_packets =
1642                 MLX5_GET_CTR(out, received_eth_unicast.packets) +
1643                 MLX5_GET_CTR(out, received_eth_multicast.packets) +
1644                 MLX5_GET_CTR(out, received_eth_broadcast.packets);
1645
1646         vf_stats->rx_bytes =
1647                 MLX5_GET_CTR(out, received_eth_unicast.octets) +
1648                 MLX5_GET_CTR(out, received_eth_multicast.octets) +
1649                 MLX5_GET_CTR(out, received_eth_broadcast.octets);
1650
1651         vf_stats->tx_packets =
1652                 MLX5_GET_CTR(out, transmitted_eth_unicast.packets) +
1653                 MLX5_GET_CTR(out, transmitted_eth_multicast.packets) +
1654                 MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);
1655
1656         vf_stats->tx_bytes =
1657                 MLX5_GET_CTR(out, transmitted_eth_unicast.octets) +
1658                 MLX5_GET_CTR(out, transmitted_eth_multicast.octets) +
1659                 MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
1660
1661         vf_stats->multicast =
1662                 MLX5_GET_CTR(out, received_eth_multicast.packets);
1663
1664         vf_stats->broadcast =
1665                 MLX5_GET_CTR(out, received_eth_broadcast.packets);
1666
1667 free_out:
1668         kvfree(out);
1669         return err;
1670 }