Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 340517
b: refs/heads/master
c: e5a55a8
h: refs/heads/master
i:
  340515: bf7e380
v: v3
  • Loading branch information
John Fastabend authored and David S. Miller committed Oct 31, 2012
1 parent 2acccdb commit 34c3c87
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 61 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a932657f51eadb8280166e82dc7034dfbff3985a
refs/heads/master: e5a55a898720096f43bc24938f8875c0a1b34cd7
10 changes: 10 additions & 0 deletions trunk/include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,10 @@ struct netdev_fcoe_hbainfo {
* struct net_device *dev, int idx)
* Used to add FDB entries to dump requests. Implementers should add
* entries to skb and update idx with the number of entries.
*
* int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh)
* int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
* struct net_device *dev)
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
Expand Down Expand Up @@ -998,6 +1002,12 @@ struct net_device_ops {
struct netlink_callback *cb,
struct net_device *dev,
int idx);

int (*ndo_bridge_setlink)(struct net_device *dev,
struct nlmsghdr *nlh);
int (*ndo_bridge_getlink)(struct sk_buff *skb,
u32 pid, u32 seq,
struct net_device *dev);
};

/*
Expand Down
2 changes: 2 additions & 0 deletions trunk/net/bridge/br_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
73 changes: 13 additions & 60 deletions trunk/net/bridge/br_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,54 +111,33 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
/*
* 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))
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions trunk/net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
80 changes: 80 additions & 0 deletions trunk/net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -2252,6 +2252,83 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}

static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
struct net_device *dev;
int idx = 0;
u32 portid = NETLINK_CB(cb->skb).portid;
u32 seq = cb->nlh->nlmsg_seq;

rcu_read_lock();
for_each_netdev_rcu(net, dev) {
const struct net_device_ops *ops = dev->netdev_ops;
struct net_device *master = dev->master;

if (idx < cb->args[0])
continue;

if (master && master->netdev_ops->ndo_bridge_getlink) {
const struct net_device_ops *bops = master->netdev_ops;
int err = bops->ndo_bridge_getlink(skb, portid,
seq, dev);

if (err < 0)
break;
else
idx++;
}

if (ops->ndo_bridge_getlink) {
int err = ops->ndo_bridge_getlink(skb, portid,
seq, dev);

if (err < 0)
break;
else
idx++;
}
}
rcu_read_unlock();
cb->args[0] = idx;

return skb->len;
}

static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
void *arg)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
struct net_device *dev;
int err = -EINVAL;

if (nlmsg_len(nlh) < sizeof(*ifm))
return -EINVAL;

ifm = nlmsg_data(nlh);
if (ifm->ifi_family != AF_BRIDGE)
return -EPFNOSUPPORT;

dev = __dev_get_by_index(net, ifm->ifi_index);
if (!dev) {
pr_info("PF_BRIDGE: RTM_SETLINK with unknown ifindex\n");
return -ENODEV;
}

if (dev->master && dev->master->netdev_ops->ndo_bridge_setlink) {
err = dev->master->netdev_ops->ndo_bridge_setlink(dev, nlh);
if (err)
goto out;
}

if (dev->netdev_ops->ndo_bridge_setlink)
err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh);

out:
return err;
}

/* Protected by RTNL sempahore. */
static struct rtattr **rta_buf;
static int rtattr_max;
Expand Down Expand Up @@ -2433,5 +2510,8 @@ void __init rtnetlink_init(void)
rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, NULL);
rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, NULL);
rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL);

rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL);
rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL);
}

0 comments on commit 34c3c87

Please sign in to comment.