datapath: Fix Tunnel options TOS
[cascardo/ovs.git] / datapath / tunnel.c
index c2133bb..d651c11 100644 (file)
@@ -1002,12 +1002,15 @@ unlock:
 static struct rtable *__find_route(const struct tnl_mutable_config *mutable,
                                   u8 ipproto, u8 tos)
 {
+       /* Tunnel configuration keeps DSCP part of TOS bits, But Linux
+        * router expect RT_TOS bits only. */
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
        struct flowi fl = { .nl_u = { .ip4_u = {
                                        .daddr = mutable->key.daddr,
                                        .saddr = mutable->key.saddr,
-                                       .tos = tos } },
-                           .proto = ipproto };
+                                       .tos   = RT_TOS(tos) } },
+                                       .proto = ipproto };
        struct rtable *rt;
 
        if (unlikely(ip_route_output_key(port_key_get_net(&mutable->key), &rt, &fl)))
@@ -1017,7 +1020,7 @@ static struct rtable *__find_route(const struct tnl_mutable_config *mutable,
 #else
        struct flowi4 fl = { .daddr = mutable->key.daddr,
                             .saddr = mutable->key.saddr,
-                            .flowi4_tos = tos,
+                            .flowi4_tos = RT_TOS(tos),
                             .flowi4_proto = ipproto };
 
        return ip_route_output_key(port_key_get_net(&mutable->key), &fl);
@@ -1034,7 +1037,7 @@ static struct rtable *find_route(struct vport *vport,
        *cache = NULL;
        tos = RT_TOS(tos);
 
-       if (likely(tos == mutable->tos &&
+       if (likely(tos == RT_TOS(mutable->tos) &&
            check_cache_valid(cur_cache, mutable))) {
                *cache = cur_cache;
                return cur_cache->rt;
@@ -1045,7 +1048,7 @@ static struct rtable *find_route(struct vport *vport,
                if (IS_ERR(rt))
                        return NULL;
 
-               if (likely(tos == mutable->tos))
+               if (likely(tos == RT_TOS(mutable->tos)))
                        *cache = build_cache(vport, mutable, rt);
 
                return rt;
@@ -1219,8 +1222,6 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
        else
                tos = mutable->tos;
 
-       tos = INET_ECN_encapsulate(tos, inner_tos);
-
        /* Route lookup */
        rt = find_route(vport, mutable, tos, &cache);
        if (unlikely(!rt))
@@ -1228,6 +1229,8 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
        if (unlikely(!cache))
                unattached_dst = &rt_dst(rt);
 
+       tos = INET_ECN_encapsulate(tos, inner_tos);
+
        /* Reset SKB */
        nf_reset(skb);
        secpath_reset(skb);
@@ -1402,7 +1405,8 @@ static int tnl_set_config(struct net *net, struct nlattr *options,
 
        if (a[OVS_TUNNEL_ATTR_TOS]) {
                mutable->tos = nla_get_u8(a[OVS_TUNNEL_ATTR_TOS]);
-               if (mutable->tos != RT_TOS(mutable->tos))
+               /* Reject ToS config with ECN bits set. */
+               if (mutable->tos & INET_ECN_MASK)
                        return -EINVAL;
        }