diff options
-rw-r--r-- | include/linux/fib_rules.h | 2 | ||||
-rw-r--r-- | include/net/fib_rules.h | 3 | ||||
-rw-r--r-- | net/core/fib_rules.c | 33 |
3 files changed, 37 insertions, 1 deletions
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 7e11bb2fa655..51da65b68b85 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #define FIB_RULE_UNRESOLVED 0x00000004 | 10 | #define FIB_RULE_UNRESOLVED 0x00000004 |
11 | #define FIB_RULE_IIF_DETACHED 0x00000008 | 11 | #define FIB_RULE_IIF_DETACHED 0x00000008 |
12 | #define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED | 12 | #define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED |
13 | #define FIB_RULE_OIF_DETACHED 0x00000010 | ||
13 | 14 | ||
14 | /* try to find source address in routing lookups */ | 15 | /* try to find source address in routing lookups */ |
15 | #define FIB_RULE_FIND_SADDR 0x00010000 | 16 | #define FIB_RULE_FIND_SADDR 0x00010000 |
@@ -47,6 +48,7 @@ enum { | |||
47 | FRA_UNUSED8, | 48 | FRA_UNUSED8, |
48 | FRA_TABLE, /* Extended table id */ | 49 | FRA_TABLE, /* Extended table id */ |
49 | FRA_FWMASK, /* mask for netfilter mark */ | 50 | FRA_FWMASK, /* mask for netfilter mark */ |
51 | FRA_OIFNAME, | ||
50 | __FRA_MAX | 52 | __FRA_MAX |
51 | }; | 53 | }; |
52 | 54 | ||
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 62bebcb2a51c..d4e875a58f8b 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h | |||
@@ -11,6 +11,7 @@ struct fib_rule { | |||
11 | struct list_head list; | 11 | struct list_head list; |
12 | atomic_t refcnt; | 12 | atomic_t refcnt; |
13 | int iifindex; | 13 | int iifindex; |
14 | int oifindex; | ||
14 | u32 mark; | 15 | u32 mark; |
15 | u32 mark_mask; | 16 | u32 mark_mask; |
16 | u32 pref; | 17 | u32 pref; |
@@ -20,6 +21,7 @@ struct fib_rule { | |||
20 | u32 target; | 21 | u32 target; |
21 | struct fib_rule * ctarget; | 22 | struct fib_rule * ctarget; |
22 | char iifname[IFNAMSIZ]; | 23 | char iifname[IFNAMSIZ]; |
24 | char oifname[IFNAMSIZ]; | ||
23 | struct rcu_head rcu; | 25 | struct rcu_head rcu; |
24 | struct net * fr_net; | 26 | struct net * fr_net; |
25 | }; | 27 | }; |
@@ -68,6 +70,7 @@ struct fib_rules_ops { | |||
68 | 70 | ||
69 | #define FRA_GENERIC_POLICY \ | 71 | #define FRA_GENERIC_POLICY \ |
70 | [FRA_IIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ | 72 | [FRA_IIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ |
73 | [FRA_OIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ | ||
71 | [FRA_PRIORITY] = { .type = NLA_U32 }, \ | 74 | [FRA_PRIORITY] = { .type = NLA_U32 }, \ |
72 | [FRA_FWMARK] = { .type = NLA_U32 }, \ | 75 | [FRA_FWMARK] = { .type = NLA_U32 }, \ |
73 | [FRA_FWMASK] = { .type = NLA_U32 }, \ | 76 | [FRA_FWMASK] = { .type = NLA_U32 }, \ |
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 8e8028cdc87f..d1a70ad4b544 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -138,6 +138,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, | |||
138 | if (rule->iifindex && (rule->iifindex != fl->iif)) | 138 | if (rule->iifindex && (rule->iifindex != fl->iif)) |
139 | goto out; | 139 | goto out; |
140 | 140 | ||
141 | if (rule->oifindex && (rule->oifindex != fl->oif)) | ||
142 | goto out; | ||
143 | |||
141 | if ((rule->mark ^ fl->mark) & rule->mark_mask) | 144 | if ((rule->mark ^ fl->mark) & rule->mark_mask) |
142 | goto out; | 145 | goto out; |
143 | 146 | ||
@@ -258,6 +261,16 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
258 | rule->iifindex = dev->ifindex; | 261 | rule->iifindex = dev->ifindex; |
259 | } | 262 | } |
260 | 263 | ||
264 | if (tb[FRA_OIFNAME]) { | ||
265 | struct net_device *dev; | ||
266 | |||
267 | rule->oifindex = -1; | ||
268 | nla_strlcpy(rule->oifname, tb[FRA_OIFNAME], IFNAMSIZ); | ||
269 | dev = __dev_get_by_name(net, rule->oifname); | ||
270 | if (dev) | ||
271 | rule->oifindex = dev->ifindex; | ||
272 | } | ||
273 | |||
261 | if (tb[FRA_FWMARK]) { | 274 | if (tb[FRA_FWMARK]) { |
262 | rule->mark = nla_get_u32(tb[FRA_FWMARK]); | 275 | rule->mark = nla_get_u32(tb[FRA_FWMARK]); |
263 | if (rule->mark) | 276 | if (rule->mark) |
@@ -392,6 +405,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
392 | nla_strcmp(tb[FRA_IIFNAME], rule->iifname)) | 405 | nla_strcmp(tb[FRA_IIFNAME], rule->iifname)) |
393 | continue; | 406 | continue; |
394 | 407 | ||
408 | if (tb[FRA_OIFNAME] && | ||
409 | nla_strcmp(tb[FRA_OIFNAME], rule->oifname)) | ||
410 | continue; | ||
411 | |||
395 | if (tb[FRA_FWMARK] && | 412 | if (tb[FRA_FWMARK] && |
396 | (rule->mark != nla_get_u32(tb[FRA_FWMARK]))) | 413 | (rule->mark != nla_get_u32(tb[FRA_FWMARK]))) |
397 | continue; | 414 | continue; |
@@ -448,6 +465,7 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, | |||
448 | { | 465 | { |
449 | size_t payload = NLMSG_ALIGN(sizeof(struct fib_rule_hdr)) | 466 | size_t payload = NLMSG_ALIGN(sizeof(struct fib_rule_hdr)) |
450 | + nla_total_size(IFNAMSIZ) /* FRA_IIFNAME */ | 467 | + nla_total_size(IFNAMSIZ) /* FRA_IIFNAME */ |
468 | + nla_total_size(IFNAMSIZ) /* FRA_OIFNAME */ | ||
451 | + nla_total_size(4) /* FRA_PRIORITY */ | 469 | + nla_total_size(4) /* FRA_PRIORITY */ |
452 | + nla_total_size(4) /* FRA_TABLE */ | 470 | + nla_total_size(4) /* FRA_TABLE */ |
453 | + nla_total_size(4) /* FRA_FWMARK */ | 471 | + nla_total_size(4) /* FRA_FWMARK */ |
@@ -488,6 +506,13 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, | |||
488 | frh->flags |= FIB_RULE_IIF_DETACHED; | 506 | frh->flags |= FIB_RULE_IIF_DETACHED; |
489 | } | 507 | } |
490 | 508 | ||
509 | if (rule->oifname[0]) { | ||
510 | NLA_PUT_STRING(skb, FRA_OIFNAME, rule->oifname); | ||
511 | |||
512 | if (rule->oifindex == -1) | ||
513 | frh->flags |= FIB_RULE_OIF_DETACHED; | ||
514 | } | ||
515 | |||
491 | if (rule->pref) | 516 | if (rule->pref) |
492 | NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref); | 517 | NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref); |
493 | 518 | ||
@@ -603,6 +628,9 @@ static void attach_rules(struct list_head *rules, struct net_device *dev) | |||
603 | if (rule->iifindex == -1 && | 628 | if (rule->iifindex == -1 && |
604 | strcmp(dev->name, rule->iifname) == 0) | 629 | strcmp(dev->name, rule->iifname) == 0) |
605 | rule->iifindex = dev->ifindex; | 630 | rule->iifindex = dev->ifindex; |
631 | if (rule->oifindex == -1 && | ||
632 | strcmp(dev->name, rule->oifname) == 0) | ||
633 | rule->oifindex = dev->ifindex; | ||
606 | } | 634 | } |
607 | } | 635 | } |
608 | 636 | ||
@@ -610,9 +638,12 @@ static void detach_rules(struct list_head *rules, struct net_device *dev) | |||
610 | { | 638 | { |
611 | struct fib_rule *rule; | 639 | struct fib_rule *rule; |
612 | 640 | ||
613 | list_for_each_entry(rule, rules, list) | 641 | list_for_each_entry(rule, rules, list) { |
614 | if (rule->iifindex == dev->ifindex) | 642 | if (rule->iifindex == dev->ifindex) |
615 | rule->iifindex = -1; | 643 | rule->iifindex = -1; |
644 | if (rule->oifindex == dev->ifindex) | ||
645 | rule->oifindex = -1; | ||
646 | } | ||
616 | } | 647 | } |
617 | 648 | ||
618 | 649 | ||