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

📄 sch_atm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct atm_flow_data *flow;	DPRINTK("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);	if (walker->stop)		return;	for (flow = p->flows; flow; flow = flow->next) {		if (walker->count >= walker->skip)			if (walker->fn(sch, (unsigned long)flow, walker) < 0) {				walker->stop = 1;				break;			}		walker->count++;	}}static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl){	struct atm_qdisc_data *p = PRIV(sch);	struct atm_flow_data *flow = (struct atm_flow_data *)cl;	DPRINTK("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);	return flow ? &flow->filter_list : &p->link.filter_list;}/* --------------------------- Qdisc operations ---------------------------- */static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch){	struct atm_qdisc_data *p = PRIV(sch);	struct atm_flow_data *flow = NULL;	/* @@@ */	struct tcf_result res;	int result;	int ret = NET_XMIT_POLICED;	D2PRINTK("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);	result = TC_POLICE_OK;	/* be nice to gcc */	if (TC_H_MAJ(skb->priority) != sch->handle ||	    !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority)))		for (flow = p->flows; flow; flow = flow->next)			if (flow->filter_list) {				result = tc_classify_compat(skb,							    flow->filter_list,							    &res);				if (result < 0)					continue;				flow = (struct atm_flow_data *)res.class;				if (!flow)					flow = lookup_flow(sch, res.classid);				break;			}	if (!flow)		flow = &p->link;	else {		if (flow->vcc)			ATM_SKB(skb)->atm_options = flow->vcc->atm_options;		/*@@@ looks good ... but it's not supposed to work :-) */#ifdef CONFIG_NET_CLS_ACT		switch (result) {		case TC_ACT_QUEUED:		case TC_ACT_STOLEN:			kfree_skb(skb);			return NET_XMIT_SUCCESS;		case TC_ACT_SHOT:			kfree_skb(skb);			goto drop;		case TC_POLICE_RECLASSIFY:			if (flow->excess)				flow = flow->excess;			else				ATM_SKB(skb)->atm_options |= ATM_ATMOPT_CLP;			break;		}#endif	}	if ((ret = flow->q->enqueue(skb, flow->q)) != 0) {drop: __maybe_unused		sch->qstats.drops++;		if (flow)			flow->qstats.drops++;		return ret;	}	sch->bstats.bytes += skb->len;	sch->bstats.packets++;	flow->bstats.bytes += skb->len;	flow->bstats.packets++;	/*	 * Okay, this may seem weird. We pretend we've dropped the packet if	 * it goes via ATM. The reason for this is that the outer qdisc	 * expects to be able to q->dequeue the packet later on if we return	 * success at this place. Also, sch->q.qdisc needs to reflect whether	 * there is a packet egligible for dequeuing or not. Note that the	 * statistics of the outer qdisc are necessarily wrong because of all	 * this. There's currently no correct solution for this.	 */	if (flow == &p->link) {		sch->q.qlen++;		return 0;	}	tasklet_schedule(&p->task);	return NET_XMIT_BYPASS;}/* * Dequeue packets and send them over ATM. Note that we quite deliberately * avoid checking net_device's flow control here, simply because sch_atm * uses its own channels, which have nothing to do with any CLIP/LANE/or * non-ATM interfaces. */static void sch_atm_dequeue(unsigned long data){	struct Qdisc *sch = (struct Qdisc *)data;	struct atm_qdisc_data *p = PRIV(sch);	struct atm_flow_data *flow;	struct sk_buff *skb;	D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);	for (flow = p->link.next; flow; flow = flow->next)		/*		 * If traffic is properly shaped, this won't generate nasty		 * little bursts. Otherwise, it may ... (but that's okay)		 */		while ((skb = flow->q->dequeue(flow->q))) {			if (!atm_may_send(flow->vcc, skb->truesize)) {				(void)flow->q->ops->requeue(skb, flow->q);				break;			}			D2PRINTK("atm_tc_dequeue: sending on class %p\n", flow);			/* remove any LL header somebody else has attached */			skb_pull(skb, skb_network_offset(skb));			if (skb_headroom(skb) < flow->hdr_len) {				struct sk_buff *new;				new = skb_realloc_headroom(skb, flow->hdr_len);				dev_kfree_skb(skb);				if (!new)					continue;				skb = new;			}			D2PRINTK("sch_atm_dequeue: ip %p, data %p\n",				 skb_network_header(skb), skb->data);			ATM_SKB(skb)->vcc = flow->vcc;			memcpy(skb_push(skb, flow->hdr_len), flow->hdr,			       flow->hdr_len);			atomic_add(skb->truesize,				   &sk_atm(flow->vcc)->sk_wmem_alloc);			/* atm.atm_options are already set by atm_tc_enqueue */			flow->vcc->send(flow->vcc, skb);		}}static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch){	struct atm_qdisc_data *p = PRIV(sch);	struct sk_buff *skb;	D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p);	tasklet_schedule(&p->task);	skb = p->link.q->dequeue(p->link.q);	if (skb)		sch->q.qlen--;	return skb;}static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch){	struct atm_qdisc_data *p = PRIV(sch);	int ret;	D2PRINTK("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);	ret = p->link.q->ops->requeue(skb, p->link.q);	if (!ret) {		sch->q.qlen++;		sch->qstats.requeues++;	} else {		sch->qstats.drops++;		p->link.qstats.drops++;	}	return ret;}static unsigned int atm_tc_drop(struct Qdisc *sch){	struct atm_qdisc_data *p = PRIV(sch);	struct atm_flow_data *flow;	unsigned int len;	DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);	for (flow = p->flows; flow; flow = flow->next)		if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))			return len;	return 0;}static int atm_tc_init(struct Qdisc *sch, struct rtattr *opt){	struct atm_qdisc_data *p = PRIV(sch);	DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);	p->flows = &p->link;	if (!(p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,					    sch->handle)))		p->link.q = &noop_qdisc;	DPRINTK("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);	p->link.filter_list = NULL;	p->link.vcc = NULL;	p->link.sock = NULL;	p->link.classid = sch->handle;	p->link.ref = 1;	p->link.next = NULL;	tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch);	return 0;}static void atm_tc_reset(struct Qdisc *sch){	struct atm_qdisc_data *p = PRIV(sch);	struct atm_flow_data *flow;	DPRINTK("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);	for (flow = p->flows; flow; flow = flow->next)		qdisc_reset(flow->q);	sch->q.qlen = 0;}static void atm_tc_destroy(struct Qdisc *sch){	struct atm_qdisc_data *p = PRIV(sch);	struct atm_flow_data *flow;	DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);	/* races ? */	while ((flow = p->flows)) {		tcf_destroy_chain(flow->filter_list);		flow->filter_list = NULL;		if (flow->ref > 1)			printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,			       flow->ref);		atm_tc_put(sch, (unsigned long)flow);		if (p->flows == flow) {			printk(KERN_ERR "atm_destroy: putting flow %p didn't "			       "kill it\n", flow);			p->flows = flow->next;	/* brute force */			break;		}	}	tasklet_kill(&p->task);}static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,			     struct sk_buff *skb, struct tcmsg *tcm){	struct atm_qdisc_data *p = PRIV(sch);	struct atm_flow_data *flow = (struct atm_flow_data *)cl;	unsigned char *b = skb_tail_pointer(skb);	struct rtattr *rta;	DPRINTK("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",		sch, p, flow, skb, tcm);	if (!find_flow(p, flow))		return -EINVAL;	tcm->tcm_handle = flow->classid;	tcm->tcm_info = flow->q->handle;	rta = (struct rtattr *)b;	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);	RTA_PUT(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr);	if (flow->vcc) {		struct sockaddr_atmpvc pvc;		int state;		pvc.sap_family = AF_ATMPVC;		pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1;		pvc.sap_addr.vpi = flow->vcc->vpi;		pvc.sap_addr.vci = flow->vcc->vci;		RTA_PUT(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc);		state = ATM_VF2VS(flow->vcc->flags);		RTA_PUT(skb, TCA_ATM_STATE, sizeof(state), &state);	}	if (flow->excess)		RTA_PUT(skb, TCA_ATM_EXCESS, sizeof(u32), &flow->classid);	else {		static u32 zero;		RTA_PUT(skb, TCA_ATM_EXCESS, sizeof(zero), &zero);	}	rta->rta_len = skb_tail_pointer(skb) - b;	return skb->len;rtattr_failure:	nlmsg_trim(skb, b);	return -1;}static intatm_tc_dump_class_stats(struct Qdisc *sch, unsigned long arg,			struct gnet_dump *d){	struct atm_flow_data *flow = (struct atm_flow_data *)arg;	flow->qstats.qlen = flow->q->q.qlen;	if (gnet_stats_copy_basic(d, &flow->bstats) < 0 ||	    gnet_stats_copy_queue(d, &flow->qstats) < 0)		return -1;	return 0;}static int atm_tc_dump(struct Qdisc *sch, struct sk_buff *skb){	return 0;}static struct Qdisc_class_ops atm_class_ops = {	.graft		= atm_tc_graft,	.leaf		= atm_tc_leaf,	.get		= atm_tc_get,	.put		= atm_tc_put,	.change		= atm_tc_change,	.delete		= atm_tc_delete,	.walk		= atm_tc_walk,	.tcf_chain	= atm_tc_find_tcf,	.bind_tcf	= atm_tc_bind_filter,	.unbind_tcf	= atm_tc_put,	.dump		= atm_tc_dump_class,	.dump_stats	= atm_tc_dump_class_stats,};static struct Qdisc_ops atm_qdisc_ops = {	.cl_ops		= &atm_class_ops,	.id		= "atm",	.priv_size	= sizeof(struct atm_qdisc_data),	.enqueue	= atm_tc_enqueue,	.dequeue	= atm_tc_dequeue,	.requeue	= atm_tc_requeue,	.drop		= atm_tc_drop,	.init		= atm_tc_init,	.reset		= atm_tc_reset,	.destroy	= atm_tc_destroy,	.dump		= atm_tc_dump,	.owner		= THIS_MODULE,};static int __init atm_init(void){	return register_qdisc(&atm_qdisc_ops);}static void __exit atm_exit(void){	unregister_qdisc(&atm_qdisc_ops);}module_init(atm_init)module_exit(atm_exit)MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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