Skip to content

Commit 6cbdcee

Browse files
Vlad Yasevichdavem330
authored andcommitted
bridge: Dump vlan information from a bridge port
Using the RTM_GETLINK dump the vlan filter list of a given bridge port. The information depends on setting the filter flag similar to how nic VF info is dumped. Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 407af32 commit 6cbdcee

File tree

7 files changed

+104
-18
lines changed

7 files changed

+104
-18
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7079,7 +7079,8 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
70797079
}
70807080

70817081
static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
7082-
struct net_device *dev)
7082+
struct net_device *dev,
7083+
u32 filter_mask)
70837084
{
70847085
struct ixgbe_adapter *adapter = netdev_priv(dev);
70857086
u16 mode;

include/linux/netdevice.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,8 @@ struct net_device_ops {
10191019
struct nlmsghdr *nlh);
10201020
int (*ndo_bridge_getlink)(struct sk_buff *skb,
10211021
u32 pid, u32 seq,
1022-
struct net_device *dev);
1022+
struct net_device *dev,
1023+
u32 filter_mask);
10231024
int (*ndo_bridge_dellink)(struct net_device *dev,
10241025
struct nlmsghdr *nlh);
10251026
int (*ndo_change_carrier)(struct net_device *dev,

include/uapi/linux/rtnetlink.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,7 @@ struct tcamsg {
630630

631631
/* New extended info filters for IFLA_EXT_MASK */
632632
#define RTEXT_FILTER_VF (1 << 0)
633+
#define RTEXT_FILTER_BRVLAN (1 << 1)
633634

634635
/* End of information exported to user level */
635636

net/bridge/br_netlink.c

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,21 @@ static int br_port_fill_attrs(struct sk_buff *skb,
6565
* Create one netlink message for one interface
6666
* Contains port and master info as well as carrier and bridge state.
6767
*/
68-
static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *port,
69-
u32 pid, u32 seq, int event, unsigned int flags)
68+
static int br_fill_ifinfo(struct sk_buff *skb,
69+
const struct net_bridge_port *port,
70+
u32 pid, u32 seq, int event, unsigned int flags,
71+
u32 filter_mask, const struct net_device *dev)
7072
{
71-
const struct net_bridge *br = port->br;
72-
const struct net_device *dev = port->dev;
73+
const struct net_bridge *br;
7374
struct ifinfomsg *hdr;
7475
struct nlmsghdr *nlh;
7576
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
7677

78+
if (port)
79+
br = port->br;
80+
else
81+
br = netdev_priv(dev);
82+
7783
br_debug(br, "br_fill_info event %d port %s master %s\n",
7884
event, dev->name, br->dev->name);
7985

@@ -99,7 +105,7 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
99105
nla_put_u32(skb, IFLA_LINK, dev->iflink)))
100106
goto nla_put_failure;
101107

102-
if (event == RTM_NEWLINK) {
108+
if (event == RTM_NEWLINK && port) {
103109
struct nlattr *nest
104110
= nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
105111

@@ -108,6 +114,40 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
108114
nla_nest_end(skb, nest);
109115
}
110116

117+
/* Check if the VID information is requested */
118+
if (filter_mask & RTEXT_FILTER_BRVLAN) {
119+
struct nlattr *af;
120+
const struct net_port_vlans *pv;
121+
struct bridge_vlan_info vinfo;
122+
u16 vid;
123+
124+
if (port)
125+
pv = nbp_get_vlan_info(port);
126+
else
127+
pv = br_get_vlan_info(br);
128+
129+
if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN))
130+
goto done;
131+
132+
af = nla_nest_start(skb, IFLA_AF_SPEC);
133+
if (!af)
134+
goto nla_put_failure;
135+
136+
for (vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
137+
vid < BR_VLAN_BITMAP_LEN;
138+
vid = find_next_bit(pv->vlan_bitmap,
139+
BR_VLAN_BITMAP_LEN, vid+1)) {
140+
vinfo.vid = vid;
141+
vinfo.flags = 0;
142+
if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
143+
sizeof(vinfo), &vinfo))
144+
goto nla_put_failure;
145+
}
146+
147+
nla_nest_end(skb, af);
148+
}
149+
150+
done:
111151
return nlmsg_end(skb, nlh);
112152

113153
nla_put_failure:
@@ -135,7 +175,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
135175
if (skb == NULL)
136176
goto errout;
137177

138-
err = br_fill_ifinfo(skb, port, 0, 0, event, 0);
178+
err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 0, port->dev);
139179
if (err < 0) {
140180
/* -EMSGSIZE implies BUG in br_nlmsg_size() */
141181
WARN_ON(err == -EMSGSIZE);
@@ -154,16 +194,17 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
154194
* Dump information about all ports, in response to GETLINK
155195
*/
156196
int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
157-
struct net_device *dev)
197+
struct net_device *dev, u32 filter_mask)
158198
{
159199
int err = 0;
160200
struct net_bridge_port *port = br_port_get_rcu(dev);
161201

162-
/* not a bridge port */
163-
if (!port)
202+
/* not a bridge port and */
203+
if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN))
164204
goto out;
165205

166-
err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI);
206+
err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI,
207+
filter_mask, dev);
167208
out:
168209
return err;
169210
}
@@ -395,6 +436,29 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[])
395436
return 0;
396437
}
397438

439+
static size_t br_get_link_af_size(const struct net_device *dev)
440+
{
441+
struct net_port_vlans *pv;
442+
443+
if (br_port_exists(dev))
444+
pv = nbp_get_vlan_info(br_port_get_rcu(dev));
445+
else if (dev->priv_flags & IFF_EBRIDGE)
446+
pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev));
447+
else
448+
return 0;
449+
450+
if (!pv)
451+
return 0;
452+
453+
/* Each VLAN is returned in bridge_vlan_info along with flags */
454+
return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info));
455+
}
456+
457+
struct rtnl_af_ops br_af_ops = {
458+
.family = AF_BRIDGE,
459+
.get_link_af_size = br_get_link_af_size,
460+
};
461+
398462
struct rtnl_link_ops br_link_ops __read_mostly = {
399463
.kind = "bridge",
400464
.priv_size = sizeof(struct net_bridge),
@@ -408,11 +472,18 @@ int __init br_netlink_init(void)
408472
int err;
409473

410474
br_mdb_init();
411-
err = rtnl_link_register(&br_link_ops);
475+
err = rtnl_af_register(&br_af_ops);
412476
if (err)
413477
goto out;
414478

479+
err = rtnl_link_register(&br_link_ops);
480+
if (err)
481+
goto out_af;
482+
415483
return 0;
484+
485+
out_af:
486+
rtnl_af_unregister(&br_af_ops);
416487
out:
417488
br_mdb_uninit();
418489
return err;
@@ -421,5 +492,6 @@ int __init br_netlink_init(void)
421492
void __exit br_netlink_fini(void)
422493
{
423494
br_mdb_uninit();
495+
rtnl_af_unregister(&br_af_ops);
424496
rtnl_link_unregister(&br_link_ops);
425497
}

net/bridge/br_private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ struct net_port_vlans {
7373
} parent;
7474
struct rcu_head rcu;
7575
unsigned long vlan_bitmap[BR_VLAN_BITMAP_LEN];
76+
u16 num_vlans;
7677
};
7778

7879
struct net_bridge_fdb_entry
@@ -715,7 +716,7 @@ extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
715716
extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg);
716717
extern int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg);
717718
extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
718-
struct net_device *dev);
719+
struct net_device *dev, u32 filter_mask);
719720

720721
#ifdef CONFIG_SYSFS
721722
/* br_sysfs_if.c */

net/bridge/br_vlan.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid)
2828
}
2929

3030
set_bit(vid, v->vlan_bitmap);
31+
v->num_vlans++;
3132
return 0;
3233
}
3334

@@ -44,6 +45,7 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid)
4445
}
4546

4647
clear_bit(vid, v->vlan_bitmap);
48+
v->num_vlans--;
4749
if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
4850
if (v->port_idx)
4951
rcu_assign_pointer(v->parent.port->vlan_info, NULL);

net/core/rtnetlink.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,6 +2315,13 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
23152315
int idx = 0;
23162316
u32 portid = NETLINK_CB(cb->skb).portid;
23172317
u32 seq = cb->nlh->nlmsg_seq;
2318+
struct nlattr *extfilt;
2319+
u32 filter_mask = 0;
2320+
2321+
extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct rtgenmsg),
2322+
IFLA_EXT_MASK);
2323+
if (extfilt)
2324+
filter_mask = nla_get_u32(extfilt);
23182325

23192326
rcu_read_lock();
23202327
for_each_netdev_rcu(net, dev) {
@@ -2324,14 +2331,15 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
23242331
if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
23252332
if (idx >= cb->args[0] &&
23262333
br_dev->netdev_ops->ndo_bridge_getlink(
2327-
skb, portid, seq, dev) < 0)
2334+
skb, portid, seq, dev, filter_mask) < 0)
23282335
break;
23292336
idx++;
23302337
}
23312338

23322339
if (ops->ndo_bridge_getlink) {
23332340
if (idx >= cb->args[0] &&
2334-
ops->ndo_bridge_getlink(skb, portid, seq, dev) < 0)
2341+
ops->ndo_bridge_getlink(skb, portid, seq, dev,
2342+
filter_mask) < 0)
23352343
break;
23362344
idx++;
23372345
}
@@ -2372,14 +2380,14 @@ static int rtnl_bridge_notify(struct net_device *dev, u16 flags)
23722380

23732381
if ((!flags || (flags & BRIDGE_FLAGS_MASTER)) &&
23742382
br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
2375-
err = br_dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev);
2383+
err = br_dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0);
23762384
if (err < 0)
23772385
goto errout;
23782386
}
23792387

23802388
if ((flags & BRIDGE_FLAGS_SELF) &&
23812389
dev->netdev_ops->ndo_bridge_getlink) {
2382-
err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev);
2390+
err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0);
23832391
if (err < 0)
23842392
goto errout;
23852393
}

0 commit comments

Comments
 (0)