Skip to content

Commit f3737ed

Browse files
committed
Merge branch 'fib-rules-convert-rtm_newrule-and-rtm_delrule-to-per-netns-rtnl'
Kuniyuki Iwashima says: ==================== fib: rules: Convert RTM_NEWRULE and RTM_DELRULE to per-netns RTNL. Patch 1 ~ 2 are small cleanup, and patch 3 ~ 8 make fib_nl_newrule() and fib_nl_delrule() hold per-netns RTNL. v1: https://lore.kernel.org/20250206084629.16602-1-kuniyu@amazon.com ==================== Link: https://patch.msgid.link/20250207072502.87775-1-kuniyu@amazon.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 51b2483 + 88b9cfc commit f3737ed

File tree

5 files changed

+110
-63
lines changed

5 files changed

+110
-63
lines changed

drivers/net/vrf.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,14 +1537,12 @@ static int vrf_fib_rule(const struct net_device *dev, __u8 family, bool add_it)
15371537

15381538
nlmsg_end(skb, nlh);
15391539

1540-
/* fib_nl_{new,del}rule handling looks for net from skb->sk */
1541-
skb->sk = dev_net(dev)->rtnl;
15421540
if (add_it) {
1543-
err = fib_nl_newrule(skb, nlh, NULL);
1541+
err = fib_newrule(dev_net(dev), skb, nlh, NULL, true);
15441542
if (err == -EEXIST)
15451543
err = 0;
15461544
} else {
1547-
err = fib_nl_delrule(skb, nlh, NULL);
1545+
err = fib_delrule(dev_net(dev), skb, nlh, NULL, true);
15481546
if (err == -ENOENT)
15491547
err = 0;
15501548
}

include/net/fib_rules.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,10 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,
178178
struct netlink_ext_ack *extack);
179179
unsigned int fib_rules_seq_read(const struct net *net, int family);
180180

181-
int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
182-
struct netlink_ext_ack *extack);
183-
int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
184-
struct netlink_ext_ack *extack);
181+
int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
182+
struct netlink_ext_ack *extack, bool rtnl_held);
183+
int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
184+
struct netlink_ext_ack *extack, bool rtnl_held);
185185

186186
INDIRECT_CALLABLE_DECLARE(int fib6_rule_match(struct fib_rule *rule,
187187
struct flowi *fl, int flags));

net/core/fib_rules.c

Lines changed: 100 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,8 @@ static int call_fib_rule_notifiers(struct net *net,
371371
.rule = rule,
372372
};
373373

374-
ASSERT_RTNL();
374+
ASSERT_RTNL_NET(net);
375+
375376
/* Paired with READ_ONCE() in fib_rules_seq() */
376377
WRITE_ONCE(ops->fib_rules_seq, ops->fib_rules_seq + 1);
377378
return call_fib_notifiers(net, event_type, &info.info);
@@ -459,9 +460,6 @@ static struct fib_rule *rule_find(struct fib_rules_ops *ops,
459460
if (rule->tun_id && r->tun_id != rule->tun_id)
460461
continue;
461462

462-
if (r->fr_net != rule->fr_net)
463-
continue;
464-
465463
if (rule->l3mdev && r->l3mdev != rule->l3mdev)
466464
continue;
467465

@@ -515,14 +513,13 @@ static int fib_nl2rule_l3mdev(struct nlattr *nla, struct fib_rule *nlrule,
515513
}
516514
#endif
517515

518-
static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
516+
static int fib_nl2rule(struct net *net, struct nlmsghdr *nlh,
519517
struct netlink_ext_ack *extack,
520518
struct fib_rules_ops *ops,
521519
struct nlattr *tb[],
522520
struct fib_rule **rule,
523521
bool *user_priority)
524522
{
525-
struct net *net = sock_net(skb->sk);
526523
struct fib_rule_hdr *frh = nlmsg_data(nlh);
527524
struct fib_rule *nlrule = NULL;
528525
int err = -EINVAL;
@@ -554,30 +551,18 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
554551
if (tb[FRA_PRIORITY]) {
555552
nlrule->pref = nla_get_u32(tb[FRA_PRIORITY]);
556553
*user_priority = true;
557-
} else {
558-
nlrule->pref = fib_default_rule_pref(ops);
559554
}
560555

561556
nlrule->proto = nla_get_u8_default(tb[FRA_PROTOCOL], RTPROT_UNSPEC);
562557

563558
if (tb[FRA_IIFNAME]) {
564-
struct net_device *dev;
565-
566559
nlrule->iifindex = -1;
567560
nla_strscpy(nlrule->iifname, tb[FRA_IIFNAME], IFNAMSIZ);
568-
dev = __dev_get_by_name(net, nlrule->iifname);
569-
if (dev)
570-
nlrule->iifindex = dev->ifindex;
571561
}
572562

573563
if (tb[FRA_OIFNAME]) {
574-
struct net_device *dev;
575-
576564
nlrule->oifindex = -1;
577565
nla_strscpy(nlrule->oifname, tb[FRA_OIFNAME], IFNAMSIZ);
578-
dev = __dev_get_by_name(net, nlrule->oifname);
579-
if (dev)
580-
nlrule->oifindex = dev->ifindex;
581566
}
582567

583568
if (tb[FRA_FWMARK]) {
@@ -619,11 +604,6 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
619604
}
620605

621606
nlrule->target = nla_get_u32(tb[FRA_GOTO]);
622-
/* Backward jumps are prohibited to avoid endless loops */
623-
if (nlrule->target <= nlrule->pref) {
624-
NL_SET_ERR_MSG(extack, "Backward goto not supported");
625-
goto errout_free;
626-
}
627607
} else if (nlrule->action == FR_ACT_GOTO) {
628608
NL_SET_ERR_MSG(extack, "Missing goto target for action goto");
629609
goto errout_free;
@@ -683,6 +663,39 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
683663
return err;
684664
}
685665

666+
static int fib_nl2rule_rtnl(struct fib_rule *nlrule,
667+
struct fib_rules_ops *ops,
668+
struct nlattr *tb[],
669+
struct netlink_ext_ack *extack)
670+
{
671+
if (!tb[FRA_PRIORITY])
672+
nlrule->pref = fib_default_rule_pref(ops);
673+
674+
/* Backward jumps are prohibited to avoid endless loops */
675+
if (tb[FRA_GOTO] && nlrule->target <= nlrule->pref) {
676+
NL_SET_ERR_MSG(extack, "Backward goto not supported");
677+
return -EINVAL;
678+
}
679+
680+
if (tb[FRA_IIFNAME]) {
681+
struct net_device *dev;
682+
683+
dev = __dev_get_by_name(nlrule->fr_net, nlrule->iifname);
684+
if (dev)
685+
nlrule->iifindex = dev->ifindex;
686+
}
687+
688+
if (tb[FRA_OIFNAME]) {
689+
struct net_device *dev;
690+
691+
dev = __dev_get_by_name(nlrule->fr_net, nlrule->oifname);
692+
if (dev)
693+
nlrule->oifindex = dev->ifindex;
694+
}
695+
696+
return 0;
697+
}
698+
686699
static int rule_exists(struct fib_rules_ops *ops, struct fib_rule_hdr *frh,
687700
struct nlattr **tb, struct fib_rule *rule)
688701
{
@@ -719,9 +732,6 @@ static int rule_exists(struct fib_rules_ops *ops, struct fib_rule_hdr *frh,
719732
if (r->tun_id != rule->tun_id)
720733
continue;
721734

722-
if (r->fr_net != rule->fr_net)
723-
continue;
724-
725735
if (r->l3mdev != rule->l3mdev)
726736
continue;
727737

@@ -774,15 +784,14 @@ static const struct nla_policy fib_rule_policy[FRA_MAX + 1] = {
774784
[FRA_FLOWLABEL_MASK] = { .type = NLA_BE32 },
775785
};
776786

777-
int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
778-
struct netlink_ext_ack *extack)
787+
int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
788+
struct netlink_ext_ack *extack, bool rtnl_held)
779789
{
780-
struct net *net = sock_net(skb->sk);
790+
struct fib_rule *rule = NULL, *r, *last = NULL;
781791
struct fib_rule_hdr *frh = nlmsg_data(nlh);
792+
int err = -EINVAL, unresolved = 0;
782793
struct fib_rules_ops *ops = NULL;
783-
struct fib_rule *rule = NULL, *r, *last = NULL;
784794
struct nlattr *tb[FRA_MAX + 1];
785-
int err = -EINVAL, unresolved = 0;
786795
bool user_priority = false;
787796

788797
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) {
@@ -804,10 +813,17 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
804813
goto errout;
805814
}
806815

807-
err = fib_nl2rule(skb, nlh, extack, ops, tb, &rule, &user_priority);
816+
err = fib_nl2rule(net, nlh, extack, ops, tb, &rule, &user_priority);
808817
if (err)
809818
goto errout;
810819

820+
if (!rtnl_held)
821+
rtnl_net_lock(net);
822+
823+
err = fib_nl2rule_rtnl(rule, ops, tb, extack);
824+
if (err)
825+
goto errout_free;
826+
811827
if ((nlh->nlmsg_flags & NLM_F_EXCL) &&
812828
rule_exists(ops, frh, tb, rule)) {
813829
err = -EEXIST;
@@ -869,29 +885,42 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
869885
if (rule->tun_id)
870886
ip_tunnel_need_metadata();
871887

888+
fib_rule_get(rule);
889+
890+
if (!rtnl_held)
891+
rtnl_net_unlock(net);
892+
872893
notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
894+
fib_rule_put(rule);
873895
flush_route_cache(ops);
874896
rules_ops_put(ops);
875897
return 0;
876898

877899
errout_free:
900+
if (!rtnl_held)
901+
rtnl_net_unlock(net);
878902
kfree(rule);
879903
errout:
880904
rules_ops_put(ops);
881905
return err;
882906
}
883-
EXPORT_SYMBOL_GPL(fib_nl_newrule);
907+
EXPORT_SYMBOL_GPL(fib_newrule);
884908

885-
int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
886-
struct netlink_ext_ack *extack)
909+
static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
910+
struct netlink_ext_ack *extack)
887911
{
888-
struct net *net = sock_net(skb->sk);
912+
return fib_newrule(sock_net(skb->sk), skb, nlh, extack, false);
913+
}
914+
915+
int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
916+
struct netlink_ext_ack *extack, bool rtnl_held)
917+
{
918+
struct fib_rule *rule = NULL, *nlrule = NULL;
889919
struct fib_rule_hdr *frh = nlmsg_data(nlh);
890920
struct fib_rules_ops *ops = NULL;
891-
struct fib_rule *rule = NULL, *r, *nlrule = NULL;
892921
struct nlattr *tb[FRA_MAX+1];
893-
int err = -EINVAL;
894922
bool user_priority = false;
923+
int err = -EINVAL;
895924

896925
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) {
897926
NL_SET_ERR_MSG(extack, "Invalid msg length");
@@ -912,25 +941,32 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
912941
goto errout;
913942
}
914943

915-
err = fib_nl2rule(skb, nlh, extack, ops, tb, &nlrule, &user_priority);
944+
err = fib_nl2rule(net, nlh, extack, ops, tb, &nlrule, &user_priority);
916945
if (err)
917946
goto errout;
918947

948+
if (!rtnl_held)
949+
rtnl_net_lock(net);
950+
951+
err = fib_nl2rule_rtnl(nlrule, ops, tb, extack);
952+
if (err)
953+
goto errout_free;
954+
919955
rule = rule_find(ops, frh, tb, nlrule, user_priority);
920956
if (!rule) {
921957
err = -ENOENT;
922-
goto errout;
958+
goto errout_free;
923959
}
924960

925961
if (rule->flags & FIB_RULE_PERMANENT) {
926962
err = -EPERM;
927-
goto errout;
963+
goto errout_free;
928964
}
929965

930966
if (ops->delete) {
931967
err = ops->delete(rule);
932968
if (err)
933-
goto errout;
969+
goto errout_free;
934970
}
935971

936972
if (rule->tun_id)
@@ -952,7 +988,7 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
952988
* current if it is goto rule, have actually been added.
953989
*/
954990
if (ops->nr_goto_rules > 0) {
955-
struct fib_rule *n;
991+
struct fib_rule *n, *r;
956992

957993
n = list_next_entry(rule, list);
958994
if (&n->list == &ops->rules_list || n->pref != rule->pref)
@@ -966,22 +1002,33 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
9661002
}
9671003
}
9681004

969-
call_fib_rule_notifiers(net, FIB_EVENT_RULE_DEL, rule, ops,
970-
NULL);
971-
notify_rule_change(RTM_DELRULE, rule, ops, nlh,
972-
NETLINK_CB(skb).portid);
1005+
call_fib_rule_notifiers(net, FIB_EVENT_RULE_DEL, rule, ops, NULL);
1006+
1007+
if (!rtnl_held)
1008+
rtnl_net_unlock(net);
1009+
1010+
notify_rule_change(RTM_DELRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
9731011
fib_rule_put(rule);
9741012
flush_route_cache(ops);
9751013
rules_ops_put(ops);
9761014
kfree(nlrule);
9771015
return 0;
9781016

979-
errout:
1017+
errout_free:
1018+
if (!rtnl_held)
1019+
rtnl_net_unlock(net);
9801020
kfree(nlrule);
1021+
errout:
9811022
rules_ops_put(ops);
9821023
return err;
9831024
}
984-
EXPORT_SYMBOL_GPL(fib_nl_delrule);
1025+
EXPORT_SYMBOL_GPL(fib_delrule);
1026+
1027+
static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
1028+
struct netlink_ext_ack *extack)
1029+
{
1030+
return fib_delrule(sock_net(skb->sk), skb, nlh, extack, false);
1031+
}
9851032

9861033
static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
9871034
struct fib_rule *rule)
@@ -1293,8 +1340,10 @@ static struct pernet_operations fib_rules_net_ops = {
12931340
};
12941341

12951342
static const struct rtnl_msg_handler fib_rules_rtnl_msg_handlers[] __initconst = {
1296-
{.msgtype = RTM_NEWRULE, .doit = fib_nl_newrule},
1297-
{.msgtype = RTM_DELRULE, .doit = fib_nl_delrule},
1343+
{.msgtype = RTM_NEWRULE, .doit = fib_nl_newrule,
1344+
.flags = RTNL_FLAG_DOIT_PERNET},
1345+
{.msgtype = RTM_DELRULE, .doit = fib_nl_delrule,
1346+
.flags = RTNL_FLAG_DOIT_PERNET},
12981347
{.msgtype = RTM_GETRULE, .dumpit = fib_nl_dumprule,
12991348
.flags = RTNL_FLAG_DUMP_UNLOCKED},
13001349
};

net/ipv4/fib_rules.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,9 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
245245
struct nlattr **tb,
246246
struct netlink_ext_ack *extack)
247247
{
248-
struct net *net = sock_net(skb->sk);
248+
struct fib4_rule *rule4 = (struct fib4_rule *)rule;
249+
struct net *net = rule->fr_net;
249250
int err = -EINVAL;
250-
struct fib4_rule *rule4 = (struct fib4_rule *) rule;
251251

252252
if (tb[FRA_FLOWLABEL] || tb[FRA_FLOWLABEL_MASK]) {
253253
NL_SET_ERR_MSG(extack,

net/ipv6/fib6_rules.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,9 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
399399
struct nlattr **tb,
400400
struct netlink_ext_ack *extack)
401401
{
402+
struct fib6_rule *rule6 = (struct fib6_rule *)rule;
403+
struct net *net = rule->fr_net;
402404
int err = -EINVAL;
403-
struct net *net = sock_net(skb->sk);
404-
struct fib6_rule *rule6 = (struct fib6_rule *) rule;
405405

406406
if (!inet_validate_dscp(frh->tos)) {
407407
NL_SET_ERR_MSG(extack,

0 commit comments

Comments
 (0)