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

📄 sch_netem.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	init_crandom(&q->dup_cor, c->dup_corr);	return 0;}static int get_reorder(struct Qdisc *sch, const struct rtattr *attr){	struct netem_sched_data *q = qdisc_priv(sch);	const struct tc_netem_reorder *r = RTA_DATA(attr);	if (RTA_PAYLOAD(attr) != sizeof(*r))		return -EINVAL;	q->reorder = r->probability;	init_crandom(&q->reorder_cor, r->correlation);	return 0;}static int get_corrupt(struct Qdisc *sch, const struct rtattr *attr){	struct netem_sched_data *q = qdisc_priv(sch);	const struct tc_netem_corrupt *r = RTA_DATA(attr);	if (RTA_PAYLOAD(attr) != sizeof(*r))		return -EINVAL;	q->corrupt = r->probability;	init_crandom(&q->corrupt_cor, r->correlation);	return 0;}/* Parse netlink message to set options */static int netem_change(struct Qdisc *sch, struct rtattr *opt){	struct netem_sched_data *q = qdisc_priv(sch);	struct tc_netem_qopt *qopt;	int ret;	if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt))		return -EINVAL;	qopt = RTA_DATA(opt);	ret = set_fifo_limit(q->qdisc, qopt->limit);	if (ret) {		pr_debug("netem: can't set fifo limit\n");		return ret;	}	q->latency = qopt->latency;	q->jitter = qopt->jitter;	q->limit = qopt->limit;	q->gap = qopt->gap;	q->counter = 0;	q->loss = qopt->loss;	q->duplicate = qopt->duplicate;	/* for compatibility with earlier versions.	 * if gap is set, need to assume 100% probability	 */	if (q->gap)		q->reorder = ~0;	/* Handle nested options after initial queue options.	 * Should have put all options in nested format but too late now.	 */	if (RTA_PAYLOAD(opt) > sizeof(*qopt)) {		struct rtattr *tb[TCA_NETEM_MAX];		if (rtattr_parse(tb, TCA_NETEM_MAX,				 RTA_DATA(opt) + sizeof(*qopt),				 RTA_PAYLOAD(opt) - sizeof(*qopt)))			return -EINVAL;		if (tb[TCA_NETEM_CORR-1]) {			ret = get_correlation(sch, tb[TCA_NETEM_CORR-1]);			if (ret)				return ret;		}		if (tb[TCA_NETEM_DELAY_DIST-1]) {			ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST-1]);			if (ret)				return ret;		}		if (tb[TCA_NETEM_REORDER-1]) {			ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]);			if (ret)				return ret;		}		if (tb[TCA_NETEM_CORRUPT-1]) {			ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT-1]);			if (ret)				return ret;		}	}	return 0;}/* * Special case version of FIFO queue for use by netem. * It queues in order based on timestamps in skb's */struct fifo_sched_data {	u32 limit;	psched_time_t oldest;};static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch){	struct fifo_sched_data *q = qdisc_priv(sch);	struct sk_buff_head *list = &sch->q;	psched_time_t tnext = ((struct netem_skb_cb *)nskb->cb)->time_to_send;	struct sk_buff *skb;	if (likely(skb_queue_len(list) < q->limit)) {		/* Optimize for add at tail */		if (likely(skb_queue_empty(list) || tnext >= q->oldest)) {			q->oldest = tnext;			return qdisc_enqueue_tail(nskb, sch);		}		skb_queue_reverse_walk(list, skb) {			const struct netem_skb_cb *cb				= (const struct netem_skb_cb *)skb->cb;			if (tnext >= cb->time_to_send)				break;		}		__skb_queue_after(list, skb, nskb);		sch->qstats.backlog += nskb->len;		sch->bstats.bytes += nskb->len;		sch->bstats.packets++;		return NET_XMIT_SUCCESS;	}	return qdisc_reshape_fail(nskb, sch);}static int tfifo_init(struct Qdisc *sch, struct rtattr *opt){	struct fifo_sched_data *q = qdisc_priv(sch);	if (opt) {		struct tc_fifo_qopt *ctl = RTA_DATA(opt);		if (RTA_PAYLOAD(opt) < sizeof(*ctl))			return -EINVAL;		q->limit = ctl->limit;	} else		q->limit = max_t(u32, sch->dev->tx_queue_len, 1);	q->oldest = PSCHED_PASTPERFECT;	return 0;}static int tfifo_dump(struct Qdisc *sch, struct sk_buff *skb){	struct fifo_sched_data *q = qdisc_priv(sch);	struct tc_fifo_qopt opt = { .limit = q->limit };	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);	return skb->len;rtattr_failure:	return -1;}static struct Qdisc_ops tfifo_qdisc_ops = {	.id		=	"tfifo",	.priv_size	=	sizeof(struct fifo_sched_data),	.enqueue	=	tfifo_enqueue,	.dequeue	=	qdisc_dequeue_head,	.requeue	=	qdisc_requeue,	.drop		=	qdisc_queue_drop,	.init		=	tfifo_init,	.reset		=	qdisc_reset_queue,	.change		=	tfifo_init,	.dump		=	tfifo_dump,};static int netem_init(struct Qdisc *sch, struct rtattr *opt){	struct netem_sched_data *q = qdisc_priv(sch);	int ret;	if (!opt)		return -EINVAL;	qdisc_watchdog_init(&q->watchdog, sch);	q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,				     TC_H_MAKE(sch->handle, 1));	if (!q->qdisc) {		pr_debug("netem: qdisc create failed\n");		return -ENOMEM;	}	ret = netem_change(sch, opt);	if (ret) {		pr_debug("netem: change failed\n");		qdisc_destroy(q->qdisc);	}	return ret;}static void netem_destroy(struct Qdisc *sch){	struct netem_sched_data *q = qdisc_priv(sch);	qdisc_watchdog_cancel(&q->watchdog);	qdisc_destroy(q->qdisc);	kfree(q->delay_dist);}static int netem_dump(struct Qdisc *sch, struct sk_buff *skb){	const struct netem_sched_data *q = qdisc_priv(sch);	unsigned char *b = skb_tail_pointer(skb);	struct rtattr *rta = (struct rtattr *) b;	struct tc_netem_qopt qopt;	struct tc_netem_corr cor;	struct tc_netem_reorder reorder;	struct tc_netem_corrupt corrupt;	qopt.latency = q->latency;	qopt.jitter = q->jitter;	qopt.limit = q->limit;	qopt.loss = q->loss;	qopt.gap = q->gap;	qopt.duplicate = q->duplicate;	RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);	cor.delay_corr = q->delay_cor.rho;	cor.loss_corr = q->loss_cor.rho;	cor.dup_corr = q->dup_cor.rho;	RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor);	reorder.probability = q->reorder;	reorder.correlation = q->reorder_cor.rho;	RTA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder);	corrupt.probability = q->corrupt;	corrupt.correlation = q->corrupt_cor.rho;	RTA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);	rta->rta_len = skb_tail_pointer(skb) - b;	return skb->len;rtattr_failure:	nlmsg_trim(skb, b);	return -1;}static int netem_dump_class(struct Qdisc *sch, unsigned long cl,			  struct sk_buff *skb, struct tcmsg *tcm){	struct netem_sched_data *q = qdisc_priv(sch);	if (cl != 1) 	/* only one class */		return -ENOENT;	tcm->tcm_handle |= TC_H_MIN(1);	tcm->tcm_info = q->qdisc->handle;	return 0;}static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,		     struct Qdisc **old){	struct netem_sched_data *q = qdisc_priv(sch);	if (new == NULL)		new = &noop_qdisc;	sch_tree_lock(sch);	*old = xchg(&q->qdisc, new);	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);	qdisc_reset(*old);	sch_tree_unlock(sch);	return 0;}static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg){	struct netem_sched_data *q = qdisc_priv(sch);	return q->qdisc;}static unsigned long netem_get(struct Qdisc *sch, u32 classid){	return 1;}static void netem_put(struct Qdisc *sch, unsigned long arg){}static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid,			    struct rtattr **tca, unsigned long *arg){	return -ENOSYS;}static int netem_delete(struct Qdisc *sch, unsigned long arg){	return -ENOSYS;}static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker){	if (!walker->stop) {		if (walker->count >= walker->skip)			if (walker->fn(sch, 1, walker) < 0) {				walker->stop = 1;				return;			}		walker->count++;	}}static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl){	return NULL;}static struct Qdisc_class_ops netem_class_ops = {	.graft		=	netem_graft,	.leaf		=	netem_leaf,	.get		=	netem_get,	.put		=	netem_put,	.change		=	netem_change_class,	.delete		=	netem_delete,	.walk		=	netem_walk,	.tcf_chain	=	netem_find_tcf,	.dump		=	netem_dump_class,};static struct Qdisc_ops netem_qdisc_ops = {	.id		=	"netem",	.cl_ops		=	&netem_class_ops,	.priv_size	=	sizeof(struct netem_sched_data),	.enqueue	=	netem_enqueue,	.dequeue	=	netem_dequeue,	.requeue	=	netem_requeue,	.drop		=	netem_drop,	.init		=	netem_init,	.reset		=	netem_reset,	.destroy	=	netem_destroy,	.change		=	netem_change,	.dump		=	netem_dump,	.owner		=	THIS_MODULE,};static int __init netem_module_init(void){	pr_info("netem: version " VERSION "\n");	return register_qdisc(&netem_qdisc_ops);}static void __exit netem_module_exit(void){	unregister_qdisc(&netem_qdisc_ops);}module_init(netem_module_init)module_exit(netem_module_exit)MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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