提交 a947b0a9 编写于 作者: N Nicolas Dichtel 提交者: Steffen Klassert

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: NNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: NSteffen Klassert <steffen.klassert@secunet.com>
上级 6fac4115
...@@ -162,6 +162,7 @@ struct xfrm_state { ...@@ -162,6 +162,7 @@ struct xfrm_state {
xfrm_address_t saddr; xfrm_address_t saddr;
int header_len; int header_len;
int trailer_len; int trailer_len;
u32 extra_flags;
} props; } props;
struct xfrm_lifetime_cfg lft; struct xfrm_lifetime_cfg lft;
......
...@@ -297,6 +297,7 @@ enum xfrm_attr_type_t { ...@@ -297,6 +297,7 @@ enum xfrm_attr_type_t {
XFRMA_MARK, /* struct xfrm_mark */ XFRMA_MARK, /* struct xfrm_mark */
XFRMA_TFCPAD, /* __u32 */ XFRMA_TFCPAD, /* __u32 */
XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */ XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */
XFRMA_SA_EXTRA_FLAGS, /* __u32 */
__XFRMA_MAX __XFRMA_MAX
#define XFRMA_MAX (__XFRMA_MAX - 1) #define XFRMA_MAX (__XFRMA_MAX - 1)
...@@ -367,6 +368,8 @@ struct xfrm_usersa_info { ...@@ -367,6 +368,8 @@ struct xfrm_usersa_info {
#define XFRM_STATE_ESN 128 #define XFRM_STATE_ESN 128
}; };
#define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1
struct xfrm_usersa_id { struct xfrm_usersa_id {
xfrm_address_t daddr; xfrm_address_t daddr;
__be32 spi; __be32 spi;
......
...@@ -75,6 +75,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) ...@@ -75,6 +75,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
t->props.mode = x->props.mode; t->props.mode = x->props.mode;
t->props.saddr.a4 = x->props.saddr.a4; t->props.saddr.a4 = x->props.saddr.a4;
t->props.flags = x->props.flags; t->props.flags = x->props.flags;
t->props.extra_flags = x->props.extra_flags;
memcpy(&t->mark, &x->mark, sizeof(t->mark)); memcpy(&t->mark, &x->mark, sizeof(t->mark));
if (xfrm_init_state(t)) if (xfrm_init_state(t))
......
...@@ -103,8 +103,12 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -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); top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
/* DS disclosed */ /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */
top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos, 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); XFRM_MODE_SKB_CB(skb)->tos);
flags = x->props.flags; flags = x->props.flags;
......
...@@ -49,8 +49,11 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -49,8 +49,11 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
sizeof(top_iph->flow_lbl)); sizeof(top_iph->flow_lbl));
top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family);
dsfield = XFRM_MODE_SKB_CB(skb)->tos; if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
dsfield = INET_ECN_encapsulate(dsfield, dsfield); 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) if (x->props.flags & XFRM_STATE_NOECN)
dsfield &= ~INET_ECN_MASK; dsfield &= ~INET_ECN_MASK;
ipv6_change_dsfield(top_iph, 0, dsfield); ipv6_change_dsfield(top_iph, 0, dsfield);
......
...@@ -1187,6 +1187,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) ...@@ -1187,6 +1187,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
goto error; goto error;
x->props.flags = orig->props.flags; x->props.flags = orig->props.flags;
x->props.extra_flags = orig->props.extra_flags;
x->curlft.add_time = orig->curlft.add_time; x->curlft.add_time = orig->curlft.add_time;
x->km.state = orig->km.state; x->km.state = orig->km.state;
......
...@@ -515,6 +515,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, ...@@ -515,6 +515,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
copy_from_user_state(x, p); 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, if ((err = attach_aead(&x->aead, &x->props.ealgo,
attrs[XFRMA_ALG_AEAD]))) attrs[XFRMA_ALG_AEAD])))
goto error; goto error;
...@@ -779,6 +782,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x, ...@@ -779,6 +782,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
copy_to_user_state(x, p); 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) { if (x->coaddr) {
ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
if (ret) if (ret)
...@@ -2302,6 +2312,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { ...@@ -2302,6 +2312,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
[XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) },
[XFRMA_TFCPAD] = { .type = NLA_U32 }, [XFRMA_TFCPAD] = { .type = NLA_U32 },
[XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) }, [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) },
[XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 },
}; };
static struct xfrm_link { static struct xfrm_link {
...@@ -2495,6 +2506,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) ...@@ -2495,6 +2506,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
x->security->ctx_len); x->security->ctx_len);
if (x->coaddr) if (x->coaddr)
l += nla_total_size(sizeof(*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. */ /* Must count x->lastused as it may become non-zero behind our back. */
l += nla_total_size(sizeof(u64)); l += nla_total_size(sizeof(u64));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册