aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2013-02-22 04:54:54 -0500
committerSteffen Klassert <steffen.klassert@secunet.com>2013-03-06 01:02:45 -0500
commita947b0a93efa9a25c012aa88848f4cf8d9b41280 (patch)
treeca5ccc41834e4c811e859724a184f223a3772ca7
parent6fac41157252220678b210fcb13e2c3dad7a912a (diff)
xfrm: allow to avoid copying DSCP during encapsulation
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>
-rw-r--r--include/net/xfrm.h1
-rw-r--r--include/uapi/linux/xfrm.h3
-rw-r--r--net/ipv4/ipcomp.c1
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c8
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c7
-rw-r--r--net/xfrm/xfrm_state.c1
-rw-r--r--net/xfrm/xfrm_user.c13
7 files changed, 30 insertions, 4 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 24c8886fd969..ae16531d0d35 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -162,6 +162,7 @@ struct xfrm_state {
162 xfrm_address_t saddr; 162 xfrm_address_t saddr;
163 int header_len; 163 int header_len;
164 int trailer_len; 164 int trailer_len;
165 u32 extra_flags;
165 } props; 166 } props;
166 167
167 struct xfrm_lifetime_cfg lft; 168 struct xfrm_lifetime_cfg lft;
diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h
index 28e493b5b94c..a8cd6a4a2970 100644
--- a/include/uapi/linux/xfrm.h
+++ b/include/uapi/linux/xfrm.h
@@ -297,6 +297,7 @@ enum xfrm_attr_type_t {
297 XFRMA_MARK, /* struct xfrm_mark */ 297 XFRMA_MARK, /* struct xfrm_mark */
298 XFRMA_TFCPAD, /* __u32 */ 298 XFRMA_TFCPAD, /* __u32 */
299 XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */ 299 XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */
300 XFRMA_SA_EXTRA_FLAGS, /* __u32 */
300 __XFRMA_MAX 301 __XFRMA_MAX
301 302
302#define XFRMA_MAX (__XFRMA_MAX - 1) 303#define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -367,6 +368,8 @@ struct xfrm_usersa_info {
367#define XFRM_STATE_ESN 128 368#define XFRM_STATE_ESN 128
368}; 369};
369 370
371#define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1
372
370struct xfrm_usersa_id { 373struct xfrm_usersa_id {
371 xfrm_address_t daddr; 374 xfrm_address_t daddr;
372 __be32 spi; 375 __be32 spi;
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index f01d1b1aff7f..59cb8c769056 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -75,6 +75,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
75 t->props.mode = x->props.mode; 75 t->props.mode = x->props.mode;
76 t->props.saddr.a4 = x->props.saddr.a4; 76 t->props.saddr.a4 = x->props.saddr.a4;
77 t->props.flags = x->props.flags; 77 t->props.flags = x->props.flags;
78 t->props.extra_flags = x->props.extra_flags;
78 memcpy(&t->mark, &x->mark, sizeof(t->mark)); 79 memcpy(&t->mark, &x->mark, sizeof(t->mark));
79 80
80 if (xfrm_init_state(t)) 81 if (xfrm_init_state(t))
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index fe5189e2e114..eb1dd4d643f2 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -103,8 +103,12 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
103 103
104 top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); 104 top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
105 105
106 /* DS disclosed */ 106 /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */
107 top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos, 107 if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
108 top_iph->tos = 0;
109 else
110 top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
111 top_iph->tos = INET_ECN_encapsulate(top_iph->tos,
108 XFRM_MODE_SKB_CB(skb)->tos); 112 XFRM_MODE_SKB_CB(skb)->tos);
109 113
110 flags = x->props.flags; 114 flags = x->props.flags;
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 9bf6a74a71d2..4770d515c2c8 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -49,8 +49,11 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
49 sizeof(top_iph->flow_lbl)); 49 sizeof(top_iph->flow_lbl));
50 top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); 50 top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family);
51 51
52 dsfield = XFRM_MODE_SKB_CB(skb)->tos; 52 if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
53 dsfield = INET_ECN_encapsulate(dsfield, dsfield); 53 dsfield = 0;
54 else
55 dsfield = XFRM_MODE_SKB_CB(skb)->tos;
56 dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos);
54 if (x->props.flags & XFRM_STATE_NOECN) 57 if (x->props.flags & XFRM_STATE_NOECN)
55 dsfield &= ~INET_ECN_MASK; 58 dsfield &= ~INET_ECN_MASK;
56 ipv6_change_dsfield(top_iph, 0, dsfield); 59 ipv6_change_dsfield(top_iph, 0, dsfield);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 2c341bdaf47c..78f66fa92449 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1187,6 +1187,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
1187 goto error; 1187 goto error;
1188 1188
1189 x->props.flags = orig->props.flags; 1189 x->props.flags = orig->props.flags;
1190 x->props.extra_flags = orig->props.extra_flags;
1190 1191
1191 x->curlft.add_time = orig->curlft.add_time; 1192 x->curlft.add_time = orig->curlft.add_time;
1192 x->km.state = orig->km.state; 1193 x->km.state = orig->km.state;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index fbd9e6cd0fd7..204cba192af8 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -515,6 +515,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
515 515
516 copy_from_user_state(x, p); 516 copy_from_user_state(x, p);
517 517
518 if (attrs[XFRMA_SA_EXTRA_FLAGS])
519 x->props.extra_flags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
520
518 if ((err = attach_aead(&x->aead, &x->props.ealgo, 521 if ((err = attach_aead(&x->aead, &x->props.ealgo,
519 attrs[XFRMA_ALG_AEAD]))) 522 attrs[XFRMA_ALG_AEAD])))
520 goto error; 523 goto error;
@@ -779,6 +782,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
779 782
780 copy_to_user_state(x, p); 783 copy_to_user_state(x, p);
781 784
785 if (x->props.extra_flags) {
786 ret = nla_put_u32(skb, XFRMA_SA_EXTRA_FLAGS,
787 x->props.extra_flags);
788 if (ret)
789 goto out;
790 }
791
782 if (x->coaddr) { 792 if (x->coaddr) {
783 ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); 793 ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
784 if (ret) 794 if (ret)
@@ -2302,6 +2312,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
2302 [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, 2312 [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) },
2303 [XFRMA_TFCPAD] = { .type = NLA_U32 }, 2313 [XFRMA_TFCPAD] = { .type = NLA_U32 },
2304 [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) }, 2314 [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) },
2315 [XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 },
2305}; 2316};
2306 2317
2307static struct xfrm_link { 2318static struct xfrm_link {
@@ -2495,6 +2506,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
2495 x->security->ctx_len); 2506 x->security->ctx_len);
2496 if (x->coaddr) 2507 if (x->coaddr)
2497 l += nla_total_size(sizeof(*x->coaddr)); 2508 l += nla_total_size(sizeof(*x->coaddr));
2509 if (x->props.extra_flags)
2510 l += nla_total_size(sizeof(x->props.extra_flags));
2498 2511
2499 /* Must count x->lastused as it may become non-zero behind our back. */ 2512 /* Must count x->lastused as it may become non-zero behind our back. */
2500 l += nla_total_size(sizeof(u64)); 2513 l += nla_total_size(sizeof(u64));