aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/sch_tbf.c47
1 files changed, 45 insertions, 2 deletions
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index c8388f3c3426..38008b0980d9 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -116,14 +116,57 @@ struct tbf_sched_data {
116 struct qdisc_watchdog watchdog; /* Watchdog timer */ 116 struct qdisc_watchdog watchdog; /* Watchdog timer */
117}; 117};
118 118
119
120/* GSO packet is too big, segment it so that tbf can transmit
121 * each segment in time
122 */
123static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
124{
125 struct tbf_sched_data *q = qdisc_priv(sch);
126 struct sk_buff *segs, *nskb;
127 netdev_features_t features = netif_skb_features(skb);
128 int ret, nb;
129
130 segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
131
132 if (IS_ERR_OR_NULL(segs))
133 return qdisc_reshape_fail(skb, sch);
134
135 nb = 0;
136 while (segs) {
137 nskb = segs->next;
138 segs->next = NULL;
139 if (likely(segs->len <= q->max_size)) {
140 qdisc_skb_cb(segs)->pkt_len = segs->len;
141 ret = qdisc_enqueue(segs, q->qdisc);
142 } else {
143 ret = qdisc_reshape_fail(skb, sch);
144 }
145 if (ret != NET_XMIT_SUCCESS) {
146 if (net_xmit_drop_count(ret))
147 sch->qstats.drops++;
148 } else {
149 nb++;
150 }
151 segs = nskb;
152 }
153 sch->q.qlen += nb;
154 if (nb > 1)
155 qdisc_tree_decrease_qlen(sch, 1 - nb);
156 consume_skb(skb);
157 return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
158}
159
119static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch) 160static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
120{ 161{
121 struct tbf_sched_data *q = qdisc_priv(sch); 162 struct tbf_sched_data *q = qdisc_priv(sch);
122 int ret; 163 int ret;
123 164
124 if (qdisc_pkt_len(skb) > q->max_size) 165 if (qdisc_pkt_len(skb) > q->max_size) {
166 if (skb_is_gso(skb))
167 return tbf_segment(skb, sch);
125 return qdisc_reshape_fail(skb, sch); 168 return qdisc_reshape_fail(skb, sch);
126 169 }
127 ret = qdisc_enqueue(skb, q->qdisc); 170 ret = qdisc_enqueue(skb, q->qdisc);
128 if (ret != NET_XMIT_SUCCESS) { 171 if (ret != NET_XMIT_SUCCESS) {
129 if (net_xmit_drop_count(ret)) 172 if (net_xmit_drop_count(ret))