/* Written 1998-2000 by Werner Almesberger, EPFL ICA */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
struct socket *sock; /* for closing */
u32 classid; /* x:y type ID */
int ref; /* reference count */
- struct tc_stats stats;
+ struct gnet_stats_basic bstats;
+ struct gnet_stats_queue qstats;
spinlock_t *stats_lock;
struct atm_flow_data *next;
struct atm_flow_data *excess; /* flow for excess traffic;
* later.)
*/
if (flow) return -EBUSY;
- if (opt == NULL || rtattr_parse(tb,TCA_ATM_MAX,RTA_DATA(opt),
- RTA_PAYLOAD(opt))) return -EINVAL;
+ if (opt == NULL || rtattr_parse_nested(tb, TCA_ATM_MAX, opt))
+ return -EINVAL;
if (!tb[TCA_ATM_FD-1] || RTA_PAYLOAD(tb[TCA_ATM_FD-1]) < sizeof(fd))
return -EINVAL;
fd = *(int *) RTA_DATA(tb[TCA_ATM_FD-1]);
}
memset(flow,0,sizeof(*flow));
flow->filter_list = NULL;
- if (!(flow->q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops)))
+ if (!(flow->q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops,classid)))
flow->q = &noop_qdisc;
DPRINTK("atm_tc_change: qdisc %p\n",flow->q);
flow->sock = sock;
result == TC_POLICE_SHOT ||
#endif
(ret = flow->q->enqueue(skb,flow->q)) != 0) {
- sch->stats.drops++;
- if (flow) flow->stats.drops++;
+ sch->qstats.drops++;
+ if (flow) flow->qstats.drops++;
return ret;
}
- sch->stats.bytes += skb->len;
- sch->stats.packets++;
- flow->stats.bytes += skb->len;
- flow->stats.packets++;
+ 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
memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
flow->hdr_len);
atomic_add(skb->truesize,
- &flow->vcc->sk->sk_wmem_alloc);
+ &sk_atm(flow->vcc)->sk_wmem_alloc);
/* atm.atm_options are already set by atm_tc_enqueue */
(void) flow->vcc->send(flow->vcc,skb);
}
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++;
- else {
- sch->stats.drops++;
- p->link.stats.drops++;
+ if (!ret) {
+ sch->q.qlen++;
+ sch->qstats.requeues++;
+ } else {
+ sch->qstats.drops++;
+ p->link.qstats.drops++;
}
return ret;
}
struct atm_qdisc_data *p = PRIV(sch);
DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
- memset(p,0,sizeof(*p));
p->flows = &p->link;
- if(!(p->link.q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops)))
+ 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;
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);
skb_trim(skb,b-skb->data);
return -1;
}
+static int
+atm_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)
{
.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 = {
module_init(atm_init)
module_exit(atm_exit)
+MODULE_LICENSE("GPL");