Commit dd87147e authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[IPSEC]: Add XFRM_STATE_NOPMTUDISC flag

This patch adds the flag XFRM_STATE_NOPMTUDISC for xfrm states.  It is
similar to the nopmtudisc on IPIP/GRE tunnels.  It only has an effect
on IPv4 tunnel mode states.  For these states, it will ensure that the
DF flag is always cleared.

This is primarily useful to work around ICMP blackholes.

In future this flag could also allow a larger MTU to be set within the
tunnel just like IPIP/GRE tunnels.  This could be useful for short haul
tunnels where temporary fragmentation outside the tunnel is desired over
smaller fragments inside the tunnel.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Acked-by: default avatarJames Morris <jmorris@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d094cd83
...@@ -245,6 +245,7 @@ struct sadb_x_nat_t_port { ...@@ -245,6 +245,7 @@ struct sadb_x_nat_t_port {
/* Security Association flags */ /* Security Association flags */
#define SADB_SAFLAGS_PFS 1 #define SADB_SAFLAGS_PFS 1
#define SADB_SAFLAGS_NOPMTUDISC 0x20000000
#define SADB_SAFLAGS_DECAP_DSCP 0x40000000 #define SADB_SAFLAGS_DECAP_DSCP 0x40000000
#define SADB_SAFLAGS_NOECN 0x80000000 #define SADB_SAFLAGS_NOECN 0x80000000
......
...@@ -196,6 +196,7 @@ struct xfrm_usersa_info { ...@@ -196,6 +196,7 @@ struct xfrm_usersa_info {
__u8 flags; __u8 flags;
#define XFRM_STATE_NOECN 1 #define XFRM_STATE_NOECN 1
#define XFRM_STATE_DECAP_DSCP 2 #define XFRM_STATE_DECAP_DSCP 2
#define XFRM_STATE_NOPMTUDISC 4
}; };
struct xfrm_usersa_id { struct xfrm_usersa_id {
......
...@@ -33,6 +33,7 @@ static void xfrm4_encap(struct sk_buff *skb) ...@@ -33,6 +33,7 @@ static void xfrm4_encap(struct sk_buff *skb)
struct dst_entry *dst = skb->dst; struct dst_entry *dst = skb->dst;
struct xfrm_state *x = dst->xfrm; struct xfrm_state *x = dst->xfrm;
struct iphdr *iph, *top_iph; struct iphdr *iph, *top_iph;
int flags;
iph = skb->nh.iph; iph = skb->nh.iph;
skb->h.ipiph = iph; skb->h.ipiph = iph;
...@@ -51,10 +52,13 @@ static void xfrm4_encap(struct sk_buff *skb) ...@@ -51,10 +52,13 @@ static void xfrm4_encap(struct sk_buff *skb)
/* DS disclosed */ /* DS disclosed */
top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);
if (x->props.flags & XFRM_STATE_NOECN)
flags = x->props.flags;
if (flags & XFRM_STATE_NOECN)
IP_ECN_clear(top_iph); IP_ECN_clear(top_iph);
top_iph->frag_off = iph->frag_off & htons(IP_DF); top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
0 : (iph->frag_off & htons(IP_DF));
if (!top_iph->frag_off) if (!top_iph->frag_off)
__ip_select_ident(top_iph, dst, 0); __ip_select_ident(top_iph, dst, 0);
......
...@@ -7,12 +7,20 @@ ...@@ -7,12 +7,20 @@
* *
*/ */
#include <net/ip.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <linux/pfkeyv2.h> #include <linux/pfkeyv2.h>
#include <linux/ipsec.h> #include <linux/ipsec.h>
static struct xfrm_state_afinfo xfrm4_state_afinfo; static struct xfrm_state_afinfo xfrm4_state_afinfo;
static int xfrm4_init_flags(struct xfrm_state *x)
{
if (ipv4_config.no_pmtu_disc)
x->props.flags |= XFRM_STATE_NOPMTUDISC;
return 0;
}
static void static void
__xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
struct xfrm_tmpl *tmpl, struct xfrm_tmpl *tmpl,
...@@ -109,6 +117,7 @@ __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, ...@@ -109,6 +117,7 @@ __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto,
static struct xfrm_state_afinfo xfrm4_state_afinfo = { static struct xfrm_state_afinfo xfrm4_state_afinfo = {
.family = AF_INET, .family = AF_INET,
.lock = RW_LOCK_UNLOCKED, .lock = RW_LOCK_UNLOCKED,
.init_flags = xfrm4_init_flags,
.init_tempsel = __xfrm4_init_tempsel, .init_tempsel = __xfrm4_init_tempsel,
.state_lookup = __xfrm4_state_lookup, .state_lookup = __xfrm4_state_lookup,
.find_acq = __xfrm4_find_acq, .find_acq = __xfrm4_find_acq,
......
...@@ -690,6 +690,8 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, ...@@ -690,6 +690,8 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN; sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN;
if (x->props.flags & XFRM_STATE_DECAP_DSCP) if (x->props.flags & XFRM_STATE_DECAP_DSCP)
sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP; sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP;
if (x->props.flags & XFRM_STATE_NOPMTUDISC)
sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC;
/* hard time */ /* hard time */
if (hsc & 2) { if (hsc & 2) {
...@@ -974,6 +976,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, ...@@ -974,6 +976,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
x->props.flags |= XFRM_STATE_NOECN; x->props.flags |= XFRM_STATE_NOECN;
if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP) if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP)
x->props.flags |= XFRM_STATE_DECAP_DSCP; x->props.flags |= XFRM_STATE_DECAP_DSCP;
if (sa->sadb_sa_flags & SADB_SAFLAGS_NOPMTUDISC)
x->props.flags |= XFRM_STATE_NOPMTUDISC;
lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1]; lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1];
if (lifetime != NULL) { if (lifetime != NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment