|
@@ -60,7 +60,6 @@ struct rtnl_link
|
|
};
|
|
};
|
|
|
|
|
|
static DEFINE_MUTEX(rtnl_mutex);
|
|
static DEFINE_MUTEX(rtnl_mutex);
|
|
-static struct sock *rtnl;
|
|
|
|
|
|
|
|
void rtnl_lock(void)
|
|
void rtnl_lock(void)
|
|
{
|
|
{
|
|
@@ -458,8 +457,9 @@ size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
|
|
|
|
|
|
+int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo)
|
|
{
|
|
{
|
|
|
|
+ struct sock *rtnl = net->rtnl;
|
|
int err = 0;
|
|
int err = 0;
|
|
|
|
|
|
NETLINK_CB(skb).dst_group = group;
|
|
NETLINK_CB(skb).dst_group = group;
|
|
@@ -471,14 +471,17 @@ int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-int rtnl_unicast(struct sk_buff *skb, u32 pid)
|
|
|
|
|
|
+int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
|
|
{
|
|
{
|
|
|
|
+ struct sock *rtnl = net->rtnl;
|
|
|
|
+
|
|
return nlmsg_unicast(rtnl, skb, pid);
|
|
return nlmsg_unicast(rtnl, skb, pid);
|
|
}
|
|
}
|
|
|
|
|
|
-int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
|
|
|
|
|
|
+int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
|
|
struct nlmsghdr *nlh, gfp_t flags)
|
|
struct nlmsghdr *nlh, gfp_t flags)
|
|
{
|
|
{
|
|
|
|
+ struct sock *rtnl = net->rtnl;
|
|
int report = 0;
|
|
int report = 0;
|
|
|
|
|
|
if (nlh)
|
|
if (nlh)
|
|
@@ -487,8 +490,10 @@ int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
|
|
return nlmsg_notify(rtnl, skb, pid, group, report, flags);
|
|
return nlmsg_notify(rtnl, skb, pid, group, report, flags);
|
|
}
|
|
}
|
|
|
|
|
|
-void rtnl_set_sk_err(u32 group, int error)
|
|
|
|
|
|
+void rtnl_set_sk_err(struct net *net, u32 group, int error)
|
|
{
|
|
{
|
|
|
|
+ struct sock *rtnl = net->rtnl;
|
|
|
|
+
|
|
netlink_set_err(rtnl, 0, group, error);
|
|
netlink_set_err(rtnl, 0, group, error);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1201,7 +1206,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
|
|
kfree_skb(nskb);
|
|
kfree_skb(nskb);
|
|
goto errout;
|
|
goto errout;
|
|
}
|
|
}
|
|
- err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
|
|
|
|
|
|
+ err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid);
|
|
errout:
|
|
errout:
|
|
dev_put(dev);
|
|
dev_put(dev);
|
|
|
|
|
|
@@ -1252,10 +1257,10 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
goto errout;
|
|
goto errout;
|
|
}
|
|
}
|
|
- err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
|
|
|
|
|
|
+ err = rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
|
|
errout:
|
|
errout:
|
|
if (err < 0)
|
|
if (err < 0)
|
|
- rtnl_set_sk_err(RTNLGRP_LINK, err);
|
|
|
|
|
|
+ rtnl_set_sk_err(&init_net, RTNLGRP_LINK, err);
|
|
}
|
|
}
|
|
|
|
|
|
/* Protected by RTNL sempahore. */
|
|
/* Protected by RTNL sempahore. */
|
|
@@ -1266,6 +1271,7 @@ static int rtattr_max;
|
|
|
|
|
|
static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
{
|
|
{
|
|
|
|
+ struct net *net = skb->sk->sk_net;
|
|
rtnl_doit_func doit;
|
|
rtnl_doit_func doit;
|
|
int sz_idx, kind;
|
|
int sz_idx, kind;
|
|
int min_len;
|
|
int min_len;
|
|
@@ -1294,6 +1300,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
return -EPERM;
|
|
return -EPERM;
|
|
|
|
|
|
if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
|
|
if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
|
|
|
|
+ struct sock *rtnl;
|
|
rtnl_dumpit_func dumpit;
|
|
rtnl_dumpit_func dumpit;
|
|
|
|
|
|
dumpit = rtnl_get_dumpit(family, type);
|
|
dumpit = rtnl_get_dumpit(family, type);
|
|
@@ -1301,6 +1308,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
__rtnl_unlock();
|
|
__rtnl_unlock();
|
|
|
|
+ rtnl = net->rtnl;
|
|
err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
|
|
err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
|
|
rtnl_lock();
|
|
rtnl_lock();
|
|
return err;
|
|
return err;
|
|
@@ -1373,6 +1381,40 @@ static struct notifier_block rtnetlink_dev_notifier = {
|
|
.notifier_call = rtnetlink_event,
|
|
.notifier_call = rtnetlink_event,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+
|
|
|
|
+static int rtnetlink_net_init(struct net *net)
|
|
|
|
+{
|
|
|
|
+ struct sock *sk;
|
|
|
|
+ sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
|
|
|
|
+ rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
|
|
|
|
+ if (!sk)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ /* Don't hold an extra reference on the namespace */
|
|
|
|
+ put_net(sk->sk_net);
|
|
|
|
+ net->rtnl = sk;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void rtnetlink_net_exit(struct net *net)
|
|
|
|
+{
|
|
|
|
+ struct sock *sk = net->rtnl;
|
|
|
|
+ if (sk) {
|
|
|
|
+ /* At the last minute lie and say this is a socket for the
|
|
|
|
+ * initial network namespace. So the socket will be safe to
|
|
|
|
+ * free.
|
|
|
|
+ */
|
|
|
|
+ sk->sk_net = get_net(&init_net);
|
|
|
|
+ sock_put(sk);
|
|
|
|
+ net->rtnl = NULL;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct pernet_operations rtnetlink_net_ops = {
|
|
|
|
+ .init = rtnetlink_net_init,
|
|
|
|
+ .exit = rtnetlink_net_exit,
|
|
|
|
+};
|
|
|
|
+
|
|
void __init rtnetlink_init(void)
|
|
void __init rtnetlink_init(void)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
@@ -1385,10 +1427,9 @@ void __init rtnetlink_init(void)
|
|
if (!rta_buf)
|
|
if (!rta_buf)
|
|
panic("rtnetlink_init: cannot allocate rta_buf\n");
|
|
panic("rtnetlink_init: cannot allocate rta_buf\n");
|
|
|
|
|
|
- rtnl = netlink_kernel_create(&init_net, NETLINK_ROUTE, RTNLGRP_MAX,
|
|
|
|
- rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
|
|
|
|
- if (rtnl == NULL)
|
|
|
|
|
|
+ if (register_pernet_subsys(&rtnetlink_net_ops))
|
|
panic("rtnetlink_init: cannot initialize rtnetlink\n");
|
|
panic("rtnetlink_init: cannot initialize rtnetlink\n");
|
|
|
|
+
|
|
netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
|
|
netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
|
|
register_netdevice_notifier(&rtnetlink_dev_notifier);
|
|
register_netdevice_notifier(&rtnetlink_dev_notifier);
|
|
|
|
|