Skip to content

Commit

Permalink
Merge branch 'ipv4-fib-convert-rtm_newroute-and-rtm_delroute-to-per-n…
Browse files Browse the repository at this point in the history
…etns-rtnl'

Kuniyuki Iwashima says:

====================
ipv4: fib: Convert RTM_NEWROUTE and RTM_DELROUTE to per-netns RTNL.

Patch 1 is misc cleanup.
Patch 2 ~ 8 converts two fib_info hash tables to per-netns.
Patch 9 ~ 12 converts rtnl_lock() to rtnl_net_lcok().

v2: https://lore.kernel.org/20250226192556.21633-1-kuniyu@amazon.com
v1: https://lore.kernel.org/20250225182250.74650-1-kuniyu@amazon.com
====================

Link: https://patch.msgid.link/20250228042328.96624-1-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Mar 3, 2025
2 parents d110dbf + 1dd2af7 commit 3424291
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 148 deletions.
2 changes: 2 additions & 0 deletions include/net/ip_fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ struct fib_info {
struct fib_nh fib_nh[] __counted_by(fib_nhs);
};

int __net_init fib4_semantics_init(struct net *net);
void __net_exit fib4_semantics_exit(struct net *net);

#ifdef CONFIG_IP_MULTIPLE_TABLES
struct fib_rule;
Expand Down
3 changes: 3 additions & 0 deletions include/net/netns/ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ struct netns_ipv4 {
#endif
struct hlist_head *fib_table_hash;
struct sock *fibnl;
struct hlist_head *fib_info_hash;
unsigned int fib_info_hash_bits;
unsigned int fib_info_cnt;

struct sock *mc_autojoin_sk;

Expand Down
74 changes: 54 additions & 20 deletions net/ipv4/fib_frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,18 +553,16 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
const struct in_ifaddr *ifa;
struct in_device *in_dev;

in_dev = __in_dev_get_rtnl(dev);
in_dev = __in_dev_get_rtnl_net(dev);
if (!in_dev)
return -ENODEV;

*colon = ':';

rcu_read_lock();
in_dev_for_each_ifa_rcu(ifa, in_dev) {
in_dev_for_each_ifa_rtnl_net(net, ifa, in_dev) {
if (strcmp(ifa->ifa_label, devname) == 0)
break;
}
rcu_read_unlock();

if (!ifa)
return -ENODEV;
Expand Down Expand Up @@ -635,7 +633,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, struct rtentry *rt)
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;

rtnl_lock();
rtnl_net_lock(net);
err = rtentry_to_fib_config(net, cmd, rt, &cfg);
if (err == 0) {
struct fib_table *tb;
Expand All @@ -659,7 +657,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, struct rtentry *rt)
/* allocated by rtentry_to_fib_config() */
kfree(cfg.fc_mx);
}
rtnl_unlock();
rtnl_net_unlock(net);
return err;
}
return -EINVAL;
Expand Down Expand Up @@ -837,19 +835,33 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
}
}

if (cfg->fc_dst_len > 32) {
NL_SET_ERR_MSG(extack, "Invalid prefix length");
err = -EINVAL;
goto errout;
}

if (cfg->fc_dst_len < 32 && (ntohl(cfg->fc_dst) << cfg->fc_dst_len)) {
NL_SET_ERR_MSG(extack, "Invalid prefix for given prefix length");
err = -EINVAL;
goto errout;
}

if (cfg->fc_nh_id) {
if (cfg->fc_oif || cfg->fc_gw_family ||
cfg->fc_encap || cfg->fc_mp) {
NL_SET_ERR_MSG(extack,
"Nexthop specification and nexthop id are mutually exclusive");
return -EINVAL;
err = -EINVAL;
goto errout;
}
}

if (has_gw && has_via) {
NL_SET_ERR_MSG(extack,
"Nexthop configuration can not contain both GATEWAY and VIA");
return -EINVAL;
err = -EINVAL;
goto errout;
}

if (!cfg->fc_table)
Expand All @@ -872,20 +884,24 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err < 0)
goto errout;

rtnl_net_lock(net);

if (cfg.fc_nh_id && !nexthop_find_by_id(net, cfg.fc_nh_id)) {
NL_SET_ERR_MSG(extack, "Nexthop id does not exist");
err = -EINVAL;
goto errout;
goto unlock;
}

tb = fib_get_table(net, cfg.fc_table);
if (!tb) {
NL_SET_ERR_MSG(extack, "FIB table does not exist");
err = -ESRCH;
goto errout;
goto unlock;
}

err = fib_table_delete(net, tb, &cfg, extack);
unlock:
rtnl_net_unlock(net);
errout:
return err;
}
Expand All @@ -902,15 +918,20 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err < 0)
goto errout;

rtnl_net_lock(net);

tb = fib_new_table(net, cfg.fc_table);
if (!tb) {
err = -ENOBUFS;
goto errout;
goto unlock;
}

err = fib_table_insert(net, tb, &cfg, extack);
if (!err && cfg.fc_type == RTN_LOCAL)
net->ipv4.fib_has_custom_local_routes = true;

unlock:
rtnl_net_unlock(net);
errout:
return err;
}
Expand Down Expand Up @@ -1450,7 +1471,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
fib_sync_up(dev, RTNH_F_DEAD);
#endif
atomic_inc(&net->ipv4.dev_addr_genid);
rt_cache_flush(dev_net(dev));
rt_cache_flush(net);
break;
case NETDEV_DOWN:
fib_del_ifaddr(ifa, NULL);
Expand All @@ -1461,7 +1482,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
*/
fib_disable_ip(dev, event, true);
} else {
rt_cache_flush(dev_net(dev));
rt_cache_flush(net);
}
break;
}
Expand Down Expand Up @@ -1575,7 +1596,7 @@ static void ip_fib_net_exit(struct net *net)
{
int i;

ASSERT_RTNL();
ASSERT_RTNL_NET(net);
#ifdef CONFIG_IP_MULTIPLE_TABLES
RCU_INIT_POINTER(net->ipv4.fib_main, NULL);
RCU_INIT_POINTER(net->ipv4.fib_default, NULL);
Expand Down Expand Up @@ -1615,9 +1636,15 @@ static int __net_init fib_net_init(struct net *net)
error = ip_fib_net_init(net);
if (error < 0)
goto out;

error = fib4_semantics_init(net);
if (error)
goto out_semantics;

error = nl_fib_lookup_init(net);
if (error < 0)
goto out_nlfl;

error = fib_proc_init(net);
if (error < 0)
goto out_proc;
Expand All @@ -1627,9 +1654,11 @@ static int __net_init fib_net_init(struct net *net)
out_proc:
nl_fib_lookup_exit(net);
out_nlfl:
rtnl_lock();
fib4_semantics_exit(net);
out_semantics:
rtnl_net_lock(net);
ip_fib_net_exit(net);
rtnl_unlock();
rtnl_net_unlock(net);
goto out;
}

Expand All @@ -1644,10 +1673,15 @@ static void __net_exit fib_net_exit_batch(struct list_head *net_list)
struct net *net;

rtnl_lock();
list_for_each_entry(net, net_list, exit_list)
list_for_each_entry(net, net_list, exit_list) {
__rtnl_net_lock(net);
ip_fib_net_exit(net);

__rtnl_net_unlock(net);
}
rtnl_unlock();

list_for_each_entry(net, net_list, exit_list)
fib4_semantics_exit(net);
}

static struct pernet_operations fib_net_ops = {
Expand All @@ -1658,9 +1692,9 @@ static struct pernet_operations fib_net_ops = {

static const struct rtnl_msg_handler fib_rtnl_msg_handlers[] __initconst = {
{.protocol = PF_INET, .msgtype = RTM_NEWROUTE,
.doit = inet_rtm_newroute},
.doit = inet_rtm_newroute, .flags = RTNL_FLAG_DOIT_PERNET},
{.protocol = PF_INET, .msgtype = RTM_DELROUTE,
.doit = inet_rtm_delroute},
.doit = inet_rtm_delroute, .flags = RTNL_FLAG_DOIT_PERNET},
{.protocol = PF_INET, .msgtype = RTM_GETROUTE, .dumpit = inet_dump_fib,
.flags = RTNL_FLAG_DUMP_UNLOCKED | RTNL_FLAG_DUMP_SPLIT_NLM_DONE},
};
Expand Down
Loading

0 comments on commit 3424291

Please sign in to comment.