Blame view
net/bridge/br_netlink.c
6.15 KB
11dc1f36a [BRIDGE]: netlink... |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * Bridge netlink control interface * * Authors: * Stephen Hemminger <shemminger@osdl.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/kernel.h> |
5a0e3ad6a include cleanup: ... |
14 |
#include <linux/slab.h> |
bb900b27a bridge: allow cre... |
15 |
#include <linux/etherdevice.h> |
32fe21c0c [BRIDGE]: Use rtn... |
16 |
#include <net/rtnetlink.h> |
881d966b4 [NET]: Make the d... |
17 |
#include <net/net_namespace.h> |
b854272b3 [NET]: Modify all... |
18 |
#include <net/sock.h> |
bb900b27a bridge: allow cre... |
19 |
|
11dc1f36a [BRIDGE]: netlink... |
20 |
#include "br_private.h" |
b03b6dd58 bridge: master de... |
21 |
#include "br_private_stp.h" |
11dc1f36a [BRIDGE]: netlink... |
22 |
|
339bf98ff [NETLINK]: Do pre... |
23 24 25 26 27 28 29 30 31 32 33 |
static inline size_t br_nlmsg_size(void) { return NLMSG_ALIGN(sizeof(struct ifinfomsg)) + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ + nla_total_size(4) /* IFLA_MASTER */ + nla_total_size(4) /* IFLA_MTU */ + nla_total_size(4) /* IFLA_LINK */ + nla_total_size(1) /* IFLA_OPERSTATE */ + nla_total_size(1); /* IFLA_PROTINFO */ } |
11dc1f36a [BRIDGE]: netlink... |
34 35 36 37 38 39 40 41 42 |
/* * Create one netlink message for one interface * Contains port and master info as well as carrier and bridge state. */ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *port, u32 pid, u32 seq, int event, unsigned int flags) { const struct net_bridge *br = port->br; const struct net_device *dev = port->dev; |
746859625 [BRIDGE] netlink:... |
43 |
struct ifinfomsg *hdr; |
11dc1f36a [BRIDGE]: netlink... |
44 |
struct nlmsghdr *nlh; |
11dc1f36a [BRIDGE]: netlink... |
45 |
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; |
11dc1f36a [BRIDGE]: netlink... |
46 |
|
28a16c979 bridge: change co... |
47 48 49 |
br_debug(br, "br_fill_info event %d port %s master %s ", event, dev->name, br->dev->name); |
11dc1f36a [BRIDGE]: netlink... |
50 |
|
746859625 [BRIDGE] netlink:... |
51 52 |
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); if (nlh == NULL) |
26932566a [NETLINK]: Don't ... |
53 |
return -EMSGSIZE; |
11dc1f36a [BRIDGE]: netlink... |
54 |
|
746859625 [BRIDGE] netlink:... |
55 56 57 58 59 60 61 |
hdr = nlmsg_data(nlh); hdr->ifi_family = AF_BRIDGE; hdr->__ifi_pad = 0; hdr->ifi_type = dev->type; hdr->ifi_index = dev->ifindex; hdr->ifi_flags = dev_get_flags(dev); hdr->ifi_change = 0; |
11dc1f36a [BRIDGE]: netlink... |
62 |
|
746859625 [BRIDGE] netlink:... |
63 64 65 66 |
NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); NLA_PUT_U32(skb, IFLA_MASTER, br->dev->ifindex); NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); NLA_PUT_U8(skb, IFLA_OPERSTATE, operstate); |
11dc1f36a [BRIDGE]: netlink... |
67 68 |
if (dev->addr_len) |
746859625 [BRIDGE] netlink:... |
69 |
NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); |
11dc1f36a [BRIDGE]: netlink... |
70 |
|
11dc1f36a [BRIDGE]: netlink... |
71 |
if (dev->ifindex != dev->iflink) |
746859625 [BRIDGE] netlink:... |
72 |
NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); |
11dc1f36a [BRIDGE]: netlink... |
73 74 |
if (event == RTM_NEWLINK) |
746859625 [BRIDGE] netlink:... |
75 |
NLA_PUT_U8(skb, IFLA_PROTINFO, port->state); |
11dc1f36a [BRIDGE]: netlink... |
76 |
|
746859625 [BRIDGE] netlink:... |
77 |
return nlmsg_end(skb, nlh); |
11dc1f36a [BRIDGE]: netlink... |
78 |
|
746859625 [BRIDGE] netlink:... |
79 |
nla_put_failure: |
26932566a [NETLINK]: Don't ... |
80 81 |
nlmsg_cancel(skb, nlh); return -EMSGSIZE; |
11dc1f36a [BRIDGE]: netlink... |
82 83 84 85 86 87 88 |
} /* * Notify listeners of a change in port information */ void br_ifinfo_notify(int event, struct net_bridge_port *port) { |
4aa678ba4 netns bridge: all... |
89 |
struct net *net = dev_net(port->dev); |
11dc1f36a [BRIDGE]: netlink... |
90 |
struct sk_buff *skb; |
280a306c5 [BRIDGE]: Convert... |
91 |
int err = -ENOBUFS; |
11dc1f36a [BRIDGE]: netlink... |
92 |
|
28a16c979 bridge: change co... |
93 94 95 |
br_debug(port->br, "port %u(%s) event %d ", (unsigned)port->port_no, port->dev->name, event); |
339bf98ff [NETLINK]: Do pre... |
96 |
skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); |
280a306c5 [BRIDGE]: Convert... |
97 98 99 100 |
if (skb == NULL) goto errout; err = br_fill_ifinfo(skb, port, 0, 0, event, 0); |
26932566a [NETLINK]: Don't ... |
101 102 103 104 105 106 |
if (err < 0) { /* -EMSGSIZE implies BUG in br_nlmsg_size() */ WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout; } |
1ce85fe40 netlink: change n... |
107 108 |
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); return; |
280a306c5 [BRIDGE]: Convert... |
109 |
errout: |
bea1b42e1 [BRIDGE]: netlink... |
110 |
if (err < 0) |
4aa678ba4 netns bridge: all... |
111 |
rtnl_set_sk_err(net, RTNLGRP_LINK, err); |
11dc1f36a [BRIDGE]: netlink... |
112 113 114 115 116 117 118 |
} /* * Dump information about all ports, in response to GETLINK */ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { |
3b1e0a655 [NET] NETNS: Omit... |
119 |
struct net *net = sock_net(skb->sk); |
11dc1f36a [BRIDGE]: netlink... |
120 121 |
struct net_device *dev; int idx; |
11dc1f36a [BRIDGE]: netlink... |
122 |
|
7562f876c [NET]: Rework dev... |
123 |
idx = 0; |
e67f88dd1 net: dont hold rt... |
124 125 126 |
rcu_read_lock(); for_each_netdev_rcu(net, dev) { struct net_bridge_port *port = br_port_get_rcu(dev); |
b5ed54e94 bridge: fix RCU r... |
127 |
|
11dc1f36a [BRIDGE]: netlink... |
128 |
/* not a bridge port */ |
b5ed54e94 bridge: fix RCU r... |
129 |
if (!port || idx < cb->args[0]) |
746859625 [BRIDGE] netlink:... |
130 |
goto skip; |
11dc1f36a [BRIDGE]: netlink... |
131 |
|
b5ed54e94 bridge: fix RCU r... |
132 |
if (br_fill_ifinfo(skb, port, |
f350a0a87 bridge: use rx_ha... |
133 |
NETLINK_CB(cb->skb).pid, |
746859625 [BRIDGE] netlink:... |
134 135 |
cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI) < 0) |
11dc1f36a [BRIDGE]: netlink... |
136 |
break; |
746859625 [BRIDGE] netlink:... |
137 |
skip: |
11dc1f36a [BRIDGE]: netlink... |
138 139 |
++idx; } |
e67f88dd1 net: dont hold rt... |
140 |
rcu_read_unlock(); |
11dc1f36a [BRIDGE]: netlink... |
141 142 143 144 145 146 147 148 149 150 151 |
cb->args[0] = idx; return skb->len; } /* * Change state of port (ie from forwarding to blocking etc) * Used by spanning tree in user space. */ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { |
3b1e0a655 [NET] NETNS: Omit... |
152 |
struct net *net = sock_net(skb->sk); |
746859625 [BRIDGE] netlink:... |
153 154 |
struct ifinfomsg *ifm; struct nlattr *protinfo; |
11dc1f36a [BRIDGE]: netlink... |
155 156 157 |
struct net_device *dev; struct net_bridge_port *p; u8 new_state; |
746859625 [BRIDGE] netlink:... |
158 159 160 161 |
if (nlmsg_len(nlh) < sizeof(*ifm)) return -EINVAL; ifm = nlmsg_data(nlh); |
11dc1f36a [BRIDGE]: netlink... |
162 163 |
if (ifm->ifi_family != AF_BRIDGE) return -EPFNOSUPPORT; |
746859625 [BRIDGE] netlink:... |
164 165 |
protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); if (!protinfo || nla_len(protinfo) < sizeof(u8)) |
11dc1f36a [BRIDGE]: netlink... |
166 |
return -EINVAL; |
746859625 [BRIDGE] netlink:... |
167 |
new_state = nla_get_u8(protinfo); |
11dc1f36a [BRIDGE]: netlink... |
168 169 |
if (new_state > BR_STATE_BLOCKING) return -EINVAL; |
4aa678ba4 netns bridge: all... |
170 |
dev = __dev_get_by_index(net, ifm->ifi_index); |
11dc1f36a [BRIDGE]: netlink... |
171 172 |
if (!dev) return -ENODEV; |
ec1e5610c bridge: add RCU a... |
173 |
p = br_port_get_rtnl(dev); |
b5ed54e94 bridge: fix RCU r... |
174 175 |
if (!p) return -EINVAL; |
11dc1f36a [BRIDGE]: netlink... |
176 177 |
/* if kernel STP is running, don't allow changes */ |
9cde07087 bridge: add suppo... |
178 |
if (p->br->stp_enabled == BR_KERNEL_STP) |
11dc1f36a [BRIDGE]: netlink... |
179 |
return -EBUSY; |
746859625 [BRIDGE] netlink:... |
180 181 |
if (!netif_running(dev) || (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED)) |
11dc1f36a [BRIDGE]: netlink... |
182 183 184 185 |
return -ENETDOWN; p->state = new_state; br_log_state(p); |
b03b6dd58 bridge: master de... |
186 187 188 189 |
spin_lock_bh(&p->br->lock); br_port_state_selection(p->br); spin_unlock_bh(&p->br->lock); |
4ecb961c8 bridge: add notif... |
190 |
br_ifinfo_notify(RTM_NEWLINK, p); |
11dc1f36a [BRIDGE]: netlink... |
191 192 |
return 0; } |
bb900b27a bridge: allow cre... |
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
static int br_validate(struct nlattr *tb[], struct nlattr *data[]) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) return -EINVAL; if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) return -EADDRNOTAVAIL; } return 0; } static struct rtnl_link_ops br_link_ops __read_mostly = { .kind = "bridge", .priv_size = sizeof(struct net_bridge), .setup = br_dev_setup, .validate = br_validate, |
1ce5cce89 bridge: fix hang ... |
210 |
.dellink = br_dev_delete, |
bb900b27a bridge: allow cre... |
211 |
}; |
11dc1f36a [BRIDGE]: netlink... |
212 |
|
32fe21c0c [BRIDGE]: Use rtn... |
213 |
int __init br_netlink_init(void) |
11dc1f36a [BRIDGE]: netlink... |
214 |
{ |
bb900b27a bridge: allow cre... |
215 |
int err; |
36fd2b63e bridge: allow cre... |
216 |
|
bb900b27a bridge: allow cre... |
217 218 219 |
err = rtnl_link_register(&br_link_ops); if (err < 0) goto err1; |
c7ac8679b rtnetlink: Comput... |
220 221 |
err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo, NULL); |
bb900b27a bridge: allow cre... |
222 223 |
if (err) goto err2; |
c7ac8679b rtnetlink: Comput... |
224 225 |
err = __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL, NULL); |
bb900b27a bridge: allow cre... |
226 227 |
if (err) goto err3; |
c7ac8679b rtnetlink: Comput... |
228 229 |
err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL, NULL); |
bb900b27a bridge: allow cre... |
230 231 |
if (err) goto err3; |
c7ac8679b rtnetlink: Comput... |
232 233 |
err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL, NULL); |
bb900b27a bridge: allow cre... |
234 235 |
if (err) goto err3; |
c7ac8679b rtnetlink: Comput... |
236 237 |
err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump, NULL); |
bb900b27a bridge: allow cre... |
238 239 |
if (err) goto err3; |
32fe21c0c [BRIDGE]: Use rtn... |
240 241 |
return 0; |
bb900b27a bridge: allow cre... |
242 243 244 245 246 247 248 |
err3: rtnl_unregister_all(PF_BRIDGE); err2: rtnl_link_unregister(&br_link_ops); err1: return err; |
11dc1f36a [BRIDGE]: netlink... |
249 250 251 252 |
} void __exit br_netlink_fini(void) { |
bb900b27a bridge: allow cre... |
253 |
rtnl_link_unregister(&br_link_ops); |
32fe21c0c [BRIDGE]: Use rtn... |
254 |
rtnl_unregister_all(PF_BRIDGE); |
11dc1f36a [BRIDGE]: netlink... |
255 |
} |