Skip to content

Commit

Permalink
[NETNS][IPV6] addrconf - make addrconf per namespace
Browse files Browse the repository at this point in the history
All the infrastructure to propagate the network namespace information
is ready. Make use of it.

There is a special case here between the initial network namespace and
the other namespaces:

* When ipv6 is initialized at boot time (aka in the init_net), it
registers to the notifier callback. So addrconf_notify will be called
as many time as there are network devices setup on the system and the
function will add ipv6 addresses to the network devices. But the first
device which needs to have its ipv6 address setup is the loopback,
unfortunatly this is not the case. So the loopback address is setup
manually in the ipv6 init function.

* With the network namespace, this ordering problem does not appears
because notifier is already setup and active, so as soon as we
register the loopback the ipv6 address is setup and it will be the
first device.

Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Benjamin Thery authored and David S. Miller committed Mar 5, 2008
1 parent af28493 commit 6fda735
Showing 1 changed file with 50 additions and 63 deletions.
113 changes: 50 additions & 63 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
write_lock(&addrconf_hash_lock);

/* Ignore adding duplicate addresses on an interface */
if (ipv6_chk_same_addr(&init_net, addr, idev->dev)) {
if (ipv6_chk_same_addr(idev->dev->nd_net, addr, idev->dev)) {
ADBG(("ipv6_add_addr: already assigned\n"));
err = -EEXIST;
goto out;
Expand Down Expand Up @@ -751,9 +751,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
struct in6_addr prefix;
struct rt6_info *rt;

struct net *net = ifp->idev->dev->nd_net;
ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
rt = rt6_lookup(&init_net, &prefix, NULL, ifp->idev->dev->ifindex, 1);
rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1);

if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
if (onlink == 0) {
Expand Down Expand Up @@ -905,6 +905,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
{
struct ipv6_saddr_score hiscore;
struct inet6_ifaddr *ifa_result = NULL;
struct net *net = daddr_dev->nd_net;
int daddr_type = __ipv6_addr_type(daddr);
int daddr_scope = __ipv6_addr_src_scope(daddr_type);
int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0;
Expand All @@ -916,7 +917,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
read_lock(&dev_base_lock);
rcu_read_lock();

for_each_netdev(&init_net, dev) {
for_each_netdev(net, dev) {
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;

Expand Down Expand Up @@ -1555,7 +1556,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
.fc_expires = expires,
.fc_dst_len = plen,
.fc_flags = RTF_UP | flags,
.fc_nlinfo.nl_net = &init_net,
.fc_nlinfo.nl_net = dev->nd_net,
};

ipv6_addr_copy(&cfg.fc_dst, pfx);
Expand All @@ -1582,7 +1583,7 @@ static void addrconf_add_mroute(struct net_device *dev)
.fc_ifindex = dev->ifindex,
.fc_dst_len = 8,
.fc_flags = RTF_UP,
.fc_nlinfo.nl_net = &init_net,
.fc_nlinfo.nl_net = dev->nd_net,
};

ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0);
Expand All @@ -1599,7 +1600,7 @@ static void sit_route_add(struct net_device *dev)
.fc_ifindex = dev->ifindex,
.fc_dst_len = 96,
.fc_flags = RTF_UP | RTF_NONEXTHOP,
.fc_nlinfo.nl_net = &init_net,
.fc_nlinfo.nl_net = dev->nd_net,
};

/* prefix length - 96 bits "::d.d.d.d" */
Expand Down Expand Up @@ -1700,7 +1701,8 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)

if (pinfo->onlink) {
struct rt6_info *rt;
rt = rt6_lookup(&init_net, &pinfo->prefix, NULL, dev->ifindex, 1);
rt = rt6_lookup(dev->nd_net, &pinfo->prefix, NULL,
dev->ifindex, 1);

if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
if (rt->rt6i_flags&RTF_EXPIRES) {
Expand Down Expand Up @@ -1743,7 +1745,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)

ok:

ifp = ipv6_get_ifaddr(&init_net, &addr, dev, 1);
ifp = ipv6_get_ifaddr(dev->nd_net, &addr, dev, 1);

if (ifp == NULL && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
Expand Down Expand Up @@ -2066,6 +2068,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
struct inet6_ifaddr * ifp;
struct in6_addr addr;
struct net_device *dev;
struct net *net = idev->dev->nd_net;
int scope;

ASSERT_RTNL();
Expand All @@ -2092,7 +2095,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
return;
}

for_each_netdev(&init_net, dev) {
for_each_netdev(net, dev) {
struct in_device * in_dev = __in_dev_get_rtnl(dev);
if (in_dev && (dev->flags & IFF_UP)) {
struct in_ifaddr * ifa;
Expand Down Expand Up @@ -2255,15 +2258,16 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
static void ip6_tnl_add_linklocal(struct inet6_dev *idev)
{
struct net_device *link_dev;
struct net *net = idev->dev->nd_net;

/* first try to inherit the link-local address from the link device */
if (idev->dev->iflink &&
(link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) {
(link_dev = __dev_get_by_index(net, idev->dev->iflink))) {
if (!ipv6_inherit_linklocal(idev, link_dev))
return;
}
/* then try to inherit it from any device */
for_each_netdev(&init_net, link_dev) {
for_each_netdev(net, link_dev) {
if (!ipv6_inherit_linklocal(idev, link_dev))
return;
}
Expand Down Expand Up @@ -2296,9 +2300,6 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
int run_pending = 0;
int err;

if (dev->nd_net != &init_net)
return NOTIFY_DONE;

switch(event) {
case NETDEV_REGISTER:
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
Expand Down Expand Up @@ -3056,9 +3057,6 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
struct in6_addr *pfx;
int err;

if (net != &init_net)
return -EINVAL;

err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
if (err < 0)
return err;
Expand Down Expand Up @@ -3121,9 +3119,6 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
u8 ifa_flags;
int err;

if (net != &init_net)
return -EINVAL;

err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
if (err < 0)
return err;
Expand Down Expand Up @@ -3324,12 +3319,13 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
struct inet6_ifaddr *ifa;
struct ifmcaddr6 *ifmca;
struct ifacaddr6 *ifaca;
struct net *net = skb->sk->sk_net;

s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];

idx = 0;
for_each_netdev(&init_net, dev) {
for_each_netdev(net, dev) {
if (idx < s_idx)
goto cont;
if (idx > s_idx)
Expand Down Expand Up @@ -3396,35 +3392,23 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,

static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = skb->sk->sk_net;
enum addr_type_t type = UNICAST_ADDR;

if (net != &init_net)
return 0;

return inet6_dump_addr(skb, cb, type);
}

static int inet6_dump_ifmcaddr(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = skb->sk->sk_net;
enum addr_type_t type = MULTICAST_ADDR;

if (net != &init_net)
return 0;

return inet6_dump_addr(skb, cb, type);
}


static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = skb->sk->sk_net;
enum addr_type_t type = ANYCAST_ADDR;

if (net != &init_net)
return 0;

return inet6_dump_addr(skb, cb, type);
}

Expand All @@ -3440,9 +3424,6 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
struct sk_buff *skb;
int err;

if (net != &init_net)
return -EINVAL;

err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
if (err < 0)
goto errout;
Expand All @@ -3455,7 +3436,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,

ifm = nlmsg_data(nlh);
if (ifm->ifa_index)
dev = __dev_get_by_index(&init_net, ifm->ifa_index);
dev = __dev_get_by_index(net, ifm->ifa_index);

if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) {
err = -EADDRNOTAVAIL;
Expand All @@ -3475,7 +3456,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
kfree_skb(skb);
goto errout_ifa;
}
err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
errout_ifa:
in6_ifa_put(ifa);
errout:
Expand All @@ -3485,6 +3466,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
{
struct sk_buff *skb;
struct net *net = ifa->idev->dev->nd_net;
int err = -ENOBUFS;

skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC);
Expand All @@ -3498,10 +3480,10 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
}

static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
Expand Down Expand Up @@ -3666,12 +3648,9 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
struct net_device *dev;
struct inet6_dev *idev;

if (net != &init_net)
return 0;

read_lock(&dev_base_lock);
idx = 0;
for_each_netdev(&init_net, dev) {
for_each_netdev(net, dev) {
if (idx < s_idx)
goto cont;
if ((idev = in6_dev_get(dev)) == NULL)
Expand All @@ -3693,6 +3672,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
{
struct sk_buff *skb;
struct net *net = idev->dev->nd_net;
int err = -ENOBUFS;

skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC);
Expand All @@ -3706,10 +3686,10 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
}

static inline size_t inet6_prefix_nlmsg_size(void)
Expand Down Expand Up @@ -3762,6 +3742,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
struct prefix_info *pinfo)
{
struct sk_buff *skb;
struct net *net = idev->dev->nd_net;
int err = -ENOBUFS;

skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC);
Expand All @@ -3775,10 +3756,10 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_PREFIX, err);
rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
}

static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
Expand Down Expand Up @@ -4276,7 +4257,26 @@ static int addrconf_net_init(struct net *net)

static void addrconf_net_exit(struct net *net)
{
;
struct net_device *dev;

/*
* Remove loopback references from default routing entries
*/
/* in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); */
/* #ifdef CONFIG_IPV6_MULTIPLE_TABLES */
/* in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); */
/* in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); */
/* #endif */

rtnl_lock();
/* clean dev list */
for_each_netdev(net, dev) {
if (__in6_dev_get(dev) == NULL)
continue;
addrconf_ifdown(dev, 1);
}
addrconf_ifdown(net->loopback_dev, 2);
rtnl_unlock();
}

static struct pernet_operations addrconf_net_ops = {
Expand Down Expand Up @@ -4357,7 +4357,6 @@ int __init addrconf_init(void)

void addrconf_cleanup(void)
{
struct net_device *dev;
struct inet6_ifaddr *ifa;
int i;

Expand All @@ -4368,21 +4367,9 @@ void addrconf_cleanup(void)

rtnl_lock();

/*
* clean dev list.
*/

for_each_netdev(&init_net, dev) {
if (__in6_dev_get(dev) == NULL)
continue;
addrconf_ifdown(dev, 1);
}
addrconf_ifdown(init_net.loopback_dev, 2);

/*
* Check hash table.
*/

write_lock_bh(&addrconf_hash_lock);
for (i=0; i < IN6_ADDR_HSIZE; i++) {
for (ifa=inet6_addr_lst[i]; ifa; ) {
Expand Down

0 comments on commit 6fda735

Please sign in to comment.