Beispiel #1
0
int
cbq_add_altq(struct pf_altq *a)
{
	cbq_state_t	*cbqp;
	struct ifnet	*ifp;

	if ((ifp = ifunit(a->ifname)) == NULL)
		return (EINVAL);
	if (!ALTQ_IS_READY(&ifp->if_snd))
		return (ENODEV);

	/* allocate and initialize cbq_state_t */
	cbqp = malloc(sizeof(cbq_state_t), M_DEVBUF, M_WAITOK|M_ZERO);
	if (cbqp == NULL)
		return (ENOMEM);
	(void)memset(cbqp, 0, sizeof(cbq_state_t));
	CALLOUT_INIT(&cbqp->cbq_callout);
	cbqp->cbq_qlen = 0;
	cbqp->ifnp.ifq_ = &ifp->if_snd;	    /* keep the ifq */

	/* keep the state in pf_altq */
	a->altq_disc = cbqp;

	return (0);
}
Beispiel #2
0
static int
cbq_ifattach(struct cbq_interface *ifacep)
{
	int		error = 0;
	char		*ifacename;
	cbq_state_t	*new_cbqp;
	struct ifnet 	*ifp;

	ifacename = ifacep->cbq_ifacename;
	if ((ifp = ifunit(ifacename)) == NULL)
		return (ENXIO);
	if (!ALTQ_IS_READY(&ifp->if_snd))
		return (ENXIO);

	/* allocate and initialize cbq_state_t */
	new_cbqp = malloc(sizeof(cbq_state_t), M_DEVBUF, M_WAITOK|M_ZERO);
	if (new_cbqp == NULL)
		return (ENOMEM);
 	CALLOUT_INIT(&new_cbqp->cbq_callout);

	new_cbqp->cbq_qlen = 0;
	new_cbqp->ifnp.ifq_ = &ifp->if_snd;	    /* keep the ifq */

	/*
	 * set CBQ to this ifnet structure.
	 */
	error = altq_attach(&ifp->if_snd, ALTQT_CBQ, new_cbqp,
			    cbq_enqueue, cbq_dequeue, cbq_request,
			    &new_cbqp->cbq_classifier, acc_classify);
	if (error) {
		free(new_cbqp, M_DEVBUF);
		return (error);
	}

	/* prepend to the list of cbq_state_t's. */
	new_cbqp->cbq_next = cbq_list;
	cbq_list = new_cbqp;

	return (0);
}
Beispiel #3
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;
	int		 s;

	if (pri >= RM_MAXPRIO)
		return (NULL);
#ifndef ALTQ_RED
	if (flags & RMCF_RED) {
#ifdef ALTQ_DEBUG
		printf("rmc_newclass: RED not configured for CBQ!\n");
#endif
		return (NULL);
	}
#endif
#ifndef ALTQ_RIO
	if (flags & RMCF_RIO) {
#ifdef ALTQ_DEBUG
		printf("rmc_newclass: RIO not configured for CBQ!\n");
#endif
		return (NULL);
	}
#endif

	cl = malloc(sizeof(struct rm_class), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (cl == NULL)
		return (NULL);
	CALLOUT_INIT(&cl->callout_);
	cl->q_ = malloc(sizeof(class_queue_t), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (cl->q_ == NULL) {
		free(cl, M_DEVBUF);
		return (NULL);
	}

	/*
	 * 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;
		if (flags & RMCF_FLOWVALVE)
			red_flags |= REDF_FLOWVALVE;
#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
	 */
	s = splnet();
	IFQ_LOCK(ifd->ifq_);
	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);
	}
	IFQ_UNLOCK(ifd->ifq_);
	splx(s);
	return (cl);
}