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

📄 sch_api.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				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){	spin_lock_bh(st->lock);	RTA_PUT(skb, TCA_STATS, (char*)&st->lock - (char*)st, st);	spin_unlock_bh(st->lock);	return 0;rtattr_failure:	spin_unlock_bh(st->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 ? q->dev->ifindex : 0;	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))		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(&qdisc_tree_lock);		for (q = dev->qdisc_list, q_idx = 0; q;		     q = q->next, q_idx++) {			if (q_idx < s_q_idx)				continue;			if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid,					  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {				read_unlock(&qdisc_tree_lock);				goto done;			}		}		read_unlock(&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 ? q->dev->ifindex : 0;	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];	read_lock(&qdisc_tree_lock);	for (q=dev->qdisc_list, t=0; q; q = q->next, t++) {		if (t < s_t) continue;		if (!q->ops->cl_ops) continue;		if (tcm->tcm_parent && TC_H_MAJ(tcm->tcm_parent) != q->handle)			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;	}	read_unlock(&qdisc_tree_lock);	cb->args[0] = t;	dev_put(dev);	return skb->len;}#endifint psched_us_per_tick = 1;int psched_tick_per_us = 1;#ifdef CONFIG_PROC_FSstatic int psched_read_proc(char *buffer, char **start, off_t offset,			     int length, int *eof, void *data){	int len;	len = sprintf(buffer, "%08x %08x %08x %08x\n",		      psched_tick_per_us, psched_us_per_tick,		      1000000, HZ);	len -= offset;	if (len > length)		len = length;	if(len < 0)		len = 0;	*start = buffer + offset;	*eof = 1;	return len;}#endif#if PSCHED_CLOCK_SOURCE == PSCHED_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;}#endifpsched_time_t psched_time_base;#if PSCHED_CLOCK_SOURCE == PSCHED_CPUpsched_tdiff_t psched_clock_per_hz;int psched_clock_scale;#endif#ifdef PSCHED_WATCHERPSCHED_WATCHER psched_time_mark;static void psched_tick(unsigned long);static struct timer_list psched_timer =	{ function: psched_tick };static void psched_tick(unsigned long dummy){#if PSCHED_CLOCK_SOURCE == PSCHED_CPU	psched_time_t dummy_stamp;	PSCHED_GET_TIME(dummy_stamp);	/* It is OK up to 4GHz cpu */	psched_timer.expires = jiffies + 1*HZ;#else	unsigned long now = jiffies;	psched_time_base = ((u64)now)<<PSCHED_JSCALE;	psched_time_mark = now;	psched_timer.expires = now + 60*60*HZ;#endif	add_timer(&psched_timer);}#endif#if PSCHED_CLOCK_SOURCE == PSCHED_CPUint __init psched_calibrate_clock(void){	psched_time_t stamp, stamp1;	struct timeval tv, tv1;	psched_tdiff_t delay;	long rdelay;	unsigned long stop;#ifdef PSCHED_WATCHER	psched_tick(0);#endif	stop = jiffies + HZ/10;	PSCHED_GET_TIME(stamp);	do_gettimeofday(&tv);	while (time_before(jiffies, stop))		barrier();	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;}#endifint __init pktsched_init(void){#ifdef CONFIG_RTNETLINK	struct rtnetlink_link *link_p;#endif#if PSCHED_CLOCK_SOURCE == PSCHED_CPU	if (psched_calibrate_clock() < 0)		return -1;#elif PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES	psched_tick_per_us = HZ<<PSCHED_JSCALE;	psched_us_per_tick = 1000000;#ifdef PSCHED_WATCHER	psched_tick(0);#endif#endif#ifdef CONFIG_RTNETLINK	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;	}#endif#define INIT_QDISC(name) { \          extern struct Qdisc_ops name##_qdisc_ops; \          register_qdisc(& name##_qdisc_ops);       \	}	INIT_QDISC(pfifo);	INIT_QDISC(bfifo);#ifdef CONFIG_NET_SCH_CBQ	INIT_QDISC(cbq);#endif#ifdef CONFIG_NET_SCH_CSZ	INIT_QDISC(csz);#endif#ifdef CONFIG_NET_SCH_HPFQ	INIT_QDISC(hpfq);#endif#ifdef CONFIG_NET_SCH_HFSC	INIT_QDISC(hfsc);#endif#ifdef CONFIG_NET_SCH_RED	INIT_QDISC(red);#endif#ifdef CONFIG_NET_SCH_GRED       INIT_QDISC(gred);#endif#ifdef CONFIG_NET_SCH_INGRESS       INIT_QDISC(ingress);#endif#ifdef CONFIG_NET_SCH_DSMARK       INIT_QDISC(dsmark);#endif#ifdef CONFIG_NET_SCH_SFQ	INIT_QDISC(sfq);#endif#ifdef CONFIG_NET_SCH_TBF	INIT_QDISC(tbf);#endif#ifdef CONFIG_NET_SCH_TEQL	teql_init();#endif#ifdef CONFIG_NET_SCH_PRIO	INIT_QDISC(prio);#endif#ifdef CONFIG_NET_SCH_ATM	INIT_QDISC(atm);#endif#ifdef CONFIG_NET_CLS	tc_filter_init();#endif#ifdef CONFIG_PROC_FS	create_proc_read_entry("net/psched", 0, 0, psched_read_proc, NULL);#endif	return 0;}

⌨️ 快捷键说明

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