Lines Matching +full:vcc +full:- +full:p
1 /* net/sched/sch_atm.c - ATM VC selection "queueing discipline" */
3 /* Written 1998-2000 by Werner Almesberger, EPFL ICA */
35 * - sometimes messes up the IP stack
36 * - any manipulations besides the few operations described in the README, are
38 * - should lock the flow while there is data in the queue (?)
41 #define VCC2FLOW(vcc) ((struct atm_flow_data *) ((vcc)->user_back)) argument
48 struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */ member
49 void (*old_pop)(struct atm_vcc *vcc,
70 /* ------------------------- Class/flow operations ------------------------- */
74 struct atm_qdisc_data *p = qdisc_priv(sch); in lookup_flow() local
77 list_for_each_entry(flow, &p->flows, list) { in lookup_flow()
78 if (flow->common.classid == classid) in lookup_flow()
88 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_graft() local
91 pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n", in atm_tc_graft()
92 sch, p, flow, new, old); in atm_tc_graft()
93 if (list_empty(&flow->list)) in atm_tc_graft()
94 return -EINVAL; in atm_tc_graft()
97 *old = flow->q; in atm_tc_graft()
98 flow->q = new; in atm_tc_graft()
108 pr_debug("atm_tc_leaf(sch %p,flow %p)\n", sch, flow); in atm_tc_leaf()
109 return flow ? flow->q : NULL; in atm_tc_leaf()
114 struct atm_qdisc_data *p __maybe_unused = qdisc_priv(sch); in atm_tc_find()
117 pr_debug("%s(sch %p,[qdisc %p],classid %x)\n", __func__, sch, p, classid); in atm_tc_find()
119 pr_debug("%s: flow %p\n", __func__, flow); in atm_tc_find()
126 struct atm_qdisc_data *p __maybe_unused = qdisc_priv(sch); in atm_tc_bind_filter()
129 pr_debug("%s(sch %p,[qdisc %p],classid %x)\n", __func__, sch, p, classid); in atm_tc_bind_filter()
132 flow->ref++; in atm_tc_bind_filter()
133 pr_debug("%s: flow %p\n", __func__, flow); in atm_tc_bind_filter()
144 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_put() local
147 pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); in atm_tc_put()
148 if (--flow->ref) in atm_tc_put()
151 list_del_init(&flow->list); in atm_tc_put()
152 pr_debug("atm_tc_put: qdisc %p\n", flow->q); in atm_tc_put()
153 qdisc_destroy(flow->q); in atm_tc_put()
154 tcf_block_put(flow->block); in atm_tc_put()
155 if (flow->sock) { in atm_tc_put()
157 file_count(flow->sock->file)); in atm_tc_put()
158 flow->vcc->pop = flow->old_pop; in atm_tc_put()
159 sockfd_put(flow->sock); in atm_tc_put()
161 if (flow->excess) in atm_tc_put()
162 atm_tc_put(sch, (unsigned long)flow->excess); in atm_tc_put()
163 if (flow != &p->link) in atm_tc_put()
166 * If flow == &p->link, the qdisc no longer works at this point and in atm_tc_put()
171 static void sch_atm_pop(struct atm_vcc *vcc, struct sk_buff *skb) in sch_atm_pop() argument
173 struct atm_qdisc_data *p = VCC2FLOW(vcc)->parent; in sch_atm_pop() local
175 pr_debug("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n", vcc, skb, p); in sch_atm_pop()
176 VCC2FLOW(vcc)->old_pop(vcc, skb); in sch_atm_pop()
177 tasklet_schedule(&p->task); in sch_atm_pop()
181 0xaa, /* DSAP: non-ISO */
182 0xaa, /* SSAP: non-ISO */
198 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_change() local
207 pr_debug("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x," in atm_tc_change()
208 "flow %p,opt %p)\n", sch, p, classid, parent, flow, opt); in atm_tc_change()
212 if (parent && parent != TC_H_ROOT && parent != sch->handle) in atm_tc_change()
213 return -EINVAL; in atm_tc_change()
222 return -EBUSY; in atm_tc_change()
224 return -EINVAL; in atm_tc_change()
231 return -EINVAL; in atm_tc_change()
247 return -ENOENT; in atm_tc_change()
250 opt->nla_type, nla_len(opt), hdr_len); in atm_tc_change()
254 pr_debug("atm_tc_change: f_count %ld\n", file_count(sock->file)); in atm_tc_change()
255 if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) { in atm_tc_change()
256 error = -EPROTOTYPE; in atm_tc_change()
260 on vcc->send */ in atm_tc_change()
262 if (TC_H_MAJ(classid ^ sch->handle)) { in atm_tc_change()
264 error = -EINVAL; in atm_tc_change()
272 classid = TC_H_MAKE(sch->handle, 0x8000 | i); in atm_tc_change()
280 pr_debug("atm_tc_change: flow %p\n", flow); in atm_tc_change()
282 error = -ENOBUFS; in atm_tc_change()
286 error = tcf_block_get(&flow->block, &flow->filter_list, sch, in atm_tc_change()
293 flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid, in atm_tc_change()
295 if (!flow->q) in atm_tc_change()
296 flow->q = &noop_qdisc; in atm_tc_change()
297 pr_debug("atm_tc_change: qdisc %p\n", flow->q); in atm_tc_change()
298 flow->sock = sock; in atm_tc_change()
299 flow->vcc = ATM_SD(sock); /* speedup */ in atm_tc_change()
300 flow->vcc->user_back = flow; in atm_tc_change()
301 pr_debug("atm_tc_change: vcc %p\n", flow->vcc); in atm_tc_change()
302 flow->old_pop = flow->vcc->pop; in atm_tc_change()
303 flow->parent = p; in atm_tc_change()
304 flow->vcc->pop = sch_atm_pop; in atm_tc_change()
305 flow->common.classid = classid; in atm_tc_change()
306 flow->ref = 1; in atm_tc_change()
307 flow->excess = excess; in atm_tc_change()
308 list_add(&flow->list, &p->link.list); in atm_tc_change()
309 flow->hdr_len = hdr_len; in atm_tc_change()
311 memcpy(flow->hdr, hdr, hdr_len); in atm_tc_change()
313 memcpy(flow->hdr, llc_oui_ip, sizeof(llc_oui_ip)); in atm_tc_change()
323 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_delete() local
326 pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); in atm_tc_delete()
327 if (list_empty(&flow->list)) in atm_tc_delete()
328 return -EINVAL; in atm_tc_delete()
329 if (rcu_access_pointer(flow->filter_list) || flow == &p->link) in atm_tc_delete()
330 return -EBUSY; in atm_tc_delete()
335 if (flow->ref < 2) { in atm_tc_delete()
336 pr_err("atm_tc_delete: flow->ref == %d\n", flow->ref); in atm_tc_delete()
337 return -EINVAL; in atm_tc_delete()
339 if (flow->ref > 2) in atm_tc_delete()
340 return -EBUSY; /* catch references via excess, etc. */ in atm_tc_delete()
347 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_walk() local
350 pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); in atm_tc_walk()
351 if (walker->stop) in atm_tc_walk()
353 list_for_each_entry(flow, &p->flows, list) { in atm_tc_walk()
354 if (walker->count >= walker->skip && in atm_tc_walk()
355 walker->fn(sch, (unsigned long)flow, walker) < 0) { in atm_tc_walk()
356 walker->stop = 1; in atm_tc_walk()
359 walker->count++; in atm_tc_walk()
366 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_tcf_block() local
369 pr_debug("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); in atm_tc_tcf_block()
370 return flow ? flow->block : p->link.block; in atm_tc_tcf_block()
373 /* --------------------------- Qdisc operations ---------------------------- */
378 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_enqueue() local
384 pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); in atm_tc_enqueue()
387 if (TC_H_MAJ(skb->priority) != sch->handle || in atm_tc_enqueue()
388 !(flow = (struct atm_flow_data *)atm_tc_find(sch, skb->priority))) { in atm_tc_enqueue()
391 list_for_each_entry(flow, &p->flows, list) { in atm_tc_enqueue()
392 fl = rcu_dereference_bh(flow->filter_list); in atm_tc_enqueue()
411 flow = &p->link; in atm_tc_enqueue()
413 if (flow->vcc) in atm_tc_enqueue()
414 ATM_SKB(skb)->atm_options = flow->vcc->atm_options; in atm_tc_enqueue()
415 /*@@@ looks good ... but it's not supposed to work :-) */ in atm_tc_enqueue()
427 if (flow->excess) in atm_tc_enqueue()
428 flow = flow->excess; in atm_tc_enqueue()
430 ATM_SKB(skb)->atm_options |= ATM_ATMOPT_CLP; in atm_tc_enqueue()
436 ret = qdisc_enqueue(skb, flow->q, to_free); in atm_tc_enqueue()
442 flow->qstats.drops++; in atm_tc_enqueue()
449 * expects to be able to q->dequeue the packet later on if we return in atm_tc_enqueue()
450 * success at this place. Also, sch->q.qdisc needs to reflect whether in atm_tc_enqueue()
455 if (flow == &p->link) { in atm_tc_enqueue()
456 sch->q.qlen++; in atm_tc_enqueue()
459 tasklet_schedule(&p->task); in atm_tc_enqueue()
467 * non-ATM interfaces.
473 struct atm_qdisc_data *p = qdisc_priv(sch); in sch_atm_dequeue() local
477 pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p); in sch_atm_dequeue()
478 list_for_each_entry(flow, &p->flows, list) { in sch_atm_dequeue()
479 if (flow == &p->link) in sch_atm_dequeue()
485 while ((skb = flow->q->ops->peek(flow->q))) { in sch_atm_dequeue()
486 if (!atm_may_send(flow->vcc, skb->truesize)) in sch_atm_dequeue()
489 skb = qdisc_dequeue_peeked(flow->q); in sch_atm_dequeue()
494 bstats_update(&flow->bstats, skb); in sch_atm_dequeue()
495 pr_debug("atm_tc_dequeue: sending on class %p\n", flow); in sch_atm_dequeue()
498 if (skb_headroom(skb) < flow->hdr_len) { in sch_atm_dequeue()
501 new = skb_realloc_headroom(skb, flow->hdr_len); in sch_atm_dequeue()
507 pr_debug("sch_atm_dequeue: ip %p, data %p\n", in sch_atm_dequeue()
508 skb_network_header(skb), skb->data); in sch_atm_dequeue()
509 ATM_SKB(skb)->vcc = flow->vcc; in sch_atm_dequeue()
510 memcpy(skb_push(skb, flow->hdr_len), flow->hdr, in sch_atm_dequeue()
511 flow->hdr_len); in sch_atm_dequeue()
512 refcount_add(skb->truesize, in sch_atm_dequeue()
513 &sk_atm(flow->vcc)->sk_wmem_alloc); in sch_atm_dequeue()
515 flow->vcc->send(flow->vcc, skb); in sch_atm_dequeue()
522 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_dequeue() local
525 pr_debug("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p); in atm_tc_dequeue()
526 tasklet_schedule(&p->task); in atm_tc_dequeue()
527 skb = qdisc_dequeue_peeked(p->link.q); in atm_tc_dequeue()
529 sch->q.qlen--; in atm_tc_dequeue()
535 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_peek() local
537 pr_debug("atm_tc_peek(sch %p,[qdisc %p])\n", sch, p); in atm_tc_peek()
539 return p->link.q->ops->peek(p->link.q); in atm_tc_peek()
545 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_init() local
548 pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); in atm_tc_init()
549 INIT_LIST_HEAD(&p->flows); in atm_tc_init()
550 INIT_LIST_HEAD(&p->link.list); in atm_tc_init()
551 list_add(&p->link.list, &p->flows); in atm_tc_init()
552 p->link.q = qdisc_create_dflt(sch->dev_queue, in atm_tc_init()
553 &pfifo_qdisc_ops, sch->handle, extack); in atm_tc_init()
554 if (!p->link.q) in atm_tc_init()
555 p->link.q = &noop_qdisc; in atm_tc_init()
556 pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); in atm_tc_init()
557 p->link.vcc = NULL; in atm_tc_init()
558 p->link.sock = NULL; in atm_tc_init()
559 p->link.common.classid = sch->handle; in atm_tc_init()
560 p->link.ref = 1; in atm_tc_init()
562 err = tcf_block_get(&p->link.block, &p->link.filter_list, sch, in atm_tc_init()
567 tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch); in atm_tc_init()
573 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_reset() local
576 pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p); in atm_tc_reset()
577 list_for_each_entry(flow, &p->flows, list) in atm_tc_reset()
578 qdisc_reset(flow->q); in atm_tc_reset()
579 sch->q.qlen = 0; in atm_tc_reset()
584 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_destroy() local
587 pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); in atm_tc_destroy()
588 list_for_each_entry(flow, &p->flows, list) { in atm_tc_destroy()
589 tcf_block_put(flow->block); in atm_tc_destroy()
590 flow->block = NULL; in atm_tc_destroy()
593 list_for_each_entry_safe(flow, tmp, &p->flows, list) { in atm_tc_destroy()
594 if (flow->ref > 1) in atm_tc_destroy()
595 pr_err("atm_destroy: %p->ref = %d\n", flow, flow->ref); in atm_tc_destroy()
598 tasklet_kill(&p->task); in atm_tc_destroy()
604 struct atm_qdisc_data *p = qdisc_priv(sch); in atm_tc_dump_class() local
608 pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", in atm_tc_dump_class()
609 sch, p, flow, skb, tcm); in atm_tc_dump_class()
610 if (list_empty(&flow->list)) in atm_tc_dump_class()
611 return -EINVAL; in atm_tc_dump_class()
612 tcm->tcm_handle = flow->common.classid; in atm_tc_dump_class()
613 tcm->tcm_info = flow->q->handle; in atm_tc_dump_class()
619 if (nla_put(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr)) in atm_tc_dump_class()
621 if (flow->vcc) { in atm_tc_dump_class()
627 pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1; in atm_tc_dump_class()
628 pvc.sap_addr.vpi = flow->vcc->vpi; in atm_tc_dump_class()
629 pvc.sap_addr.vci = flow->vcc->vci; in atm_tc_dump_class()
632 state = ATM_VF2VS(flow->vcc->flags); in atm_tc_dump_class()
636 if (flow->excess) { in atm_tc_dump_class()
637 if (nla_put_u32(skb, TCA_ATM_EXCESS, flow->common.classid)) in atm_tc_dump_class()
647 return -1; in atm_tc_dump_class()
656 d, NULL, &flow->bstats) < 0 || in atm_tc_dump_class_stats()
657 gnet_stats_copy_queue(d, NULL, &flow->qstats, flow->q->q.qlen) < 0) in atm_tc_dump_class_stats()
658 return -1; in atm_tc_dump_class_stats()