Skip to content

Commit f637941

Browse files
committed
Merge branch 'mlxsw-vlan_filtering-offload'
Jiri Pirko says: ==================== mlxsw: add offload support for vlan_filtering option Elad says: This patch adds SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING port attribute. When a bridge is offloaded to hardware, the hardware can learn if the bridge is .1Q bridge (VLAN-aware) or not VLAN aware bridge. In order to toggle the mode a user can use sysfs: $ echo 1 > /sys/devices/virtual/net/br0/bridge/vlan_filtering or via iproute2: $ ip link set dev br0 type bridge vlan_filtering 1 --- v1->v2: small fix in patch #1 ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 00ce3a1 + fc1273a commit f637941

File tree

6 files changed

+82
-8
lines changed

6 files changed

+82
-8
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,11 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
13701370
err = -ENOMEM;
13711371
goto err_port_active_vlans_alloc;
13721372
}
1373+
mlxsw_sp_port->untagged_vlans = kzalloc(bytes, GFP_KERNEL);
1374+
if (!mlxsw_sp_port->untagged_vlans) {
1375+
err = -ENOMEM;
1376+
goto err_port_untagged_vlans_alloc;
1377+
}
13731378
INIT_LIST_HEAD(&mlxsw_sp_port->vports_list);
13741379

13751380
mlxsw_sp_port->pcpu_stats =
@@ -1472,6 +1477,8 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
14721477
err_dev_addr_init:
14731478
free_percpu(mlxsw_sp_port->pcpu_stats);
14741479
err_alloc_stats:
1480+
kfree(mlxsw_sp_port->untagged_vlans);
1481+
err_port_untagged_vlans_alloc:
14751482
kfree(mlxsw_sp_port->active_vlans);
14761483
err_port_active_vlans_alloc:
14771484
free_netdev(dev);
@@ -1505,6 +1512,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
15051512
mlxsw_sp_port_vports_fini(mlxsw_sp_port);
15061513
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
15071514
free_percpu(mlxsw_sp_port->pcpu_stats);
1515+
kfree(mlxsw_sp_port->untagged_vlans);
15081516
kfree(mlxsw_sp_port->active_vlans);
15091517
free_netdev(mlxsw_sp_port->dev);
15101518
}

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ struct mlxsw_sp_port {
144144
} vport;
145145
/* 802.1Q bridge VLANs */
146146
unsigned long *active_vlans;
147+
unsigned long *untagged_vlans;
147148
/* VLAN interfaces */
148149
struct list_head vports_list;
149150
};

drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,22 @@ static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port,
299299
return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
300300
}
301301

302+
static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
303+
struct switchdev_trans *trans,
304+
struct net_device *orig_dev,
305+
bool vlan_enabled)
306+
{
307+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
308+
309+
/* SWITCHDEV_TRANS_PREPARE phase */
310+
if ((!vlan_enabled) && (mlxsw_sp->master_bridge.dev == orig_dev)) {
311+
netdev_err(mlxsw_sp_port->dev, "Bridge must be vlan-aware\n");
312+
return -EINVAL;
313+
}
314+
315+
return 0;
316+
}
317+
302318
static int mlxsw_sp_port_attr_set(struct net_device *dev,
303319
const struct switchdev_attr *attr,
304320
struct switchdev_trans *trans)
@@ -323,6 +339,11 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
323339
err = mlxsw_sp_port_attr_br_ageing_set(mlxsw_sp_port, trans,
324340
attr->u.ageing_time);
325341
break;
342+
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
343+
err = mlxsw_sp_port_attr_br_vlan_set(mlxsw_sp_port, trans,
344+
attr->orig_dev,
345+
attr->u.vlan_filtering);
346+
break;
326347
default:
327348
err = -EOPNOTSUPP;
328349
break;
@@ -505,8 +526,13 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
505526
}
506527

507528
/* Changing activity bits only if HW operation succeded */
508-
for (vid = vid_begin; vid <= vid_end; vid++)
529+
for (vid = vid_begin; vid <= vid_end; vid++) {
509530
set_bit(vid, mlxsw_sp_port->active_vlans);
531+
if (flag_untagged)
532+
set_bit(vid, mlxsw_sp_port->untagged_vlans);
533+
else
534+
clear_bit(vid, mlxsw_sp_port->untagged_vlans);
535+
}
510536

511537
/* STP state change must be done after we set active VLANs */
512538
err = mlxsw_sp_port_stp_state_set(mlxsw_sp_port,
@@ -545,15 +571,15 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
545571
const struct switchdev_obj_port_vlan *vlan,
546572
struct switchdev_trans *trans)
547573
{
548-
bool untagged_flag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
549-
bool pvid_flag = vlan->flags & BRIDGE_VLAN_INFO_PVID;
574+
bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
575+
bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
550576

551577
if (switchdev_trans_ph_prepare(trans))
552578
return 0;
553579

554580
return __mlxsw_sp_port_vlans_add(mlxsw_sp_port,
555581
vlan->vid_begin, vlan->vid_end,
556-
untagged_flag, pvid_flag);
582+
flag_untagged, flag_pvid);
557583
}
558584

559585
static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic)
@@ -933,6 +959,8 @@ static int mlxsw_sp_port_vlan_dump(struct mlxsw_sp_port *mlxsw_sp_port,
933959
vlan->flags = 0;
934960
if (vid == mlxsw_sp_port->pvid)
935961
vlan->flags |= BRIDGE_VLAN_INFO_PVID;
962+
if (test_bit(vid, mlxsw_sp_port->untagged_vlans))
963+
vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
936964
vlan->vid_begin = vid;
937965
vlan->vid_end = vid;
938966
err = cb(&vlan->obj);
@@ -1201,7 +1229,8 @@ int mlxsw_sp_port_vlan_init(struct mlxsw_sp_port *mlxsw_sp_port)
12011229
* with VID 1.
12021230
*/
12031231
mlxsw_sp_port->pvid = 1;
1204-
err = __mlxsw_sp_port_vlans_del(mlxsw_sp_port, 0, VLAN_N_VID, true);
1232+
err = __mlxsw_sp_port_vlans_del(mlxsw_sp_port, 0, VLAN_N_VID - 1,
1233+
true);
12051234
if (err) {
12061235
netdev_err(dev, "Unable to init VLANs\n");
12071236
return err;

include/net/switchdev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ enum switchdev_attr_id {
4747
SWITCHDEV_ATTR_ID_PORT_STP_STATE,
4848
SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS,
4949
SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
50+
SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
5051
};
5152

5253
struct switchdev_attr {
@@ -58,6 +59,7 @@ struct switchdev_attr {
5859
u8 stp_state; /* PORT_STP_STATE */
5960
unsigned long brport_flags; /* PORT_BRIDGE_FLAGS */
6061
u32 ageing_time; /* BRIDGE_AGEING_TIME */
62+
bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */
6163
} u;
6264
};
6365

net/bridge/br_if.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,8 +511,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
511511
if (br_fdb_insert(br, p, dev->dev_addr, 0))
512512
netdev_err(dev, "failed insert local address bridge forwarding table\n");
513513

514-
if (nbp_vlan_init(p))
514+
err = nbp_vlan_init(p);
515+
if (err) {
515516
netdev_err(dev, "failed to initialize vlan filtering on this port\n");
517+
goto err6;
518+
}
516519

517520
spin_lock_bh(&br->lock);
518521
changed_addr = br_stp_recalculate_bridge_id(br);
@@ -533,6 +536,12 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
533536

534537
return 0;
535538

539+
err6:
540+
list_del_rcu(&p->list);
541+
br_fdb_delete_by_port(br, p, 0, 1);
542+
nbp_update_port_count(br);
543+
netdev_upper_dev_unlink(dev, br->dev);
544+
536545
err5:
537546
dev->priv_flags &= ~IFF_BRIDGE_PORT;
538547
netdev_rx_handler_unregister(dev);

net/bridge/br_vlan.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,9 +626,21 @@ void br_recalculate_fwd_mask(struct net_bridge *br)
626626

627627
int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
628628
{
629+
struct switchdev_attr attr = {
630+
.orig_dev = br->dev,
631+
.id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
632+
.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
633+
.u.vlan_filtering = val,
634+
};
635+
int err;
636+
629637
if (br->vlan_enabled == val)
630638
return 0;
631639

640+
err = switchdev_port_attr_set(br->dev, &attr);
641+
if (err && err != -EOPNOTSUPP)
642+
return err;
643+
632644
br->vlan_enabled = val;
633645
br_manage_promisc(br);
634646
recalculate_group_addr(br);
@@ -639,13 +651,15 @@ int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
639651

640652
int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
641653
{
654+
int err;
655+
642656
if (!rtnl_trylock())
643657
return restart_syscall();
644658

645-
__br_vlan_filter_toggle(br, val);
659+
err = __br_vlan_filter_toggle(br, val);
646660
rtnl_unlock();
647661

648-
return 0;
662+
return err;
649663
}
650664

651665
int __br_vlan_set_proto(struct net_bridge *br, __be16 proto)
@@ -893,13 +907,23 @@ int br_vlan_init(struct net_bridge *br)
893907

894908
int nbp_vlan_init(struct net_bridge_port *p)
895909
{
910+
struct switchdev_attr attr = {
911+
.orig_dev = p->br->dev,
912+
.id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
913+
.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
914+
.u.vlan_filtering = p->br->vlan_enabled,
915+
};
896916
struct net_bridge_vlan_group *vg;
897917
int ret = -ENOMEM;
898918

899919
vg = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL);
900920
if (!vg)
901921
goto out;
902922

923+
ret = switchdev_port_attr_set(p->dev, &attr);
924+
if (ret && ret != -EOPNOTSUPP)
925+
goto err_vlan_enabled;
926+
903927
ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
904928
if (ret)
905929
goto err_rhtbl;
@@ -919,6 +943,7 @@ int nbp_vlan_init(struct net_bridge_port *p)
919943
RCU_INIT_POINTER(p->vlgrp, NULL);
920944
synchronize_rcu();
921945
rhashtable_destroy(&vg->vlan_hash);
946+
err_vlan_enabled:
922947
err_rhtbl:
923948
kfree(vg);
924949

0 commit comments

Comments
 (0)