aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Fastabend <john.r.fastabend@intel.com>2012-10-24 04:12:57 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-31 13:18:28 -0400
commite5a55a898720096f43bc24938f8875c0a1b34cd7 (patch)
treeaff4a209c158a6bee5d974647ec8726f2b9a81c0
parenta932657f51eadb8280166e82dc7034dfbff3985a (diff)
net: create generic bridge ops
The PF_BRIDGE:RTM_{GET|SET}LINK nlmsg family and type are currently embedded in the ./net/bridge module. This prohibits them from being used by other bridging devices. One example of this being hardware that has embedded bridging components. In order to use these nlmsg types more generically this patch adds two net_device_ops hooks. One to set link bridge attributes and another to dump the current bride attributes. ndo_bridge_setlink() ndo_bridge_getlink() CC: Lennert Buytenhek <buytenh@wantstofly.org> CC: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h10
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_netlink.c73
-rw-r--r--net/bridge/br_private.h3
-rw-r--r--net/core/rtnetlink.c80
5 files changed, 108 insertions, 60 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f8eda0276f03..7bf867c97043 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -887,6 +887,10 @@ struct netdev_fcoe_hbainfo {
887 * struct net_device *dev, int idx) 887 * struct net_device *dev, int idx)
888 * Used to add FDB entries to dump requests. Implementers should add 888 * Used to add FDB entries to dump requests. Implementers should add
889 * entries to skb and update idx with the number of entries. 889 * entries to skb and update idx with the number of entries.
890 *
891 * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh)
892 * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
893 * struct net_device *dev)
890 */ 894 */
891struct net_device_ops { 895struct net_device_ops {
892 int (*ndo_init)(struct net_device *dev); 896 int (*ndo_init)(struct net_device *dev);
@@ -998,6 +1002,12 @@ struct net_device_ops {
998 struct netlink_callback *cb, 1002 struct netlink_callback *cb,
999 struct net_device *dev, 1003 struct net_device *dev,
1000 int idx); 1004 int idx);
1005
1006 int (*ndo_bridge_setlink)(struct net_device *dev,
1007 struct nlmsghdr *nlh);
1008 int (*ndo_bridge_getlink)(struct sk_buff *skb,
1009 u32 pid, u32 seq,
1010 struct net_device *dev);
1001}; 1011};
1002 1012
1003/* 1013/*
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 070e8a68cfc6..63b5b088e80f 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -313,6 +313,8 @@ static const struct net_device_ops br_netdev_ops = {
313 .ndo_fdb_add = br_fdb_add, 313 .ndo_fdb_add = br_fdb_add,
314 .ndo_fdb_del = br_fdb_delete, 314 .ndo_fdb_del = br_fdb_delete,
315 .ndo_fdb_dump = br_fdb_dump, 315 .ndo_fdb_dump = br_fdb_dump,
316 .ndo_bridge_getlink = br_getlink,
317 .ndo_bridge_setlink = br_setlink,
316}; 318};
317 319
318static void br_dev_free(struct net_device *dev) 320static void br_dev_free(struct net_device *dev)
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 093f527276a3..743511bb7319 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -111,54 +111,33 @@ errout:
111/* 111/*
112 * Dump information about all ports, in response to GETLINK 112 * Dump information about all ports, in response to GETLINK
113 */ 113 */
114static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 114int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
115 struct net_device *dev)
115{ 116{
116 struct net *net = sock_net(skb->sk); 117 int err = 0;
117 struct net_device *dev; 118 struct net_bridge_port *port = br_port_get_rcu(dev);
118 int idx; 119
119 120 /* not a bridge port */
120 idx = 0; 121 if (!port)
121 rcu_read_lock(); 122 goto out;
122 for_each_netdev_rcu(net, dev) {
123 struct net_bridge_port *port = br_port_get_rcu(dev);
124
125 /* not a bridge port */
126 if (!port || idx < cb->args[0])
127 goto skip;
128
129 if (br_fill_ifinfo(skb, port,
130 NETLINK_CB(cb->skb).portid,
131 cb->nlh->nlmsg_seq, RTM_NEWLINK,
132 NLM_F_MULTI) < 0)
133 break;
134skip:
135 ++idx;
136 }
137 rcu_read_unlock();
138 cb->args[0] = idx;
139 123
140 return skb->len; 124 err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI);
125out:
126 return err;
141} 127}
142 128
143/* 129/*
144 * Change state of port (ie from forwarding to blocking etc) 130 * Change state of port (ie from forwarding to blocking etc)
145 * Used by spanning tree in user space. 131 * Used by spanning tree in user space.
146 */ 132 */
147static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 133int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
148{ 134{
149 struct net *net = sock_net(skb->sk);
150 struct ifinfomsg *ifm; 135 struct ifinfomsg *ifm;
151 struct nlattr *protinfo; 136 struct nlattr *protinfo;
152 struct net_device *dev;
153 struct net_bridge_port *p; 137 struct net_bridge_port *p;
154 u8 new_state; 138 u8 new_state;
155 139
156 if (nlmsg_len(nlh) < sizeof(*ifm))
157 return -EINVAL;
158
159 ifm = nlmsg_data(nlh); 140 ifm = nlmsg_data(nlh);
160 if (ifm->ifi_family != AF_BRIDGE)
161 return -EPFNOSUPPORT;
162 141
163 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); 142 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
164 if (!protinfo || nla_len(protinfo) < sizeof(u8)) 143 if (!protinfo || nla_len(protinfo) < sizeof(u8))
@@ -168,10 +147,6 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
168 if (new_state > BR_STATE_BLOCKING) 147 if (new_state > BR_STATE_BLOCKING)
169 return -EINVAL; 148 return -EINVAL;
170 149
171 dev = __dev_get_by_index(net, ifm->ifi_index);
172 if (!dev)
173 return -ENODEV;
174
175 p = br_port_get_rtnl(dev); 150 p = br_port_get_rtnl(dev);
176 if (!p) 151 if (!p)
177 return -EINVAL; 152 return -EINVAL;
@@ -218,29 +193,7 @@ struct rtnl_link_ops br_link_ops __read_mostly = {
218 193
219int __init br_netlink_init(void) 194int __init br_netlink_init(void)
220{ 195{
221 int err; 196 return rtnl_link_register(&br_link_ops);
222
223 err = rtnl_link_register(&br_link_ops);
224 if (err < 0)
225 goto err1;
226
227 err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL,
228 br_dump_ifinfo, NULL);
229 if (err)
230 goto err2;
231 err = __rtnl_register(PF_BRIDGE, RTM_SETLINK,
232 br_rtm_setlink, NULL, NULL);
233 if (err)
234 goto err3;
235
236 return 0;
237
238err3:
239 rtnl_unregister_all(PF_BRIDGE);
240err2:
241 rtnl_link_unregister(&br_link_ops);
242err1:
243 return err;
244} 197}
245 198
246void __exit br_netlink_fini(void) 199void __exit br_netlink_fini(void)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 9b278c4ebee1..fdcd5f626ca6 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -553,6 +553,9 @@ extern struct rtnl_link_ops br_link_ops;
553extern int br_netlink_init(void); 553extern int br_netlink_init(void);
554extern void br_netlink_fini(void); 554extern void br_netlink_fini(void);
555extern void br_ifinfo_notify(int event, struct net_bridge_port *port); 555extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
556extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg);
557extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
558 struct net_device *dev);
556 559
557#ifdef CONFIG_SYSFS 560#ifdef CONFIG_SYSFS
558/* br_sysfs_if.c */ 561/* br_sysfs_if.c */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 64fe3cca2a4e..a068666b322f 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2252,6 +2252,83 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
2252 return skb->len; 2252 return skb->len;
2253} 2253}
2254 2254
2255static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
2256{
2257 struct net *net = sock_net(skb->sk);
2258 struct net_device *dev;
2259 int idx = 0;
2260 u32 portid = NETLINK_CB(cb->skb).portid;
2261 u32 seq = cb->nlh->nlmsg_seq;
2262
2263 rcu_read_lock();
2264 for_each_netdev_rcu(net, dev) {
2265 const struct net_device_ops *ops = dev->netdev_ops;
2266 struct net_device *master = dev->master;
2267
2268 if (idx < cb->args[0])
2269 continue;
2270
2271 if (master && master->netdev_ops->ndo_bridge_getlink) {
2272 const struct net_device_ops *bops = master->netdev_ops;
2273 int err = bops->ndo_bridge_getlink(skb, portid,
2274 seq, dev);
2275
2276 if (err < 0)
2277 break;
2278 else
2279 idx++;
2280 }
2281
2282 if (ops->ndo_bridge_getlink) {
2283 int err = ops->ndo_bridge_getlink(skb, portid,
2284 seq, dev);
2285
2286 if (err < 0)
2287 break;
2288 else
2289 idx++;
2290 }
2291 }
2292 rcu_read_unlock();
2293 cb->args[0] = idx;
2294
2295 return skb->len;
2296}
2297
2298static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
2299 void *arg)
2300{
2301 struct net *net = sock_net(skb->sk);
2302 struct ifinfomsg *ifm;
2303 struct net_device *dev;
2304 int err = -EINVAL;
2305
2306 if (nlmsg_len(nlh) < sizeof(*ifm))
2307 return -EINVAL;
2308
2309 ifm = nlmsg_data(nlh);
2310 if (ifm->ifi_family != AF_BRIDGE)
2311 return -EPFNOSUPPORT;
2312
2313 dev = __dev_get_by_index(net, ifm->ifi_index);
2314 if (!dev) {
2315 pr_info("PF_BRIDGE: RTM_SETLINK with unknown ifindex\n");
2316 return -ENODEV;
2317 }
2318
2319 if (dev->master && dev->master->netdev_ops->ndo_bridge_setlink) {
2320 err = dev->master->netdev_ops->ndo_bridge_setlink(dev, nlh);
2321 if (err)
2322 goto out;
2323 }
2324
2325 if (dev->netdev_ops->ndo_bridge_setlink)
2326 err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh);
2327
2328out:
2329 return err;
2330}
2331
2255/* Protected by RTNL sempahore. */ 2332/* Protected by RTNL sempahore. */
2256static struct rtattr **rta_buf; 2333static struct rtattr **rta_buf;
2257static int rtattr_max; 2334static int rtattr_max;
@@ -2433,5 +2510,8 @@ void __init rtnetlink_init(void)
2433 rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, NULL); 2510 rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, NULL);
2434 rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, NULL); 2511 rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, NULL);
2435 rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL); 2512 rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL);
2513
2514 rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL);
2515 rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL);
2436} 2516}
2437 2517