Skip to content

Commit 407af32

Browse files
Vlad Yasevichdavem330
authored andcommitted
bridge: Add netlink interface to configure vlans on bridge ports
Add a netlink interface to add and remove vlan configuration on bridge port. The interface uses the RTM_SETLINK message and encodes the vlan configuration inside the IFLA_AF_SPEC. It is possble to include multiple vlans to either add or remove in a single message. Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 85f46c6 commit 407af32

File tree

7 files changed

+207
-18
lines changed

7 files changed

+207
-18
lines changed

include/linux/netdevice.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,8 @@ struct net_device_ops {
10201020
int (*ndo_bridge_getlink)(struct sk_buff *skb,
10211021
u32 pid, u32 seq,
10221022
struct net_device *dev);
1023+
int (*ndo_bridge_dellink)(struct net_device *dev,
1024+
struct nlmsghdr *nlh);
10231025
int (*ndo_change_carrier)(struct net_device *dev,
10241026
bool new_carrier);
10251027
};

include/uapi/linux/if_bridge.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,24 @@ struct __fdb_entry {
108108
* [IFLA_AF_SPEC] = {
109109
* [IFLA_BRIDGE_FLAGS]
110110
* [IFLA_BRIDGE_MODE]
111+
* [IFLA_BRIDGE_VLAN_INFO]
111112
* }
112113
*/
113114
enum {
114115
IFLA_BRIDGE_FLAGS,
115116
IFLA_BRIDGE_MODE,
117+
IFLA_BRIDGE_VLAN_INFO,
116118
__IFLA_BRIDGE_MAX,
117119
};
118120
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
119121

122+
#define BRIDGE_VLAN_INFO_MASTER (1<<0) /* Operate on Bridge device as well */
123+
124+
struct bridge_vlan_info {
125+
u16 flags;
126+
u16 vid;
127+
};
128+
120129
/* Bridge multicast database attributes
121130
* [MDBA_MDB] = {
122131
* [MDBA_MDB_ENTRY] = {

net/bridge/br_device.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ static const struct net_device_ops br_netdev_ops = {
316316
.ndo_fdb_dump = br_fdb_dump,
317317
.ndo_bridge_getlink = br_getlink,
318318
.ndo_bridge_setlink = br_setlink,
319+
.ndo_bridge_dellink = br_dellink,
319320
};
320321

321322
static void br_dev_free(struct net_device *dev)

net/bridge/br_if.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/if_ether.h>
2424
#include <linux/slab.h>
2525
#include <net/sock.h>
26+
#include <linux/if_vlan.h>
2627

2728
#include "br_private.h"
2829

net/bridge/br_netlink.c

Lines changed: 121 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <net/rtnetlink.h>
1717
#include <net/net_namespace.h>
1818
#include <net/sock.h>
19+
#include <uapi/linux/if_bridge.h>
1920

2021
#include "br_private.h"
2122
#include "br_private_stp.h"
@@ -119,10 +120,14 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
119120
*/
120121
void br_ifinfo_notify(int event, struct net_bridge_port *port)
121122
{
122-
struct net *net = dev_net(port->dev);
123+
struct net *net;
123124
struct sk_buff *skb;
124125
int err = -ENOBUFS;
125126

127+
if (!port)
128+
return;
129+
130+
net = dev_net(port->dev);
126131
br_debug(port->br, "port %u(%s) event %d\n",
127132
(unsigned int)port->port_no, port->dev->name, event);
128133

@@ -144,6 +149,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
144149
rtnl_set_sk_err(net, RTNLGRP_LINK, err);
145150
}
146151

152+
147153
/*
148154
* Dump information about all ports, in response to GETLINK
149155
*/
@@ -162,6 +168,64 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
162168
return err;
163169
}
164170

171+
const struct nla_policy ifla_br_policy[IFLA_MAX+1] = {
172+
[IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 },
173+
[IFLA_BRIDGE_MODE] = { .type = NLA_U16 },
174+
[IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
175+
.len = sizeof(struct bridge_vlan_info), },
176+
};
177+
178+
static int br_afspec(struct net_bridge *br,
179+
struct net_bridge_port *p,
180+
struct nlattr *af_spec,
181+
int cmd)
182+
{
183+
struct nlattr *tb[IFLA_BRIDGE_MAX+1];
184+
int err = 0;
185+
186+
err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy);
187+
if (err)
188+
return err;
189+
190+
if (tb[IFLA_BRIDGE_VLAN_INFO]) {
191+
struct bridge_vlan_info *vinfo;
192+
193+
vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
194+
195+
if (vinfo->vid >= VLAN_N_VID)
196+
return -EINVAL;
197+
198+
switch (cmd) {
199+
case RTM_SETLINK:
200+
if (p) {
201+
err = nbp_vlan_add(p, vinfo->vid);
202+
if (err)
203+
break;
204+
205+
if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
206+
err = br_vlan_add(p->br, vinfo->vid);
207+
} else
208+
err = br_vlan_add(br, vinfo->vid);
209+
210+
if (err)
211+
break;
212+
213+
break;
214+
215+
case RTM_DELLINK:
216+
if (p) {
217+
nbp_vlan_delete(p, vinfo->vid);
218+
if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
219+
br_vlan_delete(p->br, vinfo->vid);
220+
} else
221+
br_vlan_delete(br, vinfo->vid);
222+
break;
223+
}
224+
}
225+
226+
return err;
227+
}
228+
165229
static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
166230
[IFLA_BRPORT_STATE] = { .type = NLA_U8 },
167231
[IFLA_BRPORT_COST] = { .type = NLA_U32 },
@@ -241,45 +305,84 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
241305
{
242306
struct ifinfomsg *ifm;
243307
struct nlattr *protinfo;
308+
struct nlattr *afspec;
244309
struct net_bridge_port *p;
245310
struct nlattr *tb[IFLA_BRPORT_MAX + 1];
246311
int err;
247312

248313
ifm = nlmsg_data(nlh);
249314

250315
protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
251-
if (!protinfo)
316+
afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC);
317+
if (!protinfo && !afspec)
252318
return 0;
253319

254320
p = br_port_get_rtnl(dev);
255-
if (!p)
321+
/* We want to accept dev as bridge itself if the AF_SPEC
322+
* is set to see if someone is setting vlan info on the brigde
323+
*/
324+
if (!p && ((dev->priv_flags & IFF_EBRIDGE) && !afspec))
256325
return -EINVAL;
257326

258-
if (protinfo->nla_type & NLA_F_NESTED) {
259-
err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
260-
protinfo, ifla_brport_policy);
327+
if (p && protinfo) {
328+
if (protinfo->nla_type & NLA_F_NESTED) {
329+
err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
330+
protinfo, ifla_brport_policy);
331+
if (err)
332+
return err;
333+
334+
spin_lock_bh(&p->br->lock);
335+
err = br_setport(p, tb);
336+
spin_unlock_bh(&p->br->lock);
337+
} else {
338+
/* Binary compatability with old RSTP */
339+
if (nla_len(protinfo) < sizeof(u8))
340+
return -EINVAL;
341+
342+
spin_lock_bh(&p->br->lock);
343+
err = br_set_port_state(p, nla_get_u8(protinfo));
344+
spin_unlock_bh(&p->br->lock);
345+
}
261346
if (err)
262-
return err;
263-
264-
spin_lock_bh(&p->br->lock);
265-
err = br_setport(p, tb);
266-
spin_unlock_bh(&p->br->lock);
267-
} else {
268-
/* Binary compatability with old RSTP */
269-
if (nla_len(protinfo) < sizeof(u8))
270-
return -EINVAL;
347+
goto out;
348+
}
271349

272-
spin_lock_bh(&p->br->lock);
273-
err = br_set_port_state(p, nla_get_u8(protinfo));
274-
spin_unlock_bh(&p->br->lock);
350+
if (afspec) {
351+
err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
352+
afspec, RTM_SETLINK);
275353
}
276354

277355
if (err == 0)
278356
br_ifinfo_notify(RTM_NEWLINK, p);
279357

358+
out:
280359
return err;
281360
}
282361

362+
/* Delete port information */
363+
int br_dellink(struct net_device *dev, struct nlmsghdr *nlh)
364+
{
365+
struct ifinfomsg *ifm;
366+
struct nlattr *afspec;
367+
struct net_bridge_port *p;
368+
int err;
369+
370+
ifm = nlmsg_data(nlh);
371+
372+
afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC);
373+
if (!afspec)
374+
return 0;
375+
376+
p = br_port_get_rtnl(dev);
377+
/* We want to accept dev as bridge itself as well */
378+
if (!p && !(dev->priv_flags & IFF_EBRIDGE))
379+
return -EINVAL;
380+
381+
err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
382+
afspec, RTM_DELLINK);
383+
384+
return err;
385+
}
283386
static int br_validate(struct nlattr *tb[], struct nlattr *data[])
284387
{
285388
if (tb[IFLA_ADDRESS]) {

net/bridge/br_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ extern int br_netlink_init(void);
713713
extern void br_netlink_fini(void);
714714
extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
715715
extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg);
716+
extern int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg);
716717
extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
717718
struct net_device *dev);
718719

net/core/rtnetlink.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2464,6 +2464,77 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
24642464
return err;
24652465
}
24662466

2467+
static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
2468+
void *arg)
2469+
{
2470+
struct net *net = sock_net(skb->sk);
2471+
struct ifinfomsg *ifm;
2472+
struct net_device *dev;
2473+
struct nlattr *br_spec, *attr = NULL;
2474+
int rem, err = -EOPNOTSUPP;
2475+
u16 oflags, flags = 0;
2476+
bool have_flags = false;
2477+
2478+
if (nlmsg_len(nlh) < sizeof(*ifm))
2479+
return -EINVAL;
2480+
2481+
ifm = nlmsg_data(nlh);
2482+
if (ifm->ifi_family != AF_BRIDGE)
2483+
return -EPFNOSUPPORT;
2484+
2485+
dev = __dev_get_by_index(net, ifm->ifi_index);
2486+
if (!dev) {
2487+
pr_info("PF_BRIDGE: RTM_SETLINK with unknown ifindex\n");
2488+
return -ENODEV;
2489+
}
2490+
2491+
br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
2492+
if (br_spec) {
2493+
nla_for_each_nested(attr, br_spec, rem) {
2494+
if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
2495+
have_flags = true;
2496+
flags = nla_get_u16(attr);
2497+
break;
2498+
}
2499+
}
2500+
}
2501+
2502+
oflags = flags;
2503+
2504+
if (!flags || (flags & BRIDGE_FLAGS_MASTER)) {
2505+
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
2506+
2507+
if (!br_dev || !br_dev->netdev_ops->ndo_bridge_dellink) {
2508+
err = -EOPNOTSUPP;
2509+
goto out;
2510+
}
2511+
2512+
err = br_dev->netdev_ops->ndo_bridge_dellink(dev, nlh);
2513+
if (err)
2514+
goto out;
2515+
2516+
flags &= ~BRIDGE_FLAGS_MASTER;
2517+
}
2518+
2519+
if ((flags & BRIDGE_FLAGS_SELF)) {
2520+
if (!dev->netdev_ops->ndo_bridge_dellink)
2521+
err = -EOPNOTSUPP;
2522+
else
2523+
err = dev->netdev_ops->ndo_bridge_dellink(dev, nlh);
2524+
2525+
if (!err)
2526+
flags &= ~BRIDGE_FLAGS_SELF;
2527+
}
2528+
2529+
if (have_flags)
2530+
memcpy(nla_data(attr), &flags, sizeof(flags));
2531+
/* Generate event to notify upper layer of bridge change */
2532+
if (!err)
2533+
err = rtnl_bridge_notify(dev, oflags);
2534+
out:
2535+
return err;
2536+
}
2537+
24672538
/* Protected by RTNL sempahore. */
24682539
static struct rtattr **rta_buf;
24692540
static int rtattr_max;
@@ -2647,6 +2718,7 @@ void __init rtnetlink_init(void)
26472718
rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL);
26482719

26492720
rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL);
2721+
rtnl_register(PF_BRIDGE, RTM_DELLINK, rtnl_bridge_dellink, NULL, NULL);
26502722
rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL);
26512723
}
26522724

0 commit comments

Comments
 (0)