1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021 Mellanox Technologies. */
4 #include <linux/netdevice.h>
5 #include <linux/if_bridge.h>
6 #include <net/netevent.h>
7 #include <net/switchdev.h>
9 #include "esw/bridge.h"
12 #define MLX5_ESW_BRIDGE_UPDATE_INTERVAL 1000
14 struct mlx5_bridge_switchdev_fdb_work
{
15 struct work_struct work
;
16 struct switchdev_notifier_fdb_info fdb_info
;
17 struct net_device
*dev
;
18 struct mlx5_esw_bridge_offloads
*br_offloads
;
22 static bool mlx5_esw_bridge_dev_same_esw(struct net_device
*dev
, struct mlx5_eswitch
*esw
)
24 struct mlx5e_priv
*priv
= netdev_priv(dev
);
26 return esw
== priv
->mdev
->priv
.eswitch
;
29 static bool mlx5_esw_bridge_dev_same_hw(struct net_device
*dev
, struct mlx5_eswitch
*esw
)
31 struct mlx5e_priv
*priv
= netdev_priv(dev
);
32 struct mlx5_core_dev
*mdev
, *esw_mdev
;
33 u64 system_guid
, esw_system_guid
;
38 system_guid
= mlx5_query_nic_system_image_guid(mdev
);
39 esw_system_guid
= mlx5_query_nic_system_image_guid(esw_mdev
);
41 return system_guid
== esw_system_guid
;
44 static struct net_device
*
45 mlx5_esw_bridge_lag_rep_get(struct net_device
*dev
, struct mlx5_eswitch
*esw
)
47 struct net_device
*lower
;
48 struct list_head
*iter
;
50 netdev_for_each_lower_dev(dev
, lower
, iter
) {
51 struct mlx5_core_dev
*mdev
;
52 struct mlx5e_priv
*priv
;
54 if (!mlx5e_eswitch_rep(lower
))
57 priv
= netdev_priv(lower
);
59 if (mlx5_lag_is_shared_fdb(mdev
) && mlx5_esw_bridge_dev_same_esw(lower
, esw
))
66 static struct net_device
*
67 mlx5_esw_bridge_rep_vport_num_vhca_id_get(struct net_device
*dev
, struct mlx5_eswitch
*esw
,
68 u16
*vport_num
, u16
*esw_owner_vhca_id
)
70 struct mlx5e_rep_priv
*rpriv
;
71 struct mlx5e_priv
*priv
;
73 if (netif_is_lag_master(dev
))
74 dev
= mlx5_esw_bridge_lag_rep_get(dev
, esw
);
76 if (!dev
|| !mlx5e_eswitch_rep(dev
) || !mlx5_esw_bridge_dev_same_hw(dev
, esw
))
79 priv
= netdev_priv(dev
);
81 if (!priv
->mdev
->priv
.eswitch
->br_offloads
)
85 *vport_num
= rpriv
->rep
->vport
;
86 *esw_owner_vhca_id
= MLX5_CAP_GEN(priv
->mdev
, vhca_id
);
90 static struct net_device
*
91 mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(struct net_device
*dev
, struct mlx5_eswitch
*esw
,
92 u16
*vport_num
, u16
*esw_owner_vhca_id
)
94 struct net_device
*lower_dev
;
95 struct list_head
*iter
;
97 if (netif_is_lag_master(dev
) || mlx5e_eswitch_rep(dev
))
98 return mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev
, esw
, vport_num
,
101 netdev_for_each_lower_dev(dev
, lower_dev
, iter
) {
102 struct net_device
*rep
;
104 if (netif_is_bridge_master(lower_dev
))
107 rep
= mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(lower_dev
, esw
, vport_num
,
116 static bool mlx5_esw_bridge_is_local(struct net_device
*dev
, struct net_device
*rep
,
117 struct mlx5_eswitch
*esw
)
119 struct mlx5_core_dev
*mdev
;
120 struct mlx5e_priv
*priv
;
122 if (!mlx5_esw_bridge_dev_same_esw(rep
, esw
))
125 priv
= netdev_priv(rep
);
127 if (netif_is_lag_master(dev
))
128 return mlx5_lag_is_shared_fdb(mdev
) && mlx5_lag_is_master(mdev
);
132 static int mlx5_esw_bridge_port_changeupper(struct notifier_block
*nb
, void *ptr
)
134 struct mlx5_esw_bridge_offloads
*br_offloads
= container_of(nb
,
135 struct mlx5_esw_bridge_offloads
,
137 struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
138 struct netdev_notifier_changeupper_info
*info
= ptr
;
139 struct net_device
*upper
= info
->upper_dev
, *rep
;
140 struct mlx5_eswitch
*esw
= br_offloads
->esw
;
141 u16 vport_num
, esw_owner_vhca_id
;
142 struct netlink_ext_ack
*extack
;
145 if (!netif_is_bridge_master(upper
))
148 rep
= mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev
, esw
, &vport_num
, &esw_owner_vhca_id
);
152 extack
= netdev_notifier_info_to_extack(&info
->info
);
154 if (mlx5_esw_bridge_is_local(dev
, rep
, esw
))
155 err
= info
->linking
?
156 mlx5_esw_bridge_vport_link(upper
, vport_num
, esw_owner_vhca_id
,
157 br_offloads
, extack
) :
158 mlx5_esw_bridge_vport_unlink(upper
, vport_num
, esw_owner_vhca_id
,
159 br_offloads
, extack
);
160 else if (mlx5_esw_bridge_dev_same_hw(rep
, esw
))
161 err
= info
->linking
?
162 mlx5_esw_bridge_vport_peer_link(upper
, vport_num
, esw_owner_vhca_id
,
163 br_offloads
, extack
) :
164 mlx5_esw_bridge_vport_peer_unlink(upper
, vport_num
, esw_owner_vhca_id
,
165 br_offloads
, extack
);
171 mlx5_esw_bridge_changeupper_validate_netdev(void *ptr
)
173 struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
174 struct netdev_notifier_changeupper_info
*info
= ptr
;
175 struct net_device
*upper
= info
->upper_dev
;
176 struct net_device
*lower
;
177 struct list_head
*iter
;
179 if (!netif_is_bridge_master(upper
) || !netif_is_lag_master(dev
))
182 netdev_for_each_lower_dev(dev
, lower
, iter
) {
183 struct mlx5_core_dev
*mdev
;
184 struct mlx5e_priv
*priv
;
186 if (!mlx5e_eswitch_rep(lower
))
189 priv
= netdev_priv(lower
);
191 if (!mlx5_lag_is_active(mdev
))
193 if (!mlx5_lag_is_shared_fdb(mdev
))
200 static int mlx5_esw_bridge_switchdev_port_event(struct notifier_block
*nb
,
201 unsigned long event
, void *ptr
)
206 case NETDEV_PRECHANGEUPPER
:
207 err
= mlx5_esw_bridge_changeupper_validate_netdev(ptr
);
210 case NETDEV_CHANGEUPPER
:
211 err
= mlx5_esw_bridge_port_changeupper(nb
, ptr
);
215 return notifier_from_errno(err
);
219 mlx5_esw_bridge_port_obj_add(struct net_device
*dev
,
220 struct switchdev_notifier_port_obj_info
*port_obj_info
,
221 struct mlx5_esw_bridge_offloads
*br_offloads
)
223 struct netlink_ext_ack
*extack
= switchdev_notifier_info_to_extack(&port_obj_info
->info
);
224 const struct switchdev_obj
*obj
= port_obj_info
->obj
;
225 const struct switchdev_obj_port_vlan
*vlan
;
226 const struct switchdev_obj_port_mdb
*mdb
;
227 u16 vport_num
, esw_owner_vhca_id
;
230 if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev
, br_offloads
->esw
, &vport_num
,
234 port_obj_info
->handled
= true;
237 case SWITCHDEV_OBJ_ID_PORT_VLAN
:
238 vlan
= SWITCHDEV_OBJ_PORT_VLAN(obj
);
239 err
= mlx5_esw_bridge_port_vlan_add(vport_num
, esw_owner_vhca_id
, vlan
->vid
,
240 vlan
->flags
, br_offloads
, extack
);
242 case SWITCHDEV_OBJ_ID_PORT_MDB
:
243 mdb
= SWITCHDEV_OBJ_PORT_MDB(obj
);
244 err
= mlx5_esw_bridge_port_mdb_add(dev
, vport_num
, esw_owner_vhca_id
, mdb
->addr
,
245 mdb
->vid
, br_offloads
, extack
);
254 mlx5_esw_bridge_port_obj_del(struct net_device
*dev
,
255 struct switchdev_notifier_port_obj_info
*port_obj_info
,
256 struct mlx5_esw_bridge_offloads
*br_offloads
)
258 const struct switchdev_obj
*obj
= port_obj_info
->obj
;
259 const struct switchdev_obj_port_vlan
*vlan
;
260 const struct switchdev_obj_port_mdb
*mdb
;
261 u16 vport_num
, esw_owner_vhca_id
;
263 if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev
, br_offloads
->esw
, &vport_num
,
267 port_obj_info
->handled
= true;
270 case SWITCHDEV_OBJ_ID_PORT_VLAN
:
271 vlan
= SWITCHDEV_OBJ_PORT_VLAN(obj
);
272 mlx5_esw_bridge_port_vlan_del(vport_num
, esw_owner_vhca_id
, vlan
->vid
, br_offloads
);
274 case SWITCHDEV_OBJ_ID_PORT_MDB
:
275 mdb
= SWITCHDEV_OBJ_PORT_MDB(obj
);
276 mlx5_esw_bridge_port_mdb_del(dev
, vport_num
, esw_owner_vhca_id
, mdb
->addr
, mdb
->vid
,
286 mlx5_esw_bridge_port_obj_attr_set(struct net_device
*dev
,
287 struct switchdev_notifier_port_attr_info
*port_attr_info
,
288 struct mlx5_esw_bridge_offloads
*br_offloads
)
290 struct netlink_ext_ack
*extack
= switchdev_notifier_info_to_extack(&port_attr_info
->info
);
291 const struct switchdev_attr
*attr
= port_attr_info
->attr
;
292 u16 vport_num
, esw_owner_vhca_id
;
295 if (!mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(dev
, br_offloads
->esw
, &vport_num
,
299 port_attr_info
->handled
= true;
302 case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS
:
303 if (attr
->u
.brport_flags
.mask
& ~(BR_LEARNING
| BR_FLOOD
| BR_MCAST_FLOOD
)) {
304 NL_SET_ERR_MSG_MOD(extack
, "Flag is not supported");
308 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS
:
310 case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME
:
311 err
= mlx5_esw_bridge_ageing_time_set(vport_num
, esw_owner_vhca_id
,
312 attr
->u
.ageing_time
, br_offloads
);
314 case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING
:
315 err
= mlx5_esw_bridge_vlan_filtering_set(vport_num
, esw_owner_vhca_id
,
316 attr
->u
.vlan_filtering
, br_offloads
);
318 case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL
:
319 err
= mlx5_esw_bridge_vlan_proto_set(vport_num
,
321 attr
->u
.vlan_protocol
,
324 case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED
:
325 err
= mlx5_esw_bridge_mcast_set(vport_num
, esw_owner_vhca_id
,
326 !attr
->u
.mc_disabled
, br_offloads
);
335 static int mlx5_esw_bridge_event_blocking(struct notifier_block
*nb
,
336 unsigned long event
, void *ptr
)
338 struct mlx5_esw_bridge_offloads
*br_offloads
= container_of(nb
,
339 struct mlx5_esw_bridge_offloads
,
341 struct net_device
*dev
= switchdev_notifier_info_to_dev(ptr
);
345 case SWITCHDEV_PORT_OBJ_ADD
:
346 err
= mlx5_esw_bridge_port_obj_add(dev
, ptr
, br_offloads
);
348 case SWITCHDEV_PORT_OBJ_DEL
:
349 err
= mlx5_esw_bridge_port_obj_del(dev
, ptr
, br_offloads
);
351 case SWITCHDEV_PORT_ATTR_SET
:
352 err
= mlx5_esw_bridge_port_obj_attr_set(dev
, ptr
, br_offloads
);
358 return notifier_from_errno(err
);
362 mlx5_esw_bridge_cleanup_switchdev_fdb_work(struct mlx5_bridge_switchdev_fdb_work
*fdb_work
)
364 dev_put(fdb_work
->dev
);
365 kfree(fdb_work
->fdb_info
.addr
);
369 static void mlx5_esw_bridge_switchdev_fdb_event_work(struct work_struct
*work
)
371 struct mlx5_bridge_switchdev_fdb_work
*fdb_work
=
372 container_of(work
, struct mlx5_bridge_switchdev_fdb_work
, work
);
373 struct switchdev_notifier_fdb_info
*fdb_info
=
375 struct mlx5_esw_bridge_offloads
*br_offloads
=
376 fdb_work
->br_offloads
;
377 struct net_device
*dev
= fdb_work
->dev
;
378 u16 vport_num
, esw_owner_vhca_id
;
382 if (!mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev
, br_offloads
->esw
, &vport_num
,
387 mlx5_esw_bridge_fdb_create(dev
, vport_num
, esw_owner_vhca_id
, br_offloads
,
390 mlx5_esw_bridge_fdb_remove(dev
, vport_num
, esw_owner_vhca_id
, br_offloads
,
395 mlx5_esw_bridge_cleanup_switchdev_fdb_work(fdb_work
);
398 static struct mlx5_bridge_switchdev_fdb_work
*
399 mlx5_esw_bridge_init_switchdev_fdb_work(struct net_device
*dev
, bool add
,
400 struct switchdev_notifier_fdb_info
*fdb_info
,
401 struct mlx5_esw_bridge_offloads
*br_offloads
)
403 struct mlx5_bridge_switchdev_fdb_work
*work
;
406 work
= kzalloc(sizeof(*work
), GFP_ATOMIC
);
408 return ERR_PTR(-ENOMEM
);
410 INIT_WORK(&work
->work
, mlx5_esw_bridge_switchdev_fdb_event_work
);
411 memcpy(&work
->fdb_info
, fdb_info
, sizeof(work
->fdb_info
));
413 addr
= kzalloc(ETH_ALEN
, GFP_ATOMIC
);
416 return ERR_PTR(-ENOMEM
);
418 ether_addr_copy(addr
, fdb_info
->addr
);
419 work
->fdb_info
.addr
= addr
;
423 work
->br_offloads
= br_offloads
;
428 static int mlx5_esw_bridge_switchdev_event(struct notifier_block
*nb
,
429 unsigned long event
, void *ptr
)
431 struct mlx5_esw_bridge_offloads
*br_offloads
= container_of(nb
,
432 struct mlx5_esw_bridge_offloads
,
434 struct net_device
*dev
= switchdev_notifier_info_to_dev(ptr
);
435 struct switchdev_notifier_fdb_info
*fdb_info
;
436 struct mlx5_bridge_switchdev_fdb_work
*work
;
437 struct mlx5_eswitch
*esw
= br_offloads
->esw
;
438 struct switchdev_notifier_info
*info
= ptr
;
439 u16 vport_num
, esw_owner_vhca_id
;
440 struct net_device
*upper
, *rep
;
442 if (event
== SWITCHDEV_PORT_ATTR_SET
) {
443 int err
= mlx5_esw_bridge_port_obj_attr_set(dev
, ptr
, br_offloads
);
445 return notifier_from_errno(err
);
448 upper
= netdev_master_upper_dev_get_rcu(dev
);
451 if (!netif_is_bridge_master(upper
))
454 rep
= mlx5_esw_bridge_rep_vport_num_vhca_id_get(dev
, esw
, &vport_num
, &esw_owner_vhca_id
);
459 case SWITCHDEV_FDB_ADD_TO_BRIDGE
:
460 fdb_info
= container_of(info
,
461 struct switchdev_notifier_fdb_info
,
463 mlx5_esw_bridge_fdb_update_used(dev
, vport_num
, esw_owner_vhca_id
, br_offloads
,
466 case SWITCHDEV_FDB_DEL_TO_BRIDGE
:
467 /* only handle the event on peers */
468 if (mlx5_esw_bridge_is_local(dev
, rep
, esw
))
471 fdb_info
= container_of(info
,
472 struct switchdev_notifier_fdb_info
,
474 /* Mark for deletion to prevent the update wq task from
475 * spuriously refreshing the entry which would mark it again as
476 * offloaded in SW bridge. After this fallthrough to regular
479 mlx5_esw_bridge_fdb_mark_deleted(dev
, vport_num
, esw_owner_vhca_id
, br_offloads
,
482 case SWITCHDEV_FDB_ADD_TO_DEVICE
:
483 case SWITCHDEV_FDB_DEL_TO_DEVICE
:
484 fdb_info
= container_of(info
,
485 struct switchdev_notifier_fdb_info
,
488 work
= mlx5_esw_bridge_init_switchdev_fdb_work(dev
,
489 event
== SWITCHDEV_FDB_ADD_TO_DEVICE
,
493 WARN_ONCE(1, "Failed to init switchdev work, err=%ld",
495 return notifier_from_errno(PTR_ERR(work
));
498 queue_work(br_offloads
->wq
, &work
->work
);
506 static void mlx5_esw_bridge_update_work(struct work_struct
*work
)
508 struct mlx5_esw_bridge_offloads
*br_offloads
= container_of(work
,
509 struct mlx5_esw_bridge_offloads
,
513 mlx5_esw_bridge_update(br_offloads
);
516 queue_delayed_work(br_offloads
->wq
, &br_offloads
->update_work
,
517 msecs_to_jiffies(MLX5_ESW_BRIDGE_UPDATE_INTERVAL
));
520 void mlx5e_rep_bridge_init(struct mlx5e_priv
*priv
)
522 struct mlx5_esw_bridge_offloads
*br_offloads
;
523 struct mlx5_core_dev
*mdev
= priv
->mdev
;
524 struct mlx5_eswitch
*esw
=
529 br_offloads
= mlx5_esw_bridge_init(esw
);
531 if (IS_ERR(br_offloads
)) {
532 esw_warn(mdev
, "Failed to init esw bridge (err=%ld)\n", PTR_ERR(br_offloads
));
536 br_offloads
->wq
= alloc_ordered_workqueue("mlx5_bridge_wq", 0);
537 if (!br_offloads
->wq
) {
538 esw_warn(mdev
, "Failed to allocate bridge offloads workqueue\n");
542 br_offloads
->nb
.notifier_call
= mlx5_esw_bridge_switchdev_event
;
543 err
= register_switchdev_notifier(&br_offloads
->nb
);
545 esw_warn(mdev
, "Failed to register switchdev notifier (err=%d)\n", err
);
546 goto err_register_swdev
;
549 br_offloads
->nb_blk
.notifier_call
= mlx5_esw_bridge_event_blocking
;
550 err
= register_switchdev_blocking_notifier(&br_offloads
->nb_blk
);
552 esw_warn(mdev
, "Failed to register blocking switchdev notifier (err=%d)\n", err
);
553 goto err_register_swdev_blk
;
556 br_offloads
->netdev_nb
.notifier_call
= mlx5_esw_bridge_switchdev_port_event
;
557 err
= register_netdevice_notifier_net(&init_net
, &br_offloads
->netdev_nb
);
559 esw_warn(mdev
, "Failed to register bridge offloads netdevice notifier (err=%d)\n",
561 goto err_register_netdev
;
563 INIT_DELAYED_WORK(&br_offloads
->update_work
, mlx5_esw_bridge_update_work
);
564 queue_delayed_work(br_offloads
->wq
, &br_offloads
->update_work
,
565 msecs_to_jiffies(MLX5_ESW_BRIDGE_UPDATE_INTERVAL
));
569 unregister_switchdev_blocking_notifier(&br_offloads
->nb_blk
);
570 err_register_swdev_blk
:
571 unregister_switchdev_notifier(&br_offloads
->nb
);
573 destroy_workqueue(br_offloads
->wq
);
576 mlx5_esw_bridge_cleanup(esw
);
580 void mlx5e_rep_bridge_cleanup(struct mlx5e_priv
*priv
)
582 struct mlx5_esw_bridge_offloads
*br_offloads
;
583 struct mlx5_core_dev
*mdev
= priv
->mdev
;
584 struct mlx5_eswitch
*esw
=
587 br_offloads
= esw
->br_offloads
;
591 cancel_delayed_work_sync(&br_offloads
->update_work
);
592 unregister_netdevice_notifier_net(&init_net
, &br_offloads
->netdev_nb
);
593 unregister_switchdev_blocking_notifier(&br_offloads
->nb_blk
);
594 unregister_switchdev_notifier(&br_offloads
->nb
);
595 destroy_workqueue(br_offloads
->wq
);
597 mlx5_esw_bridge_cleanup(esw
);