diff options
-rw-r--r-- | include/net/fib_rules.h | 4 | ||||
-rw-r--r-- | include/uapi/linux/fib_rules.h | 2 | ||||
-rw-r--r-- | net/core/fib_rules.c | 8 | ||||
-rw-r--r-- | net/ipv4/fib_rules.c | 14 | ||||
-rw-r--r-- | net/ipv6/fib6_rules.c | 13 |
5 files changed, 40 insertions, 1 deletions
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index e361f4882426..2f286dce9259 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h | |||
@@ -18,6 +18,7 @@ struct fib_rule { | |||
18 | u32 pref; | 18 | u32 pref; |
19 | u32 flags; | 19 | u32 flags; |
20 | u32 table; | 20 | u32 table; |
21 | u8 table_prefixlen_min; | ||
21 | u8 action; | 22 | u8 action; |
22 | u32 target; | 23 | u32 target; |
23 | struct fib_rule __rcu *ctarget; | 24 | struct fib_rule __rcu *ctarget; |
@@ -46,6 +47,8 @@ struct fib_rules_ops { | |||
46 | int (*action)(struct fib_rule *, | 47 | int (*action)(struct fib_rule *, |
47 | struct flowi *, int, | 48 | struct flowi *, int, |
48 | struct fib_lookup_arg *); | 49 | struct fib_lookup_arg *); |
50 | bool (*suppress)(struct fib_rule *, | ||
51 | struct fib_lookup_arg *); | ||
49 | int (*match)(struct fib_rule *, | 52 | int (*match)(struct fib_rule *, |
50 | struct flowi *, int); | 53 | struct flowi *, int); |
51 | int (*configure)(struct fib_rule *, | 54 | int (*configure)(struct fib_rule *, |
@@ -80,6 +83,7 @@ struct fib_rules_ops { | |||
80 | [FRA_FWMARK] = { .type = NLA_U32 }, \ | 83 | [FRA_FWMARK] = { .type = NLA_U32 }, \ |
81 | [FRA_FWMASK] = { .type = NLA_U32 }, \ | 84 | [FRA_FWMASK] = { .type = NLA_U32 }, \ |
82 | [FRA_TABLE] = { .type = NLA_U32 }, \ | 85 | [FRA_TABLE] = { .type = NLA_U32 }, \ |
86 | [FRA_TABLE_PREFIXLEN_MIN] = { .type = NLA_U8 }, \ | ||
83 | [FRA_GOTO] = { .type = NLA_U32 } | 87 | [FRA_GOTO] = { .type = NLA_U32 } |
84 | 88 | ||
85 | static inline void fib_rule_get(struct fib_rule *rule) | 89 | static inline void fib_rule_get(struct fib_rule *rule) |
diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h index 51da65b68b85..59cd31b3455e 100644 --- a/include/uapi/linux/fib_rules.h +++ b/include/uapi/linux/fib_rules.h | |||
@@ -45,7 +45,7 @@ enum { | |||
45 | FRA_FLOW, /* flow/class id */ | 45 | FRA_FLOW, /* flow/class id */ |
46 | FRA_UNUSED6, | 46 | FRA_UNUSED6, |
47 | FRA_UNUSED7, | 47 | FRA_UNUSED7, |
48 | FRA_UNUSED8, | 48 | FRA_TABLE_PREFIXLEN_MIN, |
49 | FRA_TABLE, /* Extended table id */ | 49 | FRA_TABLE, /* Extended table id */ |
50 | FRA_FWMASK, /* mask for netfilter mark */ | 50 | FRA_FWMASK, /* mask for netfilter mark */ |
51 | FRA_OIFNAME, | 51 | FRA_OIFNAME, |
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 21735440c44a..2ef5040c99c8 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -226,6 +226,9 @@ jumped: | |||
226 | else | 226 | else |
227 | err = ops->action(rule, fl, flags, arg); | 227 | err = ops->action(rule, fl, flags, arg); |
228 | 228 | ||
229 | if (!err && ops->suppress && ops->suppress(rule, arg)) | ||
230 | continue; | ||
231 | |||
229 | if (err != -EAGAIN) { | 232 | if (err != -EAGAIN) { |
230 | if ((arg->flags & FIB_LOOKUP_NOREF) || | 233 | if ((arg->flags & FIB_LOOKUP_NOREF) || |
231 | likely(atomic_inc_not_zero(&rule->refcnt))) { | 234 | likely(atomic_inc_not_zero(&rule->refcnt))) { |
@@ -337,6 +340,8 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) | |||
337 | rule->action = frh->action; | 340 | rule->action = frh->action; |
338 | rule->flags = frh->flags; | 341 | rule->flags = frh->flags; |
339 | rule->table = frh_get_table(frh, tb); | 342 | rule->table = frh_get_table(frh, tb); |
343 | if (tb[FRA_TABLE_PREFIXLEN_MIN]) | ||
344 | rule->table_prefixlen_min = nla_get_u8(tb[FRA_TABLE_PREFIXLEN_MIN]); | ||
340 | 345 | ||
341 | if (!tb[FRA_PRIORITY] && ops->default_pref) | 346 | if (!tb[FRA_PRIORITY] && ops->default_pref) |
342 | rule->pref = ops->default_pref(ops); | 347 | rule->pref = ops->default_pref(ops); |
@@ -523,6 +528,7 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, | |||
523 | + nla_total_size(IFNAMSIZ) /* FRA_OIFNAME */ | 528 | + nla_total_size(IFNAMSIZ) /* FRA_OIFNAME */ |
524 | + nla_total_size(4) /* FRA_PRIORITY */ | 529 | + nla_total_size(4) /* FRA_PRIORITY */ |
525 | + nla_total_size(4) /* FRA_TABLE */ | 530 | + nla_total_size(4) /* FRA_TABLE */ |
531 | + nla_total_size(1) /* FRA_TABLE_PREFIXLEN_MIN */ | ||
526 | + nla_total_size(4) /* FRA_FWMARK */ | 532 | + nla_total_size(4) /* FRA_FWMARK */ |
527 | + nla_total_size(4); /* FRA_FWMASK */ | 533 | + nla_total_size(4); /* FRA_FWMASK */ |
528 | 534 | ||
@@ -548,6 +554,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, | |||
548 | frh->table = rule->table; | 554 | frh->table = rule->table; |
549 | if (nla_put_u32(skb, FRA_TABLE, rule->table)) | 555 | if (nla_put_u32(skb, FRA_TABLE, rule->table)) |
550 | goto nla_put_failure; | 556 | goto nla_put_failure; |
557 | if (nla_put_u8(skb, FRA_TABLE_PREFIXLEN_MIN, rule->table_prefixlen_min)) | ||
558 | goto nla_put_failure; | ||
551 | frh->res1 = 0; | 559 | frh->res1 = 0; |
552 | frh->res2 = 0; | 560 | frh->res2 = 0; |
553 | frh->action = rule->action; | 561 | frh->action = rule->action; |
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 26aa65d1fce4..9f2906679d1f 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c | |||
@@ -101,6 +101,19 @@ errout: | |||
101 | return err; | 101 | return err; |
102 | } | 102 | } |
103 | 103 | ||
104 | static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) | ||
105 | { | ||
106 | /* do not accept result if the route does | ||
107 | * not meet the required prefix length | ||
108 | */ | ||
109 | struct fib_result *result = (struct fib_result *) arg->result; | ||
110 | if (result->prefixlen < rule->table_prefixlen_min) { | ||
111 | if (!(arg->flags & FIB_LOOKUP_NOREF)) | ||
112 | fib_info_put(result->fi); | ||
113 | return true; | ||
114 | } | ||
115 | return false; | ||
116 | } | ||
104 | 117 | ||
105 | static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | 118 | static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) |
106 | { | 119 | { |
@@ -267,6 +280,7 @@ static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = { | |||
267 | .rule_size = sizeof(struct fib4_rule), | 280 | .rule_size = sizeof(struct fib4_rule), |
268 | .addr_size = sizeof(u32), | 281 | .addr_size = sizeof(u32), |
269 | .action = fib4_rule_action, | 282 | .action = fib4_rule_action, |
283 | .suppress = fib4_rule_suppress, | ||
270 | .match = fib4_rule_match, | 284 | .match = fib4_rule_match, |
271 | .configure = fib4_rule_configure, | 285 | .configure = fib4_rule_configure, |
272 | .delete = fib4_rule_delete, | 286 | .delete = fib4_rule_delete, |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 2e1a432867c0..e64e6a55fc4a 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -111,6 +111,18 @@ out: | |||
111 | return rt == NULL ? -EAGAIN : 0; | 111 | return rt == NULL ? -EAGAIN : 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) | ||
115 | { | ||
116 | struct rt6_info *rt = (struct rt6_info *) arg->result; | ||
117 | /* do not accept result if the route does | ||
118 | * not meet the required prefix length | ||
119 | */ | ||
120 | if (rt->rt6i_dst.plen < rule->table_prefixlen_min) { | ||
121 | ip6_rt_put(rt); | ||
122 | return true; | ||
123 | } | ||
124 | return false; | ||
125 | } | ||
114 | 126 | ||
115 | static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | 127 | static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) |
116 | { | 128 | { |
@@ -244,6 +256,7 @@ static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = { | |||
244 | .addr_size = sizeof(struct in6_addr), | 256 | .addr_size = sizeof(struct in6_addr), |
245 | .action = fib6_rule_action, | 257 | .action = fib6_rule_action, |
246 | .match = fib6_rule_match, | 258 | .match = fib6_rule_match, |
259 | .suppress = fib6_rule_suppress, | ||
247 | .configure = fib6_rule_configure, | 260 | .configure = fib6_rule_configure, |
248 | .compare = fib6_rule_compare, | 261 | .compare = fib6_rule_compare, |
249 | .fill = fib6_rule_fill, | 262 | .fill = fib6_rule_fill, |