#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
+#include <net/net_namespace.h>
struct pcpu_lstats {
unsigned long packets;
}
/* Setup and register the loopback device. */
-static int __init loopback_init(void)
+static int loopback_net_init(struct net *net)
{
struct net_device *dev;
int err;
if (!dev)
goto out;
+ dev->nd_net = net;
err = register_netdev(dev);
if (err)
goto out_free_netdev;
err = 0;
- loopback_dev = dev;
+ net->loopback_dev = dev;
out:
if (err)
goto out;
}
-fs_initcall(loopback_init);
+static void loopback_net_exit(struct net *net)
+{
+ struct net_device *dev = net->loopback_dev;
+
+ unregister_netdev(dev);
+}
+
+static struct pernet_operations loopback_net_ops = {
+ .init = loopback_net_init,
+ .exit = loopback_net_exit,
+};
+
+static int __init loopback_init(void)
+{
+ return register_pernet_device(&loopback_net_ops);
+}
-struct net_device *loopback_dev;
-EXPORT_SYMBOL(loopback_dev);
+fs_initcall(loopback_init);
#include <linux/interrupt.h>
#include <linux/notifier.h>
-extern struct net_device *loopback_dev; /* The loopback */
extern rwlock_t dev_base_lock; /* Device list lock */
#include <linux/list.h>
struct proc_dir_entry;
+struct net_device;
struct net {
atomic_t count; /* To decided when the network
* namespace should be freed.
struct proc_dir_entry *proc_net_stat;
struct proc_dir_entry *proc_net_root;
+ struct net_device *loopback_dev; /* The loopback */
+
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
#include <linux/types.h>
#include <net/net_namespace.h>
+#include <net/net_namespace.h>
#include <net/dst.h>
/*
if (!unregister) {
dst->input = dst->output = dst_discard;
} else {
- dst->dev = loopback_dev;
+ dst->dev = init_net.loopback_dev;
dev_hold(dst->dev);
dev_put(dev);
if (dst->neighbour && dst->neighbour->dev == dev) {
- dst->neighbour->dev = loopback_dev;
+ dst->neighbour->dev = init_net.loopback_dev;
dev_put(dev);
dev_hold(dst->neighbour->dev);
}
rv = dn_dev_get_first(dev, addr);
read_unlock(&dev_base_lock);
dev_put(dev);
- if (rv == 0 || dev == loopback_dev)
+ if (rv == 0 || dev == init_net.loopback_dev)
return rv;
}
- dev = loopback_dev;
+ dev = init_net.loopback_dev;
dev_hold(dev);
goto last_chance;
}
.scope = RT_SCOPE_UNIVERSE,
} },
.mark = oldflp->mark,
- .iif = loopback_dev->ifindex,
+ .iif = init_net.loopback_dev->ifindex,
.oif = oldflp->oif };
struct dn_route *rt = NULL;
struct net_device *dev_out = NULL, *dev;
"dn_route_output_slow: dst=%04x src=%04x mark=%d"
" iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst),
dn_ntohs(oldflp->fld_src),
- oldflp->mark, loopback_dev->ifindex, oldflp->oif);
+ oldflp->mark, init_net.loopback_dev->ifindex, oldflp->oif);
/* If we have an output interface, verify its a DECnet device */
if (oldflp->oif) {
err = -EADDRNOTAVAIL;
if (dev_out)
dev_put(dev_out);
- dev_out = loopback_dev;
+ dev_out = init_net.loopback_dev;
dev_hold(dev_out);
if (!fl.fld_dst) {
fl.fld_dst =
if (!fl.fld_dst)
goto out;
}
- fl.oif = loopback_dev->ifindex;
+ fl.oif = init_net.loopback_dev->ifindex;
res.type = RTN_LOCAL;
goto make_route;
}
if (dev_out)
dev_put(dev_out);
if (dn_dev_islocal(neigh->dev, fl.fld_dst)) {
- dev_out = loopback_dev;
+ dev_out = init_net.loopback_dev;
res.type = RTN_LOCAL;
} else {
dev_out = neigh->dev;
/* Possible improvement - check all devices for local addr */
if (dn_dev_islocal(dev_out, fl.fld_dst)) {
dev_put(dev_out);
- dev_out = loopback_dev;
+ dev_out = init_net.loopback_dev;
dev_hold(dev_out);
res.type = RTN_LOCAL;
goto select_source;
fl.fld_src = fl.fld_dst;
if (dev_out)
dev_put(dev_out);
- dev_out = loopback_dev;
+ dev_out = init_net.loopback_dev;
dev_hold(dev_out);
fl.oif = dev_out->ifindex;
if (res.fi)
{
struct rtable *rt = (struct rtable *) dst;
struct in_device *idev = rt->idev;
- if (dev != loopback_dev && idev && idev->dev == dev) {
- struct in_device *loopback_idev = in_dev_get(loopback_dev);
+ if (dev != init_net.loopback_dev && idev && idev->dev == dev) {
+ struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev);
if (loopback_idev) {
rt->idev = loopback_idev;
in_dev_put(idev);
#endif
rth->rt_iif =
rth->fl.iif = dev->ifindex;
- rth->u.dst.dev = loopback_dev;
+ rth->u.dst.dev = init_net.loopback_dev;
dev_hold(rth->u.dst.dev);
rth->idev = in_dev_get(rth->u.dst.dev);
rth->fl.oif = 0;
if (res.type == RTN_LOCAL) {
int result;
result = fib_validate_source(saddr, daddr, tos,
- loopback_dev->ifindex,
+ init_net.loopback_dev->ifindex,
dev, &spec_dst, &itag);
if (result < 0)
goto martian_source;
#endif
rth->rt_iif =
rth->fl.iif = dev->ifindex;
- rth->u.dst.dev = loopback_dev;
+ rth->u.dst.dev = init_net.loopback_dev;
dev_hold(rth->u.dst.dev);
rth->idev = in_dev_get(rth->u.dst.dev);
rth->rt_gateway = daddr;
RT_SCOPE_UNIVERSE),
} },
.mark = oldflp->mark,
- .iif = loopback_dev->ifindex,
+ .iif = init_net.loopback_dev->ifindex,
.oif = oldflp->oif };
struct fib_result res;
unsigned flags = 0;
fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK);
if (dev_out)
dev_put(dev_out);
- dev_out = loopback_dev;
+ dev_out = init_net.loopback_dev;
dev_hold(dev_out);
- fl.oif = loopback_dev->ifindex;
+ fl.oif = init_net.loopback_dev->ifindex;
res.type = RTN_LOCAL;
flags |= RTCF_LOCAL;
goto make_route;
fl.fl4_src = fl.fl4_dst;
if (dev_out)
dev_put(dev_out);
- dev_out = loopback_dev;
+ dev_out = init_net.loopback_dev;
dev_hold(dev_out);
fl.oif = dev_out->ifindex;
if (res.fi)
xdst = (struct xfrm_dst *)dst;
if (xdst->u.rt.idev->dev == dev) {
- struct in_device *loopback_idev = in_dev_get(loopback_dev);
+ struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev);
BUG_ON(!loopback_idev);
do {
ASSERT_RTNL();
- if (dev == loopback_dev && how == 1)
+ if (dev == init_net.loopback_dev && how == 1)
how = 0;
rt6_ifdown(dev);
* device and it being up should be removed.
*/
rtnl_lock();
- if (!ipv6_add_dev(loopback_dev))
+ if (!ipv6_add_dev(init_net.loopback_dev))
err = -ENOMEM;
rtnl_unlock();
if (err)
return err;
- ip6_null_entry.u.dst.dev = loopback_dev;
- ip6_null_entry.rt6i_idev = in6_dev_get(loopback_dev);
+ ip6_null_entry.u.dst.dev = init_net.loopback_dev;
+ ip6_null_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- ip6_prohibit_entry.u.dst.dev = loopback_dev;
- ip6_prohibit_entry.rt6i_idev = in6_dev_get(loopback_dev);
- ip6_blk_hole_entry.u.dst.dev = loopback_dev;
- ip6_blk_hole_entry.rt6i_idev = in6_dev_get(loopback_dev);
+ ip6_prohibit_entry.u.dst.dev = init_net.loopback_dev;
+ ip6_prohibit_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ ip6_blk_hole_entry.u.dst.dev = init_net.loopback_dev;
+ ip6_blk_hole_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
#endif
register_netdevice_notifier(&ipv6_dev_notf);
continue;
addrconf_ifdown(dev, 1);
}
- addrconf_ifdown(loopback_dev, 2);
+ addrconf_ifdown(init_net.loopback_dev, 2);
/*
* Check hash table.
send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum)
{
if (hooknum == NF_IP6_LOCAL_OUT && skb_in->dev == NULL)
- skb_in->dev = loopback_dev;
+ skb_in->dev = init_net.loopback_dev;
icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL);
}
struct rt6_info *rt = (struct rt6_info *)dst;
struct inet6_dev *idev = rt->rt6i_idev;
- if (dev != loopback_dev && idev != NULL && idev->dev == dev) {
- struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
+ if (dev != init_net.loopback_dev && idev != NULL && idev->dev == dev) {
+ struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev);
if (loopback_idev != NULL) {
rt->rt6i_idev = loopback_idev;
in6_dev_put(idev);
if ((cfg->fc_flags & RTF_REJECT) ||
(dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {
/* hold loopback dev/idev if we haven't done so. */
- if (dev != loopback_dev) {
+ if (dev != init_net.loopback_dev) {
if (dev) {
dev_put(dev);
in6_dev_put(idev);
}
- dev = loopback_dev;
+ dev = init_net.loopback_dev;
dev_hold(dev);
idev = in6_dev_get(dev);
if (!idev) {
if (rt == NULL)
return ERR_PTR(-ENOMEM);
- dev_hold(loopback_dev);
+ dev_hold(init_net.loopback_dev);
in6_dev_hold(idev);
rt->u.dst.flags = DST_HOST;
rt->u.dst.input = ip6_input;
rt->u.dst.output = ip6_output;
- rt->rt6i_dev = loopback_dev;
+ rt->rt6i_dev = init_net.loopback_dev;
rt->rt6i_idev = idev;
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
xdst = (struct xfrm_dst *)dst;
if (xdst->u.rt6.rt6i_idev->dev == dev) {
- struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
+ struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev);
BUG_ON(!loopback_idev);
do {
void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
{
while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
- dst->dev = loopback_dev;
+ dst->dev = init_net.loopback_dev;
dev_hold(dst->dev);
dev_put(dev);
}