[PATCH 2/2] route/link: handle RTEXT_FILTER_BRVLAN_COMPRESSED

Tobias Jungel tobias.jungel at bisdn.de
Thu Nov 26 07:47:58 PST 2015


notifications from the kernel regarding vlan ids are now handled
---
 lib/route/link.c        | 12 +++-----
 lib/route/link/bridge.c | 82 ++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 78 insertions(+), 16 deletions(-)

diff --git a/lib/route/link.c b/lib/route/link.c
index 5ccf629..31381ae 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -523,20 +523,16 @@ errout:
 static int parse_af_spec_bridge(struct rtnl_link *link, struct nlattr *attr)
 {
 	struct rtnl_link_af_ops *af_ops;
-	struct nlattr *af_attr;
 	char *af_data;
-	int remaining;
 	int err = 0;
 
 	af_ops = af_lookup_and_alloc(link, AF_BRIDGE);
 	af_data = link->l_af_data[AF_BRIDGE];
 
-	if (af_ops && af_ops->ao_parse_af) {
-		nla_for_each_nested(af_attr, attr, remaining) {
-			err = af_ops->ao_parse_af(link, af_attr, af_data);
-			if (err < 0)
-				goto errout;
-		}
+	if (af_ops && af_ops->ao_parse_af_full) {
+		err = af_ops->ao_parse_af_full(link, attr, af_data);
+		if (err < 0)
+			goto errout;
 	}
 
 	link->ce_mask |= LINK_ATTR_AF_SPEC;
diff --git a/lib/route/link/bridge.c b/lib/route/link/bridge.c
index 9510fde..f4243b1 100644
--- a/lib/route/link/bridge.c
+++ b/lib/route/link/bridge.c
@@ -190,6 +190,58 @@ static int bridge_parse_af(struct rtnl_link *link, struct nlattr *attr,
 {
 	struct bridge_data *bd = data;
 	struct bridge_vlan_info *vinfo = NULL;
+	uint16_t vid_range_start = 0;
+	uint16_t vid_range_flags = -1;
+
+	struct nlattr *af_attr;
+	int remaining;
+
+	nla_for_each_nested(af_attr, attr, remaining) {
+
+		if (nla_type(af_attr) != IFLA_BRIDGE_VLAN_INFO)
+			continue;
+
+		if (nla_len(af_attr) != sizeof(struct bridge_vlan_info))
+			return -EINVAL;
+
+		vinfo = nla_data(af_attr);
+		if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
+			return -EINVAL;
+
+
+		if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+			vid_range_start = vinfo->vid;
+			vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN);
+			continue;
+		}
+
+		if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
+			/* sanity check the range flags */
+			if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) {
+				NL_DBG(1, "VLAN range flags differ; can not handle it.\n");
+				return -EINVAL;
+			}
+		} else {
+			vid_range_start = vinfo->vid;
+		}
+
+		for (; vid_range_start <= vinfo->vid; vid_range_start++) {
+			if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
+				bd->vlan_info.pvid = vinfo->vid;
+
+			if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
+				set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
+
+			set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
+			bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
+		}
+
+		vid_range_flags = -1;
+	}
+
+	return 0;
+
+
 
 	if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
 		return 0;
@@ -202,18 +254,32 @@ static int bridge_parse_af(struct rtnl_link *link, struct nlattr *attr,
 		return -EINVAL;
 
 	if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
-		NL_DBG(1, "Unexpected BRIDGE_VLAN_INFO_RANGE_BEGIN flag; can not handle it.\n");
-		return -EINVAL;
+		vid_range_start = vinfo->vid;
+		vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN);
+		return 0;
+	}
+
+	if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
+		/* sanity check the range flags */
+		if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) {
+			NL_DBG(1, "VLAN range flags differ; can not handle it.\n");
+			return -EINVAL;
+		}
+	} else {
+		vid_range_start = vinfo->vid;
 	}
 
-	if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
-		bd->vlan_info.pvid = vinfo->vid;
+	for (; vid_range_start <= vinfo->vid; vid_range_start++) {
+		if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
+			bd->vlan_info.pvid = vinfo->vid;
 
-	if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
-		set_bit(vinfo->vid, bd->vlan_info.untagged_bitmap);
+		if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
+			set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
 
-	set_bit(vinfo->vid, bd->vlan_info.vlan_bitmap);
+		set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
+	}
 
+	vid_range_flags = -1;
 	bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
 
 	return 0;
@@ -722,7 +788,7 @@ static struct rtnl_link_af_ops bridge_ops = {
 	.ao_parse_protinfo		= &bridge_parse_protinfo,
 	.ao_dump[NL_DUMP_DETAILS]	= &bridge_dump_details,
 	.ao_compare			= &bridge_compare,
-	.ao_parse_af			= &bridge_parse_af,
+	.ao_parse_af_full		= &bridge_parse_af,
 	.ao_get_af			= &bridge_get_af,
 };
 
-- 
2.5.0




More information about the libnl mailing list