]> Pileus Git - ~andy/linux/commitdiff
xfrm: allow to avoid copying DSCP during encapsulation
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Fri, 22 Feb 2013 09:54:54 +0000 (10:54 +0100)
committerSteffen Klassert <steffen.klassert@secunet.com>
Wed, 6 Mar 2013 06:02:45 +0000 (07:02 +0100)
By default, DSCP is copying during encapsulation.
Copying the DSCP in IPsec tunneling may be a bit dangerous because packets with
different DSCP may get reordered relative to each other in the network and then
dropped by the remote IPsec GW if the reordering becomes too big compared to the
replay window.

It is possible to avoid this copy with netfilter rules, but it's very convenient
to be able to configure it for each SA directly.

This patch adds a toogle for this purpose. By default, it's not set to maintain
backward compatibility.

Field flags in struct xfrm_usersa_info is full, hence I add a new attribute.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
include/net/xfrm.h
include/uapi/linux/xfrm.h
net/ipv4/ipcomp.c
net/ipv4/xfrm4_mode_tunnel.c
net/ipv6/xfrm6_mode_tunnel.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c

index 24c8886fd9699969c74908bf1e78efdcbda0694b..ae16531d0d353741ac66c83e0464341d060d5cce 100644 (file)
@@ -162,6 +162,7 @@ struct xfrm_state {
                xfrm_address_t  saddr;
                int             header_len;
                int             trailer_len;
+               u32             extra_flags;
        } props;
 
        struct xfrm_lifetime_cfg lft;
index 28e493b5b94c9ba6d946d728a0908c84e34294db..a8cd6a4a297070052a0e3deddafd9a05bca62c91 100644 (file)
@@ -297,6 +297,7 @@ enum xfrm_attr_type_t {
        XFRMA_MARK,             /* struct xfrm_mark */
        XFRMA_TFCPAD,           /* __u32 */
        XFRMA_REPLAY_ESN_VAL,   /* struct xfrm_replay_esn */
+       XFRMA_SA_EXTRA_FLAGS,   /* __u32 */
        __XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -367,6 +368,8 @@ struct xfrm_usersa_info {
 #define XFRM_STATE_ESN         128
 };
 
+#define XFRM_SA_XFLAG_DONT_ENCAP_DSCP  1
+
 struct xfrm_usersa_id {
        xfrm_address_t                  daddr;
        __be32                          spi;
index f01d1b1aff7f0a08b0020055ae65e26f792a0379..59cb8c7690561f3fc44ecc382557408af53cb5fb 100644 (file)
@@ -75,6 +75,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
        t->props.mode = x->props.mode;
        t->props.saddr.a4 = x->props.saddr.a4;
        t->props.flags = x->props.flags;
+       t->props.extra_flags = x->props.extra_flags;
        memcpy(&t->mark, &x->mark, sizeof(t->mark));
 
        if (xfrm_init_state(t))
index fe5189e2e1147d338d96347666d7a98a4ac7b018..eb1dd4d643f2f92d5a2385d0839d06a3424c545c 100644 (file)
@@ -103,8 +103,12 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 
        top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
 
-       /* DS disclosed */
-       top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos,
+       /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */
+       if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
+               top_iph->tos = 0;
+       else
+               top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
+       top_iph->tos = INET_ECN_encapsulate(top_iph->tos,
                                            XFRM_MODE_SKB_CB(skb)->tos);
 
        flags = x->props.flags;
index 9bf6a74a71d261061201e3863fd32713c91720d7..4770d515c2c856684e93416d4696067cae7e3114 100644 (file)
@@ -49,8 +49,11 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
               sizeof(top_iph->flow_lbl));
        top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family);
 
-       dsfield = XFRM_MODE_SKB_CB(skb)->tos;
-       dsfield = INET_ECN_encapsulate(dsfield, dsfield);
+       if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
+               dsfield = 0;
+       else
+               dsfield = XFRM_MODE_SKB_CB(skb)->tos;
+       dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos);
        if (x->props.flags & XFRM_STATE_NOECN)
                dsfield &= ~INET_ECN_MASK;
        ipv6_change_dsfield(top_iph, 0, dsfield);
index 2c341bdaf47cbabfe1b8801e65a3b4a2ea571a66..78f66fa92449c92865dfa8314020854ed704744f 100644 (file)
@@ -1187,6 +1187,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
                goto error;
 
        x->props.flags = orig->props.flags;
+       x->props.extra_flags = orig->props.extra_flags;
 
        x->curlft.add_time = orig->curlft.add_time;
        x->km.state = orig->km.state;
index fbd9e6cd0fd7a1297d99b48c37cc6de8ce938bbf..204cba192af8d70a2596b8888fe8bb0e9f4b3904 100644 (file)
@@ -515,6 +515,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
 
        copy_from_user_state(x, p);
 
+       if (attrs[XFRMA_SA_EXTRA_FLAGS])
+               x->props.extra_flags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
+
        if ((err = attach_aead(&x->aead, &x->props.ealgo,
                               attrs[XFRMA_ALG_AEAD])))
                goto error;
@@ -779,6 +782,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
 
        copy_to_user_state(x, p);
 
+       if (x->props.extra_flags) {
+               ret = nla_put_u32(skb, XFRMA_SA_EXTRA_FLAGS,
+                                 x->props.extra_flags);
+               if (ret)
+                       goto out;
+       }
+
        if (x->coaddr) {
                ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
                if (ret)
@@ -2302,6 +2312,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
        [XFRMA_MARK]            = { .len = sizeof(struct xfrm_mark) },
        [XFRMA_TFCPAD]          = { .type = NLA_U32 },
        [XFRMA_REPLAY_ESN_VAL]  = { .len = sizeof(struct xfrm_replay_state_esn) },
+       [XFRMA_SA_EXTRA_FLAGS]  = { .type = NLA_U32 },
 };
 
 static struct xfrm_link {
@@ -2495,6 +2506,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
                                    x->security->ctx_len);
        if (x->coaddr)
                l += nla_total_size(sizeof(*x->coaddr));
+       if (x->props.extra_flags)
+               l += nla_total_size(sizeof(x->props.extra_flags));
 
        /* Must count x->lastused as it may become non-zero behind our back. */
        l += nla_total_size(sizeof(u64));