19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
292651940SAlexander Duyck /*
392651940SAlexander Duyck * Copyright (c) 2008, Intel Corporation.
492651940SAlexander Duyck *
592651940SAlexander Duyck * Author: Alexander Duyck <alexander.h.duyck@intel.com>
692651940SAlexander Duyck */
792651940SAlexander Duyck
892651940SAlexander Duyck #include <linux/module.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
1092651940SAlexander Duyck #include <linux/types.h>
1192651940SAlexander Duyck #include <linux/kernel.h>
1292651940SAlexander Duyck #include <linux/string.h>
1392651940SAlexander Duyck #include <linux/errno.h>
1492651940SAlexander Duyck #include <linux/skbuff.h>
1592651940SAlexander Duyck #include <net/netlink.h>
1692651940SAlexander Duyck #include <net/pkt_sched.h>
17cf1facdaSJiri Pirko #include <net/pkt_cls.h>
1892651940SAlexander Duyck
1992651940SAlexander Duyck struct multiq_sched_data {
2092651940SAlexander Duyck u16 bands;
2192651940SAlexander Duyck u16 max_bands;
2292651940SAlexander Duyck u16 curband;
2325d8c0d5SJohn Fastabend struct tcf_proto __rcu *filter_list;
246529eabaSJiri Pirko struct tcf_block *block;
2592651940SAlexander Duyck struct Qdisc **queues;
2692651940SAlexander Duyck };
2792651940SAlexander Duyck
2892651940SAlexander Duyck
2992651940SAlexander Duyck static struct Qdisc *
multiq_classify(struct sk_buff * skb,struct Qdisc * sch,int * qerr)3092651940SAlexander Duyck multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
3192651940SAlexander Duyck {
3292651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
3392651940SAlexander Duyck u32 band;
3492651940SAlexander Duyck struct tcf_result res;
3525d8c0d5SJohn Fastabend struct tcf_proto *fl = rcu_dereference_bh(q->filter_list);
3692651940SAlexander Duyck int err;
3792651940SAlexander Duyck
3892651940SAlexander Duyck *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
393aa26055SDavide Caratti err = tcf_classify(skb, NULL, fl, &res, false);
4092651940SAlexander Duyck #ifdef CONFIG_NET_CLS_ACT
4192651940SAlexander Duyck switch (err) {
4292651940SAlexander Duyck case TC_ACT_STOLEN:
4392651940SAlexander Duyck case TC_ACT_QUEUED:
44e25ea21fSJiri Pirko case TC_ACT_TRAP:
4592651940SAlexander Duyck *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
46964201deSGustavo A. R. Silva fallthrough;
4792651940SAlexander Duyck case TC_ACT_SHOT:
4892651940SAlexander Duyck return NULL;
4992651940SAlexander Duyck }
5092651940SAlexander Duyck #endif
5192651940SAlexander Duyck band = skb_get_queue_mapping(skb);
5292651940SAlexander Duyck
5392651940SAlexander Duyck if (band >= q->bands)
5492651940SAlexander Duyck return q->queues[0];
5592651940SAlexander Duyck
5692651940SAlexander Duyck return q->queues[band];
5792651940SAlexander Duyck }
5892651940SAlexander Duyck
5992651940SAlexander Duyck static int
multiq_enqueue(struct sk_buff * skb,struct Qdisc * sch,struct sk_buff ** to_free)60ac5c66f2SPetr Machata multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
61520ac30fSEric Dumazet struct sk_buff **to_free)
6292651940SAlexander Duyck {
6392651940SAlexander Duyck struct Qdisc *qdisc;
6492651940SAlexander Duyck int ret;
6592651940SAlexander Duyck
6692651940SAlexander Duyck qdisc = multiq_classify(skb, sch, &ret);
6792651940SAlexander Duyck #ifdef CONFIG_NET_CLS_ACT
6892651940SAlexander Duyck if (qdisc == NULL) {
6992651940SAlexander Duyck
7092651940SAlexander Duyck if (ret & __NET_XMIT_BYPASS)
7125331d6cSJohn Fastabend qdisc_qstats_drop(sch);
72520ac30fSEric Dumazet __qdisc_drop(skb, to_free);
7392651940SAlexander Duyck return ret;
7492651940SAlexander Duyck }
7592651940SAlexander Duyck #endif
7692651940SAlexander Duyck
77ac5c66f2SPetr Machata ret = qdisc_enqueue(skb, qdisc, to_free);
7892651940SAlexander Duyck if (ret == NET_XMIT_SUCCESS) {
7992651940SAlexander Duyck sch->q.qlen++;
8092651940SAlexander Duyck return NET_XMIT_SUCCESS;
8192651940SAlexander Duyck }
8292651940SAlexander Duyck if (net_xmit_drop_count(ret))
8325331d6cSJohn Fastabend qdisc_qstats_drop(sch);
8492651940SAlexander Duyck return ret;
8592651940SAlexander Duyck }
8692651940SAlexander Duyck
multiq_dequeue(struct Qdisc * sch)8792651940SAlexander Duyck static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
8892651940SAlexander Duyck {
8992651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
9092651940SAlexander Duyck struct Qdisc *qdisc;
9192651940SAlexander Duyck struct sk_buff *skb;
9292651940SAlexander Duyck int band;
9392651940SAlexander Duyck
9492651940SAlexander Duyck for (band = 0; band < q->bands; band++) {
9592651940SAlexander Duyck /* cycle through bands to ensure fairness */
9692651940SAlexander Duyck q->curband++;
9792651940SAlexander Duyck if (q->curband >= q->bands)
9892651940SAlexander Duyck q->curband = 0;
9992651940SAlexander Duyck
10092651940SAlexander Duyck /* Check that target subqueue is available before
101f30ab418SJarek Poplawski * pulling an skb to avoid head-of-line blocking.
10292651940SAlexander Duyck */
10373466498STom Herbert if (!netif_xmit_stopped(
10473466498STom Herbert netdev_get_tx_queue(qdisc_dev(sch), q->curband))) {
10592651940SAlexander Duyck qdisc = q->queues[q->curband];
10692651940SAlexander Duyck skb = qdisc->dequeue(qdisc);
10792651940SAlexander Duyck if (skb) {
1089190b3b3SEric Dumazet qdisc_bstats_update(sch, skb);
10992651940SAlexander Duyck sch->q.qlen--;
11092651940SAlexander Duyck return skb;
11192651940SAlexander Duyck }
11292651940SAlexander Duyck }
11392651940SAlexander Duyck }
11492651940SAlexander Duyck return NULL;
11592651940SAlexander Duyck
11692651940SAlexander Duyck }
11792651940SAlexander Duyck
multiq_peek(struct Qdisc * sch)1188e3af978SJarek Poplawski static struct sk_buff *multiq_peek(struct Qdisc *sch)
1198e3af978SJarek Poplawski {
1208e3af978SJarek Poplawski struct multiq_sched_data *q = qdisc_priv(sch);
1218e3af978SJarek Poplawski unsigned int curband = q->curband;
1228e3af978SJarek Poplawski struct Qdisc *qdisc;
1238e3af978SJarek Poplawski struct sk_buff *skb;
1248e3af978SJarek Poplawski int band;
1258e3af978SJarek Poplawski
1268e3af978SJarek Poplawski for (band = 0; band < q->bands; band++) {
1278e3af978SJarek Poplawski /* cycle through bands to ensure fairness */
1288e3af978SJarek Poplawski curband++;
1298e3af978SJarek Poplawski if (curband >= q->bands)
1308e3af978SJarek Poplawski curband = 0;
1318e3af978SJarek Poplawski
1328e3af978SJarek Poplawski /* Check that target subqueue is available before
133f30ab418SJarek Poplawski * pulling an skb to avoid head-of-line blocking.
1348e3af978SJarek Poplawski */
13573466498STom Herbert if (!netif_xmit_stopped(
13673466498STom Herbert netdev_get_tx_queue(qdisc_dev(sch), curband))) {
1378e3af978SJarek Poplawski qdisc = q->queues[curband];
1388e3af978SJarek Poplawski skb = qdisc->ops->peek(qdisc);
1398e3af978SJarek Poplawski if (skb)
1408e3af978SJarek Poplawski return skb;
1418e3af978SJarek Poplawski }
1428e3af978SJarek Poplawski }
1438e3af978SJarek Poplawski return NULL;
1448e3af978SJarek Poplawski
1458e3af978SJarek Poplawski }
1468e3af978SJarek Poplawski
14792651940SAlexander Duyck static void
multiq_reset(struct Qdisc * sch)14892651940SAlexander Duyck multiq_reset(struct Qdisc *sch)
14992651940SAlexander Duyck {
15092651940SAlexander Duyck u16 band;
15192651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
15292651940SAlexander Duyck
15392651940SAlexander Duyck for (band = 0; band < q->bands; band++)
15492651940SAlexander Duyck qdisc_reset(q->queues[band]);
15592651940SAlexander Duyck q->curband = 0;
15692651940SAlexander Duyck }
15792651940SAlexander Duyck
15892651940SAlexander Duyck static void
multiq_destroy(struct Qdisc * sch)15992651940SAlexander Duyck multiq_destroy(struct Qdisc *sch)
16092651940SAlexander Duyck {
16192651940SAlexander Duyck int band;
16292651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
16392651940SAlexander Duyck
1646529eabaSJiri Pirko tcf_block_put(q->block);
16592651940SAlexander Duyck for (band = 0; band < q->bands; band++)
16686bd446bSVlad Buslov qdisc_put(q->queues[band]);
16792651940SAlexander Duyck
16892651940SAlexander Duyck kfree(q->queues);
16992651940SAlexander Duyck }
17092651940SAlexander Duyck
multiq_tune(struct Qdisc * sch,struct nlattr * opt,struct netlink_ext_ack * extack)1712030721cSAlexander Aring static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
1722030721cSAlexander Aring struct netlink_ext_ack *extack)
17392651940SAlexander Duyck {
17492651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
17592651940SAlexander Duyck struct tc_multiq_qopt *qopt;
176c2999f7fSVlad Buslov struct Qdisc **removed;
177c2999f7fSVlad Buslov int i, n_removed = 0;
17892651940SAlexander Duyck
17992651940SAlexander Duyck if (!netif_is_multiqueue(qdisc_dev(sch)))
180149490f1SJarek Poplawski return -EOPNOTSUPP;
18192651940SAlexander Duyck if (nla_len(opt) < sizeof(*qopt))
18292651940SAlexander Duyck return -EINVAL;
18392651940SAlexander Duyck
18492651940SAlexander Duyck qopt = nla_data(opt);
18592651940SAlexander Duyck
18692651940SAlexander Duyck qopt->bands = qdisc_dev(sch)->real_num_tx_queues;
18792651940SAlexander Duyck
188*54c2c171SHangyu Hua removed = kmalloc(sizeof(*removed) * (q->max_bands - qopt->bands),
189c2999f7fSVlad Buslov GFP_KERNEL);
190c2999f7fSVlad Buslov if (!removed)
191c2999f7fSVlad Buslov return -ENOMEM;
192c2999f7fSVlad Buslov
19392651940SAlexander Duyck sch_tree_lock(sch);
19492651940SAlexander Duyck q->bands = qopt->bands;
19592651940SAlexander Duyck for (i = q->bands; i < q->max_bands; i++) {
196f07d1501SAlexander Duyck if (q->queues[i] != &noop_qdisc) {
197b94c8afcSPatrick McHardy struct Qdisc *child = q->queues[i];
198e5f0e8f8SPaolo Abeni
199b94c8afcSPatrick McHardy q->queues[i] = &noop_qdisc;
200c2999f7fSVlad Buslov qdisc_purge_queue(child);
201c2999f7fSVlad Buslov removed[n_removed++] = child;
20292651940SAlexander Duyck }
20392651940SAlexander Duyck }
20492651940SAlexander Duyck
20592651940SAlexander Duyck sch_tree_unlock(sch);
20692651940SAlexander Duyck
207c2999f7fSVlad Buslov for (i = 0; i < n_removed; i++)
208c2999f7fSVlad Buslov qdisc_put(removed[i]);
209c2999f7fSVlad Buslov kfree(removed);
210c2999f7fSVlad Buslov
21192651940SAlexander Duyck for (i = 0; i < q->bands; i++) {
21292651940SAlexander Duyck if (q->queues[i] == &noop_qdisc) {
213b94c8afcSPatrick McHardy struct Qdisc *child, *old;
2143511c913SChangli Gao child = qdisc_create_dflt(sch->dev_queue,
21592651940SAlexander Duyck &pfifo_qdisc_ops,
21692651940SAlexander Duyck TC_H_MAKE(sch->handle,
217a38a9882SAlexander Aring i + 1), extack);
21892651940SAlexander Duyck if (child) {
21992651940SAlexander Duyck sch_tree_lock(sch);
220b94c8afcSPatrick McHardy old = q->queues[i];
221b94c8afcSPatrick McHardy q->queues[i] = child;
22249b49971SJiri Kosina if (child != &noop_qdisc)
22349b49971SJiri Kosina qdisc_hash_add(child, true);
22492651940SAlexander Duyck
225c2999f7fSVlad Buslov if (old != &noop_qdisc)
226c2999f7fSVlad Buslov qdisc_purge_queue(old);
22792651940SAlexander Duyck sch_tree_unlock(sch);
228c2999f7fSVlad Buslov qdisc_put(old);
22992651940SAlexander Duyck }
23092651940SAlexander Duyck }
23192651940SAlexander Duyck }
23292651940SAlexander Duyck return 0;
23392651940SAlexander Duyck }
23492651940SAlexander Duyck
multiq_init(struct Qdisc * sch,struct nlattr * opt,struct netlink_ext_ack * extack)235e63d7dfdSAlexander Aring static int multiq_init(struct Qdisc *sch, struct nlattr *opt,
236e63d7dfdSAlexander Aring struct netlink_ext_ack *extack)
23792651940SAlexander Duyck {
23892651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
239f07d1501SAlexander Duyck int i, err;
24092651940SAlexander Duyck
24192651940SAlexander Duyck q->queues = NULL;
24292651940SAlexander Duyck
243ac8ef4abSAlexander Aring if (!opt)
24492651940SAlexander Duyck return -EINVAL;
24592651940SAlexander Duyck
2468d1a77f9SAlexander Aring err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
2476529eabaSJiri Pirko if (err)
2486529eabaSJiri Pirko return err;
2496529eabaSJiri Pirko
25092651940SAlexander Duyck q->max_bands = qdisc_dev(sch)->num_tx_queues;
25192651940SAlexander Duyck
25292651940SAlexander Duyck q->queues = kcalloc(q->max_bands, sizeof(struct Qdisc *), GFP_KERNEL);
25392651940SAlexander Duyck if (!q->queues)
25492651940SAlexander Duyck return -ENOBUFS;
25592651940SAlexander Duyck for (i = 0; i < q->max_bands; i++)
25692651940SAlexander Duyck q->queues[i] = &noop_qdisc;
25792651940SAlexander Duyck
2582030721cSAlexander Aring return multiq_tune(sch, opt, extack);
25992651940SAlexander Duyck }
26092651940SAlexander Duyck
multiq_dump(struct Qdisc * sch,struct sk_buff * skb)26192651940SAlexander Duyck static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb)
26292651940SAlexander Duyck {
26392651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
26492651940SAlexander Duyck unsigned char *b = skb_tail_pointer(skb);
26592651940SAlexander Duyck struct tc_multiq_qopt opt;
26692651940SAlexander Duyck
26792651940SAlexander Duyck opt.bands = q->bands;
26892651940SAlexander Duyck opt.max_bands = q->max_bands;
26992651940SAlexander Duyck
2701b34ec43SDavid S. Miller if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
2711b34ec43SDavid S. Miller goto nla_put_failure;
27292651940SAlexander Duyck
27392651940SAlexander Duyck return skb->len;
27492651940SAlexander Duyck
27592651940SAlexander Duyck nla_put_failure:
27692651940SAlexander Duyck nlmsg_trim(skb, b);
27792651940SAlexander Duyck return -1;
27892651940SAlexander Duyck }
27992651940SAlexander Duyck
multiq_graft(struct Qdisc * sch,unsigned long arg,struct Qdisc * new,struct Qdisc ** old,struct netlink_ext_ack * extack)28092651940SAlexander Duyck static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
281653d6fd6SAlexander Aring struct Qdisc **old, struct netlink_ext_ack *extack)
28292651940SAlexander Duyck {
28392651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
28492651940SAlexander Duyck unsigned long band = arg - 1;
28592651940SAlexander Duyck
28692651940SAlexander Duyck if (new == NULL)
28792651940SAlexander Duyck new = &noop_qdisc;
28892651940SAlexander Duyck
28986a7996cSWANG Cong *old = qdisc_replace(sch, new, &q->queues[band]);
29092651940SAlexander Duyck return 0;
29192651940SAlexander Duyck }
29292651940SAlexander Duyck
29392651940SAlexander Duyck static struct Qdisc *
multiq_leaf(struct Qdisc * sch,unsigned long arg)29492651940SAlexander Duyck multiq_leaf(struct Qdisc *sch, unsigned long arg)
29592651940SAlexander Duyck {
29692651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
29792651940SAlexander Duyck unsigned long band = arg - 1;
29892651940SAlexander Duyck
29992651940SAlexander Duyck return q->queues[band];
30092651940SAlexander Duyck }
30192651940SAlexander Duyck
multiq_find(struct Qdisc * sch,u32 classid)302143976ceSWANG Cong static unsigned long multiq_find(struct Qdisc *sch, u32 classid)
30392651940SAlexander Duyck {
30492651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
30592651940SAlexander Duyck unsigned long band = TC_H_MIN(classid);
30692651940SAlexander Duyck
30792651940SAlexander Duyck if (band - 1 >= q->bands)
30892651940SAlexander Duyck return 0;
30992651940SAlexander Duyck return band;
31092651940SAlexander Duyck }
31192651940SAlexander Duyck
multiq_bind(struct Qdisc * sch,unsigned long parent,u32 classid)31292651940SAlexander Duyck static unsigned long multiq_bind(struct Qdisc *sch, unsigned long parent,
31392651940SAlexander Duyck u32 classid)
31492651940SAlexander Duyck {
315143976ceSWANG Cong return multiq_find(sch, classid);
31692651940SAlexander Duyck }
31792651940SAlexander Duyck
31892651940SAlexander Duyck
multiq_unbind(struct Qdisc * q,unsigned long cl)319143976ceSWANG Cong static void multiq_unbind(struct Qdisc *q, unsigned long cl)
32092651940SAlexander Duyck {
32192651940SAlexander Duyck }
32292651940SAlexander Duyck
multiq_dump_class(struct Qdisc * sch,unsigned long cl,struct sk_buff * skb,struct tcmsg * tcm)32392651940SAlexander Duyck static int multiq_dump_class(struct Qdisc *sch, unsigned long cl,
32492651940SAlexander Duyck struct sk_buff *skb, struct tcmsg *tcm)
32592651940SAlexander Duyck {
32692651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
32792651940SAlexander Duyck
32892651940SAlexander Duyck tcm->tcm_handle |= TC_H_MIN(cl);
32992651940SAlexander Duyck tcm->tcm_info = q->queues[cl - 1]->handle;
33092651940SAlexander Duyck return 0;
33192651940SAlexander Duyck }
33292651940SAlexander Duyck
multiq_dump_class_stats(struct Qdisc * sch,unsigned long cl,struct gnet_dump * d)33392651940SAlexander Duyck static int multiq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
33492651940SAlexander Duyck struct gnet_dump *d)
33592651940SAlexander Duyck {
33692651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
33792651940SAlexander Duyck struct Qdisc *cl_q;
33892651940SAlexander Duyck
33992651940SAlexander Duyck cl_q = q->queues[cl - 1];
34029cbcd85SAhmed S. Darwish if (gnet_stats_copy_basic(d, cl_q->cpu_bstats, &cl_q->bstats, true) < 0 ||
3415dd431b6SPaolo Abeni qdisc_qstats_copy(d, cl_q) < 0)
34292651940SAlexander Duyck return -1;
34392651940SAlexander Duyck
34492651940SAlexander Duyck return 0;
34592651940SAlexander Duyck }
34692651940SAlexander Duyck
multiq_walk(struct Qdisc * sch,struct qdisc_walker * arg)34792651940SAlexander Duyck static void multiq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
34892651940SAlexander Duyck {
34992651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
35092651940SAlexander Duyck int band;
35192651940SAlexander Duyck
35292651940SAlexander Duyck if (arg->stop)
35392651940SAlexander Duyck return;
35492651940SAlexander Duyck
35592651940SAlexander Duyck for (band = 0; band < q->bands; band++) {
356e046fa89SZhengchao Shao if (!tc_qdisc_stats_dump(sch, band + 1, arg))
35792651940SAlexander Duyck break;
35892651940SAlexander Duyck }
35992651940SAlexander Duyck }
36092651940SAlexander Duyck
multiq_tcf_block(struct Qdisc * sch,unsigned long cl,struct netlink_ext_ack * extack)361cbaacc4eSAlexander Aring static struct tcf_block *multiq_tcf_block(struct Qdisc *sch, unsigned long cl,
362cbaacc4eSAlexander Aring struct netlink_ext_ack *extack)
36392651940SAlexander Duyck {
36492651940SAlexander Duyck struct multiq_sched_data *q = qdisc_priv(sch);
36592651940SAlexander Duyck
36692651940SAlexander Duyck if (cl)
36792651940SAlexander Duyck return NULL;
3686529eabaSJiri Pirko return q->block;
36992651940SAlexander Duyck }
37092651940SAlexander Duyck
37192651940SAlexander Duyck static const struct Qdisc_class_ops multiq_class_ops = {
37292651940SAlexander Duyck .graft = multiq_graft,
37392651940SAlexander Duyck .leaf = multiq_leaf,
374143976ceSWANG Cong .find = multiq_find,
37592651940SAlexander Duyck .walk = multiq_walk,
3766529eabaSJiri Pirko .tcf_block = multiq_tcf_block,
37792651940SAlexander Duyck .bind_tcf = multiq_bind,
378143976ceSWANG Cong .unbind_tcf = multiq_unbind,
37992651940SAlexander Duyck .dump = multiq_dump_class,
38092651940SAlexander Duyck .dump_stats = multiq_dump_class_stats,
38192651940SAlexander Duyck };
38292651940SAlexander Duyck
38392651940SAlexander Duyck static struct Qdisc_ops multiq_qdisc_ops __read_mostly = {
38492651940SAlexander Duyck .next = NULL,
38592651940SAlexander Duyck .cl_ops = &multiq_class_ops,
38692651940SAlexander Duyck .id = "multiq",
38792651940SAlexander Duyck .priv_size = sizeof(struct multiq_sched_data),
38892651940SAlexander Duyck .enqueue = multiq_enqueue,
38992651940SAlexander Duyck .dequeue = multiq_dequeue,
3908e3af978SJarek Poplawski .peek = multiq_peek,
39192651940SAlexander Duyck .init = multiq_init,
39292651940SAlexander Duyck .reset = multiq_reset,
39392651940SAlexander Duyck .destroy = multiq_destroy,
39492651940SAlexander Duyck .change = multiq_tune,
39592651940SAlexander Duyck .dump = multiq_dump,
39692651940SAlexander Duyck .owner = THIS_MODULE,
39792651940SAlexander Duyck };
39892651940SAlexander Duyck
multiq_module_init(void)39992651940SAlexander Duyck static int __init multiq_module_init(void)
40092651940SAlexander Duyck {
40192651940SAlexander Duyck return register_qdisc(&multiq_qdisc_ops);
40292651940SAlexander Duyck }
40392651940SAlexander Duyck
multiq_module_exit(void)40492651940SAlexander Duyck static void __exit multiq_module_exit(void)
40592651940SAlexander Duyck {
40692651940SAlexander Duyck unregister_qdisc(&multiq_qdisc_ops);
40792651940SAlexander Duyck }
40892651940SAlexander Duyck
40992651940SAlexander Duyck module_init(multiq_module_init)
41092651940SAlexander Duyck module_exit(multiq_module_exit)
41192651940SAlexander Duyck
41292651940SAlexander Duyck MODULE_LICENSE("GPL");
413