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 */
15static 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
26static 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
36static 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
45static 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
53static 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
60static 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
67static 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
74static 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 */
94int 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}
156EXPORT_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 */
169int 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}
242EXPORT_SYMBOL_GPL(ietf_dscp_to_ieee8021q_tt);
243