Skip to content

Commit bdaf32c

Browse files
serhepopovychdavem330
authored andcommitted
fib_rules: Resolve goto rules target on delete
We should avoid marking goto rules unresolved when their target is actually reachable after rule deletion. Consolder following sample scenario: # ip -4 ru sh 0: from all lookup local 32000: from all goto 32100 32100: from all lookup main 32100: from all lookup default 32766: from all lookup main 32767: from all lookup default # ip -4 ru del pref 32100 table main # ip -4 ru sh 0: from all lookup local 32000: from all goto 32100 [unresolved] 32100: from all lookup default 32766: from all lookup main 32767: from all lookup default After removal of first rule with preference 32100 we mark all goto rules as unreachable, even when rule with same preference as removed one still present. Check if next rule with same preference is available and make all rules with goto action pointing to it. Signed-off-by: Serhey Popovych <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 86fdb34 commit bdaf32c

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

net/core/fib_rules.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
568568
struct net *net = sock_net(skb->sk);
569569
struct fib_rule_hdr *frh = nlmsg_data(nlh);
570570
struct fib_rules_ops *ops = NULL;
571-
struct fib_rule *rule, *tmp;
571+
struct fib_rule *rule, *r;
572572
struct nlattr *tb[FRA_MAX+1];
573573
struct fib_kuid_range range;
574574
int err = -EINVAL;
@@ -668,16 +668,23 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
668668

669669
/*
670670
* Check if this rule is a target to any of them. If so,
671+
* adjust to the next one with the same preference or
671672
* disable them. As this operation is eventually very
672-
* expensive, it is only performed if goto rules have
673-
* actually been added.
673+
* expensive, it is only performed if goto rules, except
674+
* current if it is goto rule, have actually been added.
674675
*/
675676
if (ops->nr_goto_rules > 0) {
676-
list_for_each_entry(tmp, &ops->rules_list, list) {
677-
if (rtnl_dereference(tmp->ctarget) == rule) {
678-
RCU_INIT_POINTER(tmp->ctarget, NULL);
677+
struct fib_rule *n;
678+
679+
n = list_next_entry(rule, list);
680+
if (&n->list == &ops->rules_list || n->pref != rule->pref)
681+
n = NULL;
682+
list_for_each_entry(r, &ops->rules_list, list) {
683+
if (rtnl_dereference(r->ctarget) != rule)
684+
continue;
685+
rcu_assign_pointer(r->ctarget, n);
686+
if (!n)
679687
ops->unresolved_rules++;
680-
}
681688
}
682689
}
683690

0 commit comments

Comments
 (0)