static struct fairq_class * fairq_class_create(struct fairq_if *fif, int pri, u_int32_t qlimit, u_int64_t bandwidth, u_int32_t nbuckets, int flags, u_int64_t hogs_m1, u_int64_t lssc_m1, u_int64_t lssc_d, u_int64_t lssc_m2, u_int32_t qid) { #pragma unused(lssc_d, lssc_m2) struct ifnet *ifp; struct ifclassq *ifq; struct fairq_class *cl; u_int32_t i; IFCQ_LOCK_ASSERT_HELD(fif->fif_ifq); /* Sanitize flags unless internally configured */ if (fif->fif_flags & FAIRQIFF_ALTQ) flags &= FARF_USERFLAGS; #if !CLASSQ_RED if (flags & FARF_RED) { log(LOG_ERR, "%s: %s RED not available!\n", if_name(FAIRQIF_IFP(fif)), fairq_style(fif)); return (NULL); } #endif /* !CLASSQ_RED */ #if !CLASSQ_RIO if (flags & FARF_RIO) { log(LOG_ERR, "%s: %s RIO not available!\n", if_name(FAIRQIF_IFP(fif)), fairq_style(fif)); return (NULL); } #endif /* CLASSQ_RIO */ #if !CLASSQ_BLUE if (flags & FARF_BLUE) { log(LOG_ERR, "%s: %s BLUE not available!\n", if_name(FAIRQIF_IFP(fif)), fairq_style(fif)); return (NULL); } #endif /* CLASSQ_BLUE */ /* These are mutually exclusive */ if ((flags & (FARF_RED|FARF_RIO|FARF_BLUE|FARF_SFB)) && (flags & (FARF_RED|FARF_RIO|FARF_BLUE|FARF_SFB)) != FARF_RED && (flags & (FARF_RED|FARF_RIO|FARF_BLUE|FARF_SFB)) != FARF_RIO && (flags & (FARF_RED|FARF_RIO|FARF_BLUE|FARF_SFB)) != FARF_BLUE && (flags & (FARF_RED|FARF_RIO|FARF_BLUE|FARF_SFB)) != FARF_SFB) { log(LOG_ERR, "%s: %s more than one RED|RIO|BLUE|SFB\n", if_name(FAIRQIF_IFP(fif)), fairq_style(fif)); return (NULL); } if (bandwidth == 0 || (bandwidth / 8) == 0) { log(LOG_ERR, "%s: %s invalid data rate %llu\n", if_name(FAIRQIF_IFP(fif)), fairq_style(fif), bandwidth); return (NULL); } if (nbuckets == 0) nbuckets = 256; if (nbuckets > FAIRQ_MAX_BUCKETS) nbuckets = FAIRQ_MAX_BUCKETS; /* enforce power-of-2 size */ while ((nbuckets ^ (nbuckets - 1)) != ((nbuckets << 1) - 1)) ++nbuckets; ifq = fif->fif_ifq; ifp = FAIRQIF_IFP(fif); if ((cl = fif->fif_classes[pri]) != NULL) { /* modify the class instead of creating a new one */ if (cl->cl_head) fairq_purgeq(fif, cl, 0, NULL, NULL); #if CLASSQ_RIO if (cl->cl_qtype == Q_RIO) rio_destroy(cl->cl_rio); #endif /* CLASSQ_RIO */ #if CLASSQ_RED if (cl->cl_qtype == Q_RED) red_destroy(cl->cl_red); #endif /* CLASSQ_RED */ #if CLASSQ_BLUE if (cl->cl_qtype == Q_BLUE) blue_destroy(cl->cl_blue); #endif /* CLASSQ_BLUE */ if (cl->cl_qtype == Q_SFB && cl->cl_sfb != NULL) sfb_destroy(cl->cl_sfb); cl->cl_qalg.ptr = NULL; cl->cl_qtype = Q_DROPTAIL; cl->cl_qstate = QS_RUNNING; } else { cl = zalloc(fairq_cl_zone); if (cl == NULL) goto err_ret; bzero(cl, fairq_cl_size); cl->cl_nbuckets = nbuckets; cl->cl_nbucket_mask = nbuckets - 1; cl->cl_buckets = _MALLOC(sizeof (struct fairq_bucket) * cl->cl_nbuckets, M_DEVBUF, M_WAITOK|M_ZERO); if (cl->cl_buckets == NULL) goto err_buckets; cl->cl_head = NULL; } fif->fif_classes[pri] = cl; if (flags & FARF_DEFAULTCLASS) fif->fif_default = cl; if (qlimit == 0 || qlimit > IFCQ_MAXLEN(ifq)) { qlimit = IFCQ_MAXLEN(ifq); if (qlimit == 0) qlimit = DEFAULT_QLIMIT; /* use default */ } cl->cl_qlimit = qlimit; for (i = 0; i < cl->cl_nbuckets; ++i) { _qinit(&cl->cl_buckets[i].queue, Q_DROPTAIL, qlimit); } cl->cl_bandwidth = bandwidth / 8; /* cvt to bytes per second */ cl->cl_qtype = Q_DROPTAIL; cl->cl_qstate = QS_RUNNING; cl->cl_flags = flags; cl->cl_pri = pri; if (pri > fif->fif_maxpri) fif->fif_maxpri = pri; cl->cl_fif = fif; cl->cl_handle = qid; cl->cl_hogs_m1 = hogs_m1 / 8; cl->cl_lssc_m1 = lssc_m1 / 8; /* NOT YET USED */ cl->cl_bw_current = 0; if (flags & (FARF_RED|FARF_RIO|FARF_BLUE|FARF_SFB)) { #if CLASSQ_RED || CLASSQ_RIO u_int64_t ifbandwidth = ifnet_output_linkrate(ifp); int pkttime; #endif /* CLASSQ_RED || CLASSQ_RIO */ cl->cl_qflags = 0; if (flags & FARF_ECN) { if (flags & FARF_BLUE) cl->cl_qflags |= BLUEF_ECN; else if (flags & FARF_SFB) cl->cl_qflags |= SFBF_ECN; else if (flags & FARF_RED) cl->cl_qflags |= REDF_ECN; else if (flags & FARF_RIO) cl->cl_qflags |= RIOF_ECN; } if (flags & FARF_FLOWCTL) { if (flags & FARF_SFB) cl->cl_qflags |= SFBF_FLOWCTL; } if (flags & FARF_CLEARDSCP) { if (flags & FARF_RIO) cl->cl_qflags |= RIOF_CLEARDSCP; } #if CLASSQ_RED || CLASSQ_RIO /* * XXX: RED & RIO should be watching link speed and MTU * events and recompute pkttime accordingly. */ if (ifbandwidth < 8) pkttime = 1000 * 1000 * 1000; /* 1 sec */ else pkttime = (int64_t)ifp->if_mtu * 1000 * 1000 * 1000 / (ifbandwidth / 8); /* Test for exclusivity {RED,RIO,BLUE,SFB} was done above */ #if CLASSQ_RIO if (flags & FARF_RIO) { cl->cl_rio = rio_alloc(ifp, 0, NULL, cl->cl_qflags, pkttime); if (cl->cl_rio != NULL) cl->cl_qtype = Q_RIO; } #endif /* CLASSQ_RIO */ #if CLASSQ_RED if (flags & FARF_RED) { cl->cl_red = red_alloc(ifp, 0, 0, cl->cl_qlimit * 10/100, cl->cl_qlimit * 30/100, cl->cl_qflags, pkttime); if (cl->cl_red != NULL) cl->cl_qtype = Q_RED; } #endif /* CLASSQ_RED */ #endif /* CLASSQ_RED || CLASSQ_RIO */ #if CLASSQ_BLUE if (flags & FARF_BLUE) { cl->cl_blue = blue_alloc(ifp, 0, 0, cl->cl_qflags); if (cl->cl_blue != NULL) cl->cl_qtype = Q_BLUE; } #endif /* CLASSQ_BLUE */ if (flags & FARF_SFB) { if (!(cl->cl_flags & FARF_LAZY)) cl->cl_sfb = sfb_alloc(ifp, cl->cl_handle, cl->cl_qlimit, cl->cl_qflags); if (cl->cl_sfb != NULL || (cl->cl_flags & FARF_LAZY)) cl->cl_qtype = Q_SFB; } } if (pktsched_verbose) { log(LOG_DEBUG, "%s: %s created qid=%d pri=%d qlimit=%d " "flags=%b\n", if_name(ifp), fairq_style(fif), cl->cl_handle, cl->cl_pri, cl->cl_qlimit, flags, FARF_BITS); } return (cl); err_buckets: if (cl->cl_buckets != NULL) _FREE(cl->cl_buckets, M_DEVBUF); err_ret: if (cl != NULL) { if (cl->cl_qalg.ptr != NULL) { #if CLASSQ_RIO if (cl->cl_qtype == Q_RIO) rio_destroy(cl->cl_rio); #endif /* CLASSQ_RIO */ #if CLASSQ_RED if (cl->cl_qtype == Q_RED) red_destroy(cl->cl_red); #endif /* CLASSQ_RED */ #if CLASSQ_BLUE if (cl->cl_qtype == Q_BLUE) blue_destroy(cl->cl_blue); #endif /* CLASSQ_BLUE */ if (cl->cl_qtype == Q_SFB && cl->cl_sfb != NULL) sfb_destroy(cl->cl_sfb); cl->cl_qalg.ptr = NULL; cl->cl_qtype = Q_DROPTAIL; cl->cl_qstate = QS_RUNNING; } zfree(fairq_cl_zone, cl); } return (NULL); }
static struct priq_class * priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid) { struct priq_class *cl; int s; #ifndef ALTQ_RED if (flags & PRCF_RED) { #ifdef ALTQ_DEBUG printf("priq_class_create: RED not configured for PRIQ!\n"); #endif return (NULL); } #endif if ((cl = pif->pif_classes[pri]) != NULL) { /* modify the class instead of creating a new one */ s = splnet(); if (!qempty(cl->cl_q)) priq_purgeq(cl); splx(s); #ifdef ALTQ_RIO if (q_is_rio(cl->cl_q)) rio_destroy((rio_t *)cl->cl_red); #endif #ifdef ALTQ_RED if (q_is_red(cl->cl_q)) red_destroy(cl->cl_red); #endif } else { cl = malloc(sizeof(struct priq_class), M_DEVBUF, M_WAITOK|M_ZERO); if (cl == NULL) return (NULL); cl->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF, M_WAITOK|M_ZERO); if (cl->cl_q == NULL) goto err_ret; } pif->pif_classes[pri] = cl; if (flags & PRCF_DEFAULTCLASS) pif->pif_default = cl; if (qlimit == 0) qlimit = 50; /* use default */ qlimit(cl->cl_q) = qlimit; qtype(cl->cl_q) = Q_DROPTAIL; qlen(cl->cl_q) = 0; cl->cl_flags = flags; cl->cl_pri = pri; if (pri > pif->pif_maxpri) pif->pif_maxpri = pri; cl->cl_pif = pif; cl->cl_handle = qid; #ifdef ALTQ_RED if (flags & (PRCF_RED|PRCF_RIO)) { int red_flags, red_pkttime; red_flags = 0; if (flags & PRCF_ECN) red_flags |= REDF_ECN; #ifdef ALTQ_RIO if (flags & PRCF_CLEARDSCP) red_flags |= RIOF_CLEARDSCP; #endif if (pif->pif_bandwidth < 8) red_pkttime = 1000 * 1000 * 1000; /* 1 sec */ else red_pkttime = (int64_t)pif->pif_ifq->altq_ifp->if_mtu * 1000 * 1000 * 1000 / (pif->pif_bandwidth / 8); #ifdef ALTQ_RIO if (flags & PRCF_RIO) { cl->cl_red = (red_t *)rio_alloc(0, NULL, red_flags, red_pkttime); if (cl->cl_red != NULL) qtype(cl->cl_q) = Q_RIO; } else #endif if (flags & PRCF_RED) { cl->cl_red = red_alloc(0, 0, qlimit(cl->cl_q) * 10/100, qlimit(cl->cl_q) * 30/100, red_flags, red_pkttime); if (cl->cl_red != NULL) qtype(cl->cl_q) = Q_RED; } } #endif /* ALTQ_RED */ return (cl); err_ret: if (cl->cl_red != NULL) { #ifdef ALTQ_RIO if (q_is_rio(cl->cl_q)) rio_destroy((rio_t *)cl->cl_red); #endif #ifdef ALTQ_RED if (q_is_red(cl->cl_q)) red_destroy(cl->cl_red); #endif } if (cl->cl_q != NULL) free(cl->cl_q, M_DEVBUF); free(cl, M_DEVBUF); return (NULL); }
struct hfsc_class * hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc, struct service_curve *fsc, struct service_curve *usc, struct hfsc_class *parent, int qlimit, int flags, int qid) { struct hfsc_class *cl, *p; int i, s; if (hif->hif_classes >= HFSC_MAX_CLASSES) return (NULL); #ifndef ALTQ_RED if (flags & HFCF_RED) { #ifdef ALTQ_DEBUG printf("hfsc_class_create: RED not configured for HFSC!\n"); #endif return (NULL); } #endif MALLOC(cl, struct hfsc_class *, sizeof(struct hfsc_class), M_DEVBUF, M_WAITOK); if (cl == NULL) return (NULL); bzero(cl, sizeof(struct hfsc_class)); MALLOC(cl->cl_q, class_queue_t *, sizeof(class_queue_t), M_DEVBUF, M_WAITOK); if (cl->cl_q == NULL) goto err_ret; bzero(cl->cl_q, sizeof(class_queue_t)); cl->cl_actc = actlist_alloc(); if (cl->cl_actc == NULL) goto err_ret; if (qlimit == 0) qlimit = 50; /* use default */ qlimit(cl->cl_q) = qlimit; qtype(cl->cl_q) = Q_DROPTAIL; qlen(cl->cl_q) = 0; cl->cl_flags = flags; #ifdef ALTQ_RED if (flags & (HFCF_RED|HFCF_RIO)) { int red_flags, red_pkttime; u_int m2; m2 = 0; if (rsc != NULL && rsc->m2 > m2) m2 = rsc->m2; if (fsc != NULL && fsc->m2 > m2) m2 = fsc->m2; if (usc != NULL && usc->m2 > m2) m2 = usc->m2; red_flags = 0; if (flags & HFCF_ECN) red_flags |= REDF_ECN; #ifdef ALTQ_RIO if (flags & HFCF_CLEARDSCP) red_flags |= RIOF_CLEARDSCP; #endif if (m2 < 8) red_pkttime = 1000 * 1000 * 1000; /* 1 sec */ else red_pkttime = (int64_t)hif->hif_ifq->altq_ifp->if_mtu * 1000 * 1000 * 1000 / (m2 / 8); if (flags & HFCF_RED) { cl->cl_red = red_alloc(0, 0, qlimit(cl->cl_q) * 10/100, qlimit(cl->cl_q) * 30/100, red_flags, red_pkttime); if (cl->cl_red != NULL) qtype(cl->cl_q) = Q_RED; } #ifdef ALTQ_RIO else { cl->cl_red = (red_t *)rio_alloc(0, NULL, red_flags, red_pkttime); if (cl->cl_red != NULL) qtype(cl->cl_q) = Q_RIO; } #endif } #endif /* ALTQ_RED */ if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0)) { MALLOC(cl->cl_rsc, struct internal_sc *, sizeof(struct internal_sc), M_DEVBUF, M_WAITOK); if (cl->cl_rsc == NULL) goto err_ret; sc2isc(rsc, cl->cl_rsc); rtsc_init(&cl->cl_deadline, cl->cl_rsc, 0, 0); rtsc_init(&cl->cl_eligible, cl->cl_rsc, 0, 0); }
/* * rm_class_t * * rmc_newclass(...) - Create a new resource management class at priority * 'pri' on the interface given by 'ifd'. * * nsecPerByte is the data rate of the interface in nanoseconds/byte. * E.g., 800 for a 10Mb/s ethernet. If the class gets less * than 100% of the bandwidth, this number should be the * 'effective' rate for the class. Let f be the * bandwidth fraction allocated to this class, and let * nsPerByte be the data rate of the output link in * nanoseconds/byte. Then nsecPerByte is set to * nsPerByte / f. E.g., 1600 (= 800 / .5) * for a class that gets 50% of an ethernet's bandwidth. * * action the routine to call when the class is over limit. * * maxq max allowable queue size for class (in packets). * * parent parent class pointer. * * borrow class to borrow from (should be either 'parent' or null). * * maxidle max value allowed for class 'idle' time estimate (this * parameter determines how large an initial burst of packets * can be before overlimit action is invoked. * * offtime how long 'delay' action will delay when class goes over * limit (this parameter determines the steady-state burst * size when a class is running over its limit). * * Maxidle and offtime have to be computed from the following: If the * average packet size is s, the bandwidth fraction allocated to this * class is f, we want to allow b packet bursts, and the gain of the * averaging filter is g (= 1 - 2^(-RM_FILTER_GAIN)), then: * * ptime = s * nsPerByte * (1 - f) / f * maxidle = ptime * (1 - g^b) / g^b * minidle = -ptime * (1 / (f - 1)) * offtime = ptime * (1 + 1/(1 - g) * (1 - g^(b - 1)) / g^(b - 1) * * Operationally, it's convenient to specify maxidle & offtime in units * independent of the link bandwidth so the maxidle & offtime passed to * this routine are the above values multiplied by 8*f/(1000*nsPerByte). * (The constant factor is a scale factor needed to make the parameters * integers. This scaling also means that the 'unscaled' values of * maxidle*nsecPerByte/8 and offtime*nsecPerByte/8 will be in microseconds, * not nanoseconds.) Also note that the 'idle' filter computation keeps * an estimate scaled upward by 2^RM_FILTER_GAIN so the passed value of * maxidle also must be scaled upward by this value. Thus, the passed * values for maxidle and offtime can be computed as follows: * * maxidle = maxidle * 2^RM_FILTER_GAIN * 8 / (1000 * nsecPerByte) * offtime = offtime * 8 / (1000 * nsecPerByte) * * When USE_HRTIME is employed, then maxidle and offtime become: * maxidle = maxilde * (8.0 / nsecPerByte); * offtime = offtime * (8.0 / nsecPerByte); */ struct rm_class * rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte, void (*action)(rm_class_t *, rm_class_t *), int maxq, struct rm_class *parent, struct rm_class *borrow, u_int maxidle, int minidle, u_int offtime, int pktsize, int flags) { struct rm_class *cl; struct rm_class *peer; if (pri >= RM_MAXPRIO) return (NULL); #ifndef ALTQ_RED if (flags & RMCF_RED) { #ifdef ALTQ_DEBUG kprintf("rmc_newclass: RED not configured for CBQ!\n"); #endif return (NULL); } #endif #ifndef ALTQ_RIO if (flags & RMCF_RIO) { #ifdef ALTQ_DEBUG kprintf("rmc_newclass: RIO not configured for CBQ!\n"); #endif return (NULL); } #endif cl = kmalloc(sizeof(*cl), M_ALTQ, M_WAITOK | M_ZERO); callout_init(&cl->callout_); cl->q_ = kmalloc(sizeof(*cl->q_), M_ALTQ, M_WAITOK | M_ZERO); /* * Class initialization. */ cl->children_ = NULL; cl->parent_ = parent; cl->borrow_ = borrow; cl->leaf_ = 1; cl->ifdat_ = ifd; cl->pri_ = pri; cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */ cl->depth_ = 0; cl->qthresh_ = 0; cl->ns_per_byte_ = nsecPerByte; qlimit(cl->q_) = maxq; qtype(cl->q_) = Q_DROPHEAD; qlen(cl->q_) = 0; cl->flags_ = flags; #if 1 /* minidle is also scaled in ALTQ */ cl->minidle_ = (minidle * (int)nsecPerByte) / 8; if (cl->minidle_ > 0) cl->minidle_ = 0; #else cl->minidle_ = minidle; #endif cl->maxidle_ = (maxidle * nsecPerByte) / 8; if (cl->maxidle_ == 0) cl->maxidle_ = 1; #if 1 /* offtime is also scaled in ALTQ */ cl->avgidle_ = cl->maxidle_; cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN; if (cl->offtime_ == 0) cl->offtime_ = 1; #else cl->avgidle_ = 0; cl->offtime_ = (offtime * nsecPerByte) / 8; #endif cl->overlimit = action; #ifdef ALTQ_RED if (flags & (RMCF_RED|RMCF_RIO)) { int red_flags, red_pkttime; red_flags = 0; if (flags & RMCF_ECN) red_flags |= REDF_ECN; #ifdef ALTQ_RIO if (flags & RMCF_CLEARDSCP) red_flags |= RIOF_CLEARDSCP; #endif red_pkttime = nsecPerByte * pktsize / 1000; if (flags & RMCF_RED) { cl->red_ = red_alloc(0, 0, qlimit(cl->q_) * 10/100, qlimit(cl->q_) * 30/100, red_flags, red_pkttime); if (cl->red_ != NULL) qtype(cl->q_) = Q_RED; } #ifdef ALTQ_RIO else { cl->red_ = (red_t *)rio_alloc(0, NULL, red_flags, red_pkttime); if (cl->red_ != NULL) qtype(cl->q_) = Q_RIO; } #endif } #endif /* ALTQ_RED */ /* * put the class into the class tree */ crit_enter(); if ((peer = ifd->active_[pri]) != NULL) { /* find the last class at this pri */ cl->peer_ = peer; while (peer->peer_ != ifd->active_[pri]) peer = peer->peer_; peer->peer_ = cl; } else { ifd->active_[pri] = cl; cl->peer_ = cl; } if (cl->parent_) { cl->next_ = parent->children_; parent->children_ = cl; parent->leaf_ = 0; } /* * Compute the depth of this class and its ancestors in the class * hierarchy. */ rmc_depth_compute(cl); /* * If CBQ's WRR is enabled, then initialize the class WRR state. */ if (ifd->wrr_) { ifd->num_[pri]++; ifd->alloc_[pri] += cl->allotment_; rmc_wrr_set_weights(ifd); } crit_exit(); return (cl); }
static struct priq_class * priq_class_create(struct priq_if *pif, int pri, u_int32_t qlimit, int flags, u_int32_t qid) { struct ifnet *ifp; struct ifclassq *ifq; struct priq_class *cl; IFCQ_LOCK_ASSERT_HELD(pif->pif_ifq); /* Sanitize flags unless internally configured */ if (pif->pif_flags & PRIQIFF_ALTQ) flags &= PRCF_USERFLAGS; #if !CLASSQ_RED if (flags & PRCF_RED) { log(LOG_ERR, "%s: %s RED not available!\n", if_name(PRIQIF_IFP(pif)), priq_style(pif)); return (NULL); } #endif /* !CLASSQ_RED */ #if !CLASSQ_RIO if (flags & PRCF_RIO) { log(LOG_ERR, "%s: %s RIO not available!\n", if_name(PRIQIF_IFP(pif)), priq_style(pif)); return (NULL); } #endif /* CLASSQ_RIO */ #if !CLASSQ_BLUE if (flags & PRCF_BLUE) { log(LOG_ERR, "%s: %s BLUE not available!\n", if_name(PRIQIF_IFP(pif)), priq_style(pif)); return (NULL); } #endif /* CLASSQ_BLUE */ /* These are mutually exclusive */ if ((flags & (PRCF_RED|PRCF_RIO|PRCF_BLUE|PRCF_SFB)) && (flags & (PRCF_RED|PRCF_RIO|PRCF_BLUE|PRCF_SFB)) != PRCF_RED && (flags & (PRCF_RED|PRCF_RIO|PRCF_BLUE|PRCF_SFB)) != PRCF_RIO && (flags & (PRCF_RED|PRCF_RIO|PRCF_BLUE|PRCF_SFB)) != PRCF_BLUE && (flags & (PRCF_RED|PRCF_RIO|PRCF_BLUE|PRCF_SFB)) != PRCF_SFB) { log(LOG_ERR, "%s: %s more than one RED|RIO|BLUE|SFB\n", if_name(PRIQIF_IFP(pif)), priq_style(pif)); return (NULL); } ifq = pif->pif_ifq; ifp = PRIQIF_IFP(pif); if ((cl = pif->pif_classes[pri]) != NULL) { /* modify the class instead of creating a new one */ if (!qempty(&cl->cl_q)) priq_purgeq(pif, cl, 0, NULL, NULL); #if CLASSQ_RIO if (q_is_rio(&cl->cl_q)) rio_destroy(cl->cl_rio); #endif /* CLASSQ_RIO */ #if CLASSQ_RED if (q_is_red(&cl->cl_q)) red_destroy(cl->cl_red); #endif /* CLASSQ_RED */ #if CLASSQ_BLUE if (q_is_blue(&cl->cl_q)) blue_destroy(cl->cl_blue); #endif /* CLASSQ_BLUE */ if (q_is_sfb(&cl->cl_q) && cl->cl_sfb != NULL) sfb_destroy(cl->cl_sfb); cl->cl_qalg.ptr = NULL; qtype(&cl->cl_q) = Q_DROPTAIL; qstate(&cl->cl_q) = QS_RUNNING; } else { cl = zalloc(priq_cl_zone); if (cl == NULL) return (NULL); bzero(cl, priq_cl_size); } pif->pif_classes[pri] = cl; if (flags & PRCF_DEFAULTCLASS) pif->pif_default = cl; if (qlimit == 0 || qlimit > IFCQ_MAXLEN(ifq)) { qlimit = IFCQ_MAXLEN(ifq); if (qlimit == 0) qlimit = DEFAULT_QLIMIT; /* use default */ } _qinit(&cl->cl_q, Q_DROPTAIL, qlimit); cl->cl_flags = flags; cl->cl_pri = pri; if (pri > pif->pif_maxpri) pif->pif_maxpri = pri; cl->cl_pif = pif; cl->cl_handle = qid; if (flags & (PRCF_RED|PRCF_RIO|PRCF_BLUE|PRCF_SFB)) { #if CLASSQ_RED || CLASSQ_RIO u_int64_t ifbandwidth = ifnet_output_linkrate(ifp); int pkttime; #endif /* CLASSQ_RED || CLASSQ_RIO */ cl->cl_qflags = 0; if (flags & PRCF_ECN) { if (flags & PRCF_BLUE) cl->cl_qflags |= BLUEF_ECN; else if (flags & PRCF_SFB) cl->cl_qflags |= SFBF_ECN; else if (flags & PRCF_RED) cl->cl_qflags |= REDF_ECN; else if (flags & PRCF_RIO) cl->cl_qflags |= RIOF_ECN; } if (flags & PRCF_FLOWCTL) { if (flags & PRCF_SFB) cl->cl_qflags |= SFBF_FLOWCTL; } if (flags & PRCF_CLEARDSCP) { if (flags & PRCF_RIO) cl->cl_qflags |= RIOF_CLEARDSCP; } #if CLASSQ_RED || CLASSQ_RIO /* * XXX: RED & RIO should be watching link speed and MTU * events and recompute pkttime accordingly. */ if (ifbandwidth < 8) pkttime = 1000 * 1000 * 1000; /* 1 sec */ else pkttime = (int64_t)ifp->if_mtu * 1000 * 1000 * 1000 / (ifbandwidth / 8); /* Test for exclusivity {RED,RIO,BLUE,SFB} was done above */ #if CLASSQ_RED if (flags & PRCF_RED) { cl->cl_red = red_alloc(ifp, 0, 0, qlimit(&cl->cl_q) * 10/100, qlimit(&cl->cl_q) * 30/100, cl->cl_qflags, pkttime); if (cl->cl_red != NULL) qtype(&cl->cl_q) = Q_RED; } #endif /* CLASSQ_RED */ #if CLASSQ_RIO if (flags & PRCF_RIO) { cl->cl_rio = rio_alloc(ifp, 0, NULL, cl->cl_qflags, pkttime); if (cl->cl_rio != NULL) qtype(&cl->cl_q) = Q_RIO; } #endif /* CLASSQ_RIO */ #endif /* CLASSQ_RED || CLASSQ_RIO */ #if CLASSQ_BLUE if (flags & PRCF_BLUE) { cl->cl_blue = blue_alloc(ifp, 0, 0, cl->cl_qflags); if (cl->cl_blue != NULL) qtype(&cl->cl_q) = Q_BLUE; } #endif /* CLASSQ_BLUE */ if (flags & PRCF_SFB) { if (!(cl->cl_flags & PRCF_LAZY)) cl->cl_sfb = sfb_alloc(ifp, cl->cl_handle, qlimit(&cl->cl_q), cl->cl_qflags); if (cl->cl_sfb != NULL || (cl->cl_flags & PRCF_LAZY)) qtype(&cl->cl_q) = Q_SFB; } } if (pktsched_verbose) { log(LOG_DEBUG, "%s: %s created qid=%d pri=%d qlimit=%d " "flags=%b\n", if_name(ifp), priq_style(pif), cl->cl_handle, cl->cl_pri, qlimit, flags, PRCF_BITS); } return (cl); }