1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * net/sched/sch_mqprio.c 4 * 5 * Copyright (c) 2010 John Fastabend <john.r.fastabend@intel.com> 6 */ 7 8 #include <linux/types.h> 9 #include <linux/slab.h> 10 #include <linux/kernel.h> 11 #include <linux/string.h> 12 #include <linux/errno.h> 13 #include <linux/skbuff.h> 14 #include <linux/module.h> 15 #include <net/netlink.h> 16 #include <net/pkt_sched.h> 17 #include <net/sch_generic.h> 18 #include <net/pkt_cls.h> 19 20 #include "sch_mqprio_lib.h" 21 22 struct mqprio_sched { 23 struct Qdisc **qdiscs; 24 u16 mode; 25 u16 shaper; 26 int hw_offload; 27 u32 flags; 28 u64 min_rate[TC_QOPT_MAX_QUEUE]; 29 u64 max_rate[TC_QOPT_MAX_QUEUE]; 30 }; 31 32 static int mqprio_enable_offload(struct Qdisc *sch, 33 const struct tc_mqprio_qopt *qopt, 34 struct netlink_ext_ack *extack) 35 { 36 struct mqprio_sched *priv = qdisc_priv(sch); 37 struct net_device *dev = qdisc_dev(sch); 38 struct tc_mqprio_qopt_offload mqprio = { 39 .qopt = *qopt, 40 .extack = extack, 41 }; 42 int err, i; 43 44 switch (priv->mode) { 45 case TC_MQPRIO_MODE_DCB: 46 if (priv->shaper != TC_MQPRIO_SHAPER_DCB) 47 return -EINVAL; 48 break; 49 case TC_MQPRIO_MODE_CHANNEL: 50 mqprio.flags = priv->flags; 51 if (priv->flags & TC_MQPRIO_F_MODE) 52 mqprio.mode = priv->mode; 53 if (priv->flags & TC_MQPRIO_F_SHAPER) 54 mqprio.shaper = priv->shaper; 55 if (priv->flags & TC_MQPRIO_F_MIN_RATE) 56 for (i = 0; i < mqprio.qopt.num_tc; i++) 57 mqprio.min_rate[i] = priv->min_rate[i]; 58 if (priv->flags & TC_MQPRIO_F_MAX_RATE) 59 for (i = 0; i < mqprio.qopt.num_tc; i++) 60 mqprio.max_rate[i] = priv->max_rate[i]; 61 break; 62 default: 63 return -EINVAL; 64 } 65 66 err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_MQPRIO, 67 &mqprio); 68 if (err) 69 return err; 70 71 priv->hw_offload = mqprio.qopt.hw; 72 73 return 0; 74 } 75 76 static void mqprio_disable_offload(struct Qdisc *sch) 77 { 78 struct tc_mqprio_qopt_offload mqprio = { { 0 } }; 79 struct mqprio_sched *priv = qdisc_priv(sch); 80 struct net_device *dev = qdisc_dev(sch); 81 82 switch (priv->mode) { 83 case TC_MQPRIO_MODE_DCB: 84 case TC_MQPRIO_MODE_CHANNEL: 85 dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_MQPRIO, 86 &mqprio); 87 break; 88 } 89 } 90 91 static void mqprio_destroy(struct Qdisc *sch) 92 { 93 struct net_device *dev = qdisc_dev(sch); 94 struct mqprio_sched *priv = qdisc_priv(sch); 95 unsigned int ntx; 96 97 if (priv->qdiscs) { 98 for (ntx = 0; 99 ntx < dev->num_tx_queues && priv->qdiscs[ntx]; 100 ntx++) 101 qdisc_put(priv->qdiscs[ntx]); 102 kfree(priv->qdiscs); 103 } 104 105 if (priv->hw_offload && dev->netdev_ops->ndo_setup_tc) 106 mqprio_disable_offload(sch); 107 else 108 netdev_set_num_tc(dev, 0); 109 } 110 111 static int mqprio_parse_opt(struct net_device *dev, struct tc_mqprio_qopt *qopt, 112 const struct tc_mqprio_caps *caps, 113 struct netlink_ext_ack *extack) 114 { 115 int err; 116 117 /* Limit qopt->hw to maximum supported offload value. Drivers have 118 * the option of overriding this later if they don't support the a 119 * given offload type. 120 */ 121 if (qopt->hw > TC_MQPRIO_HW_OFFLOAD_MAX) 122 qopt->hw = TC_MQPRIO_HW_OFFLOAD_MAX; 123 124 /* If hardware offload is requested, we will leave 3 options to the 125 * device driver: 126 * - populate the queue counts itself (and ignore what was requested) 127 * - validate the provided queue counts by itself (and apply them) 128 * - request queue count validation here (and apply them) 129 */ 130 err = mqprio_validate_qopt(dev, qopt, 131 !qopt->hw || caps->validate_queue_counts, 132 false, extack); 133 if (err) 134 return err; 135 136 /* If ndo_setup_tc is not present then hardware doesn't support offload 137 * and we should return an error. 138 */ 139 if (qopt->hw && !dev->netdev_ops->ndo_setup_tc) { 140 NL_SET_ERR_MSG(extack, 141 "Device does not support hardware offload"); 142 return -EINVAL; 143 } 144 145 return 0; 146 } 147 148 static const struct nla_policy mqprio_policy[TCA_MQPRIO_MAX + 1] = { 149 [TCA_MQPRIO_MODE] = { .len = sizeof(u16) }, 150 [TCA_MQPRIO_SHAPER] = { .len = sizeof(u16) }, 151 [TCA_MQPRIO_MIN_RATE64] = { .type = NLA_NESTED }, 152 [TCA_MQPRIO_MAX_RATE64] = { .type = NLA_NESTED }, 153 }; 154 155 /* Parse the other netlink attributes that represent the payload of 156 * TCA_OPTIONS, which are appended right after struct tc_mqprio_qopt. 157 */ 158 static int mqprio_parse_nlattr(struct Qdisc *sch, struct tc_mqprio_qopt *qopt, 159 struct nlattr *opt, 160 struct netlink_ext_ack *extack) 161 { 162 struct nlattr *nlattr_opt = nla_data(opt) + NLA_ALIGN(sizeof(*qopt)); 163 int nlattr_opt_len = nla_len(opt) - NLA_ALIGN(sizeof(*qopt)); 164 struct mqprio_sched *priv = qdisc_priv(sch); 165 struct nlattr *tb[TCA_MQPRIO_MAX + 1] = {}; 166 struct nlattr *attr; 167 int i, rem, err; 168 169 if (nlattr_opt_len >= nla_attr_size(0)) { 170 err = nla_parse_deprecated(tb, TCA_MQPRIO_MAX, nlattr_opt, 171 nlattr_opt_len, mqprio_policy, 172 NULL); 173 if (err < 0) 174 return err; 175 } 176 177 if (!qopt->hw) { 178 NL_SET_ERR_MSG(extack, 179 "mqprio TCA_OPTIONS can only contain netlink attributes in hardware mode"); 180 return -EINVAL; 181 } 182 183 if (tb[TCA_MQPRIO_MODE]) { 184 priv->flags |= TC_MQPRIO_F_MODE; 185 priv->mode = nla_get_u16(tb[TCA_MQPRIO_MODE]); 186 } 187 188 if (tb[TCA_MQPRIO_SHAPER]) { 189 priv->flags |= TC_MQPRIO_F_SHAPER; 190 priv->shaper = nla_get_u16(tb[TCA_MQPRIO_SHAPER]); 191 } 192 193 if (tb[TCA_MQPRIO_MIN_RATE64]) { 194 if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) { 195 NL_SET_ERR_MSG_ATTR(extack, tb[TCA_MQPRIO_MIN_RATE64], 196 "min_rate accepted only when shaper is in bw_rlimit mode"); 197 return -EINVAL; 198 } 199 i = 0; 200 nla_for_each_nested(attr, tb[TCA_MQPRIO_MIN_RATE64], 201 rem) { 202 if (nla_type(attr) != TCA_MQPRIO_MIN_RATE64) { 203 NL_SET_ERR_MSG_ATTR(extack, attr, 204 "Attribute type expected to be TCA_MQPRIO_MIN_RATE64"); 205 return -EINVAL; 206 } 207 if (i >= qopt->num_tc) 208 break; 209 priv->min_rate[i] = nla_get_u64(attr); 210 i++; 211 } 212 priv->flags |= TC_MQPRIO_F_MIN_RATE; 213 } 214 215 if (tb[TCA_MQPRIO_MAX_RATE64]) { 216 if (priv->shaper != TC_MQPRIO_SHAPER_BW_RATE) { 217 NL_SET_ERR_MSG_ATTR(extack, tb[TCA_MQPRIO_MAX_RATE64], 218 "max_rate accepted only when shaper is in bw_rlimit mode"); 219 return -EINVAL; 220 } 221 i = 0; 222 nla_for_each_nested(attr, tb[TCA_MQPRIO_MAX_RATE64], 223 rem) { 224 if (nla_type(attr) != TCA_MQPRIO_MAX_RATE64) { 225 NL_SET_ERR_MSG_ATTR(extack, attr, 226 "Attribute type expected to be TCA_MQPRIO_MAX_RATE64"); 227 return -EINVAL; 228 } 229 if (i >= qopt->num_tc) 230 break; 231 priv->max_rate[i] = nla_get_u64(attr); 232 i++; 233 } 234 priv->flags |= TC_MQPRIO_F_MAX_RATE; 235 } 236 237 return 0; 238 } 239 240 static int mqprio_init(struct Qdisc *sch, struct nlattr *opt, 241 struct netlink_ext_ack *extack) 242 { 243 struct net_device *dev = qdisc_dev(sch); 244 struct mqprio_sched *priv = qdisc_priv(sch); 245 struct netdev_queue *dev_queue; 246 struct Qdisc *qdisc; 247 int i, err = -EOPNOTSUPP; 248 struct tc_mqprio_qopt *qopt = NULL; 249 struct tc_mqprio_caps caps; 250 int len; 251 252 BUILD_BUG_ON(TC_MAX_QUEUE != TC_QOPT_MAX_QUEUE); 253 BUILD_BUG_ON(TC_BITMASK != TC_QOPT_BITMASK); 254 255 if (sch->parent != TC_H_ROOT) 256 return -EOPNOTSUPP; 257 258 if (!netif_is_multiqueue(dev)) 259 return -EOPNOTSUPP; 260 261 /* make certain can allocate enough classids to handle queues */ 262 if (dev->num_tx_queues >= TC_H_MIN_PRIORITY) 263 return -ENOMEM; 264 265 if (!opt || nla_len(opt) < sizeof(*qopt)) 266 return -EINVAL; 267 268 qdisc_offload_query_caps(dev, TC_SETUP_QDISC_MQPRIO, 269 &caps, sizeof(caps)); 270 271 qopt = nla_data(opt); 272 if (mqprio_parse_opt(dev, qopt, &caps, extack)) 273 return -EINVAL; 274 275 len = nla_len(opt) - NLA_ALIGN(sizeof(*qopt)); 276 if (len > 0) { 277 err = mqprio_parse_nlattr(sch, qopt, opt, extack); 278 if (err) 279 return err; 280 } 281 282 /* pre-allocate qdisc, attachment can't fail */ 283 priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]), 284 GFP_KERNEL); 285 if (!priv->qdiscs) 286 return -ENOMEM; 287 288 for (i = 0; i < dev->num_tx_queues; i++) { 289 dev_queue = netdev_get_tx_queue(dev, i); 290 qdisc = qdisc_create_dflt(dev_queue, 291 get_default_qdisc_ops(dev, i), 292 TC_H_MAKE(TC_H_MAJ(sch->handle), 293 TC_H_MIN(i + 1)), extack); 294 if (!qdisc) 295 return -ENOMEM; 296 297 priv->qdiscs[i] = qdisc; 298 qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; 299 } 300 301 /* If the mqprio options indicate that hardware should own 302 * the queue mapping then run ndo_setup_tc otherwise use the 303 * supplied and verified mapping 304 */ 305 if (qopt->hw) { 306 err = mqprio_enable_offload(sch, qopt, extack); 307 if (err) 308 return err; 309 } else { 310 netdev_set_num_tc(dev, qopt->num_tc); 311 for (i = 0; i < qopt->num_tc; i++) 312 netdev_set_tc_queue(dev, i, 313 qopt->count[i], qopt->offset[i]); 314 } 315 316 /* Always use supplied priority mappings */ 317 for (i = 0; i < TC_BITMASK + 1; i++) 318 netdev_set_prio_tc_map(dev, i, qopt->prio_tc_map[i]); 319 320 sch->flags |= TCQ_F_MQROOT; 321 return 0; 322 } 323 324 static void mqprio_attach(struct Qdisc *sch) 325 { 326 struct net_device *dev = qdisc_dev(sch); 327 struct mqprio_sched *priv = qdisc_priv(sch); 328 struct Qdisc *qdisc, *old; 329 unsigned int ntx; 330 331 /* Attach underlying qdisc */ 332 for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { 333 qdisc = priv->qdiscs[ntx]; 334 old = dev_graft_qdisc(qdisc->dev_queue, qdisc); 335 if (old) 336 qdisc_put(old); 337 if (ntx < dev->real_num_tx_queues) 338 qdisc_hash_add(qdisc, false); 339 } 340 kfree(priv->qdiscs); 341 priv->qdiscs = NULL; 342 } 343 344 static struct netdev_queue *mqprio_queue_get(struct Qdisc *sch, 345 unsigned long cl) 346 { 347 struct net_device *dev = qdisc_dev(sch); 348 unsigned long ntx = cl - 1; 349 350 if (ntx >= dev->num_tx_queues) 351 return NULL; 352 return netdev_get_tx_queue(dev, ntx); 353 } 354 355 static int mqprio_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, 356 struct Qdisc **old, struct netlink_ext_ack *extack) 357 { 358 struct net_device *dev = qdisc_dev(sch); 359 struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl); 360 361 if (!dev_queue) 362 return -EINVAL; 363 364 if (dev->flags & IFF_UP) 365 dev_deactivate(dev); 366 367 *old = dev_graft_qdisc(dev_queue, new); 368 369 if (new) 370 new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; 371 372 if (dev->flags & IFF_UP) 373 dev_activate(dev); 374 375 return 0; 376 } 377 378 static int dump_rates(struct mqprio_sched *priv, 379 struct tc_mqprio_qopt *opt, struct sk_buff *skb) 380 { 381 struct nlattr *nest; 382 int i; 383 384 if (priv->flags & TC_MQPRIO_F_MIN_RATE) { 385 nest = nla_nest_start_noflag(skb, TCA_MQPRIO_MIN_RATE64); 386 if (!nest) 387 goto nla_put_failure; 388 389 for (i = 0; i < opt->num_tc; i++) { 390 if (nla_put(skb, TCA_MQPRIO_MIN_RATE64, 391 sizeof(priv->min_rate[i]), 392 &priv->min_rate[i])) 393 goto nla_put_failure; 394 } 395 nla_nest_end(skb, nest); 396 } 397 398 if (priv->flags & TC_MQPRIO_F_MAX_RATE) { 399 nest = nla_nest_start_noflag(skb, TCA_MQPRIO_MAX_RATE64); 400 if (!nest) 401 goto nla_put_failure; 402 403 for (i = 0; i < opt->num_tc; i++) { 404 if (nla_put(skb, TCA_MQPRIO_MAX_RATE64, 405 sizeof(priv->max_rate[i]), 406 &priv->max_rate[i])) 407 goto nla_put_failure; 408 } 409 nla_nest_end(skb, nest); 410 } 411 return 0; 412 413 nla_put_failure: 414 nla_nest_cancel(skb, nest); 415 return -1; 416 } 417 418 static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb) 419 { 420 struct net_device *dev = qdisc_dev(sch); 421 struct mqprio_sched *priv = qdisc_priv(sch); 422 struct nlattr *nla = (struct nlattr *)skb_tail_pointer(skb); 423 struct tc_mqprio_qopt opt = { 0 }; 424 struct Qdisc *qdisc; 425 unsigned int ntx; 426 427 sch->q.qlen = 0; 428 gnet_stats_basic_sync_init(&sch->bstats); 429 memset(&sch->qstats, 0, sizeof(sch->qstats)); 430 431 /* MQ supports lockless qdiscs. However, statistics accounting needs 432 * to account for all, none, or a mix of locked and unlocked child 433 * qdiscs. Percpu stats are added to counters in-band and locking 434 * qdisc totals are added at end. 435 */ 436 for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { 437 qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping; 438 spin_lock_bh(qdisc_lock(qdisc)); 439 440 gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats, 441 &qdisc->bstats, false); 442 gnet_stats_add_queue(&sch->qstats, qdisc->cpu_qstats, 443 &qdisc->qstats); 444 sch->q.qlen += qdisc_qlen(qdisc); 445 446 spin_unlock_bh(qdisc_lock(qdisc)); 447 } 448 449 mqprio_qopt_reconstruct(dev, &opt); 450 opt.hw = priv->hw_offload; 451 452 if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) 453 goto nla_put_failure; 454 455 if ((priv->flags & TC_MQPRIO_F_MODE) && 456 nla_put_u16(skb, TCA_MQPRIO_MODE, priv->mode)) 457 goto nla_put_failure; 458 459 if ((priv->flags & TC_MQPRIO_F_SHAPER) && 460 nla_put_u16(skb, TCA_MQPRIO_SHAPER, priv->shaper)) 461 goto nla_put_failure; 462 463 if ((priv->flags & TC_MQPRIO_F_MIN_RATE || 464 priv->flags & TC_MQPRIO_F_MAX_RATE) && 465 (dump_rates(priv, &opt, skb) != 0)) 466 goto nla_put_failure; 467 468 return nla_nest_end(skb, nla); 469 nla_put_failure: 470 nlmsg_trim(skb, nla); 471 return -1; 472 } 473 474 static struct Qdisc *mqprio_leaf(struct Qdisc *sch, unsigned long cl) 475 { 476 struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl); 477 478 if (!dev_queue) 479 return NULL; 480 481 return dev_queue->qdisc_sleeping; 482 } 483 484 static unsigned long mqprio_find(struct Qdisc *sch, u32 classid) 485 { 486 struct net_device *dev = qdisc_dev(sch); 487 unsigned int ntx = TC_H_MIN(classid); 488 489 /* There are essentially two regions here that have valid classid 490 * values. The first region will have a classid value of 1 through 491 * num_tx_queues. All of these are backed by actual Qdiscs. 492 */ 493 if (ntx < TC_H_MIN_PRIORITY) 494 return (ntx <= dev->num_tx_queues) ? ntx : 0; 495 496 /* The second region represents the hardware traffic classes. These 497 * are represented by classid values of TC_H_MIN_PRIORITY through 498 * TC_H_MIN_PRIORITY + netdev_get_num_tc - 1 499 */ 500 return ((ntx - TC_H_MIN_PRIORITY) < netdev_get_num_tc(dev)) ? ntx : 0; 501 } 502 503 static int mqprio_dump_class(struct Qdisc *sch, unsigned long cl, 504 struct sk_buff *skb, struct tcmsg *tcm) 505 { 506 if (cl < TC_H_MIN_PRIORITY) { 507 struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl); 508 struct net_device *dev = qdisc_dev(sch); 509 int tc = netdev_txq_to_tc(dev, cl - 1); 510 511 tcm->tcm_parent = (tc < 0) ? 0 : 512 TC_H_MAKE(TC_H_MAJ(sch->handle), 513 TC_H_MIN(tc + TC_H_MIN_PRIORITY)); 514 tcm->tcm_info = dev_queue->qdisc_sleeping->handle; 515 } else { 516 tcm->tcm_parent = TC_H_ROOT; 517 tcm->tcm_info = 0; 518 } 519 tcm->tcm_handle |= TC_H_MIN(cl); 520 return 0; 521 } 522 523 static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, 524 struct gnet_dump *d) 525 __releases(d->lock) 526 __acquires(d->lock) 527 { 528 if (cl >= TC_H_MIN_PRIORITY) { 529 int i; 530 __u32 qlen; 531 struct gnet_stats_queue qstats = {0}; 532 struct gnet_stats_basic_sync bstats; 533 struct net_device *dev = qdisc_dev(sch); 534 struct netdev_tc_txq tc = dev->tc_to_txq[cl & TC_BITMASK]; 535 536 gnet_stats_basic_sync_init(&bstats); 537 /* Drop lock here it will be reclaimed before touching 538 * statistics this is required because the d->lock we 539 * hold here is the look on dev_queue->qdisc_sleeping 540 * also acquired below. 541 */ 542 if (d->lock) 543 spin_unlock_bh(d->lock); 544 545 for (i = tc.offset; i < tc.offset + tc.count; i++) { 546 struct netdev_queue *q = netdev_get_tx_queue(dev, i); 547 struct Qdisc *qdisc = rtnl_dereference(q->qdisc); 548 549 spin_lock_bh(qdisc_lock(qdisc)); 550 551 gnet_stats_add_basic(&bstats, qdisc->cpu_bstats, 552 &qdisc->bstats, false); 553 gnet_stats_add_queue(&qstats, qdisc->cpu_qstats, 554 &qdisc->qstats); 555 sch->q.qlen += qdisc_qlen(qdisc); 556 557 spin_unlock_bh(qdisc_lock(qdisc)); 558 } 559 qlen = qdisc_qlen(sch) + qstats.qlen; 560 561 /* Reclaim root sleeping lock before completing stats */ 562 if (d->lock) 563 spin_lock_bh(d->lock); 564 if (gnet_stats_copy_basic(d, NULL, &bstats, false) < 0 || 565 gnet_stats_copy_queue(d, NULL, &qstats, qlen) < 0) 566 return -1; 567 } else { 568 struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl); 569 570 sch = dev_queue->qdisc_sleeping; 571 if (gnet_stats_copy_basic(d, sch->cpu_bstats, 572 &sch->bstats, true) < 0 || 573 qdisc_qstats_copy(d, sch) < 0) 574 return -1; 575 } 576 return 0; 577 } 578 579 static void mqprio_walk(struct Qdisc *sch, struct qdisc_walker *arg) 580 { 581 struct net_device *dev = qdisc_dev(sch); 582 unsigned long ntx; 583 584 if (arg->stop) 585 return; 586 587 /* Walk hierarchy with a virtual class per tc */ 588 arg->count = arg->skip; 589 for (ntx = arg->skip; ntx < netdev_get_num_tc(dev); ntx++) { 590 if (!tc_qdisc_stats_dump(sch, ntx + TC_H_MIN_PRIORITY, arg)) 591 return; 592 } 593 594 /* Pad the values and skip over unused traffic classes */ 595 if (ntx < TC_MAX_QUEUE) { 596 arg->count = TC_MAX_QUEUE; 597 ntx = TC_MAX_QUEUE; 598 } 599 600 /* Reset offset, sort out remaining per-queue qdiscs */ 601 for (ntx -= TC_MAX_QUEUE; ntx < dev->num_tx_queues; ntx++) { 602 if (arg->fn(sch, ntx + 1, arg) < 0) { 603 arg->stop = 1; 604 return; 605 } 606 arg->count++; 607 } 608 } 609 610 static struct netdev_queue *mqprio_select_queue(struct Qdisc *sch, 611 struct tcmsg *tcm) 612 { 613 return mqprio_queue_get(sch, TC_H_MIN(tcm->tcm_parent)); 614 } 615 616 static const struct Qdisc_class_ops mqprio_class_ops = { 617 .graft = mqprio_graft, 618 .leaf = mqprio_leaf, 619 .find = mqprio_find, 620 .walk = mqprio_walk, 621 .dump = mqprio_dump_class, 622 .dump_stats = mqprio_dump_class_stats, 623 .select_queue = mqprio_select_queue, 624 }; 625 626 static struct Qdisc_ops mqprio_qdisc_ops __read_mostly = { 627 .cl_ops = &mqprio_class_ops, 628 .id = "mqprio", 629 .priv_size = sizeof(struct mqprio_sched), 630 .init = mqprio_init, 631 .destroy = mqprio_destroy, 632 .attach = mqprio_attach, 633 .change_real_num_tx = mq_change_real_num_tx, 634 .dump = mqprio_dump, 635 .owner = THIS_MODULE, 636 }; 637 638 static int __init mqprio_module_init(void) 639 { 640 return register_qdisc(&mqprio_qdisc_ops); 641 } 642 643 static void __exit mqprio_module_exit(void) 644 { 645 unregister_qdisc(&mqprio_qdisc_ops); 646 } 647 648 module_init(mqprio_module_init); 649 module_exit(mqprio_module_exit); 650 651 MODULE_LICENSE("GPL"); 652