]>
Commit | Line | Data |
---|---|---|
768cf841 OR |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2024 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> | |
3 | ||
4 | #include <linux/array_size.h> | |
5 | #include <linux/printk.h> | |
6 | #include <linux/types.h> | |
7 | #include <net/dscp.h> | |
8 | #include <net/ieee8021q.h> | |
9 | ||
10 | /* The following arrays map Traffic Types (TT) to traffic classes (TC) for | |
11 | * different number of queues as shown in the example provided by | |
12 | * IEEE 802.1Q-2022 in Annex I "I.3 Traffic type to traffic class mapping" and | |
13 | * Table I-1 "Traffic type to traffic class mapping". | |
14 | */ | |
15 | static const u8 ieee8021q_8queue_tt_tc_map[] = { | |
16 | [IEEE8021Q_TT_BK] = 0, | |
17 | [IEEE8021Q_TT_BE] = 1, | |
18 | [IEEE8021Q_TT_EE] = 2, | |
19 | [IEEE8021Q_TT_CA] = 3, | |
20 | [IEEE8021Q_TT_VI] = 4, | |
21 | [IEEE8021Q_TT_VO] = 5, | |
22 | [IEEE8021Q_TT_IC] = 6, | |
23 | [IEEE8021Q_TT_NC] = 7, | |
24 | }; | |
25 | ||
26 | static const u8 ieee8021q_7queue_tt_tc_map[] = { | |
27 | [IEEE8021Q_TT_BK] = 0, | |
28 | [IEEE8021Q_TT_BE] = 1, | |
29 | [IEEE8021Q_TT_EE] = 2, | |
30 | [IEEE8021Q_TT_CA] = 3, | |
31 | [IEEE8021Q_TT_VI] = 4, [IEEE8021Q_TT_VO] = 4, | |
32 | [IEEE8021Q_TT_IC] = 5, | |
33 | [IEEE8021Q_TT_NC] = 6, | |
34 | }; | |
35 | ||
36 | static const u8 ieee8021q_6queue_tt_tc_map[] = { | |
37 | [IEEE8021Q_TT_BK] = 0, | |
38 | [IEEE8021Q_TT_BE] = 1, | |
39 | [IEEE8021Q_TT_EE] = 2, [IEEE8021Q_TT_CA] = 2, | |
40 | [IEEE8021Q_TT_VI] = 3, [IEEE8021Q_TT_VO] = 3, | |
41 | [IEEE8021Q_TT_IC] = 4, | |
42 | [IEEE8021Q_TT_NC] = 5, | |
43 | }; | |
44 | ||
45 | static const u8 ieee8021q_5queue_tt_tc_map[] = { | |
46 | [IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0, | |
47 | [IEEE8021Q_TT_EE] = 1, [IEEE8021Q_TT_CA] = 1, | |
48 | [IEEE8021Q_TT_VI] = 2, [IEEE8021Q_TT_VO] = 2, | |
49 | [IEEE8021Q_TT_IC] = 3, | |
50 | [IEEE8021Q_TT_NC] = 4, | |
51 | }; | |
52 | ||
53 | static const u8 ieee8021q_4queue_tt_tc_map[] = { | |
54 | [IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0, | |
55 | [IEEE8021Q_TT_EE] = 1, [IEEE8021Q_TT_CA] = 1, | |
56 | [IEEE8021Q_TT_VI] = 2, [IEEE8021Q_TT_VO] = 2, | |
57 | [IEEE8021Q_TT_IC] = 3, [IEEE8021Q_TT_NC] = 3, | |
58 | }; | |
59 | ||
60 | static const u8 ieee8021q_3queue_tt_tc_map[] = { | |
61 | [IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0, | |
62 | [IEEE8021Q_TT_EE] = 0, [IEEE8021Q_TT_CA] = 0, | |
63 | [IEEE8021Q_TT_VI] = 1, [IEEE8021Q_TT_VO] = 1, | |
64 | [IEEE8021Q_TT_IC] = 2, [IEEE8021Q_TT_NC] = 2, | |
65 | }; | |
66 | ||
67 | static const u8 ieee8021q_2queue_tt_tc_map[] = { | |
68 | [IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0, | |
69 | [IEEE8021Q_TT_EE] = 0, [IEEE8021Q_TT_CA] = 0, | |
70 | [IEEE8021Q_TT_VI] = 1, [IEEE8021Q_TT_VO] = 1, | |
71 | [IEEE8021Q_TT_IC] = 1, [IEEE8021Q_TT_NC] = 1, | |
72 | }; | |
73 | ||
74 | static const u8 ieee8021q_1queue_tt_tc_map[] = { | |
75 | [IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0, | |
76 | [IEEE8021Q_TT_EE] = 0, [IEEE8021Q_TT_CA] = 0, | |
77 | [IEEE8021Q_TT_VI] = 0, [IEEE8021Q_TT_VO] = 0, | |
78 | [IEEE8021Q_TT_IC] = 0, [IEEE8021Q_TT_NC] = 0, | |
79 | }; | |
80 | ||
81 | /** | |
82 | * ieee8021q_tt_to_tc - Map IEEE 802.1Q Traffic Type to Traffic Class | |
83 | * @tt: IEEE 802.1Q Traffic Type | |
84 | * @num_queues: Number of queues | |
85 | * | |
86 | * This function maps an IEEE 802.1Q Traffic Type to a Traffic Class (TC) based | |
87 | * on the number of queues configured on the NIC. The mapping is based on the | |
88 | * example provided by IEEE 802.1Q-2022 in Annex I "I.3 Traffic type to traffic | |
89 | * class mapping" and Table I-1 "Traffic type to traffic class mapping". | |
90 | * | |
91 | * Return: Traffic Class corresponding to the given Traffic Type or negative | |
92 | * value in case of error. | |
93 | */ | |
94 | int ieee8021q_tt_to_tc(enum ieee8021q_traffic_type tt, unsigned int num_queues) | |
95 | { | |
96 | if (tt < 0 || tt >= IEEE8021Q_TT_MAX) { | |
97 | pr_err("Requested Traffic Type (%d) is out of range (%d)\n", tt, | |
98 | IEEE8021Q_TT_MAX); | |
99 | return -EINVAL; | |
100 | } | |
101 | ||
102 | switch (num_queues) { | |
103 | case 8: | |
104 | compiletime_assert(ARRAY_SIZE(ieee8021q_8queue_tt_tc_map) != | |
105 | IEEE8021Q_TT_MAX - 1, | |
106 | "ieee8021q_8queue_tt_tc_map != max - 1"); | |
107 | return ieee8021q_8queue_tt_tc_map[tt]; | |
108 | case 7: | |
109 | compiletime_assert(ARRAY_SIZE(ieee8021q_7queue_tt_tc_map) != | |
110 | IEEE8021Q_TT_MAX - 1, | |
111 | "ieee8021q_7queue_tt_tc_map != max - 1"); | |
112 | ||
113 | return ieee8021q_7queue_tt_tc_map[tt]; | |
114 | case 6: | |
115 | compiletime_assert(ARRAY_SIZE(ieee8021q_6queue_tt_tc_map) != | |
116 | IEEE8021Q_TT_MAX - 1, | |
117 | "ieee8021q_6queue_tt_tc_map != max - 1"); | |
118 | ||
119 | return ieee8021q_6queue_tt_tc_map[tt]; | |
120 | case 5: | |
121 | compiletime_assert(ARRAY_SIZE(ieee8021q_5queue_tt_tc_map) != | |
122 | IEEE8021Q_TT_MAX - 1, | |
123 | "ieee8021q_5queue_tt_tc_map != max - 1"); | |
124 | ||
125 | return ieee8021q_5queue_tt_tc_map[tt]; | |
126 | case 4: | |
127 | compiletime_assert(ARRAY_SIZE(ieee8021q_4queue_tt_tc_map) != | |
128 | IEEE8021Q_TT_MAX - 1, | |
129 | "ieee8021q_4queue_tt_tc_map != max - 1"); | |
130 | ||
131 | return ieee8021q_4queue_tt_tc_map[tt]; | |
132 | case 3: | |
133 | compiletime_assert(ARRAY_SIZE(ieee8021q_3queue_tt_tc_map) != | |
134 | IEEE8021Q_TT_MAX - 1, | |
135 | "ieee8021q_3queue_tt_tc_map != max - 1"); | |
136 | ||
137 | return ieee8021q_3queue_tt_tc_map[tt]; | |
138 | case 2: | |
139 | compiletime_assert(ARRAY_SIZE(ieee8021q_2queue_tt_tc_map) != | |
140 | IEEE8021Q_TT_MAX - 1, | |
141 | "ieee8021q_2queue_tt_tc_map != max - 1"); | |
142 | ||
143 | return ieee8021q_2queue_tt_tc_map[tt]; | |
144 | case 1: | |
145 | compiletime_assert(ARRAY_SIZE(ieee8021q_1queue_tt_tc_map) != | |
146 | IEEE8021Q_TT_MAX - 1, | |
147 | "ieee8021q_1queue_tt_tc_map != max - 1"); | |
148 | ||
149 | return ieee8021q_1queue_tt_tc_map[tt]; | |
150 | } | |
151 | ||
152 | pr_err("Invalid number of queues %d\n", num_queues); | |
153 | ||
154 | return -EINVAL; | |
155 | } | |
156 | EXPORT_SYMBOL_GPL(ieee8021q_tt_to_tc); | |
157 | ||
158 | /** | |
159 | * ietf_dscp_to_ieee8021q_tt - Map IETF DSCP to IEEE 802.1Q Traffic Type | |
160 | * @dscp: IETF DSCP value | |
161 | * | |
162 | * This function maps an IETF DSCP value to an IEEE 802.1Q Traffic Type (TT). | |
163 | * Since there is no corresponding mapping between DSCP and IEEE 802.1Q Traffic | |
164 | * Type, this function is inspired by the RFC8325 documentation which describe | |
165 | * the mapping between DSCP and 802.11 User Priority (UP) values. | |
166 | * | |
167 | * Return: IEEE 802.1Q Traffic Type corresponding to the given DSCP value | |
168 | */ | |
169 | int ietf_dscp_to_ieee8021q_tt(u8 dscp) | |
170 | { | |
171 | switch (dscp) { | |
172 | case DSCP_CS0: | |
173 | /* Comment from RFC8325: | |
174 | * [RFC4594], Section 4.8, recommends High-Throughput Data be marked | |
175 | * AF1x (that is, AF11, AF12, and AF13, according to the rules defined | |
176 | * in [RFC2475]). | |
177 | * | |
178 | * By default (as described in Section 2.3), High-Throughput Data will | |
179 | * map to UP 1 and, thus, to the Background Access Category (AC_BK), | |
180 | * which is contrary to the intent expressed in [RFC4594]. | |
181 | ||
182 | * Unfortunately, there really is no corresponding fit for the High- | |
183 | * Throughput Data service class within the constrained 4 Access | |
184 | * Category [IEEE.802.11-2016] model. If the High-Throughput Data | |
185 | * service class is assigned to the Best Effort Access Category (AC_BE), | |
186 | * then it would contend with Low-Latency Data (while [RFC4594] | |
187 | * recommends a distinction in servicing between these service classes) | |
188 | * as well as with the default service class; alternatively, if it is | |
189 | * assigned to the Background Access Category (AC_BK), then it would | |
190 | * receive a less-then-best-effort service and contend with Low-Priority | |
191 | * Data (as discussed in Section 4.2.10). | |
192 | * | |
193 | * As such, since there is no directly corresponding fit for the High- | |
194 | * Throughout Data service class within the [IEEE.802.11-2016] model, it | |
195 | * is generally RECOMMENDED to map High-Throughput Data to UP 0, thereby | |
196 | * admitting it to the Best Effort Access Category (AC_BE). | |
197 | * | |
198 | * Note: The above text is from RFC8325 which is describing the mapping | |
199 | * between DSCP and 802.11 User Priority (UP) values. The mapping | |
200 | * between UP and IEEE 802.1Q Traffic Type is not defined in the RFC but | |
201 | * the 802.11 AC_BK and AC_BE are closely related to the IEEE 802.1Q | |
202 | * Traffic Types BE and BK. | |
203 | */ | |
204 | case DSCP_AF11: | |
205 | case DSCP_AF12: | |
206 | case DSCP_AF13: | |
207 | return IEEE8021Q_TT_BE; | |
208 | /* Comment from RFC8325: | |
209 | * RFC3662 and RFC4594 both recommend Low-Priority Data be marked | |
210 | * with DSCP CS1. The Low-Priority Data service class loosely | |
211 | * corresponds to the [IEEE.802.11-2016] Background Access Category | |
212 | */ | |
213 | case DSCP_CS1: | |
214 | return IEEE8021Q_TT_BK; | |
215 | case DSCP_CS2: | |
216 | case DSCP_AF21: | |
217 | case DSCP_AF22: | |
218 | case DSCP_AF23: | |
219 | return IEEE8021Q_TT_EE; | |
220 | case DSCP_CS3: | |
221 | case DSCP_AF31: | |
222 | case DSCP_AF32: | |
223 | case DSCP_AF33: | |
224 | return IEEE8021Q_TT_CA; | |
225 | case DSCP_CS4: | |
226 | case DSCP_AF41: | |
227 | case DSCP_AF42: | |
228 | case DSCP_AF43: | |
229 | return IEEE8021Q_TT_VI; | |
230 | case DSCP_CS5: | |
231 | case DSCP_EF: | |
232 | case DSCP_VOICE_ADMIT: | |
233 | return IEEE8021Q_TT_VO; | |
234 | case DSCP_CS6: | |
235 | return IEEE8021Q_TT_IC; | |
236 | case DSCP_CS7: | |
237 | return IEEE8021Q_TT_NC; | |
238 | } | |
239 | ||
240 | return SIMPLE_IETF_DSCP_TO_IEEE8021Q_TT(dscp); | |
241 | } | |
242 | EXPORT_SYMBOL_GPL(ietf_dscp_to_ieee8021q_tt); |