History

net/sched: mqprio: allow per-TC user input of FP adminStatus

IEEE 802.1Q-2018 clause 6.7.2 Frame preemption specifies that each packet priority can be assigned to a "frame preemption status" value of either "express" or "preemptible". Express priorities are transmitted by the local device through the eMAC, and preemptible priorities through the pMAC (the concepts of eMAC and pMAC come from the 802.3 MAC Merge layer). The FP adminStatus is defined per packet priority, but 802.1Q clause 12.30.1.1.1 framePreemptionAdminStatus also says that: | Priorities that all map to the same traffic class should be | constrained to use the same value of preemption status. It is impossible to ignore the cognitive dissonance in the standard here, because it practically means that the FP adminStatus only takes distinct values per traffic class, even though it is defined per priority. I can see no valid use case which is prevented by having the kernel take the FP adminStatus as input per traffic class (what we do here). In addition, this also enforces the above constraint by construction. User space network managers which wish to expose FP adminStatus per priority are free to do so; they must only observe the prio_tc_map of the netdev (which presumably is also under their control, when constructing the mqprio netlink attributes). The reason for configuring frame preemption as a property of the Qdisc layer is that the information about "preemptible TCs" is closest to the place which handles the num_tc and prio_tc_map of the netdev. If the UAPI would have been any other layer, it would be unclear what to do with the FP information when num_tc collapses to 0. A key assumption is that only mqprio/taprio change the num_tc and prio_tc_map of the netdev. Not sure if that's a great assumption to make. Having FP in tc-mqprio can be seen as an implementation of the use case defined in 802.1Q Annex S.2 "Preemption used in isolation". There will be a separate implementation of FP in tc-taprio, for the other use cases.

Vladimir Oltean committed 3 years ago

Commit f62af201 parent c54876c5 files · +160 −1Browse files

Unified · Split

5 files
  1. include/net/pkt_sched.h +1 −0
  2. include/uapi/linux/pkt_sched.h +16 −0
  3. net/sched/sch_mqprio.c +127 −1
  4. net/sched/sch_mqprio_lib.c +14 −0
  5. net/sched/sch_mqprio_lib.h +2 −0
include/net/pkt_sched.h+1−0
@@ -172,6 +172,7 @@ struct tc_mqprio_qopt_offload { · 171 unmodified lines
172 u32 flags;172 u32 flags;
173 u64 min_rate[TC_QOPT_MAX_QUEUE];173 u64 min_rate[TC_QOPT_MAX_QUEUE];
174 u64 max_rate[TC_QOPT_MAX_QUEUE];174 u64 max_rate[TC_QOPT_MAX_QUEUE];
175 unsigned long preemptible_tcs;
175};176};
176 177
177struct tc_taprio_caps {178struct tc_taprio_caps {
include/uapi/linux/pkt_sched.h+16−0
@@ -719,6 +719,11 @@ enum { · 718 unmodified lines
719 719
720#define __TC_MQPRIO_SHAPER_MAX (__TC_MQPRIO_SHAPER_MAX - 1)720#define __TC_MQPRIO_SHAPER_MAX (__TC_MQPRIO_SHAPER_MAX - 1)
721 721
722enum {
723 TC_FP_EXPRESS = 1,
724 TC_FP_PREEMPTIBLE = 2,
725};
726
722struct tc_mqprio_qopt {727struct tc_mqprio_qopt {
723 __u8 num_tc;728 __u8 num_tc;
724 __u8 prio_tc_map[TC_QOPT_BITMASK + 1];729 __u8 prio_tc_map[TC_QOPT_BITMASK + 1];
@@ -732,12 +737,23 @@ struct tc_mqprio_qopt { · 7 unmodified lines
732#define TC_MQPRIO_F_MIN_RATE 0x4737#define TC_MQPRIO_F_MIN_RATE 0x4
733#define TC_MQPRIO_F_MAX_RATE 0x8738#define TC_MQPRIO_F_MAX_RATE 0x8
734 739
740enum {
741 TCA_MQPRIO_TC_ENTRY_UNSPEC,
742 TCA_MQPRIO_TC_ENTRY_INDEX, /* u32 */
743 TCA_MQPRIO_TC_ENTRY_FP, /* u32 */
744
745 /* add new constants above here */
746 __TCA_MQPRIO_TC_ENTRY_CNT,
747 TCA_MQPRIO_TC_ENTRY_MAX = (__TCA_MQPRIO_TC_ENTRY_CNT - 1)
748};
749
735enum {750enum {
736 TCA_MQPRIO_UNSPEC,751 TCA_MQPRIO_UNSPEC,
737 TCA_MQPRIO_MODE,752 TCA_MQPRIO_MODE,
738 TCA_MQPRIO_SHAPER,753 TCA_MQPRIO_SHAPER,
739 TCA_MQPRIO_MIN_RATE64,754 TCA_MQPRIO_MIN_RATE64,
740 TCA_MQPRIO_MAX_RATE64,755 TCA_MQPRIO_MAX_RATE64,
756 TCA_MQPRIO_TC_ENTRY,
741 __TCA_MQPRIO_MAX,757 __TCA_MQPRIO_MAX,
742};758};
743 759
net/sched/sch_mqprio.c+127−1
@@ -5,6 +5,7 @@ · 4 unmodified lines
5 * Copyright (c) 2010 John Fastabend <john.r.fastabend@intel.com>5 * Copyright (c) 2010 John Fastabend <john.r.fastabend@intel.com>
6 */6 */
7 7
8#include <linux/ethtool_netlink.h>
8#include <linux/types.h>9#include <linux/types.h>
9#include <linux/slab.h>10#include <linux/slab.h>
10#include <linux/kernel.h>11#include <linux/kernel.h>
@@ -27,6 +28,7 @@ struct mqprio_sched { · 16 unmodified lines
27 u32 flags;28 u32 flags;
28 u64 min_rate[TC_QOPT_MAX_QUEUE];29 u64 min_rate[TC_QOPT_MAX_QUEUE];
29 u64 max_rate[TC_QOPT_MAX_QUEUE];30 u64 max_rate[TC_QOPT_MAX_QUEUE];
31 u32 fp[TC_QOPT_MAX_QUEUE];
30};32};
31 33
32static int mqprio_enable_offload(struct Qdisc *sch,34static int mqprio_enable_offload(struct Qdisc *sch,
@@ -63,6 +65,8 @@ static int mqprio_enable_offload(struct Qdisc *sch, · 30 unmodified lines
63 return -EINVAL;65 return -EINVAL;
64 }66 }
65 67
68 mqprio_fp_to_offload(priv->fp, &mqprio);
69
66 err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_MQPRIO,70 err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_MQPRIO,
67 &mqprio);71 &mqprio);
68 if (err)72 if (err)
@@ -145,13 +149,95 @@ static int mqprio_parse_opt(struct net_device *dev, struct tc_mqprio_qopt *qopt, · 76 unmodified lines
145 return 0;149 return 0;
146}150}
147 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] = {161static const struct nla_policy mqprio_policy[TCA_MQPRIO_MAX + 1] = {
149 [TCA_MQPRIO_MODE] = { .len = sizeof(u16) },162 [TCA_MQPRIO_MODE] = { .len = sizeof(u16) },
150 [TCA_MQPRIO_SHAPER] = { .len = sizeof(u16) },163 [TCA_MQPRIO_SHAPER] = { .len = sizeof(u16) },
151 [TCA_MQPRIO_MIN_RATE64] = { .type = NLA_NESTED },164 [TCA_MQPRIO_MIN_RATE64] = { .type = NLA_NESTED },
152 [TCA_MQPRIO_MAX_RATE64] = { .type = NLA_NESTED },165 [TCA_MQPRIO_MAX_RATE64] = { .type = NLA_NESTED },
166 [TCA_MQPRIO_TC_ENTRY] = { .type = NLA_NESTED },
153};167};
154 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 of241/* Parse the other netlink attributes that represent the payload of
156 * TCA_OPTIONS, which are appended right after struct tc_mqprio_qopt.242 * TCA_OPTIONS, which are appended right after struct tc_mqprio_qopt.
157 */243 */
@@ -234,6 +320,13 @@ static int mqprio_parse_nlattr(struct Qdisc *sch, struct tc_mqprio_qopt *qopt, · 76 unmodified lines
234 priv->flags |= TC_MQPRIO_F_MAX_RATE;320 priv->flags |= TC_MQPRIO_F_MAX_RATE;
235 }321 }
236 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;330 return 0;
238}331}
239 332
@@ -247,7 +340,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt, · 7 unmodified lines
247 int i, err = -EOPNOTSUPP;340 int i, err = -EOPNOTSUPP;
248 struct tc_mqprio_qopt *qopt = NULL;341 struct tc_mqprio_qopt *qopt = NULL;
249 struct tc_mqprio_caps caps;342 struct tc_mqprio_caps caps;
250 int len;343 int len, tc;
251 344
252 BUILD_BUG_ON(TC_MAX_QUEUE != TC_QOPT_MAX_QUEUE);345 BUILD_BUG_ON(TC_MAX_QUEUE != TC_QOPT_MAX_QUEUE);
253 BUILD_BUG_ON(TC_BITMASK != TC_QOPT_BITMASK);346 BUILD_BUG_ON(TC_BITMASK != TC_QOPT_BITMASK);
@@ -265,6 +358,9 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt, · 11 unmodified lines
265 if (!opt || nla_len(opt) < sizeof(*qopt))358 if (!opt || nla_len(opt) < sizeof(*qopt))
266 return -EINVAL;359 return -EINVAL;
267 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,364 qdisc_offload_query_caps(dev, TC_SETUP_QDISC_MQPRIO,
269 &caps, sizeof(caps));365 &caps, sizeof(caps));
270 366
@@ -415,6 +511,33 @@ nla_put_failure: · 144 unmodified lines
415 return -1;511 return -1;
416}512}
417 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)541static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
419{542{
420 struct net_device *dev = qdisc_dev(sch);543 struct net_device *dev = qdisc_dev(sch);
@@ -465,6 +588,9 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb) · 44 unmodified lines
465 (dump_rates(priv, &opt, skb) != 0))588 (dump_rates(priv, &opt, skb) != 0))
466 goto nla_put_failure;589 goto nla_put_failure;
467 590
591 if (mqprio_dump_tc_entries(priv, skb))
592 goto nla_put_failure;
593
468 return nla_nest_end(skb, nla);594 return nla_nest_end(skb, nla);
469nla_put_failure:595nla_put_failure:
470 nlmsg_trim(skb, nla);596 nlmsg_trim(skb, nla);
net/sched/sch_mqprio_lib.c+14−0
@@ -114,4 +114,18 @@ void mqprio_qopt_reconstruct(struct net_device *dev, struct tc_mqprio_qopt *qopt · 113 unmodified lines
114}114}
115EXPORT_SYMBOL_GPL(mqprio_qopt_reconstruct);115EXPORT_SYMBOL_GPL(mqprio_qopt_reconstruct);
116 116
117void mqprio_fp_to_offload(u32 fp[TC_QOPT_MAX_QUEUE],
118 struct tc_mqprio_qopt_offload *mqprio)
119{
120 unsigned long preemptible_tcs = 0;
121 int tc;
122
123 for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++)
124 if (fp[tc] == TC_FP_PREEMPTIBLE)
125 preemptible_tcs |= BIT(tc);
126
127 mqprio->preemptible_tcs = preemptible_tcs;
128}
129EXPORT_SYMBOL_GPL(mqprio_fp_to_offload);
130
117MODULE_LICENSE("GPL");131MODULE_LICENSE("GPL");
net/sched/sch_mqprio_lib.h+2−0
@@ -14,5 +14,7 @@ int mqprio_validate_qopt(struct net_device *dev, struct tc_mqprio_qopt *qopt, · 13 unmodified lines
14 struct netlink_ext_ack *extack);14 struct netlink_ext_ack *extack);
15void mqprio_qopt_reconstruct(struct net_device *dev,15void mqprio_qopt_reconstruct(struct net_device *dev,
16 struct tc_mqprio_qopt *qopt);16 struct tc_mqprio_qopt *qopt);
17void mqprio_fp_to_offload(u32 fp[TC_QOPT_MAX_QUEUE],
18 struct tc_mqprio_qopt_offload *mqprio);
17 19
18#endif20#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t