📄 sch_cbq.c
字号:
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 + -