Skip to content

Commit 7d4f8d8

Browse files
scottfeldmandavem330
authored andcommitted
switchdev; add VLAN support for port's bridge_getlink
One more missing piece of the puzzle. Add vlan dump support to switchdev port's bridge_getlink. iproute2 "bridge vlan show" cmd already knows how to show the vlans installed on the bridge and the device , but (until now) no one implemented the port vlan part of the netlink PF_BRIDGE:RTM_GETLINK msg. Before this patch, "bridge vlan show": $ bridge -c vlan show port vlan ids sw1p1 30-34 << bridge side vlans 57 sw1p1 << device side vlans (missing) sw1p2 57 sw1p2 sw1p3 sw1p4 br0 None (When the port is bridged, the output repeats the vlan list for the vlans on the bridge side of the port and the vlans on the device side of the port. The listing above show no vlans for the device side even though they are installed). After this patch: $ bridge -c vlan show port vlan ids sw1p1 30-34 << bridge side vlan 57 sw1p1 30-34 << device side vlans 57 3840 PVID sw1p2 57 sw1p2 57 3840 PVID sw1p3 3842 PVID sw1p4 3843 PVID br0 None I re-used ndo_dflt_bridge_getlink to add vlan fill call-back func. switchdev support adds an obj dump for VLAN objects, using the same call-back scheme as FDB dump. Support included for both compressed and un-compressed vlan dumps. Signed-off-by: Scott Feldman <sfeldma@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 3e3a78b commit 7d4f8d8

File tree

7 files changed

+172
-9
lines changed

7 files changed

+172
-9
lines changed

drivers/net/ethernet/emulex/benet/be_main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5096,7 +5096,7 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
50965096
return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
50975097
hsw_mode == PORT_FWD_TYPE_VEPA ?
50985098
BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB,
5099-
0, 0, nlflags);
5099+
0, 0, nlflags, filter_mask, NULL);
51005100
}
51015101

51025102
#ifdef CONFIG_BE2NET_VXLAN

drivers/net/ethernet/intel/i40e/i40e_main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8069,7 +8069,7 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
80698069
#ifdef HAVE_BRIDGE_FILTER
80708070
static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
80718071
struct net_device *dev,
8072-
u32 __always_unused filter_mask, int nlflags)
8072+
u32 filter_mask, int nlflags)
80738073
#else
80748074
static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
80758075
struct net_device *dev, int nlflags)
@@ -8095,7 +8095,7 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
80958095
return 0;
80968096

80978097
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode,
8098-
nlflags);
8098+
nlflags, 0, 0, filter_mask, NULL);
80998099
}
81008100
#endif /* HAVE_BRIDGE_ATTRIBS */
81018101

drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8095,7 +8095,8 @@ static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
80958095
return 0;
80968096

80978097
return ndo_dflt_bridge_getlink(skb, pid, seq, dev,
8098-
adapter->bridge_mode, 0, 0, nlflags);
8098+
adapter->bridge_mode, 0, 0, nlflags,
8099+
filter_mask, NULL);
80998100
}
81008101

81018102
static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)

drivers/net/ethernet/rocker/rocker.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4456,6 +4456,28 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port,
44564456
return err;
44574457
}
44584458

4459+
static int rocker_port_vlan_dump(const struct rocker_port *rocker_port,
4460+
struct switchdev_obj *obj)
4461+
{
4462+
struct switchdev_obj_vlan *vlan = &obj->u.vlan;
4463+
u16 vid;
4464+
int err = 0;
4465+
4466+
for (vid = 1; vid < VLAN_N_VID; vid++) {
4467+
if (!test_bit(vid, rocker_port->vlan_bitmap))
4468+
continue;
4469+
vlan->flags = 0;
4470+
if (rocker_vlan_id_is_internal(htons(vid)))
4471+
vlan->flags |= BRIDGE_VLAN_INFO_PVID;
4472+
vlan->vid_begin = vlan->vid_end = vid;
4473+
err = obj->cb(rocker_port->dev, obj);
4474+
if (err)
4475+
break;
4476+
}
4477+
4478+
return err;
4479+
}
4480+
44594481
static int rocker_port_obj_dump(struct net_device *dev,
44604482
struct switchdev_obj *obj)
44614483
{
@@ -4466,6 +4488,9 @@ static int rocker_port_obj_dump(struct net_device *dev,
44664488
case SWITCHDEV_OBJ_PORT_FDB:
44674489
err = rocker_port_fdb_dump(rocker_port, obj);
44684490
break;
4491+
case SWITCHDEV_OBJ_PORT_VLAN:
4492+
err = rocker_port_vlan_dump(rocker_port, obj);
4493+
break;
44694494
default:
44704495
err = -EOPNOTSUPP;
44714496
break;

include/linux/rtnetlink.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,9 @@ extern int ndo_dflt_fdb_del(struct ndmsg *ndm,
114114

115115
extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
116116
struct net_device *dev, u16 mode,
117-
u32 flags, u32 mask, int nlflags);
117+
u32 flags, u32 mask, int nlflags,
118+
u32 filter_mask,
119+
int (*vlan_fill)(struct sk_buff *skb,
120+
struct net_device *dev,
121+
u32 filter_mask));
118122
#endif /* __LINUX_RTNETLINK_H */

net/core/rtnetlink.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2908,14 +2908,19 @@ static int brport_nla_put_flag(struct sk_buff *skb, u32 flags, u32 mask,
29082908

29092909
int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
29102910
struct net_device *dev, u16 mode,
2911-
u32 flags, u32 mask, int nlflags)
2911+
u32 flags, u32 mask, int nlflags,
2912+
u32 filter_mask,
2913+
int (*vlan_fill)(struct sk_buff *skb,
2914+
struct net_device *dev,
2915+
u32 filter_mask))
29122916
{
29132917
struct nlmsghdr *nlh;
29142918
struct ifinfomsg *ifm;
29152919
struct nlattr *br_afspec;
29162920
struct nlattr *protinfo;
29172921
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
29182922
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
2923+
int err = 0;
29192924

29202925
nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), nlflags);
29212926
if (nlh == NULL)
@@ -2956,6 +2961,13 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
29562961
goto nla_put_failure;
29572962
}
29582963
}
2964+
if (vlan_fill) {
2965+
err = vlan_fill(skb, dev, filter_mask);
2966+
if (err) {
2967+
nla_nest_cancel(skb, br_afspec);
2968+
goto nla_put_failure;
2969+
}
2970+
}
29592971
nla_nest_end(skb, br_afspec);
29602972

29612973
protinfo = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
@@ -2989,9 +3001,9 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
29893001
return 0;
29903002
nla_put_failure:
29913003
nlmsg_cancel(skb, nlh);
2992-
return -EMSGSIZE;
3004+
return err ? err : -EMSGSIZE;
29933005
}
2994-
EXPORT_SYMBOL(ndo_dflt_bridge_getlink);
3006+
EXPORT_SYMBOL_GPL(ndo_dflt_bridge_getlink);
29953007

29963008
static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
29973009
{

net/switchdev/switchdev.c

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,126 @@ int call_switchdev_notifiers(unsigned long val, struct net_device *dev,
391391
}
392392
EXPORT_SYMBOL_GPL(call_switchdev_notifiers);
393393

394+
struct switchdev_vlan_dump {
395+
struct switchdev_obj obj;
396+
struct sk_buff *skb;
397+
u32 filter_mask;
398+
u16 flags;
399+
u16 begin;
400+
u16 end;
401+
};
402+
403+
static int switchdev_port_vlan_dump_put(struct net_device *dev,
404+
struct switchdev_vlan_dump *dump)
405+
{
406+
struct bridge_vlan_info vinfo;
407+
408+
vinfo.flags = dump->flags;
409+
410+
if (dump->begin == 0 && dump->end == 0) {
411+
return 0;
412+
} else if (dump->begin == dump->end) {
413+
vinfo.vid = dump->begin;
414+
if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO,
415+
sizeof(vinfo), &vinfo))
416+
return -EMSGSIZE;
417+
} else {
418+
vinfo.vid = dump->begin;
419+
vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
420+
if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO,
421+
sizeof(vinfo), &vinfo))
422+
return -EMSGSIZE;
423+
vinfo.vid = dump->end;
424+
vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
425+
vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
426+
if (nla_put(dump->skb, IFLA_BRIDGE_VLAN_INFO,
427+
sizeof(vinfo), &vinfo))
428+
return -EMSGSIZE;
429+
}
430+
431+
return 0;
432+
}
433+
434+
static int switchdev_port_vlan_dump_cb(struct net_device *dev,
435+
struct switchdev_obj *obj)
436+
{
437+
struct switchdev_vlan_dump *dump =
438+
container_of(obj, struct switchdev_vlan_dump, obj);
439+
struct switchdev_obj_vlan *vlan = &dump->obj.u.vlan;
440+
int err = 0;
441+
442+
if (vlan->vid_begin > vlan->vid_end)
443+
return -EINVAL;
444+
445+
if (dump->filter_mask & RTEXT_FILTER_BRVLAN) {
446+
dump->flags = vlan->flags;
447+
for (dump->begin = dump->end = vlan->vid_begin;
448+
dump->begin <= vlan->vid_end;
449+
dump->begin++, dump->end++) {
450+
err = switchdev_port_vlan_dump_put(dev, dump);
451+
if (err)
452+
return err;
453+
}
454+
} else if (dump->filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) {
455+
if (dump->begin > vlan->vid_begin &&
456+
dump->begin >= vlan->vid_end) {
457+
if ((dump->begin - 1) == vlan->vid_end &&
458+
dump->flags == vlan->flags) {
459+
/* prepend */
460+
dump->begin = vlan->vid_begin;
461+
} else {
462+
err = switchdev_port_vlan_dump_put(dev, dump);
463+
dump->flags = vlan->flags;
464+
dump->begin = vlan->vid_begin;
465+
dump->end = vlan->vid_end;
466+
}
467+
} else if (dump->end <= vlan->vid_begin &&
468+
dump->end < vlan->vid_end) {
469+
if ((dump->end + 1) == vlan->vid_begin &&
470+
dump->flags == vlan->flags) {
471+
/* append */
472+
dump->end = vlan->vid_end;
473+
} else {
474+
err = switchdev_port_vlan_dump_put(dev, dump);
475+
dump->flags = vlan->flags;
476+
dump->begin = vlan->vid_begin;
477+
dump->end = vlan->vid_end;
478+
}
479+
} else {
480+
err = -EINVAL;
481+
}
482+
}
483+
484+
return err;
485+
}
486+
487+
static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev,
488+
u32 filter_mask)
489+
{
490+
struct switchdev_vlan_dump dump = {
491+
.obj = {
492+
.id = SWITCHDEV_OBJ_PORT_VLAN,
493+
.cb = switchdev_port_vlan_dump_cb,
494+
},
495+
.skb = skb,
496+
.filter_mask = filter_mask,
497+
};
498+
int err = 0;
499+
500+
if ((filter_mask & RTEXT_FILTER_BRVLAN) ||
501+
(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) {
502+
err = switchdev_port_obj_dump(dev, &dump.obj);
503+
if (err)
504+
goto err_out;
505+
if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
506+
/* last one */
507+
err = switchdev_port_vlan_dump_put(dev, &dump);
508+
}
509+
510+
err_out:
511+
return err == -EOPNOTSUPP ? 0 : err;
512+
}
513+
394514
/**
395515
* switchdev_port_bridge_getlink - Get bridge port attributes
396516
*
@@ -415,7 +535,8 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
415535
return err;
416536

417537
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode,
418-
attr.u.brport_flags, mask, nlflags);
538+
attr.u.brport_flags, mask, nlflags,
539+
filter_mask, switchdev_port_vlan_fill);
419540
}
420541
EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink);
421542

0 commit comments

Comments
 (0)