Thread (6 messages) 6 messages, 2 authors, 2015-01-01

Re: [PATCH 5/6] bridge: new function to pack vlans using both IFLA_BRIDGE_VLAN_INFO and IFLA_BRIDGE_VLAN_RANGE_INFO

From: Scott Feldman <hidden>
Date: 2014-12-29 23:25:49

On Mon, Dec 29, 2014 at 1:05 PM,  [off-list ref] wrote:
quoted hunk ↗ jump to hunk
From: Roopa Prabhu <redacted>

This patch adds new function to compress vlans into ranges.
Vlans are compressed into ranges only if the fill request is called with
RTEXT_FILTER_BRVLAN_COMPRESSED in filtermask.

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: Wilson kok <redacted>
Signed-off-by: Roopa Prabhu <redacted>
---
 net/bridge/br_netlink.c |  157 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 137 insertions(+), 20 deletions(-)
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 4c47ba0..16bdd5a 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -67,6 +67,133 @@ static int br_port_fill_attrs(struct sk_buff *skb,
        return 0;
 }

+static int br_fill_ifvlaninfo_bitmap(struct sk_buff *skb,
+                                    const unsigned long *vlan_bmp, u16 flags)
+{
+       struct bridge_vlan_range_info vinfo_range;
+       struct bridge_vlan_info vinfo;
+       u16 vid, start = 0, end = 0;
One per line?
+       u16 pvid;
Aren't you getting an "unused" compile warning on this ^^^?
+
+       /* handle the untagged */
This comment ^^^ doesn't make sense here.
+       for_each_set_bit(vid, vlan_bmp, VLAN_N_VID) {
+               if (start == 0) {
+                       start = vid;
+                       end = vid;
+               }
+               if ((vid - end) > 1) {
+                       memset(&vinfo_range, 0, sizeof(vinfo_range));
+                       vinfo_range.flags |= flags;
+                       vinfo_range.vid = start;
+                       vinfo_range.vid_end = end;
+                       if (nla_put(skb, IFLA_BRIDGE_VLAN_RANGE_INFO,
+                                   sizeof(vinfo_range), &vinfo_range))
+                               goto nla_put_failure;
+                       start = vid;
+                       end = vid;
+               } else {
+                       end = vid;
+               }
+       }
What happens with this set {1-10, 12, 20-25, 30}?  On vid 12, will
that put a VLAN_RANGE_INFO with start=end=12?  Seems strange to use
RANGE_INFO for single vlan.

Can the algorithm be simplified?  Maybe there are other examples in
the kernel of finding ranges/singles from a bitmap we could borrow
code from?
+       if (start != 0 && end != 0) {
+               if (start != end) {
+                       memset(&vinfo_range, 0, sizeof(vinfo_range));
+                       vinfo_range.flags |= flags;
+                       vinfo_range.vid = start;
+                       vinfo_range.vid_end = end;
+                       if (nla_put(skb, IFLA_BRIDGE_VLAN_RANGE_INFO,
+                                   sizeof(vinfo_range), &vinfo_range))
+                               goto nla_put_failure;
+               } else {
+                       memset(&vinfo, 0, sizeof(vinfo));
+                       vinfo.flags |= flags;
+                       vinfo.vid = start;
+                       if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
+                                   sizeof(vinfo), &vinfo))
+                               goto nla_put_failure;
How many IFLA_BRIDGE_VLAN_INFOs can you fit into skb?   It seems the
worst case is you'll have 4094/2 = 2047 VLAN_INFOs if using all
even-numbered vids, for example.  Will that fit?  I guess the original
code had the same concern...wonder if anyone checked this worst-case?
+               }
+       }
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
+                                        const struct net_port_vlans *pv)
+{
+       unsigned long vlan_bmp_copy[BR_VLAN_BITMAP_LEN];
+       unsigned long untagged_bmp_copy[BR_VLAN_BITMAP_LEN];
Lots of automatic space on the stack...can you use dynamic mem
(kzalloc) for these?
+       struct bridge_vlan_range_info vinfo_range;
+       struct bridge_vlan_info vinfo;
+       u16 pvid;
+
+       memset(vlan_bmp_copy, 0,
+              sizeof(unsigned long) * BR_VLAN_BITMAP_LEN);
+       bitmap_copy(vlan_bmp_copy, pv->vlan_bitmap, VLAN_N_VID);
+
+       memset(untagged_bmp_copy, 0,
+              sizeof(unsigned long) * BR_VLAN_BITMAP_LEN);
+       bitmap_copy(untagged_bmp_copy, pv->untagged_bitmap, VLAN_N_VID);
+
+       /* send the pvid separately first */
+       pvid = br_get_pvid(pv);
+       if (pvid && (pvid != VLAN_N_VID)) {
+               memset(&vinfo, 0, sizeof(vinfo));
+               vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
+               if (test_bit(pvid, untagged_bmp_copy)) {
+                       vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+                       clear_bit(pvid, untagged_bmp_copy);
+               }
+               clear_bit(pvid, vlan_bmp_copy);
+               vinfo.vid = pvid;
+               if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
+                           sizeof(vinfo), &vinfo))
+                       goto nla_put_failure;
+       }
What if pvid is not in vlan_bmp_copy?  This statement block seems
slightly different than the original logic where BRIDGE_VLAN_INFO_PVID
was set only when looping thru vlan_bitmap and vid == pvid.  Now can
you send a IFLA_BRIDGE_VLAN_INFO with pvid even if pvid isn't in
vlan_bitmap?  Maybe pvid is always in vlan_bitmap, so it doesn't
matter.  But there is a subtle logic change here, so something to
consider.
+
+       /* fill untagged vlans */
+       br_fill_ifvlaninfo_bitmap(skb, untagged_bmp_copy,
+                                 BRIDGE_VLAN_INFO_UNTAGGED);
This might be doing more than original logic.  Original logic looped
thru vid in vlan_btimap and checked if vid was in untagged_bitmap.
Here you're dumping all bits in untagged_bitmap, without looking if
bit was set in vlan_bitmap.  Maybe you want to do an intersection of
sets vlan_bitmap and untagged_bitmap.
quoted hunk ↗ jump to hunk
+       for_each_set_bit(vid, untagged_bmp_copy, VLAN_N_VID)
+               clear_bit(vid, vlan_bmp_copy);
+
+       /* fill tagged vlans */
+       br_fill_ifvlaninfo_bitmap(skb, vlan_bmp_copy, 0);
+
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+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 +248,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 +266,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);
        }

--
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help