0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #include <linux/module.h>
0036 #include <linux/types.h>
0037 #include <linux/kernel.h>
0038 #include <linux/errno.h>
0039 #include <linux/netdevice.h>
0040 #include <linux/skbuff.h>
0041 #include <net/pkt_sched.h>
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 struct plug_sched_data {
0057
0058
0059
0060
0061 bool unplug_indefinite;
0062
0063 bool throttled;
0064
0065
0066 u32 limit;
0067
0068
0069
0070
0071 u32 pkts_current_epoch;
0072
0073
0074
0075
0076
0077
0078 u32 pkts_last_epoch;
0079
0080
0081
0082
0083
0084 u32 pkts_to_release;
0085 };
0086
0087 static int plug_enqueue(struct sk_buff *skb, struct Qdisc *sch,
0088 struct sk_buff **to_free)
0089 {
0090 struct plug_sched_data *q = qdisc_priv(sch);
0091
0092 if (likely(sch->qstats.backlog + skb->len <= q->limit)) {
0093 if (!q->unplug_indefinite)
0094 q->pkts_current_epoch++;
0095 return qdisc_enqueue_tail(skb, sch);
0096 }
0097
0098 return qdisc_drop(skb, sch, to_free);
0099 }
0100
0101 static struct sk_buff *plug_dequeue(struct Qdisc *sch)
0102 {
0103 struct plug_sched_data *q = qdisc_priv(sch);
0104
0105 if (q->throttled)
0106 return NULL;
0107
0108 if (!q->unplug_indefinite) {
0109 if (!q->pkts_to_release) {
0110
0111
0112
0113 q->throttled = true;
0114 return NULL;
0115 }
0116 q->pkts_to_release--;
0117 }
0118
0119 return qdisc_dequeue_head(sch);
0120 }
0121
0122 static int plug_init(struct Qdisc *sch, struct nlattr *opt,
0123 struct netlink_ext_ack *extack)
0124 {
0125 struct plug_sched_data *q = qdisc_priv(sch);
0126
0127 q->pkts_current_epoch = 0;
0128 q->pkts_last_epoch = 0;
0129 q->pkts_to_release = 0;
0130 q->unplug_indefinite = false;
0131
0132 if (opt == NULL) {
0133 q->limit = qdisc_dev(sch)->tx_queue_len
0134 * psched_mtu(qdisc_dev(sch));
0135 } else {
0136 struct tc_plug_qopt *ctl = nla_data(opt);
0137
0138 if (nla_len(opt) < sizeof(*ctl))
0139 return -EINVAL;
0140
0141 q->limit = ctl->limit;
0142 }
0143
0144 q->throttled = true;
0145 return 0;
0146 }
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 static int plug_change(struct Qdisc *sch, struct nlattr *opt,
0159 struct netlink_ext_ack *extack)
0160 {
0161 struct plug_sched_data *q = qdisc_priv(sch);
0162 struct tc_plug_qopt *msg;
0163
0164 if (opt == NULL)
0165 return -EINVAL;
0166
0167 msg = nla_data(opt);
0168 if (nla_len(opt) < sizeof(*msg))
0169 return -EINVAL;
0170
0171 switch (msg->action) {
0172 case TCQ_PLUG_BUFFER:
0173
0174 q->pkts_last_epoch = q->pkts_current_epoch;
0175 q->pkts_current_epoch = 0;
0176 if (q->unplug_indefinite)
0177 q->throttled = true;
0178 q->unplug_indefinite = false;
0179 break;
0180 case TCQ_PLUG_RELEASE_ONE:
0181
0182
0183
0184 q->pkts_to_release += q->pkts_last_epoch;
0185 q->pkts_last_epoch = 0;
0186 q->throttled = false;
0187 netif_schedule_queue(sch->dev_queue);
0188 break;
0189 case TCQ_PLUG_RELEASE_INDEFINITE:
0190 q->unplug_indefinite = true;
0191 q->pkts_to_release = 0;
0192 q->pkts_last_epoch = 0;
0193 q->pkts_current_epoch = 0;
0194 q->throttled = false;
0195 netif_schedule_queue(sch->dev_queue);
0196 break;
0197 case TCQ_PLUG_LIMIT:
0198
0199 q->limit = msg->limit;
0200 break;
0201 default:
0202 return -EINVAL;
0203 }
0204
0205 return 0;
0206 }
0207
0208 static struct Qdisc_ops plug_qdisc_ops __read_mostly = {
0209 .id = "plug",
0210 .priv_size = sizeof(struct plug_sched_data),
0211 .enqueue = plug_enqueue,
0212 .dequeue = plug_dequeue,
0213 .peek = qdisc_peek_head,
0214 .init = plug_init,
0215 .change = plug_change,
0216 .reset = qdisc_reset_queue,
0217 .owner = THIS_MODULE,
0218 };
0219
0220 static int __init plug_module_init(void)
0221 {
0222 return register_qdisc(&plug_qdisc_ops);
0223 }
0224
0225 static void __exit plug_module_exit(void)
0226 {
0227 unregister_qdisc(&plug_qdisc_ops);
0228 }
0229 module_init(plug_module_init)
0230 module_exit(plug_module_exit)
0231 MODULE_LICENSE("GPL");