This allow to define vlan range on bridge ports.

example:
bridge vlan add vid 1-4094 dev eth0

(This require iproute2 4.0 utils)

Theses patches are already in kernel 4.0, so we can remove them when will 
upgrade to 4.X kernel.

Signed-off-by: Alexandre Derumier <aderum...@odiso.com>
---
 Makefile                 |   4 +
 bridge-vlandrange1.patch | 166 +++++++++++++++++++++++++++++++++++++++
 bridge-vlandrange2.patch |  28 +++++++
 bridge-vlandrange3.patch | 196 +++++++++++++++++++++++++++++++++++++++++++++++
 bridge-vlandrange4.patch |  47 ++++++++++++
 5 files changed, 441 insertions(+)
 create mode 100644 bridge-vlandrange1.patch
 create mode 100644 bridge-vlandrange2.patch
 create mode 100644 bridge-vlandrange3.patch
 create mode 100644 bridge-vlandrange4.patch

diff --git a/Makefile b/Makefile
index e7c7764..a2ff8a0 100644
--- a/Makefile
+++ b/Makefile
@@ -201,6 +201,10 @@ ${KERNEL_SRC}/README ${KERNEL_CFG_ORG}: ${KERNELSRCTAR}
        tar xf ${KERNELSRCTAR}
        cat ${KERNEL_SRC}/debian.master/config/config.common.ubuntu 
${KERNEL_SRC}/debian.master/config/amd64/config.common.amd64 
${KERNEL_SRC}/debian.master/config/amd64/config.flavour.generic > 
${KERNEL_CFG_ORG}
        cd ${KERNEL_SRC}; patch -p1 <../bridge-patch.diff
+       cd ${KERNEL_SRC}; patch -p1 <../bridge-vlandrange1.patch
+       cd ${KERNEL_SRC}; patch -p1 <../bridge-vlandrange2.patch
+       cd ${KERNEL_SRC}; patch -p1 <../bridge-vlandrange3.patch
+       cd ${KERNEL_SRC}; patch -p1 <../bridge-vlandrange4.patch
        #cd ${KERNEL_SRC}; patch -p1 
<../bridge-forward-ipv6-neighbor-solicitation.patch
        #cd ${KERNEL_SRC}; patch -p1 
<../add-empty-ndo_poll_controller-to-veth.patch
        #cd ${KERNEL_SRC}; patch -p1 
<../override_for_missing_acs_capabilities.patch
diff --git a/bridge-vlandrange1.patch b/bridge-vlandrange1.patch
new file mode 100644
index 0000000..11b86bb
--- /dev/null
+++ b/bridge-vlandrange1.patch
@@ -0,0 +1,166 @@
+From bdced7ef7838c1c4aebe9f295e44b7f0dcae2109 Mon Sep 17 00:00:00 2001
+From: Roopa Prabhu <ro...@cumulusnetworks.com>
+Date: Sat, 10 Jan 2015 07:31:12 -0800
+Subject: bridge: support for multiple vlans and vlan ranges in setlink and
+ dellink requests
+
+This patch changes bridge IFLA_AF_SPEC netlink attribute parser to
+look for more than one IFLA_BRIDGE_VLAN_INFO attribute. This allows
+userspace to pack more than one vlan in the setlink msg.
+
+The dumps were already sending more than one vlan info in the getlink msg.
+
+This patch also adds bridge_vlan_info flags BRIDGE_VLAN_INFO_RANGE_BEGIN and
+BRIDGE_VLAN_INFO_RANGE_END to indicate start and end of vlan range
+
+This patch also deletes unused ifla_br_policy.
+
+Signed-off-by: Roopa Prabhu <ro...@cumulusnetworks.com>
+Signed-off-by: David S. Miller <da...@davemloft.net>
+
+diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
+index b03ee8f..eaaea62 100644
+--- a/include/uapi/linux/if_bridge.h
++++ b/include/uapi/linux/if_bridge.h
+@@ -125,6 +125,8 @@ enum {
+ #define BRIDGE_VLAN_INFO_MASTER       (1<<0)  /* Operate on Bridge device as 
well */
+ #define BRIDGE_VLAN_INFO_PVID (1<<1)  /* VLAN is PVID, ingress untagged */
+ #define BRIDGE_VLAN_INFO_UNTAGGED     (1<<2)  /* VLAN egresses untagged */
++#define BRIDGE_VLAN_INFO_RANGE_BEGIN  (1<<3) /* VLAN is start of vlan range */
++#define BRIDGE_VLAN_INFO_RANGE_END    (1<<4) /* VLAN is end of vlan range */
+ 
+ struct bridge_vlan_info {
+       __u16 flags;
+diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
+index 9f5eb55..6f616a2 100644
+--- a/net/bridge/br_netlink.c
++++ b/net/bridge/br_netlink.c
+@@ -218,57 +218,89 @@ out:
+       return err;
+ }
+ 
+-static const struct nla_policy ifla_br_policy[IFLA_MAX+1] = {
+-      [IFLA_BRIDGE_FLAGS]     = { .type = NLA_U16 },
+-      [IFLA_BRIDGE_MODE]      = { .type = NLA_U16 },
+-      [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
+-                                  .len = sizeof(struct bridge_vlan_info), },
+-};
++static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
++                      int cmd, struct bridge_vlan_info *vinfo)
++{
++      int err = 0;
++
++      switch (cmd) {
++      case RTM_SETLINK:
++              if (p) {
++                      err = nbp_vlan_add(p, vinfo->vid, vinfo->flags);
++                      if (err)
++                              break;
++
++                      if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
++                              err = br_vlan_add(p->br, vinfo->vid,
++                                                vinfo->flags);
++              } else {
++                      err = br_vlan_add(br, vinfo->vid, vinfo->flags);
++              }
++              break;
++
++      case RTM_DELLINK:
++              if (p) {
++                      nbp_vlan_delete(p, vinfo->vid);
++                      if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
++                              br_vlan_delete(p->br, vinfo->vid);
++              } else {
++                      br_vlan_delete(br, vinfo->vid);
++              }
++              break;
++      }
++
++      return err;
++}
+ 
+ static int br_afspec(struct net_bridge *br,
+                    struct net_bridge_port *p,
+                    struct nlattr *af_spec,
+                    int cmd)
+ {
+-      struct nlattr *tb[IFLA_BRIDGE_MAX+1];
++      struct bridge_vlan_info *vinfo_start = NULL;
++      struct bridge_vlan_info *vinfo = NULL;
++      struct nlattr *attr;
+       int err = 0;
++      int rem;
+ 
+-      err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy);
+-      if (err)
+-              return err;
++      nla_for_each_nested(attr, af_spec, rem) {
++              if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
++                      continue;
++              if (nla_len(attr) != sizeof(struct bridge_vlan_info))
++                      return -EINVAL;
++              vinfo = nla_data(attr);
++              if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
++                      if (vinfo_start)
++                              return -EINVAL;
++                      vinfo_start = vinfo;
++                      continue;
++              }
++
++              if (vinfo_start) {
++                      struct bridge_vlan_info tmp_vinfo;
++                      int v;
+ 
+-      if (tb[IFLA_BRIDGE_VLAN_INFO]) {
+-              struct bridge_vlan_info *vinfo;
++                      if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
++                              return -EINVAL;
+ 
+-              vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
++                      if (vinfo->vid <= vinfo_start->vid)
++                              return -EINVAL;
+ 
+-              if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
+-                      return -EINVAL;
++                      memcpy(&tmp_vinfo, vinfo_start,
++                             sizeof(struct bridge_vlan_info));
+ 
+-              switch (cmd) {
+-              case RTM_SETLINK:
+-                      if (p) {
+-                              err = nbp_vlan_add(p, vinfo->vid, vinfo->flags);
++                      for (v = vinfo_start->vid; v <= vinfo->vid; v++) {
++                              tmp_vinfo.vid = v;
++                              err = br_vlan_info(br, p, cmd, &tmp_vinfo);
+                               if (err)
+                                       break;
+-
+-                              if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
+-                                      err = br_vlan_add(p->br, vinfo->vid,
+-                                                        vinfo->flags);
+-                      } else
+-                              err = br_vlan_add(br, vinfo->vid, vinfo->flags);
+-
+-                      break;
+-
+-              case RTM_DELLINK:
+-                      if (p) {
+-                              nbp_vlan_delete(p, vinfo->vid);
+-                              if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
+-                                      br_vlan_delete(p->br, vinfo->vid);
+-                      } else
+-                              br_vlan_delete(br, vinfo->vid);
+-                      break;
++                      }
++                      vinfo_start = NULL;
++              } else {
++                      err = br_vlan_info(br, p, cmd, vinfo);
+               }
++              if (err)
++                      break;
+       }
+ 
+       return err;
+-- 
+cgit v0.10.2
+
diff --git a/bridge-vlandrange2.patch b/bridge-vlandrange2.patch
new file mode 100644
index 0000000..a4335c4
--- /dev/null
+++ b/bridge-vlandrange2.patch
@@ -0,0 +1,28 @@
+From 35a27cee321e7c4e7cba3550b2f48c2ca44d8a72 Mon Sep 17 00:00:00 2001
+From: Roopa Prabhu <ro...@cumulusnetworks.com>
+Date: Sat, 10 Jan 2015 07:31:13 -0800
+Subject: rtnetlink: new filter RTEXT_FILTER_BRVLAN_COMPRESSED
+
+This filter is same as RTEXT_FILTER_BRVLAN except that it tries
+to compress the consecutive vlans into ranges.
+
+This helps on systems with large number of configured vlans.
+
+Signed-off-by: Roopa Prabhu <ro...@cumulusnetworks.com>
+Signed-off-by: David S. Miller <da...@davemloft.net>
+
+diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
+index d81f22d..a1d1859 100644
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -636,6 +636,7 @@ struct tcamsg {
+ /* New extended info filters for IFLA_EXT_MASK */
+ #define RTEXT_FILTER_VF               (1 << 0)
+ #define RTEXT_FILTER_BRVLAN   (1 << 1)
++#define RTEXT_FILTER_BRVLAN_COMPRESSED        (1 << 2)
+ 
+ /* End of information exported to user level */
+ 
+-- 
+cgit v0.10.2
+
diff --git a/bridge-vlandrange3.patch b/bridge-vlandrange3.patch
new file mode 100644
index 0000000..d11f03f
--- /dev/null
+++ b/bridge-vlandrange3.patch
@@ -0,0 +1,196 @@
+From 36cd0ffbab8a65f44ae13fb200bfb5a8f9ea68de Mon Sep 17 00:00:00 2001
+From: Roopa Prabhu <ro...@cumulusnetworks.com>
+Date: Sat, 10 Jan 2015 07:31:14 -0800
+Subject: bridge: new function to pack vlans into ranges during gets
+
+This patch adds new function to pack vlans into ranges
+whereever applicable using the flags BRIDGE_VLAN_INFO_RANGE_BEGIN
+and BRIDGE VLAN_INFO_RANGE_END
+
+Old vlan packing code is moved to a new function and continues to be
+called when filter_mask is RTEXT_FILTER_BRVLAN.
+
+Signed-off-by: Roopa Prabhu <ro...@cumulusnetworks.com>
+Signed-off-by: David S. Miller <da...@davemloft.net>
+
+diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
+index 6f616a2..0b03879 100644
+--- a/net/bridge/br_netlink.c
++++ b/net/bridge/br_netlink.c
+@@ -67,6 +67,118 @@ static int br_port_fill_attrs(struct sk_buff *skb,
+       return 0;
+ }
+ 
++static int br_fill_ifvlaninfo_range(struct sk_buff *skb, u16 vid_start,
++                                  u16 vid_end, u16 flags)
++{
++      struct  bridge_vlan_info vinfo;
++
++      if ((vid_end - vid_start) > 0) {
++              /* add range to skb */
++              vinfo.vid = vid_start;
++              vinfo.flags = flags | BRIDGE_VLAN_INFO_RANGE_BEGIN;
++              if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
++                          sizeof(vinfo), &vinfo))
++                      goto nla_put_failure;
++
++              vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
++
++              vinfo.vid = vid_end;
++              vinfo.flags = flags | BRIDGE_VLAN_INFO_RANGE_END;
++              if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
++                          sizeof(vinfo), &vinfo))
++                      goto nla_put_failure;
++      } else {
++              vinfo.vid = vid_start;
++              vinfo.flags = flags;
++              if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
++                          sizeof(vinfo), &vinfo))
++                      goto nla_put_failure;
++      }
++
++      return 0;
++
++nla_put_failure:
++      return -EMSGSIZE;
++}
++
++static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
++                                       const struct net_port_vlans *pv)
++{
++      u16 vid_range_start = 0, vid_range_end = 0;
++      u16 vid_range_flags;
++      u16 pvid, vid, flags;
++      int err = 0;
++
++      /* Pack IFLA_BRIDGE_VLAN_INFO's for every vlan
++       * and mark vlan info with begin and end flags
++       * if vlaninfo represents a range
++       */
++      pvid = br_get_pvid(pv);
++      for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
++              flags = 0;
++              if (vid == pvid)
++                      flags |= BRIDGE_VLAN_INFO_PVID;
++
++              if (test_bit(vid, pv->untagged_bitmap))
++                      flags |= BRIDGE_VLAN_INFO_UNTAGGED;
++
++              if (vid_range_start == 0) {
++                      goto initvars;
++              } else if ((vid - vid_range_end) == 1 &&
++                      flags == vid_range_flags) {
++                      vid_range_end = vid;
++                      continue;
++              } else {
++                      err = br_fill_ifvlaninfo_range(skb, vid_range_start,
++                                                     vid_range_end,
++                                                     vid_range_flags);
++                      if (err)
++                              return err;
++              }
++
++initvars:
++              vid_range_start = vid;
++              vid_range_end = vid;
++              vid_range_flags = flags;
++      }
++
++      /* Call it once more to send any left over vlans */
++      err = br_fill_ifvlaninfo_range(skb, vid_range_start,
++                                     vid_range_end,
++                                     vid_range_flags);
++      if (err)
++              return err;
++
++      return 0;
++}
++
++static int br_fill_ifvlaninfo(struct sk_buff *skb,
++                            const struct net_port_vlans *pv)
++{
++      struct bridge_vlan_info vinfo;
++      u16 pvid, vid;
++
++      pvid = br_get_pvid(pv);
++      for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
++              vinfo.vid = vid;
++              vinfo.flags = 0;
++              if (vid == pvid)
++                      vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
++
++              if (test_bit(vid, pv->untagged_bitmap))
++                      vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
++
++              if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
++                          sizeof(vinfo), &vinfo))
++                      goto nla_put_failure;
++      }
++
++      return 0;
++
++nla_put_failure:
++      return -EMSGSIZE;
++}
++
+ /*
+  * Create one netlink message for one interface
+  * Contains port and master info as well as carrier and bridge state.
+@@ -121,12 +233,11 @@ static int br_fill_ifinfo(struct sk_buff *skb,
+       }
+ 
+       /* Check if  the VID information is requested */
+-      if (filter_mask & RTEXT_FILTER_BRVLAN) {
+-              struct nlattr *af;
++      if ((filter_mask & RTEXT_FILTER_BRVLAN) ||
++          (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) {
+               const struct net_port_vlans *pv;
+-              struct bridge_vlan_info vinfo;
+-              u16 vid;
+-              u16 pvid;
++              struct nlattr *af;
++              int err;
+ 
+               if (port)
+                       pv = nbp_get_vlan_info(port);
+@@ -140,21 +251,12 @@ static int br_fill_ifinfo(struct sk_buff *skb,
+               if (!af)
+                       goto nla_put_failure;
+ 
+-              pvid = br_get_pvid(pv);
+-              for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
+-                      vinfo.vid = vid;
+-                      vinfo.flags = 0;
+-                      if (vid == pvid)
+-                              vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
+-
+-                      if (test_bit(vid, pv->untagged_bitmap))
+-                              vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+-
+-                      if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
+-                                  sizeof(vinfo), &vinfo))
+-                              goto nla_put_failure;
+-              }
+-
++              if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
++                      err = br_fill_ifvlaninfo_compressed(skb, pv);
++              else
++                      err = br_fill_ifvlaninfo(skb, pv);
++              if (err)
++                      goto nla_put_failure;
+               nla_nest_end(skb, af);
+       }
+ 
+@@ -209,7 +311,8 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
+       int err = 0;
+       struct net_bridge_port *port = br_port_get_rtnl(dev);
+ 
+-      if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN))
++      if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN) &&
++          !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED))
+               goto out;
+ 
+       err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI,
+-- 
+cgit v0.10.2
+
diff --git a/bridge-vlandrange4.patch b/bridge-vlandrange4.patch
new file mode 100644
index 0000000..a044ed4
--- /dev/null
+++ b/bridge-vlandrange4.patch
@@ -0,0 +1,47 @@
+From patchwork Thu Jul  2 12:48:17 2015
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net] bridge: vlan: fix usage of vlan 0 and 4095 again
+From: Nikolay Aleksandrov <niko...@cumulusnetworks.com>
+X-Patchwork-Id: 490608
+Message-Id: <1435841297-44200-1-git-send-email-niko...@cumulusnetworks.com>
+To: net...@vger.kernel.org
+Cc: vyasev...@gmail.com, bri...@lists.linux-foundation.org,
+ da...@davemloft.net, toshiaki.maki...@gmail.com,
+ step...@networkplumber.org, ro...@cumulusnetworks.com,
+ Nikolay Aleksandrov <niko...@cumulusnetworks.com>
+Date: Thu,  2 Jul 2015 05:48:17 -0700
+
+Vlan ids 0 and 4095 were disallowed by commit:
+8adff41c3d25 ("bridge: Don't use VID 0 and 4095 in vlan filtering")
+but then the check was removed when vlan ranges were introduced by:
+bdced7ef7838 ("bridge: support for multiple vlans and vlan ranges in setlink 
and dellink requests")
+So reintroduce the vlan range check.
+Before patch:
+[root@testvm ~]# bridge vlan add vid 0 dev eth0 master
+(succeeds)
+After Patch:
+[root@testvm ~]# bridge vlan add vid 0 dev eth0 master
+RTNETLINK answers: Invalid argument
+
+Signed-off-by: Nikolay Aleksandrov <niko...@cumulusnetworks.com>
+Fixes: bdced7ef7838 ("bridge: support for multiple vlans and vlan ranges in 
setlink and dellink requests")
+Acked-by: Toshiaki Makita <toshiaki.maki...@gmail.com>
+---
+ net/bridge/br_netlink.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
+index 6b67ed3831de..364bdc98bd9b 100644
+--- a/net/bridge/br_netlink.c
++++ b/net/bridge/br_netlink.c
+@@ -457,6 +457,8 @@ static int br_afspec(struct net_bridge *br,
+               if (nla_len(attr) != sizeof(struct bridge_vlan_info))
+                       return -EINVAL;
+               vinfo = nla_data(attr);
++              if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
++                      return -EINVAL;
+               if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+                       if (vinfo_start)
+                               return -EINVAL;
-- 
2.1.4

_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to