Skip to content

Commit 175f9c1

Browse files
jkivilindavem330
authored andcommitted
net_sched: Add size table for qdiscs
Add size table functions for qdiscs and calculate packet size in qdisc_enqueue(). Based on patch by Patrick McHardy http://marc.info/?l=linux-netdev&m=115201979221729&w=2 Signed-off-by: Jussi Kivilinna <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0abf77e commit 175f9c1

File tree

7 files changed

+199
-5
lines changed

7 files changed

+199
-5
lines changed

include/linux/pkt_sched.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,26 @@ struct tc_ratespec
8585

8686
#define TC_RTAB_SIZE 1024
8787

88+
struct tc_sizespec {
89+
unsigned char cell_log;
90+
unsigned char size_log;
91+
short cell_align;
92+
int overhead;
93+
unsigned int linklayer;
94+
unsigned int mpu;
95+
unsigned int mtu;
96+
unsigned int tsize;
97+
};
98+
99+
enum {
100+
TCA_STAB_UNSPEC,
101+
TCA_STAB_BASE,
102+
TCA_STAB_DATA,
103+
__TCA_STAB_MAX
104+
};
105+
106+
#define TCA_STAB_MAX (__TCA_STAB_MAX - 1)
107+
88108
/* FIFO section */
89109

90110
struct tc_fifo_qopt

include/linux/rtnetlink.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ enum
482482
TCA_RATE,
483483
TCA_FCNT,
484484
TCA_STATS2,
485+
TCA_STAB,
485486
__TCA_MAX
486487
};
487488

include/net/pkt_sched.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ extern struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
8383
extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
8484
struct nlattr *tab);
8585
extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
86+
extern void qdisc_put_stab(struct qdisc_size_table *tab);
8687

8788
extern void __qdisc_run(struct Qdisc *q);
8889

include/net/sch_generic.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ enum qdisc_state_t
2929
__QDISC_STATE_SCHED,
3030
};
3131

32+
struct qdisc_size_table {
33+
struct list_head list;
34+
struct tc_sizespec szopts;
35+
int refcnt;
36+
u16 data[];
37+
};
38+
3239
struct Qdisc
3340
{
3441
int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
@@ -39,6 +46,7 @@ struct Qdisc
3946
#define TCQ_F_INGRESS 4
4047
int padded;
4148
struct Qdisc_ops *ops;
49+
struct qdisc_size_table *stab;
4250
u32 handle;
4351
u32 parent;
4452
atomic_t refcnt;
@@ -165,6 +173,16 @@ struct tcf_proto
165173
struct tcf_proto_ops *ops;
166174
};
167175

176+
struct qdisc_skb_cb {
177+
unsigned int pkt_len;
178+
char data[];
179+
};
180+
181+
static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb)
182+
{
183+
return (struct qdisc_skb_cb *)skb->cb;
184+
}
185+
168186
static inline spinlock_t *qdisc_lock(struct Qdisc *qdisc)
169187
{
170188
return &qdisc->q.lock;
@@ -257,6 +275,8 @@ extern struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
257275
extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
258276
struct netdev_queue *dev_queue,
259277
struct Qdisc_ops *ops, u32 parentid);
278+
extern void qdisc_calculate_pkt_len(struct sk_buff *skb,
279+
struct qdisc_size_table *stab);
260280
extern void tcf_destroy(struct tcf_proto *tp);
261281
extern void tcf_destroy_chain(struct tcf_proto **fl);
262282

@@ -308,16 +328,19 @@ static inline bool qdisc_tx_is_noop(const struct net_device *dev)
308328

309329
static inline unsigned int qdisc_pkt_len(struct sk_buff *skb)
310330
{
311-
return skb->len;
331+
return qdisc_skb_cb(skb)->pkt_len;
312332
}
313333

314334
static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
315335
{
336+
if (sch->stab)
337+
qdisc_calculate_pkt_len(skb, sch->stab);
316338
return sch->enqueue(skb, sch);
317339
}
318340

319341
static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch)
320342
{
343+
qdisc_skb_cb(skb)->pkt_len = skb->len;
321344
return qdisc_enqueue(skb, sch);
322345
}
323346

net/sched/sch_api.c

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,129 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab)
286286
}
287287
EXPORT_SYMBOL(qdisc_put_rtab);
288288

289+
static LIST_HEAD(qdisc_stab_list);
290+
static DEFINE_SPINLOCK(qdisc_stab_lock);
291+
292+
static const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = {
293+
[TCA_STAB_BASE] = { .len = sizeof(struct tc_sizespec) },
294+
[TCA_STAB_DATA] = { .type = NLA_BINARY },
295+
};
296+
297+
static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt)
298+
{
299+
struct nlattr *tb[TCA_STAB_MAX + 1];
300+
struct qdisc_size_table *stab;
301+
struct tc_sizespec *s;
302+
unsigned int tsize = 0;
303+
u16 *tab = NULL;
304+
int err;
305+
306+
err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy);
307+
if (err < 0)
308+
return ERR_PTR(err);
309+
if (!tb[TCA_STAB_BASE])
310+
return ERR_PTR(-EINVAL);
311+
312+
s = nla_data(tb[TCA_STAB_BASE]);
313+
314+
if (s->tsize > 0) {
315+
if (!tb[TCA_STAB_DATA])
316+
return ERR_PTR(-EINVAL);
317+
tab = nla_data(tb[TCA_STAB_DATA]);
318+
tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16);
319+
}
320+
321+
if (!s || tsize != s->tsize || (!tab && tsize > 0))
322+
return ERR_PTR(-EINVAL);
323+
324+
spin_lock(&qdisc_stab_lock);
325+
326+
list_for_each_entry(stab, &qdisc_stab_list, list) {
327+
if (memcmp(&stab->szopts, s, sizeof(*s)))
328+
continue;
329+
if (tsize > 0 && memcmp(stab->data, tab, tsize * sizeof(u16)))
330+
continue;
331+
stab->refcnt++;
332+
spin_unlock(&qdisc_stab_lock);
333+
return stab;
334+
}
335+
336+
spin_unlock(&qdisc_stab_lock);
337+
338+
stab = kmalloc(sizeof(*stab) + tsize * sizeof(u16), GFP_KERNEL);
339+
if (!stab)
340+
return ERR_PTR(-ENOMEM);
341+
342+
stab->refcnt = 1;
343+
stab->szopts = *s;
344+
if (tsize > 0)
345+
memcpy(stab->data, tab, tsize * sizeof(u16));
346+
347+
spin_lock(&qdisc_stab_lock);
348+
list_add_tail(&stab->list, &qdisc_stab_list);
349+
spin_unlock(&qdisc_stab_lock);
350+
351+
return stab;
352+
}
353+
354+
void qdisc_put_stab(struct qdisc_size_table *tab)
355+
{
356+
if (!tab)
357+
return;
358+
359+
spin_lock(&qdisc_stab_lock);
360+
361+
if (--tab->refcnt == 0) {
362+
list_del(&tab->list);
363+
kfree(tab);
364+
}
365+
366+
spin_unlock(&qdisc_stab_lock);
367+
}
368+
EXPORT_SYMBOL(qdisc_put_stab);
369+
370+
static int qdisc_dump_stab(struct sk_buff *skb, struct qdisc_size_table *stab)
371+
{
372+
struct nlattr *nest;
373+
374+
nest = nla_nest_start(skb, TCA_STAB);
375+
NLA_PUT(skb, TCA_STAB_BASE, sizeof(stab->szopts), &stab->szopts);
376+
nla_nest_end(skb, nest);
377+
378+
return skb->len;
379+
380+
nla_put_failure:
381+
return -1;
382+
}
383+
384+
void qdisc_calculate_pkt_len(struct sk_buff *skb, struct qdisc_size_table *stab)
385+
{
386+
int pkt_len, slot;
387+
388+
pkt_len = skb->len + stab->szopts.overhead;
389+
if (unlikely(!stab->szopts.tsize))
390+
goto out;
391+
392+
slot = pkt_len + stab->szopts.cell_align;
393+
if (unlikely(slot < 0))
394+
slot = 0;
395+
396+
slot >>= stab->szopts.cell_log;
397+
if (likely(slot < stab->szopts.tsize))
398+
pkt_len = stab->data[slot];
399+
else
400+
pkt_len = stab->data[stab->szopts.tsize - 1] *
401+
(slot / stab->szopts.tsize) +
402+
stab->data[slot % stab->szopts.tsize];
403+
404+
pkt_len <<= stab->szopts.size_log;
405+
out:
406+
if (unlikely(pkt_len < 1))
407+
pkt_len = 1;
408+
qdisc_skb_cb(skb)->pkt_len = pkt_len;
409+
}
410+
EXPORT_SYMBOL(qdisc_calculate_pkt_len);
411+
289412
static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
290413
{
291414
struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
@@ -613,6 +736,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
613736
struct nlattr *kind = tca[TCA_KIND];
614737
struct Qdisc *sch;
615738
struct Qdisc_ops *ops;
739+
struct qdisc_size_table *stab;
616740

617741
ops = qdisc_lookup_ops(kind);
618742
#ifdef CONFIG_KMOD
@@ -670,6 +794,14 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
670794
sch->handle = handle;
671795

672796
if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS])) == 0) {
797+
if (tca[TCA_STAB]) {
798+
stab = qdisc_get_stab(tca[TCA_STAB]);
799+
if (IS_ERR(stab)) {
800+
err = PTR_ERR(stab);
801+
goto err_out3;
802+
}
803+
sch->stab = stab;
804+
}
673805
if (tca[TCA_RATE]) {
674806
err = gen_new_estimator(&sch->bstats, &sch->rate_est,
675807
qdisc_root_lock(sch),
@@ -691,6 +823,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
691823
return sch;
692824
}
693825
err_out3:
826+
qdisc_put_stab(sch->stab);
694827
dev_put(dev);
695828
kfree((char *) sch - sch->padded);
696829
err_out2:
@@ -702,15 +835,26 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
702835

703836
static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
704837
{
705-
if (tca[TCA_OPTIONS]) {
706-
int err;
838+
struct qdisc_size_table *stab = NULL;
839+
int err = 0;
707840

841+
if (tca[TCA_OPTIONS]) {
708842
if (sch->ops->change == NULL)
709843
return -EINVAL;
710844
err = sch->ops->change(sch, tca[TCA_OPTIONS]);
711845
if (err)
712846
return err;
713847
}
848+
849+
if (tca[TCA_STAB]) {
850+
stab = qdisc_get_stab(tca[TCA_STAB]);
851+
if (IS_ERR(stab))
852+
return PTR_ERR(stab);
853+
}
854+
855+
qdisc_put_stab(sch->stab);
856+
sch->stab = stab;
857+
714858
if (tca[TCA_RATE])
715859
gen_replace_estimator(&sch->bstats, &sch->rate_est,
716860
qdisc_root_lock(sch), tca[TCA_RATE]);
@@ -994,6 +1138,9 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
9941138
goto nla_put_failure;
9951139
q->qstats.qlen = q->q.qlen;
9961140

1141+
if (q->stab && qdisc_dump_stab(skb, q->stab) < 0)
1142+
goto nla_put_failure;
1143+
9971144
if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
9981145
TCA_XSTATS, qdisc_root_lock(q), &d) < 0)
9991146
goto nla_put_failure;

net/sched/sch_generic.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ static void __qdisc_destroy(struct rcu_head *head)
469469
struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu);
470470
const struct Qdisc_ops *ops = qdisc->ops;
471471

472+
qdisc_put_stab(qdisc->stab);
472473
gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
473474
if (ops->reset)
474475
ops->reset(qdisc);

net/sched/sch_netem.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ struct netem_skb_cb {
8484

8585
static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
8686
{
87-
BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct netem_skb_cb));
88-
return (struct netem_skb_cb *)skb->cb;
87+
BUILD_BUG_ON(sizeof(skb->cb) <
88+
sizeof(struct qdisc_skb_cb) + sizeof(struct netem_skb_cb));
89+
return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
8990
}
9091

9192
/* init_crandom - initialize correlated random number generator

0 commit comments

Comments
 (0)