Skip to content

Commit 47ecd2d

Browse files
Nikolay Aleksandrovdavem330
authored andcommitted
net: bridge: vlan: add support for global options
We can have two types of vlan options depending on context: - per-device vlan options (split in per-bridge and per-port) - global vlan options The second type wasn't supported in the bridge until now, but we need them for per-vlan multicast support, per-vlan STP support and other options which require global vlan context. They are contained in the global bridge vlan context even if the vlan is not configured on the bridge device itself. This patch adds initial netlink attributes and support for setting these global vlan options, they can only be set (RTM_NEWVLAN) and the operation must use the bridge device. Since there are no such options yet it shouldn't have any functional effect. Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 1e9ca45 commit 47ecd2d

File tree

4 files changed

+115
-3
lines changed

4 files changed

+115
-3
lines changed

include/uapi/linux/if_bridge.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,15 @@ enum {
485485
* [BRIDGE_VLANDB_ENTRY_INFO]
486486
* ...
487487
* }
488+
* [BRIDGE_VLANDB_GLOBAL_OPTIONS] = {
489+
* [BRIDGE_VLANDB_GOPTS_ID]
490+
* ...
491+
* }
488492
*/
489493
enum {
490494
BRIDGE_VLANDB_UNSPEC,
491495
BRIDGE_VLANDB_ENTRY,
496+
BRIDGE_VLANDB_GLOBAL_OPTIONS,
492497
__BRIDGE_VLANDB_MAX,
493498
};
494499
#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1)
@@ -538,6 +543,14 @@ enum {
538543
};
539544
#define BRIDGE_VLANDB_STATS_MAX (__BRIDGE_VLANDB_STATS_MAX - 1)
540545

546+
enum {
547+
BRIDGE_VLANDB_GOPTS_UNSPEC,
548+
BRIDGE_VLANDB_GOPTS_ID,
549+
BRIDGE_VLANDB_GOPTS_RANGE,
550+
__BRIDGE_VLANDB_GOPTS_MAX
551+
};
552+
#define BRIDGE_VLANDB_GOPTS_MAX (__BRIDGE_VLANDB_GOPTS_MAX - 1)
553+
541554
/* Bridge multicast database attributes
542555
* [MDBA_MDB] = {
543556
* [MDBA_MDB_ENTRY] = {

net/bridge/br_private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,10 @@ int br_vlan_process_options(const struct net_bridge *br,
15921592
struct net_bridge_vlan *range_end,
15931593
struct nlattr **tb,
15941594
struct netlink_ext_ack *extack);
1595+
int br_vlan_rtm_process_global_options(struct net_device *dev,
1596+
const struct nlattr *attr,
1597+
int cmd,
1598+
struct netlink_ext_ack *extack);
15951599

15961600
/* vlan state manipulation helpers using *_ONCE to annotate lock-free access */
15971601
static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)

net/bridge/br_vlan.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,12 +2203,22 @@ static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh,
22032203
}
22042204

22052205
nlmsg_for_each_attr(attr, nlh, sizeof(*bvm), rem) {
2206-
if (nla_type(attr) != BRIDGE_VLANDB_ENTRY)
2206+
switch (nla_type(attr)) {
2207+
case BRIDGE_VLANDB_ENTRY:
2208+
err = br_vlan_rtm_process_one(dev, attr,
2209+
nlh->nlmsg_type,
2210+
extack);
2211+
break;
2212+
case BRIDGE_VLANDB_GLOBAL_OPTIONS:
2213+
err = br_vlan_rtm_process_global_options(dev, attr,
2214+
nlh->nlmsg_type,
2215+
extack);
2216+
break;
2217+
default:
22072218
continue;
2219+
}
22082220

22092221
vlans++;
2210-
err = br_vlan_rtm_process_one(dev, attr, nlh->nlmsg_type,
2211-
extack);
22122222
if (err)
22132223
break;
22142224
}

net/bridge/br_vlan_options.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,88 @@ int br_vlan_process_options(const struct net_bridge *br,
258258

259259
return err;
260260
}
261+
262+
static int br_vlan_process_global_one_opts(const struct net_bridge *br,
263+
struct net_bridge_vlan_group *vg,
264+
struct net_bridge_vlan *v,
265+
struct nlattr **tb,
266+
bool *changed,
267+
struct netlink_ext_ack *extack)
268+
{
269+
*changed = false;
270+
return 0;
271+
}
272+
273+
static const struct nla_policy br_vlan_db_gpol[BRIDGE_VLANDB_GOPTS_MAX + 1] = {
274+
[BRIDGE_VLANDB_GOPTS_ID] = { .type = NLA_U16 },
275+
[BRIDGE_VLANDB_GOPTS_RANGE] = { .type = NLA_U16 },
276+
};
277+
278+
int br_vlan_rtm_process_global_options(struct net_device *dev,
279+
const struct nlattr *attr,
280+
int cmd,
281+
struct netlink_ext_ack *extack)
282+
{
283+
struct nlattr *tb[BRIDGE_VLANDB_GOPTS_MAX + 1];
284+
struct net_bridge_vlan_group *vg;
285+
struct net_bridge_vlan *v;
286+
u16 vid, vid_range = 0;
287+
struct net_bridge *br;
288+
int err = 0;
289+
290+
if (cmd != RTM_NEWVLAN) {
291+
NL_SET_ERR_MSG_MOD(extack, "Global vlan options support only set operation");
292+
return -EINVAL;
293+
}
294+
if (!netif_is_bridge_master(dev)) {
295+
NL_SET_ERR_MSG_MOD(extack, "Global vlan options can only be set on bridge device");
296+
return -EINVAL;
297+
}
298+
br = netdev_priv(dev);
299+
vg = br_vlan_group(br);
300+
if (WARN_ON(!vg))
301+
return -ENODEV;
302+
303+
err = nla_parse_nested(tb, BRIDGE_VLANDB_GOPTS_MAX, attr,
304+
br_vlan_db_gpol, extack);
305+
if (err)
306+
return err;
307+
308+
if (!tb[BRIDGE_VLANDB_GOPTS_ID]) {
309+
NL_SET_ERR_MSG_MOD(extack, "Missing vlan entry id");
310+
return -EINVAL;
311+
}
312+
vid = nla_get_u16(tb[BRIDGE_VLANDB_GOPTS_ID]);
313+
if (!br_vlan_valid_id(vid, extack))
314+
return -EINVAL;
315+
316+
if (tb[BRIDGE_VLANDB_GOPTS_RANGE]) {
317+
vid_range = nla_get_u16(tb[BRIDGE_VLANDB_GOPTS_RANGE]);
318+
if (!br_vlan_valid_id(vid_range, extack))
319+
return -EINVAL;
320+
if (vid >= vid_range) {
321+
NL_SET_ERR_MSG_MOD(extack, "End vlan id is less than or equal to start vlan id");
322+
return -EINVAL;
323+
}
324+
} else {
325+
vid_range = vid;
326+
}
327+
328+
for (; vid <= vid_range; vid++) {
329+
bool changed = false;
330+
331+
v = br_vlan_find(vg, vid);
332+
if (!v) {
333+
NL_SET_ERR_MSG_MOD(extack, "Vlan in range doesn't exist, can't process global options");
334+
err = -ENOENT;
335+
break;
336+
}
337+
338+
err = br_vlan_process_global_one_opts(br, vg, v, tb, &changed,
339+
extack);
340+
if (err)
341+
break;
342+
}
343+
344+
return err;
345+
}

0 commit comments

Comments
 (0)