Commit 36cd0ffb authored by Roopa Prabhu's avatar Roopa Prabhu Committed by David S. Miller

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: default avatarRoopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 35a27cee
...@@ -67,6 +67,118 @@ static int br_port_fill_attrs(struct sk_buff *skb, ...@@ -67,6 +67,118 @@ static int br_port_fill_attrs(struct sk_buff *skb,
return 0; 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 * Create one netlink message for one interface
* Contains port and master info as well as carrier and bridge state. * 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, ...@@ -121,12 +233,11 @@ static int br_fill_ifinfo(struct sk_buff *skb,
} }
/* Check if the VID information is requested */ /* Check if the VID information is requested */
if (filter_mask & RTEXT_FILTER_BRVLAN) { if ((filter_mask & RTEXT_FILTER_BRVLAN) ||
struct nlattr *af; (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) {
const struct net_port_vlans *pv; const struct net_port_vlans *pv;
struct bridge_vlan_info vinfo; struct nlattr *af;
u16 vid; int err;
u16 pvid;
if (port) if (port)
pv = nbp_get_vlan_info(port); pv = nbp_get_vlan_info(port);
...@@ -140,21 +251,12 @@ static int br_fill_ifinfo(struct sk_buff *skb, ...@@ -140,21 +251,12 @@ static int br_fill_ifinfo(struct sk_buff *skb,
if (!af) if (!af)
goto nla_put_failure; goto nla_put_failure;
pvid = br_get_pvid(pv); if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) { err = br_fill_ifvlaninfo_compressed(skb, pv);
vinfo.vid = vid; else
vinfo.flags = 0; err = br_fill_ifvlaninfo(skb, pv);
if (vid == pvid) if (err)
vinfo.flags |= BRIDGE_VLAN_INFO_PVID; goto nla_put_failure;
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;
}
nla_nest_end(skb, af); nla_nest_end(skb, af);
} }
...@@ -209,7 +311,8 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, ...@@ -209,7 +311,8 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
int err = 0; int err = 0;
struct net_bridge_port *port = br_port_get_rtnl(dev); 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; goto out;
err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI, err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment