Projet

Général

Profil

Télécharger (53 ko) Statistiques
| Branche: | Révision:

univnautes-tools / patches / stable / 10 / altq_codel.diff @ 4ab3b90b

1
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
2
index da1468b..591db6b 100644
3
--- a/sbin/pfctl/parse.y
4
+++ b/sbin/pfctl/parse.y
5
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
6
 #include <altq/altq_priq.h>
7
 #include <altq/altq_hfsc.h>
8
 #include <altq/altq_fairq.h>
9
+#include <altq/altq_codel.h>
10
 
11
 #include <stdio.h>
12
 #include <unistd.h>
13
@@ -315,6 +316,7 @@ struct pool_opts {
14
 
15
 struct node_hfsc_opts	 hfsc_opts;
16
 struct node_fairq_opts	 fairq_opts;
17
+struct codel_opts	 codel_opts;
18
 struct node_state_opt	*keep_state_defaults = NULL;
19
 
20
 int		 disallow_table(struct node_host *, const char *);
21
@@ -439,6 +441,7 @@ typedef struct {
22
 		struct pool_opts	 pool_opts;
23
 		struct node_hfsc_opts	 hfsc_opts;
24
 		struct node_fairq_opts	fairq_opts;
25
+		struct codel_opts	codel_opts;
26
 	} v;
27
 	int lineno;
28
 } YYSTYPE;
29
@@ -463,8 +466,8 @@ int	parseport(char *, struct range *r, int);
30
 %token	REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
31
 %token	ANTISPOOF FOR INCLUDE
32
 %token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
33
-%token	ALTQ CBQ PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
34
-%token	QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE
35
+%token	ALTQ CBQ PRIQ HFSC FAIRQ CODEL BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
36
+%token	QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE INTERVAL
37
 %token  DNPIPE DNQUEUE 
38
 %token	LOAD RULESET_OPTIMIZATION
39
 %token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
40
@@ -515,6 +518,7 @@ int	parseport(char *, struct range *r, int);
41
 %type	<v.number>		priqflags_list priqflags_item
42
 %type	<v.hfsc_opts>		hfscopts_list hfscopts_item hfsc_opts
43
 %type	<v.fairq_opts>		fairqopts_list fairqopts_item fairq_opts
44
+%type	<v.codel_opts>		codelopts_list codelopts_item codel_opts
45
 %type	<v.queue_bwspec>	bandwidth
46
 %type	<v.filter_opts>		filter_opts filter_opt filter_opts_l
47
 %type	<v.antispoof_opts>	antispoof_opts antispoof_opt antispoof_opts_l
48
@@ -1491,7 +1495,7 @@ altqif		: ALTQ interface queue_opts QUEUE qassign {
49
 			a.scheduler = $3.scheduler.qtype;
50
 			a.qlimit = $3.qlimit;
51
 			a.tbrsize = $3.tbrsize;
52
-			if ($5 == NULL) {
53
+			if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
54
 				yyerror("no child queues specified");
55
 				YYERROR;
56
 			}
57
@@ -1701,6 +1705,15 @@ scheduler	: CBQ				{
58
                         $$.qtype = ALTQT_FAIRQ;
59
                         $$.data.fairq_opts = $3;
60
                 }
61
+		| CODEL {
62
+			$$.qtype = ALTQT_CODEL;
63
+			bzero(&$$.data.codel_opts,
64
+				sizeof(struct codel_opts));
65
+		}
66
+                | CODEL '(' codel_opts ')'      {
67
+                        $$.qtype = ALTQT_CODEL;
68
+                        $$.data.codel_opts = $3;
69
+                }
70
 		;
71
 
72
 cbqflags_list	: cbqflags_item				{ $$ |= $1; }
73
@@ -1718,6 +1731,8 @@ cbqflags_item	: STRING	{
74
 				$$ = CBQCLF_RED|CBQCLF_ECN;
75
 			else if (!strcmp($1, "rio"))
76
 				$$ = CBQCLF_RIO;
77
+			else if (!strcmp($1, "codel"))
78
+				$$ = CBQCLF_CODEL;
79
 			else {
80
 				yyerror("unknown cbq flag \"%s\"", $1);
81
 				free($1);
82
@@ -1740,6 +1755,8 @@ priqflags_item	: STRING	{
83
 				$$ = PRCF_RED|PRCF_ECN;
84
 			else if (!strcmp($1, "rio"))
85
 				$$ = PRCF_RIO;
86
+			else if (!strcmp($1, "codel"))
87
+				$$ = PRCF_CODEL;
88
 			else {
89
 				yyerror("unknown priq flag \"%s\"", $1);
90
 				free($1);
91
@@ -1840,6 +1857,8 @@ hfscopts_item	: LINKSHARE bandwidth				{
92
 				hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
93
 			else if (!strcmp($1, "rio"))
94
 				hfsc_opts.flags |= HFCF_RIO;
95
+			else if (!strcmp($1, "codel"))
96
+				hfsc_opts.flags |= HFCF_CODEL;
97
 			else {
98
 				yyerror("unknown hfsc flag \"%s\"", $1);
99
 				free($1);
100
@@ -1895,6 +1914,8 @@ fairqopts_item	: LINKSHARE bandwidth				{
101
 				fairq_opts.flags |= FARF_RED|FARF_ECN;
102
 			else if (!strcmp($1, "rio"))
103
 				fairq_opts.flags |= FARF_RIO;
104
+			else if (!strcmp($1, "codel"))
105
+				fairq_opts.flags |= FARF_CODEL;
106
 			else {
107
 				yyerror("unknown fairq flag \"%s\"", $1);
108
 				free($1);
109
@@ -1904,6 +1925,45 @@ fairqopts_item	: LINKSHARE bandwidth				{
110
 		}
111
 		;
112
 
113
+codel_opts	:	{
114
+				bzero(&codel_opts,
115
+				    sizeof(struct codel_opts));
116
+			}
117
+		    codelopts_list				{
118
+			$$ = codel_opts;
119
+		}
120
+		;
121
+
122
+codelopts_list	: codelopts_item
123
+		| codelopts_list comma codelopts_item
124
+		;
125
+
126
+codelopts_item	: QLIMIT number					{
127
+			if (codel_opts.target) {
128
+				yyerror("target already specified");
129
+				YYERROR;
130
+			}
131
+			codel_opts.target = $2;
132
+		}
133
+		| INTERVAL number				{
134
+			if (codel_opts.interval) {
135
+				yyerror("interval already specified");
136
+				YYERROR;
137
+			}
138
+			codel_opts.interval = $2;
139
+		}
140
+		| STRING					{
141
+			if (!strcmp($1, "ecn"))
142
+				codel_opts.ecn = 1;
143
+			else {
144
+				yyerror("unknown codel option \"%s\"", $1);
145
+				free($1);
146
+				YYERROR;
147
+			}
148
+			free($1);
149
+		}
150
+		;
151
+
152
 qassign		: /* empty */		{ $$ = NULL; }
153
 		| qassign_item		{ $$ = $1; }
154
 		| '{' optnl qassign_list '}'	{ $$ = $3; }
155
@@ -5051,7 +5111,8 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces,
156
 
157
 	if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
158
 		FREE_LIST(struct node_if, interfaces);
159
-		FREE_LIST(struct node_queue, nqueues);
160
+		if (nqueues)
161
+			FREE_LIST(struct node_queue, nqueues);
162
 		return (0);
163
 	}
164
 
165
@@ -5113,37 +5174,40 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces,
166
 						errs++;
167
 			}
168
 
169
-			LOOP_THROUGH(struct node_queue, queue, nqueues,
170
-				n = calloc(1, sizeof(struct node_queue));
171
-				if (n == NULL)
172
-					err(1, "expand_altq: calloc");
173
-				if (pa.scheduler == ALTQT_CBQ ||
174
-				    pa.scheduler == ALTQT_HFSC /* ||
175
-				    pa.scheduler == ALTQT_FAIRQ */)
176
-					if (strlcpy(n->parent, qname,
177
-					    sizeof(n->parent)) >=
178
-					    sizeof(n->parent))
179
+			if (nqueues) {
180
+				LOOP_THROUGH(struct node_queue, queue, nqueues,
181
+					n = calloc(1, sizeof(struct node_queue));
182
+					if (n == NULL)
183
+						err(1, "expand_altq: calloc");
184
+					if (pa.scheduler == ALTQT_CBQ ||
185
+					    pa.scheduler == ALTQT_HFSC /* ||
186
+					    pa.scheduler == ALTQT_FAIRQ */)
187
+						if (strlcpy(n->parent, qname,
188
+						    sizeof(n->parent)) >=
189
+						    sizeof(n->parent))
190
+							errx(1, "expand_altq: strlcpy");
191
+					if (strlcpy(n->queue, queue->queue,
192
+					    sizeof(n->queue)) >= sizeof(n->queue))
193
 						errx(1, "expand_altq: strlcpy");
194
-				if (strlcpy(n->queue, queue->queue,
195
-				    sizeof(n->queue)) >= sizeof(n->queue))
196
-					errx(1, "expand_altq: strlcpy");
197
-				if (strlcpy(n->ifname, interface->ifname,
198
-				    sizeof(n->ifname)) >= sizeof(n->ifname))
199
-					errx(1, "expand_altq: strlcpy");
200
-				n->scheduler = pa.scheduler;
201
-				n->next = NULL;
202
-				n->tail = n;
203
-				if (queues == NULL)
204
-					queues = n;
205
-				else {
206
-					queues->tail->next = n;
207
-					queues->tail = n;
208
-				}
209
-			);
210
+					if (strlcpy(n->ifname, interface->ifname,
211
+					    sizeof(n->ifname)) >= sizeof(n->ifname))
212
+						errx(1, "expand_altq: strlcpy");
213
+					n->scheduler = pa.scheduler;
214
+					n->next = NULL;
215
+					n->tail = n;
216
+					if (queues == NULL)
217
+						queues = n;
218
+					else {
219
+						queues->tail->next = n;
220
+						queues->tail = n;
221
+					}
222
+				);
223
+			}
224
 		}
225
 	);
226
 	FREE_LIST(struct node_if, interfaces);
227
-	FREE_LIST(struct node_queue, nqueues);
228
+	if (nqueues)
229
+		FREE_LIST(struct node_queue, nqueues);
230
 
231
 	return (errs);
232
 }
233
@@ -5557,6 +5621,7 @@ lookup(char *s)
234
 		{ "buckets",		BUCKETS},
235
 		{ "cbq",		CBQ},
236
 		{ "code",		CODE},
237
+		{ "codelq",		CODEL},
238
 		{ "crop",		FRAGCROP},
239
 		{ "debug",		DEBUG},
240
 		{ "dnpipe",             DNPIPE},
241
@@ -5591,6 +5656,7 @@ lookup(char *s)
242
 		{ "include",		INCLUDE},
243
 		{ "inet",		INET},
244
 		{ "inet6",		INET6},
245
+		{ "interval",		INTERVAL},
246
 		{ "keep",		KEEP},
247
 		{ "label",		LABEL},
248
 		{ "limit",		LIMIT},
249
diff --git a/sbin/pfctl/pfctl_altq.c b/sbin/pfctl/pfctl_altq.c
250
index 9a33c01..f532aeb 100644
251
--- a/sbin/pfctl/pfctl_altq.c
252
+++ b/sbin/pfctl/pfctl_altq.c
253
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
254
 #include <altq/altq_priq.h>
255
 #include <altq/altq_hfsc.h>
256
 #include <altq/altq_fairq.h>
257
+#include <altq/altq_codel.h>
258
 
259
 #include "pfctl_parser.h"
260
 #include "pfctl.h"
261
@@ -75,6 +76,9 @@ static int	print_fairq_opts(const struct pf_altq *,
262
 		    const struct node_queue_opt *);
263
 static int	check_commit_fairq(int, int, struct pf_altq *);
264
 
265
+static int	print_codel_opts(const struct pf_altq *,
266
+		    const struct node_queue_opt *);
267
+
268
 static void		 gsc_add_sc(struct gen_sc *, struct service_curve *);
269
 static int		 is_gsc_under_sc(struct gen_sc *,
270
 			     struct service_curve *);
271
@@ -186,6 +190,10 @@ print_altq(const struct pf_altq *a, unsigned int level,
272
 		if (!print_fairq_opts(a, qopts))
273
 			printf("fairq ");
274
 		break;
275
+	case ALTQT_CODEL:
276
+		if (!print_codel_opts(a, qopts))
277
+			printf("codel ");
278
+		break;
279
 	}
280
 
281
 	if (bw != NULL && bw->bw_percent > 0) {
282
@@ -588,6 +596,8 @@ print_cbq_opts(const struct pf_altq *a)
283
 			printf(" ecn");
284
 		if (opts->flags & CBQCLF_RIO)
285
 			printf(" rio");
286
+		if (opts->flags & CBQCLF_CODEL)
287
+			printf(" codel");
288
 		if (opts->flags & CBQCLF_CLEARDSCP)
289
 			printf(" cleardscp");
290
 		if (opts->flags & CBQCLF_FLOWVALVE)
291
@@ -675,6 +685,8 @@ print_priq_opts(const struct pf_altq *a)
292
 			printf(" ecn");
293
 		if (opts->flags & PRCF_RIO)
294
 			printf(" rio");
295
+		if (opts->flags & PRCF_CODEL)
296
+			printf(" codel");
297
 		if (opts->flags & PRCF_CLEARDSCP)
298
 			printf(" cleardscp");
299
 		if (opts->flags & PRCF_DEFAULTCLASS)
300
@@ -1000,6 +1012,8 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
301
 			printf(" ecn");
302
 		if (opts->flags & HFCF_RIO)
303
 			printf(" rio");
304
+		if (opts->flags & HFCF_CODEL)
305
+			printf(" codel");
306
 		if (opts->flags & HFCF_CLEARDSCP)
307
 			printf(" cleardscp");
308
 		if (opts->flags & HFCF_DEFAULTCLASS)
309
@@ -1022,6 +1036,28 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
310
 }
311
 
312
 static int
313
+print_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
314
+{
315
+	const struct codel_opts	*opts;
316
+
317
+	opts = &a->pq_u.codel_opts;
318
+	if (opts->target || opts->interval || opts->ecn) {
319
+		printf("codel(");
320
+		if (opts->target)
321
+			printf(" target %d", opts->target);
322
+		if (opts->interval)
323
+			printf(" interval %d", opts->interval);
324
+		if (opts->ecn)
325
+			printf("ecn");
326
+		printf(") ");
327
+
328
+		return (1);
329
+	}
330
+
331
+	return (0);
332
+}
333
+
334
+static int
335
 print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
336
 {
337
 	const struct fairq_opts		*opts;
338
@@ -1043,6 +1079,8 @@ print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
339
 			printf(" ecn");
340
 		if (opts->flags & FARF_RIO)
341
 			printf(" rio");
342
+		if (opts->flags & FARF_CODEL)
343
+			printf(" codel");
344
 		if (opts->flags & FARF_CLEARDSCP)
345
 			printf(" cleardscp");
346
 		if (opts->flags & FARF_DEFAULTCLASS)
347
@@ -1394,6 +1432,11 @@ eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
348
 			    opts->data.fairq_opts.linkshare.d;
349
 		}
350
 		break;
351
+	case ALTQT_CODEL:
352
+		pa->pq_u.codel_opts.target = opts->data.codel_opts.target;
353
+		pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval;
354
+		pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn;
355
+		break;
356
 	default:
357
 		warnx("eval_queue_opts: unknown scheduler type %u",
358
 		    opts->qtype);
359
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
360
index f2b0a9b..b44a65a 100644
361
--- a/sbin/pfctl/pfctl_parser.h
362
+++ b/sbin/pfctl/pfctl_parser.h
363
@@ -169,6 +169,7 @@ struct node_queue_opt {
364
 	union {
365
 		struct cbq_opts		cbq_opts;
366
 		struct priq_opts	priq_opts;
367
+		struct codel_opts	codel_opts;
368
 		struct node_hfsc_opts	hfsc_opts;
369
 		struct node_fairq_opts	fairq_opts;
370
 	}			 data;
371
diff --git a/sbin/pfctl/pfctl_qstats.c b/sbin/pfctl/pfctl_qstats.c
372
index 4087d71..5530572 100644
373
--- a/sbin/pfctl/pfctl_qstats.c
374
+++ b/sbin/pfctl/pfctl_qstats.c
375
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
376
 #include <altq/altq_priq.h>
377
 #include <altq/altq_hfsc.h>
378
 #include <altq/altq_fairq.h>
379
+#include <altq/altq_codel.h>
380
 
381
 #include "pfctl.h"
382
 #include "pfctl_parser.h"
383
@@ -48,6 +49,7 @@ union class_stats {
384
 	struct priq_classstats	priq_stats;
385
 	struct hfsc_classstats	hfsc_stats;
386
 	struct fairq_classstats fairq_stats;
387
+	struct codel_ifstats	codel_stats;
388
 };
389
 
390
 #define AVGN_MAX	8
391
@@ -78,6 +80,7 @@ void			 pfctl_print_altq_node(int, const struct pf_altq_node *,
392
 			    unsigned, int);
393
 void			 print_cbqstats(struct queue_stats);
394
 void			 print_priqstats(struct queue_stats);
395
+void			 print_codelstats(struct queue_stats);
396
 void			 print_hfscstats(struct queue_stats);
397
 void			 print_fairqstats(struct queue_stats);
398
 void			 pfctl_free_altq_node(struct pf_altq_node *);
399
@@ -165,7 +168,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root)
400
 			return (-1);
401
 		}
402
 #ifdef __FreeBSD__
403
-		if (pa.altq.qid > 0 &&
404
+		if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
405
 		    !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
406
 #else
407
 		if (pa.altq.qid > 0) {
408
@@ -303,7 +306,7 @@ pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
409
 void
410
 pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
411
 {
412
-	if (a->altq.qid == 0)
413
+	if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
414
 		return;
415
 
416
 #ifdef __FreeBSD__
417
@@ -323,6 +326,9 @@ pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
418
 	case ALTQT_FAIRQ:
419
 		print_fairqstats(a->qstats);
420
 		break;
421
+	case ALTQT_CODEL:
422
+		print_codelstats(a->qstats);
423
+		break;
424
 	}
425
 }
426
 
427
@@ -368,6 +374,26 @@ print_priqstats(struct queue_stats cur)
428
 }
429
 
430
 void
431
+print_codelstats(struct queue_stats cur)
432
+{
433
+	printf("  [ pkts: %10llu  bytes: %10llu  "
434
+	    "dropped pkts: %6llu bytes: %6llu ]\n",
435
+	    (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
436
+	    (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
437
+	    (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets + cur.data.codel_stats.stats.drop_cnt.packets,
438
+	    (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes  + cur.data.codel_stats.stats.drop_cnt.bytes);
439
+	printf("  [ qlength: %3d/%3d ]\n",
440
+	    cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
441
+
442
+	if (cur.avgn < 2)
443
+		return;
444
+
445
+	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
446
+	    cur.avg_packets / STAT_INTERVAL,
447
+	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
448
+}
449
+
450
+void
451
 print_hfscstats(struct queue_stats cur)
452
 {
453
 	printf("  [ pkts: %10llu  bytes: %10llu  "
454
@@ -428,7 +454,7 @@ update_avg(struct pf_altq_node *a)
455
 	u_int64_t		 b, p;
456
 	int			 n;
457
 
458
-	if (a->altq.qid == 0)
459
+	if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
460
 		return;
461
 
462
 	qs = &a->qstats;
463
@@ -451,6 +477,10 @@ update_avg(struct pf_altq_node *a)
464
 		b = qs->data.fairq_stats.xmit_cnt.bytes;
465
 		p = qs->data.fairq_stats.xmit_cnt.packets;
466
 		break;
467
+	case ALTQT_CODEL:
468
+		b = qs->data.codel_stats.cl_xmitcnt.bytes;
469
+		p = qs->data.codel_stats.cl_xmitcnt.packets;
470
+		break;
471
 	default:
472
 		b = 0;
473
 		p = 0;
474
diff --git a/sys/conf/files b/sys/conf/files
475
index 434ffaf..6c2d452 100644
476
--- a/sys/conf/files
477
+++ b/sys/conf/files
478
@@ -286,6 +286,7 @@ compat/freebsd32/freebsd32_sysent.c	optional compat_freebsd32
479
 contrib/altq/altq/altq_cbq.c		optional altq
480
 contrib/altq/altq/altq_cdnr.c		optional altq
481
 contrib/altq/altq/altq_hfsc.c		optional altq
482
+contrib/altq/altq/altq_codel.c		optional altq
483
 contrib/altq/altq/altq_fairq.c		optional altq
484
 contrib/altq/altq/altq_priq.c		optional altq
485
 contrib/altq/altq/altq_red.c		optional altq
486
diff --git a/sys/conf/options b/sys/conf/options
487
index 55030c3..b838d17 100644
488
--- a/sys/conf/options
489
+++ b/sys/conf/options
490
@@ -384,6 +384,7 @@ ALTQ_NOPCC		opt_altq.h
491
 ALTQ_PRIQ		opt_altq.h
492
 ALTQ_RED		opt_altq.h
493
 ALTQ_RIO		opt_altq.h
494
+ALTQ_CODEL		opt_altq.h
495
 BOOTP			opt_bootp.h
496
 BOOTP_BLOCKSIZE		opt_bootp.h
497
 BOOTP_COMPAT		opt_bootp.h
498
diff --git a/sys/contrib/altq/altq/altq.h b/sys/contrib/altq/altq/altq.h
499
index 6200ac5..26d6cb7 100644
500
--- a/sys/contrib/altq/altq/altq.h
501
+++ b/sys/contrib/altq/altq/altq.h
502
@@ -64,7 +64,8 @@
503
 #define	ALTQT_PRIQ		11	/* priority queue */
504
 #define	ALTQT_JOBS		12	/* JoBS */
505
 #define ALTQT_FAIRQ		13	/* fairq */
506
-#define	ALTQT_MAX		14	/* should be max discipline type + 1 */
507
+#define ALTQT_CODEL		14	/* fairq */
508
+#define	ALTQT_MAX		15	/* should be max discipline type + 1 */
509
 
510
 #ifdef ALTQ3_COMPAT
511
 struct	altqreq {
512
diff --git a/sys/contrib/altq/altq/altq_cbq.c b/sys/contrib/altq/altq/altq_cbq.c
513
index 3991d1d..13f9721 100644
514
--- a/sys/contrib/altq/altq/altq_cbq.c
515
+++ b/sys/contrib/altq/altq/altq_cbq.c
516
@@ -241,6 +241,10 @@ get_class_stats(class_stats_t *statsp, struct rm_class *cl)
517
 	if (q_is_rio(cl->q_))
518
 		rio_getstats((rio_t *)cl->red_, &statsp->red[0]);
519
 #endif
520
+#ifdef ALTQ_CODEL
521
+	if (q_is_codel(cl->q_))
522
+		codel_getstats(cl->codel_, &statsp->codel);
523
+#endif
524
 }
525
 
526
 int
527
diff --git a/sys/contrib/altq/altq/altq_cbq.h b/sys/contrib/altq/altq/altq_cbq.h
528
index 76096af..45509f0 100644
529
--- a/sys/contrib/altq/altq/altq_cbq.h
530
+++ b/sys/contrib/altq/altq/altq_cbq.h
531
@@ -37,6 +37,7 @@
532
 #include <altq/altq_rmclass.h>
533
 #include <altq/altq_red.h>
534
 #include <altq/altq_rio.h>
535
+#include <altq/altq_codel.h>
536
 
537
 #ifdef __cplusplus
538
 extern "C" {
539
@@ -51,6 +52,7 @@ extern "C" {
540
 #define	CBQCLF_FLOWVALVE	0x0008	/* use flowvalve (aka penalty-box) */
541
 #define	CBQCLF_CLEARDSCP	0x0010  /* clear diffserv codepoint */
542
 #define	CBQCLF_BORROW		0x0020  /* borrow from parent */
543
+#define	CBQCLF_CODEL		0x0040  /* use CODEL */
544
 
545
 /* class flags only for root class */
546
 #define	CBQCLF_WRR		0x0100	/* weighted-round robin */
547
@@ -93,6 +95,7 @@ typedef struct _cbq_class_stats_ {
548
 	/* red and rio related info */
549
 	int		qtype;
550
 	struct redstats	red[3];
551
+	struct codel_stats codel;
552
 } class_stats_t;
553
 
554
 #ifdef ALTQ3_COMPAT
555
diff --git a/sys/contrib/altq/altq/altq_classq.h b/sys/contrib/altq/altq/altq_classq.h
556
index dc5c646..8e4d1db 100644
557
--- a/sys/contrib/altq/altq/altq_classq.h
558
+++ b/sys/contrib/altq/altq/altq_classq.h
559
@@ -49,6 +49,7 @@ extern "C" {
560
 #define	Q_RED		0x01
561
 #define	Q_RIO		0x02
562
 #define	Q_DROPTAIL	0x03
563
+#define	Q_CODEL		0x04
564
 
565
 #ifdef _KERNEL
566
 
567
@@ -58,6 +59,7 @@ extern "C" {
568
 struct _class_queue_ {
569
 	struct mbuf	*tail_;	/* Tail of packet queue */
570
 	int	qlen_;		/* Queue length (in number of packets) */
571
+	int	qsize_;		/* Queue size (in number of bytes*) */
572
 	int	qlim_;		/* Queue limit (in number of packets*) */
573
 	int	qtype_;		/* Queue type */
574
 };
575
@@ -67,11 +69,13 @@ typedef struct _class_queue_	class_queue_t;
576
 #define	qtype(q)	(q)->qtype_		/* Get queue type */
577
 #define	qlimit(q)	(q)->qlim_		/* Max packets to be queued */
578
 #define	qlen(q)		(q)->qlen_		/* Current queue length. */
579
+#define	qsize(q)	(q)->qsize_		/* Current queue size. */
580
 #define	qtail(q)	(q)->tail_		/* Tail of the queue */
581
 #define	qhead(q)	((q)->tail_ ? (q)->tail_->m_nextpkt : NULL)
582
 
583
 #define	qempty(q)	((q)->qlen_ == 0)	/* Is the queue empty?? */
584
 #define	q_is_red(q)	((q)->qtype_ == Q_RED)	/* Is the queue a red queue */
585
+#define	q_is_codel(q)	((q)->qtype_ == Q_CODEL) /* Is the queue a codel queue */
586
 #define	q_is_rio(q)	((q)->qtype_ == Q_RIO)	/* Is the queue a rio queue */
587
 #define	q_is_red_or_rio(q)	((q)->qtype_ == Q_RED || (q)->qtype_ == Q_RIO)
588
 
589
@@ -100,6 +104,7 @@ _addq(class_queue_t *q, struct mbuf *m)
590
 	m0->m_nextpkt = m;
591
 	qtail(q) = m;
592
 	qlen(q)++;
593
+	qsize(q) += m_pktlen(m);
594
 }
595
 
596
 static __inline struct mbuf *
597
@@ -114,6 +119,7 @@ _getq(class_queue_t *q)
598
 	else
599
 		qtail(q) = NULL;
600
 	qlen(q)--;
601
+	qsize(q) -= m_pktlen(m0);
602
 	m0->m_nextpkt = NULL;
603
 	return (m0);
604
 }
605
diff --git a/sys/contrib/altq/altq/altq_codel.c b/sys/contrib/altq/altq/altq_codel.c
606
new file mode 100644
607
index 0000000..81628c5
608
--- /dev/null
609
+++ b/sys/contrib/altq/altq/altq_codel.c
610
@@ -0,0 +1,434 @@
611
+/*
612
+ * Codel - The Controlled-Delay Active Queue Management algorithm
613
+ *
614
+ *  Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
615
+ *  Copyright (C) 2011-2012 Van Jacobson <van@pollere.net>
616
+ *  Copyright (C) 2012 Michael D. Taht <dave.taht@bufferbloat.net>
617
+ *  Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
618
+ *
619
+ * Redistribution and use in source and binary forms, with or without
620
+ * modification, are permitted provided that the following conditions
621
+ * are met:
622
+ * 1. Redistributions of source code must retain the above copyright
623
+ *    notice, this list of conditions, and the following disclaimer,
624
+ *    without modification.
625
+ * 2. Redistributions in binary form must reproduce the above copyright
626
+ *    notice, this list of conditions and the following disclaimer in the
627
+ *    documentation and/or other materials provided with the distribution.
628
+ * 3. The names of the authors may not be used to endorse or promote products
629
+ *    derived from this software without specific prior written permission.
630
+ *
631
+ * Alternatively, provided that this notice is retained in full, this
632
+ * software may be distributed under the terms of the GNU General
633
+ * Public License ("GPL") version 2, in which case the provisions of the
634
+ * GPL apply INSTEAD OF those given above.
635
+ *
636
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
637
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
638
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
639
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
640
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
641
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
642
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
643
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
644
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
645
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
646
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
647
+ * DAMAGE.
648
+ *
649
+ */
650
+
651
+#include <sys/param.h>
652
+#include <sys/malloc.h>
653
+#include <sys/mbuf.h>
654
+#include <sys/socket.h>
655
+#include <sys/systm.h>
656
+
657
+#include <net/if.h>
658
+#include <netinet/in.h>
659
+
660
+#include <net/pfvar.h>
661
+
662
+#include <altq/altq.h>
663
+#include <altq/altq_codel.h>
664
+
665
+static int		 codel_should_drop(struct codel *, class_queue_t *,
666
+			    struct mbuf *, u_int64_t);
667
+static void		 codel_Newton_step(struct codel_vars *);
668
+static u_int64_t	 codel_control_law(u_int64_t t, u_int64_t, u_int32_t);
669
+
670
+#define codel_time_after(a, b)		((int64_t)(a) - (int64_t)(b) > 0)
671
+#define codel_time_after_eq(a, b)	((int64_t)(a) - (int64_t)(b) >= 0)
672
+#define codel_time_before(a, b)		((int64_t)(a) - (int64_t)(b) < 0)
673
+#define codel_time_before_eq(a, b)	((int64_t)(a) - (int64_t)(b) <= 0)
674
+
675
+static int codel_request(struct ifaltq *, int, void *);
676
+
677
+static int codel_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *);
678
+static struct mbuf *codel_dequeue(struct ifaltq *, int);
679
+
680
+int
681
+codel_pfattach(struct pf_altq *a)
682
+{
683
+	struct ifnet *ifp;
684
+	int s, error;
685
+
686
+	if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
687
+		return (EINVAL);
688
+#ifdef __NetBSD__
689
+	s = splnet();
690
+#else
691
+	s = splimp();
692
+#endif
693
+	error = altq_attach(&ifp->if_snd, ALTQT_CODEL, a->altq_disc,
694
+	    codel_enqueue, codel_dequeue, codel_request, NULL, NULL);
695
+	splx(s);
696
+	return (error);
697
+}
698
+
699
+int
700
+codel_add_altq(struct pf_altq *a)
701
+{
702
+	struct codel_if	*cif;
703
+	struct ifnet	*ifp;
704
+	struct codel_opts	*opts;
705
+
706
+	if ((ifp = ifunit(a->ifname)) == NULL)
707
+		return (EINVAL);
708
+	if (!ALTQ_IS_READY(&ifp->if_snd))
709
+		return (ENODEV);
710
+
711
+	opts = &a->pq_u.codel_opts;
712
+
713
+	cif = malloc(sizeof(struct codel_if), M_DEVBUF, M_NOWAIT | M_ZERO);
714
+	if (cif == NULL)
715
+		return (ENOMEM);
716
+	cif->cif_bandwidth = a->ifbandwidth;
717
+	cif->cif_ifq = &ifp->if_snd;
718
+
719
+	cif->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF, M_NOWAIT | M_ZERO);
720
+	if (cif->cl_q == NULL) {
721
+		free(cif, M_DEVBUF);
722
+		return (ENOMEM);
723
+	}
724
+
725
+	if (a->qlimit == 0)
726
+		a->qlimit = 100;
727
+	qlimit(cif->cl_q) = a->qlimit;
728
+	qtype(cif->cl_q) = Q_CODEL;
729
+	qlen(cif->cl_q) = 0;
730
+	qsize(cif->cl_q) = 0;
731
+
732
+	if (!opts->target)
733
+		opts->target = a->qlimit;
734
+	if (!opts->interval)
735
+		opts->interval = 5;
736
+	cif->codel.params.target = machclk_freq * opts->target / 1000;
737
+        cif->codel.params.interval = machclk_freq * opts->interval / 1000;
738
+        cif->codel.params.ecn = opts->ecn;
739
+        cif->codel.stats.maxpacket = 256;
740
+
741
+	cif->cl_stats.qlength = qlen(cif->cl_q);
742
+	cif->cl_stats.qlimit = qlimit(cif->cl_q);
743
+
744
+	/* keep the state in pf_altq */
745
+	a->altq_disc = cif;
746
+
747
+	return (0);
748
+}
749
+
750
+int
751
+codel_remove_altq(struct pf_altq *a)
752
+{
753
+	struct codel_if *cif;
754
+
755
+	if ((cif = a->altq_disc) == NULL)
756
+		return (EINVAL);
757
+	a->altq_disc = NULL;
758
+
759
+	if (cif->cl_q)
760
+		free(cif->cl_q, M_DEVBUF);
761
+	free(cif, M_DEVBUF);
762
+	return (0);
763
+}
764
+
765
+int
766
+codel_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
767
+{
768
+	struct codel_if *cif;
769
+	struct codel_ifstats stats;
770
+	int error = 0;
771
+
772
+	if ((cif = altq_lookup(a->ifname, ALTQT_CODEL)) == NULL)
773
+		return (EBADF);
774
+
775
+	if (*nbytes < sizeof(stats))
776
+		return (EINVAL);
777
+
778
+	stats = cif->cl_stats;
779
+	stats.stats = cif->codel.stats;
780
+
781
+	if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
782
+		return (error);
783
+	*nbytes = sizeof(stats);
784
+	return (0);
785
+}
786
+
787
+static int
788
+codel_request(struct ifaltq *ifq, int req, void *arg)
789
+{
790
+	struct codel_if	*cif = (struct codel_if *)ifq->altq_disc;
791
+	struct mbuf *m;
792
+
793
+	IFQ_LOCK_ASSERT(ifq);
794
+
795
+	switch (req) {
796
+	case ALTRQ_PURGE:
797
+		if (!ALTQ_IS_ENABLED(cif->cif_ifq))
798
+			break;
799
+
800
+		if (qempty(cif->cl_q))
801
+			break;
802
+
803
+		while ((m = _getq(cif->cl_q)) != NULL) {
804
+			PKTCNTR_ADD(&cif->cl_stats.cl_dropcnt, m_pktlen(m));
805
+			m_freem(m);
806
+			IFQ_DEC_LEN(cif->cif_ifq);
807
+		}
808
+		cif->cif_ifq->ifq_len = 0;
809
+		break;
810
+	}
811
+	return (0);
812
+}
813
+
814
+static int
815
+codel_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
816
+{
817
+
818
+	struct codel_if *cif = (struct codel_if *) ifq->altq_disc;
819
+
820
+	IFQ_LOCK_ASSERT(ifq);
821
+
822
+	/* grab class set by classifier */
823
+	if ((m->m_flags & M_PKTHDR) == 0) {
824
+		/* should not happen */
825
+		printf("altq: packet for %s does not have pkthdr\n",
826
+		   ifq->altq_ifp->if_xname);
827
+		m_freem(m);
828
+		PKTCNTR_ADD(&cif->cl_stats.cl_dropcnt, m_pktlen(m));
829
+		return (ENOBUFS);
830
+	}
831
+
832
+	if (codel_addq(&cif->codel, cif->cl_q, m)) {
833
+		PKTCNTR_ADD(&cif->cl_stats.cl_dropcnt, m_pktlen(m));
834
+		return (ENOBUFS);
835
+	}
836
+	IFQ_INC_LEN(ifq);
837
+
838
+	return (0);
839
+}
840
+
841
+static struct mbuf *
842
+codel_dequeue(struct ifaltq *ifq, int op)
843
+{
844
+	struct codel_if *cif = (struct codel_if *)ifq->altq_disc;
845
+	struct mbuf *m;
846
+
847
+	IFQ_LOCK_ASSERT(ifq);
848
+
849
+	if (IFQ_IS_EMPTY(ifq))
850
+		return (NULL);
851
+
852
+	if (op == ALTDQ_POLL)
853
+		return (qhead(cif->cl_q));
854
+
855
+
856
+	m = codel_getq(&cif->codel, cif->cl_q);
857
+	if (m != NULL) {
858
+		IFQ_DEC_LEN(ifq);
859
+		PKTCNTR_ADD(&cif->cl_stats.cl_xmitcnt, m_pktlen(m));
860
+		return (m);
861
+	}
862
+
863
+	return (NULL);
864
+}
865
+
866
+struct codel *
867
+codel_alloc(int target, int interval, int ecn)
868
+{
869
+	struct codel	*c;
870
+
871
+	c = malloc(sizeof(*c), M_DEVBUF, M_NOWAIT|M_ZERO);
872
+
873
+	c->params.target = machclk_freq * target / 1000;
874
+	c->params.interval = machclk_freq * interval / 1000;
875
+	c->params.ecn = ecn;
876
+	c->stats.maxpacket = 256;
877
+
878
+	return (c);
879
+}
880
+
881
+void
882
+codel_destroy(struct codel *c)
883
+{
884
+	free(c, M_DEVBUF);
885
+}
886
+
887
+int
888
+codel_addq(struct codel *c, class_queue_t *q, struct mbuf *m)
889
+{
890
+	if (qlen(q) < qlimit(q)) {
891
+		m->m_pkthdr.enqueue_time = read_machclk();
892
+		_addq(q, m);
893
+		return (0);
894
+	}
895
+	c->drop_overlimit++;
896
+	m_freem(m);
897
+	return (-1);
898
+}
899
+
900
+static int
901
+codel_should_drop(struct codel *c, class_queue_t *q, struct mbuf *m,
902
+    u_int64_t now)
903
+{
904
+	if (m == NULL) {
905
+		c->vars.first_above_time = 0;
906
+		return (0);
907
+	}
908
+
909
+	c->vars.ldelay = now - m->m_pkthdr.enqueue_time;
910
+	c->stats.maxpacket = MAX(c->stats.maxpacket, m_pktlen(m));
911
+
912
+	if (codel_time_before(c->vars.ldelay, c->params.target) ||
913
+	    qsize(q) <= c->stats.maxpacket) {
914
+		/* went below - stay below for at least interval */
915
+		c->vars.first_above_time = 0;
916
+		return (0);
917
+	}
918
+	if (c->vars.first_above_time == 0) {
919
+		/* just went above from below. If we stay above
920
+		 * for at least interval we'll say it's ok to drop
921
+		 */
922
+		c->vars.first_above_time = now + c->params.interval;
923
+		return (0);
924
+	}
925
+	if (codel_time_after(now, c->vars.first_above_time))
926
+		return (1);
927
+	return (0);
928
+}
929
+
930
+/*
931
+ * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots
932
+ * new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2)
933
+ *
934
+ * Here, invsqrt is a fixed point number (< 1.0), 32bit mantissa, aka Q0.32
935
+ */
936
+static void codel_Newton_step(struct codel_vars *vars)
937
+{
938
+#define REC_INV_SQRT_BITS (8 * sizeof(u_int16_t)) /* or sizeof_in_bits(rec_inv_sqrt) */
939
+/* needed shift to get a Q0.32 number from rec_inv_sqrt */
940
+#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
941
+
942
+	u_int32_t invsqrt = ((u_int32_t)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT;
943
+	u_int32_t invsqrt2 = ((u_int64_t)invsqrt * invsqrt) >> 32;
944
+	u_int64_t val = (3LL << 32) - ((u_int64_t)vars->count * invsqrt2);
945
+
946
+	val >>= 2; /* avoid overflow in following multiply */
947
+	val = (val * invsqrt) >> (32 - 2 + 1);
948
+
949
+	vars->rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT;
950
+}
951
+
952
+static u_int64_t
953
+codel_control_law(u_int64_t t, u_int64_t interval, u_int32_t rec_inv_sqrt)
954
+{
955
+	return (t + (u_int32_t)(((u_int64_t)interval *
956
+	    (rec_inv_sqrt << REC_INV_SQRT_SHIFT)) >> 32));
957
+}
958
+
959
+struct mbuf *
960
+codel_getq(struct codel *c, class_queue_t *q)
961
+{
962
+	struct mbuf	*m;
963
+	u_int64_t	 now;
964
+	int		 drop;
965
+
966
+	if ((m = _getq(q)) == NULL) {
967
+		c->vars.dropping = 0;
968
+		return (m);
969
+	}
970
+
971
+	now = read_machclk();
972
+	drop = codel_should_drop(c, q, m, now);
973
+	if (c->vars.dropping) {
974
+		if (!drop) {
975
+			/* sojourn time below target - leave dropping state */
976
+			c->vars.dropping = 0;
977
+		} else if (codel_time_after_eq(now, c->vars.drop_next)) {
978
+			/* It's time for the next drop. Drop the current
979
+			 * packet and dequeue the next. The dequeue might
980
+			 * take us out of dropping state.
981
+			 * If not, schedule the next drop.
982
+			 * A large backlog might result in drop rates so high
983
+			 * that the next drop should happen now,
984
+			 * hence the while loop.
985
+			 */
986
+			while (c->vars.dropping &&
987
+			    codel_time_after_eq(now, c->vars.drop_next)) {
988
+				c->vars.count++; /* don't care of possible wrap
989
+						  * since there is no more
990
+						  * divide */
991
+				codel_Newton_step(&c->vars);
992
+				/* TODO ECN */
993
+				PKTCNTR_ADD(&c->stats.drop_cnt, m_pktlen(m));
994
+				m_freem(m);
995
+				m = _getq(q);
996
+				if (!codel_should_drop(c, q, m, now))
997
+					/* leave dropping state */
998
+					c->vars.dropping = 0;
999
+				else
1000
+					/* and schedule the next drop */
1001
+					c->vars.drop_next =
1002
+					    codel_control_law(c->vars.drop_next,
1003
+						c->params.interval,
1004
+						c->vars.rec_inv_sqrt);
1005
+			}
1006
+		}
1007
+	} else if (drop) {
1008
+		/* TODO ECN */
1009
+		PKTCNTR_ADD(&c->stats.drop_cnt, m_pktlen(m));
1010
+		m_freem(m);
1011
+
1012
+		m = _getq(q);
1013
+		drop = codel_should_drop(c, q, m, now);
1014
+
1015
+		c->vars.dropping = 1;
1016
+		/* if min went above target close to when we last went below it
1017
+		 * assume that the drop rate that controlled the queue on the
1018
+		 * last cycle is a good starting point to control it now.
1019
+		 */
1020
+		if (codel_time_before(now - c->vars.drop_next,
1021
+		    16 * c->params.interval)) {
1022
+			c->vars.count = (c->vars.count - c->vars.lastcount) | 1;
1023
+			/* we dont care if rec_inv_sqrt approximation
1024
+			 * is not very precise :
1025
+			 * Next Newton steps will correct it quadratically.
1026
+			 */
1027
+			codel_Newton_step(&c->vars);
1028
+		} else {
1029
+			c->vars.count = 1;
1030
+			c->vars.rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT;
1031
+		}
1032
+		c->vars.lastcount = c->vars.count;
1033
+		c->vars.drop_next = codel_control_law(now, c->params.interval,
1034
+		    c->vars.rec_inv_sqrt);
1035
+	}
1036
+
1037
+	return m;
1038
+}
1039
+
1040
+void
1041
+codel_getstats(struct codel *c, struct codel_stats *s)
1042
+{
1043
+	*s = c->stats;
1044
+}
1045
diff --git a/sys/contrib/altq/altq/altq_codel.h b/sys/contrib/altq/altq/altq_codel.h
1046
new file mode 100644
1047
index 0000000..9413ae1
1048
--- /dev/null
1049
+++ b/sys/contrib/altq/altq/altq_codel.h
1050
@@ -0,0 +1,87 @@
1051
+#ifndef _ALTQ_ALTQ_CODEL_H_
1052
+#define _ALTQ_ALTQ_CODEL_H_
1053
+
1054
+struct codel_stats {
1055
+	u_int32_t	 maxpacket;
1056
+	struct pktcntr	 drop_cnt;
1057
+	u_int		 marked_packets;
1058
+};
1059
+
1060
+struct codel_ifstats {
1061
+	u_int                   qlength;
1062
+        u_int                   qlimit;
1063
+        struct codel_stats       stats;
1064
+	struct pktcntr  cl_xmitcnt;	/* transmitted packet counter */
1065
+	struct pktcntr  cl_dropcnt;	/* dropped packet counter */
1066
+};
1067
+
1068
+#ifdef _KERNEL
1069
+#include <altq/altq_classq.h>
1070
+
1071
+/**
1072
+ * struct codel_params - contains codel parameters
1073
+ *  <at> target:        target queue size (in time units)
1074
+ *  <at> interval:      width of moving time window
1075
+ *  <at> ecn:   is Explicit Congestion Notification enabled
1076
+ */
1077
+struct codel_params {
1078
+        u_int64_t       target;
1079
+        u_int64_t       interval;
1080
+        int             ecn;
1081
+};
1082
+
1083
+/**
1084
+ * struct codel_vars - contains codel variables
1085
+ *  <at> count:         how many drops we've done since the last time we
1086
+ *                      entered dropping state
1087
+ *  <at> lastcount:             count at entry to dropping state
1088
+ *  <at> dropping:              set to true if in dropping state
1089
+ *  <at> rec_inv_sqrt:  reciprocal value of sqrt(count) >> 1
1090
+ *  <at> first_above_time:      when we went (or will go) continuously above target
1091
+ *                      for interval
1092
+ *  <at> drop_next:             time to drop next packet, or when we dropped last
1093
+ *  <at> ldelay:                sojourn time of last dequeued packet
1094
+ */
1095
+struct codel_vars {
1096
+        u_int32_t       count;
1097
+        u_int32_t       lastcount;
1098
+        int             dropping;
1099
+        u_int16_t       rec_inv_sqrt;
1100
+        u_int64_t       first_above_time;
1101
+        u_int64_t       drop_next;
1102
+        u_int64_t       ldelay;
1103
+};
1104
+        
1105
+struct codel {
1106
+        struct codel_params      params;
1107
+        struct codel_vars        vars;
1108
+        struct codel_stats       stats;
1109
+        u_int32_t                drop_overlimit;
1110
+};
1111
+
1112
+/*
1113
+ * codel interface state
1114
+ */
1115
+struct codel_if {
1116
+	struct codel_if		*cif_next;	/* interface state list */
1117
+	struct ifaltq		*cif_ifq;	/* backpointer to ifaltq */
1118
+	u_int			cif_bandwidth;	/* link bandwidth in bps */
1119
+
1120
+	class_queue_t	*cl_q;		/* class queue structure */
1121
+	struct codel	codel;
1122
+
1123
+	/* statistics */
1124
+	struct codel_ifstats cl_stats;
1125
+};
1126
+
1127
+struct codel;
1128
+
1129
+struct codel	*codel_alloc(int, int, int);
1130
+void		 codel_destroy(struct codel *);
1131
+int		 codel_addq(struct codel *, class_queue_t *, struct mbuf *);
1132
+struct mbuf	*codel_getq(struct codel *, class_queue_t *);
1133
+void		 codel_getstats(struct codel *, struct codel_stats *);
1134
+
1135
+#endif
1136
+
1137
+#endif /* _ALTQ_ALTQ_CODEL_H_ */
1138
diff --git a/sys/contrib/altq/altq/altq_fairq.c b/sys/contrib/altq/altq/altq_fairq.c
1139
index 2267bfd..2277aa8 100644
1140
--- a/sys/contrib/altq/altq/altq_fairq.c
1141
+++ b/sys/contrib/altq/altq/altq_fairq.c
1142
@@ -156,10 +156,7 @@ fairq_add_altq(struct pf_altq *a)
1143
 
1144
 
1145
 	MALLOC(pif, struct fairq_if *, sizeof(struct fairq_if),
1146
-		M_DEVBUF, M_WAITOK);
1147
-	if (pif == NULL)
1148
-		return (ENOMEM);
1149
-	bzero(pif, sizeof(struct fairq_if));
1150
+		M_DEVBUF, M_WAITOK|M_ZERO);
1151
 	pif->pif_bandwidth = a->ifbandwidth;
1152
 	pif->pif_maxpri = -1;
1153
 	pif->pif_ifq = &ifp->if_snd;
1154
@@ -318,6 +315,14 @@ fairq_class_create(struct fairq_if *pif, int pri, int qlimit,
1155
 		return (NULL);
1156
 	}
1157
 #endif
1158
+#ifndef ALTQ_CODEL
1159
+	if (flags & FARF_CODEL) {
1160
+#ifdef ALTQ_DEBUG
1161
+		printf("fairq_class_create: CODEL not configured for FAIRQ!\n");
1162
+#endif
1163
+		return (NULL);
1164
+	}
1165
+#endif
1166
 	if (nbuckets == 0)
1167
 		nbuckets = 256;
1168
 	if (nbuckets > FAIRQ_MAX_BUCKETS)
1169
@@ -342,6 +347,10 @@ fairq_class_create(struct fairq_if *pif, int pri, int qlimit,
1170
 		if (cl->cl_qtype == Q_RED)
1171
 			red_destroy(cl->cl_red);
1172
 #endif
1173
+#ifdef ALTQ_CODEL
1174
+		if (cl->cl_qtype == Q_CODEL)
1175
+			codel_destroy(cl->cl_codel);
1176
+#endif
1177
 	} else {
1178
 		MALLOC(cl, struct fairq_class *, sizeof(struct fairq_class),
1179
 			M_DEVBUF, M_WAITOK);
1180
@@ -415,6 +424,12 @@ fairq_class_create(struct fairq_if *pif, int pri, int qlimit,
1181
 		}
1182
 	}
1183
 #endif /* ALTQ_RED */
1184
+#ifdef ALTQ_CODEL
1185
+	if (flags & FARF_CODEL) {
1186
+		cl->cl_codel = codel_alloc(100, 5, 0);
1187
+		cl->cl_qtype = Q_CODEL;
1188
+	}
1189
+#endif
1190
 
1191
 	return (cl);
1192
 
1193
@@ -431,6 +446,10 @@ err_ret:
1194
                if (cl->cl_qtype == Q_RED)
1195
                        red_destroy(cl->cl_red);
1196
 #endif
1197
+#ifdef ALTQ_CODEL
1198
+               if (cl->cl_qtype == Q_CODEL)
1199
+                       codel_destroy(cl->cl_codel);
1200
+#endif
1201
         }
1202
         if (cl != NULL)
1203
                 FREE(cl, M_DEVBUF);
1204
@@ -474,6 +493,10 @@ fairq_class_destroy(struct fairq_class *cl)
1205
 		if (cl->cl_qtype == Q_RED)
1206
 			red_destroy(cl->cl_red);
1207
 #endif
1208
+#ifdef ALTQ_CODEL
1209
+		if (cl->cl_qtype == Q_CODEL)
1210
+			codel_destroy(cl->cl_codel);
1211
+#endif
1212
 	}
1213
 	FREE(cl->cl_buckets, M_DEVBUF);
1214
 	cl->cl_head = NULL;	/* sanity */
1215
@@ -671,6 +694,10 @@ fairq_addq(struct fairq_class *cl, struct mbuf *m, u_int32_t bucketid)
1216
 	if (cl->cl_qtype == Q_RED)
1217
 		return red_addq(cl->cl_red, &b->queue, m, cl->cl_pktattr);
1218
 #endif
1219
+#ifdef ALTQ_CODEL
1220
+	if (cl->cl_qtype == Q_CODEL)
1221
+		return codel_addq(cl->cl_codel, &b->queue, m);
1222
+#endif
1223
 	if (qlen(&b->queue) >= qlimit(&b->queue)) {
1224
 		m_freem(m);
1225
 		return (-1);
1226
@@ -701,6 +728,10 @@ fairq_getq(struct fairq_class *cl, uint64_t cur_time)
1227
 	else if (cl->cl_qtype == Q_RED)
1228
 		m = red_getq(cl->cl_red, &b->queue);
1229
 #endif
1230
+#ifdef ALTQ_CODEL
1231
+	else if (cl->cl_qtype == Q_CODEL)
1232
+		m = codel_getq(cl->cl_codel, &b->queue);
1233
+#endif
1234
 	else
1235
 		m = _getq(&b->queue);
1236
 
1237
@@ -882,6 +913,10 @@ get_class_stats(struct fairq_classstats *sp, struct fairq_class *cl)
1238
 	if (cl->cl_qtype == Q_RIO)
1239
 		rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
1240
 #endif
1241
+#ifdef ALTQ_CODEL
1242
+	if (cl->cl_qtype == Q_CODEL)
1243
+		codel_getstats(cl->cl_codel, &sp->codel);
1244
+#endif
1245
 }
1246
 
1247
 /* convert a class handle to the corresponding class pointer */
1248
diff --git a/sys/contrib/altq/altq/altq_fairq.h b/sys/contrib/altq/altq/altq_fairq.h
1249
index e4675e0..f13513b 100644
1250
--- a/sys/contrib/altq/altq/altq_fairq.h
1251
+++ b/sys/contrib/altq/altq/altq_fairq.h
1252
@@ -42,6 +42,7 @@
1253
 #include <altq/altq_red.h>
1254
 #include <altq/altq_rio.h>
1255
 #include <altq/altq_rmclass.h>
1256
+#include <altq/altq_codel.h>
1257
 
1258
 #define	FAIRQ_MAX_BUCKETS	2048	/* maximum number of sorting buckets */
1259
 #define	FAIRQ_MAXPRI		RM_MAXPRIO
1260
@@ -52,6 +53,7 @@
1261
 #define	FARF_RED		0x0001	/* use RED */
1262
 #define	FARF_ECN		0x0002  /* use RED/ECN */
1263
 #define	FARF_RIO		0x0004  /* use RIO */
1264
+#define	FARF_CODEL		0x0008  /* use CODEL */
1265
 #define	FARF_CLEARDSCP		0x0010  /* clear diffserv codepoint */
1266
 #define	FARF_DEFAULTCLASS	0x1000	/* default class */
1267
 
1268
@@ -76,6 +78,7 @@ struct fairq_classstats {
1269
 	/* red and rio related info */
1270
 	int			qtype;
1271
 	struct redstats		red[3];	/* rio has 3 red stats */
1272
+	struct codel_stats	codel;
1273
 };
1274
 
1275
 #ifdef _KERNEL
1276
@@ -97,7 +100,10 @@ struct fairq_class {
1277
 	fairq_bucket_t	*cl_buckets;
1278
 	fairq_bucket_t	*cl_head;	/* head of circular bucket list */
1279
 	fairq_bucket_t	*cl_polled;
1280
-	struct red	*cl_red;	/* RED state */
1281
+	union {
1282
+		struct red	*cl_red;	/* RED state */
1283
+		struct codel	*cl_codel;
1284
+	} cl_aqm;
1285
 	u_int		cl_hogs_m1;
1286
 	u_int		cl_lssc_m1;
1287
 	u_int		cl_bandwidth;
1288
@@ -117,6 +123,8 @@ struct fairq_class {
1289
 	struct pktcntr  cl_xmitcnt;	/* transmitted packet counter */
1290
 	struct pktcntr  cl_dropcnt;	/* dropped packet counter */
1291
 };
1292
+#define	cl_red	cl_aqm.cl_red
1293
+#define	cl_codel	cl_aqm.cl_codel
1294
 
1295
 /*
1296
  * fairq interface state
1297
diff --git a/sys/contrib/altq/altq/altq_hfsc.c b/sys/contrib/altq/altq/altq_hfsc.c
1298
index 0363016..b87ac3a 100644
1299
--- a/sys/contrib/altq/altq/altq_hfsc.c
1300
+++ b/sys/contrib/altq/altq/altq_hfsc.c
1301
@@ -391,6 +391,14 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc,
1302
 		return (NULL);
1303
 	}
1304
 #endif
1305
+#ifndef ALTQ_CODEL
1306
+	if (flags & HFCF_CODEL) {
1307
+#ifdef ALTQ_DEBUG
1308
+		printf("hfsc_class_create: CODEL not configured for HFSC!\n");
1309
+#endif
1310
+		return (NULL);
1311
+	}
1312
+#endif
1313
 
1314
 	cl = malloc(sizeof(struct hfsc_class), M_DEVBUF, M_NOWAIT | M_ZERO);
1315
 	if (cl == NULL)
1316
@@ -407,6 +415,7 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc,
1317
 	qlimit(cl->cl_q) = qlimit;
1318
 	qtype(cl->cl_q) = Q_DROPTAIL;
1319
 	qlen(cl->cl_q) = 0;
1320
+	qsize(cl->cl_q) = 0;
1321
 	cl->cl_flags = flags;
1322
 #ifdef ALTQ_RED
1323
 	if (flags & (HFCF_RED|HFCF_RIO)) {
1324
@@ -451,6 +460,12 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc,
1325
 #endif
1326
 	}
1327
 #endif /* ALTQ_RED */
1328
+#ifdef ALTQ_CODEL
1329
+	if (flags & HFCF_CODEL) {
1330
+		cl->cl_codel = codel_alloc(100, 5, 0);
1331
+		qtype(cl->cl_q) = Q_CODEL;
1332
+	}
1333
+#endif
1334
 
1335
 	if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0)) {
1336
 		cl->cl_rsc = malloc(sizeof(struct internal_sc),
1337
@@ -543,6 +558,10 @@ hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc,
1338
 		if (q_is_red(cl->cl_q))
1339
 			red_destroy(cl->cl_red);
1340
 #endif
1341
+#ifdef ALTQ_CODEL
1342
+		if (q_is_codel(cl->cl_q))
1343
+			codel_destroy(cl->cl_codel);
1344
+#endif
1345
 	}
1346
 	if (cl->cl_fsc != NULL)
1347
 		free(cl->cl_fsc, M_DEVBUF);
1348
@@ -617,6 +636,10 @@ hfsc_class_destroy(struct hfsc_class *cl)
1349
 		if (q_is_red(cl->cl_q))
1350
 			red_destroy(cl->cl_red);
1351
 #endif
1352
+#ifdef ALTQ_CODEL
1353
+		if (q_is_codel(cl->cl_q))
1354
+			codel_destroy(cl->cl_codel);
1355
+#endif
1356
 	}
1357
 
1358
 	IFQ_LOCK(cl->cl_hif->hif_ifq);
1359
@@ -844,6 +867,10 @@ hfsc_addq(struct hfsc_class *cl, struct mbuf *m)
1360
 	if (q_is_red(cl->cl_q))
1361
 		return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr);
1362
 #endif
1363
+#ifdef ALTQ_CODEL
1364
+	if (q_is_codel(cl->cl_q))
1365
+		return codel_addq(cl->cl_codel, cl->cl_q, m);
1366
+#endif
1367
 	if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) {
1368
 		m_freem(m);
1369
 		return (-1);
1370
@@ -868,6 +895,10 @@ hfsc_getq(struct hfsc_class *cl)
1371
 	if (q_is_red(cl->cl_q))
1372
 		return red_getq(cl->cl_red, cl->cl_q);
1373
 #endif
1374
+#ifdef ALTQ_CODEL
1375
+	if (q_is_codel(cl->cl_q))
1376
+		return codel_getq(cl->cl_codel, cl->cl_q);
1377
+#endif
1378
 	return _getq(cl->cl_q);
1379
 }
1380
 
1381
@@ -1652,6 +1683,10 @@ get_class_stats(struct hfsc_classstats *sp, struct hfsc_class *cl)
1382
 	if (q_is_rio(cl->cl_q))
1383
 		rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
1384
 #endif
1385
+#ifdef ALTQ_CODEL
1386
+	if (q_is_codel(cl->cl_q))
1387
+		codel_getstats(cl->cl_codel, &sp->codel);
1388
+#endif
1389
 }
1390
 
1391
 /* convert a class handle to the corresponding class pointer */
1392
diff --git a/sys/contrib/altq/altq/altq_hfsc.h b/sys/contrib/altq/altq/altq_hfsc.h
1393
index e5595cb..c8e9b13 100644
1394
--- a/sys/contrib/altq/altq/altq_hfsc.h
1395
+++ b/sys/contrib/altq/altq/altq_hfsc.h
1396
@@ -36,6 +36,7 @@
1397
 #include <altq/altq_classq.h>
1398
 #include <altq/altq_red.h>
1399
 #include <altq/altq_rio.h>
1400
+#include <altq/altq_codel.h>
1401
 
1402
 #ifdef __cplusplus
1403
 extern "C" {
1404
@@ -55,6 +56,7 @@ struct service_curve {
1405
 #define	HFCF_RED		0x0001	/* use RED */
1406
 #define	HFCF_ECN		0x0002  /* use RED/ECN */
1407
 #define	HFCF_RIO		0x0004  /* use RIO */
1408
+#define	HFCF_CODEL		0x0008  /* use CODEL */
1409
 #define	HFCF_CLEARDSCP		0x0010  /* clear diffserv codepoint */
1410
 #define	HFCF_DEFAULTCLASS	0x1000	/* default class */
1411
 
1412
@@ -104,6 +106,7 @@ struct hfsc_classstats {
1413
 	/* red and rio related info */
1414
 	int			qtype;
1415
 	struct redstats		red[3];
1416
+	struct codel_stats	codel;
1417
 };
1418
 
1419
 #ifdef ALTQ3_COMPAT
1420
@@ -229,7 +232,10 @@ struct hfsc_class {
1421
 	struct hfsc_class *cl_children;	/* child classes */
1422
 
1423
 	class_queue_t	*cl_q;		/* class queue structure */
1424
-	struct red	*cl_red;	/* RED state */
1425
+	union {
1426
+		struct red	*cl_red;	/* RED state */
1427
+		struct codel	*cl_codel;	/* CoDel state */
1428
+	} cl_aqm;
1429
 	struct altq_pktattr *cl_pktattr; /* saved header used by ECN */
1430
 
1431
 	u_int64_t	cl_total;	/* total work in bytes */
1432
@@ -278,6 +284,8 @@ struct hfsc_class {
1433
 		u_int period;
1434
 	} cl_stats;
1435
 };
1436
+#define cl_red			cl_aqm.cl_red
1437
+#define cl_codel		cl_aqm.cl_codel
1438
 
1439
 /*
1440
  * hfsc interface state
1441
diff --git a/sys/contrib/altq/altq/altq_priq.c b/sys/contrib/altq/altq/altq_priq.c
1442
index 3ce65dc..cea88be 100644
1443
--- a/sys/contrib/altq/altq/altq_priq.c
1444
+++ b/sys/contrib/altq/altq/altq_priq.c
1445
@@ -297,6 +297,15 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid)
1446
 		return (NULL);
1447
 	}
1448
 #endif
1449
+#ifndef ALTQ_CODEL
1450
+	if (flags & PRCF_CODEL) {
1451
+#ifdef ALTQ_DEBUG
1452
+		printf("priq_class_create: CODEL not configured for PRIQ!\n");
1453
+#endif
1454
+		return (NULL);
1455
+	}
1456
+#endif
1457
+	
1458
 
1459
 	if ((cl = pif->pif_classes[pri]) != NULL) {
1460
 		/* modify the class instead of creating a new one */
1461
@@ -318,6 +327,10 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid)
1462
 		if (q_is_red(cl->cl_q))
1463
 			red_destroy(cl->cl_red);
1464
 #endif
1465
+#ifdef ALTQ_CODEL
1466
+		if (q_is_codel(cl->cl_q))
1467
+			codel_destroy(cl->cl_codel);
1468
+#endif
1469
 	} else {
1470
 		cl = malloc(sizeof(struct priq_class), M_DEVBUF,
1471
 		    M_NOWAIT | M_ZERO);
1472
@@ -338,6 +351,7 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid)
1473
 	qlimit(cl->cl_q) = qlimit;
1474
 	qtype(cl->cl_q) = Q_DROPTAIL;
1475
 	qlen(cl->cl_q) = 0;
1476
+	qsize(cl->cl_q) = 0;
1477
 	cl->cl_flags = flags;
1478
 	cl->cl_pri = pri;
1479
 	if (pri > pif->pif_maxpri)
1480
@@ -381,6 +395,12 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid)
1481
 		}
1482
 	}
1483
 #endif /* ALTQ_RED */
1484
+#ifdef ALTQ_CODEL
1485
+	if (flags & PRCF_CODEL) {
1486
+		cl->cl_codel = codel_alloc(100, 5, 0);
1487
+		qtype(cl->cl_q) = Q_CODEL;
1488
+	}
1489
+#endif
1490
 
1491
 	return (cl);
1492
 
1493
@@ -394,6 +414,10 @@ priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid)
1494
 		if (q_is_red(cl->cl_q))
1495
 			red_destroy(cl->cl_red);
1496
 #endif
1497
+#ifdef ALTQ_CODEL
1498
+		if (q_is_codel(cl->cl_q))
1499
+			codel_destroy(cl->cl_codel);
1500
+#endif
1501
 	}
1502
 	if (cl->cl_q != NULL)
1503
 		free(cl->cl_q, M_DEVBUF);
1504
@@ -445,6 +469,10 @@ priq_class_destroy(struct priq_class *cl)
1505
 		if (q_is_red(cl->cl_q))
1506
 			red_destroy(cl->cl_red);
1507
 #endif
1508
+#ifdef ALTQ_CODEL
1509
+		if (q_is_codel(cl->cl_q))
1510
+			codel_destroy(cl->cl_codel);
1511
+#endif
1512
 	}
1513
 	free(cl->cl_q, M_DEVBUF);
1514
 	free(cl, M_DEVBUF);
1515
@@ -560,6 +588,10 @@ priq_addq(struct priq_class *cl, struct mbuf *m)
1516
 	if (q_is_red(cl->cl_q))
1517
 		return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr);
1518
 #endif
1519
+#ifdef ALTQ_CODEL
1520
+	if (q_is_codel(cl->cl_q))
1521
+		return codel_addq(cl->cl_codel, cl->cl_q, m);
1522
+#endif
1523
 	if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) {
1524
 		m_freem(m);
1525
 		return (-1);
1526
@@ -584,6 +616,10 @@ priq_getq(struct priq_class *cl)
1527
 	if (q_is_red(cl->cl_q))
1528
 		return red_getq(cl->cl_red, cl->cl_q);
1529
 #endif
1530
+#ifdef ALTQ_CODEL
1531
+	if (q_is_codel(cl->cl_q))
1532
+		return codel_getq(cl->cl_codel, cl->cl_q);
1533
+#endif
1534
 	return _getq(cl->cl_q);
1535
 }
1536
 
1537
@@ -628,6 +664,10 @@ get_class_stats(struct priq_classstats *sp, struct priq_class *cl)
1538
 	if (q_is_rio(cl->cl_q))
1539
 		rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
1540
 #endif
1541
+#ifdef ALTQ_CODEL
1542
+	if (q_is_codel(cl->cl_q))
1543
+		codel_getstats(cl->cl_codel, &sp->codel);
1544
+#endif
1545
 
1546
 }
1547
 
1548
diff --git a/sys/contrib/altq/altq/altq_priq.h b/sys/contrib/altq/altq/altq_priq.h
1549
index 481d31b..b5b062f 100644
1550
--- a/sys/contrib/altq/altq/altq_priq.h
1551
+++ b/sys/contrib/altq/altq/altq_priq.h
1552
@@ -32,6 +32,7 @@
1553
 #include <altq/altq_classq.h>
1554
 #include <altq/altq_red.h>
1555
 #include <altq/altq_rio.h>
1556
+#include <altq/altq_codel.h>
1557
 
1558
 #ifdef __cplusplus
1559
 extern "C" {
1560
@@ -59,6 +60,7 @@ struct priq_add_class {
1561
 #define	PRCF_RED		0x0001	/* use RED */
1562
 #define	PRCF_ECN		0x0002  /* use RED/ECN */
1563
 #define	PRCF_RIO		0x0004  /* use RIO */
1564
+#define	PRCF_CODEL		0x0008  /* use CODEL */
1565
 #define	PRCF_CLEARDSCP		0x0010  /* clear diffserv codepoint */
1566
 #define	PRCF_DEFAULTCLASS	0x1000	/* default class */
1567
 
1568
@@ -105,6 +107,7 @@ struct priq_classstats {
1569
 	/* red and rio related info */
1570
 	int			qtype;
1571
 	struct redstats		red[3];	/* rio has 3 red stats */
1572
+	struct codel_stats	codel;
1573
 };
1574
 
1575
 #ifdef ALTQ3_COMPAT
1576
@@ -134,7 +137,10 @@ struct priq_class_stats {
1577
 struct priq_class {
1578
 	u_int32_t	cl_handle;	/* class handle */
1579
 	class_queue_t	*cl_q;		/* class queue structure */
1580
-	struct red	*cl_red;	/* RED state */
1581
+	union {
1582
+		struct red	*cl_red; /* RED state */
1583
+		struct codel	*cl_codel;	/* CoDel state */
1584
+	} cl_aqm;
1585
 	int		cl_pri;		/* priority */
1586
 	int		cl_flags;	/* class flags */
1587
 	struct priq_if	*cl_pif;	/* back pointer to pif */
1588
@@ -145,7 +151,8 @@ struct priq_class {
1589
 	struct pktcntr  cl_xmitcnt;	/* transmitted packet counter */
1590
 	struct pktcntr  cl_dropcnt;	/* dropped packet counter */
1591
 };
1592
-
1593
+#define	cl_red	cl_aqm.cl_red
1594
+#define cl_codel	cl_aqm.cl_codel
1595
 /*
1596
  * priq interface state
1597
  */
1598
diff --git a/sys/contrib/altq/altq/altq_rmclass.c b/sys/contrib/altq/altq/altq_rmclass.c
1599
index c433024..7208c60 100644
1600
--- a/sys/contrib/altq/altq/altq_rmclass.c
1601
+++ b/sys/contrib/altq/altq/altq_rmclass.c
1602
@@ -72,6 +72,7 @@
1603
 #include <altq/altq_rmclass_debug.h>
1604
 #include <altq/altq_red.h>
1605
 #include <altq/altq_rio.h>
1606
+#include <altq/altq_codel.h>
1607
 
1608
 /*
1609
  * Local Macros
1610
@@ -218,6 +219,14 @@ rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte,
1611
 		return (NULL);
1612
 	}
1613
 #endif
1614
+#ifndef ALTQ_CODEL
1615
+	if (flags & RMCF_CODEL) {
1616
+#ifdef ALTQ_DEBUG
1617
+		printf("rmc_newclass: CODEL not configured for CBQ!\n");
1618
+#endif
1619
+		return (NULL);
1620
+	}
1621
+#endif
1622
 
1623
 	cl = malloc(sizeof(struct rm_class), M_DEVBUF, M_NOWAIT | M_ZERO);
1624
 	if (cl == NULL)
1625
@@ -302,6 +311,12 @@ rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte,
1626
 #endif
1627
 	}
1628
 #endif /* ALTQ_RED */
1629
+#ifdef	ALTQ_CODEL
1630
+	if (flags & RMCF_CODEL) {
1631
+		cl->codel_ = codel_alloc(100, 5, 0);
1632
+		qtype(cl->q_) = Q_CODEL;
1633
+	}
1634
+#endif
1635
 
1636
 	/*
1637
 	 * put the class into the class tree
1638
@@ -652,6 +667,10 @@ rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl)
1639
 		if (q_is_red(cl->q_))
1640
 			red_destroy(cl->red_);
1641
 #endif
1642
+#ifdef ALTQ_CODEL
1643
+		if (q_is_codel(cl->q_))
1644
+			codel_destroy(cl->codel_);
1645
+#endif
1646
 	}
1647
 	free(cl->q_, M_DEVBUF);
1648
 	free(cl, M_DEVBUF);
1649
@@ -1618,6 +1637,10 @@ _rmc_addq(rm_class_t *cl, mbuf_t *m)
1650
 	if (q_is_red(cl->q_))
1651
 		return red_addq(cl->red_, cl->q_, m, cl->pktattr_);
1652
 #endif /* ALTQ_RED */
1653
+#ifdef ALTQ_CODEL
1654
+	if (q_is_codel(cl->q_))
1655
+		return codel_addq(cl->codel_, cl->q_, m);
1656
+#endif /* ALTQ_RED */
1657
 
1658
 	if (cl->flags_ & RMCF_CLEARDSCP)
1659
 		write_dsfield(m, cl->pktattr_, 0);
1660
@@ -1647,6 +1670,10 @@ _rmc_getq(rm_class_t *cl)
1661
 	if (q_is_red(cl->q_))
1662
 		return red_getq(cl->red_, cl->q_);
1663
 #endif
1664
+#ifdef ALTQ_CODEL
1665
+	if (q_is_codel(cl->q_))
1666
+		return codel_getq(cl->codel_, cl->q_);
1667
+#endif
1668
 	return _getq(cl->q_);
1669
 }
1670
 
1671
@@ -1717,7 +1744,7 @@ void cbqtrace_dump(int counter)
1672
 #endif /* CBQ_TRACE */
1673
 #endif /* ALTQ_CBQ */
1674
 
1675
-#if defined(ALTQ_CBQ) || defined(ALTQ_RED) || defined(ALTQ_RIO) || defined(ALTQ_HFSC) || defined(ALTQ_PRIQ)
1676
+#if defined(ALTQ_CBQ) || defined(ALTQ_RED) || defined(ALTQ_RIO) || defined(ALTQ_HFSC) || defined(ALTQ_PRIQ) || defined(ALTQ_CODEL)
1677
 #if !defined(__GNUC__) || defined(ALTQ_DEBUG)
1678
 
1679
 void
1680
diff --git a/sys/contrib/altq/altq/altq_rmclass.h b/sys/contrib/altq/altq/altq_rmclass.h
1681
index cf0ddf4..bd87591 100644
1682
--- a/sys/contrib/altq/altq/altq_rmclass.h
1683
+++ b/sys/contrib/altq/altq/altq_rmclass.h
1684
@@ -53,6 +53,7 @@ typedef struct rm_ifdat		rm_ifdat_t;
1685
 typedef struct rm_class		rm_class_t;
1686
 
1687
 struct red;
1688
+struct codel;
1689
 
1690
 /*
1691
  * Macros for dealing with time values.  We assume all times are
1692
@@ -164,7 +165,10 @@ struct rm_class {
1693
 	void	(*overlimit)(struct rm_class *, struct rm_class *);
1694
 	void	(*drop)(struct rm_class *);       /* Class drop action. */
1695
 
1696
-	struct red	*red_;		/* RED state pointer */
1697
+	union {
1698
+		struct red	*red_;		/* RED state pointer */
1699
+		struct codel	*codel;
1700
+	} cl_aqm;
1701
 	struct altq_pktattr *pktattr_;	/* saved hdr used by RED/ECN */
1702
 	int		flags_;
1703
 
1704
@@ -176,6 +180,8 @@ struct rm_class {
1705
 
1706
 	rm_class_stats_t stats_;	/* Class Statistics */
1707
 };
1708
+#define	red_	cl_aqm.red_
1709
+#define	codel_	cl_aqm.codel
1710
 
1711
 /*
1712
  * CBQ Interface state
1713
@@ -233,6 +239,7 @@ struct rm_ifdat {
1714
 #define	RMCF_RIO		0x0004
1715
 #define	RMCF_FLOWVALVE		0x0008	/* use flowvalve (aka penalty-box) */
1716
 #define	RMCF_CLEARDSCP		0x0010  /* clear diffserv codepoint */
1717
+#define	RMCF_CODEL		0x0040
1718
 
1719
 /* flags for rmc_init */
1720
 #define	RMCF_WRR		0x0100
1721
diff --git a/sys/contrib/altq/altq/altq_subr.c b/sys/contrib/altq/altq/altq_subr.c
1722
index d59751a..fff1b49 100644
1723
--- a/sys/contrib/altq/altq/altq_subr.c
1724
+++ b/sys/contrib/altq/altq/altq_subr.c
1725
@@ -542,6 +542,11 @@ altq_pfattach(struct pf_altq *a)
1726
 		error = fairq_pfattach(a);
1727
 		break;
1728
 #endif
1729
+#ifdef ALTQ_CODEL
1730
+	case ALTQT_CODEL:
1731
+		error = codel_pfattach(a);
1732
+		break;
1733
+#endif
1734
 	default:
1735
 		error = ENXIO;
1736
 	}
1737
@@ -622,6 +627,11 @@ altq_add(struct pf_altq *a)
1738
                 error = fairq_add_altq(a);
1739
                 break;
1740
 #endif
1741
+#ifdef ALTQ_CODEL
1742
+        case ALTQT_CODEL:
1743
+                error = codel_add_altq(a);
1744
+                break;
1745
+#endif
1746
 	default:
1747
 		error = ENXIO;
1748
 	}
1749
@@ -663,6 +673,11 @@ altq_remove(struct pf_altq *a)
1750
                 error = fairq_remove_altq(a);
1751
                 break;
1752
 #endif
1753
+#ifdef ALTQ_CODEL
1754
+        case ALTQT_CODEL:
1755
+                error = codel_remove_altq(a);
1756
+                break;
1757
+#endif
1758
 	default:
1759
 		error = ENXIO;
1760
 	}
1761
@@ -777,6 +792,11 @@ altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
1762
                 error = fairq_getqstats(a, ubuf, nbytes);
1763
                 break;
1764
 #endif
1765
+#ifdef ALTQ_CODEL
1766
+        case ALTQT_CODEL:
1767
+                error = codel_getqstats(a, ubuf, nbytes);
1768
+                break;
1769
+#endif
1770
 	default:
1771
 		error = ENXIO;
1772
 	}
1773
diff --git a/sys/contrib/altq/altq/altq_var.h b/sys/contrib/altq/altq/altq_var.h
1774
index eb603ea..6ea7b7c 100644
1775
--- a/sys/contrib/altq/altq/altq_var.h
1776
+++ b/sys/contrib/altq/altq/altq_var.h
1777
@@ -250,6 +250,11 @@ int	priq_add_queue(struct pf_altq *);
1778
 int	priq_remove_queue(struct pf_altq *);
1779
 int	priq_getqstats(struct pf_altq *, void *, int *);
1780
 
1781
+int     codel_pfattach(struct pf_altq *);
1782
+int     codel_add_altq(struct pf_altq *);
1783
+int     codel_remove_altq(struct pf_altq *);
1784
+int     codel_getqstats(struct pf_altq *, void *, int *);
1785
+
1786
 int	hfsc_pfattach(struct pf_altq *);
1787
 int	hfsc_add_altq(struct pf_altq *);
1788
 int	hfsc_remove_altq(struct pf_altq *);
1789
diff --git a/sys/netpfil/pf/pf_altq.h b/sys/netpfil/pf/pf_altq.h
1790
index db681fb..e578ae1 100644
1791
--- a/sys/netpfil/pf/pf_altq.h
1792
+++ b/sys/netpfil/pf/pf_altq.h
1793
@@ -79,6 +79,12 @@ struct fairq_opts {
1794
 	u_int           lssc_m2;
1795
 };
1796
 
1797
+struct codel_opts {
1798
+       u_int           target;
1799
+        u_int          interval;
1800
+        int            ecn;
1801
+};
1802
+
1803
 struct pf_altq {
1804
 	char			 ifname[IFNAMSIZ];
1805
 
1806
@@ -106,6 +112,7 @@ struct pf_altq {
1807
 		struct priq_opts	 priq_opts;
1808
 		struct hfsc_opts	 hfsc_opts;
1809
 		struct fairq_opts        fairq_opts;
1810
+		struct codel_opts        codel_opts;
1811
 	} pq_u;
1812
 
1813
 	uint32_t		 qid;		/* return value */
1814
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
1815
index bc2924a..8b52f19 100644
1816
--- a/sys/sys/mbuf.h
1817
+++ b/sys/sys/mbuf.h
1818
@@ -128,6 +128,7 @@ struct pkthdr {
1819
 	uint32_t	 flowid;	/* packet's 4-tuple system */
1820
 	uint64_t	 csum_flags;	/* checksum and offload features */
1821
 	uint16_t	 fibnum;	/* this packet should use this fib */
1822
+	uint64_t	 enqueue_time;
1823
 	uint8_t		 cosqos;	/* class/quality of service */
1824
 	uint8_t		 rsstype;	/* hash type */
1825
 	uint8_t		 l2hlen;	/* layer 2 header length */
(5-5/67)