sch_mqprio.c (c54876cd5961ce0f8e74807f79a6739cd6b35ddf) sch_mqprio.c (f62af20bed2d9e824f51cfc97ff01bc261f40e58)
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
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/ethtool_netlink.h>
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>

--- 6 unchanged lines hidden (view full) ---

22struct 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];
9#include <linux/types.h>
10#include <linux/slab.h>
11#include <linux/kernel.h>
12#include <linux/string.h>
13#include <linux/errno.h>
14#include <linux/skbuff.h>
15#include <linux/module.h>
16#include <net/netlink.h>

--- 6 unchanged lines hidden (view full) ---

23struct mqprio_sched {
24 struct Qdisc **qdiscs;
25 u16 mode;
26 u16 shaper;
27 int hw_offload;
28 u32 flags;
29 u64 min_rate[TC_QOPT_MAX_QUEUE];
30 u64 max_rate[TC_QOPT_MAX_QUEUE];
31 u32 fp[TC_QOPT_MAX_QUEUE];
30};
31
32static 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);

--- 20 unchanged lines hidden (view full) ---

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
32};
33
34static int mqprio_enable_offload(struct Qdisc *sch,
35 const struct tc_mqprio_qopt *qopt,
36 struct netlink_ext_ack *extack)
37{
38 struct mqprio_sched *priv = qdisc_priv(sch);
39 struct net_device *dev = qdisc_dev(sch);

--- 20 unchanged lines hidden (view full) ---

60 if (priv->flags & TC_MQPRIO_F_MAX_RATE)
61 for (i = 0; i < mqprio.qopt.num_tc; i++)
62 mqprio.max_rate[i] = priv->max_rate[i];
63 break;
64 default:
65 return -EINVAL;
66 }
67
68 mqprio_fp_to_offload(priv->fp, &mqprio);
69
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;

--- 66 unchanged lines hidden (view full) ---

140 NL_SET_ERR_MSG(extack,
141 "Device does not support hardware offload");
142 return -EINVAL;
143 }
144
145 return 0;
146}
147
70 err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_MQPRIO,
71 &mqprio);
72 if (err)
73 return err;
74
75 priv->hw_offload = mqprio.qopt.hw;
76
77 return 0;

--- 66 unchanged lines hidden (view full) ---

144 NL_SET_ERR_MSG(extack,
145 "Device does not support hardware offload");
146 return -EINVAL;
147 }
148
149 return 0;
150}
151
152static const struct
153nla_policy mqprio_tc_entry_policy[TCA_MQPRIO_TC_ENTRY_MAX + 1] = {
154 [TCA_MQPRIO_TC_ENTRY_INDEX] = NLA_POLICY_MAX(NLA_U32,
155 TC_QOPT_MAX_QUEUE),
156 [TCA_MQPRIO_TC_ENTRY_FP] = NLA_POLICY_RANGE(NLA_U32,
157 TC_FP_EXPRESS,
158 TC_FP_PREEMPTIBLE),
159};
160
148static 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 },
161static const struct nla_policy mqprio_policy[TCA_MQPRIO_MAX + 1] = {
162 [TCA_MQPRIO_MODE] = { .len = sizeof(u16) },
163 [TCA_MQPRIO_SHAPER] = { .len = sizeof(u16) },
164 [TCA_MQPRIO_MIN_RATE64] = { .type = NLA_NESTED },
165 [TCA_MQPRIO_MAX_RATE64] = { .type = NLA_NESTED },
166 [TCA_MQPRIO_TC_ENTRY] = { .type = NLA_NESTED },
153};
154
167};
168
169static int mqprio_parse_tc_entry(u32 fp[TC_QOPT_MAX_QUEUE],
170 struct nlattr *opt,
171 unsigned long *seen_tcs,
172 struct netlink_ext_ack *extack)
173{
174 struct nlattr *tb[TCA_MQPRIO_TC_ENTRY_MAX + 1];
175 int err, tc;
176
177 err = nla_parse_nested(tb, TCA_MQPRIO_TC_ENTRY_MAX, opt,
178 mqprio_tc_entry_policy, extack);
179 if (err < 0)
180 return err;
181
182 if (NL_REQ_ATTR_CHECK(extack, opt, tb, TCA_MQPRIO_TC_ENTRY_INDEX)) {
183 NL_SET_ERR_MSG(extack, "TC entry index missing");
184 return -EINVAL;
185 }
186
187 tc = nla_get_u32(tb[TCA_MQPRIO_TC_ENTRY_INDEX]);
188 if (*seen_tcs & BIT(tc)) {
189 NL_SET_ERR_MSG_ATTR(extack, tb[TCA_MQPRIO_TC_ENTRY_INDEX],
190 "Duplicate tc entry");
191 return -EINVAL;
192 }
193
194 *seen_tcs |= BIT(tc);
195
196 if (tb[TCA_MQPRIO_TC_ENTRY_FP])
197 fp[tc] = nla_get_u32(tb[TCA_MQPRIO_TC_ENTRY_FP]);
198
199 return 0;
200}
201
202static int mqprio_parse_tc_entries(struct Qdisc *sch, struct nlattr *nlattr_opt,
203 int nlattr_opt_len,
204 struct netlink_ext_ack *extack)
205{
206 struct mqprio_sched *priv = qdisc_priv(sch);
207 struct net_device *dev = qdisc_dev(sch);
208 bool have_preemption = false;
209 unsigned long seen_tcs = 0;
210 u32 fp[TC_QOPT_MAX_QUEUE];
211 struct nlattr *n;
212 int tc, rem;
213 int err = 0;
214
215 for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++)
216 fp[tc] = priv->fp[tc];
217
218 nla_for_each_attr(n, nlattr_opt, nlattr_opt_len, rem) {
219 if (nla_type(n) != TCA_MQPRIO_TC_ENTRY)
220 continue;
221
222 err = mqprio_parse_tc_entry(fp, n, &seen_tcs, extack);
223 if (err)
224 goto out;
225 }
226
227 for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++) {
228 priv->fp[tc] = fp[tc];
229 if (fp[tc] == TC_FP_PREEMPTIBLE)
230 have_preemption = true;
231 }
232
233 if (have_preemption && !ethtool_dev_mm_supported(dev)) {
234 NL_SET_ERR_MSG(extack, "Device does not support preemption");
235 return -EOPNOTSUPP;
236 }
237out:
238 return err;
239}
240
155/* Parse the other netlink attributes that represent the payload of
156 * TCA_OPTIONS, which are appended right after struct tc_mqprio_qopt.
157 */
158static 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));

--- 66 unchanged lines hidden (view full) ---

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
241/* Parse the other netlink attributes that represent the payload of
242 * TCA_OPTIONS, which are appended right after struct tc_mqprio_qopt.
243 */
244static int mqprio_parse_nlattr(struct Qdisc *sch, struct tc_mqprio_qopt *qopt,
245 struct nlattr *opt,
246 struct netlink_ext_ack *extack)
247{
248 struct nlattr *nlattr_opt = nla_data(opt) + NLA_ALIGN(sizeof(*qopt));

--- 66 unchanged lines hidden (view full) ---

315 if (i >= qopt->num_tc)
316 break;
317 priv->max_rate[i] = nla_get_u64(attr);
318 i++;
319 }
320 priv->flags |= TC_MQPRIO_F_MAX_RATE;
321 }
322
323 if (tb[TCA_MQPRIO_TC_ENTRY]) {
324 err = mqprio_parse_tc_entries(sch, nlattr_opt, nlattr_opt_len,
325 extack);
326 if (err)
327 return err;
328 }
329
237 return 0;
238}
239
240static 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;
330 return 0;
331}
332
333static int mqprio_init(struct Qdisc *sch, struct nlattr *opt,
334 struct netlink_ext_ack *extack)
335{
336 struct net_device *dev = qdisc_dev(sch);
337 struct mqprio_sched *priv = qdisc_priv(sch);
338 struct netdev_queue *dev_queue;
339 struct Qdisc *qdisc;
340 int i, err = -EOPNOTSUPP;
341 struct tc_mqprio_qopt *qopt = NULL;
342 struct tc_mqprio_caps caps;
250 int len;
343 int len, tc;
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
344
345 BUILD_BUG_ON(TC_MAX_QUEUE != TC_QOPT_MAX_QUEUE);
346 BUILD_BUG_ON(TC_BITMASK != TC_QOPT_BITMASK);
347
348 if (sch->parent != TC_H_ROOT)
349 return -EOPNOTSUPP;
350
351 if (!netif_is_multiqueue(dev))
352 return -EOPNOTSUPP;
353
354 /* make certain can allocate enough classids to handle queues */
355 if (dev->num_tx_queues >= TC_H_MIN_PRIORITY)
356 return -ENOMEM;
357
358 if (!opt || nla_len(opt) < sizeof(*qopt))
359 return -EINVAL;
360
361 for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++)
362 priv->fp[tc] = TC_FP_EXPRESS;
363
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));

--- 134 unchanged lines hidden (view full) ---

410 }
411 return 0;
412
413nla_put_failure:
414 nla_nest_cancel(skb, nest);
415 return -1;
416}
417
364 qdisc_offload_query_caps(dev, TC_SETUP_QDISC_MQPRIO,
365 &caps, sizeof(caps));
366
367 qopt = nla_data(opt);
368 if (mqprio_parse_opt(dev, qopt, &caps, extack))
369 return -EINVAL;
370
371 len = nla_len(opt) - NLA_ALIGN(sizeof(*qopt));

--- 134 unchanged lines hidden (view full) ---

506 }
507 return 0;
508
509nla_put_failure:
510 nla_nest_cancel(skb, nest);
511 return -1;
512}
513
514static int mqprio_dump_tc_entries(struct mqprio_sched *priv,
515 struct sk_buff *skb)
516{
517 struct nlattr *n;
518 int tc;
519
520 for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++) {
521 n = nla_nest_start(skb, TCA_MQPRIO_TC_ENTRY);
522 if (!n)
523 return -EMSGSIZE;
524
525 if (nla_put_u32(skb, TCA_MQPRIO_TC_ENTRY_INDEX, tc))
526 goto nla_put_failure;
527
528 if (nla_put_u32(skb, TCA_MQPRIO_TC_ENTRY_FP, priv->fp[tc]))
529 goto nla_put_failure;
530
531 nla_nest_end(skb, n);
532 }
533
534 return 0;
535
536nla_put_failure:
537 nla_nest_cancel(skb, n);
538 return -EMSGSIZE;
539}
540
418static 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;

--- 34 unchanged lines hidden (view full) ---

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
541static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
542{
543 struct net_device *dev = qdisc_dev(sch);
544 struct mqprio_sched *priv = qdisc_priv(sch);
545 struct nlattr *nla = (struct nlattr *)skb_tail_pointer(skb);
546 struct tc_mqprio_qopt opt = { 0 };
547 struct Qdisc *qdisc;
548 unsigned int ntx;

--- 34 unchanged lines hidden (view full) ---

583 nla_put_u16(skb, TCA_MQPRIO_SHAPER, priv->shaper))
584 goto nla_put_failure;
585
586 if ((priv->flags & TC_MQPRIO_F_MIN_RATE ||
587 priv->flags & TC_MQPRIO_F_MAX_RATE) &&
588 (dump_rates(priv, &opt, skb) != 0))
589 goto nla_put_failure;
590
591 if (mqprio_dump_tc_entries(priv, skb))
592 goto nla_put_failure;
593
468 return nla_nest_end(skb, nla);
469nla_put_failure:
470 nlmsg_trim(skb, nla);
471 return -1;
472}
473
474static struct Qdisc *mqprio_leaf(struct Qdisc *sch, unsigned long cl)
475{

--- 176 unchanged lines hidden ---
594 return nla_nest_end(skb, nla);
595nla_put_failure:
596 nlmsg_trim(skb, nla);
597 return -1;
598}
599
600static struct Qdisc *mqprio_leaf(struct Qdisc *sch, unsigned long cl)
601{

--- 176 unchanged lines hidden ---