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