[pve-devel] [PATCH] add bridge-vlanrage patches.

Alexandre Derumier aderumier at odiso.com
Fri Jul 24 09:50:39 CEST 2015


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 <aderumier at 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 <roopa at 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 <roopa at cumulusnetworks.com>
+Signed-off-by: David S. Miller <davem at 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 <roopa at 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 <roopa at cumulusnetworks.com>
+Signed-off-by: David S. Miller <davem at 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 <roopa at 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 <roopa at cumulusnetworks.com>
+Signed-off-by: David S. Miller <davem at 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 <nikolay at cumulusnetworks.com>
+X-Patchwork-Id: 490608
+Message-Id: <1435841297-44200-1-git-send-email-nikolay at cumulusnetworks.com>
+To: netdev at vger.kernel.org
+Cc: vyasevich at gmail.com, bridge at lists.linux-foundation.org,
+ davem at davemloft.net, toshiaki.makita1 at gmail.com,
+ stephen at networkplumber.org, roopa at cumulusnetworks.com,
+ Nikolay Aleksandrov <nikolay at 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 at testvm ~]# bridge vlan add vid 0 dev eth0 master
+(succeeds)
+After Patch:
+[root at testvm ~]# bridge vlan add vid 0 dev eth0 master
+RTNETLINK answers: Invalid argument
+
+Signed-off-by: Nikolay Aleksandrov <nikolay at cumulusnetworks.com>
+Fixes: bdced7ef7838 ("bridge: support for multiple vlans and vlan ranges in setlink and dellink requests")
+Acked-by: Toshiaki Makita <toshiaki.makita1 at 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




More information about the pve-devel mailing list