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