On Tue, Jul 22, 2003 at 11:44:08PM -0700, David S. Miller wrote: > > So the new bits should mean "disable ECN forwarding". > > Ok? That's fine by me. Here is the patch which does that. -- Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ ) Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: kernel-source-2.5/include/linux/pfkeyv2.h =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/linux/pfkeyv2.h,v retrieving revision 1.2 diff -u -r1.2 pfkeyv2.h --- kernel-source-2.5/include/linux/pfkeyv2.h 22 Jul 2003 09:13:59 -0000 1.2 +++ kernel-source-2.5/include/linux/pfkeyv2.h 23 Jul 2003 06:55:12 -0000 @@ -245,6 +245,7 @@ /* Security Association flags */ #define SADB_SAFLAGS_PFS 1 +#define SADB_SAFLAGS_NOECN 0x80000000 /* Security Association states */ #define SADB_SASTATE_LARVAL 0 Index: kernel-source-2.5/include/linux/xfrm.h =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/linux/xfrm.h,v retrieving revision 1.5 diff -u -r1.5 xfrm.h --- kernel-source-2.5/include/linux/xfrm.h 22 Jul 2003 09:13:59 -0000 1.5 +++ kernel-source-2.5/include/linux/xfrm.h 23 Jul 2003 06:55:23 -0000 @@ -166,6 +166,8 @@ __u16 family; __u8 mode; /* 0=transport,1=tunnel */ __u8 replay_window; + __u8 flags; +#define XFRM_STATE_NOECN 1 }; struct xfrm_usersa_id { Index: kernel-source-2.5/include/net/inet_ecn.h =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/inet_ecn.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 inet_ecn.h --- kernel-source-2.5/include/net/inet_ecn.h 19 Oct 2002 04:02:29 -0000 1.1.1.1 +++ kernel-source-2.5/include/net/inet_ecn.h 22 Jul 2003 10:47:31 -0000 @@ -1,6 +1,8 @@ #ifndef _INET_ECN_H_ #define _INET_ECN_H_ +#include <linux/ip.h> + static inline int INET_ECN_is_ce(__u8 dsfield) { return (dsfield&3) == 3; @@ -44,11 +46,21 @@ iph->tos |= 1; } +static inline void IP_ECN_clear(struct iphdr *iph) +{ + iph->tos &= ~3; +} + struct ipv6hdr; static inline void IP6_ECN_set_ce(struct ipv6hdr *iph) { *(u32*)iph |= htonl(1<<20); +} + +static inline void IP6_ECN_clear(struct ipv6hdr *iph) +{ + *(u32*)iph &= ~htonl(3<<20); } #define ip6_get_dsfield(iph) ((ntohs(*(u16*)(iph)) >> 4) & 0xFF) Index: kernel-source-2.5/include/net/xfrm.h =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/xfrm.h,v retrieving revision 1.13 diff -u -r1.13 xfrm.h --- kernel-source-2.5/include/net/xfrm.h 22 Jul 2003 09:13:59 -0000 1.13 +++ kernel-source-2.5/include/net/xfrm.h 22 Jul 2003 09:14:50 -0000 @@ -108,6 +108,7 @@ u8 mode; u8 replay_window; u8 aalgo, ealgo, calgo; + u8 flags; u16 family; xfrm_address_t saddr; int header_len; Index: kernel-source-2.5/net/ipv4/ah4.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/ah4.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 ah4.c --- kernel-source-2.5/net/ipv4/ah4.c 17 Jun 2003 04:20:22 -0000 1.1.1.1 +++ kernel-source-2.5/net/ipv4/ah4.c 23 Jul 2003 06:56:53 -0000 @@ -1,5 +1,6 @@ #include <linux/config.h> #include <linux/module.h> +#include <net/inet_ecn.h> #include <net/ip.h> #include <net/xfrm.h> #include <net/ah.h> @@ -123,6 +124,8 @@ top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; if (x->props.mode) { + if (x->props.flags & XFRM_STATE_NOECN) + IP_ECN_clear(top_iph); top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET); memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); } else { Index: kernel-source-2.5/net/ipv4/esp4.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/esp4.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 esp4.c --- kernel-source-2.5/net/ipv4/esp4.c 17 Jun 2003 04:20:05 -0000 1.1.1.1 +++ kernel-source-2.5/net/ipv4/esp4.c 23 Jul 2003 06:57:01 -0000 @@ -1,5 +1,6 @@ #include <linux/config.h> #include <linux/module.h> +#include <net/inet_ecn.h> #include <net/ip.h> #include <net/xfrm.h> #include <net/esp.h> @@ -109,6 +110,8 @@ top_iph->ihl = 5; top_iph->version = 4; top_iph->tos = iph->tos; /* DS disclosed */ + if (x->props.flags & XFRM_STATE_NOECN) + IP_ECN_clear(top_iph); top_iph->tot_len = htons(skb->len + alen); top_iph->frag_off = iph->frag_off&htons(IP_DF); if (!(top_iph->frag_off)) Index: kernel-source-2.5/net/ipv4/ipcomp.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/ipcomp.c,v retrieving revision 1.1.1.3 diff -u -r1.1.1.3 ipcomp.c --- kernel-source-2.5/net/ipv4/ipcomp.c 17 Jun 2003 04:20:21 -0000 1.1.1.3 +++ kernel-source-2.5/net/ipv4/ipcomp.c 23 Jul 2003 06:57:18 -0000 @@ -18,6 +18,7 @@ #include <asm/scatterlist.h> #include <linux/crypto.h> #include <linux/pfkeyv2.h> +#include <net/inet_ecn.h> #include <net/ip.h> #include <net/xfrm.h> #include <net/icmp.h> @@ -210,6 +211,8 @@ top_iph = (struct iphdr *)skb_push(skb, sizeof(struct ip_comp_hdr)); memcpy(top_iph, &tmp_iph, iph->ihl * 4); iph = top_iph; + if (x->props.mode && (x->props.flags & XFRM_STATE_NOECN)) + IP_ECN_clear(iph); iph->tot_len = htons(skb->len); iph->protocol = IPPROTO_COMP; iph->check = 0; Index: kernel-source-2.5/net/ipv4/xfrm4_input.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/xfrm4_input.c,v retrieving revision 1.2 diff -u -r1.2 xfrm4_input.c --- kernel-source-2.5/net/ipv4/xfrm4_input.c 2 Jun 2003 10:55:50 -0000 1.2 +++ kernel-source-2.5/net/ipv4/xfrm4_input.c 23 Jul 2003 06:57:35 -0000 @@ -10,6 +10,7 @@ */ #include <linux/slab.h> +#include <net/inet_ecn.h> #include <net/ip.h> #include <net/xfrm.h> @@ -20,6 +21,15 @@ return xfrm4_rcv_encap(skb, 0); } +static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb) +{ + struct iphdr *inner_iph = skb->nh.iph; + + if (INET_ECN_is_ce(outer_iph->tos) && + INET_ECN_is_not_ce(inner_iph->tos)) + IP_ECN_set_ce(inner_iph); +} + int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) { int err; @@ -75,6 +85,8 @@ if (iph->protocol != IPPROTO_IPIP) goto drop; skb->nh.raw = skb->data; + if (!(x->props.flags & XFRM_STATE_NOECN)) + ipip_ecn_decapsulate(iph, skb); iph = skb->nh.iph; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); decaps = 1; Index: kernel-source-2.5/net/ipv6/ah6.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/ah6.c,v retrieving revision 1.1.1.5 diff -u -r1.1.1.5 ah6.c --- kernel-source-2.5/net/ipv6/ah6.c 17 Jun 2003 04:20:07 -0000 1.1.1.5 +++ kernel-source-2.5/net/ipv6/ah6.c 23 Jul 2003 06:58:45 -0000 @@ -26,6 +26,7 @@ #include <linux/config.h> #include <linux/module.h> +#include <net/inet_ecn.h> #include <net/ip.h> #include <net/xfrm.h> #include <net/ah.h> @@ -220,6 +221,8 @@ skb->nh.ipv6h->flow_lbl[0] = iph->flow_lbl[0]; skb->nh.ipv6h->flow_lbl[1] = iph->flow_lbl[1]; skb->nh.ipv6h->flow_lbl[2] = iph->flow_lbl[2]; + if (x->props.flags & XFRM_STATE_NOECN) + IP6_ECN_clear(skb->nh.ipv6h); } else { memcpy(skb->nh.ipv6h, iph, hdr_len); skb->nh.raw[nh_offset] = IPPROTO_AH; Index: kernel-source-2.5/net/ipv6/esp6.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/esp6.c,v retrieving revision 1.1.1.5 diff -u -r1.1.1.5 esp6.c --- kernel-source-2.5/net/ipv6/esp6.c 17 Jun 2003 04:20:06 -0000 1.1.1.5 +++ kernel-source-2.5/net/ipv6/esp6.c 23 Jul 2003 07:11:28 -0000 @@ -26,6 +26,7 @@ #include <linux/config.h> #include <linux/module.h> +#include <net/inet_ecn.h> #include <net/ip.h> #include <net/xfrm.h> #include <net/esp.h> @@ -121,6 +122,8 @@ top_iph->flow_lbl[0] = iph->flow_lbl[0]; top_iph->flow_lbl[1] = iph->flow_lbl[1]; top_iph->flow_lbl[2] = iph->flow_lbl[2]; + if (x->props.flags & XFRM_STATE_NOECN) + IP6_ECN_clear(top_iph); top_iph->nexthdr = IPPROTO_ESP; top_iph->payload_len = htons(skb->len + alen - sizeof(struct ipv6hdr)); top_iph->hop_limit = iph->hop_limit; Index: kernel-source-2.5/net/ipv6/ipcomp6.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/ipcomp6.c,v retrieving revision 1.1.1.2 diff -u -r1.1.1.2 ipcomp6.c --- kernel-source-2.5/net/ipv6/ipcomp6.c 17 Jun 2003 04:20:01 -0000 1.1.1.2 +++ kernel-source-2.5/net/ipv6/ipcomp6.c 23 Jul 2003 07:11:34 -0000 @@ -32,6 +32,7 @@ */ #include <linux/config.h> #include <linux/module.h> +#include <net/inet_ecn.h> #include <net/ip.h> #include <net/xfrm.h> #include <net/ipcomp.h> @@ -201,6 +202,8 @@ memcpy(top_iph, tmp_iph, hdr_len); kfree(tmp_iph); + if (x->props.mode && (x->props.flags & XFRM_STATE_NOECN)) + IP6_ECN_clear(top_iph); top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); skb->nh.raw = skb->data; /* top_iph */ ip6_find_1stfragopt(skb, &prevhdr); Index: kernel-source-2.5/net/ipv6/xfrm6_input.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/xfrm6_input.c,v retrieving revision 1.1.1.5 diff -u -r1.1.1.5 xfrm6_input.c --- kernel-source-2.5/net/ipv6/xfrm6_input.c 2 Jul 2003 20:58:14 -0000 1.1.1.5 +++ kernel-source-2.5/net/ipv6/xfrm6_input.c 23 Jul 2003 07:11:04 -0000 @@ -9,12 +9,21 @@ * IPv6 support */ +#include <net/inet_ecn.h> #include <net/ip.h> #include <net/ipv6.h> #include <net/xfrm.h> static kmem_cache_t *secpath_cachep; +static inline void ipip6_ecn_decapsulate(struct ipv6hdr *iph, + struct sk_buff *skb) +{ + if (INET_ECN_is_ce(ip6_get_dsfield(iph)) && + INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h))) + IP6_ECN_set_ce(skb->nh.ipv6h); +} + int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) { struct sk_buff *skb = *pskb; @@ -71,6 +80,8 @@ if (nexthdr != IPPROTO_IPV6) goto drop; skb->nh.raw = skb->data; + if (!(x->props.flags & XFRM_STATE_NOECN)) + ipip6_ecn_decapsulate(iph, skb); iph = skb->nh.ipv6h; decaps = 1; break; Index: kernel-source-2.5/net/key/af_key.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/key/af_key.c,v retrieving revision 1.11 diff -u -r1.11 af_key.c --- kernel-source-2.5/net/key/af_key.c 22 Jul 2003 09:13:59 -0000 1.11 +++ kernel-source-2.5/net/key/af_key.c 23 Jul 2003 06:55:40 -0000 @@ -681,6 +681,8 @@ } sa->sadb_sa_flags = 0; + if (x->props.flags & XFRM_STATE_NOECN) + sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN; /* hard time */ if (hsc & 2) { @@ -957,6 +959,8 @@ x->id.proto = proto; x->id.spi = sa->sadb_sa_spi; x->props.replay_window = sa->sadb_sa_replay; + if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN) + x->props.flags |= XFRM_STATE_NOECN; lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1]; if (lifetime != NULL) { Index: kernel-source-2.5/net/xfrm/xfrm_user.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/xfrm/xfrm_user.c,v retrieving revision 1.9 diff -u -r1.9 xfrm_user.c --- kernel-source-2.5/net/xfrm/xfrm_user.c 5 Jul 2003 22:54:05 -0000 1.9 +++ kernel-source-2.5/net/xfrm/xfrm_user.c 22 Jul 2003 09:17:50 -0000 @@ -201,6 +201,7 @@ x->props.reqid = p->reqid; x->props.family = p->family; x->props.saddr = p->saddr; + x->props.flags = p->flags; } static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, @@ -305,6 +306,7 @@ p->replay_window = x->props.replay_window; p->reqid = x->props.reqid; p->family = x->props.family; + p->flags = x->props.flags; p->seq = x->km.seq; }