aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/fib_rules.h4
-rw-r--r--include/uapi/linux/fib_rules.h2
-rw-r--r--net/core/fib_rules.c8
-rw-r--r--net/ipv4/fib_rules.c14
-rw-r--r--net/ipv6/fib6_rules.c13
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
85static inline void fib_rule_get(struct fib_rule *rule) 89static 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
104static 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
105static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) 118static 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
114static 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
115static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) 127static 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,