From nobody Thu Mar 19 10:29:05 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fc2463FZ4z6W7pY for ; Thu, 19 Mar 2026 10:29:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fc24629glz3f70 for ; Thu, 19 Mar 2026 10:29:10 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1773916150; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Z/VUTeWPkUmK/5hODPafvTwNLbYG52FN214XoTI9riU=; b=x8TKcyeG8Asfo8/IOYUAQ4XQ5eo6YBtPC84lS6Rim4TqyoJXYNYWTXdI7M7vQKt8NT2ks7 GLTZb53Xx57KwtZtcisBqkuevxxkIywYj4wToXddmJZ3yJTsU95ODdv7xn0wIsSSaMY+la ys33anrFZeu9NRRCF0lQLyM7qFIjpQekI9O1IGOJQ3EP/K+epjhskroO35ta707LNqd3/C BdGzplYNdabjHXyf6C9n960+GxBCi06tyC902X77sV4bCv5EDJWrrTOYREeqyvLH7SD1WW zguWGML1Xzsa9ya7ewx71D+3KIg4QV+jd+heW2Dewue+erSPhenHq5jmhUHpUw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1773916150; a=rsa-sha256; cv=none; b=F4GLPevoIsRWqTmgKqgkpvEj3NWZTiDnaLRjKw18aj9AdPMjMJIohuFhMUYPtguZI+pVpA m1HDDSSIFPXG2bWNyfUg3VGjwBNlDwT+JKKsB7EJWrSMZJXtXKOING4cCdGMmgcqnPGp4g rE0mjN9DKczeDi+Fwgh5pqKA4JPAnsEW2mUmUo0/W3w+eeppfFz5N/0qaV8zG4zKmVXJH5 nwmItSeoGhMV8RN3Puo0xSC480q+9qP+W0qC2i8XD7tpmeSEbg3Ptw6xakhc+2wIsDYxKW WdVKGgvV7TJgIUcghMJ/9Gr+Ji8hi2e0UjosL//jYZxU6Sss2JLTTbkKT4GcWA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1773916150; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Z/VUTeWPkUmK/5hODPafvTwNLbYG52FN214XoTI9riU=; b=tlCP4zEdroD9R2F2bvSxZnu19+quuMq5UFZgJGKXbsUgIR3shaxvqy3ehqvzX/YBZ5N6xi +7WSCyE/k59+Bo7bXA0RIY8gFsr+DDzoE/u5ZuEdkejlni4czL/M8Cwvj54UpvtZnSQ6P/ LqqPVBSvOYNtnpe1aXxGsXkMUPiT8dT508qTn5Eyo03Nd1VXd5IOOlKkrgJ3/rcFH+s1Oy MvXfeuTRz9BWMbTcSWE9N5zk+pB1piiT6bL9Uso0063McEMEWX/A0lNiQg1sJTr/Vo4viX n9TTcy1UHFBO+ijJw/POMBFPUS/TBDo+FJ4M6L4bBNaAn73dihe2QN5CraU97Q== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fc2461NFJzs14 for ; Thu, 19 Mar 2026 10:29:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 2130f by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 19 Mar 2026 10:29:05 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Pouria Mousavizadeh Tehrani Subject: git: 32a462ba9cdc - main - ecn(9): Update ecn tunneling functions to RFC 6040 List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: pouria X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 32a462ba9cdc8a927c1aba5d9bff9d16d367d7da Auto-Submitted: auto-generated Date: Thu, 19 Mar 2026 10:29:05 +0000 Message-Id: <69bbcff1.2130f.484abf8a@gitrepo.freebsd.org> The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=32a462ba9cdc8a927c1aba5d9bff9d16d367d7da commit 32a462ba9cdc8a927c1aba5d9bff9d16d367d7da Author: Pouria Mousavizadeh Tehrani AuthorDate: 2026-03-19 10:18:34 +0000 Commit: Pouria Mousavizadeh Tehrani CommitDate: 2026-03-19 10:18:34 +0000 ecn(9): Update ecn tunneling functions to RFC 6040 Update ECN tunneling functions from obsolete RFC 3168 to newer RFC 6040. Also, add ECN_COMPLETE to support dangerous packet reporting without causing extra costs to existing caller functions. Finally, return values are specified as macro to reduce confusion, considering extra return values for ECN_WARN and ECN_ALARM were added. Reviewed By: glebius, tuexen Differential Revision: https://reviews.freebsd.org/D53516 --- sys/netinet/ip_ecn.c | 149 +++++++++++++++++++++++++++++++------------------ sys/netinet/ip_ecn.h | 17 +++--- sys/netinet6/ip6_ecn.h | 5 -- 3 files changed, 106 insertions(+), 65 deletions(-) diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c index 0166c8b5d9c5..9b708b265037 100644 --- 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 "opt_inet.h" #include "opt_inet6.h" @@ -58,7 +54,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 @@ -66,18 +62,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(!!!)| (!!!)| + * 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. @@ -94,26 +114,22 @@ void 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 %s", __func__)); *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; } } @@ -126,33 +142,57 @@ int 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 %s", __func__)); 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 @@ -161,31 +201,34 @@ ip6_ecn_ingress(int mode, uint32_t *outer, const uint32_t *inner) { uint8_t outer8, inner8; - if (!outer || !inner) - panic("NULL pointer passed to ip6_ecn_ingress"); + KASSERT(outer != NULL && inner != NULL, + ("NULL pointer passed to %s", __func__)); - 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 %s", __func__)); - 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/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h index 6632418fc9ca..9ecb7f036fe7 100644 --- a/sys/netinet/ip_ecn.h +++ b/sys/netinet/ip_ecn.h @@ -31,19 +31,22 @@ * 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 */ +#ifdef _KERNEL +#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 diff --git a/sys/netinet6/ip6_ecn.h b/sys/netinet6/ip6_ecn.h index 169e027dc265..6b82796e83a5 100644 --- 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 *);