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
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 { · 43 unmodified lines
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+4−0
@@ -1592,6 +1592,10 @@ int br_vlan_process_options(const struct net_bridge *br, · 1591 unmodified lines
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+13−3
@@ -2203,12 +2203,22 @@ static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh, · 2202 unmodified lines
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+85−0
@@ -258,3 +258,88 @@ int br_vlan_process_options(const struct net_bridge *br, · 257 unmodified lines
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+}