[IPSEC]: Add XFRM_STATE_NOPMTUDISC flag
authorHerbert Xu <herbert@gondor.apana.org.au>
Mon, 20 Jun 2005 20:21:43 +0000 (13:21 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 20 Jun 2005 20:21:43 +0000 (13:21 -0700)
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: Herbert Xu <herbert@gondor.apana.org.au>
Acked-by: James Morris <jmorris@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/pfkeyv2.h
include/linux/xfrm.h
net/ipv4/xfrm4_output.c
net/ipv4/xfrm4_state.c
net/key/af_key.c

index e6b5192202453edfc6fd7d1fac27d2d2fb5c2ef2..724066778affe84f50bbdf8d6a08a245e26132f4 100644 (file)
@@ -245,6 +245,7 @@ struct sadb_x_nat_t_port {
 
 /* Security Association flags */
 #define SADB_SAFLAGS_PFS       1
+#define SADB_SAFLAGS_NOPMTUDISC        0x20000000
 #define SADB_SAFLAGS_DECAP_DSCP        0x40000000
 #define SADB_SAFLAGS_NOECN     0x80000000
 
index d68391a9b9f30c5a1aa01e8e2f3f551ff62491cd..f0d423300d84aead0467e222d4d3d3961627abef 100644 (file)
@@ -196,6 +196,7 @@ struct xfrm_usersa_info {
        __u8                            flags;
 #define XFRM_STATE_NOECN       1
 #define XFRM_STATE_DECAP_DSCP  2
+#define XFRM_STATE_NOPMTUDISC  4
 };
 
 struct xfrm_usersa_id {
index af2392ae576965e60ec55f59e17b78167f2d0cbe..66620a95942a5f3f05f0964883eb358706130964 100644 (file)
@@ -33,6 +33,7 @@ static void xfrm4_encap(struct sk_buff *skb)
        struct dst_entry *dst = skb->dst;
        struct xfrm_state *x = dst->xfrm;
        struct iphdr *iph, *top_iph;
+       int flags;
 
        iph = skb->nh.iph;
        skb->h.ipiph = iph;
@@ -51,10 +52,13 @@ static void xfrm4_encap(struct sk_buff *skb)
 
        /* DS disclosed */
        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);
 
-       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)
                __ip_select_ident(top_iph, dst, 0);
 
index 223a2e83853f9d6e6c8bb8802498bf907cf32d79..050611d7a9670d178c37cc6a835fd7503f0117b9 100644 (file)
@@ -7,12 +7,20 @@
  *
  */
 
+#include <net/ip.h>
 #include <net/xfrm.h>
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
 
 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
 __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
                     struct xfrm_tmpl *tmpl,
@@ -109,6 +117,7 @@ __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto,
 static struct xfrm_state_afinfo xfrm4_state_afinfo = {
        .family                 = AF_INET,
        .lock                   = RW_LOCK_UNLOCKED,
+       .init_flags             = xfrm4_init_flags,
        .init_tempsel           = __xfrm4_init_tempsel,
        .state_lookup           = __xfrm4_state_lookup,
        .find_acq               = __xfrm4_find_acq,
index 652dd09ccd3a653cb3340960dc90d872ad38bdd4..4879743b945ae5956c6713a6c50dc5a2052f37ae 100644 (file)
@@ -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;
        if (x->props.flags & XFRM_STATE_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 */
        if (hsc & 2) {
@@ -974,6 +976,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
                x->props.flags |= XFRM_STATE_NOECN;
        if (sa->sadb_sa_flags & SADB_SAFLAGS_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];
        if (lifetime != NULL) {