History

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.

Nikolay Aleksandrov committed 5 years ago

Commit 47ecd2d1 parent 1e9ca454 files · +115 −3Browse files

Unified · Split

4 files
  1. include/uapi/linux/if_bridge.h +13 −0
  2. net/bridge/br_private.h +4 −0
  3. net/bridge/br_vlan.c +13 −3
  4. net/bridge/br_vlan_options.c +85 −0
include/uapi/linux/if_bridge.h+13−0
@@ -485,10 +485,15 @@ enum { · 484 unmodified lines
485 * [BRIDGE_VLANDB_ENTRY_INFO]485 * [BRIDGE_VLANDB_ENTRY_INFO]
486 * ...486 * ...
487 * }487 * }
488 * [BRIDGE_VLANDB_GLOBAL_OPTIONS] = {
489 * [BRIDGE_VLANDB_GOPTS_ID]
490 * ...
491 * }
488 */492 */
489enum {493enum {
490 BRIDGE_VLANDB_UNSPEC,494 BRIDGE_VLANDB_UNSPEC,
491 BRIDGE_VLANDB_ENTRY,495 BRIDGE_VLANDB_ENTRY,
496 BRIDGE_VLANDB_GLOBAL_OPTIONS,
492 __BRIDGE_VLANDB_MAX,497 __BRIDGE_VLANDB_MAX,
493};498};
494#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1)499#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1)
@@ -538,6 +543,14 @@ enum { · 43 unmodified lines
538};543};
539#define BRIDGE_VLANDB_STATS_MAX (__BRIDGE_VLANDB_STATS_MAX - 1)544#define BRIDGE_VLANDB_STATS_MAX (__BRIDGE_VLANDB_STATS_MAX - 1)
540 545
546enum {
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
541/* Bridge multicast database attributes554/* Bridge multicast database attributes
542 * [MDBA_MDB] = {555 * [MDBA_MDB] = {
543 * [MDBA_MDB_ENTRY] = {556 * [MDBA_MDB_ENTRY] = {
net/bridge/br_private.h+4−0
@@ -1592,6 +1592,10 @@ int br_vlan_process_options(const struct net_bridge *br, · 1591 unmodified lines
1592 struct net_bridge_vlan *range_end,1592 struct net_bridge_vlan *range_end,
1593 struct nlattr **tb,1593 struct nlattr **tb,
1594 struct netlink_ext_ack *extack);1594 struct netlink_ext_ack *extack);
1595int br_vlan_rtm_process_global_options(struct net_device *dev,
1596 const struct nlattr *attr,
1597 int cmd,
1598 struct netlink_ext_ack *extack);
1595 1599
1596/* vlan state manipulation helpers using *_ONCE to annotate lock-free access */1600/* vlan state manipulation helpers using *_ONCE to annotate lock-free access */
1597static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)1601static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)
net/bridge/br_vlan.c+13−3
@@ -2203,12 +2203,22 @@ static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh, · 2202 unmodified lines
2203 }2203 }
2204 2204
2205 nlmsg_for_each_attr(attr, nlh, sizeof(*bvm), rem) {2205 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:
2207 continue;2218 continue;
2219 }
2208 2220
2209 vlans++;2221 vlans++;
2210 err = br_vlan_rtm_process_one(dev, attr, nlh->nlmsg_type,
2211 extack);
2212 if (err)2222 if (err)
2213 break;2223 break;
2214 }2224 }
net/bridge/br_vlan_options.c+85−0
@@ -258,3 +258,88 @@ int br_vlan_process_options(const struct net_bridge *br, · 257 unmodified lines
258 258
259 return err;259 return err;
260}260}
261
262static 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
273static 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
278int 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}