Page MenuHomeFreeBSD

D53516.diff
No OneTemporary

D53516.diff

diff --git a/sys/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h
--- a/sys/netinet/ip_ecn.h
+++ b/sys/netinet/ip_ecn.h
@@ -31,20 +31,25 @@
* SUCH DAMAGE.
*
*/
-/*
- * ECN consideration on tunnel ingress/egress operation.
- * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt
- */
#ifndef _NETINET_IP_ECN_H_
#define _NETINET_IP_ECN_H_
-#define ECN_ALLOWED 1 /* ECN allowed */
-#define ECN_FORBIDDEN 0 /* ECN forbidden */
+#ifndef _KERNEL
+#error "no user-serviceable parts inside"
+#endif
+
+#define ECN_COMPLETE 2 /* ECN normal mode with security log */
+#define ECN_ALLOWED 1 /* ECN normal mode */
+#define ECN_FORBIDDEN 0 /* ECN compatibility mode */
#define ECN_NOCARE (-1) /* no consideration to ECN */
-#ifdef _KERNEL
+/* ip[6]_ecn_egress return values */
+#define ECN_DROP 0 /* caller MUST drop the packet */
+#define ECN_SUCCESS 1 /* success */
+#define ECN_WARN 2 /* caller MAY log */
+#define ECN_ALARM 3 /* caller SHOULD log and MAY raise alarm */
+
extern void ip_ecn_ingress(int, uint8_t *, const uint8_t *);
extern int ip_ecn_egress(int, const uint8_t *, uint8_t *);
#endif
-#endif
diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c
--- a/sys/netinet/ip_ecn.c
+++ b/sys/netinet/ip_ecn.c
@@ -31,10 +31,6 @@
* SUCH DAMAGE.
*
*/
-/*
- * ECN consideration on tunnel ingress/egress operation.
- * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt
- */
#include <sys/cdefs.h>
#include "opt_inet.h"
@@ -59,7 +55,7 @@
/*
* ECN and TOS (or TCLASS) processing rules at tunnel encapsulation and
- * decapsulation from RFC3168:
+ * decapsulation from RFC6040:
*
* Outer Hdr at Inner Hdr at
* Encapsulator Decapsulator
@@ -67,18 +63,42 @@
* 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.
+ * ECN_ALLOWED (normal mode):
+ * (I) 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.
+ * If the ECN field in the inner header is set to ECT(0) and the ECN
+ * field in the outer header is set to ECT(1), copy ECT(1) to
+ * the inner header. 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, copy CE to the inner header.
+ * Otherwise, make no change to the inner header. This behaviour can be
+ * summarized in the table below:
+ *
+ * Outer Header at Decapsulator
+ * +---------+------------+------------+------------+
+ * | Not-ECT | ECT(0) | ECT(1) | CE |
+ * Inner Hdr: +---------+------------+------------+------------+
+ * Not-ECT | Not-ECT |Not-ECT(!!!)|Not-ECT(!!!)| <drop>(!!!)|
+ * ECT(0) | ECT(0) | ECT(0) | ECT(1) | CE |
+ * ECT(1) | ECT(1) | ECT(1) (!) | ECT(1) | CE |
+ * CE | CE | CE | CE(!!!)| CE |
+ * +---------+------------+------------+------------+
+ *
+ * ECN_COMPLETE (normal mode with security log):
+ * certain combinations indicated in table by '(!!!)' or '(!)',
+ * where '(!!!)' means the combination always potentially dangerous which
+ * returns 3, while '(!)' means possibly dangerous in which returns 2.
+ * These combinations are unsed by previous ECN tunneling specifications
+ * and could be logged. Also, in case of more dangerous ones, the
+ * decapsulator SHOULD log the event and MAY also raise an alarm.
+ *
+ * Note: Caller SHOULD use rate-limited alarms so that the anomalous
+ * combinations will not amplify into a flood of alarm messages.
+ * Also, it MUST be possible to suppress alarms or logging.
*
- * ECN_FORBIDDEN (limited functionality):
+ * ECN_FORBIDDEN (compatibility mode):
* (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.
@@ -95,26 +115,22 @@
ip_ecn_ingress(int mode, uint8_t *outer, const uint8_t *inner)
{
- if (!outer || !inner)
- panic("NULL pointer passed to ip_ecn_ingress");
+ KASSERT(outer != NULL && inner != NULL,
+ "NULL pointer passed to ip_ecn_ingress");
*outer = *inner;
switch (mode) {
- case ECN_ALLOWED: /* ECN allowed */
- /*
- * 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;
+ case ECN_COMPLETE:
+ case ECN_ALLOWED:
+ /* normal mode: always copy the ECN field. */
break;
- case ECN_FORBIDDEN: /* ECN forbidden */
- /*
- * limited-functionality: set not-ECT to the outer
- */
+
+ case ECN_FORBIDDEN:
+ /* compatibility mode: set not-ECT to the outer */
*outer &= ~IPTOS_ECN_MASK;
break;
- case ECN_NOCARE: /* no consideration to ECN */
+
+ case ECN_NOCARE:
break;
}
}
@@ -127,33 +143,57 @@
ip_ecn_egress(int mode, const uint8_t *outer, uint8_t *inner)
{
- if (!outer || !inner)
- panic("NULL pointer passed to ip_ecn_egress");
+ KASSERT(outer != NULL && inner != NULL,
+ "NULL pointer passed to ip_ecn_egress");
switch (mode) {
+ case ECN_COMPLETE:
+ if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_ECT0) {
+ /* if the outer is ECT(0) and inner is ECT(1) raise a warning */
+ if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_ECT1)
+ return (ECN_WARN);
+ /* if the inner is not-ECT and outer is ECT(0) raise an alarm */
+ if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
+ return (ECN_ALARM);
+ return (ECN_SUCCESS);
+ } else if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_ECT1) {
+ /* if the outer is ECT(1) and inner is CE or ECT(1), raise an alarm */
+ if (((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_CE) ||
+ ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT))
+ return (ECN_ALARM);
+ /* if the outer is ECT(1) and inner is ECT(0), copy ECT(1) */
+ if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_ECT0)
+ *inner = IPTOS_ECN_ECT1;
+ return (ECN_SUCCESS);
+ }
+ /* fallthrough */
case ECN_ALLOWED:
- /*
- * 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 the outer is CE and the inner is not-ECT, drop it. */
if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
- return (0);
+ return (ECN_DROP);
+ /* otherwise, copy CE */
*inner |= IPTOS_ECN_CE;
+ } else if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_ECT1) {
+ /* if the outer is ECT(1) and inner is ECT(0), copy ECT(1) */
+ if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_ECT0)
+ *inner = IPTOS_ECN_ECT1;
}
break;
- case ECN_FORBIDDEN: /* ECN forbidden */
+
+ case ECN_FORBIDDEN:
/*
- * limited-functionality: if the outer is CE, should drop it.
+ * compatibility mode: if the outer is CE, should drop it.
* otherwise, leave the inner.
*/
if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
- return (0);
+ return (ECN_DROP);
break;
- case ECN_NOCARE: /* no consideration to ECN */
+
+ case ECN_NOCARE:
break;
}
- return (1);
+ return (ECN_SUCCESS);
}
#ifdef INET6
@@ -162,31 +202,34 @@
{
uint8_t outer8, inner8;
- if (!outer || !inner)
- panic("NULL pointer passed to ip6_ecn_ingress");
+ KASSERT(outer != NULL && inner != NULL,
+ "NULL pointer passed to ip6_ecn_ingress");
- inner8 = (ntohl(*inner) >> 20) & 0xff;
+ inner8 = (ntohl(*inner) >> IPV6_FLOWLABEL_LEN) & 0xff;
ip_ecn_ingress(mode, &outer8, &inner8);
- *outer &= ~htonl(0xff << 20);
- *outer |= htonl((uint32_t)outer8 << 20);
+ *outer &= ~htonl(0xff << IPV6_FLOWLABEL_LEN);
+ *outer |= htonl((uint32_t)outer8 << IPV6_FLOWLABEL_LEN);
}
int
ip6_ecn_egress(int mode, const uint32_t *outer, uint32_t *inner)
{
uint8_t outer8, inner8, oinner8;
+ int ret;
+
+ KASSERT(outer != NULL && inner != NULL,
+ "NULL pointer passed to ip6_ecn_egress");
- if (!outer || !inner)
- panic("NULL pointer passed to ip6_ecn_egress");
+ outer8 = (ntohl(*outer) >> IPV6_FLOWLABEL_LEN) & 0xff;
+ inner8 = oinner8 = (ntohl(*inner) >> IPV6_FLOWLABEL_LEN) & 0xff;
- outer8 = (ntohl(*outer) >> 20) & 0xff;
- inner8 = oinner8 = (ntohl(*inner) >> 20) & 0xff;
- if (ip_ecn_egress(mode, &outer8, &inner8) == 0)
- return (0);
+ ret = ip_ecn_egress(mode, &outer8, &inner8);
+ if (ret == ECN_DROP)
+ return (ECN_DROP);
if (inner8 != oinner8) {
- *inner &= ~htonl(0xff << 20);
- *inner |= htonl((uint32_t)inner8 << 20);
+ *inner &= ~htonl(0xff << IPV6_FLOWLABEL_LEN);
+ *inner |= htonl((uint32_t)inner8 << IPV6_FLOWLABEL_LEN);
}
- return (1);
+ return (ret);
}
#endif
diff --git a/sys/netinet6/ip6_ecn.h b/sys/netinet6/ip6_ecn.h
--- a/sys/netinet6/ip6_ecn.h
+++ b/sys/netinet6/ip6_ecn.h
@@ -31,11 +31,6 @@
* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $
*/
-/*
- * ECN consideration on tunnel ingress/egress operation.
- * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt
- */
-
#ifdef _KERNEL
extern void ip6_ecn_ingress(int, uint32_t *, const uint32_t *);
extern int ip6_ecn_egress(int, const uint32_t *, uint32_t *);

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 22, 3:13 AM (14 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27132950
Default Alt Text
D53516.diff (9 KB)

Event Timeline