@@ -286,6 +286,129 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab)
286286}
287287EXPORT_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+
289412static 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 }
693825err_out3 :
826+ qdisc_put_stab (sch -> stab );
694827 dev_put (dev );
695828 kfree ((char * ) sch - sch -> padded );
696829err_out2 :
@@ -702,15 +835,26 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
702835
703836static 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 ;
0 commit comments