xref: /dragonfly/sys/net/altq/altq_subr.c (revision 81c11cd3)
1 /*	$KAME: altq_subr.c,v 1.23 2004/04/20 16:10:06 itojun Exp $	*/
2 /*	$DragonFly: src/sys/net/altq/altq_subr.c,v 1.12 2008/05/14 11:59:23 sephe Exp $ */
3 
4 /*
5  * Copyright (C) 1997-2003
6  *	Sony Computer Science Laboratories Inc.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include "opt_altq.h"
31 #include "opt_inet.h"
32 #include "opt_inet6.h"
33 
34 #include <sys/param.h>
35 #include <sys/malloc.h>
36 #include <sys/mbuf.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/kernel.h>
42 #include <sys/callout.h>
43 #include <sys/errno.h>
44 #include <sys/syslog.h>
45 #include <sys/sysctl.h>
46 #include <sys/queue.h>
47 #include <sys/thread2.h>
48 
49 #include <net/if.h>
50 #include <net/if_dl.h>
51 #include <net/if_types.h>
52 #include <net/ifq_var.h>
53 
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
57 #ifdef INET6
58 #include <netinet/ip6.h>
59 #endif
60 #include <netinet/tcp.h>
61 #include <netinet/udp.h>
62 
63 #include <net/pf/pfvar.h>
64 #include <net/altq/altq.h>
65 
66 /* machine dependent clock related includes */
67 #include <machine/clock.h>		/* for tsc_frequency */
68 #include <machine/md_var.h>		/* for cpu_feature */
69 #include <machine/specialreg.h>		/* for CPUID_TSC */
70 
71 /*
72  * internal function prototypes
73  */
74 static void	tbr_timeout(void *);
75 static int	altq_enable_locked(struct ifaltq *);
76 static int	altq_disable_locked(struct ifaltq *);
77 static int	altq_detach_locked(struct ifaltq *);
78 static int	tbr_set_locked(struct ifaltq *, struct tb_profile *);
79 
80 int (*altq_input)(struct mbuf *, int) = NULL;
81 static int tbr_timer = 0;	/* token bucket regulator timer */
82 static struct callout tbr_callout;
83 
84 int pfaltq_running;	/* keep track of running state */
85 
86 MALLOC_DEFINE(M_ALTQ, "altq", "ALTQ structures");
87 
88 /*
89  * alternate queueing support routines
90  */
91 
92 /* look up the queue state by the interface name and the queueing type. */
93 void *
94 altq_lookup(const char *name, int type)
95 {
96 	struct ifnet *ifp;
97 
98 	if ((ifp = ifunit(name)) != NULL) {
99 		if (type != ALTQT_NONE && ifp->if_snd.altq_type == type)
100 			return (ifp->if_snd.altq_disc);
101 	}
102 
103 	return (NULL);
104 }
105 
106 int
107 altq_attach(struct ifaltq *ifq, int type, void *discipline,
108 	    int (*enqueue)(struct ifaltq *, struct mbuf *, struct altq_pktattr *),
109 	    struct mbuf *(*dequeue)(struct ifaltq *, struct mbuf *, int),
110 	    int (*request)(struct ifaltq *, int, void *),
111 	    void *clfier,
112 	    void *(*classify)(struct ifaltq *, struct mbuf *,
113 			      struct altq_pktattr *))
114 {
115 	if (!ifq_is_ready(ifq))
116 		return ENXIO;
117 
118 	ifq->altq_type     = type;
119 	ifq->altq_disc     = discipline;
120 	ifq->altq_enqueue  = enqueue;
121 	ifq->altq_dequeue  = dequeue;
122 	ifq->altq_request  = request;
123 	ifq->altq_clfier   = clfier;
124 	ifq->altq_classify = classify;
125 	ifq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED);
126 	return 0;
127 }
128 
129 static int
130 altq_detach_locked(struct ifaltq *ifq)
131 {
132 	if (!ifq_is_ready(ifq))
133 		return ENXIO;
134 	if (ifq_is_enabled(ifq))
135 		return EBUSY;
136 	if (!ifq_is_attached(ifq))
137 		return (0);
138 
139 	ifq_set_classic(ifq);
140 	ifq->altq_type     = ALTQT_NONE;
141 	ifq->altq_disc     = NULL;
142 	ifq->altq_clfier   = NULL;
143 	ifq->altq_classify = NULL;
144 	ifq->altq_flags &= ALTQF_CANTCHANGE;
145 	return 0;
146 }
147 
148 int
149 altq_detach(struct ifaltq *ifq)
150 {
151 	int error;
152 
153 	ALTQ_LOCK(ifq);
154 	error = altq_detach_locked(ifq);
155 	ALTQ_UNLOCK(ifq);
156 	return error;
157 }
158 
159 static int
160 altq_enable_locked(struct ifaltq *ifq)
161 {
162 	if (!ifq_is_ready(ifq))
163 		return ENXIO;
164 	if (ifq_is_enabled(ifq))
165 		return 0;
166 
167 	ifq_purge_locked(ifq);
168 	KKASSERT(ifq->ifq_len == 0);
169 
170 	ifq->altq_flags |= ALTQF_ENABLED;
171 	if (ifq->altq_clfier != NULL)
172 		ifq->altq_flags |= ALTQF_CLASSIFY;
173 	return 0;
174 }
175 
176 int
177 altq_enable(struct ifaltq *ifq)
178 {
179 	int error;
180 
181 	ALTQ_LOCK(ifq);
182 	error = altq_enable_locked(ifq);
183 	ALTQ_UNLOCK(ifq);
184 	return error;
185 }
186 
187 static int
188 altq_disable_locked(struct ifaltq *ifq)
189 {
190 	if (!ifq_is_enabled(ifq))
191 		return 0;
192 
193 	ifq_purge_locked(ifq);
194 	KKASSERT(ifq->ifq_len == 0);
195 	ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY);
196 	return 0;
197 }
198 
199 int
200 altq_disable(struct ifaltq *ifq)
201 {
202 	int error;
203 
204 	ALTQ_LOCK(ifq);
205 	error = altq_disable_locked(ifq);
206 	ALTQ_UNLOCK(ifq);
207 	return error;
208 }
209 
210 /*
211  * internal representation of token bucket parameters
212  *	rate:	byte_per_unittime << 32
213  *		(((bits_per_sec) / 8) << 32) / machclk_freq
214  *	depth:	byte << 32
215  *
216  */
217 #define	TBR_SHIFT	32
218 #define	TBR_SCALE(x)	((int64_t)(x) << TBR_SHIFT)
219 #define	TBR_UNSCALE(x)	((x) >> TBR_SHIFT)
220 
221 struct mbuf *
222 tbr_dequeue(struct ifaltq *ifq, struct mbuf *mpolled, int op)
223 {
224 	struct tb_regulator *tbr;
225 	struct mbuf *m;
226 	int64_t interval;
227 	uint64_t now;
228 
229 	crit_enter();
230 	tbr = ifq->altq_tbr;
231 	if (op == ALTDQ_REMOVE && tbr->tbr_lastop == ALTDQ_POLL) {
232 		/* if this is a remove after poll, bypass tbr check */
233 	} else {
234 		/* update token only when it is negative */
235 		if (tbr->tbr_token <= 0) {
236 			now = read_machclk();
237 			interval = now - tbr->tbr_last;
238 			if (interval >= tbr->tbr_filluptime)
239 				tbr->tbr_token = tbr->tbr_depth;
240 			else {
241 				tbr->tbr_token += interval * tbr->tbr_rate;
242 				if (tbr->tbr_token > tbr->tbr_depth)
243 					tbr->tbr_token = tbr->tbr_depth;
244 			}
245 			tbr->tbr_last = now;
246 		}
247 		/* if token is still negative, don't allow dequeue */
248 		if (tbr->tbr_token <= 0) {
249 			crit_exit();
250 			return (NULL);
251 		}
252 	}
253 
254 	if (ifq_is_enabled(ifq)) {
255 		m = (*ifq->altq_dequeue)(ifq, mpolled, op);
256 	} else if (op == ALTDQ_POLL) {
257 		IF_POLL(ifq, m);
258 	} else {
259 		IF_DEQUEUE(ifq, m);
260 		KKASSERT(mpolled == NULL || mpolled == m);
261 	}
262 
263 	if (m != NULL && op == ALTDQ_REMOVE)
264 		tbr->tbr_token -= TBR_SCALE(m_pktlen(m));
265 	tbr->tbr_lastop = op;
266 	crit_exit();
267 	return (m);
268 }
269 
270 /*
271  * set a token bucket regulator.
272  * if the specified rate is zero, the token bucket regulator is deleted.
273  */
274 static int
275 tbr_set_locked(struct ifaltq *ifq, struct tb_profile *profile)
276 {
277 	struct tb_regulator *tbr, *otbr;
278 
279 	if (machclk_freq == 0)
280 		init_machclk();
281 	if (machclk_freq == 0) {
282 		kprintf("%s: no cpu clock available!\n", __func__);
283 		return (ENXIO);
284 	}
285 
286 	if (profile->rate == 0) {
287 		/* delete this tbr */
288 		if ((tbr = ifq->altq_tbr) == NULL)
289 			return (ENOENT);
290 		ifq->altq_tbr = NULL;
291 		kfree(tbr, M_ALTQ);
292 		return (0);
293 	}
294 
295 	tbr = kmalloc(sizeof(*tbr), M_ALTQ, M_WAITOK | M_ZERO);
296 	tbr->tbr_rate = TBR_SCALE(profile->rate / 8) / machclk_freq;
297 	tbr->tbr_depth = TBR_SCALE(profile->depth);
298 	if (tbr->tbr_rate > 0)
299 		tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate;
300 	else
301 		tbr->tbr_filluptime = 0xffffffffffffffffLL;
302 	tbr->tbr_token = tbr->tbr_depth;
303 	tbr->tbr_last = read_machclk();
304 	tbr->tbr_lastop = ALTDQ_REMOVE;
305 
306 	otbr = ifq->altq_tbr;
307 	ifq->altq_tbr = tbr;	/* set the new tbr */
308 
309 	if (otbr != NULL)
310 		kfree(otbr, M_ALTQ);
311 	else if (tbr_timer == 0) {
312 		callout_reset(&tbr_callout, 1, tbr_timeout, NULL);
313 		tbr_timer = 1;
314 	}
315 	return (0);
316 }
317 
318 int
319 tbr_set(struct ifaltq *ifq, struct tb_profile *profile)
320 {
321 	int error;
322 
323 	ALTQ_LOCK(ifq);
324 	error = tbr_set_locked(ifq, profile);
325 	ALTQ_UNLOCK(ifq);
326 	return error;
327 }
328 
329 /*
330  * tbr_timeout goes through the interface list, and kicks the drivers
331  * if necessary.
332  */
333 static void
334 tbr_timeout(void *arg)
335 {
336 	struct ifnet *ifp;
337 	int active;
338 
339 	active = 0;
340 	crit_enter();
341 	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
342 		if (ifp->if_snd.altq_tbr == NULL)
343 			continue;
344 		active++;
345 		if (!ifq_is_empty(&ifp->if_snd) && ifp->if_start != NULL) {
346 			ifnet_serialize_tx(ifp);
347 			(*ifp->if_start)(ifp);
348 			ifnet_deserialize_tx(ifp);
349 		}
350 	}
351 	crit_exit();
352 	if (active > 0)
353 		callout_reset(&tbr_callout, 1, tbr_timeout, NULL);
354 	else
355 		tbr_timer = 0;	/* don't need tbr_timer anymore */
356 }
357 
358 /*
359  * get token bucket regulator profile
360  */
361 int
362 tbr_get(struct ifaltq *ifq, struct tb_profile *profile)
363 {
364 	struct tb_regulator *tbr;
365 
366 	if ((tbr = ifq->altq_tbr) == NULL) {
367 		profile->rate = 0;
368 		profile->depth = 0;
369 	} else {
370 		profile->rate =
371 		    (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq);
372 		profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth);
373 	}
374 	return (0);
375 }
376 
377 /*
378  * attach a discipline to the interface.  if one already exists, it is
379  * overridden.
380  */
381 int
382 altq_pfattach(struct pf_altq *a)
383 {
384 	struct ifaltq *ifq;
385 	struct ifnet *ifp;
386 	int error;
387 
388 	if (a->scheduler == ALTQT_NONE)
389 		return 0;
390 
391 	if (a->altq_disc == NULL)
392 		return EINVAL;
393 
394 	ifp = ifunit(a->ifname);
395 	if (ifp == NULL)
396 		return EINVAL;
397 	ifq = &ifp->if_snd;
398 
399 	ALTQ_LOCK(ifq);
400 
401 	switch (a->scheduler) {
402 #ifdef ALTQ_CBQ
403 	case ALTQT_CBQ:
404 		error = cbq_pfattach(a, ifq);
405 		break;
406 #endif
407 #ifdef ALTQ_PRIQ
408 	case ALTQT_PRIQ:
409 		error = priq_pfattach(a, ifq);
410 		break;
411 #endif
412 #ifdef ALTQ_HFSC
413 	case ALTQT_HFSC:
414 		error = hfsc_pfattach(a, ifq);
415 		break;
416 #endif
417 #ifdef ALTQ_FAIRQ
418 	case ALTQT_FAIRQ:
419 		error = fairq_pfattach(a, ifq);
420 		break;
421 #endif
422 	default:
423 		error = ENXIO;
424 		goto back;
425 	}
426 
427 	/* if the state is running, enable altq */
428 	if (error == 0 && pfaltq_running && ifq->altq_type != ALTQT_NONE &&
429 	    !ifq_is_enabled(ifq))
430 		error = altq_enable_locked(ifq);
431 
432 	/* if altq is already enabled, reset set tokenbucket regulator */
433 	if (error == 0 && ifq_is_enabled(ifq)) {
434 		struct tb_profile tb;
435 
436 		tb.rate = a->ifbandwidth;
437 		tb.depth = a->tbrsize;
438 		error = tbr_set_locked(ifq, &tb);
439 	}
440 back:
441 	ALTQ_UNLOCK(ifq);
442 	return (error);
443 }
444 
445 /*
446  * detach a discipline from the interface.
447  * it is possible that the discipline was already overridden by another
448  * discipline.
449  */
450 int
451 altq_pfdetach(struct pf_altq *a)
452 {
453 	struct ifnet *ifp;
454 	struct ifaltq *ifq;
455 	int error = 0;
456 
457 	ifp = ifunit(a->ifname);
458 	if (ifp == NULL)
459 		return (EINVAL);
460 	ifq = &ifp->if_snd;
461 
462 	/* if this discipline is no longer referenced, just return */
463 	if (a->altq_disc == NULL)
464 		return (0);
465 
466 	ALTQ_LOCK(ifq);
467 
468 	if (a->altq_disc != ifq->altq_disc)
469 		goto back;
470 
471 	if (ifq_is_enabled(ifq))
472 		error = altq_disable_locked(ifq);
473 	if (error == 0)
474 		error = altq_detach_locked(ifq);
475 
476 back:
477 	ALTQ_UNLOCK(ifq);
478 	return (error);
479 }
480 
481 /*
482  * add a discipline or a queue
483  */
484 int
485 altq_add(struct pf_altq *a)
486 {
487 	int error = 0;
488 
489 	if (a->qname[0] != 0)
490 		return (altq_add_queue(a));
491 
492 	if (machclk_freq == 0)
493 		init_machclk();
494 	if (machclk_freq == 0)
495 		panic("altq_add: no cpu clock");
496 
497 	switch (a->scheduler) {
498 #ifdef ALTQ_CBQ
499 	case ALTQT_CBQ:
500 		error = cbq_add_altq(a);
501 		break;
502 #endif
503 #ifdef ALTQ_PRIQ
504 	case ALTQT_PRIQ:
505 		error = priq_add_altq(a);
506 		break;
507 #endif
508 #ifdef ALTQ_HFSC
509 	case ALTQT_HFSC:
510 		error = hfsc_add_altq(a);
511 		break;
512 #endif
513 #ifdef ALTQ_FAIRQ
514 	case ALTQT_FAIRQ:
515 		error = fairq_add_altq(a);
516 		break;
517 #endif
518 	default:
519 		error = ENXIO;
520 	}
521 
522 	return (error);
523 }
524 
525 /*
526  * remove a discipline or a queue
527  */
528 int
529 altq_remove(struct pf_altq *a)
530 {
531 	int error = 0;
532 
533 	if (a->qname[0] != 0)
534 		return (altq_remove_queue(a));
535 
536 	switch (a->scheduler) {
537 #ifdef ALTQ_CBQ
538 	case ALTQT_CBQ:
539 		error = cbq_remove_altq(a);
540 		break;
541 #endif
542 #ifdef ALTQ_PRIQ
543 	case ALTQT_PRIQ:
544 		error = priq_remove_altq(a);
545 		break;
546 #endif
547 #ifdef ALTQ_HFSC
548 	case ALTQT_HFSC:
549 		error = hfsc_remove_altq(a);
550 		break;
551 #endif
552 #ifdef ALTQ_FAIRQ
553 	case ALTQT_FAIRQ:
554 		error = fairq_remove_altq(a);
555 		break;
556 #endif
557 	default:
558 		error = ENXIO;
559 	}
560 
561 	return (error);
562 }
563 
564 /*
565  * add a queue to the discipline
566  */
567 int
568 altq_add_queue(struct pf_altq *a)
569 {
570 	int error = 0;
571 
572 	switch (a->scheduler) {
573 #ifdef ALTQ_CBQ
574 	case ALTQT_CBQ:
575 		error = cbq_add_queue(a);
576 		break;
577 #endif
578 #ifdef ALTQ_PRIQ
579 	case ALTQT_PRIQ:
580 		error = priq_add_queue(a);
581 		break;
582 #endif
583 #ifdef ALTQ_HFSC
584 	case ALTQT_HFSC:
585 		error = hfsc_add_queue(a);
586 		break;
587 #endif
588 #ifdef ALTQ_FAIRQ
589 	case ALTQT_FAIRQ:
590 		error = fairq_add_queue(a);
591 		break;
592 #endif
593 	default:
594 		error = ENXIO;
595 	}
596 
597 	return (error);
598 }
599 
600 /*
601  * remove a queue from the discipline
602  */
603 int
604 altq_remove_queue(struct pf_altq *a)
605 {
606 	int error = 0;
607 
608 	switch (a->scheduler) {
609 #ifdef ALTQ_CBQ
610 	case ALTQT_CBQ:
611 		error = cbq_remove_queue(a);
612 		break;
613 #endif
614 #ifdef ALTQ_PRIQ
615 	case ALTQT_PRIQ:
616 		error = priq_remove_queue(a);
617 		break;
618 #endif
619 #ifdef ALTQ_HFSC
620 	case ALTQT_HFSC:
621 		error = hfsc_remove_queue(a);
622 		break;
623 #endif
624 #ifdef ALTQ_FAIRQ
625 	case ALTQT_FAIRQ:
626 		error = fairq_remove_queue(a);
627 		break;
628 #endif
629 	default:
630 		error = ENXIO;
631 	}
632 
633 	return (error);
634 }
635 
636 /*
637  * get queue statistics
638  */
639 int
640 altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
641 {
642 	int error = 0;
643 
644 	switch (a->scheduler) {
645 #ifdef ALTQ_CBQ
646 	case ALTQT_CBQ:
647 		error = cbq_getqstats(a, ubuf, nbytes);
648 		break;
649 #endif
650 #ifdef ALTQ_PRIQ
651 	case ALTQT_PRIQ:
652 		error = priq_getqstats(a, ubuf, nbytes);
653 		break;
654 #endif
655 #ifdef ALTQ_HFSC
656 	case ALTQT_HFSC:
657 		error = hfsc_getqstats(a, ubuf, nbytes);
658 		break;
659 #endif
660 #ifdef ALTQ_FAIRQ
661 	case ALTQT_FAIRQ:
662 		error = fairq_getqstats(a, ubuf, nbytes);
663 		break;
664 #endif
665 	default:
666 		error = ENXIO;
667 	}
668 
669 	return (error);
670 }
671 
672 /*
673  * read and write diffserv field in IPv4 or IPv6 header
674  */
675 uint8_t
676 read_dsfield(struct mbuf *m, struct altq_pktattr *pktattr)
677 {
678 	struct mbuf *m0;
679 	uint8_t ds_field = 0;
680 
681 	if (pktattr == NULL ||
682 	    (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
683 		return ((uint8_t)0);
684 
685 	/* verify that pattr_hdr is within the mbuf data */
686 	for (m0 = m; m0 != NULL; m0 = m0->m_next) {
687 		if ((pktattr->pattr_hdr >= m0->m_data) &&
688 		    (pktattr->pattr_hdr < m0->m_data + m0->m_len))
689 			break;
690 	}
691 	if (m0 == NULL) {
692 		/* ick, pattr_hdr is stale */
693 		pktattr->pattr_af = AF_UNSPEC;
694 #ifdef ALTQ_DEBUG
695 		kprintf("read_dsfield: can't locate header!\n");
696 #endif
697 		return ((uint8_t)0);
698 	}
699 
700 	if (pktattr->pattr_af == AF_INET) {
701 		struct ip *ip = (struct ip *)pktattr->pattr_hdr;
702 
703 		if (ip->ip_v != 4)
704 			return ((uint8_t)0);	/* version mismatch! */
705 		ds_field = ip->ip_tos;
706 	}
707 #ifdef INET6
708 	else if (pktattr->pattr_af == AF_INET6) {
709 		struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
710 		uint32_t flowlabel;
711 
712 		flowlabel = ntohl(ip6->ip6_flow);
713 		if ((flowlabel >> 28) != 6)
714 			return ((uint8_t)0);	/* version mismatch! */
715 		ds_field = (flowlabel >> 20) & 0xff;
716 	}
717 #endif
718 	return (ds_field);
719 }
720 
721 void
722 write_dsfield(struct mbuf *m, struct altq_pktattr *pktattr, uint8_t dsfield)
723 {
724 	struct mbuf *m0;
725 
726 	if (pktattr == NULL ||
727 	    (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
728 		return;
729 
730 	/* verify that pattr_hdr is within the mbuf data */
731 	for (m0 = m; m0 != NULL; m0 = m0->m_next) {
732 		if ((pktattr->pattr_hdr >= m0->m_data) &&
733 		    (pktattr->pattr_hdr < m0->m_data + m0->m_len))
734 			break;
735 	}
736 	if (m0 == NULL) {
737 		/* ick, pattr_hdr is stale */
738 		pktattr->pattr_af = AF_UNSPEC;
739 #ifdef ALTQ_DEBUG
740 		kprintf("write_dsfield: can't locate header!\n");
741 #endif
742 		return;
743 	}
744 
745 	if (pktattr->pattr_af == AF_INET) {
746 		struct ip *ip = (struct ip *)pktattr->pattr_hdr;
747 		uint8_t old;
748 		int32_t sum;
749 
750 		if (ip->ip_v != 4)
751 			return;		/* version mismatch! */
752 		old = ip->ip_tos;
753 		dsfield |= old & 3;	/* leave CU bits */
754 		if (old == dsfield)
755 			return;
756 		ip->ip_tos = dsfield;
757 		/*
758 		 * update checksum (from RFC1624)
759 		 *	   HC' = ~(~HC + ~m + m')
760 		 */
761 		sum = ~ntohs(ip->ip_sum) & 0xffff;
762 		sum += 0xff00 + (~old & 0xff) + dsfield;
763 		sum = (sum >> 16) + (sum & 0xffff);
764 		sum += (sum >> 16);  /* add carry */
765 
766 		ip->ip_sum = htons(~sum & 0xffff);
767 	}
768 #ifdef INET6
769 	else if (pktattr->pattr_af == AF_INET6) {
770 		struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
771 		uint32_t flowlabel;
772 
773 		flowlabel = ntohl(ip6->ip6_flow);
774 		if ((flowlabel >> 28) != 6)
775 			return;		/* version mismatch! */
776 		flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20);
777 		ip6->ip6_flow = htonl(flowlabel);
778 	}
779 #endif
780 }
781 
782 /*
783  * high resolution clock support taking advantage of a machine dependent
784  * high resolution time counter (e.g., timestamp counter of intel pentium).
785  * we assume
786  *  - 64-bit-long monotonically-increasing counter
787  *  - frequency range is 100M-4GHz (CPU speed)
788  */
789 /* if pcc is not available or disabled, emulate 256MHz using microtime() */
790 #define	MACHCLK_SHIFT	8
791 
792 int machclk_usepcc;
793 uint64_t machclk_freq = 0;
794 uint32_t machclk_per_tick = 0;
795 
796 void
797 init_machclk(void)
798 {
799 	callout_init(&tbr_callout);
800 
801 	machclk_usepcc = 1;
802 
803 #if !defined(__i386__) || defined(ALTQ_NOPCC)
804 	machclk_usepcc = 0;
805 #elif defined(__DragonFly__) && defined(SMP)
806 	machclk_usepcc = 0;
807 #elif defined(__i386__)
808 	/* check if TSC is available */
809 	if (machclk_usepcc == 1 && (cpu_feature & CPUID_TSC) == 0)
810 		machclk_usepcc = 0;
811 #endif
812 
813 	if (machclk_usepcc == 0) {
814 		/* emulate 256MHz using microtime() */
815 		machclk_freq = 1000000LLU << MACHCLK_SHIFT;
816 		machclk_per_tick = machclk_freq / hz;
817 #ifdef ALTQ_DEBUG
818 		kprintf("altq: emulate %juHz cpu clock\n", (uintmax_t)machclk_freq);
819 #endif
820 		return;
821 	}
822 
823 	/*
824 	 * if the clock frequency (of Pentium TSC or Alpha PCC) is
825 	 * accessible, just use it.
826 	 */
827 #ifdef _RDTSC_SUPPORTED_
828 	if (cpu_feature & CPUID_TSC)
829 		machclk_freq = (uint64_t)tsc_frequency;
830 #endif
831 
832 	/*
833 	 * if we don't know the clock frequency, measure it.
834 	 */
835 	if (machclk_freq == 0) {
836 		static int	wait;
837 		struct timeval	tv_start, tv_end;
838 		uint64_t	start, end, diff;
839 		int		timo;
840 
841 		microtime(&tv_start);
842 		start = read_machclk();
843 		timo = hz;	/* 1 sec */
844 		tsleep(&wait, PCATCH, "init_machclk", timo);
845 		microtime(&tv_end);
846 		end = read_machclk();
847 		diff = (uint64_t)(tv_end.tv_sec - tv_start.tv_sec) * 1000000
848 		    + tv_end.tv_usec - tv_start.tv_usec;
849 		if (diff != 0)
850 			machclk_freq = (end - start) * 1000000 / diff;
851 	}
852 
853 	machclk_per_tick = machclk_freq / hz;
854 
855 #ifdef ALTQ_DEBUG
856 	kprintf("altq: CPU clock: %juHz\n", (uintmax_t)machclk_freq);
857 #endif
858 }
859 
860 uint64_t
861 read_machclk(void)
862 {
863 	uint64_t val;
864 
865 	if (machclk_usepcc) {
866 #ifdef _RDTSC_SUPPORTED_
867 		val = rdtsc();
868 #else
869 		panic("read_machclk");
870 #endif
871 	} else {
872 		struct timeval tv;
873 
874 		microtime(&tv);
875 		val = (((uint64_t)(tv.tv_sec - boottime.tv_sec) * 1000000
876 		    + tv.tv_usec) << MACHCLK_SHIFT);
877 	}
878 	return (val);
879 }
880 
881