⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sch_cbq.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb){	struct cbq_sched_data *q = (struct cbq_sched_data*)sch->data;	unsigned char	 *b = skb->tail;	struct rtattr *rta;	rta = (struct rtattr*)b;	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);	if (cbq_dump_attr(skb, &q->link) < 0)		goto rtattr_failure;	rta->rta_len = skb->tail - b;	spin_lock_bh(&sch->dev->queue_lock);	q->link.xstats.avgidle = q->link.avgidle;	if (cbq_copy_xstats(skb, &q->link.xstats)) {		spin_unlock_bh(&sch->dev->queue_lock);		goto rtattr_failure;	}	spin_unlock_bh(&sch->dev->queue_lock);	return skb->len;rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}static intcbq_dump_class(struct Qdisc *sch, unsigned long arg,	       struct sk_buff *skb, struct tcmsg *tcm){	struct cbq_sched_data *q = (struct cbq_sched_data*)sch->data;	struct cbq_class *cl = (struct cbq_class*)arg;	unsigned char	 *b = skb->tail;	struct rtattr *rta;	if (cl->tparent)		tcm->tcm_parent = cl->tparent->classid;	else		tcm->tcm_parent = TC_H_ROOT;	tcm->tcm_handle = cl->classid;	tcm->tcm_info = cl->q->handle;	rta = (struct rtattr*)b;	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);	if (cbq_dump_attr(skb, cl) < 0)		goto rtattr_failure;	rta->rta_len = skb->tail - b;	cl->stats.qlen = cl->q->q.qlen;	if (qdisc_copy_stats(skb, &cl->stats))		goto rtattr_failure;	spin_lock_bh(&sch->dev->queue_lock);	cl->xstats.avgidle = cl->avgidle;	cl->xstats.undertime = 0;	if (!PSCHED_IS_PASTPERFECT(cl->undertime))		cl->xstats.undertime = PSCHED_TDIFF(cl->undertime, q->now);	q->link.xstats.avgidle = q->link.avgidle;	if (cbq_copy_xstats(skb, &cl->xstats)) {		spin_unlock_bh(&sch->dev->queue_lock);		goto rtattr_failure;	}	spin_unlock_bh(&sch->dev->queue_lock);	return skb->len;rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}#endifstatic int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,		     struct Qdisc **old){	struct cbq_class *cl = (struct cbq_class*)arg;	if (cl) {		if (new == NULL) {			if ((new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops)) == NULL)				return -ENOBUFS;		} else {#ifdef CONFIG_NET_CLS_POLICE			if (cl->police == TC_POLICE_RECLASSIFY)				new->reshape_fail = cbq_reshape_fail;#endif		}		sch_tree_lock(sch);		*old = cl->q;		cl->q = new;		qdisc_reset(*old);		sch_tree_unlock(sch);		return 0;	}	return -ENOENT;}static struct Qdisc *cbq_leaf(struct Qdisc *sch, unsigned long arg){	struct cbq_class *cl = (struct cbq_class*)arg;	return cl ? cl->q : NULL;}static unsigned long cbq_get(struct Qdisc *sch, u32 classid){	struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;	struct cbq_class *cl = cbq_class_lookup(q, classid);	if (cl) {		cl->refcnt++;		return (unsigned long)cl;	}	return 0;}static void cbq_destroy_filters(struct cbq_class *cl){	struct tcf_proto *tp;	while ((tp = cl->filter_list) != NULL) {		cl->filter_list = tp->next;		tp->ops->destroy(tp);	}}static void cbq_destroy_class(struct cbq_class *cl){	cbq_destroy_filters(cl);	qdisc_destroy(cl->q);	qdisc_put_rtab(cl->R_tab);#ifdef CONFIG_NET_ESTIMATOR	qdisc_kill_estimator(&cl->stats);#endif	kfree(cl);}static voidcbq_destroy(struct Qdisc* sch){	struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;	struct cbq_class *cl;	unsigned h;#ifdef CONFIG_NET_CLS_POLICE	q->rx_class = NULL;#endif	for (h = 0; h < 16; h++) {		for (cl = q->classes[h]; cl; cl = cl->next)			cbq_destroy_filters(cl);	}	for (h = 0; h < 16; h++) {		for (cl = q->classes[h]; cl; cl = cl->next)			if (cl != &q->link)				cbq_destroy_class(cl);	}	qdisc_put_rtab(q->link.R_tab);	MOD_DEC_USE_COUNT;}static void cbq_put(struct Qdisc *sch, unsigned long arg){	struct cbq_class *cl = (struct cbq_class*)arg;	if (--cl->refcnt == 0) {#ifdef CONFIG_NET_CLS_POLICE		struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;		spin_lock_bh(&sch->dev->queue_lock);		if (q->rx_class == cl)			q->rx_class = NULL;		spin_unlock_bh(&sch->dev->queue_lock);#endif		cbq_destroy_class(cl);	}}static intcbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **tca,		 unsigned long *arg){	int err;	struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;	struct cbq_class *cl = (struct cbq_class*)*arg;	struct rtattr *opt = tca[TCA_OPTIONS-1];	struct rtattr *tb[TCA_CBQ_MAX];	struct cbq_class *parent;	struct qdisc_rate_table *rtab = NULL;	if (opt==NULL ||	    rtattr_parse(tb, TCA_CBQ_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)))		return -EINVAL;	if (tb[TCA_CBQ_OVL_STRATEGY-1] &&	    RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY-1]) < sizeof(struct tc_cbq_ovl))		return -EINVAL;	if (tb[TCA_CBQ_FOPT-1] &&	    RTA_PAYLOAD(tb[TCA_CBQ_FOPT-1]) < sizeof(struct tc_cbq_fopt))		return -EINVAL;	if (tb[TCA_CBQ_RATE-1] &&	    RTA_PAYLOAD(tb[TCA_CBQ_RATE-1]) < sizeof(struct tc_ratespec))			return -EINVAL;	if (tb[TCA_CBQ_LSSOPT-1] &&	    RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT-1]) < sizeof(struct tc_cbq_lssopt))			return -EINVAL;	if (tb[TCA_CBQ_WRROPT-1] &&	    RTA_PAYLOAD(tb[TCA_CBQ_WRROPT-1]) < sizeof(struct tc_cbq_wrropt))			return -EINVAL;#ifdef CONFIG_NET_CLS_POLICE	if (tb[TCA_CBQ_POLICE-1] &&	    RTA_PAYLOAD(tb[TCA_CBQ_POLICE-1]) < sizeof(struct tc_cbq_police))			return -EINVAL;#endif	if (cl) {		/* Check parent */		if (parentid) {			if (cl->tparent && cl->tparent->classid != parentid)				return -EINVAL;			if (!cl->tparent && parentid != TC_H_ROOT)				return -EINVAL;		}		if (tb[TCA_CBQ_RATE-1]) {			rtab = qdisc_get_rtab(RTA_DATA(tb[TCA_CBQ_RATE-1]), tb[TCA_CBQ_RTAB-1]);			if (rtab == NULL)				return -EINVAL;		}		/* Change class parameters */		sch_tree_lock(sch);		if (cl->next_alive != NULL)			cbq_deactivate_class(cl);		if (rtab) {			rtab = xchg(&cl->R_tab, rtab);			qdisc_put_rtab(rtab);		}		if (tb[TCA_CBQ_LSSOPT-1])			cbq_set_lss(cl, RTA_DATA(tb[TCA_CBQ_LSSOPT-1]));		if (tb[TCA_CBQ_WRROPT-1]) {			cbq_rmprio(q, cl);			cbq_set_wrr(cl, RTA_DATA(tb[TCA_CBQ_WRROPT-1]));		}		if (tb[TCA_CBQ_OVL_STRATEGY-1])			cbq_set_overlimit(cl, RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY-1]));#ifdef CONFIG_NET_CLS_POLICE		if (tb[TCA_CBQ_POLICE-1])			cbq_set_police(cl, RTA_DATA(tb[TCA_CBQ_POLICE-1]));#endif		if (tb[TCA_CBQ_FOPT-1])			cbq_set_fopt(cl, RTA_DATA(tb[TCA_CBQ_FOPT-1]));		if (cl->q->q.qlen)			cbq_activate_class(cl);		sch_tree_unlock(sch);#ifdef CONFIG_NET_ESTIMATOR		if (tca[TCA_RATE-1]) {			qdisc_kill_estimator(&cl->stats);			qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]);		}#endif		return 0;	}	if (parentid == TC_H_ROOT)		return -EINVAL;	if (tb[TCA_CBQ_WRROPT-1] == NULL || tb[TCA_CBQ_RATE-1] == NULL ||	    tb[TCA_CBQ_LSSOPT-1] == NULL)		return -EINVAL;	rtab = qdisc_get_rtab(RTA_DATA(tb[TCA_CBQ_RATE-1]), tb[TCA_CBQ_RTAB-1]);	if (rtab == NULL)		return -EINVAL;	if (classid) {		err = -EINVAL;		if (TC_H_MAJ(classid^sch->handle) || cbq_class_lookup(q, classid))			goto failure;	} else {		int i;		classid = TC_H_MAKE(sch->handle,0x8000);		for (i=0; i<0x8000; i++) {			if (++q->hgenerator >= 0x8000)				q->hgenerator = 1;			if (cbq_class_lookup(q, classid|q->hgenerator) == NULL)				break;		}		err = -ENOSR;		if (i >= 0x8000)			goto failure;		classid = classid|q->hgenerator;	}	parent = &q->link;	if (parentid) {		parent = cbq_class_lookup(q, parentid);		err = -EINVAL;		if (parent == NULL)			goto failure;	}	err = -ENOBUFS;	cl = kmalloc(sizeof(*cl), GFP_KERNEL);	if (cl == NULL)		goto failure;	memset(cl, 0, sizeof(*cl));	cl->R_tab = rtab;	rtab = NULL;	cl->refcnt = 1;	if (!(cl->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops)))		cl->q = &noop_qdisc;	cl->classid = classid;	cl->tparent = parent;	cl->qdisc = sch;	cl->allot = parent->allot;	cl->quantum = cl->allot;	cl->weight = cl->R_tab->rate.rate;	cl->stats.lock = &sch->dev->queue_lock;	sch_tree_lock(sch);	cbq_link_class(cl);	cl->borrow = cl->tparent;	if (cl->tparent != &q->link)		cl->share = cl->tparent;	cbq_adjust_levels(parent);	cl->minidle = -0x7FFFFFFF;	cbq_set_lss(cl, RTA_DATA(tb[TCA_CBQ_LSSOPT-1]));	cbq_set_wrr(cl, RTA_DATA(tb[TCA_CBQ_WRROPT-1]));	if (cl->ewma_log==0)		cl->ewma_log = q->link.ewma_log;	if (cl->maxidle==0)		cl->maxidle = q->link.maxidle;	if (cl->avpkt==0)		cl->avpkt = q->link.avpkt;	cl->overlimit = cbq_ovl_classic;	if (tb[TCA_CBQ_OVL_STRATEGY-1])		cbq_set_overlimit(cl, RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY-1]));#ifdef CONFIG_NET_CLS_POLICE	if (tb[TCA_CBQ_POLICE-1])		cbq_set_police(cl, RTA_DATA(tb[TCA_CBQ_POLICE-1]));#endif	if (tb[TCA_CBQ_FOPT-1])		cbq_set_fopt(cl, RTA_DATA(tb[TCA_CBQ_FOPT-1]));	sch_tree_unlock(sch);#ifdef CONFIG_NET_ESTIMATOR	if (tca[TCA_RATE-1])		qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]);#endif	*arg = (unsigned long)cl;	return 0;failure:	qdisc_put_rtab(rtab);	return err;}static int cbq_delete(struct Qdisc *sch, unsigned long arg){	struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;	struct cbq_class *cl = (struct cbq_class*)arg;	if (cl->filters || cl->children || cl == &q->link)		return -EBUSY;	sch_tree_lock(sch);	if (cl->next_alive)		cbq_deactivate_class(cl);	if (q->tx_borrowed == cl)		q->tx_borrowed = q->tx_class;	if (q->tx_class == cl) {		q->tx_class = NULL;		q->tx_borrowed = NULL;	}#ifdef CONFIG_NET_CLS_POLICE	if (q->rx_class == cl)		q->rx_class = NULL;#endif	cbq_unlink_class(cl);	cbq_adjust_levels(cl->tparent);	cl->defmap = 0;	cbq_sync_defmap(cl);	cbq_rmprio(q, cl);	sch_tree_unlock(sch);	if (--cl->refcnt == 0)		cbq_destroy_class(cl);	return 0;}static struct tcf_proto **cbq_find_tcf(struct Qdisc *sch, unsigned long arg){	struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;	struct cbq_class *cl = (struct cbq_class *)arg;	if (cl == NULL)		cl = &q->link;	return &cl->filter_list;}static unsigned long cbq_bind_filter(struct Qdisc *sch, unsigned long parent,				     u32 classid){	struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;	struct cbq_class *p = (struct cbq_class*)parent;	struct cbq_class *cl = cbq_class_lookup(q, classid);	if (cl) {		if (p && p->level <= cl->level)			return 0;		cl->filters++;		return (unsigned long)cl;	}	return 0;}static void cbq_unbind_filter(struct Qdisc *sch, unsigned long arg){	struct cbq_class *cl = (struct cbq_class*)arg;	cl->filters--;}static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg){	struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data;	unsigned h;	if (arg->stop)		return;	for (h = 0; h < 16; h++) {		struct cbq_class *cl;		for (cl = q->classes[h]; cl; cl = cl->next) {			if (arg->count < arg->skip) {				arg->count++;				continue;			}			if (arg->fn(sch, (unsigned long)cl, arg) < 0) {				arg->stop = 1;				return;			}			arg->count++;		}	}}static struct Qdisc_class_ops cbq_class_ops ={	cbq_graft,	cbq_leaf,	cbq_get,	cbq_put,	cbq_change_class,	cbq_delete,	cbq_walk,	cbq_find_tcf,	cbq_bind_filter,	cbq_unbind_filter,#ifdef CONFIG_RTNETLINK	cbq_dump_class,#endif};struct Qdisc_ops cbq_qdisc_ops ={	NULL,	&cbq_class_ops,	"cbq",	sizeof(struct cbq_sched_data),	cbq_enqueue,	cbq_dequeue,	cbq_requeue,	cbq_drop,	cbq_init,	cbq_reset,	cbq_destroy,	NULL /* cbq_change */,#ifdef CONFIG_RTNETLINK	cbq_dump,#endif};#ifdef MODULEint init_module(void){	return register_qdisc(&cbq_qdisc_ops);}void cleanup_module(void) {	unregister_qdisc(&cbq_qdisc_ops);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -