aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_netlink.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /net/bridge/br_netlink.c
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'net/bridge/br_netlink.c')
-rw-r--r--net/bridge/br_netlink.c276
1 files changed, 108 insertions, 168 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 5dc66abcc9e..e5f9ece3c9a 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -18,46 +18,17 @@
18#include <net/sock.h> 18#include <net/sock.h>
19 19
20#include "br_private.h" 20#include "br_private.h"
21#include "br_private_stp.h"
22
23static inline size_t br_port_info_size(void)
24{
25 return nla_total_size(1) /* IFLA_BRPORT_STATE */
26 + nla_total_size(2) /* IFLA_BRPORT_PRIORITY */
27 + nla_total_size(4) /* IFLA_BRPORT_COST */
28 + nla_total_size(1) /* IFLA_BRPORT_MODE */
29 + nla_total_size(1) /* IFLA_BRPORT_GUARD */
30 + nla_total_size(1) /* IFLA_BRPORT_PROTECT */
31 + 0;
32}
33 21
34static inline size_t br_nlmsg_size(void) 22static inline size_t br_nlmsg_size(void)
35{ 23{
36 return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 24 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
37 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ 25 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
38 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ 26 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
39 + nla_total_size(4) /* IFLA_MASTER */ 27 + nla_total_size(4) /* IFLA_MASTER */
40 + nla_total_size(4) /* IFLA_MTU */ 28 + nla_total_size(4) /* IFLA_MTU */
41 + nla_total_size(4) /* IFLA_LINK */ 29 + nla_total_size(4) /* IFLA_LINK */
42 + nla_total_size(1) /* IFLA_OPERSTATE */ 30 + nla_total_size(1) /* IFLA_OPERSTATE */
43 + nla_total_size(br_port_info_size()); /* IFLA_PROTINFO */ 31 + nla_total_size(1); /* IFLA_PROTINFO */
44}
45
46static int br_port_fill_attrs(struct sk_buff *skb,
47 const struct net_bridge_port *p)
48{
49 u8 mode = !!(p->flags & BR_HAIRPIN_MODE);
50
51 if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) ||
52 nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) ||
53 nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) ||
54 nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
55 nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
56 nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) ||
57 nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)))
58 return -EMSGSIZE;
59
60 return 0;
61} 32}
62 33
63/* 34/*
@@ -88,24 +59,19 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
88 hdr->ifi_flags = dev_get_flags(dev); 59 hdr->ifi_flags = dev_get_flags(dev);
89 hdr->ifi_change = 0; 60 hdr->ifi_change = 0;
90 61
91 if (nla_put_string(skb, IFLA_IFNAME, dev->name) || 62 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
92 nla_put_u32(skb, IFLA_MASTER, br->dev->ifindex) || 63 NLA_PUT_U32(skb, IFLA_MASTER, br->dev->ifindex);
93 nla_put_u32(skb, IFLA_MTU, dev->mtu) || 64 NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
94 nla_put_u8(skb, IFLA_OPERSTATE, operstate) || 65 NLA_PUT_U8(skb, IFLA_OPERSTATE, operstate);
95 (dev->addr_len && 66
96 nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || 67 if (dev->addr_len)
97 (dev->ifindex != dev->iflink && 68 NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
98 nla_put_u32(skb, IFLA_LINK, dev->iflink))) 69
99 goto nla_put_failure; 70 if (dev->ifindex != dev->iflink)
100 71 NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
101 if (event == RTM_NEWLINK) { 72
102 struct nlattr *nest 73 if (event == RTM_NEWLINK)
103 = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); 74 NLA_PUT_U8(skb, IFLA_PROTINFO, port->state);
104
105 if (nest == NULL || br_port_fill_attrs(skb, port) < 0)
106 goto nla_put_failure;
107 nla_nest_end(skb, nest);
108 }
109 75
110 return nlmsg_end(skb, nlh); 76 return nlmsg_end(skb, nlh);
111 77
@@ -124,7 +90,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
124 int err = -ENOBUFS; 90 int err = -ENOBUFS;
125 91
126 br_debug(port->br, "port %u(%s) event %d\n", 92 br_debug(port->br, "port %u(%s) event %d\n",
127 (unsigned int)port->port_no, port->dev->name, event); 93 (unsigned)port->port_no, port->dev->name, event);
128 94
129 skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); 95 skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC);
130 if (skb == NULL) 96 if (skb == NULL)
@@ -147,134 +113,84 @@ errout:
147/* 113/*
148 * Dump information about all ports, in response to GETLINK 114 * Dump information about all ports, in response to GETLINK
149 */ 115 */
150int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, 116static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
151 struct net_device *dev)
152{
153 int err = 0;
154 struct net_bridge_port *port = br_port_get_rcu(dev);
155
156 /* not a bridge port */
157 if (!port)
158 goto out;
159
160 err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI);
161out:
162 return err;
163}
164
165static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
166 [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
167 [IFLA_BRPORT_COST] = { .type = NLA_U32 },
168 [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
169 [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
170 [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
171 [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
172};
173
174/* Change the state of the port and notify spanning tree */
175static int br_set_port_state(struct net_bridge_port *p, u8 state)
176{
177 if (state > BR_STATE_BLOCKING)
178 return -EINVAL;
179
180 /* if kernel STP is running, don't allow changes */
181 if (p->br->stp_enabled == BR_KERNEL_STP)
182 return -EBUSY;
183
184 if (!netif_running(p->dev) ||
185 (!netif_carrier_ok(p->dev) && state != BR_STATE_DISABLED))
186 return -ENETDOWN;
187
188 p->state = state;
189 br_log_state(p);
190 br_port_state_selection(p->br);
191 return 0;
192}
193
194/* Set/clear or port flags based on attribute */
195static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[],
196 int attrtype, unsigned long mask)
197{ 117{
198 if (tb[attrtype]) { 118 struct net *net = sock_net(skb->sk);
199 u8 flag = nla_get_u8(tb[attrtype]); 119 struct net_device *dev;
200 if (flag) 120 int idx;
201 p->flags |= mask; 121
202 else 122 idx = 0;
203 p->flags &= ~mask; 123 rcu_read_lock();
124 for_each_netdev_rcu(net, dev) {
125 struct net_bridge_port *port = br_port_get_rcu(dev);
126
127 /* not a bridge port */
128 if (!port || idx < cb->args[0])
129 goto skip;
130
131 if (br_fill_ifinfo(skb, port,
132 NETLINK_CB(cb->skb).pid,
133 cb->nlh->nlmsg_seq, RTM_NEWLINK,
134 NLM_F_MULTI) < 0)
135 break;
136skip:
137 ++idx;
204 } 138 }
205} 139 rcu_read_unlock();
140 cb->args[0] = idx;
206 141
207/* Process bridge protocol info on port */ 142 return skb->len;
208static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
209{
210 int err;
211
212 br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
213 br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD);
214 br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE);
215
216 if (tb[IFLA_BRPORT_COST]) {
217 err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
218 if (err)
219 return err;
220 }
221
222 if (tb[IFLA_BRPORT_PRIORITY]) {
223 err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY]));
224 if (err)
225 return err;
226 }
227
228 if (tb[IFLA_BRPORT_STATE]) {
229 err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE]));
230 if (err)
231 return err;
232 }
233 return 0;
234} 143}
235 144
236/* Change state and parameters on port. */ 145/*
237int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) 146 * Change state of port (ie from forwarding to blocking etc)
147 * Used by spanning tree in user space.
148 */
149static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
238{ 150{
151 struct net *net = sock_net(skb->sk);
239 struct ifinfomsg *ifm; 152 struct ifinfomsg *ifm;
240 struct nlattr *protinfo; 153 struct nlattr *protinfo;
154 struct net_device *dev;
241 struct net_bridge_port *p; 155 struct net_bridge_port *p;
242 struct nlattr *tb[IFLA_BRPORT_MAX + 1]; 156 u8 new_state;
243 int err; 157
158 if (nlmsg_len(nlh) < sizeof(*ifm))
159 return -EINVAL;
244 160
245 ifm = nlmsg_data(nlh); 161 ifm = nlmsg_data(nlh);
162 if (ifm->ifi_family != AF_BRIDGE)
163 return -EPFNOSUPPORT;
246 164
247 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); 165 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
248 if (!protinfo) 166 if (!protinfo || nla_len(protinfo) < sizeof(u8))
249 return 0; 167 return -EINVAL;
168
169 new_state = nla_get_u8(protinfo);
170 if (new_state > BR_STATE_BLOCKING)
171 return -EINVAL;
172
173 dev = __dev_get_by_index(net, ifm->ifi_index);
174 if (!dev)
175 return -ENODEV;
250 176
251 p = br_port_get_rtnl(dev); 177 p = br_port_get_rtnl(dev);
252 if (!p) 178 if (!p)
253 return -EINVAL; 179 return -EINVAL;
254 180
255 if (protinfo->nla_type & NLA_F_NESTED) { 181 /* if kernel STP is running, don't allow changes */
256 err = nla_parse_nested(tb, IFLA_BRPORT_MAX, 182 if (p->br->stp_enabled == BR_KERNEL_STP)
257 protinfo, ifla_brport_policy); 183 return -EBUSY;
258 if (err)
259 return err;
260
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 184
269 spin_lock_bh(&p->br->lock); 185 if (!netif_running(dev) ||
270 err = br_set_port_state(p, nla_get_u8(protinfo)); 186 (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
271 spin_unlock_bh(&p->br->lock); 187 return -ENETDOWN;
272 }
273 188
274 if (err == 0) 189 p->state = new_state;
275 br_ifinfo_notify(RTM_NEWLINK, p); 190 br_log_state(p);
191 br_ifinfo_notify(RTM_NEWLINK, p);
276 192
277 return err; 193 return 0;
278} 194}
279 195
280static int br_validate(struct nlattr *tb[], struct nlattr *data[]) 196static int br_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -289,7 +205,7 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[])
289 return 0; 205 return 0;
290} 206}
291 207
292struct rtnl_link_ops br_link_ops __read_mostly = { 208static struct rtnl_link_ops br_link_ops __read_mostly = {
293 .kind = "bridge", 209 .kind = "bridge",
294 .priv_size = sizeof(struct net_bridge), 210 .priv_size = sizeof(struct net_bridge),
295 .setup = br_dev_setup, 211 .setup = br_dev_setup,
@@ -301,19 +217,43 @@ int __init br_netlink_init(void)
301{ 217{
302 int err; 218 int err;
303 219
304 br_mdb_init();
305 err = rtnl_link_register(&br_link_ops); 220 err = rtnl_link_register(&br_link_ops);
221 if (err < 0)
222 goto err1;
223
224 err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL,
225 br_dump_ifinfo, NULL);
226 if (err)
227 goto err2;
228 err = __rtnl_register(PF_BRIDGE, RTM_SETLINK,
229 br_rtm_setlink, NULL, NULL);
230 if (err)
231 goto err3;
232 err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH,
233 br_fdb_add, NULL, NULL);
306 if (err) 234 if (err)
307 goto out; 235 goto err3;
236 err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH,
237 br_fdb_delete, NULL, NULL);
238 if (err)
239 goto err3;
240 err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH,
241 NULL, br_fdb_dump, NULL);
242 if (err)
243 goto err3;
308 244
309 return 0; 245 return 0;
310out: 246
311 br_mdb_uninit(); 247err3:
248 rtnl_unregister_all(PF_BRIDGE);
249err2:
250 rtnl_link_unregister(&br_link_ops);
251err1:
312 return err; 252 return err;
313} 253}
314 254
315void __exit br_netlink_fini(void) 255void __exit br_netlink_fini(void)
316{ 256{
317 br_mdb_uninit();
318 rtnl_link_unregister(&br_link_ops); 257 rtnl_link_unregister(&br_link_ops);
258 rtnl_unregister_all(PF_BRIDGE);
319} 259}