Date: Fri, 3 Jun 2016 00:48:51 +0000 (UTC) From: Don Lewis <truckman@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r301231 - in stable/10: sbin/ipfw sys/netinet sys/netpfil/ipfw Message-ID: <201606030048.u530mpoc043874@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: truckman Date: Fri Jun 3 00:48:50 2016 New Revision: 301231 URL: https://svnweb.freebsd.org/changeset/base/301231 Log: MFC r266941, r266955 Needed for anticipated dummynet AQM MFC next week. r266941 | hiren | 2014-06-01 00:28:24 -0700 (Sun, 01 Jun 2014) | 9 lines ECN marking implenetation for dummynet. Changes include both DCTCP and RFC 3168 ECN marking methodology. DCTCP draft: http://tools.ietf.org/html/draft-bensley-tcpm-dctcp-00 Submitted by: Midori Kato (aoimidori27@gmail.com) Worked with: Lars Eggert (lars@netapp.com) Reviewed by: luigi, hiren r266955 | hiren | 2014-06-01 13:19:17 -0700 (Sun, 01 Jun 2014) | 5 lines DNOLD_IS_ECN introduced by r266941 is not required. DNOLD_* flags are for compat with old binaries. Suggested by: luigi Discussed with: hiren Relnotes: yes Modified: stable/10/sbin/ipfw/dummynet.c stable/10/sbin/ipfw/ipfw.8 stable/10/sbin/ipfw/ipfw2.h stable/10/sys/netinet/ip_dummynet.h stable/10/sys/netpfil/ipfw/ip_dn_io.c stable/10/sys/netpfil/ipfw/ip_dummynet.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sbin/ipfw/dummynet.c ============================================================================== --- stable/10/sbin/ipfw/dummynet.c Fri Jun 3 00:06:24 2016 (r301230) +++ stable/10/sbin/ipfw/dummynet.c Fri Jun 3 00:48:50 2016 (r301231) @@ -56,6 +56,7 @@ static struct _s_x dummynet_params[] = { { "sched_mask", TOK_SCHED_MASK }, { "flow_mask", TOK_FLOW_MASK }, { "droptail", TOK_DROPTAIL }, + { "ecn", TOK_ECN }, { "red", TOK_RED }, { "gred", TOK_GRED }, { "bw", TOK_BW }, @@ -239,7 +240,7 @@ print_flowset_parms(struct dn_fs *fs, ch else plr[0] = '\0'; - if (fs->flags & DN_IS_RED) /* RED parameters */ + if (fs->flags & DN_IS_RED) { /* RED parameters */ sprintf(red, "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", (fs->flags & DN_IS_GENTLE_RED) ? 'G' : ' ', @@ -247,7 +248,9 @@ print_flowset_parms(struct dn_fs *fs, ch fs->min_th, fs->max_th, 1.0 * fs->max_p / (double)(1 << SCALE_RED)); - else + if (fs->flags & DN_IS_ECN) + strncat(red, " (ecn)", 6); + } else sprintf(red, "droptail"); if (prefix[0]) { @@ -1046,13 +1049,17 @@ end_mask: } if ((end = strsep(&av[0], "/"))) { double max_p = strtod(end, NULL); - if (max_p > 1 || max_p <= 0) - errx(EX_DATAERR, "0 < max_p <= 1"); + if (max_p > 1 || max_p < 0) + errx(EX_DATAERR, "0 <= max_p <= 1"); fs->max_p = (int)(max_p * (1 << SCALE_RED)); } ac--; av++; break; + case TOK_ECN: + fs->flags |= DN_IS_ECN; + break; + case TOK_DROPTAIL: NEED(fs, "droptail is only for flowsets"); fs->flags &= ~(DN_IS_RED|DN_IS_GENTLE_RED); @@ -1175,13 +1182,20 @@ end_mask: errx(EX_DATAERR, "2 <= queue size <= %ld", limit); } + if ((fs->flags & DN_IS_ECN) && !(fs->flags & DN_IS_RED)) + errx(EX_USAGE, "enable red/gred for ECN"); + if (fs->flags & DN_IS_RED) { size_t len; int lookup_depth, avg_pkt_size; - if (fs->min_th >= fs->max_th) + if (!(fs->flags & DN_IS_ECN) && (fs->min_th >= fs->max_th)) errx(EX_DATAERR, "min_th %d must be < than max_th %d", fs->min_th, fs->max_th); + else if ((fs->flags & DN_IS_ECN) && (fs->min_th > fs->max_th)) + errx(EX_DATAERR, "min_th %d must be =< than max_th %d", + fs->min_th, fs->max_th); + if (fs->max_th == 0) errx(EX_DATAERR, "max_th must be > 0"); Modified: stable/10/sbin/ipfw/ipfw.8 ============================================================================== --- stable/10/sbin/ipfw/ipfw.8 Fri Jun 3 00:06:24 2016 (r301230) +++ stable/10/sbin/ipfw/ipfw.8 Fri Jun 3 00:48:50 2016 (r301231) @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 25, 2012 +.Dd May 31, 2014 .Dt IPFW 8 .Os .Sh NAME @@ -2442,22 +2442,23 @@ and control the maximum lengths that can be specified. .Pp .It Cm red | gred Ar w_q Ns / Ns Ar min_th Ns / Ns Ar max_th Ns / Ns Ar max_p +[ecn] Make use of the RED (Random Early Detection) queue management algorithm. .Ar w_q and .Ar max_p are floating -point numbers between 0 and 1 (0 not included), while +point numbers between 0 and 1 (inclusive), while .Ar min_th and .Ar max_th are integer numbers specifying thresholds for queue management (thresholds are computed in bytes if the queue has been defined in bytes, in slots otherwise). -The +The two parameters can also be of the same value if needed. The .Nm dummynet -also supports the gentle RED variant (gred). -Three +also supports the gentle RED variant (gred) and ECN (Explicit Congestion +Notification) as optional. Three .Xr sysctl 8 variables can be used to control the RED behaviour: .Bl -tag -width indent Modified: stable/10/sbin/ipfw/ipfw2.h ============================================================================== --- stable/10/sbin/ipfw/ipfw2.h Fri Jun 3 00:06:24 2016 (r301230) +++ stable/10/sbin/ipfw/ipfw2.h Fri Jun 3 00:48:50 2016 (r301231) @@ -165,6 +165,7 @@ enum tokens { TOK_BURST, TOK_RED, TOK_GRED, + TOK_ECN, TOK_DROPTAIL, TOK_PROTO, /* dummynet tokens */ Modified: stable/10/sys/netinet/ip_dummynet.h ============================================================================== --- stable/10/sys/netinet/ip_dummynet.h Fri Jun 3 00:06:24 2016 (r301230) +++ stable/10/sys/netinet/ip_dummynet.h Fri Jun 3 00:48:50 2016 (r301231) @@ -104,6 +104,7 @@ enum { /* user flags */ DN_HAS_PROFILE = 0x0010, /* a link has a profile */ DN_IS_RED = 0x0020, DN_IS_GENTLE_RED= 0x0040, + DN_IS_ECN = 0x0080, DN_PIPE_CMD = 0x1000, /* pipe config... */ }; Modified: stable/10/sys/netpfil/ipfw/ip_dn_io.c ============================================================================== --- stable/10/sys/netpfil/ipfw/ip_dn_io.c Fri Jun 3 00:06:24 2016 (r301230) +++ stable/10/sys/netpfil/ipfw/ip_dn_io.c Fri Jun 3 00:48:50 2016 (r301231) @@ -337,6 +337,8 @@ red_drops (struct dn_queue *q, int len) return (0); /* accept packet */ } if (q->avg >= fs->max_th) { /* average queue >= max threshold */ + if (fs->fs.flags & DN_IS_ECN) + return (1); if (fs->fs.flags & DN_IS_GENTLE_RED) { /* * According to Gentle-RED, if avg is greater than @@ -352,6 +354,8 @@ red_drops (struct dn_queue *q, int len) return (1); } } else if (q->avg > fs->min_th) { + if (fs->fs.flags & DN_IS_ECN) + return (1); /* * We compute p_b using the linear dropping function * p_b = c_1 * avg - c_2 @@ -384,6 +388,70 @@ red_drops (struct dn_queue *q, int len) } /* + * ECN/ECT Processing (partially adopted from altq) + */ +static int +ecn_mark(struct mbuf* m) +{ + struct ip *ip; + ip = mtod(m, struct ip *); + + switch (ip->ip_v) { + case IPVERSION: + { + u_int8_t otos; + int sum; + + if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT) + return (0); /* not-ECT */ + if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_CE) + return (1); /* already marked */ + + /* + * ecn-capable but not marked, + * mark CE and update checksum + */ + otos = ip->ip_tos; + ip->ip_tos |= IPTOS_ECN_CE; + /* + * update checksum (from RFC1624) + * HC' = ~(~HC + ~m + m') + */ + sum = ~ntohs(ip->ip_sum) & 0xffff; + sum += (~otos & 0xffff) + ip->ip_tos; + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); /* add carry */ + ip->ip_sum = htons(~sum & 0xffff); + return (1); + } +#ifdef INET6 + case (IPV6_VERSION >> 4): + { + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + u_int32_t flowlabel; + + flowlabel = ntohl(ip6->ip6_flow); + if ((flowlabel >> 28) != 6) + return (0); /* version mismatch! */ + if ((flowlabel & (IPTOS_ECN_MASK << 20)) == + (IPTOS_ECN_NOTECT << 20)) + return (0); /* not-ECT */ + if ((flowlabel & (IPTOS_ECN_MASK << 20)) == + (IPTOS_ECN_CE << 20)) + return (1); /* already marked */ + /* + * ecn-capable but not marked, mark CE + */ + flowlabel |= (IPTOS_ECN_CE << 20); + ip6->ip6_flow = htonl(flowlabel); + return (1); + } +#endif + } + return (0); +} + +/* * Enqueue a packet in q, subject to space and queue management policy * (whose parameters are in q->fs). * Update stats for the queue and the scheduler. @@ -414,8 +482,10 @@ dn_enqueue(struct dn_queue *q, struct mb goto drop; if (f->plr && random() < f->plr) goto drop; - if (f->flags & DN_IS_RED && red_drops(q, m->m_pkthdr.len)) - goto drop; + if (f->flags & DN_IS_RED && red_drops(q, m->m_pkthdr.len)) { + if (!(f->flags & DN_IS_ECN) || !ecn_mark(m)) + goto drop; + } if (f->flags & DN_QSIZE_BYTES) { if (q->ni.len_bytes > f->qsize) goto drop; @@ -427,14 +497,14 @@ dn_enqueue(struct dn_queue *q, struct mb q->ni.len_bytes += len; ni->length++; ni->len_bytes += len; - return 0; + return (0); drop: io_pkt_drop++; q->ni.drops++; ni->drops++; FREE_PKT(m); - return 1; + return (1); } /* Modified: stable/10/sys/netpfil/ipfw/ip_dummynet.c ============================================================================== --- stable/10/sys/netpfil/ipfw/ip_dummynet.c Fri Jun 3 00:06:24 2016 (r301230) +++ stable/10/sys/netpfil/ipfw/ip_dummynet.c Fri Jun 3 00:48:50 2016 (r301231) @@ -1073,7 +1073,10 @@ config_red(struct dn_fsk *fs) fs->min_th = SCALE(fs->fs.min_th); fs->max_th = SCALE(fs->fs.max_th); - fs->c_1 = fs->max_p / (fs->fs.max_th - fs->fs.min_th); + if (fs->fs.max_th == fs->fs.min_th) + fs->c_1 = fs->max_p; + else + fs->c_1 = SCALE((int64_t)(fs->max_p)) / (fs->fs.max_th - fs->fs.min_th); fs->c_2 = SCALE_MUL(fs->c_1, SCALE(fs->fs.min_th)); if (fs->fs.flags & DN_IS_GENTLE_RED) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606030048.u530mpoc043874>