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.2 2005/04/04 17:08:16 joerg 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 48 #include <net/if.h> 49 #include <net/if_dl.h> 50 #include <net/if_types.h> 51 #include <net/ifq_var.h> 52 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/ip.h> 56 #ifdef INET6 57 #include <netinet/ip6.h> 58 #endif 59 #include <netinet/tcp.h> 60 #include <netinet/udp.h> 61 62 #include <net/pf/pfvar.h> 63 #include <net/altq/altq.h> 64 65 /* machine dependent clock related includes */ 66 #if defined(__i386__) 67 #include <machine/clock.h> /* for tsc_freq */ 68 #include <machine/md_var.h> /* for cpu_feature */ 69 #include <machine/specialreg.h> /* for CPUID_TSC */ 70 #endif /* __i386__ */ 71 72 /* 73 * internal function prototypes 74 */ 75 static void tbr_timeout(void *); 76 int (*altq_input)(struct mbuf *, int) = NULL; 77 static int tbr_timer = 0; /* token bucket regulator timer */ 78 static struct callout tbr_callout; 79 80 int pfaltq_running; /* keep track of running state */ 81 82 MALLOC_DEFINE(M_ALTQ, "altq", "ALTQ structures"); 83 84 /* 85 * alternate queueing support routines 86 */ 87 88 /* look up the queue state by the interface name and the queueing type. */ 89 void * 90 altq_lookup(const char *name, int type) 91 { 92 struct ifnet *ifp; 93 94 if ((ifp = ifunit(name)) != NULL) { 95 if (type != ALTQT_NONE && ifp->if_snd.altq_type == type) 96 return (ifp->if_snd.altq_disc); 97 } 98 99 return (NULL); 100 } 101 102 int 103 altq_attach(struct ifaltq *ifq, int type, void *discipline, 104 int (*enqueue)(struct ifaltq *, struct mbuf *, struct altq_pktattr *), 105 struct mbuf *(*dequeue)(struct ifaltq *, int), 106 int (*request)(struct ifaltq *, int, void *), 107 void *clfier, 108 void *(*classify)(struct ifaltq *, struct mbuf *, 109 struct altq_pktattr *)) 110 { 111 if (!ifq_is_ready(ifq)) 112 return ENXIO; 113 114 ifq->altq_type = type; 115 ifq->altq_disc = discipline; 116 ifq->altq_enqueue = enqueue; 117 ifq->altq_dequeue = dequeue; 118 ifq->altq_request = request; 119 ifq->altq_clfier = clfier; 120 ifq->altq_classify = classify; 121 ifq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED); 122 return 0; 123 } 124 125 int 126 altq_detach(struct ifaltq *ifq) 127 { 128 if (!ifq_is_ready(ifq)) 129 return ENXIO; 130 if (ifq_is_enabled(ifq)) 131 return EBUSY; 132 if (!ifq_is_attached(ifq)) 133 return (0); 134 135 ifq_set_classic(ifq); 136 ifq->altq_type = ALTQT_NONE; 137 ifq->altq_disc = NULL; 138 ifq->altq_clfier = NULL; 139 ifq->altq_classify = NULL; 140 ifq->altq_flags &= ALTQF_CANTCHANGE; 141 return 0; 142 } 143 144 int 145 altq_enable(struct ifaltq *ifq) 146 { 147 int s; 148 149 if (!ifq_is_ready(ifq)) 150 return ENXIO; 151 if (ifq_is_enabled(ifq)) 152 return 0; 153 154 s = splimp(); 155 ifq_purge(ifq); 156 KKASSERT(ifq->ifq_len == 0); 157 ifq->altq_flags |= ALTQF_ENABLED; 158 if (ifq->altq_clfier != NULL) 159 ifq->altq_flags |= ALTQF_CLASSIFY; 160 splx(s); 161 162 return 0; 163 } 164 165 int 166 altq_disable(struct ifaltq *ifq) 167 { 168 int s; 169 170 if (!ifq_is_enabled(ifq)) 171 return 0; 172 173 s = splimp(); 174 ifq_purge(ifq); 175 KKASSERT(ifq->ifq_len == 0); 176 ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY); 177 splx(s); 178 return 0; 179 } 180 181 /* 182 * internal representation of token bucket parameters 183 * rate: byte_per_unittime << 32 184 * (((bits_per_sec) / 8) << 32) / machclk_freq 185 * depth: byte << 32 186 * 187 */ 188 #define TBR_SHIFT 32 189 #define TBR_SCALE(x) ((int64_t)(x) << TBR_SHIFT) 190 #define TBR_UNSCALE(x) ((x) >> TBR_SHIFT) 191 192 struct mbuf * 193 tbr_dequeue(struct ifaltq *ifq, int op) 194 { 195 struct tb_regulator *tbr; 196 struct mbuf *m; 197 int64_t interval; 198 uint64_t now; 199 200 tbr = ifq->altq_tbr; 201 if (op == ALTDQ_REMOVE && tbr->tbr_lastop == ALTDQ_POLL) { 202 /* if this is a remove after poll, bypass tbr check */ 203 } else { 204 /* update token only when it is negative */ 205 if (tbr->tbr_token <= 0) { 206 now = read_machclk(); 207 interval = now - tbr->tbr_last; 208 if (interval >= tbr->tbr_filluptime) 209 tbr->tbr_token = tbr->tbr_depth; 210 else { 211 tbr->tbr_token += interval * tbr->tbr_rate; 212 if (tbr->tbr_token > tbr->tbr_depth) 213 tbr->tbr_token = tbr->tbr_depth; 214 } 215 tbr->tbr_last = now; 216 } 217 /* if token is still negative, don't allow dequeue */ 218 if (tbr->tbr_token <= 0) 219 return (NULL); 220 } 221 222 if (ifq_is_enabled(ifq)) 223 m = (*ifq->altq_dequeue)(ifq, op); 224 else if (op == ALTDQ_POLL) 225 IF_POLL(ifq, m); 226 else 227 IF_DEQUEUE(ifq, m); 228 229 if (m != NULL && op == ALTDQ_REMOVE) 230 tbr->tbr_token -= TBR_SCALE(m_pktlen(m)); 231 tbr->tbr_lastop = op; 232 return (m); 233 } 234 235 /* 236 * set a token bucket regulator. 237 * if the specified rate is zero, the token bucket regulator is deleted. 238 */ 239 int 240 tbr_set(struct ifaltq *ifq, struct tb_profile *profile) 241 { 242 struct tb_regulator *tbr, *otbr; 243 244 if (machclk_freq == 0) 245 init_machclk(); 246 if (machclk_freq == 0) { 247 printf("tbr_set: no cpu clock available!\n"); 248 return (ENXIO); 249 } 250 251 if (profile->rate == 0) { 252 /* delete this tbr */ 253 if ((tbr = ifq->altq_tbr) == NULL) 254 return (ENOENT); 255 ifq->altq_tbr = NULL; 256 free(tbr, M_ALTQ); 257 return (0); 258 } 259 260 tbr = malloc(sizeof(*tbr), M_ALTQ, M_WAITOK | M_ZERO); 261 tbr->tbr_rate = TBR_SCALE(profile->rate / 8) / machclk_freq; 262 tbr->tbr_depth = TBR_SCALE(profile->depth); 263 if (tbr->tbr_rate > 0) 264 tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate; 265 else 266 tbr->tbr_filluptime = 0xffffffffffffffffLL; 267 tbr->tbr_token = tbr->tbr_depth; 268 tbr->tbr_last = read_machclk(); 269 tbr->tbr_lastop = ALTDQ_REMOVE; 270 271 otbr = ifq->altq_tbr; 272 ifq->altq_tbr = tbr; /* set the new tbr */ 273 274 if (otbr != NULL) 275 free(otbr, M_ALTQ); 276 else if (tbr_timer == 0) { 277 callout_reset(&tbr_callout, 1, tbr_timeout, NULL); 278 tbr_timer = 1; 279 } 280 return (0); 281 } 282 283 /* 284 * tbr_timeout goes through the interface list, and kicks the drivers 285 * if necessary. 286 */ 287 static void 288 tbr_timeout(void *arg) 289 { 290 struct ifnet *ifp; 291 int active, s; 292 293 active = 0; 294 s = splimp(); 295 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { 296 if (ifp->if_snd.altq_tbr == NULL) 297 continue; 298 active++; 299 if (!ifq_is_empty(&ifp->if_snd) && ifp->if_start != NULL) 300 (*ifp->if_start)(ifp); 301 } 302 splx(s); 303 if (active > 0) 304 callout_reset(&tbr_callout, 1, tbr_timeout, NULL); 305 else 306 tbr_timer = 0; /* don't need tbr_timer anymore */ 307 } 308 309 /* 310 * get token bucket regulator profile 311 */ 312 int 313 tbr_get(struct ifaltq *ifq, struct tb_profile *profile) 314 { 315 struct tb_regulator *tbr; 316 317 if ((tbr = ifq->altq_tbr) == NULL) { 318 profile->rate = 0; 319 profile->depth = 0; 320 } else { 321 profile->rate = 322 (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq); 323 profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth); 324 } 325 return (0); 326 } 327 328 /* 329 * attach a discipline to the interface. if one already exists, it is 330 * overridden. 331 */ 332 int 333 altq_pfattach(struct pf_altq *a) 334 { 335 struct ifnet *ifp; 336 struct tb_profile tb; 337 int s, error = 0; 338 339 switch (a->scheduler) { 340 case ALTQT_NONE: 341 break; 342 #ifdef ALTQ_CBQ 343 case ALTQT_CBQ: 344 error = cbq_pfattach(a); 345 break; 346 #endif 347 #ifdef ALTQ_PRIQ 348 case ALTQT_PRIQ: 349 error = priq_pfattach(a); 350 break; 351 #endif 352 #ifdef ALTQ_HFSC 353 case ALTQT_HFSC: 354 error = hfsc_pfattach(a); 355 break; 356 #endif 357 default: 358 error = ENXIO; 359 } 360 361 ifp = ifunit(a->ifname); 362 363 /* if the state is running, enable altq */ 364 if (error == 0 && pfaltq_running && 365 ifp != NULL && ifp->if_snd.altq_type != ALTQT_NONE && 366 !ifq_is_enabled(&ifp->if_snd)) 367 error = altq_enable(&ifp->if_snd); 368 369 /* if altq is already enabled, reset set tokenbucket regulator */ 370 if (error == 0 && ifp != NULL && ifq_is_enabled(&ifp->if_snd)) { 371 tb.rate = a->ifbandwidth; 372 tb.depth = a->tbrsize; 373 s = splimp(); 374 error = tbr_set(&ifp->if_snd, &tb); 375 splx(s); 376 } 377 378 return (error); 379 } 380 381 /* 382 * detach a discipline from the interface. 383 * it is possible that the discipline was already overridden by another 384 * discipline. 385 */ 386 int 387 altq_pfdetach(struct pf_altq *a) 388 { 389 struct ifnet *ifp; 390 int s, error = 0; 391 392 if ((ifp = ifunit(a->ifname)) == NULL) 393 return (EINVAL); 394 395 /* if this discipline is no longer referenced, just return */ 396 if (a->altq_disc == NULL || a->altq_disc != ifp->if_snd.altq_disc) 397 return (0); 398 399 s = splimp(); 400 if (ifq_is_enabled(&ifp->if_snd)) 401 error = altq_disable(&ifp->if_snd); 402 if (error == 0) 403 error = altq_detach(&ifp->if_snd); 404 splx(s); 405 406 return (error); 407 } 408 409 /* 410 * add a discipline or a queue 411 */ 412 int 413 altq_add(struct pf_altq *a) 414 { 415 int error = 0; 416 417 if (a->qname[0] != 0) 418 return (altq_add_queue(a)); 419 420 if (machclk_freq == 0) 421 init_machclk(); 422 if (machclk_freq == 0) 423 panic("altq_add: no cpu clock"); 424 425 switch (a->scheduler) { 426 #ifdef ALTQ_CBQ 427 case ALTQT_CBQ: 428 error = cbq_add_altq(a); 429 break; 430 #endif 431 #ifdef ALTQ_PRIQ 432 case ALTQT_PRIQ: 433 error = priq_add_altq(a); 434 break; 435 #endif 436 #ifdef ALTQ_HFSC 437 case ALTQT_HFSC: 438 error = hfsc_add_altq(a); 439 break; 440 #endif 441 default: 442 error = ENXIO; 443 } 444 445 return (error); 446 } 447 448 /* 449 * remove a discipline or a queue 450 */ 451 int 452 altq_remove(struct pf_altq *a) 453 { 454 int error = 0; 455 456 if (a->qname[0] != 0) 457 return (altq_remove_queue(a)); 458 459 switch (a->scheduler) { 460 #ifdef ALTQ_CBQ 461 case ALTQT_CBQ: 462 error = cbq_remove_altq(a); 463 break; 464 #endif 465 #ifdef ALTQ_PRIQ 466 case ALTQT_PRIQ: 467 error = priq_remove_altq(a); 468 break; 469 #endif 470 #ifdef ALTQ_HFSC 471 case ALTQT_HFSC: 472 error = hfsc_remove_altq(a); 473 break; 474 #endif 475 default: 476 error = ENXIO; 477 } 478 479 return (error); 480 } 481 482 /* 483 * add a queue to the discipline 484 */ 485 int 486 altq_add_queue(struct pf_altq *a) 487 { 488 int error = 0; 489 490 switch (a->scheduler) { 491 #ifdef ALTQ_CBQ 492 case ALTQT_CBQ: 493 error = cbq_add_queue(a); 494 break; 495 #endif 496 #ifdef ALTQ_PRIQ 497 case ALTQT_PRIQ: 498 error = priq_add_queue(a); 499 break; 500 #endif 501 #ifdef ALTQ_HFSC 502 case ALTQT_HFSC: 503 error = hfsc_add_queue(a); 504 break; 505 #endif 506 default: 507 error = ENXIO; 508 } 509 510 return (error); 511 } 512 513 /* 514 * remove a queue from the discipline 515 */ 516 int 517 altq_remove_queue(struct pf_altq *a) 518 { 519 int error = 0; 520 521 switch (a->scheduler) { 522 #ifdef ALTQ_CBQ 523 case ALTQT_CBQ: 524 error = cbq_remove_queue(a); 525 break; 526 #endif 527 #ifdef ALTQ_PRIQ 528 case ALTQT_PRIQ: 529 error = priq_remove_queue(a); 530 break; 531 #endif 532 #ifdef ALTQ_HFSC 533 case ALTQT_HFSC: 534 error = hfsc_remove_queue(a); 535 break; 536 #endif 537 default: 538 error = ENXIO; 539 } 540 541 return (error); 542 } 543 544 /* 545 * get queue statistics 546 */ 547 int 548 altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) 549 { 550 int error = 0; 551 552 switch (a->scheduler) { 553 #ifdef ALTQ_CBQ 554 case ALTQT_CBQ: 555 error = cbq_getqstats(a, ubuf, nbytes); 556 break; 557 #endif 558 #ifdef ALTQ_PRIQ 559 case ALTQT_PRIQ: 560 error = priq_getqstats(a, ubuf, nbytes); 561 break; 562 #endif 563 #ifdef ALTQ_HFSC 564 case ALTQT_HFSC: 565 error = hfsc_getqstats(a, ubuf, nbytes); 566 break; 567 #endif 568 default: 569 error = ENXIO; 570 } 571 572 return (error); 573 } 574 575 /* 576 * read and write diffserv field in IPv4 or IPv6 header 577 */ 578 uint8_t 579 read_dsfield(struct mbuf *m, struct altq_pktattr *pktattr) 580 { 581 struct mbuf *m0; 582 uint8_t ds_field = 0; 583 584 if (pktattr == NULL || 585 (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6)) 586 return ((uint8_t)0); 587 588 /* verify that pattr_hdr is within the mbuf data */ 589 for (m0 = m; m0 != NULL; m0 = m0->m_next) { 590 if ((pktattr->pattr_hdr >= m0->m_data) && 591 (pktattr->pattr_hdr < m0->m_data + m0->m_len)) 592 break; 593 } 594 if (m0 == NULL) { 595 /* ick, pattr_hdr is stale */ 596 pktattr->pattr_af = AF_UNSPEC; 597 #ifdef ALTQ_DEBUG 598 printf("read_dsfield: can't locate header!\n"); 599 #endif 600 return ((uint8_t)0); 601 } 602 603 if (pktattr->pattr_af == AF_INET) { 604 struct ip *ip = (struct ip *)pktattr->pattr_hdr; 605 606 if (ip->ip_v != 4) 607 return ((uint8_t)0); /* version mismatch! */ 608 ds_field = ip->ip_tos; 609 } 610 #ifdef INET6 611 else if (pktattr->pattr_af == AF_INET6) { 612 struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr; 613 uint32_t flowlabel; 614 615 flowlabel = ntohl(ip6->ip6_flow); 616 if ((flowlabel >> 28) != 6) 617 return ((uint8_t)0); /* version mismatch! */ 618 ds_field = (flowlabel >> 20) & 0xff; 619 } 620 #endif 621 return (ds_field); 622 } 623 624 void 625 write_dsfield(struct mbuf *m, struct altq_pktattr *pktattr, uint8_t dsfield) 626 { 627 struct mbuf *m0; 628 629 if (pktattr == NULL || 630 (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6)) 631 return; 632 633 /* verify that pattr_hdr is within the mbuf data */ 634 for (m0 = m; m0 != NULL; m0 = m0->m_next) { 635 if ((pktattr->pattr_hdr >= m0->m_data) && 636 (pktattr->pattr_hdr < m0->m_data + m0->m_len)) 637 break; 638 } 639 if (m0 == NULL) { 640 /* ick, pattr_hdr is stale */ 641 pktattr->pattr_af = AF_UNSPEC; 642 #ifdef ALTQ_DEBUG 643 printf("write_dsfield: can't locate header!\n"); 644 #endif 645 return; 646 } 647 648 if (pktattr->pattr_af == AF_INET) { 649 struct ip *ip = (struct ip *)pktattr->pattr_hdr; 650 uint8_t old; 651 int32_t sum; 652 653 if (ip->ip_v != 4) 654 return; /* version mismatch! */ 655 old = ip->ip_tos; 656 dsfield |= old & 3; /* leave CU bits */ 657 if (old == dsfield) 658 return; 659 ip->ip_tos = dsfield; 660 /* 661 * update checksum (from RFC1624) 662 * HC' = ~(~HC + ~m + m') 663 */ 664 sum = ~ntohs(ip->ip_sum) & 0xffff; 665 sum += 0xff00 + (~old & 0xff) + dsfield; 666 sum = (sum >> 16) + (sum & 0xffff); 667 sum += (sum >> 16); /* add carry */ 668 669 ip->ip_sum = htons(~sum & 0xffff); 670 } 671 #ifdef INET6 672 else if (pktattr->pattr_af == AF_INET6) { 673 struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr; 674 uint32_t flowlabel; 675 676 flowlabel = ntohl(ip6->ip6_flow); 677 if ((flowlabel >> 28) != 6) 678 return; /* version mismatch! */ 679 flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20); 680 ip6->ip6_flow = htonl(flowlabel); 681 } 682 #endif 683 } 684 685 /* 686 * high resolution clock support taking advantage of a machine dependent 687 * high resolution time counter (e.g., timestamp counter of intel pentium). 688 * we assume 689 * - 64-bit-long monotonically-increasing counter 690 * - frequency range is 100M-4GHz (CPU speed) 691 */ 692 /* if pcc is not available or disabled, emulate 256MHz using microtime() */ 693 #define MACHCLK_SHIFT 8 694 695 int machclk_usepcc; 696 uint32_t machclk_freq = 0; 697 uint32_t machclk_per_tick = 0; 698 699 void 700 init_machclk(void) 701 { 702 callout_init(&tbr_callout); 703 704 machclk_usepcc = 1; 705 706 #if !defined(__i386__) || defined(ALTQ_NOPCC) 707 machclk_usepcc = 0; 708 #elif defined(__DragonFly__) && defined(SMP) 709 machclk_usepcc = 0; 710 #elif defined(__i386__) 711 /* check if TSC is available */ 712 if (machclk_usepcc == 1 && (cpu_feature & CPUID_TSC) == 0) 713 machclk_usepcc = 0; 714 #endif 715 716 if (machclk_usepcc == 0) { 717 /* emulate 256MHz using microtime() */ 718 machclk_freq = 1000000 << MACHCLK_SHIFT; 719 machclk_per_tick = machclk_freq / hz; 720 #ifdef ALTQ_DEBUG 721 printf("altq: emulate %uHz cpu clock\n", machclk_freq); 722 #endif 723 return; 724 } 725 726 /* 727 * if the clock frequency (of Pentium TSC or Alpha PCC) is 728 * accessible, just use it. 729 */ 730 #ifdef __i386__ 731 machclk_freq = tsc_freq; 732 #else 733 #error "machclk_freq interface not implemented" 734 #endif 735 736 /* 737 * if we don't know the clock frequency, measure it. 738 */ 739 if (machclk_freq == 0) { 740 static int wait; 741 struct timeval tv_start, tv_end; 742 uint64_t start, end, diff; 743 int timo; 744 745 microtime(&tv_start); 746 start = read_machclk(); 747 timo = hz; /* 1 sec */ 748 tsleep(&wait, PCATCH, "init_machclk", timo); 749 microtime(&tv_end); 750 end = read_machclk(); 751 diff = (uint64_t)(tv_end.tv_sec - tv_start.tv_sec) * 1000000 752 + tv_end.tv_usec - tv_start.tv_usec; 753 if (diff != 0) 754 machclk_freq = (u_int)((end - start) * 1000000 / diff); 755 } 756 757 machclk_per_tick = machclk_freq / hz; 758 759 #ifdef ALTQ_DEBUG 760 printf("altq: CPU clock: %uHz\n", machclk_freq); 761 #endif 762 } 763 764 uint64_t 765 read_machclk(void) 766 { 767 uint64_t val; 768 769 if (machclk_usepcc) { 770 #if defined(__i386__) 771 val = rdtsc(); 772 #else 773 panic("read_machclk"); 774 #endif 775 } else { 776 struct timeval tv; 777 778 microtime(&tv); 779 val = (((uint64_t)(tv.tv_sec - boottime.tv_sec) * 1000000 780 + tv.tv_usec) << MACHCLK_SHIFT); 781 } 782 return (val); 783 } 784