aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopa Prabhu <roopa@cumulusnetworks.com>2015-01-10 10:31:12 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-12 16:47:04 -0500
commitbdced7ef7838c1c4aebe9f295e44b7f0dcae2109 (patch)
tree085509e3c66585999c7b2fd10612b34bf8eaafb3
parentdd2e8bf586a69b824e50d50a5bbc16ed38f50986 (diff)
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@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/if_bridge.h2
-rw-r--r--net/bridge/br_netlink.c104
2 files changed, 70 insertions, 36 deletions
diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index b03ee8f62d3c..eaaea6208b42 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -125,6 +125,8 @@ enum {
125#define BRIDGE_VLAN_INFO_MASTER (1<<0) /* Operate on Bridge device as well */ 125#define BRIDGE_VLAN_INFO_MASTER (1<<0) /* Operate on Bridge device as well */
126#define BRIDGE_VLAN_INFO_PVID (1<<1) /* VLAN is PVID, ingress untagged */ 126#define BRIDGE_VLAN_INFO_PVID (1<<1) /* VLAN is PVID, ingress untagged */
127#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2) /* VLAN egresses untagged */ 127#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2) /* VLAN egresses untagged */
128#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
129#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
128 130
129struct bridge_vlan_info { 131struct bridge_vlan_info {
130 __u16 flags; 132 __u16 flags;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 9f5eb55a4d3a..6f616a2df0b4 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -218,57 +218,89 @@ out:
218 return err; 218 return err;
219} 219}
220 220
221static const struct nla_policy ifla_br_policy[IFLA_MAX+1] = { 221static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
222 [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 }, 222 int cmd, struct bridge_vlan_info *vinfo)
223 [IFLA_BRIDGE_MODE] = { .type = NLA_U16 }, 223{
224 [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY, 224 int err = 0;
225 .len = sizeof(struct bridge_vlan_info), }, 225
226}; 226 switch (cmd) {
227 case RTM_SETLINK:
228 if (p) {
229 err = nbp_vlan_add(p, vinfo->vid, vinfo->flags);
230 if (err)
231 break;
232
233 if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
234 err = br_vlan_add(p->br, vinfo->vid,
235 vinfo->flags);
236 } else {
237 err = br_vlan_add(br, vinfo->vid, vinfo->flags);
238 }
239 break;
240
241 case RTM_DELLINK:
242 if (p) {
243 nbp_vlan_delete(p, vinfo->vid);
244 if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
245 br_vlan_delete(p->br, vinfo->vid);
246 } else {
247 br_vlan_delete(br, vinfo->vid);
248 }
249 break;
250 }
251
252 return err;
253}
227 254
228static int br_afspec(struct net_bridge *br, 255static int br_afspec(struct net_bridge *br,
229 struct net_bridge_port *p, 256 struct net_bridge_port *p,
230 struct nlattr *af_spec, 257 struct nlattr *af_spec,
231 int cmd) 258 int cmd)
232{ 259{
233 struct nlattr *tb[IFLA_BRIDGE_MAX+1]; 260 struct bridge_vlan_info *vinfo_start = NULL;
261 struct bridge_vlan_info *vinfo = NULL;
262 struct nlattr *attr;
234 int err = 0; 263 int err = 0;
264 int rem;
235 265
236 err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy); 266 nla_for_each_nested(attr, af_spec, rem) {
237 if (err) 267 if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
238 return err; 268 continue;
269 if (nla_len(attr) != sizeof(struct bridge_vlan_info))
270 return -EINVAL;
271 vinfo = nla_data(attr);
272 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
273 if (vinfo_start)
274 return -EINVAL;
275 vinfo_start = vinfo;
276 continue;
277 }
278
279 if (vinfo_start) {
280 struct bridge_vlan_info tmp_vinfo;
281 int v;
239 282
240 if (tb[IFLA_BRIDGE_VLAN_INFO]) { 283 if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
241 struct bridge_vlan_info *vinfo; 284 return -EINVAL;
242 285
243 vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); 286 if (vinfo->vid <= vinfo_start->vid)
287 return -EINVAL;
244 288
245 if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK) 289 memcpy(&tmp_vinfo, vinfo_start,
246 return -EINVAL; 290 sizeof(struct bridge_vlan_info));
247 291
248 switch (cmd) { 292 for (v = vinfo_start->vid; v <= vinfo->vid; v++) {
249 case RTM_SETLINK: 293 tmp_vinfo.vid = v;
250 if (p) { 294 err = br_vlan_info(br, p, cmd, &tmp_vinfo);
251 err = nbp_vlan_add(p, vinfo->vid, vinfo->flags);
252 if (err) 295 if (err)
253 break; 296 break;
254 297 }
255 if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) 298 vinfo_start = NULL;
256 err = br_vlan_add(p->br, vinfo->vid, 299 } else {
257 vinfo->flags); 300 err = br_vlan_info(br, p, cmd, vinfo);
258 } else
259 err = br_vlan_add(br, vinfo->vid, vinfo->flags);
260
261 break;
262
263 case RTM_DELLINK:
264 if (p) {
265 nbp_vlan_delete(p, vinfo->vid);
266 if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
267 br_vlan_delete(p->br, vinfo->vid);
268 } else
269 br_vlan_delete(br, vinfo->vid);
270 break;
271 } 301 }
302 if (err)
303 break;
272 } 304 }
273 305
274 return err; 306 return err;