diff options
author | Roopa Prabhu <roopa@cumulusnetworks.com> | 2018-06-29 17:32:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-06-30 09:11:13 -0400 |
commit | 35e8c7ba0863acadd4b9badd09740af7a8331125 (patch) | |
tree | 4f64022fc3ee35c5eb4e94ccabccc31c247e700a | |
parent | 3ffe64f1a641b80a82d9ef4efa7a05ce69049871 (diff) |
net: fib_rules: bring back rule_exists to match rule during add
After commit f9d4b0c1e969 ("fib_rules: move common handling of newrule
delrule msgs into fib_nl2rule"), rule_exists got replaced by rule_find
for existing rule lookup in both the add and del paths. While this
is good for the delete path, it solves a few problems but opens up
a few invalid key matches in the add path.
$ip -4 rule add table main tos 10 fwmark 1
$ip -4 rule add table main tos 10
RTNETLINK answers: File exists
The problem here is rule_find does not check if the key masks in
the new and old rule are the same and hence ends up matching a more
secific rule. Rule key masks cannot be easily compared today without
an elaborate if-else block. Its best to introduce key masks for easier
and accurate rule comparison in the future. Until then, due to fear of
regressions this patch re-introduces older loose rule_exists during add.
Also fixes both rule_exists and rule_find to cover missing attributes.
Fixes: f9d4b0c1e969 ("fib_rules: move common handling of newrule delrule msgs into fib_nl2rule")
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/core/fib_rules.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index bc8425d81022..f64aa13811ea 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -444,6 +444,9 @@ static struct fib_rule *rule_find(struct fib_rules_ops *ops, | |||
444 | if (rule->ip_proto && r->ip_proto != rule->ip_proto) | 444 | if (rule->ip_proto && r->ip_proto != rule->ip_proto) |
445 | continue; | 445 | continue; |
446 | 446 | ||
447 | if (rule->proto && r->proto != rule->proto) | ||
448 | continue; | ||
449 | |||
447 | if (fib_rule_port_range_set(&rule->sport_range) && | 450 | if (fib_rule_port_range_set(&rule->sport_range) && |
448 | !fib_rule_port_range_compare(&r->sport_range, | 451 | !fib_rule_port_range_compare(&r->sport_range, |
449 | &rule->sport_range)) | 452 | &rule->sport_range)) |
@@ -653,6 +656,73 @@ errout: | |||
653 | return err; | 656 | return err; |
654 | } | 657 | } |
655 | 658 | ||
659 | static int rule_exists(struct fib_rules_ops *ops, struct fib_rule_hdr *frh, | ||
660 | struct nlattr **tb, struct fib_rule *rule) | ||
661 | { | ||
662 | struct fib_rule *r; | ||
663 | |||
664 | list_for_each_entry(r, &ops->rules_list, list) { | ||
665 | if (r->action != rule->action) | ||
666 | continue; | ||
667 | |||
668 | if (r->table != rule->table) | ||
669 | continue; | ||
670 | |||
671 | if (r->pref != rule->pref) | ||
672 | continue; | ||
673 | |||
674 | if (memcmp(r->iifname, rule->iifname, IFNAMSIZ)) | ||
675 | continue; | ||
676 | |||
677 | if (memcmp(r->oifname, rule->oifname, IFNAMSIZ)) | ||
678 | continue; | ||
679 | |||
680 | if (r->mark != rule->mark) | ||
681 | continue; | ||
682 | |||
683 | if (r->suppress_ifgroup != rule->suppress_ifgroup) | ||
684 | continue; | ||
685 | |||
686 | if (r->suppress_prefixlen != rule->suppress_prefixlen) | ||
687 | continue; | ||
688 | |||
689 | if (r->mark_mask != rule->mark_mask) | ||
690 | continue; | ||
691 | |||
692 | if (r->tun_id != rule->tun_id) | ||
693 | continue; | ||
694 | |||
695 | if (r->fr_net != rule->fr_net) | ||
696 | continue; | ||
697 | |||
698 | if (r->l3mdev != rule->l3mdev) | ||
699 | continue; | ||
700 | |||
701 | if (!uid_eq(r->uid_range.start, rule->uid_range.start) || | ||
702 | !uid_eq(r->uid_range.end, rule->uid_range.end)) | ||
703 | continue; | ||
704 | |||
705 | if (r->ip_proto != rule->ip_proto) | ||
706 | continue; | ||
707 | |||
708 | if (r->proto != rule->proto) | ||
709 | continue; | ||
710 | |||
711 | if (!fib_rule_port_range_compare(&r->sport_range, | ||
712 | &rule->sport_range)) | ||
713 | continue; | ||
714 | |||
715 | if (!fib_rule_port_range_compare(&r->dport_range, | ||
716 | &rule->dport_range)) | ||
717 | continue; | ||
718 | |||
719 | if (!ops->compare(r, frh, tb)) | ||
720 | continue; | ||
721 | return 1; | ||
722 | } | ||
723 | return 0; | ||
724 | } | ||
725 | |||
656 | int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, | 726 | int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, |
657 | struct netlink_ext_ack *extack) | 727 | struct netlink_ext_ack *extack) |
658 | { | 728 | { |
@@ -687,7 +757,7 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
687 | goto errout; | 757 | goto errout; |
688 | 758 | ||
689 | if ((nlh->nlmsg_flags & NLM_F_EXCL) && | 759 | if ((nlh->nlmsg_flags & NLM_F_EXCL) && |
690 | rule_find(ops, frh, tb, rule, user_priority)) { | 760 | rule_exists(ops, frh, tb, rule)) { |
691 | err = -EEXIST; | 761 | err = -EEXIST; |
692 | goto errout_free; | 762 | goto errout_free; |
693 | } | 763 | } |