aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopa Prabhu <roopa@cumulusnetworks.com>2018-02-28 22:40:16 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-28 22:44:43 -0500
commitbfff4862653bb96001ab57c1edd6d03f48e5f035 (patch)
tree463387f66425eff78e5aff19a5c3965f85c6c082
parent292749915743758013e290c994f41de196d47498 (diff)
net: fib_rules: support for match on ip_proto, sport and dport
uapi for ip_proto, sport and dport range match in fib rules. Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/fib_rules.h36
-rw-r--r--include/uapi/linux/fib_rules.h8
-rw-r--r--net/core/fib_rules.c92
3 files changed, 133 insertions, 3 deletions
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index b3d216249240..6dd0a00653ae 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -27,7 +27,7 @@ struct fib_rule {
27 u8 action; 27 u8 action;
28 u8 l3mdev; 28 u8 l3mdev;
29 u8 proto; 29 u8 proto;
30 /* 1 byte hole, try to use */ 30 u8 ip_proto;
31 u32 target; 31 u32 target;
32 __be64 tun_id; 32 __be64 tun_id;
33 struct fib_rule __rcu *ctarget; 33 struct fib_rule __rcu *ctarget;
@@ -40,6 +40,8 @@ struct fib_rule {
40 char iifname[IFNAMSIZ]; 40 char iifname[IFNAMSIZ];
41 char oifname[IFNAMSIZ]; 41 char oifname[IFNAMSIZ];
42 struct fib_kuid_range uid_range; 42 struct fib_kuid_range uid_range;
43 struct fib_rule_port_range sport_range;
44 struct fib_rule_port_range dport_range;
43 struct rcu_head rcu; 45 struct rcu_head rcu;
44}; 46};
45 47
@@ -144,6 +146,38 @@ static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla)
144 return frh->table; 146 return frh->table;
145} 147}
146 148
149static inline bool fib_rule_port_range_set(const struct fib_rule_port_range *range)
150{
151 return range->start != 0 && range->end != 0;
152}
153
154static inline bool fib_rule_port_inrange(const struct fib_rule_port_range *a,
155 __be16 port)
156{
157 return ntohs(port) >= a->start &&
158 ntohs(port) <= a->end;
159}
160
161static inline bool fib_rule_port_range_valid(const struct fib_rule_port_range *a)
162{
163 return a->start != 0 && a->end != 0 && a->end < 0xffff &&
164 a->start <= a->end;
165}
166
167static inline bool fib_rule_port_range_compare(struct fib_rule_port_range *a,
168 struct fib_rule_port_range *b)
169{
170 return a->start == b->start &&
171 a->end == b->end;
172}
173
174static inline bool fib_rule_requires_fldissect(struct fib_rule *rule)
175{
176 return rule->ip_proto ||
177 fib_rule_port_range_set(&rule->sport_range) ||
178 fib_rule_port_range_set(&rule->dport_range);
179}
180
147struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *, 181struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *,
148 struct net *); 182 struct net *);
149void fib_rules_unregister(struct fib_rules_ops *); 183void fib_rules_unregister(struct fib_rules_ops *);
diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
index 77d90ae38114..232df14e1287 100644
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -35,6 +35,11 @@ struct fib_rule_uid_range {
35 __u32 end; 35 __u32 end;
36}; 36};
37 37
38struct fib_rule_port_range {
39 __u16 start;
40 __u16 end;
41};
42
38enum { 43enum {
39 FRA_UNSPEC, 44 FRA_UNSPEC,
40 FRA_DST, /* destination address */ 45 FRA_DST, /* destination address */
@@ -59,6 +64,9 @@ enum {
59 FRA_L3MDEV, /* iif or oif is l3mdev goto its table */ 64 FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
60 FRA_UID_RANGE, /* UID range */ 65 FRA_UID_RANGE, /* UID range */
61 FRA_PROTOCOL, /* Originator of the rule */ 66 FRA_PROTOCOL, /* Originator of the rule */
67 FRA_IP_PROTO, /* ip proto */
68 FRA_SPORT_RANGE, /* sport */
69 FRA_DPORT_RANGE, /* dport */
62 __FRA_MAX 70 __FRA_MAX
63}; 71};
64 72
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index a6aea805a0a2..f6f04fc0f629 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -33,6 +33,10 @@ bool fib_rule_matchall(const struct fib_rule *rule)
33 if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) || 33 if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) ||
34 !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end)) 34 !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end))
35 return false; 35 return false;
36 if (fib_rule_port_range_set(&rule->sport_range))
37 return false;
38 if (fib_rule_port_range_set(&rule->dport_range))
39 return false;
36 return true; 40 return true;
37} 41}
38EXPORT_SYMBOL_GPL(fib_rule_matchall); 42EXPORT_SYMBOL_GPL(fib_rule_matchall);
@@ -221,6 +225,26 @@ static int nla_put_uid_range(struct sk_buff *skb, struct fib_kuid_range *range)
221 return nla_put(skb, FRA_UID_RANGE, sizeof(out), &out); 225 return nla_put(skb, FRA_UID_RANGE, sizeof(out), &out);
222} 226}
223 227
228static int nla_get_port_range(struct nlattr *pattr,
229 struct fib_rule_port_range *port_range)
230{
231 const struct fib_rule_port_range *pr = nla_data(pattr);
232
233 if (!fib_rule_port_range_valid(pr))
234 return -EINVAL;
235
236 port_range->start = pr->start;
237 port_range->end = pr->end;
238
239 return 0;
240}
241
242static int nla_put_port_range(struct sk_buff *skb, int attrtype,
243 struct fib_rule_port_range *range)
244{
245 return nla_put(skb, attrtype, sizeof(*range), range);
246}
247
224static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, 248static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
225 struct flowi *fl, int flags, 249 struct flowi *fl, int flags,
226 struct fib_lookup_arg *arg) 250 struct fib_lookup_arg *arg)
@@ -425,6 +449,17 @@ static int rule_exists(struct fib_rules_ops *ops, struct fib_rule_hdr *frh,
425 !uid_eq(r->uid_range.end, rule->uid_range.end)) 449 !uid_eq(r->uid_range.end, rule->uid_range.end))
426 continue; 450 continue;
427 451
452 if (r->ip_proto != rule->ip_proto)
453 continue;
454
455 if (!fib_rule_port_range_compare(&r->sport_range,
456 &rule->sport_range))
457 continue;
458
459 if (!fib_rule_port_range_compare(&r->dport_range,
460 &rule->dport_range))
461 continue;
462
428 if (!ops->compare(r, frh, tb)) 463 if (!ops->compare(r, frh, tb))
429 continue; 464 continue;
430 return 1; 465 return 1;
@@ -569,6 +604,23 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
569 rule->uid_range = fib_kuid_range_unset; 604 rule->uid_range = fib_kuid_range_unset;
570 } 605 }
571 606
607 if (tb[FRA_IP_PROTO])
608 rule->ip_proto = nla_get_u8(tb[FRA_IP_PROTO]);
609
610 if (tb[FRA_SPORT_RANGE]) {
611 err = nla_get_port_range(tb[FRA_SPORT_RANGE],
612 &rule->sport_range);
613 if (err)
614 goto errout_free;
615 }
616
617 if (tb[FRA_DPORT_RANGE]) {
618 err = nla_get_port_range(tb[FRA_DPORT_RANGE],
619 &rule->dport_range);
620 if (err)
621 goto errout_free;
622 }
623
572 if ((nlh->nlmsg_flags & NLM_F_EXCL) && 624 if ((nlh->nlmsg_flags & NLM_F_EXCL) &&
573 rule_exists(ops, frh, tb, rule)) { 625 rule_exists(ops, frh, tb, rule)) {
574 err = -EEXIST; 626 err = -EEXIST;
@@ -634,6 +686,8 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
634{ 686{
635 struct net *net = sock_net(skb->sk); 687 struct net *net = sock_net(skb->sk);
636 struct fib_rule_hdr *frh = nlmsg_data(nlh); 688 struct fib_rule_hdr *frh = nlmsg_data(nlh);
689 struct fib_rule_port_range sprange = {0, 0};
690 struct fib_rule_port_range dprange = {0, 0};
637 struct fib_rules_ops *ops = NULL; 691 struct fib_rules_ops *ops = NULL;
638 struct fib_rule *rule, *r; 692 struct fib_rule *rule, *r;
639 struct nlattr *tb[FRA_MAX+1]; 693 struct nlattr *tb[FRA_MAX+1];
@@ -667,6 +721,20 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
667 range = fib_kuid_range_unset; 721 range = fib_kuid_range_unset;
668 } 722 }
669 723
724 if (tb[FRA_SPORT_RANGE]) {
725 err = nla_get_port_range(tb[FRA_SPORT_RANGE],
726 &sprange);
727 if (err)
728 goto errout;
729 }
730
731 if (tb[FRA_DPORT_RANGE]) {
732 err = nla_get_port_range(tb[FRA_DPORT_RANGE],
733 &dprange);
734 if (err)
735 goto errout;
736 }
737
670 list_for_each_entry(rule, &ops->rules_list, list) { 738 list_for_each_entry(rule, &ops->rules_list, list) {
671 if (tb[FRA_PROTOCOL] && 739 if (tb[FRA_PROTOCOL] &&
672 (rule->proto != nla_get_u8(tb[FRA_PROTOCOL]))) 740 (rule->proto != nla_get_u8(tb[FRA_PROTOCOL])))
@@ -712,6 +780,18 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
712 !uid_eq(rule->uid_range.end, range.end))) 780 !uid_eq(rule->uid_range.end, range.end)))
713 continue; 781 continue;
714 782
783 if (tb[FRA_IP_PROTO] &&
784 (rule->ip_proto != nla_get_u8(tb[FRA_IP_PROTO])))
785 continue;
786
787 if (fib_rule_port_range_set(&sprange) &&
788 !fib_rule_port_range_compare(&rule->sport_range, &sprange))
789 continue;
790
791 if (fib_rule_port_range_set(&dprange) &&
792 !fib_rule_port_range_compare(&rule->dport_range, &dprange))
793 continue;
794
715 if (!ops->compare(rule, frh, tb)) 795 if (!ops->compare(rule, frh, tb))
716 continue; 796 continue;
717 797
@@ -790,7 +870,10 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
790 + nla_total_size(4) /* FRA_FWMASK */ 870 + nla_total_size(4) /* FRA_FWMASK */
791 + nla_total_size_64bit(8) /* FRA_TUN_ID */ 871 + nla_total_size_64bit(8) /* FRA_TUN_ID */
792 + nla_total_size(sizeof(struct fib_kuid_range)) 872 + nla_total_size(sizeof(struct fib_kuid_range))
793 + nla_total_size(1); /* FRA_PROTOCOL */ 873 + nla_total_size(1) /* FRA_PROTOCOL */
874 + nla_total_size(1) /* FRA_IP_PROTO */
875 + nla_total_size(sizeof(struct fib_rule_port_range)) /* FRA_SPORT_RANGE */
876 + nla_total_size(sizeof(struct fib_rule_port_range)); /* FRA_DPORT_RANGE */
794 877
795 if (ops->nlmsg_payload) 878 if (ops->nlmsg_payload)
796 payload += ops->nlmsg_payload(rule); 879 payload += ops->nlmsg_payload(rule);
@@ -855,7 +938,12 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
855 (rule->l3mdev && 938 (rule->l3mdev &&
856 nla_put_u8(skb, FRA_L3MDEV, rule->l3mdev)) || 939 nla_put_u8(skb, FRA_L3MDEV, rule->l3mdev)) ||
857 (uid_range_set(&rule->uid_range) && 940 (uid_range_set(&rule->uid_range) &&
858 nla_put_uid_range(skb, &rule->uid_range))) 941 nla_put_uid_range(skb, &rule->uid_range)) ||
942 (fib_rule_port_range_set(&rule->sport_range) &&
943 nla_put_port_range(skb, FRA_SPORT_RANGE, &rule->sport_range)) ||
944 (fib_rule_port_range_set(&rule->dport_range) &&
945 nla_put_port_range(skb, FRA_DPORT_RANGE, &rule->dport_range)) ||
946 (rule->ip_proto && nla_put_u8(skb, FRA_IP_PROTO, rule->ip_proto)))
859 goto nla_put_failure; 947 goto nla_put_failure;
860 948
861 if (rule->suppress_ifgroup != -1) { 949 if (rule->suppress_ifgroup != -1) {