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

📄 sch_api.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct Qdisc *q = NULL;	struct Qdisc *p = NULL;	int err;	if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL)		return -ENODEV;	if (clid) {		if (clid != TC_H_ROOT) {			if (clid != TC_H_INGRESS) {				if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL)					return -ENOENT;				q = qdisc_leaf(p, clid);			} else { /*ingress */				q = dev->qdisc_ingress;			}		} else {			q = dev->qdisc_sleeping;		}		/* It may be default qdisc, ignore it */		if (q && q->handle == 0)			q = NULL;		if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) {			if (tcm->tcm_handle) {				if (q && !(n->nlmsg_flags&NLM_F_REPLACE))					return -EEXIST;				if (TC_H_MIN(tcm->tcm_handle))					return -EINVAL;				if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL)					goto create_n_graft;				if (n->nlmsg_flags&NLM_F_EXCL)					return -EEXIST;				if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))					return -EINVAL;				if (q == p ||				    (p && check_loop(q, p, 0)))					return -ELOOP;				atomic_inc(&q->refcnt);				goto graft;			} else {				if (q == NULL)					goto create_n_graft;				/* This magic test requires explanation.				 *				 *   We know, that some child q is already				 *   attached to this parent and have choice:				 *   either to change it or to create/graft new one.				 *				 *   1. We are allowed to create/graft only				 *   if CREATE and REPLACE flags are set.				 *				 *   2. If EXCL is set, requestor wanted to say,				 *   that qdisc tcm_handle is not expected				 *   to exist, so that we choose create/graft too.				 *				 *   3. The last case is when no flags are set.				 *   Alas, it is sort of hole in API, we				 *   cannot decide what to do unambiguously.				 *   For now we select create/graft, if				 *   user gave KIND, which does not match existing.				 */				if ((n->nlmsg_flags&NLM_F_CREATE) &&				    (n->nlmsg_flags&NLM_F_REPLACE) &&				    ((n->nlmsg_flags&NLM_F_EXCL) ||				     (tca[TCA_KIND-1] &&				      rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))))					goto create_n_graft;			}		}	} else {		if (!tcm->tcm_handle)			return -EINVAL;		q = qdisc_lookup(dev, tcm->tcm_handle);	}	/* Change qdisc parameters */	if (q == NULL)		return -ENOENT;	if (n->nlmsg_flags&NLM_F_EXCL)		return -EEXIST;	if (tca[TCA_KIND-1] && rtattr_strcmp(tca[TCA_KIND-1], q->ops->id))		return -EINVAL;	err = qdisc_change(q, tca);	if (err == 0)		qdisc_notify(skb, n, clid, NULL, q);	return err;create_n_graft:	if (!(n->nlmsg_flags&NLM_F_CREATE))		return -ENOENT;	if (clid == TC_H_INGRESS)		q = qdisc_create(dev, tcm->tcm_parent, tca, &err);        else		q = qdisc_create(dev, tcm->tcm_handle, tca, &err);	if (q == NULL)		return err;graft:	if (1) {		struct Qdisc *old_q = NULL;		err = qdisc_graft(dev, p, clid, q, &old_q);		if (err) {			if (q) {				spin_lock_bh(&dev->queue_lock);				qdisc_destroy(q);				spin_unlock_bh(&dev->queue_lock);			}			return err;		}		qdisc_notify(skb, n, clid, old_q, q);		if (old_q) {			spin_lock_bh(&dev->queue_lock);			qdisc_destroy(old_q);			spin_unlock_bh(&dev->queue_lock);		}	}	return 0;}int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st, spinlock_t *lock){	spin_lock_bh(lock);	RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), st);	spin_unlock_bh(lock);	return 0;rtattr_failure:	spin_unlock_bh(lock);	return -1;}static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,			 u32 pid, u32 seq, unsigned flags, int event){	struct tcmsg *tcm;	struct nlmsghdr  *nlh;	unsigned char	 *b = skb->tail;	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*tcm));	nlh->nlmsg_flags = flags;	tcm = NLMSG_DATA(nlh);	tcm->tcm_family = AF_UNSPEC;	tcm->tcm_ifindex = q->dev->ifindex;	tcm->tcm_parent = clid;	tcm->tcm_handle = q->handle;	tcm->tcm_info = atomic_read(&q->refcnt);	RTA_PUT(skb, TCA_KIND, IFNAMSIZ, q->ops->id);	if (q->ops->dump && q->ops->dump(q, skb) < 0)		goto rtattr_failure;	q->stats.qlen = q->q.qlen;	if (qdisc_copy_stats(skb, &q->stats, q->stats_lock))		goto rtattr_failure;	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,			u32 clid, struct Qdisc *old, struct Qdisc *new){	struct sk_buff *skb;	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb)		return -ENOBUFS;	if (old && old->handle) {		if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0)			goto err_out;	}	if (new) {		if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)			goto err_out;	}	if (skb->len)		return rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO);err_out:	kfree_skb(skb);	return -EINVAL;}static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb){	int idx, q_idx;	int s_idx, s_q_idx;	struct net_device *dev;	struct Qdisc *q;	s_idx = cb->args[0];	s_q_idx = q_idx = cb->args[1];	read_lock(&dev_base_lock);	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {		if (idx < s_idx)			continue;		if (idx > s_idx)			s_q_idx = 0;		read_lock_bh(&qdisc_tree_lock);		q_idx = 0;		list_for_each_entry(q, &dev->qdisc_list, list) {			if (q_idx < s_q_idx) {				q_idx++;				continue;			}			if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,					  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {				read_unlock_bh(&qdisc_tree_lock);				goto done;			}			q_idx++;		}		read_unlock_bh(&qdisc_tree_lock);	}done:	read_unlock(&dev_base_lock);	cb->args[0] = idx;	cb->args[1] = q_idx;	return skb->len;}/************************************************ *	Traffic classes manipulation.		* ************************************************/static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg){	struct tcmsg *tcm = NLMSG_DATA(n);	struct rtattr **tca = arg;	struct net_device *dev;	struct Qdisc *q = NULL;	struct Qdisc_class_ops *cops;	unsigned long cl = 0;	unsigned long new_cl;	u32 pid = tcm->tcm_parent;	u32 clid = tcm->tcm_handle;	u32 qid = TC_H_MAJ(clid);	int err;	if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL)		return -ENODEV;	/*	   parent == TC_H_UNSPEC - unspecified parent.	   parent == TC_H_ROOT   - class is root, which has no parent.	   parent == X:0	 - parent is root class.	   parent == X:Y	 - parent is a node in hierarchy.	   parent == 0:Y	 - parent is X:Y, where X:0 is qdisc.	   handle == 0:0	 - generate handle from kernel pool.	   handle == 0:Y	 - class is X:Y, where X:0 is qdisc.	   handle == X:Y	 - clear.	   handle == X:0	 - root class.	 */	/* Step 1. Determine qdisc handle X:0 */	if (pid != TC_H_ROOT) {		u32 qid1 = TC_H_MAJ(pid);		if (qid && qid1) {			/* If both majors are known, they must be identical. */			if (qid != qid1)				return -EINVAL;		} else if (qid1) {			qid = qid1;		} else if (qid == 0)			qid = dev->qdisc_sleeping->handle;		/* Now qid is genuine qdisc handle consistent		   both with parent and child.		   TC_H_MAJ(pid) still may be unspecified, complete it now.		 */		if (pid)			pid = TC_H_MAKE(qid, pid);	} else {		if (qid == 0)			qid = dev->qdisc_sleeping->handle;	}	/* OK. Locate qdisc */	if ((q = qdisc_lookup(dev, qid)) == NULL) 		return -ENOENT;	/* An check that it supports classes */	cops = q->ops->cl_ops;	if (cops == NULL)		return -EINVAL;	/* Now try to get class */	if (clid == 0) {		if (pid == TC_H_ROOT)			clid = qid;	} else		clid = TC_H_MAKE(qid, clid);	if (clid)		cl = cops->get(q, clid);	if (cl == 0) {		err = -ENOENT;		if (n->nlmsg_type != RTM_NEWTCLASS || !(n->nlmsg_flags&NLM_F_CREATE))			goto out;	} else {		switch (n->nlmsg_type) {		case RTM_NEWTCLASS:				err = -EEXIST;			if (n->nlmsg_flags&NLM_F_EXCL)				goto out;			break;		case RTM_DELTCLASS:			err = cops->delete(q, cl);			if (err == 0)				tclass_notify(skb, n, q, cl, RTM_DELTCLASS);			goto out;		case RTM_GETTCLASS:			err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS);			goto out;		default:			err = -EINVAL;			goto out;		}	}	new_cl = cl;	err = cops->change(q, clid, pid, tca, &new_cl);	if (err == 0)		tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS);out:	if (cl)		cops->put(q, cl);	return err;}static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,			  unsigned long cl,			  u32 pid, u32 seq, unsigned flags, int event){	struct tcmsg *tcm;	struct nlmsghdr  *nlh;	unsigned char	 *b = skb->tail;	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*tcm));	nlh->nlmsg_flags = flags;	tcm = NLMSG_DATA(nlh);	tcm->tcm_family = AF_UNSPEC;	tcm->tcm_ifindex = q->dev->ifindex;	tcm->tcm_parent = q->handle;	tcm->tcm_handle = q->handle;	tcm->tcm_info = 0;	RTA_PUT(skb, TCA_KIND, IFNAMSIZ, q->ops->id);	if (q->ops->cl_ops->dump && q->ops->cl_ops->dump(q, cl, skb, tcm) < 0)		goto rtattr_failure;	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,			  struct Qdisc *q, unsigned long cl, int event){	struct sk_buff *skb;	u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb)		return -ENOBUFS;	if (tc_fill_tclass(skb, q, cl, pid, n->nlmsg_seq, 0, event) < 0) {		kfree_skb(skb);		return -EINVAL;	}	return rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO);}struct qdisc_dump_args{	struct qdisc_walker w;	struct sk_buff *skb;	struct netlink_callback *cb;};static int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg){	struct qdisc_dump_args *a = (struct qdisc_dump_args *)arg;	return tc_fill_tclass(a->skb, q, cl, NETLINK_CB(a->cb->skb).pid,			      a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTCLASS);}static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb){	int t;	int s_t;	struct net_device *dev;	struct Qdisc *q;	struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh);	struct qdisc_dump_args arg;	if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))		return 0;	if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)		return 0;	s_t = cb->args[0];	t = 0;	read_lock_bh(&qdisc_tree_lock);	list_for_each_entry(q, &dev->qdisc_list, list) {		if (t < s_t || !q->ops->cl_ops ||		    (tcm->tcm_parent &&		     TC_H_MAJ(tcm->tcm_parent) != q->handle)) {			t++;			continue;		}		if (t > s_t)			memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));		arg.w.fn = qdisc_class_dump;		arg.skb = skb;		arg.cb = cb;		arg.w.stop  = 0;		arg.w.skip = cb->args[1];		arg.w.count = 0;		q->ops->cl_ops->walk(q, &arg.w);		cb->args[1] = arg.w.count;		if (arg.w.stop)			break;		t++;	}	read_unlock_bh(&qdisc_tree_lock);	cb->args[0] = t;	dev_put(dev);	return skb->len;}int psched_us_per_tick = 1;int psched_tick_per_us = 1;#ifdef CONFIG_PROC_FSstatic int psched_show(struct seq_file *seq, void *v){	seq_printf(seq, "%08x %08x %08x %08x\n",		      psched_tick_per_us, psched_us_per_tick,		      1000000, HZ);	return 0;}static int psched_open(struct inode *inode, struct file *file){	return single_open(file, psched_show, PDE(inode)->data);}static struct file_operations psched_fops = {	.owner = THIS_MODULE,	.open = psched_open,	.read  = seq_read,	.llseek = seq_lseek,	.release = single_release,};	#endif#ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAYint psched_tod_diff(int delta_sec, int bound){	int delta;	if (bound <= 1000000 || delta_sec > (0x7FFFFFFF/1000000)-1)		return bound;	delta = delta_sec * 1000000;	if (delta > bound)		delta = bound;	return delta;}EXPORT_SYMBOL(psched_tod_diff);#endif#ifdef CONFIG_NET_SCH_CLK_CPUpsched_tdiff_t psched_clock_per_hz;int psched_clock_scale;EXPORT_SYMBOL(psched_clock_per_hz);EXPORT_SYMBOL(psched_clock_scale);psched_time_t psched_time_base;cycles_t psched_time_mark;EXPORT_SYMBOL(psched_time_mark);EXPORT_SYMBOL(psched_time_base);/* * Periodically adjust psched_time_base to avoid overflow * with 32-bit get_cycles(). Safe up to 4GHz CPU. */static void psched_tick(unsigned long);static struct timer_list psched_timer = TIMER_INITIALIZER(psched_tick, 0, 0);static void psched_tick(unsigned long dummy){	if (sizeof(cycles_t) == sizeof(u32)) {		psched_time_t dummy_stamp;		PSCHED_GET_TIME(dummy_stamp);		psched_timer.expires = jiffies + 1*HZ;		add_timer(&psched_timer);	}}int __init psched_calibrate_clock(void){	psched_time_t stamp, stamp1;	struct timeval tv, tv1;	psched_tdiff_t delay;	long rdelay;	unsigned long stop;	psched_tick(0);	stop = jiffies + HZ/10;	PSCHED_GET_TIME(stamp);	do_gettimeofday(&tv);	while (time_before(jiffies, stop)) {		barrier();		cpu_relax();	}	PSCHED_GET_TIME(stamp1);	do_gettimeofday(&tv1);	delay = PSCHED_TDIFF(stamp1, stamp);	rdelay = tv1.tv_usec - tv.tv_usec;	rdelay += (tv1.tv_sec - tv.tv_sec)*1000000;	if (rdelay > delay)		return -1;	delay /= rdelay;	psched_tick_per_us = delay;	while ((delay>>=1) != 0)		psched_clock_scale++;	psched_us_per_tick = 1<<psched_clock_scale;	psched_clock_per_hz = (psched_tick_per_us*(1000000/HZ))>>psched_clock_scale;	return 0;}#endifstatic int __init pktsched_init(void){	struct rtnetlink_link *link_p;#ifdef CONFIG_NET_SCH_CLK_CPU	if (psched_calibrate_clock() < 0)		return -1;#elif defined(CONFIG_NET_SCH_CLK_JIFFIES)	psched_tick_per_us = HZ<<PSCHED_JSCALE;	psched_us_per_tick = 1000000;#endif	link_p = rtnetlink_links[PF_UNSPEC];	/* Setup rtnetlink links. It is made here to avoid	   exporting large number of public symbols.	 */	if (link_p) {		link_p[RTM_NEWQDISC-RTM_BASE].doit = tc_modify_qdisc;		link_p[RTM_DELQDISC-RTM_BASE].doit = tc_get_qdisc;		link_p[RTM_GETQDISC-RTM_BASE].doit = tc_get_qdisc;		link_p[RTM_GETQDISC-RTM_BASE].dumpit = tc_dump_qdisc;		link_p[RTM_NEWTCLASS-RTM_BASE].doit = tc_ctl_tclass;		link_p[RTM_DELTCLASS-RTM_BASE].doit = tc_ctl_tclass;		link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass;		link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass;	}	register_qdisc(&pfifo_qdisc_ops);	register_qdisc(&bfifo_qdisc_ops);	proc_net_fops_create("psched", 0, &psched_fops);	return 0;}subsys_initcall(pktsched_init);EXPORT_SYMBOL(qdisc_copy_stats);EXPORT_SYMBOL(qdisc_get_rtab);EXPORT_SYMBOL(qdisc_put_rtab);EXPORT_SYMBOL(register_qdisc);EXPORT_SYMBOL(unregister_qdisc);

⌨️ 快捷键说明

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