6767*/
6868
6969struct netem_sched_data {
70+ /* internal t(ime)fifo qdisc uses sch->q and sch->limit */
71+
72+ /* optional qdisc for classful handling (NULL at netem init) */
7073 struct Qdisc * qdisc ;
74+
7175 struct qdisc_watchdog watchdog ;
7276
7377 psched_tdiff_t latency ;
@@ -117,7 +121,9 @@ struct netem_sched_data {
117121
118122};
119123
120- /* Time stamp put into socket buffer control block */
124+ /* Time stamp put into socket buffer control block
125+ * Only valid when skbs are in our internal t(ime)fifo queue.
126+ */
121127struct netem_skb_cb {
122128 psched_time_t time_to_send ;
123129};
@@ -324,6 +330,31 @@ static psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sche
324330 return PSCHED_NS2TICKS (ticks );
325331}
326332
333+ static int tfifo_enqueue (struct sk_buff * nskb , struct Qdisc * sch )
334+ {
335+ struct sk_buff_head * list = & sch -> q ;
336+ psched_time_t tnext = netem_skb_cb (nskb )-> time_to_send ;
337+ struct sk_buff * skb ;
338+
339+ if (likely (skb_queue_len (list ) < sch -> limit )) {
340+ skb = skb_peek_tail (list );
341+ /* Optimize for add at tail */
342+ if (likely (!skb || tnext >= netem_skb_cb (skb )-> time_to_send ))
343+ return qdisc_enqueue_tail (nskb , sch );
344+
345+ skb_queue_reverse_walk (list , skb ) {
346+ if (tnext >= netem_skb_cb (skb )-> time_to_send )
347+ break ;
348+ }
349+
350+ __skb_queue_after (list , skb , nskb );
351+ sch -> qstats .backlog += qdisc_pkt_len (nskb );
352+ return NET_XMIT_SUCCESS ;
353+ }
354+
355+ return qdisc_reshape_fail (nskb , sch );
356+ }
357+
327358/*
328359 * Insert one skb into qdisc.
329360 * Note: parent depends on return value to account for queue length.
@@ -399,7 +430,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
399430 now = psched_get_time ();
400431
401432 if (q -> rate ) {
402- struct sk_buff_head * list = & q -> qdisc -> q ;
433+ struct sk_buff_head * list = & sch -> q ;
403434
404435 delay += packet_len_2_sched_time (skb -> len , q );
405436
@@ -417,7 +448,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
417448
418449 cb -> time_to_send = now + delay ;
419450 ++ q -> counter ;
420- ret = qdisc_enqueue (skb , q -> qdisc );
451+ ret = tfifo_enqueue (skb , sch );
421452 } else {
422453 /*
423454 * Do re-ordering by putting one out of N packets at the front
@@ -426,7 +457,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
426457 cb -> time_to_send = psched_get_time ();
427458 q -> counter = 0 ;
428459
429- __skb_queue_head (& q -> qdisc -> q , skb );
460+ __skb_queue_head (& sch -> q , skb );
430461 q -> qdisc -> qstats .backlog += qdisc_pkt_len (skb );
431462 q -> qdisc -> qstats .requeues ++ ;
432463 ret = NET_XMIT_SUCCESS ;
@@ -439,19 +470,20 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
439470 }
440471 }
441472
442- sch -> q .qlen ++ ;
443473 return NET_XMIT_SUCCESS ;
444474}
445475
446476static unsigned int netem_drop (struct Qdisc * sch )
447477{
448478 struct netem_sched_data * q = qdisc_priv (sch );
449- unsigned int len = 0 ;
479+ unsigned int len ;
450480
451- if (q -> qdisc -> ops -> drop && (len = q -> qdisc -> ops -> drop (q -> qdisc )) != 0 ) {
452- sch -> q .qlen -- ;
481+ len = qdisc_queue_drop (sch );
482+ if (!len && q -> qdisc && q -> qdisc -> ops -> drop )
483+ len = q -> qdisc -> ops -> drop (q -> qdisc );
484+ if (len )
453485 sch -> qstats .drops ++ ;
454- }
486+
455487 return len ;
456488}
457489
@@ -463,16 +495,16 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
463495 if (qdisc_is_throttled (sch ))
464496 return NULL ;
465497
466- skb = q -> qdisc -> ops -> peek (q -> qdisc );
498+ tfifo_dequeue :
499+ skb = qdisc_peek_head (sch );
467500 if (skb ) {
468501 const struct netem_skb_cb * cb = netem_skb_cb (skb );
469- psched_time_t now = psched_get_time ();
470502
471503 /* if more time remaining? */
472- if (cb -> time_to_send <= now ) {
473- skb = qdisc_dequeue_peeked ( q -> qdisc );
504+ if (cb -> time_to_send <= psched_get_time () ) {
505+ skb = qdisc_dequeue_tail ( sch );
474506 if (unlikely (!skb ))
475- return NULL ;
507+ goto qdisc_dequeue ;
476508
477509#ifdef CONFIG_NET_CLS_ACT
478510 /*
@@ -483,24 +515,47 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
483515 skb -> tstamp .tv64 = 0 ;
484516#endif
485517
486- sch -> q .qlen -- ;
518+ if (q -> qdisc ) {
519+ int err = qdisc_enqueue (skb , q -> qdisc );
520+
521+ if (unlikely (err != NET_XMIT_SUCCESS )) {
522+ if (net_xmit_drop_count (err )) {
523+ sch -> qstats .drops ++ ;
524+ qdisc_tree_decrease_qlen (sch , 1 );
525+ }
526+ }
527+ goto tfifo_dequeue ;
528+ }
529+ deliver :
487530 qdisc_unthrottled (sch );
488531 qdisc_bstats_update (sch , skb );
489532 return skb ;
490533 }
491534
535+ if (q -> qdisc ) {
536+ skb = q -> qdisc -> ops -> dequeue (q -> qdisc );
537+ if (skb )
538+ goto deliver ;
539+ }
492540 qdisc_watchdog_schedule (& q -> watchdog , cb -> time_to_send );
493541 }
494542
543+ qdisc_dequeue :
544+ if (q -> qdisc ) {
545+ skb = q -> qdisc -> ops -> dequeue (q -> qdisc );
546+ if (skb )
547+ goto deliver ;
548+ }
495549 return NULL ;
496550}
497551
498552static void netem_reset (struct Qdisc * sch )
499553{
500554 struct netem_sched_data * q = qdisc_priv (sch );
501555
502- qdisc_reset (q -> qdisc );
503- sch -> q .qlen = 0 ;
556+ qdisc_reset_queue (sch );
557+ if (q -> qdisc )
558+ qdisc_reset (q -> qdisc );
504559 qdisc_watchdog_cancel (& q -> watchdog );
505560}
506561
@@ -690,11 +745,7 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
690745 if (ret < 0 )
691746 return ret ;
692747
693- ret = fifo_set_limit (q -> qdisc , qopt -> limit );
694- if (ret ) {
695- pr_info ("netem: can't set fifo limit\n" );
696- return ret ;
697- }
748+ sch -> limit = qopt -> limit ;
698749
699750 q -> latency = qopt -> latency ;
700751 q -> jitter = qopt -> jitter ;
@@ -735,88 +786,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
735786 return ret ;
736787}
737788
738- /*
739- * Special case version of FIFO queue for use by netem.
740- * It queues in order based on timestamps in skb's
741- */
742- struct fifo_sched_data {
743- u32 limit ;
744- psched_time_t oldest ;
745- };
746-
747- static int tfifo_enqueue (struct sk_buff * nskb , struct Qdisc * sch )
748- {
749- struct fifo_sched_data * q = qdisc_priv (sch );
750- struct sk_buff_head * list = & sch -> q ;
751- psched_time_t tnext = netem_skb_cb (nskb )-> time_to_send ;
752- struct sk_buff * skb ;
753-
754- if (likely (skb_queue_len (list ) < q -> limit )) {
755- /* Optimize for add at tail */
756- if (likely (skb_queue_empty (list ) || tnext >= q -> oldest )) {
757- q -> oldest = tnext ;
758- return qdisc_enqueue_tail (nskb , sch );
759- }
760-
761- skb_queue_reverse_walk (list , skb ) {
762- const struct netem_skb_cb * cb = netem_skb_cb (skb );
763-
764- if (tnext >= cb -> time_to_send )
765- break ;
766- }
767-
768- __skb_queue_after (list , skb , nskb );
769-
770- sch -> qstats .backlog += qdisc_pkt_len (nskb );
771-
772- return NET_XMIT_SUCCESS ;
773- }
774-
775- return qdisc_reshape_fail (nskb , sch );
776- }
777-
778- static int tfifo_init (struct Qdisc * sch , struct nlattr * opt )
779- {
780- struct fifo_sched_data * q = qdisc_priv (sch );
781-
782- if (opt ) {
783- struct tc_fifo_qopt * ctl = nla_data (opt );
784- if (nla_len (opt ) < sizeof (* ctl ))
785- return - EINVAL ;
786-
787- q -> limit = ctl -> limit ;
788- } else
789- q -> limit = max_t (u32 , qdisc_dev (sch )-> tx_queue_len , 1 );
790-
791- q -> oldest = PSCHED_PASTPERFECT ;
792- return 0 ;
793- }
794-
795- static int tfifo_dump (struct Qdisc * sch , struct sk_buff * skb )
796- {
797- struct fifo_sched_data * q = qdisc_priv (sch );
798- struct tc_fifo_qopt opt = { .limit = q -> limit };
799-
800- NLA_PUT (skb , TCA_OPTIONS , sizeof (opt ), & opt );
801- return skb -> len ;
802-
803- nla_put_failure :
804- return -1 ;
805- }
806-
807- static struct Qdisc_ops tfifo_qdisc_ops __read_mostly = {
808- .id = "tfifo" ,
809- .priv_size = sizeof (struct fifo_sched_data ),
810- .enqueue = tfifo_enqueue ,
811- .dequeue = qdisc_dequeue_head ,
812- .peek = qdisc_peek_head ,
813- .drop = qdisc_queue_drop ,
814- .init = tfifo_init ,
815- .reset = qdisc_reset_queue ,
816- .change = tfifo_init ,
817- .dump = tfifo_dump ,
818- };
819-
820789static int netem_init (struct Qdisc * sch , struct nlattr * opt )
821790{
822791 struct netem_sched_data * q = qdisc_priv (sch );
@@ -828,18 +797,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt)
828797 qdisc_watchdog_init (& q -> watchdog , sch );
829798
830799 q -> loss_model = CLG_RANDOM ;
831- q -> qdisc = qdisc_create_dflt (sch -> dev_queue , & tfifo_qdisc_ops ,
832- TC_H_MAKE (sch -> handle , 1 ));
833- if (!q -> qdisc ) {
834- pr_notice ("netem: qdisc create tfifo qdisc failed\n" );
835- return - ENOMEM ;
836- }
837-
838800 ret = netem_change (sch , opt );
839- if (ret ) {
801+ if (ret )
840802 pr_info ("netem: change failed\n" );
841- qdisc_destroy (q -> qdisc );
842- }
843803 return ret ;
844804}
845805
@@ -848,7 +808,8 @@ static void netem_destroy(struct Qdisc *sch)
848808 struct netem_sched_data * q = qdisc_priv (sch );
849809
850810 qdisc_watchdog_cancel (& q -> watchdog );
851- qdisc_destroy (q -> qdisc );
811+ if (q -> qdisc )
812+ qdisc_destroy (q -> qdisc );
852813 dist_free (q -> delay_dist );
853814}
854815
@@ -952,7 +913,7 @@ static int netem_dump_class(struct Qdisc *sch, unsigned long cl,
952913{
953914 struct netem_sched_data * q = qdisc_priv (sch );
954915
955- if (cl != 1 ) /* only one class */
916+ if (cl != 1 || ! q -> qdisc ) /* only one class */
956917 return - ENOENT ;
957918
958919 tcm -> tcm_handle |= TC_H_MIN (1 );
@@ -966,14 +927,13 @@ static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
966927{
967928 struct netem_sched_data * q = qdisc_priv (sch );
968929
969- if (new == NULL )
970- new = & noop_qdisc ;
971-
972930 sch_tree_lock (sch );
973931 * old = q -> qdisc ;
974932 q -> qdisc = new ;
975- qdisc_tree_decrease_qlen (* old , (* old )-> q .qlen );
976- qdisc_reset (* old );
933+ if (* old ) {
934+ qdisc_tree_decrease_qlen (* old , (* old )-> q .qlen );
935+ qdisc_reset (* old );
936+ }
977937 sch_tree_unlock (sch );
978938
979939 return 0 ;
0 commit comments