2 * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
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:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
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.
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
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"
51 /* Vport UC/MC hash node */
53 struct l2addr_node node
;
56 struct mlx5_flow_handle
*flow_rule
;
57 bool mpfs
; /* UC MAC was added to MPFs */
58 /* A flag indicating that mac was added due to mc promiscuous vport */
62 static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch
*esw
);
63 static void esw_cleanup_vepa_rules(struct mlx5_eswitch
*esw
);
65 struct mlx5_vport
*__must_check
66 mlx5_eswitch_get_vport(struct mlx5_eswitch
*esw
, u16 vport_num
)
70 if (!esw
|| !MLX5_CAP_GEN(esw
->dev
, vport_group_manager
))
71 return ERR_PTR(-EPERM
);
73 idx
= mlx5_eswitch_vport_num_to_index(esw
, vport_num
);
75 if (idx
> esw
->total_vports
- 1) {
76 esw_debug(esw
->dev
, "vport out of range: num(0x%x), idx(0x%x)\n",
78 return ERR_PTR(-EINVAL
);
81 return &esw
->vports
[idx
];
84 static int arm_vport_context_events_cmd(struct mlx5_core_dev
*dev
, u16 vport
,
87 int in
[MLX5_ST_SZ_DW(modify_nic_vport_context_in
)] = {0};
88 int out
[MLX5_ST_SZ_DW(modify_nic_vport_context_out
)] = {0};
91 MLX5_SET(modify_nic_vport_context_in
, in
,
92 opcode
, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT
);
93 MLX5_SET(modify_nic_vport_context_in
, in
, field_select
.change_event
, 1);
94 MLX5_SET(modify_nic_vport_context_in
, in
, vport_number
, vport
);
95 MLX5_SET(modify_nic_vport_context_in
, in
, other_vport
, 1);
96 nic_vport_ctx
= MLX5_ADDR_OF(modify_nic_vport_context_in
,
97 in
, nic_vport_context
);
99 MLX5_SET(nic_vport_context
, nic_vport_ctx
, arm_change_event
, 1);
101 if (events_mask
& MLX5_VPORT_UC_ADDR_CHANGE
)
102 MLX5_SET(nic_vport_context
, nic_vport_ctx
,
103 event_on_uc_address_change
, 1);
104 if (events_mask
& MLX5_VPORT_MC_ADDR_CHANGE
)
105 MLX5_SET(nic_vport_context
, nic_vport_ctx
,
106 event_on_mc_address_change
, 1);
107 if (events_mask
& MLX5_VPORT_PROMISC_CHANGE
)
108 MLX5_SET(nic_vport_context
, nic_vport_ctx
,
109 event_on_promisc_change
, 1);
111 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, sizeof(out
));
114 /* E-Switch vport context HW commands */
115 int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev
*dev
, u16 vport
,
119 u32 out
[MLX5_ST_SZ_DW(modify_esw_vport_context_out
)] = {0};
121 MLX5_SET(modify_esw_vport_context_in
, in
, opcode
,
122 MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT
);
123 MLX5_SET(modify_esw_vport_context_in
, in
, vport_number
, vport
);
124 MLX5_SET(modify_esw_vport_context_in
, in
, other_vport
, other_vport
);
125 return mlx5_cmd_exec(dev
, in
, inlen
, out
, sizeof(out
));
128 int mlx5_eswitch_query_esw_vport_context(struct mlx5_core_dev
*dev
, u16 vport
,
130 void *out
, int outlen
)
132 u32 in
[MLX5_ST_SZ_DW(query_esw_vport_context_in
)] = {};
134 MLX5_SET(query_esw_vport_context_in
, in
, opcode
,
135 MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT
);
136 MLX5_SET(modify_esw_vport_context_in
, in
, vport_number
, vport
);
137 MLX5_SET(modify_esw_vport_context_in
, in
, other_vport
, other_vport
);
138 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, outlen
);
141 static int modify_esw_vport_cvlan(struct mlx5_core_dev
*dev
, u16 vport
,
142 u16 vlan
, u8 qos
, u8 set_flags
)
144 u32 in
[MLX5_ST_SZ_DW(modify_esw_vport_context_in
)] = {0};
146 if (!MLX5_CAP_ESW(dev
, vport_cvlan_strip
) ||
147 !MLX5_CAP_ESW(dev
, vport_cvlan_insert_if_not_exist
))
150 esw_debug(dev
, "Set Vport[%d] VLAN %d qos %d set=%x\n",
151 vport
, vlan
, qos
, set_flags
);
153 if (set_flags
& SET_VLAN_STRIP
)
154 MLX5_SET(modify_esw_vport_context_in
, in
,
155 esw_vport_context
.vport_cvlan_strip
, 1);
157 if (set_flags
& SET_VLAN_INSERT
) {
158 /* insert only if no vlan in packet */
159 MLX5_SET(modify_esw_vport_context_in
, in
,
160 esw_vport_context
.vport_cvlan_insert
, 1);
162 MLX5_SET(modify_esw_vport_context_in
, in
,
163 esw_vport_context
.cvlan_pcp
, qos
);
164 MLX5_SET(modify_esw_vport_context_in
, in
,
165 esw_vport_context
.cvlan_id
, vlan
);
168 MLX5_SET(modify_esw_vport_context_in
, in
,
169 field_select
.vport_cvlan_strip
, 1);
170 MLX5_SET(modify_esw_vport_context_in
, in
,
171 field_select
.vport_cvlan_insert
, 1);
173 return mlx5_eswitch_modify_esw_vport_context(dev
, vport
, true,
178 static struct mlx5_flow_handle
*
179 __esw_fdb_set_vport_rule(struct mlx5_eswitch
*esw
, u16 vport
, bool rx_rule
,
180 u8 mac_c
[ETH_ALEN
], u8 mac_v
[ETH_ALEN
])
182 int match_header
= (is_zero_ether_addr(mac_c
) ? 0 :
183 MLX5_MATCH_OUTER_HEADERS
);
184 struct mlx5_flow_handle
*flow_rule
= NULL
;
185 struct mlx5_flow_act flow_act
= {0};
186 struct mlx5_flow_destination dest
= {};
187 struct mlx5_flow_spec
*spec
;
188 void *mv_misc
= NULL
;
189 void *mc_misc
= NULL
;
194 match_header
|= MLX5_MATCH_MISC_PARAMETERS
;
196 spec
= kvzalloc(sizeof(*spec
), GFP_KERNEL
);
200 dmac_v
= MLX5_ADDR_OF(fte_match_param
, spec
->match_value
,
201 outer_headers
.dmac_47_16
);
202 dmac_c
= MLX5_ADDR_OF(fte_match_param
, spec
->match_criteria
,
203 outer_headers
.dmac_47_16
);
205 if (match_header
& MLX5_MATCH_OUTER_HEADERS
) {
206 ether_addr_copy(dmac_v
, mac_v
);
207 ether_addr_copy(dmac_c
, mac_c
);
210 if (match_header
& MLX5_MATCH_MISC_PARAMETERS
) {
211 mv_misc
= MLX5_ADDR_OF(fte_match_param
, spec
->match_value
,
213 mc_misc
= MLX5_ADDR_OF(fte_match_param
, spec
->match_criteria
,
215 MLX5_SET(fte_match_set_misc
, mv_misc
, source_port
, MLX5_VPORT_UPLINK
);
216 MLX5_SET_TO_ONES(fte_match_set_misc
, mc_misc
, source_port
);
219 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_VPORT
;
220 dest
.vport
.num
= vport
;
223 "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",
224 dmac_v
, dmac_c
, vport
);
225 spec
->match_criteria_enable
= match_header
;
226 flow_act
.action
= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST
;
228 mlx5_add_flow_rules(esw
->fdb_table
.legacy
.fdb
, spec
,
229 &flow_act
, &dest
, 1);
230 if (IS_ERR(flow_rule
)) {
232 "FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n",
233 dmac_v
, dmac_c
, vport
, PTR_ERR(flow_rule
));
241 static struct mlx5_flow_handle
*
242 esw_fdb_set_vport_rule(struct mlx5_eswitch
*esw
, u8 mac
[ETH_ALEN
], u16 vport
)
246 eth_broadcast_addr(mac_c
);
247 return __esw_fdb_set_vport_rule(esw
, vport
, false, mac_c
, mac
);
250 static struct mlx5_flow_handle
*
251 esw_fdb_set_vport_allmulti_rule(struct mlx5_eswitch
*esw
, u16 vport
)
256 eth_zero_addr(mac_c
);
257 eth_zero_addr(mac_v
);
260 return __esw_fdb_set_vport_rule(esw
, vport
, false, mac_c
, mac_v
);
263 static struct mlx5_flow_handle
*
264 esw_fdb_set_vport_promisc_rule(struct mlx5_eswitch
*esw
, u16 vport
)
269 eth_zero_addr(mac_c
);
270 eth_zero_addr(mac_v
);
271 return __esw_fdb_set_vport_rule(esw
, vport
, true, mac_c
, mac_v
);
275 LEGACY_VEPA_PRIO
= 0,
279 static int esw_create_legacy_vepa_table(struct mlx5_eswitch
*esw
)
281 struct mlx5_flow_table_attr ft_attr
= {};
282 struct mlx5_core_dev
*dev
= esw
->dev
;
283 struct mlx5_flow_namespace
*root_ns
;
284 struct mlx5_flow_table
*fdb
;
287 root_ns
= mlx5_get_fdb_sub_ns(dev
, 0);
289 esw_warn(dev
, "Failed to get FDB flow namespace\n");
293 /* num FTE 2, num FG 2 */
294 ft_attr
.prio
= LEGACY_VEPA_PRIO
;
296 ft_attr
.autogroup
.max_num_groups
= 2;
297 fdb
= mlx5_create_auto_grouped_flow_table(root_ns
, &ft_attr
);
300 esw_warn(dev
, "Failed to create VEPA FDB err %d\n", err
);
303 esw
->fdb_table
.legacy
.vepa_fdb
= fdb
;
308 static int esw_create_legacy_fdb_table(struct mlx5_eswitch
*esw
)
310 int inlen
= MLX5_ST_SZ_BYTES(create_flow_group_in
);
311 struct mlx5_flow_table_attr ft_attr
= {};
312 struct mlx5_core_dev
*dev
= esw
->dev
;
313 struct mlx5_flow_namespace
*root_ns
;
314 struct mlx5_flow_table
*fdb
;
315 struct mlx5_flow_group
*g
;
316 void *match_criteria
;
322 esw_debug(dev
, "Create FDB log_max_size(%d)\n",
323 MLX5_CAP_ESW_FLOWTABLE_FDB(dev
, log_max_ft_size
));
325 root_ns
= mlx5_get_fdb_sub_ns(dev
, 0);
327 esw_warn(dev
, "Failed to get FDB flow namespace\n");
331 flow_group_in
= kvzalloc(inlen
, GFP_KERNEL
);
335 table_size
= BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev
, log_max_ft_size
));
336 ft_attr
.max_fte
= table_size
;
337 ft_attr
.prio
= LEGACY_FDB_PRIO
;
338 fdb
= mlx5_create_flow_table(root_ns
, &ft_attr
);
341 esw_warn(dev
, "Failed to create FDB Table err %d\n", err
);
344 esw
->fdb_table
.legacy
.fdb
= fdb
;
346 /* Addresses group : Full match unicast/multicast addresses */
347 MLX5_SET(create_flow_group_in
, flow_group_in
, match_criteria_enable
,
348 MLX5_MATCH_OUTER_HEADERS
);
349 match_criteria
= MLX5_ADDR_OF(create_flow_group_in
, flow_group_in
, match_criteria
);
350 dmac
= MLX5_ADDR_OF(fte_match_param
, match_criteria
, outer_headers
.dmac_47_16
);
351 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, 0);
352 /* Preserve 2 entries for allmulti and promisc rules*/
353 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, table_size
- 3);
354 eth_broadcast_addr(dmac
);
355 g
= mlx5_create_flow_group(fdb
, flow_group_in
);
358 esw_warn(dev
, "Failed to create flow group err(%d)\n", err
);
361 esw
->fdb_table
.legacy
.addr_grp
= g
;
363 /* Allmulti group : One rule that forwards any mcast traffic */
364 MLX5_SET(create_flow_group_in
, flow_group_in
, match_criteria_enable
,
365 MLX5_MATCH_OUTER_HEADERS
);
366 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, table_size
- 2);
367 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, table_size
- 2);
370 g
= mlx5_create_flow_group(fdb
, flow_group_in
);
373 esw_warn(dev
, "Failed to create allmulti flow group err(%d)\n", err
);
376 esw
->fdb_table
.legacy
.allmulti_grp
= g
;
378 /* Promiscuous group :
379 * One rule that forward all unmatched traffic from previous groups
382 MLX5_SET(create_flow_group_in
, flow_group_in
, match_criteria_enable
,
383 MLX5_MATCH_MISC_PARAMETERS
);
384 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, misc_parameters
.source_port
);
385 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, table_size
- 1);
386 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, table_size
- 1);
387 g
= mlx5_create_flow_group(fdb
, flow_group_in
);
390 esw_warn(dev
, "Failed to create promisc flow group err(%d)\n", err
);
393 esw
->fdb_table
.legacy
.promisc_grp
= g
;
397 esw_destroy_legacy_fdb_table(esw
);
399 kvfree(flow_group_in
);
403 static void esw_destroy_legacy_vepa_table(struct mlx5_eswitch
*esw
)
405 esw_debug(esw
->dev
, "Destroy VEPA Table\n");
406 if (!esw
->fdb_table
.legacy
.vepa_fdb
)
409 mlx5_destroy_flow_table(esw
->fdb_table
.legacy
.vepa_fdb
);
410 esw
->fdb_table
.legacy
.vepa_fdb
= NULL
;
413 static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch
*esw
)
415 esw_debug(esw
->dev
, "Destroy FDB Table\n");
416 if (!esw
->fdb_table
.legacy
.fdb
)
419 if (esw
->fdb_table
.legacy
.promisc_grp
)
420 mlx5_destroy_flow_group(esw
->fdb_table
.legacy
.promisc_grp
);
421 if (esw
->fdb_table
.legacy
.allmulti_grp
)
422 mlx5_destroy_flow_group(esw
->fdb_table
.legacy
.allmulti_grp
);
423 if (esw
->fdb_table
.legacy
.addr_grp
)
424 mlx5_destroy_flow_group(esw
->fdb_table
.legacy
.addr_grp
);
425 mlx5_destroy_flow_table(esw
->fdb_table
.legacy
.fdb
);
427 esw
->fdb_table
.legacy
.fdb
= NULL
;
428 esw
->fdb_table
.legacy
.addr_grp
= NULL
;
429 esw
->fdb_table
.legacy
.allmulti_grp
= NULL
;
430 esw
->fdb_table
.legacy
.promisc_grp
= NULL
;
433 static int esw_create_legacy_table(struct mlx5_eswitch
*esw
)
437 memset(&esw
->fdb_table
.legacy
, 0, sizeof(struct legacy_fdb
));
439 err
= esw_create_legacy_vepa_table(esw
);
443 err
= esw_create_legacy_fdb_table(esw
);
445 esw_destroy_legacy_vepa_table(esw
);
450 static void esw_destroy_legacy_table(struct mlx5_eswitch
*esw
)
452 esw_cleanup_vepa_rules(esw
);
453 esw_destroy_legacy_fdb_table(esw
);
454 esw_destroy_legacy_vepa_table(esw
);
457 #define MLX5_LEGACY_SRIOV_VPORT_EVENTS (MLX5_VPORT_UC_ADDR_CHANGE | \
458 MLX5_VPORT_MC_ADDR_CHANGE | \
459 MLX5_VPORT_PROMISC_CHANGE)
461 static int esw_legacy_enable(struct mlx5_eswitch
*esw
)
463 struct mlx5_vport
*vport
;
466 ret
= esw_create_legacy_table(esw
);
470 mlx5_esw_for_each_vf_vport(esw
, i
, vport
, esw
->esw_funcs
.num_vfs
)
471 vport
->info
.link_state
= MLX5_VPORT_ADMIN_STATE_AUTO
;
473 ret
= mlx5_eswitch_enable_pf_vf_vports(esw
, MLX5_LEGACY_SRIOV_VPORT_EVENTS
);
475 esw_destroy_legacy_table(esw
);
479 static void esw_legacy_disable(struct mlx5_eswitch
*esw
)
481 struct esw_mc_addr
*mc_promisc
;
483 mlx5_eswitch_disable_pf_vf_vports(esw
);
485 mc_promisc
= &esw
->mc_promisc
;
486 if (mc_promisc
->uplink_rule
)
487 mlx5_del_flow_rules(mc_promisc
->uplink_rule
);
489 esw_destroy_legacy_table(esw
);
492 /* E-Switch vport UC/MC lists management */
493 typedef int (*vport_addr_action
)(struct mlx5_eswitch
*esw
,
494 struct vport_addr
*vaddr
);
496 static int esw_add_uc_addr(struct mlx5_eswitch
*esw
, struct vport_addr
*vaddr
)
498 u8
*mac
= vaddr
->node
.addr
;
499 u16 vport
= vaddr
->vport
;
502 /* Skip mlx5_mpfs_add_mac for eswitch_managers,
503 * it is already done by its netdev in mlx5e_execute_l2_action
505 if (mlx5_esw_is_manager_vport(esw
, vport
))
508 err
= mlx5_mpfs_add_mac(esw
->dev
, mac
);
511 "Failed to add L2 table mac(%pM) for vport(0x%x), err(%d)\n",
518 /* SRIOV is enabled: Forward UC MAC to vport */
519 if (esw
->fdb_table
.legacy
.fdb
&& esw
->mode
== MLX5_ESWITCH_LEGACY
)
520 vaddr
->flow_rule
= esw_fdb_set_vport_rule(esw
, mac
, vport
);
522 esw_debug(esw
->dev
, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n",
523 vport
, mac
, vaddr
->flow_rule
);
528 static int esw_del_uc_addr(struct mlx5_eswitch
*esw
, struct vport_addr
*vaddr
)
530 u8
*mac
= vaddr
->node
.addr
;
531 u16 vport
= vaddr
->vport
;
534 /* Skip mlx5_mpfs_del_mac for eswitch managers,
535 * it is already done by its netdev in mlx5e_execute_l2_action
537 if (!vaddr
->mpfs
|| mlx5_esw_is_manager_vport(esw
, vport
))
540 err
= mlx5_mpfs_del_mac(esw
->dev
, mac
);
543 "Failed to del L2 table mac(%pM) for vport(%d), err(%d)\n",
548 if (vaddr
->flow_rule
)
549 mlx5_del_flow_rules(vaddr
->flow_rule
);
550 vaddr
->flow_rule
= NULL
;
555 static void update_allmulti_vports(struct mlx5_eswitch
*esw
,
556 struct vport_addr
*vaddr
,
557 struct esw_mc_addr
*esw_mc
)
559 u8
*mac
= vaddr
->node
.addr
;
560 struct mlx5_vport
*vport
;
563 mlx5_esw_for_all_vports(esw
, i
, vport
) {
564 struct hlist_head
*vport_hash
= vport
->mc_list
;
565 struct vport_addr
*iter_vaddr
=
566 l2addr_hash_find(vport_hash
,
569 vport_num
= vport
->vport
;
570 if (IS_ERR_OR_NULL(vport
->allmulti_rule
) ||
571 vaddr
->vport
== vport_num
)
573 switch (vaddr
->action
) {
574 case MLX5_ACTION_ADD
:
577 iter_vaddr
= l2addr_hash_add(vport_hash
, mac
,
582 "ALL-MULTI: Failed to add MAC(%pM) to vport[%d] DB\n",
586 iter_vaddr
->vport
= vport_num
;
587 iter_vaddr
->flow_rule
=
588 esw_fdb_set_vport_rule(esw
,
591 iter_vaddr
->mc_promisc
= true;
593 case MLX5_ACTION_DEL
:
596 mlx5_del_flow_rules(iter_vaddr
->flow_rule
);
597 l2addr_hash_del(iter_vaddr
);
603 static int esw_add_mc_addr(struct mlx5_eswitch
*esw
, struct vport_addr
*vaddr
)
605 struct hlist_head
*hash
= esw
->mc_table
;
606 struct esw_mc_addr
*esw_mc
;
607 u8
*mac
= vaddr
->node
.addr
;
608 u16 vport
= vaddr
->vport
;
610 if (!esw
->fdb_table
.legacy
.fdb
)
613 esw_mc
= l2addr_hash_find(hash
, mac
, struct esw_mc_addr
);
617 esw_mc
= l2addr_hash_add(hash
, mac
, struct esw_mc_addr
, GFP_KERNEL
);
621 esw_mc
->uplink_rule
= /* Forward MC MAC to Uplink */
622 esw_fdb_set_vport_rule(esw
, mac
, MLX5_VPORT_UPLINK
);
624 /* Add this multicast mac to all the mc promiscuous vports */
625 update_allmulti_vports(esw
, vaddr
, esw_mc
);
628 /* If the multicast mac is added as a result of mc promiscuous vport,
629 * don't increment the multicast ref count
631 if (!vaddr
->mc_promisc
)
634 /* Forward MC MAC to vport */
635 vaddr
->flow_rule
= esw_fdb_set_vport_rule(esw
, mac
, vport
);
637 "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
638 vport
, mac
, vaddr
->flow_rule
,
639 esw_mc
->refcnt
, esw_mc
->uplink_rule
);
643 static int esw_del_mc_addr(struct mlx5_eswitch
*esw
, struct vport_addr
*vaddr
)
645 struct hlist_head
*hash
= esw
->mc_table
;
646 struct esw_mc_addr
*esw_mc
;
647 u8
*mac
= vaddr
->node
.addr
;
648 u16 vport
= vaddr
->vport
;
650 if (!esw
->fdb_table
.legacy
.fdb
)
653 esw_mc
= l2addr_hash_find(hash
, mac
, struct esw_mc_addr
);
656 "Failed to find eswitch MC addr for MAC(%pM) vport(%d)",
661 "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
662 vport
, mac
, vaddr
->flow_rule
, esw_mc
->refcnt
,
663 esw_mc
->uplink_rule
);
665 if (vaddr
->flow_rule
)
666 mlx5_del_flow_rules(vaddr
->flow_rule
);
667 vaddr
->flow_rule
= NULL
;
669 /* If the multicast mac is added as a result of mc promiscuous vport,
670 * don't decrement the multicast ref count.
672 if (vaddr
->mc_promisc
|| (--esw_mc
->refcnt
> 0))
675 /* Remove this multicast mac from all the mc promiscuous vports */
676 update_allmulti_vports(esw
, vaddr
, esw_mc
);
678 if (esw_mc
->uplink_rule
)
679 mlx5_del_flow_rules(esw_mc
->uplink_rule
);
681 l2addr_hash_del(esw_mc
);
685 /* Apply vport UC/MC list to HW l2 table and FDB table */
686 static void esw_apply_vport_addr_list(struct mlx5_eswitch
*esw
,
687 struct mlx5_vport
*vport
, int list_type
)
689 bool is_uc
= list_type
== MLX5_NVPRT_LIST_TYPE_UC
;
690 vport_addr_action vport_addr_add
;
691 vport_addr_action vport_addr_del
;
692 struct vport_addr
*addr
;
693 struct l2addr_node
*node
;
694 struct hlist_head
*hash
;
695 struct hlist_node
*tmp
;
698 vport_addr_add
= is_uc
? esw_add_uc_addr
:
700 vport_addr_del
= is_uc
? esw_del_uc_addr
:
703 hash
= is_uc
? vport
->uc_list
: vport
->mc_list
;
704 for_each_l2hash_node(node
, tmp
, hash
, hi
) {
705 addr
= container_of(node
, struct vport_addr
, node
);
706 switch (addr
->action
) {
707 case MLX5_ACTION_ADD
:
708 vport_addr_add(esw
, addr
);
709 addr
->action
= MLX5_ACTION_NONE
;
711 case MLX5_ACTION_DEL
:
712 vport_addr_del(esw
, addr
);
713 l2addr_hash_del(addr
);
719 /* Sync vport UC/MC list from vport context */
720 static void esw_update_vport_addr_list(struct mlx5_eswitch
*esw
,
721 struct mlx5_vport
*vport
, int list_type
)
723 bool is_uc
= list_type
== MLX5_NVPRT_LIST_TYPE_UC
;
724 u8 (*mac_list
)[ETH_ALEN
];
725 struct l2addr_node
*node
;
726 struct vport_addr
*addr
;
727 struct hlist_head
*hash
;
728 struct hlist_node
*tmp
;
734 size
= is_uc
? MLX5_MAX_UC_PER_VPORT(esw
->dev
) :
735 MLX5_MAX_MC_PER_VPORT(esw
->dev
);
737 mac_list
= kcalloc(size
, ETH_ALEN
, GFP_KERNEL
);
741 hash
= is_uc
? vport
->uc_list
: vport
->mc_list
;
743 for_each_l2hash_node(node
, tmp
, hash
, hi
) {
744 addr
= container_of(node
, struct vport_addr
, node
);
745 addr
->action
= MLX5_ACTION_DEL
;
751 err
= mlx5_query_nic_vport_mac_list(esw
->dev
, vport
->vport
, list_type
,
755 esw_debug(esw
->dev
, "vport[%d] context update %s list size (%d)\n",
756 vport
->vport
, is_uc
? "UC" : "MC", size
);
758 for (i
= 0; i
< size
; i
++) {
759 if (is_uc
&& !is_valid_ether_addr(mac_list
[i
]))
762 if (!is_uc
&& !is_multicast_ether_addr(mac_list
[i
]))
765 addr
= l2addr_hash_find(hash
, mac_list
[i
], struct vport_addr
);
767 addr
->action
= MLX5_ACTION_NONE
;
768 /* If this mac was previously added because of allmulti
769 * promiscuous rx mode, its now converted to be original
772 if (addr
->mc_promisc
) {
773 struct esw_mc_addr
*esw_mc
=
774 l2addr_hash_find(esw
->mc_table
,
779 "Failed to MAC(%pM) in mcast DB\n",
784 addr
->mc_promisc
= false;
789 addr
= l2addr_hash_add(hash
, mac_list
[i
], struct vport_addr
,
793 "Failed to add MAC(%pM) to vport[%d] DB\n",
794 mac_list
[i
], vport
->vport
);
797 addr
->vport
= vport
->vport
;
798 addr
->action
= MLX5_ACTION_ADD
;
804 /* Sync vport UC/MC list from vport context
805 * Must be called after esw_update_vport_addr_list
807 static void esw_update_vport_mc_promisc(struct mlx5_eswitch
*esw
,
808 struct mlx5_vport
*vport
)
810 struct l2addr_node
*node
;
811 struct vport_addr
*addr
;
812 struct hlist_head
*hash
;
813 struct hlist_node
*tmp
;
816 hash
= vport
->mc_list
;
818 for_each_l2hash_node(node
, tmp
, esw
->mc_table
, hi
) {
819 u8
*mac
= node
->addr
;
821 addr
= l2addr_hash_find(hash
, mac
, struct vport_addr
);
823 if (addr
->action
== MLX5_ACTION_DEL
)
824 addr
->action
= MLX5_ACTION_NONE
;
827 addr
= l2addr_hash_add(hash
, mac
, struct vport_addr
,
831 "Failed to add allmulti MAC(%pM) to vport[%d] DB\n",
835 addr
->vport
= vport
->vport
;
836 addr
->action
= MLX5_ACTION_ADD
;
837 addr
->mc_promisc
= true;
841 /* Apply vport rx mode to HW FDB table */
842 static void esw_apply_vport_rx_mode(struct mlx5_eswitch
*esw
,
843 struct mlx5_vport
*vport
,
844 bool promisc
, bool mc_promisc
)
846 struct esw_mc_addr
*allmulti_addr
= &esw
->mc_promisc
;
848 if (IS_ERR_OR_NULL(vport
->allmulti_rule
) != mc_promisc
)
852 vport
->allmulti_rule
=
853 esw_fdb_set_vport_allmulti_rule(esw
, vport
->vport
);
854 if (!allmulti_addr
->uplink_rule
)
855 allmulti_addr
->uplink_rule
=
856 esw_fdb_set_vport_allmulti_rule(esw
,
858 allmulti_addr
->refcnt
++;
859 } else if (vport
->allmulti_rule
) {
860 mlx5_del_flow_rules(vport
->allmulti_rule
);
861 vport
->allmulti_rule
= NULL
;
863 if (--allmulti_addr
->refcnt
> 0)
866 if (allmulti_addr
->uplink_rule
)
867 mlx5_del_flow_rules(allmulti_addr
->uplink_rule
);
868 allmulti_addr
->uplink_rule
= NULL
;
872 if (IS_ERR_OR_NULL(vport
->promisc_rule
) != promisc
)
876 vport
->promisc_rule
=
877 esw_fdb_set_vport_promisc_rule(esw
, vport
->vport
);
878 } else if (vport
->promisc_rule
) {
879 mlx5_del_flow_rules(vport
->promisc_rule
);
880 vport
->promisc_rule
= NULL
;
884 /* Sync vport rx mode from vport context */
885 static void esw_update_vport_rx_mode(struct mlx5_eswitch
*esw
,
886 struct mlx5_vport
*vport
)
893 err
= mlx5_query_nic_vport_promisc(esw
->dev
,
900 esw_debug(esw
->dev
, "vport[%d] context update rx mode promisc_all=%d, all_multi=%d\n",
901 vport
->vport
, promisc_all
, promisc_mc
);
903 if (!vport
->info
.trusted
|| !vport
->enabled
) {
909 esw_apply_vport_rx_mode(esw
, vport
, promisc_all
,
910 (promisc_all
|| promisc_mc
));
913 static void esw_vport_change_handle_locked(struct mlx5_vport
*vport
)
915 struct mlx5_core_dev
*dev
= vport
->dev
;
916 struct mlx5_eswitch
*esw
= dev
->priv
.eswitch
;
919 mlx5_query_nic_vport_mac_address(dev
, vport
->vport
, true, mac
);
920 esw_debug(dev
, "vport[%d] Context Changed: perm mac: %pM\n",
923 if (vport
->enabled_events
& MLX5_VPORT_UC_ADDR_CHANGE
) {
924 esw_update_vport_addr_list(esw
, vport
, MLX5_NVPRT_LIST_TYPE_UC
);
925 esw_apply_vport_addr_list(esw
, vport
, MLX5_NVPRT_LIST_TYPE_UC
);
928 if (vport
->enabled_events
& MLX5_VPORT_MC_ADDR_CHANGE
)
929 esw_update_vport_addr_list(esw
, vport
, MLX5_NVPRT_LIST_TYPE_MC
);
931 if (vport
->enabled_events
& MLX5_VPORT_PROMISC_CHANGE
) {
932 esw_update_vport_rx_mode(esw
, vport
);
933 if (!IS_ERR_OR_NULL(vport
->allmulti_rule
))
934 esw_update_vport_mc_promisc(esw
, vport
);
937 if (vport
->enabled_events
& (MLX5_VPORT_PROMISC_CHANGE
| MLX5_VPORT_MC_ADDR_CHANGE
))
938 esw_apply_vport_addr_list(esw
, vport
, MLX5_NVPRT_LIST_TYPE_MC
);
940 esw_debug(esw
->dev
, "vport[%d] Context Changed: Done\n", vport
->vport
);
942 arm_vport_context_events_cmd(dev
, vport
->vport
,
943 vport
->enabled_events
);
946 static void esw_vport_change_handler(struct work_struct
*work
)
948 struct mlx5_vport
*vport
=
949 container_of(work
, struct mlx5_vport
, vport_change_handler
);
950 struct mlx5_eswitch
*esw
= vport
->dev
->priv
.eswitch
;
952 mutex_lock(&esw
->state_lock
);
953 esw_vport_change_handle_locked(vport
);
954 mutex_unlock(&esw
->state_lock
);
957 int esw_vport_enable_egress_acl(struct mlx5_eswitch
*esw
,
958 struct mlx5_vport
*vport
)
960 int inlen
= MLX5_ST_SZ_BYTES(create_flow_group_in
);
961 struct mlx5_flow_group
*vlan_grp
= NULL
;
962 struct mlx5_flow_group
*drop_grp
= NULL
;
963 struct mlx5_core_dev
*dev
= esw
->dev
;
964 struct mlx5_flow_namespace
*root_ns
;
965 struct mlx5_flow_table
*acl
;
966 void *match_criteria
;
968 /* The egress acl table contains 2 rules:
969 * 1)Allow traffic with vlan_tag=vst_vlan_id
970 * 2)Drop all other traffic.
975 if (!MLX5_CAP_ESW_EGRESS_ACL(dev
, ft_support
))
978 if (!IS_ERR_OR_NULL(vport
->egress
.acl
))
981 esw_debug(dev
, "Create vport[%d] egress ACL log_max_size(%d)\n",
982 vport
->vport
, MLX5_CAP_ESW_EGRESS_ACL(dev
, log_max_ft_size
));
984 root_ns
= mlx5_get_flow_vport_acl_namespace(dev
, MLX5_FLOW_NAMESPACE_ESW_EGRESS
,
985 mlx5_eswitch_vport_num_to_index(esw
, vport
->vport
));
987 esw_warn(dev
, "Failed to get E-Switch egress flow namespace for vport (%d)\n", vport
->vport
);
991 flow_group_in
= kvzalloc(inlen
, GFP_KERNEL
);
995 acl
= mlx5_create_vport_flow_table(root_ns
, 0, table_size
, 0, vport
->vport
);
998 esw_warn(dev
, "Failed to create E-Switch vport[%d] egress flow Table, err(%d)\n",
1003 MLX5_SET(create_flow_group_in
, flow_group_in
, match_criteria_enable
, MLX5_MATCH_OUTER_HEADERS
);
1004 match_criteria
= MLX5_ADDR_OF(create_flow_group_in
, flow_group_in
, match_criteria
);
1005 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, outer_headers
.cvlan_tag
);
1006 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, outer_headers
.first_vid
);
1007 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, 0);
1008 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, 0);
1010 vlan_grp
= mlx5_create_flow_group(acl
, flow_group_in
);
1011 if (IS_ERR(vlan_grp
)) {
1012 err
= PTR_ERR(vlan_grp
);
1013 esw_warn(dev
, "Failed to create E-Switch vport[%d] egress allowed vlans flow group, err(%d)\n",
1018 memset(flow_group_in
, 0, inlen
);
1019 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, 1);
1020 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, 1);
1021 drop_grp
= mlx5_create_flow_group(acl
, flow_group_in
);
1022 if (IS_ERR(drop_grp
)) {
1023 err
= PTR_ERR(drop_grp
);
1024 esw_warn(dev
, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n",
1029 vport
->egress
.acl
= acl
;
1030 vport
->egress
.drop_grp
= drop_grp
;
1031 vport
->egress
.allowed_vlans_grp
= vlan_grp
;
1033 kvfree(flow_group_in
);
1034 if (err
&& !IS_ERR_OR_NULL(vlan_grp
))
1035 mlx5_destroy_flow_group(vlan_grp
);
1036 if (err
&& !IS_ERR_OR_NULL(acl
))
1037 mlx5_destroy_flow_table(acl
);
1041 void esw_vport_cleanup_egress_rules(struct mlx5_eswitch
*esw
,
1042 struct mlx5_vport
*vport
)
1044 if (!IS_ERR_OR_NULL(vport
->egress
.allowed_vlan
)) {
1045 mlx5_del_flow_rules(vport
->egress
.allowed_vlan
);
1046 vport
->egress
.allowed_vlan
= NULL
;
1049 if (!IS_ERR_OR_NULL(vport
->egress
.legacy
.drop_rule
)) {
1050 mlx5_del_flow_rules(vport
->egress
.legacy
.drop_rule
);
1051 vport
->egress
.legacy
.drop_rule
= NULL
;
1055 void esw_vport_disable_egress_acl(struct mlx5_eswitch
*esw
,
1056 struct mlx5_vport
*vport
)
1058 if (IS_ERR_OR_NULL(vport
->egress
.acl
))
1061 esw_debug(esw
->dev
, "Destroy vport[%d] E-Switch egress ACL\n", vport
->vport
);
1063 esw_vport_cleanup_egress_rules(esw
, vport
);
1064 mlx5_destroy_flow_group(vport
->egress
.allowed_vlans_grp
);
1065 mlx5_destroy_flow_group(vport
->egress
.drop_grp
);
1066 mlx5_destroy_flow_table(vport
->egress
.acl
);
1067 vport
->egress
.allowed_vlans_grp
= NULL
;
1068 vport
->egress
.drop_grp
= NULL
;
1069 vport
->egress
.acl
= NULL
;
1073 esw_vport_create_legacy_ingress_acl_groups(struct mlx5_eswitch
*esw
,
1074 struct mlx5_vport
*vport
)
1076 int inlen
= MLX5_ST_SZ_BYTES(create_flow_group_in
);
1077 struct mlx5_core_dev
*dev
= esw
->dev
;
1078 struct mlx5_flow_group
*g
;
1079 void *match_criteria
;
1083 flow_group_in
= kvzalloc(inlen
, GFP_KERNEL
);
1087 match_criteria
= MLX5_ADDR_OF(create_flow_group_in
, flow_group_in
, match_criteria
);
1089 MLX5_SET(create_flow_group_in
, flow_group_in
, match_criteria_enable
, MLX5_MATCH_OUTER_HEADERS
);
1090 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, outer_headers
.cvlan_tag
);
1091 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, outer_headers
.smac_47_16
);
1092 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, outer_headers
.smac_15_0
);
1093 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, 0);
1094 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, 0);
1096 g
= mlx5_create_flow_group(vport
->ingress
.acl
, flow_group_in
);
1099 esw_warn(dev
, "vport[%d] ingress create untagged spoofchk flow group, err(%d)\n",
1103 vport
->ingress
.legacy
.allow_untagged_spoofchk_grp
= g
;
1105 memset(flow_group_in
, 0, inlen
);
1106 MLX5_SET(create_flow_group_in
, flow_group_in
, match_criteria_enable
, MLX5_MATCH_OUTER_HEADERS
);
1107 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, outer_headers
.cvlan_tag
);
1108 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, 1);
1109 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, 1);
1111 g
= mlx5_create_flow_group(vport
->ingress
.acl
, flow_group_in
);
1114 esw_warn(dev
, "vport[%d] ingress create untagged flow group, err(%d)\n",
1118 vport
->ingress
.legacy
.allow_untagged_only_grp
= g
;
1120 memset(flow_group_in
, 0, inlen
);
1121 MLX5_SET(create_flow_group_in
, flow_group_in
, match_criteria_enable
, MLX5_MATCH_OUTER_HEADERS
);
1122 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, outer_headers
.smac_47_16
);
1123 MLX5_SET_TO_ONES(fte_match_param
, match_criteria
, outer_headers
.smac_15_0
);
1124 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, 2);
1125 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, 2);
1127 g
= mlx5_create_flow_group(vport
->ingress
.acl
, flow_group_in
);
1130 esw_warn(dev
, "vport[%d] ingress create spoofchk flow group, err(%d)\n",
1132 goto allow_spoof_err
;
1134 vport
->ingress
.legacy
.allow_spoofchk_only_grp
= g
;
1136 memset(flow_group_in
, 0, inlen
);
1137 MLX5_SET(create_flow_group_in
, flow_group_in
, start_flow_index
, 3);
1138 MLX5_SET(create_flow_group_in
, flow_group_in
, end_flow_index
, 3);
1140 g
= mlx5_create_flow_group(vport
->ingress
.acl
, flow_group_in
);
1143 esw_warn(dev
, "vport[%d] ingress create drop flow group, err(%d)\n",
1147 vport
->ingress
.legacy
.drop_grp
= g
;
1148 kvfree(flow_group_in
);
1152 if (!IS_ERR_OR_NULL(vport
->ingress
.legacy
.allow_spoofchk_only_grp
)) {
1153 mlx5_destroy_flow_group(vport
->ingress
.legacy
.allow_spoofchk_only_grp
);
1154 vport
->ingress
.legacy
.allow_spoofchk_only_grp
= NULL
;
1157 if (!IS_ERR_OR_NULL(vport
->ingress
.legacy
.allow_untagged_only_grp
)) {
1158 mlx5_destroy_flow_group(vport
->ingress
.legacy
.allow_untagged_only_grp
);
1159 vport
->ingress
.legacy
.allow_untagged_only_grp
= NULL
;
1162 if (!IS_ERR_OR_NULL(vport
->ingress
.legacy
.allow_untagged_spoofchk_grp
)) {
1163 mlx5_destroy_flow_group(vport
->ingress
.legacy
.allow_untagged_spoofchk_grp
);
1164 vport
->ingress
.legacy
.allow_untagged_spoofchk_grp
= NULL
;
1167 kvfree(flow_group_in
);
1171 int esw_vport_create_ingress_acl_table(struct mlx5_eswitch
*esw
,
1172 struct mlx5_vport
*vport
, int table_size
)
1174 struct mlx5_core_dev
*dev
= esw
->dev
;
1175 struct mlx5_flow_namespace
*root_ns
;
1176 struct mlx5_flow_table
*acl
;
1180 if (!MLX5_CAP_ESW_INGRESS_ACL(dev
, ft_support
))
1183 esw_debug(dev
, "Create vport[%d] ingress ACL log_max_size(%d)\n",
1184 vport
->vport
, MLX5_CAP_ESW_INGRESS_ACL(dev
, log_max_ft_size
));
1186 vport_index
= mlx5_eswitch_vport_num_to_index(esw
, vport
->vport
);
1187 root_ns
= mlx5_get_flow_vport_acl_namespace(dev
, MLX5_FLOW_NAMESPACE_ESW_INGRESS
,
1190 esw_warn(dev
, "Failed to get E-Switch ingress flow namespace for vport (%d)\n",
1195 acl
= mlx5_create_vport_flow_table(root_ns
, 0, table_size
, 0, vport
->vport
);
1198 esw_warn(dev
, "vport[%d] ingress create flow Table, err(%d)\n",
1202 vport
->ingress
.acl
= acl
;
1206 void esw_vport_destroy_ingress_acl_table(struct mlx5_vport
*vport
)
1208 if (!vport
->ingress
.acl
)
1211 mlx5_destroy_flow_table(vport
->ingress
.acl
);
1212 vport
->ingress
.acl
= NULL
;
1215 void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch
*esw
,
1216 struct mlx5_vport
*vport
)
1218 if (vport
->ingress
.legacy
.drop_rule
) {
1219 mlx5_del_flow_rules(vport
->ingress
.legacy
.drop_rule
);
1220 vport
->ingress
.legacy
.drop_rule
= NULL
;
1223 if (vport
->ingress
.allow_rule
) {
1224 mlx5_del_flow_rules(vport
->ingress
.allow_rule
);
1225 vport
->ingress
.allow_rule
= NULL
;
1229 static void esw_vport_disable_legacy_ingress_acl(struct mlx5_eswitch
*esw
,
1230 struct mlx5_vport
*vport
)
1232 if (!vport
->ingress
.acl
)
1235 esw_debug(esw
->dev
, "Destroy vport[%d] E-Switch ingress ACL\n", vport
->vport
);
1237 esw_vport_cleanup_ingress_rules(esw
, vport
);
1238 if (vport
->ingress
.legacy
.allow_spoofchk_only_grp
) {
1239 mlx5_destroy_flow_group(vport
->ingress
.legacy
.allow_spoofchk_only_grp
);
1240 vport
->ingress
.legacy
.allow_spoofchk_only_grp
= NULL
;
1242 if (vport
->ingress
.legacy
.allow_untagged_only_grp
) {
1243 mlx5_destroy_flow_group(vport
->ingress
.legacy
.allow_untagged_only_grp
);
1244 vport
->ingress
.legacy
.allow_untagged_only_grp
= NULL
;
1246 if (vport
->ingress
.legacy
.allow_untagged_spoofchk_grp
) {
1247 mlx5_destroy_flow_group(vport
->ingress
.legacy
.allow_untagged_spoofchk_grp
);
1248 vport
->ingress
.legacy
.allow_untagged_spoofchk_grp
= NULL
;
1250 if (vport
->ingress
.legacy
.drop_grp
) {
1251 mlx5_destroy_flow_group(vport
->ingress
.legacy
.drop_grp
);
1252 vport
->ingress
.legacy
.drop_grp
= NULL
;
1254 esw_vport_destroy_ingress_acl_table(vport
);
1257 static int esw_vport_ingress_config(struct mlx5_eswitch
*esw
,
1258 struct mlx5_vport
*vport
)
1260 struct mlx5_fc
*counter
= vport
->ingress
.legacy
.drop_counter
;
1261 struct mlx5_flow_destination drop_ctr_dst
= {0};
1262 struct mlx5_flow_destination
*dst
= NULL
;
1263 struct mlx5_flow_act flow_act
= {0};
1264 struct mlx5_flow_spec
*spec
= NULL
;
1269 /* The ingress acl table contains 4 groups
1270 * (2 active rules at the same time -
1271 * 1 allow rule from one of the first 3 groups.
1272 * 1 drop rule from the last group):
1273 * 1)Allow untagged traffic with smac=original mac.
1274 * 2)Allow untagged traffic.
1275 * 3)Allow traffic with smac=original mac.
1276 * 4)Drop all other traffic.
1280 esw_vport_cleanup_ingress_rules(esw
, vport
);
1282 if (!vport
->info
.vlan
&& !vport
->info
.qos
&& !vport
->info
.spoofchk
) {
1283 esw_vport_disable_legacy_ingress_acl(esw
, vport
);
1287 if (!vport
->ingress
.acl
) {
1288 err
= esw_vport_create_ingress_acl_table(esw
, vport
, table_size
);
1291 "vport[%d] enable ingress acl err (%d)\n",
1296 err
= esw_vport_create_legacy_ingress_acl_groups(esw
, vport
);
1302 "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n",
1303 vport
->vport
, vport
->info
.vlan
, vport
->info
.qos
);
1305 spec
= kvzalloc(sizeof(*spec
), GFP_KERNEL
);
1311 if (vport
->info
.vlan
|| vport
->info
.qos
)
1312 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.cvlan_tag
);
1314 if (vport
->info
.spoofchk
) {
1315 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.smac_47_16
);
1316 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.smac_15_0
);
1317 smac_v
= MLX5_ADDR_OF(fte_match_param
,
1319 outer_headers
.smac_47_16
);
1320 ether_addr_copy(smac_v
, vport
->info
.mac
);
1323 spec
->match_criteria_enable
= MLX5_MATCH_OUTER_HEADERS
;
1324 flow_act
.action
= MLX5_FLOW_CONTEXT_ACTION_ALLOW
;
1325 vport
->ingress
.allow_rule
=
1326 mlx5_add_flow_rules(vport
->ingress
.acl
, spec
,
1327 &flow_act
, NULL
, 0);
1328 if (IS_ERR(vport
->ingress
.allow_rule
)) {
1329 err
= PTR_ERR(vport
->ingress
.allow_rule
);
1331 "vport[%d] configure ingress allow rule, err(%d)\n",
1333 vport
->ingress
.allow_rule
= NULL
;
1337 flow_act
.action
= MLX5_FLOW_CONTEXT_ACTION_DROP
;
1339 /* Attach drop flow counter */
1341 flow_act
.action
|= MLX5_FLOW_CONTEXT_ACTION_COUNT
;
1342 drop_ctr_dst
.type
= MLX5_FLOW_DESTINATION_TYPE_COUNTER
;
1343 drop_ctr_dst
.counter_id
= mlx5_fc_id(counter
);
1344 dst
= &drop_ctr_dst
;
1347 vport
->ingress
.legacy
.drop_rule
=
1348 mlx5_add_flow_rules(vport
->ingress
.acl
, NULL
,
1349 &flow_act
, dst
, dest_num
);
1350 if (IS_ERR(vport
->ingress
.legacy
.drop_rule
)) {
1351 err
= PTR_ERR(vport
->ingress
.legacy
.drop_rule
);
1353 "vport[%d] configure ingress drop rule, err(%d)\n",
1355 vport
->ingress
.legacy
.drop_rule
= NULL
;
1362 esw_vport_disable_legacy_ingress_acl(esw
, vport
);
1367 int mlx5_esw_create_vport_egress_acl_vlan(struct mlx5_eswitch
*esw
,
1368 struct mlx5_vport
*vport
,
1369 u16 vlan_id
, u32 flow_action
)
1371 struct mlx5_flow_act flow_act
= {};
1372 struct mlx5_flow_spec
*spec
;
1375 if (vport
->egress
.allowed_vlan
)
1378 spec
= kvzalloc(sizeof(*spec
), GFP_KERNEL
);
1382 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.cvlan_tag
);
1383 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_value
, outer_headers
.cvlan_tag
);
1384 MLX5_SET_TO_ONES(fte_match_param
, spec
->match_criteria
, outer_headers
.first_vid
);
1385 MLX5_SET(fte_match_param
, spec
->match_value
, outer_headers
.first_vid
, vlan_id
);
1387 spec
->match_criteria_enable
= MLX5_MATCH_OUTER_HEADERS
;
1388 flow_act
.action
= flow_action
;
1389 vport
->egress
.allowed_vlan
=
1390 mlx5_add_flow_rules(vport
->egress
.acl
, spec
,
1391 &flow_act
, NULL
, 0);
1392 if (IS_ERR(vport
->egress
.allowed_vlan
)) {
1393 err
= PTR_ERR(vport
->egress
.allowed_vlan
);
1395 "vport[%d] configure egress vlan rule failed, err(%d)\n",
1397 vport
->egress
.allowed_vlan
= NULL
;
1404 static int esw_vport_egress_config(struct mlx5_eswitch
*esw
,
1405 struct mlx5_vport
*vport
)
1407 struct mlx5_fc
*counter
= vport
->egress
.legacy
.drop_counter
;
1408 struct mlx5_flow_destination drop_ctr_dst
= {0};
1409 struct mlx5_flow_destination
*dst
= NULL
;
1410 struct mlx5_flow_act flow_act
= {0};
1414 esw_vport_cleanup_egress_rules(esw
, vport
);
1416 if (!vport
->info
.vlan
&& !vport
->info
.qos
) {
1417 esw_vport_disable_egress_acl(esw
, vport
);
1421 err
= esw_vport_enable_egress_acl(esw
, vport
);
1423 mlx5_core_warn(esw
->dev
,
1424 "failed to enable egress acl (%d) on vport[%d]\n",
1430 "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
1431 vport
->vport
, vport
->info
.vlan
, vport
->info
.qos
);
1433 /* Allowed vlan rule */
1434 err
= mlx5_esw_create_vport_egress_acl_vlan(esw
, vport
, vport
->info
.vlan
,
1435 MLX5_FLOW_CONTEXT_ACTION_ALLOW
);
1439 flow_act
.action
= MLX5_FLOW_CONTEXT_ACTION_DROP
;
1441 /* Attach egress drop flow counter */
1443 flow_act
.action
|= MLX5_FLOW_CONTEXT_ACTION_COUNT
;
1444 drop_ctr_dst
.type
= MLX5_FLOW_DESTINATION_TYPE_COUNTER
;
1445 drop_ctr_dst
.counter_id
= mlx5_fc_id(counter
);
1446 dst
= &drop_ctr_dst
;
1449 vport
->egress
.legacy
.drop_rule
=
1450 mlx5_add_flow_rules(vport
->egress
.acl
, NULL
,
1451 &flow_act
, dst
, dest_num
);
1452 if (IS_ERR(vport
->egress
.legacy
.drop_rule
)) {
1453 err
= PTR_ERR(vport
->egress
.legacy
.drop_rule
);
1455 "vport[%d] configure egress drop rule failed, err(%d)\n",
1457 vport
->egress
.legacy
.drop_rule
= NULL
;
1463 static bool element_type_supported(struct mlx5_eswitch
*esw
, int type
)
1465 const struct mlx5_core_dev
*dev
= esw
->dev
;
1468 case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR
:
1469 return MLX5_CAP_QOS(dev
, esw_element_type
) &
1470 ELEMENT_TYPE_CAP_MASK_TASR
;
1471 case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT
:
1472 return MLX5_CAP_QOS(dev
, esw_element_type
) &
1473 ELEMENT_TYPE_CAP_MASK_VPORT
;
1474 case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC
:
1475 return MLX5_CAP_QOS(dev
, esw_element_type
) &
1476 ELEMENT_TYPE_CAP_MASK_VPORT_TC
;
1477 case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC
:
1478 return MLX5_CAP_QOS(dev
, esw_element_type
) &
1479 ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC
;
1484 /* Vport QoS management */
1485 static void esw_create_tsar(struct mlx5_eswitch
*esw
)
1487 u32 tsar_ctx
[MLX5_ST_SZ_DW(scheduling_context
)] = {0};
1488 struct mlx5_core_dev
*dev
= esw
->dev
;
1492 if (!MLX5_CAP_GEN(dev
, qos
) || !MLX5_CAP_QOS(dev
, esw_scheduling
))
1495 if (!element_type_supported(esw
, SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR
))
1498 if (esw
->qos
.enabled
)
1501 MLX5_SET(scheduling_context
, tsar_ctx
, element_type
,
1502 SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR
);
1504 attr
= MLX5_ADDR_OF(scheduling_context
, tsar_ctx
, element_attributes
);
1505 *attr
= cpu_to_be32(TSAR_ELEMENT_TSAR_TYPE_DWRR
<< 16);
1507 err
= mlx5_create_scheduling_element_cmd(dev
,
1508 SCHEDULING_HIERARCHY_E_SWITCH
,
1510 &esw
->qos
.root_tsar_id
);
1512 esw_warn(esw
->dev
, "E-Switch create TSAR failed (%d)\n", err
);
1516 esw
->qos
.enabled
= true;
1519 static void esw_destroy_tsar(struct mlx5_eswitch
*esw
)
1523 if (!esw
->qos
.enabled
)
1526 err
= mlx5_destroy_scheduling_element_cmd(esw
->dev
,
1527 SCHEDULING_HIERARCHY_E_SWITCH
,
1528 esw
->qos
.root_tsar_id
);
1530 esw_warn(esw
->dev
, "E-Switch destroy TSAR failed (%d)\n", err
);
1532 esw
->qos
.enabled
= false;
1535 static int esw_vport_enable_qos(struct mlx5_eswitch
*esw
,
1536 struct mlx5_vport
*vport
,
1537 u32 initial_max_rate
, u32 initial_bw_share
)
1539 u32 sched_ctx
[MLX5_ST_SZ_DW(scheduling_context
)] = {0};
1540 struct mlx5_core_dev
*dev
= esw
->dev
;
1544 if (!esw
->qos
.enabled
|| !MLX5_CAP_GEN(dev
, qos
) ||
1545 !MLX5_CAP_QOS(dev
, esw_scheduling
))
1548 if (vport
->qos
.enabled
)
1551 MLX5_SET(scheduling_context
, sched_ctx
, element_type
,
1552 SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT
);
1553 vport_elem
= MLX5_ADDR_OF(scheduling_context
, sched_ctx
,
1554 element_attributes
);
1555 MLX5_SET(vport_element
, vport_elem
, vport_number
, vport
->vport
);
1556 MLX5_SET(scheduling_context
, sched_ctx
, parent_element_id
,
1557 esw
->qos
.root_tsar_id
);
1558 MLX5_SET(scheduling_context
, sched_ctx
, max_average_bw
,
1560 MLX5_SET(scheduling_context
, sched_ctx
, bw_share
, initial_bw_share
);
1562 err
= mlx5_create_scheduling_element_cmd(dev
,
1563 SCHEDULING_HIERARCHY_E_SWITCH
,
1565 &vport
->qos
.esw_tsar_ix
);
1567 esw_warn(esw
->dev
, "E-Switch create TSAR vport element failed (vport=%d,err=%d)\n",
1572 vport
->qos
.enabled
= true;
1576 static void esw_vport_disable_qos(struct mlx5_eswitch
*esw
,
1577 struct mlx5_vport
*vport
)
1581 if (!vport
->qos
.enabled
)
1584 err
= mlx5_destroy_scheduling_element_cmd(esw
->dev
,
1585 SCHEDULING_HIERARCHY_E_SWITCH
,
1586 vport
->qos
.esw_tsar_ix
);
1588 esw_warn(esw
->dev
, "E-Switch destroy TSAR vport element failed (vport=%d,err=%d)\n",
1591 vport
->qos
.enabled
= false;
1594 static int esw_vport_qos_config(struct mlx5_eswitch
*esw
,
1595 struct mlx5_vport
*vport
,
1596 u32 max_rate
, u32 bw_share
)
1598 u32 sched_ctx
[MLX5_ST_SZ_DW(scheduling_context
)] = {0};
1599 struct mlx5_core_dev
*dev
= esw
->dev
;
1604 if (!MLX5_CAP_GEN(dev
, qos
) || !MLX5_CAP_QOS(dev
, esw_scheduling
))
1607 if (!vport
->qos
.enabled
)
1610 MLX5_SET(scheduling_context
, sched_ctx
, element_type
,
1611 SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT
);
1612 vport_elem
= MLX5_ADDR_OF(scheduling_context
, sched_ctx
,
1613 element_attributes
);
1614 MLX5_SET(vport_element
, vport_elem
, vport_number
, vport
->vport
);
1615 MLX5_SET(scheduling_context
, sched_ctx
, parent_element_id
,
1616 esw
->qos
.root_tsar_id
);
1617 MLX5_SET(scheduling_context
, sched_ctx
, max_average_bw
,
1619 MLX5_SET(scheduling_context
, sched_ctx
, bw_share
, bw_share
);
1620 bitmask
|= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW
;
1621 bitmask
|= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE
;
1623 err
= mlx5_modify_scheduling_element_cmd(dev
,
1624 SCHEDULING_HIERARCHY_E_SWITCH
,
1626 vport
->qos
.esw_tsar_ix
,
1629 esw_warn(esw
->dev
, "E-Switch modify TSAR vport element failed (vport=%d,err=%d)\n",
1637 int mlx5_esw_modify_vport_rate(struct mlx5_eswitch
*esw
, u16 vport_num
,
1640 u32 ctx
[MLX5_ST_SZ_DW(scheduling_context
)] = {};
1641 struct mlx5_vport
*vport
;
1643 vport
= mlx5_eswitch_get_vport(esw
, vport_num
);
1644 MLX5_SET(scheduling_context
, ctx
, max_average_bw
, rate_mbps
);
1646 return mlx5_modify_scheduling_element_cmd(esw
->dev
,
1647 SCHEDULING_HIERARCHY_E_SWITCH
,
1649 vport
->qos
.esw_tsar_ix
,
1650 MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW
);
1653 static void node_guid_gen_from_mac(u64
*node_guid
, u8 mac
[ETH_ALEN
])
1655 ((u8
*)node_guid
)[7] = mac
[0];
1656 ((u8
*)node_guid
)[6] = mac
[1];
1657 ((u8
*)node_guid
)[5] = mac
[2];
1658 ((u8
*)node_guid
)[4] = 0xff;
1659 ((u8
*)node_guid
)[3] = 0xfe;
1660 ((u8
*)node_guid
)[2] = mac
[3];
1661 ((u8
*)node_guid
)[1] = mac
[4];
1662 ((u8
*)node_guid
)[0] = mac
[5];
1665 static int esw_vport_create_legacy_acl_tables(struct mlx5_eswitch
*esw
,
1666 struct mlx5_vport
*vport
)
1670 /* Only non manager vports need ACL in legacy mode */
1671 if (mlx5_esw_is_manager_vport(esw
, vport
->vport
))
1674 if (MLX5_CAP_ESW_INGRESS_ACL(esw
->dev
, flow_counter
)) {
1675 vport
->ingress
.legacy
.drop_counter
= mlx5_fc_create(esw
->dev
, false);
1676 if (IS_ERR(vport
->ingress
.legacy
.drop_counter
)) {
1678 "vport[%d] configure ingress drop rule counter failed\n",
1680 vport
->ingress
.legacy
.drop_counter
= NULL
;
1684 ret
= esw_vport_ingress_config(esw
, vport
);
1688 if (MLX5_CAP_ESW_EGRESS_ACL(esw
->dev
, flow_counter
)) {
1689 vport
->egress
.legacy
.drop_counter
= mlx5_fc_create(esw
->dev
, false);
1690 if (IS_ERR(vport
->egress
.legacy
.drop_counter
)) {
1692 "vport[%d] configure egress drop rule counter failed\n",
1694 vport
->egress
.legacy
.drop_counter
= NULL
;
1698 ret
= esw_vport_egress_config(esw
, vport
);
1705 esw_vport_disable_legacy_ingress_acl(esw
, vport
);
1706 mlx5_fc_destroy(esw
->dev
, vport
->egress
.legacy
.drop_counter
);
1707 vport
->egress
.legacy
.drop_counter
= NULL
;
1710 mlx5_fc_destroy(esw
->dev
, vport
->ingress
.legacy
.drop_counter
);
1711 vport
->ingress
.legacy
.drop_counter
= NULL
;
1715 static int esw_vport_setup_acl(struct mlx5_eswitch
*esw
,
1716 struct mlx5_vport
*vport
)
1718 if (esw
->mode
== MLX5_ESWITCH_LEGACY
)
1719 return esw_vport_create_legacy_acl_tables(esw
, vport
);
1721 return esw_vport_create_offloads_acl_tables(esw
, vport
);
1724 static void esw_vport_destroy_legacy_acl_tables(struct mlx5_eswitch
*esw
,
1725 struct mlx5_vport
*vport
)
1728 if (mlx5_esw_is_manager_vport(esw
, vport
->vport
))
1731 esw_vport_disable_egress_acl(esw
, vport
);
1732 mlx5_fc_destroy(esw
->dev
, vport
->egress
.legacy
.drop_counter
);
1733 vport
->egress
.legacy
.drop_counter
= NULL
;
1735 esw_vport_disable_legacy_ingress_acl(esw
, vport
);
1736 mlx5_fc_destroy(esw
->dev
, vport
->ingress
.legacy
.drop_counter
);
1737 vport
->ingress
.legacy
.drop_counter
= NULL
;
1740 static void esw_vport_cleanup_acl(struct mlx5_eswitch
*esw
,
1741 struct mlx5_vport
*vport
)
1743 if (esw
->mode
== MLX5_ESWITCH_LEGACY
)
1744 esw_vport_destroy_legacy_acl_tables(esw
, vport
);
1746 esw_vport_destroy_offloads_acl_tables(esw
, vport
);
1749 static int esw_vport_setup(struct mlx5_eswitch
*esw
, struct mlx5_vport
*vport
)
1751 u16 vport_num
= vport
->vport
;
1755 err
= esw_vport_setup_acl(esw
, vport
);
1759 /* Attach vport to the eswitch rate limiter */
1760 esw_vport_enable_qos(esw
, vport
, vport
->info
.max_rate
, vport
->qos
.bw_share
);
1762 if (mlx5_esw_is_manager_vport(esw
, vport_num
))
1765 mlx5_modify_vport_admin_state(esw
->dev
,
1766 MLX5_VPORT_STATE_OP_MOD_ESW_VPORT
,
1768 vport
->info
.link_state
);
1770 /* Host PF has its own mac/guid. */
1772 mlx5_modify_nic_vport_mac_address(esw
->dev
, vport_num
,
1774 mlx5_modify_nic_vport_node_guid(esw
->dev
, vport_num
,
1775 vport
->info
.node_guid
);
1778 flags
= (vport
->info
.vlan
|| vport
->info
.qos
) ?
1779 SET_VLAN_STRIP
| SET_VLAN_INSERT
: 0;
1780 modify_esw_vport_cvlan(esw
->dev
, vport_num
, vport
->info
.vlan
,
1781 vport
->info
.qos
, flags
);
1786 /* Don't cleanup vport->info, it's needed to restore vport configuration */
1787 static void esw_vport_cleanup(struct mlx5_eswitch
*esw
, struct mlx5_vport
*vport
)
1789 u16 vport_num
= vport
->vport
;
1791 if (!mlx5_esw_is_manager_vport(esw
, vport_num
))
1792 mlx5_modify_vport_admin_state(esw
->dev
,
1793 MLX5_VPORT_STATE_OP_MOD_ESW_VPORT
,
1795 MLX5_VPORT_ADMIN_STATE_DOWN
);
1797 esw_vport_disable_qos(esw
, vport
);
1798 esw_vport_cleanup_acl(esw
, vport
);
1801 static int esw_enable_vport(struct mlx5_eswitch
*esw
, u16 vport_num
,
1802 enum mlx5_eswitch_vport_event enabled_events
)
1804 struct mlx5_vport
*vport
;
1807 vport
= mlx5_eswitch_get_vport(esw
, vport_num
);
1809 mutex_lock(&esw
->state_lock
);
1810 WARN_ON(vport
->enabled
);
1812 esw_debug(esw
->dev
, "Enabling VPORT(%d)\n", vport_num
);
1814 ret
= esw_vport_setup(esw
, vport
);
1818 /* Sync with current vport context */
1819 vport
->enabled_events
= enabled_events
;
1820 vport
->enabled
= true;
1822 /* Esw manager is trusted by default. Host PF (vport 0) is trusted as well
1823 * in smartNIC as it's a vport group manager.
1825 if (mlx5_esw_is_manager_vport(esw
, vport_num
) ||
1826 (!vport_num
&& mlx5_core_is_ecpf(esw
->dev
)))
1827 vport
->info
.trusted
= true;
1829 esw_vport_change_handle_locked(vport
);
1831 esw
->enabled_vports
++;
1832 esw_debug(esw
->dev
, "Enabled VPORT(%d)\n", vport_num
);
1834 mutex_unlock(&esw
->state_lock
);
1838 static void esw_disable_vport(struct mlx5_eswitch
*esw
, u16 vport_num
)
1840 struct mlx5_vport
*vport
;
1842 vport
= mlx5_eswitch_get_vport(esw
, vport_num
);
1844 mutex_lock(&esw
->state_lock
);
1845 if (!vport
->enabled
)
1848 esw_debug(esw
->dev
, "Disabling vport(%d)\n", vport_num
);
1849 /* Mark this vport as disabled to discard new events */
1850 vport
->enabled
= false;
1852 /* Disable events from this vport */
1853 arm_vport_context_events_cmd(esw
->dev
, vport
->vport
, 0);
1854 /* We don't assume VFs will cleanup after themselves.
1855 * Calling vport change handler while vport is disabled will cleanup
1856 * the vport resources.
1858 esw_vport_change_handle_locked(vport
);
1859 vport
->enabled_events
= 0;
1860 esw_vport_cleanup(esw
, vport
);
1861 esw
->enabled_vports
--;
1864 mutex_unlock(&esw
->state_lock
);
1867 static int eswitch_vport_event(struct notifier_block
*nb
,
1868 unsigned long type
, void *data
)
1870 struct mlx5_eswitch
*esw
= mlx5_nb_cof(nb
, struct mlx5_eswitch
, nb
);
1871 struct mlx5_eqe
*eqe
= data
;
1872 struct mlx5_vport
*vport
;
1875 vport_num
= be16_to_cpu(eqe
->data
.vport_change
.vport_num
);
1876 vport
= mlx5_eswitch_get_vport(esw
, vport_num
);
1878 queue_work(esw
->work_queue
, &vport
->vport_change_handler
);
1883 * mlx5_esw_query_functions - Returns raw output about functions state
1884 * @dev: Pointer to device to query
1886 * mlx5_esw_query_functions() allocates and returns functions changed
1887 * raw output memory pointer from device on success. Otherwise returns ERR_PTR.
1888 * Caller must free the memory using kvfree() when valid pointer is returned.
1890 const u32
*mlx5_esw_query_functions(struct mlx5_core_dev
*dev
)
1892 int outlen
= MLX5_ST_SZ_BYTES(query_esw_functions_out
);
1893 u32 in
[MLX5_ST_SZ_DW(query_esw_functions_in
)] = {};
1897 out
= kvzalloc(outlen
, GFP_KERNEL
);
1899 return ERR_PTR(-ENOMEM
);
1901 MLX5_SET(query_esw_functions_in
, in
, opcode
,
1902 MLX5_CMD_OP_QUERY_ESW_FUNCTIONS
);
1904 err
= mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, outlen
);
1909 return ERR_PTR(err
);
1912 static void mlx5_eswitch_event_handlers_register(struct mlx5_eswitch
*esw
)
1914 MLX5_NB_INIT(&esw
->nb
, eswitch_vport_event
, NIC_VPORT_CHANGE
);
1915 mlx5_eq_notifier_register(esw
->dev
, &esw
->nb
);
1917 if (esw
->mode
== MLX5_ESWITCH_OFFLOADS
&& mlx5_eswitch_is_funcs_handler(esw
->dev
)) {
1918 MLX5_NB_INIT(&esw
->esw_funcs
.nb
, mlx5_esw_funcs_changed_handler
,
1919 ESW_FUNCTIONS_CHANGED
);
1920 mlx5_eq_notifier_register(esw
->dev
, &esw
->esw_funcs
.nb
);
1924 static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch
*esw
)
1926 if (esw
->mode
== MLX5_ESWITCH_OFFLOADS
&& mlx5_eswitch_is_funcs_handler(esw
->dev
))
1927 mlx5_eq_notifier_unregister(esw
->dev
, &esw
->esw_funcs
.nb
);
1929 mlx5_eq_notifier_unregister(esw
->dev
, &esw
->nb
);
1931 flush_workqueue(esw
->work_queue
);
1934 static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch
*esw
)
1936 struct mlx5_vport
*vport
;
1939 mlx5_esw_for_each_vf_vport(esw
, i
, vport
, esw
->esw_funcs
.num_vfs
) {
1940 memset(&vport
->info
, 0, sizeof(vport
->info
));
1941 vport
->info
.link_state
= MLX5_VPORT_ADMIN_STATE_AUTO
;
1945 /* Public E-Switch API */
1946 #define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev))
1948 int mlx5_eswitch_load_vport(struct mlx5_eswitch
*esw
, u16 vport_num
,
1949 enum mlx5_eswitch_vport_event enabled_events
)
1953 err
= esw_enable_vport(esw
, vport_num
, enabled_events
);
1957 err
= esw_offloads_load_rep(esw
, vport_num
);
1964 esw_disable_vport(esw
, vport_num
);
1968 void mlx5_eswitch_unload_vport(struct mlx5_eswitch
*esw
, u16 vport_num
)
1970 esw_offloads_unload_rep(esw
, vport_num
);
1971 esw_disable_vport(esw
, vport_num
);
1974 void mlx5_eswitch_unload_vf_vports(struct mlx5_eswitch
*esw
, u16 num_vfs
)
1978 mlx5_esw_for_each_vf_vport_num_reverse(esw
, i
, num_vfs
)
1979 mlx5_eswitch_unload_vport(esw
, i
);
1982 int mlx5_eswitch_load_vf_vports(struct mlx5_eswitch
*esw
, u16 num_vfs
,
1983 enum mlx5_eswitch_vport_event enabled_events
)
1988 mlx5_esw_for_each_vf_vport_num(esw
, i
, num_vfs
) {
1989 err
= mlx5_eswitch_load_vport(esw
, i
, enabled_events
);
1997 mlx5_eswitch_unload_vf_vports(esw
, i
- 1);
2001 /* mlx5_eswitch_enable_pf_vf_vports() enables vports of PF, ECPF and VFs
2002 * whichever are present on the eswitch.
2005 mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch
*esw
,
2006 enum mlx5_eswitch_vport_event enabled_events
)
2010 /* Enable PF vport */
2011 ret
= mlx5_eswitch_load_vport(esw
, MLX5_VPORT_PF
, enabled_events
);
2015 /* Enable ECPF vport */
2016 if (mlx5_ecpf_vport_exists(esw
->dev
)) {
2017 ret
= mlx5_eswitch_load_vport(esw
, MLX5_VPORT_ECPF
, enabled_events
);
2022 /* Enable VF vports */
2023 ret
= mlx5_eswitch_load_vf_vports(esw
, esw
->esw_funcs
.num_vfs
,
2030 if (mlx5_ecpf_vport_exists(esw
->dev
))
2031 mlx5_eswitch_unload_vport(esw
, MLX5_VPORT_ECPF
);
2034 mlx5_eswitch_unload_vport(esw
, MLX5_VPORT_PF
);
2038 /* mlx5_eswitch_disable_pf_vf_vports() disables vports of PF, ECPF and VFs
2039 * whichever are previously enabled on the eswitch.
2041 void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch
*esw
)
2043 mlx5_eswitch_unload_vf_vports(esw
, esw
->esw_funcs
.num_vfs
);
2045 if (mlx5_ecpf_vport_exists(esw
->dev
))
2046 mlx5_eswitch_unload_vport(esw
, MLX5_VPORT_ECPF
);
2048 mlx5_eswitch_unload_vport(esw
, MLX5_VPORT_PF
);
2051 static void mlx5_eswitch_get_devlink_param(struct mlx5_eswitch
*esw
)
2053 struct devlink
*devlink
= priv_to_devlink(esw
->dev
);
2054 union devlink_param_value val
;
2057 err
= devlink_param_driverinit_value_get(devlink
,
2058 MLX5_DEVLINK_PARAM_ID_ESW_LARGE_GROUP_NUM
,
2061 esw
->params
.large_group_num
= val
.vu32
;
2064 "Devlink can't get param fdb_large_groups, uses default (%d).\n",
2065 ESW_OFFLOADS_DEFAULT_NUM_GROUPS
);
2066 esw
->params
.large_group_num
= ESW_OFFLOADS_DEFAULT_NUM_GROUPS
;
2071 mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch
*esw
, int num_vfs
)
2075 WARN_ON_ONCE(esw
->mode
!= MLX5_ESWITCH_NONE
);
2080 if (!mlx5_core_is_ecpf_esw_manager(esw
->dev
)) {
2081 esw
->esw_funcs
.num_vfs
= num_vfs
;
2085 out
= mlx5_esw_query_functions(esw
->dev
);
2089 esw
->esw_funcs
.num_vfs
= MLX5_GET(query_esw_functions_out
, out
,
2090 host_params_context
.host_num_of_vfs
);
2095 * mlx5_eswitch_enable_locked - Enable eswitch
2096 * @esw: Pointer to eswitch
2097 * @mode: Eswitch mode to enable
2098 * @num_vfs: Enable eswitch for given number of VFs. This is optional.
2099 * Valid value are 0, > 0 and MLX5_ESWITCH_IGNORE_NUM_VFS.
2100 * Caller should pass num_vfs > 0 when enabling eswitch for
2101 * vf vports. Caller should pass num_vfs = 0, when eswitch
2102 * is enabled without sriov VFs or when caller
2103 * is unaware of the sriov state of the host PF on ECPF based
2104 * eswitch. Caller should pass < 0 when num_vfs should be
2105 * completely ignored. This is typically the case when eswitch
2106 * is enabled without sriov regardless of PF/ECPF system.
2107 * mlx5_eswitch_enable_locked() Enables eswitch in either legacy or offloads
2108 * mode. If num_vfs >=0 is provided, it setup VF related eswitch vports.
2109 * It returns 0 on success or error code on failure.
2111 int mlx5_eswitch_enable_locked(struct mlx5_eswitch
*esw
, int mode
, int num_vfs
)
2115 lockdep_assert_held(&esw
->mode_lock
);
2117 if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw
->dev
, ft_support
)) {
2118 esw_warn(esw
->dev
, "FDB is not supported, aborting ...\n");
2122 if (!MLX5_CAP_ESW_INGRESS_ACL(esw
->dev
, ft_support
))
2123 esw_warn(esw
->dev
, "ingress ACL is not supported by FW\n");
2125 if (!MLX5_CAP_ESW_EGRESS_ACL(esw
->dev
, ft_support
))
2126 esw_warn(esw
->dev
, "engress ACL is not supported by FW\n");
2128 mlx5_eswitch_get_devlink_param(esw
);
2130 mlx5_eswitch_update_num_of_vfs(esw
, num_vfs
);
2132 esw_create_tsar(esw
);
2136 mlx5_lag_update(esw
->dev
);
2138 if (mode
== MLX5_ESWITCH_LEGACY
) {
2139 err
= esw_legacy_enable(esw
);
2141 mlx5_reload_interface(esw
->dev
, MLX5_INTERFACE_PROTOCOL_ETH
);
2142 mlx5_reload_interface(esw
->dev
, MLX5_INTERFACE_PROTOCOL_IB
);
2143 err
= esw_offloads_enable(esw
);
2149 mlx5_eswitch_event_handlers_register(esw
);
2151 esw_info(esw
->dev
, "Enable: mode(%s), nvfs(%d), active vports(%d)\n",
2152 mode
== MLX5_ESWITCH_LEGACY
? "LEGACY" : "OFFLOADS",
2153 esw
->esw_funcs
.num_vfs
, esw
->enabled_vports
);
2158 esw
->mode
= MLX5_ESWITCH_NONE
;
2160 if (mode
== MLX5_ESWITCH_OFFLOADS
) {
2161 mlx5_reload_interface(esw
->dev
, MLX5_INTERFACE_PROTOCOL_IB
);
2162 mlx5_reload_interface(esw
->dev
, MLX5_INTERFACE_PROTOCOL_ETH
);
2169 * mlx5_eswitch_enable - Enable eswitch
2170 * @esw: Pointer to eswitch
2171 * @num_vfs: Enable eswitch swich for given number of VFs.
2172 * Caller must pass num_vfs > 0 when enabling eswitch for
2174 * mlx5_eswitch_enable() returns 0 on success or error code on failure.
2176 int mlx5_eswitch_enable(struct mlx5_eswitch
*esw
, int num_vfs
)
2180 if (!ESW_ALLOWED(esw
))
2183 mutex_lock(&esw
->mode_lock
);
2184 ret
= mlx5_eswitch_enable_locked(esw
, MLX5_ESWITCH_LEGACY
, num_vfs
);
2185 mutex_unlock(&esw
->mode_lock
);
2189 void mlx5_eswitch_disable_locked(struct mlx5_eswitch
*esw
, bool clear_vf
)
2193 lockdep_assert_held_write(&esw
->mode_lock
);
2195 if (esw
->mode
== MLX5_ESWITCH_NONE
)
2198 esw_info(esw
->dev
, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
2199 esw
->mode
== MLX5_ESWITCH_LEGACY
? "LEGACY" : "OFFLOADS",
2200 esw
->esw_funcs
.num_vfs
, esw
->enabled_vports
);
2202 mlx5_eswitch_event_handlers_unregister(esw
);
2204 if (esw
->mode
== MLX5_ESWITCH_LEGACY
)
2205 esw_legacy_disable(esw
);
2206 else if (esw
->mode
== MLX5_ESWITCH_OFFLOADS
)
2207 esw_offloads_disable(esw
);
2209 esw_destroy_tsar(esw
);
2211 old_mode
= esw
->mode
;
2212 esw
->mode
= MLX5_ESWITCH_NONE
;
2214 mlx5_lag_update(esw
->dev
);
2216 if (old_mode
== MLX5_ESWITCH_OFFLOADS
) {
2217 mlx5_reload_interface(esw
->dev
, MLX5_INTERFACE_PROTOCOL_IB
);
2218 mlx5_reload_interface(esw
->dev
, MLX5_INTERFACE_PROTOCOL_ETH
);
2221 mlx5_eswitch_clear_vf_vports_info(esw
);
2224 void mlx5_eswitch_disable(struct mlx5_eswitch
*esw
, bool clear_vf
)
2226 if (!ESW_ALLOWED(esw
))
2229 mutex_lock(&esw
->mode_lock
);
2230 mlx5_eswitch_disable_locked(esw
, clear_vf
);
2231 mutex_unlock(&esw
->mode_lock
);
2234 int mlx5_eswitch_init(struct mlx5_core_dev
*dev
)
2236 struct mlx5_eswitch
*esw
;
2237 struct mlx5_vport
*vport
;
2241 if (!MLX5_VPORT_MANAGER(dev
))
2244 total_vports
= mlx5_eswitch_get_total_vports(dev
);
2247 "Total vports %d, per vport: max uc(%d) max mc(%d)\n",
2249 MLX5_MAX_UC_PER_VPORT(dev
),
2250 MLX5_MAX_MC_PER_VPORT(dev
));
2252 esw
= kzalloc(sizeof(*esw
), GFP_KERNEL
);
2257 esw
->manager_vport
= mlx5_eswitch_manager_vport(dev
);
2258 esw
->first_host_vport
= mlx5_eswitch_first_host_vport_num(dev
);
2260 esw
->work_queue
= create_singlethread_workqueue("mlx5_esw_wq");
2261 if (!esw
->work_queue
) {
2266 esw
->vports
= kcalloc(total_vports
, sizeof(struct mlx5_vport
),
2273 esw
->total_vports
= total_vports
;
2275 err
= esw_offloads_init_reps(esw
);
2279 mutex_init(&esw
->offloads
.encap_tbl_lock
);
2280 hash_init(esw
->offloads
.encap_tbl
);
2281 mutex_init(&esw
->offloads
.mod_hdr
.lock
);
2282 hash_init(esw
->offloads
.mod_hdr
.hlist
);
2283 atomic64_set(&esw
->offloads
.num_flows
, 0);
2284 mutex_init(&esw
->state_lock
);
2285 mutex_init(&esw
->mode_lock
);
2287 mlx5_esw_for_all_vports(esw
, i
, vport
) {
2288 vport
->vport
= mlx5_eswitch_index_to_vport_num(esw
, i
);
2289 vport
->info
.link_state
= MLX5_VPORT_ADMIN_STATE_AUTO
;
2291 INIT_WORK(&vport
->vport_change_handler
,
2292 esw_vport_change_handler
);
2295 esw
->enabled_vports
= 0;
2296 esw
->mode
= MLX5_ESWITCH_NONE
;
2297 esw
->offloads
.inline_mode
= MLX5_INLINE_MODE_NONE
;
2299 dev
->priv
.eswitch
= esw
;
2302 if (esw
->work_queue
)
2303 destroy_workqueue(esw
->work_queue
);
2304 esw_offloads_cleanup_reps(esw
);
2310 void mlx5_eswitch_cleanup(struct mlx5_eswitch
*esw
)
2312 if (!esw
|| !MLX5_VPORT_MANAGER(esw
->dev
))
2315 esw_info(esw
->dev
, "cleanup\n");
2317 esw
->dev
->priv
.eswitch
= NULL
;
2318 destroy_workqueue(esw
->work_queue
);
2319 esw_offloads_cleanup_reps(esw
);
2320 mutex_destroy(&esw
->mode_lock
);
2321 mutex_destroy(&esw
->state_lock
);
2322 mutex_destroy(&esw
->offloads
.mod_hdr
.lock
);
2323 mutex_destroy(&esw
->offloads
.encap_tbl_lock
);
2328 /* Vport Administration */
2329 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch
*esw
,
2330 u16 vport
, u8 mac
[ETH_ALEN
])
2332 struct mlx5_vport
*evport
= mlx5_eswitch_get_vport(esw
, vport
);
2337 return PTR_ERR(evport
);
2338 if (is_multicast_ether_addr(mac
))
2341 mutex_lock(&esw
->state_lock
);
2343 if (evport
->info
.spoofchk
&& !is_valid_ether_addr(mac
))
2344 mlx5_core_warn(esw
->dev
,
2345 "Set invalid MAC while spoofchk is on, vport(%d)\n",
2348 err
= mlx5_modify_nic_vport_mac_address(esw
->dev
, vport
, mac
);
2350 mlx5_core_warn(esw
->dev
,
2351 "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n",
2356 node_guid_gen_from_mac(&node_guid
, mac
);
2357 err
= mlx5_modify_nic_vport_node_guid(esw
->dev
, vport
, node_guid
);
2359 mlx5_core_warn(esw
->dev
,
2360 "Failed to set vport %d node guid, err = %d. RDMA_CM will not function properly for this VF.\n",
2363 ether_addr_copy(evport
->info
.mac
, mac
);
2364 evport
->info
.node_guid
= node_guid
;
2365 if (evport
->enabled
&& esw
->mode
== MLX5_ESWITCH_LEGACY
)
2366 err
= esw_vport_ingress_config(esw
, evport
);
2369 mutex_unlock(&esw
->state_lock
);
2373 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch
*esw
,
2374 u16 vport
, int link_state
)
2376 struct mlx5_vport
*evport
= mlx5_eswitch_get_vport(esw
, vport
);
2379 if (!ESW_ALLOWED(esw
))
2382 return PTR_ERR(evport
);
2384 mutex_lock(&esw
->state_lock
);
2386 err
= mlx5_modify_vport_admin_state(esw
->dev
,
2387 MLX5_VPORT_STATE_OP_MOD_ESW_VPORT
,
2388 vport
, 1, link_state
);
2390 mlx5_core_warn(esw
->dev
,
2391 "Failed to set vport %d link state, err = %d",
2396 evport
->info
.link_state
= link_state
;
2399 mutex_unlock(&esw
->state_lock
);
2403 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch
*esw
,
2404 u16 vport
, struct ifla_vf_info
*ivi
)
2406 struct mlx5_vport
*evport
= mlx5_eswitch_get_vport(esw
, vport
);
2409 return PTR_ERR(evport
);
2411 memset(ivi
, 0, sizeof(*ivi
));
2412 ivi
->vf
= vport
- 1;
2414 mutex_lock(&esw
->state_lock
);
2415 ether_addr_copy(ivi
->mac
, evport
->info
.mac
);
2416 ivi
->linkstate
= evport
->info
.link_state
;
2417 ivi
->vlan
= evport
->info
.vlan
;
2418 ivi
->qos
= evport
->info
.qos
;
2419 ivi
->spoofchk
= evport
->info
.spoofchk
;
2420 ivi
->trusted
= evport
->info
.trusted
;
2421 ivi
->min_tx_rate
= evport
->info
.min_rate
;
2422 ivi
->max_tx_rate
= evport
->info
.max_rate
;
2423 mutex_unlock(&esw
->state_lock
);
2428 int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch
*esw
,
2429 u16 vport
, u16 vlan
, u8 qos
, u8 set_flags
)
2431 struct mlx5_vport
*evport
= mlx5_eswitch_get_vport(esw
, vport
);
2434 if (!ESW_ALLOWED(esw
))
2437 return PTR_ERR(evport
);
2438 if (vlan
> 4095 || qos
> 7)
2441 err
= modify_esw_vport_cvlan(esw
->dev
, vport
, vlan
, qos
, set_flags
);
2445 evport
->info
.vlan
= vlan
;
2446 evport
->info
.qos
= qos
;
2447 if (evport
->enabled
&& esw
->mode
== MLX5_ESWITCH_LEGACY
) {
2448 err
= esw_vport_ingress_config(esw
, evport
);
2451 err
= esw_vport_egress_config(esw
, evport
);
2457 int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch
*esw
,
2458 u16 vport
, u16 vlan
, u8 qos
)
2464 set_flags
= SET_VLAN_STRIP
| SET_VLAN_INSERT
;
2466 mutex_lock(&esw
->state_lock
);
2467 err
= __mlx5_eswitch_set_vport_vlan(esw
, vport
, vlan
, qos
, set_flags
);
2468 mutex_unlock(&esw
->state_lock
);
2473 int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch
*esw
,
2474 u16 vport
, bool spoofchk
)
2476 struct mlx5_vport
*evport
= mlx5_eswitch_get_vport(esw
, vport
);
2480 if (!ESW_ALLOWED(esw
))
2483 return PTR_ERR(evport
);
2485 mutex_lock(&esw
->state_lock
);
2486 pschk
= evport
->info
.spoofchk
;
2487 evport
->info
.spoofchk
= spoofchk
;
2488 if (pschk
&& !is_valid_ether_addr(evport
->info
.mac
))
2489 mlx5_core_warn(esw
->dev
,
2490 "Spoofchk in set while MAC is invalid, vport(%d)\n",
2492 if (evport
->enabled
&& esw
->mode
== MLX5_ESWITCH_LEGACY
)
2493 err
= esw_vport_ingress_config(esw
, evport
);
2495 evport
->info
.spoofchk
= pschk
;
2496 mutex_unlock(&esw
->state_lock
);
2501 static void esw_cleanup_vepa_rules(struct mlx5_eswitch
*esw
)
2503 if (esw
->fdb_table
.legacy
.vepa_uplink_rule
)
2504 mlx5_del_flow_rules(esw
->fdb_table
.legacy
.vepa_uplink_rule
);
2506 if (esw
->fdb_table
.legacy
.vepa_star_rule
)
2507 mlx5_del_flow_rules(esw
->fdb_table
.legacy
.vepa_star_rule
);
2509 esw
->fdb_table
.legacy
.vepa_uplink_rule
= NULL
;
2510 esw
->fdb_table
.legacy
.vepa_star_rule
= NULL
;
2513 static int _mlx5_eswitch_set_vepa_locked(struct mlx5_eswitch
*esw
,
2516 struct mlx5_flow_destination dest
= {};
2517 struct mlx5_flow_act flow_act
= {};
2518 struct mlx5_flow_handle
*flow_rule
;
2519 struct mlx5_flow_spec
*spec
;
2524 esw_cleanup_vepa_rules(esw
);
2528 if (esw
->fdb_table
.legacy
.vepa_uplink_rule
)
2531 spec
= kvzalloc(sizeof(*spec
), GFP_KERNEL
);
2535 /* Uplink rule forward uplink traffic to FDB */
2536 misc
= MLX5_ADDR_OF(fte_match_param
, spec
->match_value
, misc_parameters
);
2537 MLX5_SET(fte_match_set_misc
, misc
, source_port
, MLX5_VPORT_UPLINK
);
2539 misc
= MLX5_ADDR_OF(fte_match_param
, spec
->match_criteria
, misc_parameters
);
2540 MLX5_SET_TO_ONES(fte_match_set_misc
, misc
, source_port
);
2542 spec
->match_criteria_enable
= MLX5_MATCH_MISC_PARAMETERS
;
2543 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE
;
2544 dest
.ft
= esw
->fdb_table
.legacy
.fdb
;
2545 flow_act
.action
= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST
;
2546 flow_rule
= mlx5_add_flow_rules(esw
->fdb_table
.legacy
.vepa_fdb
, spec
,
2547 &flow_act
, &dest
, 1);
2548 if (IS_ERR(flow_rule
)) {
2549 err
= PTR_ERR(flow_rule
);
2552 esw
->fdb_table
.legacy
.vepa_uplink_rule
= flow_rule
;
2555 /* Star rule to forward all traffic to uplink vport */
2556 memset(&dest
, 0, sizeof(dest
));
2557 dest
.type
= MLX5_FLOW_DESTINATION_TYPE_VPORT
;
2558 dest
.vport
.num
= MLX5_VPORT_UPLINK
;
2559 flow_act
.action
= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST
;
2560 flow_rule
= mlx5_add_flow_rules(esw
->fdb_table
.legacy
.vepa_fdb
, NULL
,
2561 &flow_act
, &dest
, 1);
2562 if (IS_ERR(flow_rule
)) {
2563 err
= PTR_ERR(flow_rule
);
2566 esw
->fdb_table
.legacy
.vepa_star_rule
= flow_rule
;
2572 esw_cleanup_vepa_rules(esw
);
2576 int mlx5_eswitch_set_vepa(struct mlx5_eswitch
*esw
, u8 setting
)
2583 if (!ESW_ALLOWED(esw
))
2586 mutex_lock(&esw
->state_lock
);
2587 if (esw
->mode
!= MLX5_ESWITCH_LEGACY
) {
2592 err
= _mlx5_eswitch_set_vepa_locked(esw
, setting
);
2595 mutex_unlock(&esw
->state_lock
);
2599 int mlx5_eswitch_get_vepa(struct mlx5_eswitch
*esw
, u8
*setting
)
2604 if (!ESW_ALLOWED(esw
))
2607 if (esw
->mode
!= MLX5_ESWITCH_LEGACY
)
2610 *setting
= esw
->fdb_table
.legacy
.vepa_uplink_rule
? 1 : 0;
2614 int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch
*esw
,
2615 u16 vport
, bool setting
)
2617 struct mlx5_vport
*evport
= mlx5_eswitch_get_vport(esw
, vport
);
2619 if (!ESW_ALLOWED(esw
))
2622 return PTR_ERR(evport
);
2624 mutex_lock(&esw
->state_lock
);
2625 evport
->info
.trusted
= setting
;
2626 if (evport
->enabled
)
2627 esw_vport_change_handle_locked(evport
);
2628 mutex_unlock(&esw
->state_lock
);
2633 static u32
calculate_vports_min_rate_divider(struct mlx5_eswitch
*esw
)
2635 u32 fw_max_bw_share
= MLX5_CAP_QOS(esw
->dev
, max_tsar_bw_share
);
2636 struct mlx5_vport
*evport
;
2637 u32 max_guarantee
= 0;
2640 mlx5_esw_for_all_vports(esw
, i
, evport
) {
2641 if (!evport
->enabled
|| evport
->info
.min_rate
< max_guarantee
)
2643 max_guarantee
= evport
->info
.min_rate
;
2646 return max_t(u32
, max_guarantee
/ fw_max_bw_share
, 1);
2649 static int normalize_vports_min_rate(struct mlx5_eswitch
*esw
, u32 divider
)
2651 u32 fw_max_bw_share
= MLX5_CAP_QOS(esw
->dev
, max_tsar_bw_share
);
2652 struct mlx5_vport
*evport
;
2659 mlx5_esw_for_all_vports(esw
, i
, evport
) {
2660 if (!evport
->enabled
)
2662 vport_min_rate
= evport
->info
.min_rate
;
2663 vport_max_rate
= evport
->info
.max_rate
;
2664 bw_share
= MLX5_MIN_BW_SHARE
;
2667 bw_share
= MLX5_RATE_TO_BW_SHARE(vport_min_rate
,
2671 if (bw_share
== evport
->qos
.bw_share
)
2674 err
= esw_vport_qos_config(esw
, evport
, vport_max_rate
,
2677 evport
->qos
.bw_share
= bw_share
;
2685 int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch
*esw
, u16 vport
,
2686 u32 max_rate
, u32 min_rate
)
2688 struct mlx5_vport
*evport
= mlx5_eswitch_get_vport(esw
, vport
);
2689 u32 fw_max_bw_share
;
2690 u32 previous_min_rate
;
2692 bool min_rate_supported
;
2693 bool max_rate_supported
;
2696 if (!ESW_ALLOWED(esw
))
2699 return PTR_ERR(evport
);
2701 fw_max_bw_share
= MLX5_CAP_QOS(esw
->dev
, max_tsar_bw_share
);
2702 min_rate_supported
= MLX5_CAP_QOS(esw
->dev
, esw_bw_share
) &&
2703 fw_max_bw_share
>= MLX5_MIN_BW_SHARE
;
2704 max_rate_supported
= MLX5_CAP_QOS(esw
->dev
, esw_rate_limit
);
2706 if ((min_rate
&& !min_rate_supported
) || (max_rate
&& !max_rate_supported
))
2709 mutex_lock(&esw
->state_lock
);
2711 if (min_rate
== evport
->info
.min_rate
)
2714 previous_min_rate
= evport
->info
.min_rate
;
2715 evport
->info
.min_rate
= min_rate
;
2716 divider
= calculate_vports_min_rate_divider(esw
);
2717 err
= normalize_vports_min_rate(esw
, divider
);
2719 evport
->info
.min_rate
= previous_min_rate
;
2724 if (max_rate
== evport
->info
.max_rate
)
2727 err
= esw_vport_qos_config(esw
, evport
, max_rate
, evport
->qos
.bw_share
);
2729 evport
->info
.max_rate
= max_rate
;
2732 mutex_unlock(&esw
->state_lock
);
2736 static int mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev
*dev
,
2737 struct mlx5_vport
*vport
,
2738 struct mlx5_vport_drop_stats
*stats
)
2740 struct mlx5_eswitch
*esw
= dev
->priv
.eswitch
;
2741 u64 rx_discard_vport_down
, tx_discard_vport_down
;
2745 if (esw
->mode
!= MLX5_ESWITCH_LEGACY
)
2748 mutex_lock(&esw
->state_lock
);
2749 if (!vport
->enabled
)
2752 if (vport
->egress
.legacy
.drop_counter
)
2753 mlx5_fc_query(dev
, vport
->egress
.legacy
.drop_counter
,
2754 &stats
->rx_dropped
, &bytes
);
2756 if (vport
->ingress
.legacy
.drop_counter
)
2757 mlx5_fc_query(dev
, vport
->ingress
.legacy
.drop_counter
,
2758 &stats
->tx_dropped
, &bytes
);
2760 if (!MLX5_CAP_GEN(dev
, receive_discard_vport_down
) &&
2761 !MLX5_CAP_GEN(dev
, transmit_discard_vport_down
))
2764 err
= mlx5_query_vport_down_stats(dev
, vport
->vport
, 1,
2765 &rx_discard_vport_down
,
2766 &tx_discard_vport_down
);
2770 if (MLX5_CAP_GEN(dev
, receive_discard_vport_down
))
2771 stats
->rx_dropped
+= rx_discard_vport_down
;
2772 if (MLX5_CAP_GEN(dev
, transmit_discard_vport_down
))
2773 stats
->tx_dropped
+= tx_discard_vport_down
;
2776 mutex_unlock(&esw
->state_lock
);
2780 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch
*esw
,
2782 struct ifla_vf_stats
*vf_stats
)
2784 struct mlx5_vport
*vport
= mlx5_eswitch_get_vport(esw
, vport_num
);
2785 int outlen
= MLX5_ST_SZ_BYTES(query_vport_counter_out
);
2786 u32 in
[MLX5_ST_SZ_DW(query_vport_counter_in
)] = {0};
2787 struct mlx5_vport_drop_stats stats
= {0};
2792 return PTR_ERR(vport
);
2794 out
= kvzalloc(outlen
, GFP_KERNEL
);
2798 MLX5_SET(query_vport_counter_in
, in
, opcode
,
2799 MLX5_CMD_OP_QUERY_VPORT_COUNTER
);
2800 MLX5_SET(query_vport_counter_in
, in
, op_mod
, 0);
2801 MLX5_SET(query_vport_counter_in
, in
, vport_number
, vport
->vport
);
2802 MLX5_SET(query_vport_counter_in
, in
, other_vport
, 1);
2804 err
= mlx5_cmd_exec(esw
->dev
, in
, sizeof(in
), out
, outlen
);
2808 #define MLX5_GET_CTR(p, x) \
2809 MLX5_GET64(query_vport_counter_out, p, x)
2811 memset(vf_stats
, 0, sizeof(*vf_stats
));
2812 vf_stats
->rx_packets
=
2813 MLX5_GET_CTR(out
, received_eth_unicast
.packets
) +
2814 MLX5_GET_CTR(out
, received_ib_unicast
.packets
) +
2815 MLX5_GET_CTR(out
, received_eth_multicast
.packets
) +
2816 MLX5_GET_CTR(out
, received_ib_multicast
.packets
) +
2817 MLX5_GET_CTR(out
, received_eth_broadcast
.packets
);
2819 vf_stats
->rx_bytes
=
2820 MLX5_GET_CTR(out
, received_eth_unicast
.octets
) +
2821 MLX5_GET_CTR(out
, received_ib_unicast
.octets
) +
2822 MLX5_GET_CTR(out
, received_eth_multicast
.octets
) +
2823 MLX5_GET_CTR(out
, received_ib_multicast
.octets
) +
2824 MLX5_GET_CTR(out
, received_eth_broadcast
.octets
);
2826 vf_stats
->tx_packets
=
2827 MLX5_GET_CTR(out
, transmitted_eth_unicast
.packets
) +
2828 MLX5_GET_CTR(out
, transmitted_ib_unicast
.packets
) +
2829 MLX5_GET_CTR(out
, transmitted_eth_multicast
.packets
) +
2830 MLX5_GET_CTR(out
, transmitted_ib_multicast
.packets
) +
2831 MLX5_GET_CTR(out
, transmitted_eth_broadcast
.packets
);
2833 vf_stats
->tx_bytes
=
2834 MLX5_GET_CTR(out
, transmitted_eth_unicast
.octets
) +
2835 MLX5_GET_CTR(out
, transmitted_ib_unicast
.octets
) +
2836 MLX5_GET_CTR(out
, transmitted_eth_multicast
.octets
) +
2837 MLX5_GET_CTR(out
, transmitted_ib_multicast
.octets
) +
2838 MLX5_GET_CTR(out
, transmitted_eth_broadcast
.octets
);
2840 vf_stats
->multicast
=
2841 MLX5_GET_CTR(out
, received_eth_multicast
.packets
) +
2842 MLX5_GET_CTR(out
, received_ib_multicast
.packets
);
2844 vf_stats
->broadcast
=
2845 MLX5_GET_CTR(out
, received_eth_broadcast
.packets
);
2847 err
= mlx5_eswitch_query_vport_drop_stats(esw
->dev
, vport
, &stats
);
2850 vf_stats
->rx_dropped
= stats
.rx_dropped
;
2851 vf_stats
->tx_dropped
= stats
.tx_dropped
;
2858 u8
mlx5_eswitch_mode(struct mlx5_eswitch
*esw
)
2860 return ESW_ALLOWED(esw
) ? esw
->mode
: MLX5_ESWITCH_NONE
;
2862 EXPORT_SYMBOL_GPL(mlx5_eswitch_mode
);
2864 enum devlink_eswitch_encap_mode
2865 mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev
*dev
)
2867 struct mlx5_eswitch
*esw
;
2869 esw
= dev
->priv
.eswitch
;
2870 return ESW_ALLOWED(esw
) ? esw
->offloads
.encap
:
2871 DEVLINK_ESWITCH_ENCAP_MODE_NONE
;
2873 EXPORT_SYMBOL(mlx5_eswitch_get_encap_mode
);
2875 bool mlx5_esw_lag_prereq(struct mlx5_core_dev
*dev0
, struct mlx5_core_dev
*dev1
)
2877 if ((dev0
->priv
.eswitch
->mode
== MLX5_ESWITCH_NONE
&&
2878 dev1
->priv
.eswitch
->mode
== MLX5_ESWITCH_NONE
) ||
2879 (dev0
->priv
.eswitch
->mode
== MLX5_ESWITCH_OFFLOADS
&&
2880 dev1
->priv
.eswitch
->mode
== MLX5_ESWITCH_OFFLOADS
))
2886 bool mlx5_esw_multipath_prereq(struct mlx5_core_dev
*dev0
,
2887 struct mlx5_core_dev
*dev1
)
2889 return (dev0
->priv
.eswitch
->mode
== MLX5_ESWITCH_OFFLOADS
&&
2890 dev1
->priv
.eswitch
->mode
== MLX5_ESWITCH_OFFLOADS
);