These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / core / fib_rules.c
index 0ad144f..365de66 100644 (file)
@@ -16,6 +16,7 @@
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #include <net/fib_rules.h>
+#include <net/ip_tunnels.h>
 
 int fib_default_rule_add(struct fib_rules_ops *ops,
                         u32 pref, u32 table, u32 flags)
@@ -43,7 +44,7 @@ int fib_default_rule_add(struct fib_rules_ops *ops,
 }
 EXPORT_SYMBOL(fib_default_rule_add);
 
-u32 fib_default_rule_pref(struct fib_rules_ops *ops)
+static u32 fib_default_rule_pref(struct fib_rules_ops *ops)
 {
        struct list_head *pos;
        struct fib_rule *rule;
@@ -59,7 +60,6 @@ u32 fib_default_rule_pref(struct fib_rules_ops *ops)
 
        return 0;
 }
-EXPORT_SYMBOL(fib_default_rule_pref);
 
 static void notify_rule_change(int event, struct fib_rule *rule,
                               struct fib_rules_ops *ops, struct nlmsghdr *nlh,
@@ -186,6 +186,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
        if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask)
                goto out;
 
+       if (rule->tun_id && (rule->tun_id != fl->flowi_tun_key.tun_id))
+               goto out;
+
        ret = ops->match(rule, fl, flags);
 out:
        return (rule->flags & FIB_RULE_INVERT) ? !ret : ret;
@@ -295,8 +298,8 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
        }
        rule->fr_net = net;
 
-       if (tb[FRA_PRIORITY])
-               rule->pref = nla_get_u32(tb[FRA_PRIORITY]);
+       rule->pref = tb[FRA_PRIORITY] ? nla_get_u32(tb[FRA_PRIORITY])
+                                     : fib_default_rule_pref(ops);
 
        if (tb[FRA_IIFNAME]) {
                struct net_device *dev;
@@ -330,6 +333,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
        if (tb[FRA_FWMASK])
                rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]);
 
+       if (tb[FRA_TUN_ID])
+               rule->tun_id = nla_get_be64(tb[FRA_TUN_ID]);
+
        rule->action = frh->action;
        rule->flags = frh->flags;
        rule->table = frh_get_table(frh, tb);
@@ -343,9 +349,6 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
        else
                rule->suppress_ifgroup = -1;
 
-       if (!tb[FRA_PRIORITY] && ops->default_pref)
-               rule->pref = ops->default_pref(ops);
-
        err = -EINVAL;
        if (tb[FRA_GOTO]) {
                if (rule->action != FR_ACT_GOTO)
@@ -407,6 +410,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
        if (unresolved)
                ops->unresolved_rules++;
 
+       if (rule->tun_id)
+               ip_tunnel_need_metadata();
+
        notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
        flush_route_cache(ops);
        rules_ops_put(ops);
@@ -473,6 +479,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
                    (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK])))
                        continue;
 
+               if (tb[FRA_TUN_ID] &&
+                   (rule->tun_id != nla_get_be64(tb[FRA_TUN_ID])))
+                       continue;
+
                if (!ops->compare(rule, frh, tb))
                        continue;
 
@@ -487,6 +497,9 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
                                goto errout;
                }
 
+               if (rule->tun_id)
+                       ip_tunnel_unneed_metadata();
+
                list_del_rcu(&rule->list);
 
                if (rule->action == FR_ACT_GOTO) {
@@ -535,7 +548,8 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
                         + nla_total_size(4) /* FRA_SUPPRESS_PREFIXLEN */
                         + nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */
                         + nla_total_size(4) /* FRA_FWMARK */
-                        + nla_total_size(4); /* FRA_FWMASK */
+                        + nla_total_size(4) /* FRA_FWMASK */
+                        + nla_total_size(8); /* FRA_TUN_ID */
 
        if (ops->nlmsg_payload)
                payload += ops->nlmsg_payload(rule);
@@ -591,7 +605,9 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
            ((rule->mark_mask || rule->mark) &&
             nla_put_u32(skb, FRA_FWMASK, rule->mark_mask)) ||
            (rule->target &&
-            nla_put_u32(skb, FRA_GOTO, rule->target)))
+            nla_put_u32(skb, FRA_GOTO, rule->target)) ||
+           (rule->tun_id &&
+            nla_put_be64(skb, FRA_TUN_ID, rule->tun_id)))
                goto nla_put_failure;
 
        if (rule->suppress_ifgroup != -1) {