#include <net/ip_fib.h>
#include <net/rtnetlink.h>
-#define FFprint(a...) printk(KERN_DEBUG a)
-
#ifndef CONFIG_IP_MULTIPLE_TABLES
static int __net_init fib4_rules_init(struct net *net)
{
struct fib_table *local_table, *main_table;
- local_table = fib_hash_init(RT_TABLE_LOCAL);
+ local_table = fib_hash_table(RT_TABLE_LOCAL);
if (local_table == NULL)
return -ENOMEM;
- main_table = fib_hash_init(RT_TABLE_MAIN);
+ main_table = fib_hash_table(RT_TABLE_MAIN);
if (main_table == NULL)
goto fail;
tb = fib_get_table(net, id);
if (tb)
return tb;
- tb = fib_hash_init(id);
+
+ tb = fib_hash_table(id);
if (!tb)
return NULL;
h = id & (FIB_TABLE_HASHSZ - 1);
}
#endif /* CONFIG_IP_MULTIPLE_TABLES */
+void fib_select_default(struct net *net,
+ const struct flowi *flp, struct fib_result *res)
+{
+ struct fib_table *tb;
+ int table = RT_TABLE_MAIN;
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ if (res->r == NULL || res->r->action != FR_ACT_TO_TBL)
+ return;
+ table = res->r->table;
+#endif
+ tb = fib_get_table(net, table);
+ if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
+ tb->tb_select_default(tb, flp, res);
+}
+
static void fib_flush(struct net *net)
{
int flushed = 0;
* Find the first device with a given source address.
*/
-struct net_device * ip_dev_find(__be32 addr)
+struct net_device * ip_dev_find(struct net *net, __be32 addr)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res;
res.r = NULL;
#endif
- local_table = fib_get_table(&init_net, RT_TABLE_LOCAL);
+ local_table = fib_get_table(net, RT_TABLE_LOCAL);
if (!local_table || local_table->tb_lookup(local_table, &fl, &res))
return NULL;
if (res.type != RTN_LOCAL)
unsigned ret = RTN_BROADCAST;
struct fib_table *local_table;
- if (ipv4_is_zeronet(addr) || ipv4_is_badclass(addr))
+ if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
return RTN_BROADCAST;
if (ipv4_is_multicast(addr))
return RTN_MULTICAST;
struct fib_result res;
int no_addr, rpf;
int ret;
+ struct net *net;
no_addr = rpf = 0;
rcu_read_lock();
if (in_dev == NULL)
goto e_inval;
- if (fib_lookup(&fl, &res))
+ net = dev->nd_net;
+ if (fib_lookup(net, &fl, &res))
goto last_resort;
if (res.type != RTN_UNICAST)
goto e_inval_res;
fl.oif = dev->ifindex;
ret = 0;
- if (fib_lookup(&fl, &res) == 0) {
+ if (fib_lookup(net, &fl, &res) == 0) {
if (res.type == RTN_UNICAST) {
*spec_dst = FIB_RES_PREFSRC(res);
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
return len + nla_total_size(4);
}
-static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
+static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
struct fib_config *cfg)
{
__be32 addr;
int plen;
memset(cfg, 0, sizeof(*cfg));
- cfg->fc_nlinfo.nl_net = &init_net;
+ cfg->fc_nlinfo.nl_net = net;
if (rt->rt_dst.sa_family != AF_INET)
return -EAFNOSUPPORT;
colon = strchr(devname, ':');
if (colon)
*colon = 0;
- dev = __dev_get_by_name(&init_net, devname);
+ dev = __dev_get_by_name(net, devname);
if (!dev)
return -ENODEV;
cfg->fc_oif = dev->ifindex;
if (rt->rt_gateway.sa_family == AF_INET && addr) {
cfg->fc_gw = addr;
if (rt->rt_flags & RTF_GATEWAY &&
- inet_addr_type(&init_net, addr) == RTN_UNICAST)
+ inet_addr_type(net, addr) == RTN_UNICAST)
cfg->fc_scope = RT_SCOPE_UNIVERSE;
}
* Handle IP routing ioctl calls. These are used to manipulate the routing tables
*/
-int ip_rt_ioctl(unsigned int cmd, void __user *arg)
+int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct fib_config cfg;
struct rtentry rt;
return -EFAULT;
rtnl_lock();
- err = rtentry_to_fib_config(cmd, &rt, &cfg);
+ err = rtentry_to_fib_config(net, cmd, &rt, &cfg);
if (err == 0) {
struct fib_table *tb;
if (cmd == SIOCDELRT) {
- tb = fib_get_table(&init_net, cfg.fc_table);
+ tb = fib_get_table(net, cfg.fc_table);
if (tb)
err = tb->tb_delete(tb, &cfg);
else
err = -ESRCH;
} else {
- tb = fib_new_table(&init_net, cfg.fc_table);
+ tb = fib_new_table(net, cfg.fc_table);
if (tb)
err = tb->tb_insert(tb, &cfg);
else
[RTA_FLOW] = { .type = NLA_U32 },
};
-static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
- struct fib_config *cfg)
+static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
+ struct nlmsghdr *nlh, struct fib_config *cfg)
{
struct nlattr *attr;
int err, remaining;
cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
cfg->fc_nlinfo.nlh = nlh;
- cfg->fc_nlinfo.nl_net = &init_net;
+ cfg->fc_nlinfo.nl_net = net;
if (cfg->fc_type > RTN_MAX) {
err = -EINVAL;
struct fib_table *tb;
int err;
- if (net != &init_net)
- return -EINVAL;
-
- err = rtm_to_fib_config(skb, nlh, &cfg);
+ err = rtm_to_fib_config(net, skb, nlh, &cfg);
if (err < 0)
goto errout;
struct fib_table *tb;
int err;
- if (net != &init_net)
- return -EINVAL;
-
- err = rtm_to_fib_config(skb, nlh, &cfg);
+ err = rtm_to_fib_config(net, skb, nlh, &cfg);
if (err < 0)
goto errout;
- tb = fib_new_table(&init_net, cfg.fc_table);
+ tb = fib_new_table(net, cfg.fc_table);
if (tb == NULL) {
err = -ENOBUFS;
goto errout;
struct hlist_head *head;
int dumped = 0;
- if (net != &init_net)
- return 0;
-
if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED)
return ip_rt_dump(skb, cb);
static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
{
+ struct net *net = ifa->ifa_dev->dev->nd_net;
struct fib_table *tb;
struct fib_config cfg = {
.fc_protocol = RTPROT_KERNEL,
.fc_oif = ifa->ifa_dev->dev->ifindex,
.fc_nlflags = NLM_F_CREATE | NLM_F_APPEND,
.fc_nlinfo = {
- .nl_net = &init_net,
+ .nl_net = net,
},
};
if (type == RTN_UNICAST)
- tb = fib_new_table(&init_net, RT_TABLE_MAIN);
+ tb = fib_new_table(net, RT_TABLE_MAIN);
else
- tb = fib_new_table(&init_net, RT_TABLE_LOCAL);
+ tb = fib_new_table(net, RT_TABLE_LOCAL);
if (tb == NULL)
return;
if (ifa->ifa_flags&IFA_F_SECONDARY) {
prim = inet_ifa_byprefix(in_dev, prefix, mask);
if (prim == NULL) {
- printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n");
+ printk(KERN_WARNING "fib_add_ifaddr: bug: prim == NULL\n");
return;
}
}
else {
prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
if (prim == NULL) {
- printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n");
+ printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL\n");
return;
}
}
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
/* Check, that this local address finally disappeared. */
- if (inet_addr_type(&init_net, ifa->ifa_local) != RTN_LOCAL) {
+ if (inet_addr_type(dev->nd_net, ifa->ifa_local) != RTN_LOCAL) {
/* And the last, but not the least thing.
We must flush stray FIB entries.
First of all, we scan fib_info list searching
for stray nexthop entries, then ignite fib_flush.
*/
- if (fib_sync_down(ifa->ifa_local, NULL, 0))
- fib_flush(&init_net);
+ if (fib_sync_down_addr(dev->nd_net, ifa->ifa_local))
+ fib_flush(dev->nd_net);
}
}
#undef LOCAL_OK
nl_fib_input, NULL, THIS_MODULE);
if (sk == NULL)
return -EAFNOSUPPORT;
- /* Don't hold an extra reference on the namespace */
- put_net(sk->sk_net);
net->ipv4.fibnl = sk;
return 0;
}
static void nl_fib_lookup_exit(struct net *net)
{
- /* At the last minute lie and say this is a socket for the
- * initial network namespace. So the socket will be safe to free.
- */
- net->ipv4.fibnl->sk_net = get_net(&init_net);
- sock_put(net->ipv4.fibnl);
+ netlink_kernel_release(net->ipv4.fibnl);
+ net->ipv4.fibnl = NULL;
}
static void fib_disable_ip(struct net_device *dev, int force)
{
- if (fib_sync_down(0, dev, force))
- fib_flush(&init_net);
+ if (fib_sync_down_dev(dev, force))
+ fib_flush(dev->nd_net);
rt_cache_flush(0);
arp_ifdown(dev);
}
struct net_device *dev = ptr;
struct in_device *in_dev = __in_dev_get_rtnl(dev);
- if (dev->nd_net != &init_net)
- return NOTIFY_DONE;
-
if (event == NETDEV_UNREGISTER) {
fib_disable_ip(dev, 2);
return NOTIFY_DONE;
static int __net_init ip_fib_net_init(struct net *net)
{
+ int err;
unsigned int i;
net->ipv4.fib_table_hash = kzalloc(
for (i = 0; i < FIB_TABLE_HASHSZ; i++)
INIT_HLIST_HEAD(&net->ipv4.fib_table_hash[i]);
- return fib4_rules_init(net);
+ err = fib4_rules_init(net);
+ if (err < 0)
+ goto fail;
+ return 0;
+
+fail:
+ kfree(net->ipv4.fib_table_hash);
+ return err;
}
static void __net_exit ip_fib_net_exit(struct net *net)
{
int error;
- error = 0;
- if (net != &init_net)
- goto out;
-
error = ip_fib_net_init(net);
if (error < 0)
goto out;
register_pernet_subsys(&fib_net_ops);
register_netdevice_notifier(&fib_netdev_notifier);
register_inetaddr_notifier(&fib_inetaddr_notifier);
+
+ fib_hash_init();
}
EXPORT_SYMBOL(inet_addr_type);