]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - net/core/rtnetlink.c
[NET]: Make the device list and device lookups per namespace.
[mirror_ubuntu-zesty-kernel.git] / net / core / rtnetlink.c
index 06eccca8cb5d305e0a6d2750e724cc65f0666235..44f91bb1ae8d41f7adfcc180c97565af7949a1f7 100644 (file)
@@ -306,10 +306,13 @@ EXPORT_SYMBOL_GPL(rtnl_link_register);
 void __rtnl_link_unregister(struct rtnl_link_ops *ops)
 {
        struct net_device *dev, *n;
+       struct net *net;
 
-       for_each_netdev_safe(dev, n) {
-               if (dev->rtnl_link_ops == ops)
-                       ops->dellink(dev);
+       for_each_net(net) {
+               for_each_netdev_safe(net, dev, n) {
+                       if (dev->rtnl_link_ops == ops)
+                               ops->dellink(dev);
+               }
        }
        list_del(&ops->list);
 }
@@ -634,7 +637,6 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
 
        NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
        NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len);
-       NLA_PUT_U32(skb, IFLA_WEIGHT, dev->weight);
        NLA_PUT_U8(skb, IFLA_OPERSTATE,
                   netif_running(dev) ? dev->operstate : IF_OPER_DOWN);
        NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode);
@@ -694,12 +696,13 @@ nla_put_failure:
 
 static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = skb->sk->sk_net;
        int idx;
        int s_idx = cb->args[0];
        struct net_device *dev;
 
        idx = 0;
-       for_each_netdev(dev) {
+       for_each_netdev(net, dev) {
                if (idx < s_idx)
                        goto cont;
                if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
@@ -714,7 +717,7 @@ cont:
        return skb->len;
 }
 
-static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
+const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_IFNAME]           = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
        [IFLA_ADDRESS]          = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
        [IFLA_BROADCAST]        = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
@@ -834,9 +837,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        if (tb[IFLA_TXQLEN])
                dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
 
-       if (tb[IFLA_WEIGHT])
-               dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
-
        if (tb[IFLA_OPERSTATE])
                set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
 
@@ -862,6 +862,7 @@ errout:
 
 static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        struct ifinfomsg *ifm;
        struct net_device *dev;
        int err;
@@ -880,9 +881,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        err = -EINVAL;
        ifm = nlmsg_data(nlh);
        if (ifm->ifi_index > 0)
-               dev = dev_get_by_index(ifm->ifi_index);
+               dev = dev_get_by_index(net, ifm->ifi_index);
        else if (tb[IFLA_IFNAME])
-               dev = dev_get_by_name(ifname);
+               dev = dev_get_by_name(net, ifname);
        else
                goto errout;
 
@@ -908,6 +909,7 @@ errout:
 
 static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        const struct rtnl_link_ops *ops;
        struct net_device *dev;
        struct ifinfomsg *ifm;
@@ -924,9 +926,9 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 
        ifm = nlmsg_data(nlh);
        if (ifm->ifi_index > 0)
-               dev = __dev_get_by_index(ifm->ifi_index);
+               dev = __dev_get_by_index(net, ifm->ifi_index);
        else if (tb[IFLA_IFNAME])
-               dev = __dev_get_by_name(ifname);
+               dev = __dev_get_by_name(net, ifname);
        else
                return -EINVAL;
 
@@ -941,8 +943,52 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        return 0;
 }
 
+struct net_device *rtnl_create_link(struct net *net, char *ifname,
+               const struct rtnl_link_ops *ops, struct nlattr *tb[])
+{
+       int err;
+       struct net_device *dev;
+
+       err = -ENOMEM;
+       dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
+       if (!dev)
+               goto err;
+
+       if (strchr(dev->name, '%')) {
+               err = dev_alloc_name(dev, dev->name);
+               if (err < 0)
+                       goto err_free;
+       }
+
+       dev->nd_net = net;
+       dev->rtnl_link_ops = ops;
+
+       if (tb[IFLA_MTU])
+               dev->mtu = nla_get_u32(tb[IFLA_MTU]);
+       if (tb[IFLA_ADDRESS])
+               memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
+                               nla_len(tb[IFLA_ADDRESS]));
+       if (tb[IFLA_BROADCAST])
+               memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
+                               nla_len(tb[IFLA_BROADCAST]));
+       if (tb[IFLA_TXQLEN])
+               dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
+       if (tb[IFLA_OPERSTATE])
+               set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
+       if (tb[IFLA_LINKMODE])
+               dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
+
+       return dev;
+
+err_free:
+       free_netdev(dev);
+err:
+       return ERR_PTR(err);
+}
+
 static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        const struct rtnl_link_ops *ops;
        struct net_device *dev;
        struct ifinfomsg *ifm;
@@ -952,7 +998,9 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        struct nlattr *linkinfo[IFLA_INFO_MAX+1];
        int err;
 
+#ifdef CONFIG_KMOD
 replay:
+#endif
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
        if (err < 0)
                return err;
@@ -964,9 +1012,9 @@ replay:
 
        ifm = nlmsg_data(nlh);
        if (ifm->ifi_index > 0)
-               dev = __dev_get_by_index(ifm->ifi_index);
+               dev = __dev_get_by_index(net, ifm->ifi_index);
        else if (ifname[0])
-               dev = __dev_get_by_name(ifname);
+               dev = __dev_get_by_name(net, ifname);
        else
                dev = NULL;
 
@@ -1051,40 +1099,17 @@ replay:
 
                if (!ifname[0])
                        snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
-               dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
-               if (!dev)
-                       return -ENOMEM;
-
-               if (strchr(dev->name, '%')) {
-                       err = dev_alloc_name(dev, dev->name);
-                       if (err < 0)
-                               goto err_free;
-               }
-               dev->rtnl_link_ops = ops;
-
-               if (tb[IFLA_MTU])
-                       dev->mtu = nla_get_u32(tb[IFLA_MTU]);
-               if (tb[IFLA_ADDRESS])
-                       memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
-                              nla_len(tb[IFLA_ADDRESS]));
-               if (tb[IFLA_BROADCAST])
-                       memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
-                              nla_len(tb[IFLA_BROADCAST]));
-               if (tb[IFLA_TXQLEN])
-                       dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
-               if (tb[IFLA_WEIGHT])
-                       dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
-               if (tb[IFLA_OPERSTATE])
-                       set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
-               if (tb[IFLA_LINKMODE])
-                       dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
-
-               if (ops->newlink)
+
+               dev = rtnl_create_link(net, ifname, ops, tb);
+
+               if (IS_ERR(dev))
+                       err = PTR_ERR(dev);
+               else if (ops->newlink)
                        err = ops->newlink(dev, tb, data);
                else
                        err = register_netdevice(dev);
-err_free:
-               if (err < 0)
+
+               if (err < 0 && !IS_ERR(dev))
                        free_netdev(dev);
                return err;
        }
@@ -1092,6 +1117,7 @@ err_free:
 
 static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        struct ifinfomsg *ifm;
        struct nlattr *tb[IFLA_MAX+1];
        struct net_device *dev = NULL;
@@ -1104,7 +1130,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 
        ifm = nlmsg_data(nlh);
        if (ifm->ifi_index > 0) {
-               dev = dev_get_by_index(ifm->ifi_index);
+               dev = dev_get_by_index(net, ifm->ifi_index);
                if (dev == NULL)
                        return -ENODEV;
        } else
@@ -1269,6 +1295,10 @@ static void rtnetlink_rcv(struct sock *sk, int len)
 static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
        struct net_device *dev = ptr;
+
+       if (dev->nd_net != &init_net)
+               return NOTIFY_DONE;
+
        switch (event) {
        case NETDEV_UNREGISTER:
                rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
@@ -1306,8 +1336,8 @@ void __init rtnetlink_init(void)
        if (!rta_buf)
                panic("rtnetlink_init: cannot allocate rta_buf\n");
 
-       rtnl = netlink_kernel_create(NETLINK_ROUTE, RTNLGRP_MAX, rtnetlink_rcv,
-                                    &rtnl_mutex, THIS_MODULE);
+       rtnl = netlink_kernel_create(&init_net, NETLINK_ROUTE, RTNLGRP_MAX,
+                                    rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
        if (rtnl == NULL)
                panic("rtnetlink_init: cannot initialize rtnetlink\n");
        netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
@@ -1333,3 +1363,5 @@ EXPORT_SYMBOL(rtnl_unlock);
 EXPORT_SYMBOL(rtnl_unicast);
 EXPORT_SYMBOL(rtnl_notify);
 EXPORT_SYMBOL(rtnl_set_sk_err);
+EXPORT_SYMBOL(rtnl_create_link);
+EXPORT_SYMBOL(ifla_policy);