diff options
Diffstat (limited to 'net/bridge/br_netlink.c')
-rw-r--r-- | net/bridge/br_netlink.c | 247 |
1 files changed, 217 insertions, 30 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 5dc66abcc9e2..27aa3ee517ce 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <net/rtnetlink.h> | 16 | #include <net/rtnetlink.h> |
17 | #include <net/net_namespace.h> | 17 | #include <net/net_namespace.h> |
18 | #include <net/sock.h> | 18 | #include <net/sock.h> |
19 | #include <uapi/linux/if_bridge.h> | ||
19 | 20 | ||
20 | #include "br_private.h" | 21 | #include "br_private.h" |
21 | #include "br_private_stp.h" | 22 | #include "br_private_stp.h" |
@@ -64,15 +65,21 @@ static int br_port_fill_attrs(struct sk_buff *skb, | |||
64 | * Create one netlink message for one interface | 65 | * Create one netlink message for one interface |
65 | * Contains port and master info as well as carrier and bridge state. | 66 | * Contains port and master info as well as carrier and bridge state. |
66 | */ | 67 | */ |
67 | static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *port, | 68 | static int br_fill_ifinfo(struct sk_buff *skb, |
68 | u32 pid, u32 seq, int event, unsigned int flags) | 69 | const struct net_bridge_port *port, |
70 | u32 pid, u32 seq, int event, unsigned int flags, | ||
71 | u32 filter_mask, const struct net_device *dev) | ||
69 | { | 72 | { |
70 | const struct net_bridge *br = port->br; | 73 | const struct net_bridge *br; |
71 | const struct net_device *dev = port->dev; | ||
72 | struct ifinfomsg *hdr; | 74 | struct ifinfomsg *hdr; |
73 | struct nlmsghdr *nlh; | 75 | struct nlmsghdr *nlh; |
74 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; | 76 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; |
75 | 77 | ||
78 | if (port) | ||
79 | br = port->br; | ||
80 | else | ||
81 | br = netdev_priv(dev); | ||
82 | |||
76 | br_debug(br, "br_fill_info event %d port %s master %s\n", | 83 | br_debug(br, "br_fill_info event %d port %s master %s\n", |
77 | event, dev->name, br->dev->name); | 84 | event, dev->name, br->dev->name); |
78 | 85 | ||
@@ -98,7 +105,7 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por | |||
98 | nla_put_u32(skb, IFLA_LINK, dev->iflink))) | 105 | nla_put_u32(skb, IFLA_LINK, dev->iflink))) |
99 | goto nla_put_failure; | 106 | goto nla_put_failure; |
100 | 107 | ||
101 | if (event == RTM_NEWLINK) { | 108 | if (event == RTM_NEWLINK && port) { |
102 | struct nlattr *nest | 109 | struct nlattr *nest |
103 | = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); | 110 | = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); |
104 | 111 | ||
@@ -107,6 +114,48 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por | |||
107 | nla_nest_end(skb, nest); | 114 | nla_nest_end(skb, nest); |
108 | } | 115 | } |
109 | 116 | ||
117 | /* Check if the VID information is requested */ | ||
118 | if (filter_mask & RTEXT_FILTER_BRVLAN) { | ||
119 | struct nlattr *af; | ||
120 | const struct net_port_vlans *pv; | ||
121 | struct bridge_vlan_info vinfo; | ||
122 | u16 vid; | ||
123 | u16 pvid; | ||
124 | |||
125 | if (port) | ||
126 | pv = nbp_get_vlan_info(port); | ||
127 | else | ||
128 | pv = br_get_vlan_info(br); | ||
129 | |||
130 | if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN)) | ||
131 | goto done; | ||
132 | |||
133 | af = nla_nest_start(skb, IFLA_AF_SPEC); | ||
134 | if (!af) | ||
135 | goto nla_put_failure; | ||
136 | |||
137 | pvid = br_get_pvid(pv); | ||
138 | for (vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN); | ||
139 | vid < BR_VLAN_BITMAP_LEN; | ||
140 | vid = find_next_bit(pv->vlan_bitmap, | ||
141 | BR_VLAN_BITMAP_LEN, vid+1)) { | ||
142 | vinfo.vid = vid; | ||
143 | vinfo.flags = 0; | ||
144 | if (vid == pvid) | ||
145 | vinfo.flags |= BRIDGE_VLAN_INFO_PVID; | ||
146 | |||
147 | if (test_bit(vid, pv->untagged_bitmap)) | ||
148 | vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; | ||
149 | |||
150 | if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO, | ||
151 | sizeof(vinfo), &vinfo)) | ||
152 | goto nla_put_failure; | ||
153 | } | ||
154 | |||
155 | nla_nest_end(skb, af); | ||
156 | } | ||
157 | |||
158 | done: | ||
110 | return nlmsg_end(skb, nlh); | 159 | return nlmsg_end(skb, nlh); |
111 | 160 | ||
112 | nla_put_failure: | 161 | nla_put_failure: |
@@ -119,10 +168,14 @@ nla_put_failure: | |||
119 | */ | 168 | */ |
120 | void br_ifinfo_notify(int event, struct net_bridge_port *port) | 169 | void br_ifinfo_notify(int event, struct net_bridge_port *port) |
121 | { | 170 | { |
122 | struct net *net = dev_net(port->dev); | 171 | struct net *net; |
123 | struct sk_buff *skb; | 172 | struct sk_buff *skb; |
124 | int err = -ENOBUFS; | 173 | int err = -ENOBUFS; |
125 | 174 | ||
175 | if (!port) | ||
176 | return; | ||
177 | |||
178 | net = dev_net(port->dev); | ||
126 | br_debug(port->br, "port %u(%s) event %d\n", | 179 | br_debug(port->br, "port %u(%s) event %d\n", |
127 | (unsigned int)port->port_no, port->dev->name, event); | 180 | (unsigned int)port->port_no, port->dev->name, event); |
128 | 181 | ||
@@ -130,7 +183,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port) | |||
130 | if (skb == NULL) | 183 | if (skb == NULL) |
131 | goto errout; | 184 | goto errout; |
132 | 185 | ||
133 | err = br_fill_ifinfo(skb, port, 0, 0, event, 0); | 186 | err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 0, port->dev); |
134 | if (err < 0) { | 187 | if (err < 0) { |
135 | /* -EMSGSIZE implies BUG in br_nlmsg_size() */ | 188 | /* -EMSGSIZE implies BUG in br_nlmsg_size() */ |
136 | WARN_ON(err == -EMSGSIZE); | 189 | WARN_ON(err == -EMSGSIZE); |
@@ -144,24 +197,85 @@ errout: | |||
144 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); | 197 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); |
145 | } | 198 | } |
146 | 199 | ||
200 | |||
147 | /* | 201 | /* |
148 | * Dump information about all ports, in response to GETLINK | 202 | * Dump information about all ports, in response to GETLINK |
149 | */ | 203 | */ |
150 | int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, | 204 | int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, |
151 | struct net_device *dev) | 205 | struct net_device *dev, u32 filter_mask) |
152 | { | 206 | { |
153 | int err = 0; | 207 | int err = 0; |
154 | struct net_bridge_port *port = br_port_get_rcu(dev); | 208 | struct net_bridge_port *port = br_port_get_rcu(dev); |
155 | 209 | ||
156 | /* not a bridge port */ | 210 | /* not a bridge port and */ |
157 | if (!port) | 211 | if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN)) |
158 | goto out; | 212 | goto out; |
159 | 213 | ||
160 | err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI); | 214 | err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI, |
215 | filter_mask, dev); | ||
161 | out: | 216 | out: |
162 | return err; | 217 | return err; |
163 | } | 218 | } |
164 | 219 | ||
220 | static const struct nla_policy ifla_br_policy[IFLA_MAX+1] = { | ||
221 | [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 }, | ||
222 | [IFLA_BRIDGE_MODE] = { .type = NLA_U16 }, | ||
223 | [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY, | ||
224 | .len = sizeof(struct bridge_vlan_info), }, | ||
225 | }; | ||
226 | |||
227 | static int br_afspec(struct net_bridge *br, | ||
228 | struct net_bridge_port *p, | ||
229 | struct nlattr *af_spec, | ||
230 | int cmd) | ||
231 | { | ||
232 | struct nlattr *tb[IFLA_BRIDGE_MAX+1]; | ||
233 | int err = 0; | ||
234 | |||
235 | err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy); | ||
236 | if (err) | ||
237 | return err; | ||
238 | |||
239 | if (tb[IFLA_BRIDGE_VLAN_INFO]) { | ||
240 | struct bridge_vlan_info *vinfo; | ||
241 | |||
242 | vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); | ||
243 | |||
244 | if (vinfo->vid >= VLAN_N_VID) | ||
245 | return -EINVAL; | ||
246 | |||
247 | switch (cmd) { | ||
248 | case RTM_SETLINK: | ||
249 | if (p) { | ||
250 | err = nbp_vlan_add(p, vinfo->vid, vinfo->flags); | ||
251 | if (err) | ||
252 | break; | ||
253 | |||
254 | if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) | ||
255 | err = br_vlan_add(p->br, vinfo->vid, | ||
256 | vinfo->flags); | ||
257 | } else | ||
258 | err = br_vlan_add(br, vinfo->vid, vinfo->flags); | ||
259 | |||
260 | if (err) | ||
261 | break; | ||
262 | |||
263 | break; | ||
264 | |||
265 | case RTM_DELLINK: | ||
266 | if (p) { | ||
267 | nbp_vlan_delete(p, vinfo->vid); | ||
268 | if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) | ||
269 | br_vlan_delete(p->br, vinfo->vid); | ||
270 | } else | ||
271 | br_vlan_delete(br, vinfo->vid); | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | return err; | ||
277 | } | ||
278 | |||
165 | static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { | 279 | static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { |
166 | [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, | 280 | [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, |
167 | [IFLA_BRPORT_COST] = { .type = NLA_U32 }, | 281 | [IFLA_BRPORT_COST] = { .type = NLA_U32 }, |
@@ -181,8 +295,11 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state) | |||
181 | if (p->br->stp_enabled == BR_KERNEL_STP) | 295 | if (p->br->stp_enabled == BR_KERNEL_STP) |
182 | return -EBUSY; | 296 | return -EBUSY; |
183 | 297 | ||
298 | /* if device is not up, change is not allowed | ||
299 | * if link is not present, only allowable state is disabled | ||
300 | */ | ||
184 | if (!netif_running(p->dev) || | 301 | if (!netif_running(p->dev) || |
185 | (!netif_carrier_ok(p->dev) && state != BR_STATE_DISABLED)) | 302 | (!netif_oper_up(p->dev) && state != BR_STATE_DISABLED)) |
186 | return -ENETDOWN; | 303 | return -ENETDOWN; |
187 | 304 | ||
188 | p->state = state; | 305 | p->state = state; |
@@ -238,6 +355,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) | |||
238 | { | 355 | { |
239 | struct ifinfomsg *ifm; | 356 | struct ifinfomsg *ifm; |
240 | struct nlattr *protinfo; | 357 | struct nlattr *protinfo; |
358 | struct nlattr *afspec; | ||
241 | struct net_bridge_port *p; | 359 | struct net_bridge_port *p; |
242 | struct nlattr *tb[IFLA_BRPORT_MAX + 1]; | 360 | struct nlattr *tb[IFLA_BRPORT_MAX + 1]; |
243 | int err; | 361 | int err; |
@@ -245,38 +363,76 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) | |||
245 | ifm = nlmsg_data(nlh); | 363 | ifm = nlmsg_data(nlh); |
246 | 364 | ||
247 | protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); | 365 | protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); |
248 | if (!protinfo) | 366 | afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC); |
367 | if (!protinfo && !afspec) | ||
249 | return 0; | 368 | return 0; |
250 | 369 | ||
251 | p = br_port_get_rtnl(dev); | 370 | p = br_port_get_rtnl(dev); |
252 | if (!p) | 371 | /* We want to accept dev as bridge itself if the AF_SPEC |
372 | * is set to see if someone is setting vlan info on the brigde | ||
373 | */ | ||
374 | if (!p && ((dev->priv_flags & IFF_EBRIDGE) && !afspec)) | ||
253 | return -EINVAL; | 375 | return -EINVAL; |
254 | 376 | ||
255 | if (protinfo->nla_type & NLA_F_NESTED) { | 377 | if (p && protinfo) { |
256 | err = nla_parse_nested(tb, IFLA_BRPORT_MAX, | 378 | if (protinfo->nla_type & NLA_F_NESTED) { |
257 | protinfo, ifla_brport_policy); | 379 | err = nla_parse_nested(tb, IFLA_BRPORT_MAX, |
380 | protinfo, ifla_brport_policy); | ||
381 | if (err) | ||
382 | return err; | ||
383 | |||
384 | spin_lock_bh(&p->br->lock); | ||
385 | err = br_setport(p, tb); | ||
386 | spin_unlock_bh(&p->br->lock); | ||
387 | } else { | ||
388 | /* Binary compatability with old RSTP */ | ||
389 | if (nla_len(protinfo) < sizeof(u8)) | ||
390 | return -EINVAL; | ||
391 | |||
392 | spin_lock_bh(&p->br->lock); | ||
393 | err = br_set_port_state(p, nla_get_u8(protinfo)); | ||
394 | spin_unlock_bh(&p->br->lock); | ||
395 | } | ||
258 | if (err) | 396 | if (err) |
259 | return err; | 397 | goto out; |
260 | 398 | } | |
261 | spin_lock_bh(&p->br->lock); | ||
262 | err = br_setport(p, tb); | ||
263 | spin_unlock_bh(&p->br->lock); | ||
264 | } else { | ||
265 | /* Binary compatability with old RSTP */ | ||
266 | if (nla_len(protinfo) < sizeof(u8)) | ||
267 | return -EINVAL; | ||
268 | 399 | ||
269 | spin_lock_bh(&p->br->lock); | 400 | if (afspec) { |
270 | err = br_set_port_state(p, nla_get_u8(protinfo)); | 401 | err = br_afspec((struct net_bridge *)netdev_priv(dev), p, |
271 | spin_unlock_bh(&p->br->lock); | 402 | afspec, RTM_SETLINK); |
272 | } | 403 | } |
273 | 404 | ||
274 | if (err == 0) | 405 | if (err == 0) |
275 | br_ifinfo_notify(RTM_NEWLINK, p); | 406 | br_ifinfo_notify(RTM_NEWLINK, p); |
276 | 407 | ||
408 | out: | ||
277 | return err; | 409 | return err; |
278 | } | 410 | } |
279 | 411 | ||
412 | /* Delete port information */ | ||
413 | int br_dellink(struct net_device *dev, struct nlmsghdr *nlh) | ||
414 | { | ||
415 | struct ifinfomsg *ifm; | ||
416 | struct nlattr *afspec; | ||
417 | struct net_bridge_port *p; | ||
418 | int err; | ||
419 | |||
420 | ifm = nlmsg_data(nlh); | ||
421 | |||
422 | afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC); | ||
423 | if (!afspec) | ||
424 | return 0; | ||
425 | |||
426 | p = br_port_get_rtnl(dev); | ||
427 | /* We want to accept dev as bridge itself as well */ | ||
428 | if (!p && !(dev->priv_flags & IFF_EBRIDGE)) | ||
429 | return -EINVAL; | ||
430 | |||
431 | err = br_afspec((struct net_bridge *)netdev_priv(dev), p, | ||
432 | afspec, RTM_DELLINK); | ||
433 | |||
434 | return err; | ||
435 | } | ||
280 | static int br_validate(struct nlattr *tb[], struct nlattr *data[]) | 436 | static int br_validate(struct nlattr *tb[], struct nlattr *data[]) |
281 | { | 437 | { |
282 | if (tb[IFLA_ADDRESS]) { | 438 | if (tb[IFLA_ADDRESS]) { |
@@ -289,6 +445,29 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
289 | return 0; | 445 | return 0; |
290 | } | 446 | } |
291 | 447 | ||
448 | static size_t br_get_link_af_size(const struct net_device *dev) | ||
449 | { | ||
450 | struct net_port_vlans *pv; | ||
451 | |||
452 | if (br_port_exists(dev)) | ||
453 | pv = nbp_get_vlan_info(br_port_get_rcu(dev)); | ||
454 | else if (dev->priv_flags & IFF_EBRIDGE) | ||
455 | pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev)); | ||
456 | else | ||
457 | return 0; | ||
458 | |||
459 | if (!pv) | ||
460 | return 0; | ||
461 | |||
462 | /* Each VLAN is returned in bridge_vlan_info along with flags */ | ||
463 | return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info)); | ||
464 | } | ||
465 | |||
466 | static struct rtnl_af_ops br_af_ops = { | ||
467 | .family = AF_BRIDGE, | ||
468 | .get_link_af_size = br_get_link_af_size, | ||
469 | }; | ||
470 | |||
292 | struct rtnl_link_ops br_link_ops __read_mostly = { | 471 | struct rtnl_link_ops br_link_ops __read_mostly = { |
293 | .kind = "bridge", | 472 | .kind = "bridge", |
294 | .priv_size = sizeof(struct net_bridge), | 473 | .priv_size = sizeof(struct net_bridge), |
@@ -302,11 +481,18 @@ int __init br_netlink_init(void) | |||
302 | int err; | 481 | int err; |
303 | 482 | ||
304 | br_mdb_init(); | 483 | br_mdb_init(); |
305 | err = rtnl_link_register(&br_link_ops); | 484 | err = rtnl_af_register(&br_af_ops); |
306 | if (err) | 485 | if (err) |
307 | goto out; | 486 | goto out; |
308 | 487 | ||
488 | err = rtnl_link_register(&br_link_ops); | ||
489 | if (err) | ||
490 | goto out_af; | ||
491 | |||
309 | return 0; | 492 | return 0; |
493 | |||
494 | out_af: | ||
495 | rtnl_af_unregister(&br_af_ops); | ||
310 | out: | 496 | out: |
311 | br_mdb_uninit(); | 497 | br_mdb_uninit(); |
312 | return err; | 498 | return err; |
@@ -315,5 +501,6 @@ out: | |||
315 | void __exit br_netlink_fini(void) | 501 | void __exit br_netlink_fini(void) |
316 | { | 502 | { |
317 | br_mdb_uninit(); | 503 | br_mdb_uninit(); |
504 | rtnl_af_unregister(&br_af_ops); | ||
318 | rtnl_link_unregister(&br_link_ops); | 505 | rtnl_link_unregister(&br_link_ops); |
319 | } | 506 | } |