From e5a55a898720096f43bc24938f8875c0a1b34cd7 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Wed, 24 Oct 2012 08:12:57 +0000 Subject: 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 CC: Stephen Hemminger Signed-off-by: John Fastabend Signed-off-by: David S. Miller --- net/bridge/br_device.c | 2 ++ net/bridge/br_netlink.c | 73 +++++++++---------------------------------------- net/bridge/br_private.h | 3 ++ 3 files changed, 18 insertions(+), 60 deletions(-) (limited to 'net/bridge') 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 = { .ndo_fdb_add = br_fdb_add, .ndo_fdb_del = br_fdb_delete, .ndo_fdb_dump = br_fdb_dump, + .ndo_bridge_getlink = br_getlink, + .ndo_bridge_setlink = br_setlink, }; static 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: /* * Dump information about all ports, in response to GETLINK */ -static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) +int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev) { - struct net *net = sock_net(skb->sk); - struct net_device *dev; - int idx; - - idx = 0; - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { - struct net_bridge_port *port = br_port_get_rcu(dev); - - /* not a bridge port */ - if (!port || idx < cb->args[0]) - goto skip; - - if (br_fill_ifinfo(skb, port, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, RTM_NEWLINK, - NLM_F_MULTI) < 0) - break; -skip: - ++idx; - } - rcu_read_unlock(); - cb->args[0] = idx; + int err = 0; + struct net_bridge_port *port = br_port_get_rcu(dev); + + /* not a bridge port */ + if (!port) + goto out; - return skb->len; + err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI); +out: + return err; } /* * 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) +int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) { - struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; struct nlattr *protinfo; - struct net_device *dev; struct net_bridge_port *p; u8 new_state; - if (nlmsg_len(nlh) < sizeof(*ifm)) - return -EINVAL; - ifm = nlmsg_data(nlh); - if (ifm->ifi_family != AF_BRIDGE) - return -EPFNOSUPPORT; protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); 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) if (new_state > BR_STATE_BLOCKING) return -EINVAL; - dev = __dev_get_by_index(net, ifm->ifi_index); - if (!dev) - return -ENODEV; - p = br_port_get_rtnl(dev); if (!p) return -EINVAL; @@ -218,29 +193,7 @@ struct rtnl_link_ops br_link_ops __read_mostly = { int __init br_netlink_init(void) { - int err; - - err = rtnl_link_register(&br_link_ops); - if (err < 0) - goto err1; - - err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, - br_dump_ifinfo, NULL); - if (err) - goto err2; - err = __rtnl_register(PF_BRIDGE, RTM_SETLINK, - br_rtm_setlink, NULL, NULL); - if (err) - goto err3; - - return 0; - -err3: - rtnl_unregister_all(PF_BRIDGE); -err2: - rtnl_link_unregister(&br_link_ops); -err1: - return err; + return rtnl_link_register(&br_link_ops); } void __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; extern int br_netlink_init(void); extern void br_netlink_fini(void); extern void br_ifinfo_notify(int event, struct net_bridge_port *port); +extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg); +extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev); #ifdef CONFIG_SYSFS /* br_sysfs_if.c */ -- cgit v1.2.3