sch_ets.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * net/sched/sch_ets.c Enhanced Transmission Selection scheduler
  4. *
  5. * Description
  6. * -----------
  7. *
  8. * The Enhanced Transmission Selection scheduler is a classful queuing
  9. * discipline that merges functionality of PRIO and DRR qdiscs in one scheduler.
  10. * ETS makes it easy to configure a set of strict and bandwidth-sharing bands to
  11. * implement the transmission selection described in 802.1Qaz.
  12. *
  13. * Although ETS is technically classful, it's not possible to add and remove
  14. * classes at will. Instead one specifies number of classes, how many are
  15. * PRIO-like and how many DRR-like, and quanta for the latter.
  16. *
  17. * Algorithm
  18. * ---------
  19. *
  20. * The strict classes, if any, are tried for traffic first: first band 0, if it
  21. * has no traffic then band 1, etc.
  22. *
  23. * When there is no traffic in any of the strict queues, the bandwidth-sharing
  24. * ones are tried next. Each band is assigned a deficit counter, initialized to
  25. * "quantum" of that band. ETS maintains a list of active bandwidth-sharing
  26. * bands whose qdiscs are non-empty. A packet is dequeued from the band at the
  27. * head of the list if the packet size is smaller or equal to the deficit
  28. * counter. If the counter is too small, it is increased by "quantum" and the
  29. * scheduler moves on to the next band in the active list.
  30. */
  31. #include <linux/module.h>
  32. #include <net/gen_stats.h>
  33. #include <net/netlink.h>
  34. #include <net/pkt_cls.h>
  35. #include <net/pkt_sched.h>
  36. #include <net/sch_generic.h>
  37. struct ets_class {
  38. struct list_head alist; /* In struct ets_sched.active. */
  39. struct Qdisc *qdisc;
  40. u32 quantum;
  41. u32 deficit;
  42. struct gnet_stats_basic_sync bstats;
  43. struct gnet_stats_queue qstats;
  44. };
  45. struct ets_sched {
  46. struct list_head active;
  47. struct tcf_proto __rcu *filter_list;
  48. struct tcf_block *block;
  49. unsigned int nbands;
  50. unsigned int nstrict;
  51. u8 prio2band[TC_PRIO_MAX + 1];
  52. struct ets_class classes[TCQ_ETS_MAX_BANDS];
  53. };
  54. static const struct nla_policy ets_policy[TCA_ETS_MAX + 1] = {
  55. [TCA_ETS_NBANDS] = { .type = NLA_U8 },
  56. [TCA_ETS_NSTRICT] = { .type = NLA_U8 },
  57. [TCA_ETS_QUANTA] = { .type = NLA_NESTED },
  58. [TCA_ETS_PRIOMAP] = { .type = NLA_NESTED },
  59. };
  60. static const struct nla_policy ets_priomap_policy[TCA_ETS_MAX + 1] = {
  61. [TCA_ETS_PRIOMAP_BAND] = { .type = NLA_U8 },
  62. };
  63. static const struct nla_policy ets_quanta_policy[TCA_ETS_MAX + 1] = {
  64. [TCA_ETS_QUANTA_BAND] = { .type = NLA_U32 },
  65. };
  66. static const struct nla_policy ets_class_policy[TCA_ETS_MAX + 1] = {
  67. [TCA_ETS_QUANTA_BAND] = { .type = NLA_U32 },
  68. };
  69. static bool cl_is_active(struct ets_class *cl)
  70. {
  71. return !list_empty(&cl->alist);
  72. }
  73. static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr,
  74. unsigned int *quantum,
  75. struct netlink_ext_ack *extack)
  76. {
  77. *quantum = nla_get_u32(attr);
  78. if (!*quantum) {
  79. NL_SET_ERR_MSG(extack, "ETS quantum cannot be zero");
  80. return -EINVAL;
  81. }
  82. return 0;
  83. }
  84. static struct ets_class *
  85. ets_class_from_arg(struct Qdisc *sch, unsigned long arg)
  86. {
  87. struct ets_sched *q = qdisc_priv(sch);
  88. if (arg == 0 || arg > q->nbands)
  89. return NULL;
  90. return &q->classes[arg - 1];
  91. }
  92. static u32 ets_class_id(struct Qdisc *sch, const struct ets_class *cl)
  93. {
  94. struct ets_sched *q = qdisc_priv(sch);
  95. int band = cl - q->classes;
  96. return TC_H_MAKE(sch->handle, band + 1);
  97. }
  98. static void ets_offload_change(struct Qdisc *sch)
  99. {
  100. struct net_device *dev = qdisc_dev(sch);
  101. struct ets_sched *q = qdisc_priv(sch);
  102. struct tc_ets_qopt_offload qopt;
  103. unsigned int w_psum_prev = 0;
  104. unsigned int q_psum = 0;
  105. unsigned int q_sum = 0;
  106. unsigned int quantum;
  107. unsigned int w_psum;
  108. unsigned int weight;
  109. unsigned int i;
  110. if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
  111. return;
  112. qopt.command = TC_ETS_REPLACE;
  113. qopt.handle = sch->handle;
  114. qopt.parent = sch->parent;
  115. qopt.replace_params.bands = q->nbands;
  116. qopt.replace_params.qstats = &sch->qstats;
  117. memcpy(&qopt.replace_params.priomap,
  118. q->prio2band, sizeof(q->prio2band));
  119. for (i = 0; i < q->nbands; i++)
  120. q_sum += q->classes[i].quantum;
  121. for (i = 0; i < q->nbands; i++) {
  122. quantum = q->classes[i].quantum;
  123. q_psum += quantum;
  124. w_psum = quantum ? q_psum * 100 / q_sum : 0;
  125. weight = w_psum - w_psum_prev;
  126. w_psum_prev = w_psum;
  127. qopt.replace_params.quanta[i] = quantum;
  128. qopt.replace_params.weights[i] = weight;
  129. }
  130. dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETS, &qopt);
  131. }
  132. static void ets_offload_destroy(struct Qdisc *sch)
  133. {
  134. struct net_device *dev = qdisc_dev(sch);
  135. struct tc_ets_qopt_offload qopt;
  136. if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
  137. return;
  138. qopt.command = TC_ETS_DESTROY;
  139. qopt.handle = sch->handle;
  140. qopt.parent = sch->parent;
  141. dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETS, &qopt);
  142. }
  143. static void ets_offload_graft(struct Qdisc *sch, struct Qdisc *new,
  144. struct Qdisc *old, unsigned long arg,
  145. struct netlink_ext_ack *extack)
  146. {
  147. struct net_device *dev = qdisc_dev(sch);
  148. struct tc_ets_qopt_offload qopt;
  149. qopt.command = TC_ETS_GRAFT;
  150. qopt.handle = sch->handle;
  151. qopt.parent = sch->parent;
  152. qopt.graft_params.band = arg - 1;
  153. qopt.graft_params.child_handle = new->handle;
  154. qdisc_offload_graft_helper(dev, sch, new, old, TC_SETUP_QDISC_ETS,
  155. &qopt, extack);
  156. }
  157. static int ets_offload_dump(struct Qdisc *sch)
  158. {
  159. struct tc_ets_qopt_offload qopt;
  160. qopt.command = TC_ETS_STATS;
  161. qopt.handle = sch->handle;
  162. qopt.parent = sch->parent;
  163. qopt.stats.bstats = &sch->bstats;
  164. qopt.stats.qstats = &sch->qstats;
  165. return qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_ETS, &qopt);
  166. }
  167. static bool ets_class_is_strict(struct ets_sched *q, const struct ets_class *cl)
  168. {
  169. unsigned int band = cl - q->classes;
  170. return band < q->nstrict;
  171. }
  172. static int ets_class_change(struct Qdisc *sch, u32 classid, u32 parentid,
  173. struct nlattr **tca, unsigned long *arg,
  174. struct netlink_ext_ack *extack)
  175. {
  176. struct ets_class *cl = ets_class_from_arg(sch, *arg);
  177. struct ets_sched *q = qdisc_priv(sch);
  178. struct nlattr *opt = tca[TCA_OPTIONS];
  179. struct nlattr *tb[TCA_ETS_MAX + 1];
  180. unsigned int quantum;
  181. int err;
  182. /* Classes can be added and removed only through Qdisc_ops.change
  183. * interface.
  184. */
  185. if (!cl) {
  186. NL_SET_ERR_MSG(extack, "Fine-grained class addition and removal is not supported");
  187. return -EOPNOTSUPP;
  188. }
  189. if (!opt) {
  190. NL_SET_ERR_MSG(extack, "ETS options are required for this operation");
  191. return -EINVAL;
  192. }
  193. err = nla_parse_nested(tb, TCA_ETS_MAX, opt, ets_class_policy, extack);
  194. if (err < 0)
  195. return err;
  196. if (!tb[TCA_ETS_QUANTA_BAND])
  197. /* Nothing to configure. */
  198. return 0;
  199. if (ets_class_is_strict(q, cl)) {
  200. NL_SET_ERR_MSG(extack, "Strict bands do not have a configurable quantum");
  201. return -EINVAL;
  202. }
  203. err = ets_quantum_parse(sch, tb[TCA_ETS_QUANTA_BAND], &quantum,
  204. extack);
  205. if (err)
  206. return err;
  207. sch_tree_lock(sch);
  208. cl->quantum = quantum;
  209. sch_tree_unlock(sch);
  210. ets_offload_change(sch);
  211. return 0;
  212. }
  213. static int ets_class_graft(struct Qdisc *sch, unsigned long arg,
  214. struct Qdisc *new, struct Qdisc **old,
  215. struct netlink_ext_ack *extack)
  216. {
  217. struct ets_class *cl = ets_class_from_arg(sch, arg);
  218. if (!new) {
  219. new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
  220. ets_class_id(sch, cl), NULL);
  221. if (!new)
  222. new = &noop_qdisc;
  223. else
  224. qdisc_hash_add(new, true);
  225. }
  226. *old = qdisc_replace(sch, new, &cl->qdisc);
  227. ets_offload_graft(sch, new, *old, arg, extack);
  228. return 0;
  229. }
  230. static struct Qdisc *ets_class_leaf(struct Qdisc *sch, unsigned long arg)
  231. {
  232. struct ets_class *cl = ets_class_from_arg(sch, arg);
  233. return cl->qdisc;
  234. }
  235. static unsigned long ets_class_find(struct Qdisc *sch, u32 classid)
  236. {
  237. unsigned long band = TC_H_MIN(classid);
  238. struct ets_sched *q = qdisc_priv(sch);
  239. if (band - 1 >= q->nbands)
  240. return 0;
  241. return band;
  242. }
  243. static void ets_class_qlen_notify(struct Qdisc *sch, unsigned long arg)
  244. {
  245. struct ets_class *cl = ets_class_from_arg(sch, arg);
  246. struct ets_sched *q = qdisc_priv(sch);
  247. /* We get notified about zero-length child Qdiscs as well if they are
  248. * offloaded. Those aren't on the active list though, so don't attempt
  249. * to remove them.
  250. */
  251. if (!ets_class_is_strict(q, cl) && sch->q.qlen)
  252. list_del_init(&cl->alist);
  253. }
  254. static int ets_class_dump(struct Qdisc *sch, unsigned long arg,
  255. struct sk_buff *skb, struct tcmsg *tcm)
  256. {
  257. struct ets_class *cl = ets_class_from_arg(sch, arg);
  258. struct ets_sched *q = qdisc_priv(sch);
  259. struct nlattr *nest;
  260. tcm->tcm_parent = TC_H_ROOT;
  261. tcm->tcm_handle = ets_class_id(sch, cl);
  262. tcm->tcm_info = cl->qdisc->handle;
  263. nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
  264. if (!nest)
  265. goto nla_put_failure;
  266. if (!ets_class_is_strict(q, cl)) {
  267. if (nla_put_u32(skb, TCA_ETS_QUANTA_BAND, cl->quantum))
  268. goto nla_put_failure;
  269. }
  270. return nla_nest_end(skb, nest);
  271. nla_put_failure:
  272. nla_nest_cancel(skb, nest);
  273. return -EMSGSIZE;
  274. }
  275. static int ets_class_dump_stats(struct Qdisc *sch, unsigned long arg,
  276. struct gnet_dump *d)
  277. {
  278. struct ets_class *cl = ets_class_from_arg(sch, arg);
  279. struct Qdisc *cl_q = cl->qdisc;
  280. if (gnet_stats_copy_basic(d, NULL, &cl_q->bstats, true) < 0 ||
  281. qdisc_qstats_copy(d, cl_q) < 0)
  282. return -1;
  283. return 0;
  284. }
  285. static void ets_qdisc_walk(struct Qdisc *sch, struct qdisc_walker *arg)
  286. {
  287. struct ets_sched *q = qdisc_priv(sch);
  288. int i;
  289. if (arg->stop)
  290. return;
  291. for (i = 0; i < q->nbands; i++) {
  292. if (!tc_qdisc_stats_dump(sch, i + 1, arg))
  293. break;
  294. }
  295. }
  296. static struct tcf_block *
  297. ets_qdisc_tcf_block(struct Qdisc *sch, unsigned long cl,
  298. struct netlink_ext_ack *extack)
  299. {
  300. struct ets_sched *q = qdisc_priv(sch);
  301. if (cl) {
  302. NL_SET_ERR_MSG(extack, "ETS classid must be zero");
  303. return NULL;
  304. }
  305. return q->block;
  306. }
  307. static unsigned long ets_qdisc_bind_tcf(struct Qdisc *sch, unsigned long parent,
  308. u32 classid)
  309. {
  310. return ets_class_find(sch, classid);
  311. }
  312. static void ets_qdisc_unbind_tcf(struct Qdisc *sch, unsigned long arg)
  313. {
  314. }
  315. static struct ets_class *ets_classify(struct sk_buff *skb, struct Qdisc *sch,
  316. int *qerr)
  317. {
  318. struct ets_sched *q = qdisc_priv(sch);
  319. u32 band = skb->priority;
  320. struct tcf_result res;
  321. struct tcf_proto *fl;
  322. int err;
  323. *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
  324. if (TC_H_MAJ(skb->priority) != sch->handle) {
  325. fl = rcu_dereference_bh(q->filter_list);
  326. err = tcf_classify(skb, NULL, fl, &res, false);
  327. #ifdef CONFIG_NET_CLS_ACT
  328. switch (err) {
  329. case TC_ACT_STOLEN:
  330. case TC_ACT_QUEUED:
  331. case TC_ACT_TRAP:
  332. *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
  333. fallthrough;
  334. case TC_ACT_SHOT:
  335. return NULL;
  336. }
  337. #endif
  338. if (!fl || err < 0) {
  339. if (TC_H_MAJ(band))
  340. band = 0;
  341. return &q->classes[q->prio2band[band & TC_PRIO_MAX]];
  342. }
  343. band = res.classid;
  344. }
  345. band = TC_H_MIN(band) - 1;
  346. if (band >= q->nbands)
  347. return &q->classes[q->prio2band[0]];
  348. return &q->classes[band];
  349. }
  350. static int ets_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
  351. struct sk_buff **to_free)
  352. {
  353. unsigned int len = qdisc_pkt_len(skb);
  354. struct ets_sched *q = qdisc_priv(sch);
  355. struct ets_class *cl;
  356. int err = 0;
  357. cl = ets_classify(skb, sch, &err);
  358. if (!cl) {
  359. if (err & __NET_XMIT_BYPASS)
  360. qdisc_qstats_drop(sch);
  361. __qdisc_drop(skb, to_free);
  362. return err;
  363. }
  364. err = qdisc_enqueue(skb, cl->qdisc, to_free);
  365. if (unlikely(err != NET_XMIT_SUCCESS)) {
  366. if (net_xmit_drop_count(err)) {
  367. cl->qstats.drops++;
  368. qdisc_qstats_drop(sch);
  369. }
  370. return err;
  371. }
  372. if (!cl_is_active(cl) && !ets_class_is_strict(q, cl)) {
  373. list_add_tail(&cl->alist, &q->active);
  374. cl->deficit = cl->quantum;
  375. }
  376. sch->qstats.backlog += len;
  377. sch->q.qlen++;
  378. return err;
  379. }
  380. static struct sk_buff *
  381. ets_qdisc_dequeue_skb(struct Qdisc *sch, struct sk_buff *skb)
  382. {
  383. qdisc_bstats_update(sch, skb);
  384. qdisc_qstats_backlog_dec(sch, skb);
  385. sch->q.qlen--;
  386. return skb;
  387. }
  388. static struct sk_buff *ets_qdisc_dequeue(struct Qdisc *sch)
  389. {
  390. struct ets_sched *q = qdisc_priv(sch);
  391. struct ets_class *cl;
  392. struct sk_buff *skb;
  393. unsigned int band;
  394. unsigned int len;
  395. while (1) {
  396. for (band = 0; band < q->nstrict; band++) {
  397. cl = &q->classes[band];
  398. skb = qdisc_dequeue_peeked(cl->qdisc);
  399. if (skb)
  400. return ets_qdisc_dequeue_skb(sch, skb);
  401. }
  402. if (list_empty(&q->active))
  403. goto out;
  404. cl = list_first_entry(&q->active, struct ets_class, alist);
  405. skb = cl->qdisc->ops->peek(cl->qdisc);
  406. if (!skb) {
  407. qdisc_warn_nonwc(__func__, cl->qdisc);
  408. goto out;
  409. }
  410. len = qdisc_pkt_len(skb);
  411. if (len <= cl->deficit) {
  412. cl->deficit -= len;
  413. skb = qdisc_dequeue_peeked(cl->qdisc);
  414. if (unlikely(!skb))
  415. goto out;
  416. if (cl->qdisc->q.qlen == 0)
  417. list_del_init(&cl->alist);
  418. return ets_qdisc_dequeue_skb(sch, skb);
  419. }
  420. cl->deficit += cl->quantum;
  421. list_move_tail(&cl->alist, &q->active);
  422. }
  423. out:
  424. return NULL;
  425. }
  426. static int ets_qdisc_priomap_parse(struct nlattr *priomap_attr,
  427. unsigned int nbands, u8 *priomap,
  428. struct netlink_ext_ack *extack)
  429. {
  430. const struct nlattr *attr;
  431. int prio = 0;
  432. u8 band;
  433. int rem;
  434. int err;
  435. err = __nla_validate_nested(priomap_attr, TCA_ETS_MAX,
  436. ets_priomap_policy, NL_VALIDATE_STRICT,
  437. extack);
  438. if (err)
  439. return err;
  440. nla_for_each_nested(attr, priomap_attr, rem) {
  441. switch (nla_type(attr)) {
  442. case TCA_ETS_PRIOMAP_BAND:
  443. if (prio > TC_PRIO_MAX) {
  444. NL_SET_ERR_MSG_MOD(extack, "Too many priorities in ETS priomap");
  445. return -EINVAL;
  446. }
  447. band = nla_get_u8(attr);
  448. if (band >= nbands) {
  449. NL_SET_ERR_MSG_MOD(extack, "Invalid band number in ETS priomap");
  450. return -EINVAL;
  451. }
  452. priomap[prio++] = band;
  453. break;
  454. default:
  455. WARN_ON_ONCE(1); /* Validate should have caught this. */
  456. return -EINVAL;
  457. }
  458. }
  459. return 0;
  460. }
  461. static int ets_qdisc_quanta_parse(struct Qdisc *sch, struct nlattr *quanta_attr,
  462. unsigned int nbands, unsigned int nstrict,
  463. unsigned int *quanta,
  464. struct netlink_ext_ack *extack)
  465. {
  466. const struct nlattr *attr;
  467. int band = nstrict;
  468. int rem;
  469. int err;
  470. err = __nla_validate_nested(quanta_attr, TCA_ETS_MAX,
  471. ets_quanta_policy, NL_VALIDATE_STRICT,
  472. extack);
  473. if (err < 0)
  474. return err;
  475. nla_for_each_nested(attr, quanta_attr, rem) {
  476. switch (nla_type(attr)) {
  477. case TCA_ETS_QUANTA_BAND:
  478. if (band >= nbands) {
  479. NL_SET_ERR_MSG_MOD(extack, "ETS quanta has more values than bands");
  480. return -EINVAL;
  481. }
  482. err = ets_quantum_parse(sch, attr, &quanta[band++],
  483. extack);
  484. if (err)
  485. return err;
  486. break;
  487. default:
  488. WARN_ON_ONCE(1); /* Validate should have caught this. */
  489. return -EINVAL;
  490. }
  491. }
  492. return 0;
  493. }
  494. static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
  495. struct netlink_ext_ack *extack)
  496. {
  497. unsigned int quanta[TCQ_ETS_MAX_BANDS] = {0};
  498. struct Qdisc *queues[TCQ_ETS_MAX_BANDS];
  499. struct ets_sched *q = qdisc_priv(sch);
  500. struct nlattr *tb[TCA_ETS_MAX + 1];
  501. unsigned int oldbands = q->nbands;
  502. u8 priomap[TC_PRIO_MAX + 1];
  503. unsigned int nstrict = 0;
  504. unsigned int nbands;
  505. unsigned int i;
  506. int err;
  507. err = nla_parse_nested(tb, TCA_ETS_MAX, opt, ets_policy, extack);
  508. if (err < 0)
  509. return err;
  510. if (!tb[TCA_ETS_NBANDS]) {
  511. NL_SET_ERR_MSG_MOD(extack, "Number of bands is a required argument");
  512. return -EINVAL;
  513. }
  514. nbands = nla_get_u8(tb[TCA_ETS_NBANDS]);
  515. if (nbands < 1 || nbands > TCQ_ETS_MAX_BANDS) {
  516. NL_SET_ERR_MSG_MOD(extack, "Invalid number of bands");
  517. return -EINVAL;
  518. }
  519. /* Unless overridden, traffic goes to the last band. */
  520. memset(priomap, nbands - 1, sizeof(priomap));
  521. if (tb[TCA_ETS_NSTRICT]) {
  522. nstrict = nla_get_u8(tb[TCA_ETS_NSTRICT]);
  523. if (nstrict > nbands) {
  524. NL_SET_ERR_MSG_MOD(extack, "Invalid number of strict bands");
  525. return -EINVAL;
  526. }
  527. }
  528. if (tb[TCA_ETS_PRIOMAP]) {
  529. err = ets_qdisc_priomap_parse(tb[TCA_ETS_PRIOMAP],
  530. nbands, priomap, extack);
  531. if (err)
  532. return err;
  533. }
  534. if (tb[TCA_ETS_QUANTA]) {
  535. err = ets_qdisc_quanta_parse(sch, tb[TCA_ETS_QUANTA],
  536. nbands, nstrict, quanta, extack);
  537. if (err)
  538. return err;
  539. }
  540. /* If there are more bands than strict + quanta provided, the remaining
  541. * ones are ETS with quantum of MTU. Initialize the missing values here.
  542. */
  543. for (i = nstrict; i < nbands; i++) {
  544. if (!quanta[i])
  545. quanta[i] = psched_mtu(qdisc_dev(sch));
  546. }
  547. /* Before commit, make sure we can allocate all new qdiscs */
  548. for (i = oldbands; i < nbands; i++) {
  549. queues[i] = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
  550. ets_class_id(sch, &q->classes[i]),
  551. extack);
  552. if (!queues[i]) {
  553. while (i > oldbands)
  554. qdisc_put(queues[--i]);
  555. return -ENOMEM;
  556. }
  557. }
  558. sch_tree_lock(sch);
  559. for (i = nbands; i < oldbands; i++) {
  560. if (i >= q->nstrict && q->classes[i].qdisc->q.qlen)
  561. list_del_init(&q->classes[i].alist);
  562. qdisc_purge_queue(q->classes[i].qdisc);
  563. }
  564. WRITE_ONCE(q->nbands, nbands);
  565. for (i = nstrict; i < q->nstrict; i++) {
  566. if (q->classes[i].qdisc->q.qlen) {
  567. list_add_tail(&q->classes[i].alist, &q->active);
  568. q->classes[i].deficit = quanta[i];
  569. }
  570. }
  571. WRITE_ONCE(q->nstrict, nstrict);
  572. memcpy(q->prio2band, priomap, sizeof(priomap));
  573. for (i = 0; i < q->nbands; i++)
  574. WRITE_ONCE(q->classes[i].quantum, quanta[i]);
  575. for (i = oldbands; i < q->nbands; i++) {
  576. q->classes[i].qdisc = queues[i];
  577. if (q->classes[i].qdisc != &noop_qdisc)
  578. qdisc_hash_add(q->classes[i].qdisc, true);
  579. }
  580. sch_tree_unlock(sch);
  581. ets_offload_change(sch);
  582. for (i = q->nbands; i < oldbands; i++) {
  583. qdisc_put(q->classes[i].qdisc);
  584. q->classes[i].qdisc = NULL;
  585. WRITE_ONCE(q->classes[i].quantum, 0);
  586. q->classes[i].deficit = 0;
  587. gnet_stats_basic_sync_init(&q->classes[i].bstats);
  588. memset(&q->classes[i].qstats, 0, sizeof(q->classes[i].qstats));
  589. }
  590. return 0;
  591. }
  592. static int ets_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
  593. struct netlink_ext_ack *extack)
  594. {
  595. struct ets_sched *q = qdisc_priv(sch);
  596. int err, i;
  597. if (!opt)
  598. return -EINVAL;
  599. err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
  600. if (err)
  601. return err;
  602. INIT_LIST_HEAD(&q->active);
  603. for (i = 0; i < TCQ_ETS_MAX_BANDS; i++)
  604. INIT_LIST_HEAD(&q->classes[i].alist);
  605. return ets_qdisc_change(sch, opt, extack);
  606. }
  607. static void ets_qdisc_reset(struct Qdisc *sch)
  608. {
  609. struct ets_sched *q = qdisc_priv(sch);
  610. int band;
  611. for (band = q->nstrict; band < q->nbands; band++) {
  612. if (q->classes[band].qdisc->q.qlen)
  613. list_del_init(&q->classes[band].alist);
  614. }
  615. for (band = 0; band < q->nbands; band++)
  616. qdisc_reset(q->classes[band].qdisc);
  617. }
  618. static void ets_qdisc_destroy(struct Qdisc *sch)
  619. {
  620. struct ets_sched *q = qdisc_priv(sch);
  621. int band;
  622. ets_offload_destroy(sch);
  623. tcf_block_put(q->block);
  624. for (band = 0; band < q->nbands; band++)
  625. qdisc_put(q->classes[band].qdisc);
  626. }
  627. static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb)
  628. {
  629. struct ets_sched *q = qdisc_priv(sch);
  630. struct nlattr *opts;
  631. struct nlattr *nest;
  632. u8 nbands, nstrict;
  633. int band;
  634. int prio;
  635. int err;
  636. err = ets_offload_dump(sch);
  637. if (err)
  638. return err;
  639. opts = nla_nest_start_noflag(skb, TCA_OPTIONS);
  640. if (!opts)
  641. goto nla_err;
  642. nbands = READ_ONCE(q->nbands);
  643. if (nla_put_u8(skb, TCA_ETS_NBANDS, nbands))
  644. goto nla_err;
  645. nstrict = READ_ONCE(q->nstrict);
  646. if (nstrict && nla_put_u8(skb, TCA_ETS_NSTRICT, nstrict))
  647. goto nla_err;
  648. if (nbands > nstrict) {
  649. nest = nla_nest_start(skb, TCA_ETS_QUANTA);
  650. if (!nest)
  651. goto nla_err;
  652. for (band = nstrict; band < nbands; band++) {
  653. if (nla_put_u32(skb, TCA_ETS_QUANTA_BAND,
  654. READ_ONCE(q->classes[band].quantum)))
  655. goto nla_err;
  656. }
  657. nla_nest_end(skb, nest);
  658. }
  659. nest = nla_nest_start(skb, TCA_ETS_PRIOMAP);
  660. if (!nest)
  661. goto nla_err;
  662. for (prio = 0; prio <= TC_PRIO_MAX; prio++) {
  663. if (nla_put_u8(skb, TCA_ETS_PRIOMAP_BAND,
  664. READ_ONCE(q->prio2band[prio])))
  665. goto nla_err;
  666. }
  667. nla_nest_end(skb, nest);
  668. return nla_nest_end(skb, opts);
  669. nla_err:
  670. nla_nest_cancel(skb, opts);
  671. return -EMSGSIZE;
  672. }
  673. static const struct Qdisc_class_ops ets_class_ops = {
  674. .change = ets_class_change,
  675. .graft = ets_class_graft,
  676. .leaf = ets_class_leaf,
  677. .find = ets_class_find,
  678. .qlen_notify = ets_class_qlen_notify,
  679. .dump = ets_class_dump,
  680. .dump_stats = ets_class_dump_stats,
  681. .walk = ets_qdisc_walk,
  682. .tcf_block = ets_qdisc_tcf_block,
  683. .bind_tcf = ets_qdisc_bind_tcf,
  684. .unbind_tcf = ets_qdisc_unbind_tcf,
  685. };
  686. static struct Qdisc_ops ets_qdisc_ops __read_mostly = {
  687. .cl_ops = &ets_class_ops,
  688. .id = "ets",
  689. .priv_size = sizeof(struct ets_sched),
  690. .enqueue = ets_qdisc_enqueue,
  691. .dequeue = ets_qdisc_dequeue,
  692. .peek = qdisc_peek_dequeued,
  693. .change = ets_qdisc_change,
  694. .init = ets_qdisc_init,
  695. .reset = ets_qdisc_reset,
  696. .destroy = ets_qdisc_destroy,
  697. .dump = ets_qdisc_dump,
  698. .owner = THIS_MODULE,
  699. };
  700. MODULE_ALIAS_NET_SCH("ets");
  701. static int __init ets_init(void)
  702. {
  703. return register_qdisc(&ets_qdisc_ops);
  704. }
  705. static void __exit ets_exit(void)
  706. {
  707. unregister_qdisc(&ets_qdisc_ops);
  708. }
  709. module_init(ets_init);
  710. module_exit(ets_exit);
  711. MODULE_LICENSE("GPL");
  712. MODULE_DESCRIPTION("Enhanced Transmission Selection(ETS) scheduler");