tcp: use dctcp if enabled on the route to the initiator
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / fib_semantics.c
index 01f1c7dcd329ca6ec6f281328e52db7bb256ae9b..992a9597daf80d7d734d8e0245c8410dc334511b 100644 (file)
@@ -511,7 +511,8 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
                                        dev = __dev_get_by_index(net, cfg->fc_oif);
                                ret = lwtunnel_build_state(dev, nla_get_u16(
                                                           nla_entype),
-                                                          nla, &lwtstate);
+                                                          nla,  AF_INET, cfg,
+                                                          &lwtstate);
                                if (ret)
                                        goto errout;
                                nexthop_nh->nh_lwtstate =
@@ -535,7 +536,8 @@ errout:
 
 static int fib_encap_match(struct net *net, u16 encap_type,
                           struct nlattr *encap,
-                          int oif, const struct fib_nh *nh)
+                          int oif, const struct fib_nh *nh,
+                          const struct fib_config *cfg)
 {
        struct lwtunnel_state *lwtstate;
        struct net_device *dev = NULL;
@@ -546,8 +548,8 @@ static int fib_encap_match(struct net *net, u16 encap_type,
 
        if (oif)
                dev = __dev_get_by_index(net, oif);
-       ret = lwtunnel_build_state(dev, encap_type,
-                                  encap, &lwtstate);
+       ret = lwtunnel_build_state(dev, encap_type, encap,
+                                  AF_INET, cfg, &lwtstate);
        if (!ret) {
                result = lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate);
                lwtstate_free(lwtstate);
@@ -571,7 +573,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
                if (cfg->fc_encap) {
                        if (fib_encap_match(net, cfg->fc_encap_type,
                                            cfg->fc_encap, cfg->fc_oif,
-                                           fi->fib_nh))
+                                           fi->fib_nh, cfg))
                            return 1;
                }
                if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
@@ -663,7 +665,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
 static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
                        struct fib_nh *nh)
 {
-       int err;
+       int err = 0;
        struct net *net;
        struct net_device *dev;
 
@@ -874,6 +876,50 @@ static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
        return true;
 }
 
+static int
+fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg)
+{
+       bool ecn_ca = false;
+       struct nlattr *nla;
+       int remaining;
+
+       if (!cfg->fc_mx)
+               return 0;
+
+       nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
+               int type = nla_type(nla);
+               u32 val;
+
+               if (!type)
+                       continue;
+               if (type > RTAX_MAX)
+                       return -EINVAL;
+
+               if (type == RTAX_CC_ALGO) {
+                       char tmp[TCP_CA_NAME_MAX];
+
+                       nla_strlcpy(tmp, nla, sizeof(tmp));
+                       val = tcp_ca_get_key_by_name(tmp, &ecn_ca);
+                       if (val == TCP_CA_UNSPEC)
+                               return -EINVAL;
+               } else {
+                       val = nla_get_u32(nla);
+               }
+               if (type == RTAX_ADVMSS && val > 65535 - 40)
+                       val = 65535 - 40;
+               if (type == RTAX_MTU && val > 65535 - 15)
+                       val = 65535 - 15;
+               if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
+                       return -EINVAL;
+               fi->fib_metrics[type - 1] = val;
+       }
+
+       if (ecn_ca)
+               fi->fib_metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
+
+       return 0;
+}
+
 struct fib_info *fib_create_info(struct fib_config *cfg)
 {
        int err;
@@ -946,36 +992,9 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
                        goto failure;
        } endfor_nexthops(fi)
 
-       if (cfg->fc_mx) {
-               struct nlattr *nla;
-               int remaining;
-
-               nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
-                       int type = nla_type(nla);
-
-                       if (type) {
-                               u32 val;
-
-                               if (type > RTAX_MAX)
-                                       goto err_inval;
-                               if (type == RTAX_CC_ALGO) {
-                                       char tmp[TCP_CA_NAME_MAX];
-
-                                       nla_strlcpy(tmp, nla, sizeof(tmp));
-                                       val = tcp_ca_get_key_by_name(tmp);
-                                       if (val == TCP_CA_UNSPEC)
-                                               goto err_inval;
-                               } else {
-                                       val = nla_get_u32(nla);
-                               }
-                               if (type == RTAX_ADVMSS && val > 65535 - 40)
-                                       val = 65535 - 40;
-                               if (type == RTAX_MTU && val > 65535 - 15)
-                                       val = 65535 - 15;
-                               fi->fib_metrics[type - 1] = val;
-                       }
-               }
-       }
+       err = fib_convert_metrics(fi, cfg);
+       if (err)
+               goto failure;
 
        if (cfg->fc_mp) {
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
@@ -1005,7 +1024,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
                        if (cfg->fc_oif)
                                dev = __dev_get_by_index(net, cfg->fc_oif);
                        err = lwtunnel_build_state(dev, cfg->fc_encap_type,
-                                                  cfg->fc_encap, &lwtstate);
+                                                  cfg->fc_encap, AF_INET, cfg,
+                                                  &lwtstate);
                        if (err)
                                goto failure;