summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_ecn.c
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2003-10-29 15:07:04 +0000
committerume <ume@FreeBSD.org>2003-10-29 15:07:04 +0000
commitb9fecc82d3e55cefb5fd427307272fed377b780a (patch)
treeff2af6160ee3c3b0bf6e218dc2107ae003e82cde /sys/netinet/ip_ecn.c
parentf965698ed4683de29221f38b96189223a4cf0b2e (diff)
downloadFreeBSD-src-b9fecc82d3e55cefb5fd427307272fed377b780a.zip
FreeBSD-src-b9fecc82d3e55cefb5fd427307272fed377b780a.tar.gz
add ECN support in layer-3.
- implement the tunnel egress rule in ip_ecn_egress() in ip_ecn.c. make ip{,6}_ecn_egress() return integer to tell the caller that this packet should be dropped. - handle ECN at fragment reassembly in ip_input.c and frag6.c. Obtained from: KAME
Diffstat (limited to 'sys/netinet/ip_ecn.c')
-rw-r--r--sys/netinet/ip_ecn.c84
1 files changed, 71 insertions, 13 deletions
diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c
index de3d38e..9ea2f6b 100644
--- a/sys/netinet/ip_ecn.c
+++ b/sys/netinet/ip_ecn.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ip_ecn.c,v 1.11 2001/05/03 16:09:29 itojun Exp $ */
+/* $KAME: ip_ecn.c,v 1.12 2002/01/07 11:34:47 kjc Exp $ */
/*
* Copyright (C) 1999 WIDE Project.
@@ -56,6 +56,37 @@
#endif
/*
+ * ECN and TOS (or TCLASS) processing rules at tunnel encapsulation and
+ * decapsulation from RFC3168:
+ *
+ * Outer Hdr at Inner Hdr at
+ * Encapsulator Decapsulator
+ * Header fields: -------------------- ------------
+ * DS Field copied from inner hdr no change
+ * ECN Field constructed by (I) constructed by (E)
+ *
+ * ECN_ALLOWED (full functionality):
+ * (I) if the ECN field in the inner header is set to CE, then set the
+ * ECN field in the outer header to ECT(0).
+ * otherwise, copy the ECN field to the outer header.
+ *
+ * (E) if the ECN field in the outer header is set to CE and the ECN
+ * field of the inner header is not-ECT, drop the packet.
+ * if the ECN field in the inner header is set to ECT(0) or ECT(1)
+ * and the ECN field in the outer header is set to CE, then copy CE to
+ * the inner header. otherwise, make no change to the inner header.
+ *
+ * ECN_FORBIDDEN (limited functionality):
+ * (I) set the ECN field to not-ECT in the outer header.
+ *
+ * (E) if the ECN field in the outer header is set to CE, drop the packet.
+ * otherwise, make no change to the ECN field in the inner header.
+ *
+ * the drop rule is for backward compatibility and protection against
+ * erasure of CE.
+ */
+
+/*
* modify outer ECN (TOS) field on ingress operation (tunnel encapsulation).
*/
void
@@ -70,10 +101,18 @@ ip_ecn_ingress(mode, outer, inner)
*outer = *inner;
switch (mode) {
case ECN_ALLOWED: /* ECN allowed */
- *outer &= ~IPTOS_CE;
+ /*
+ * full-functionality: if the inner is CE, set ECT(0)
+ * to the outer. otherwise, copy the ECN field.
+ */
+ if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
+ *outer &= ~IPTOS_ECN_ECT1;
break;
case ECN_FORBIDDEN: /* ECN forbidden */
- *outer &= ~(IPTOS_ECT | IPTOS_CE);
+ /*
+ * limited-functionality: set not-ECT to the outer
+ */
+ *outer &= ~IPTOS_ECN_MASK;
break;
case ECN_NOCARE: /* no consideration to ECN */
break;
@@ -82,8 +121,9 @@ ip_ecn_ingress(mode, outer, inner)
/*
* modify inner ECN (TOS) field on egress operation (tunnel decapsulation).
+ * the caller should drop the packet if the return value is 0.
*/
-void
+int
ip_ecn_egress(mode, outer, inner)
int mode;
const u_int8_t *outer;
@@ -94,13 +134,28 @@ ip_ecn_egress(mode, outer, inner)
switch (mode) {
case ECN_ALLOWED:
- if (*outer & IPTOS_CE)
- *inner |= IPTOS_CE;
+ /*
+ * full-functionality: if the outer is CE and the inner is
+ * not-ECT, should drop it. otherwise, copy CE.
+ */
+ if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE) {
+ if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
+ return (0);
+ *inner |= IPTOS_ECN_CE;
+ }
break;
case ECN_FORBIDDEN: /* ECN forbidden */
+ /*
+ * limited-functionality: if the outer is CE, should drop it.
+ * otherwise, leave the inner.
+ */
+ if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
+ return (0);
+ break;
case ECN_NOCARE: /* no consideration to ECN */
break;
}
+ return (1);
}
#ifdef INET6
@@ -115,28 +170,31 @@ ip6_ecn_ingress(mode, outer, inner)
if (!outer || !inner)
panic("NULL pointer passed to ip6_ecn_ingress");
- outer8 = (ntohl(*outer) >> 20) & 0xff;
inner8 = (ntohl(*inner) >> 20) & 0xff;
ip_ecn_ingress(mode, &outer8, &inner8);
*outer &= ~htonl(0xff << 20);
*outer |= htonl((u_int32_t)outer8 << 20);
}
-void
+int
ip6_ecn_egress(mode, outer, inner)
int mode;
const u_int32_t *outer;
u_int32_t *inner;
{
- u_int8_t outer8, inner8;
+ u_int8_t outer8, inner8, oinner8;
if (!outer || !inner)
panic("NULL pointer passed to ip6_ecn_egress");
outer8 = (ntohl(*outer) >> 20) & 0xff;
- inner8 = (ntohl(*inner) >> 20) & 0xff;
- ip_ecn_egress(mode, &outer8, &inner8);
- *inner &= ~htonl(0xff << 20);
- *inner |= htonl((u_int32_t)inner8 << 20);
+ inner8 = oinner8 = (ntohl(*inner) >> 20) & 0xff;
+ if (ip_ecn_egress(mode, &outer8, &inner8) == 0)
+ return (0);
+ if (inner8 != oinner8) {
+ *inner &= ~htonl(0xff << 20);
+ *inner |= htonl((u_int32_t)inner8 << 20);
+ }
+ return (1);
}
#endif
OpenPOWER on IntegriCloud