summaryrefslogtreecommitdiffstats
path: root/net/core/ieee8021q_helpers.c
blob: 759a9b9f3f898b10ac2d1f5e534b8e5aca71c2c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2024 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>

#include <linux/array_size.h>
#include <linux/printk.h>
#include <linux/types.h>
#include <net/dscp.h>
#include <net/ieee8021q.h>

/* The following arrays map Traffic Types (TT) to traffic classes (TC) for
 * different number of queues as shown in the example provided by
 * IEEE 802.1Q-2022 in Annex I "I.3 Traffic type to traffic class mapping" and
 * Table I-1 "Traffic type to traffic class mapping".
 */
static const u8 ieee8021q_8queue_tt_tc_map[] = {
	[IEEE8021Q_TT_BK] = 0,
	[IEEE8021Q_TT_BE] = 1,
	[IEEE8021Q_TT_EE] = 2,
	[IEEE8021Q_TT_CA] = 3,
	[IEEE8021Q_TT_VI] = 4,
	[IEEE8021Q_TT_VO] = 5,
	[IEEE8021Q_TT_IC] = 6,
	[IEEE8021Q_TT_NC] = 7,
};

static const u8 ieee8021q_7queue_tt_tc_map[] = {
	[IEEE8021Q_TT_BK] = 0,
	[IEEE8021Q_TT_BE] = 1,
	[IEEE8021Q_TT_EE] = 2,
	[IEEE8021Q_TT_CA] = 3,
	[IEEE8021Q_TT_VI] = 4,	[IEEE8021Q_TT_VO] = 4,
	[IEEE8021Q_TT_IC] = 5,
	[IEEE8021Q_TT_NC] = 6,
};

static const u8 ieee8021q_6queue_tt_tc_map[] = {
	[IEEE8021Q_TT_BK] = 0,
	[IEEE8021Q_TT_BE] = 1,
	[IEEE8021Q_TT_EE] = 2,	[IEEE8021Q_TT_CA] = 2,
	[IEEE8021Q_TT_VI] = 3,	[IEEE8021Q_TT_VO] = 3,
	[IEEE8021Q_TT_IC] = 4,
	[IEEE8021Q_TT_NC] = 5,
};

static const u8 ieee8021q_5queue_tt_tc_map[] = {
	[IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0,
	[IEEE8021Q_TT_EE] = 1, [IEEE8021Q_TT_CA] = 1,
	[IEEE8021Q_TT_VI] = 2, [IEEE8021Q_TT_VO] = 2,
	[IEEE8021Q_TT_IC] = 3,
	[IEEE8021Q_TT_NC] = 4,
};

static const u8 ieee8021q_4queue_tt_tc_map[] = {
	[IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0,
	[IEEE8021Q_TT_EE] = 1, [IEEE8021Q_TT_CA] = 1,
	[IEEE8021Q_TT_VI] = 2, [IEEE8021Q_TT_VO] = 2,
	[IEEE8021Q_TT_IC] = 3, [IEEE8021Q_TT_NC] = 3,
};

static const u8 ieee8021q_3queue_tt_tc_map[] = {
	[IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0,
	[IEEE8021Q_TT_EE] = 0, [IEEE8021Q_TT_CA] = 0,
	[IEEE8021Q_TT_VI] = 1, [IEEE8021Q_TT_VO] = 1,
	[IEEE8021Q_TT_IC] = 2, [IEEE8021Q_TT_NC] = 2,
};

static const u8 ieee8021q_2queue_tt_tc_map[] = {
	[IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0,
	[IEEE8021Q_TT_EE] = 0, [IEEE8021Q_TT_CA] = 0,
	[IEEE8021Q_TT_VI] = 1, [IEEE8021Q_TT_VO] = 1,
	[IEEE8021Q_TT_IC] = 1, [IEEE8021Q_TT_NC] = 1,
};

static const u8 ieee8021q_1queue_tt_tc_map[] = {
	[IEEE8021Q_TT_BK] = 0, [IEEE8021Q_TT_BE] = 0,
	[IEEE8021Q_TT_EE] = 0, [IEEE8021Q_TT_CA] = 0,
	[IEEE8021Q_TT_VI] = 0, [IEEE8021Q_TT_VO] = 0,
	[IEEE8021Q_TT_IC] = 0, [IEEE8021Q_TT_NC] = 0,
};

/**
 * ieee8021q_tt_to_tc - Map IEEE 802.1Q Traffic Type to Traffic Class
 * @tt: IEEE 802.1Q Traffic Type
 * @num_queues: Number of queues
 *
 * This function maps an IEEE 802.1Q Traffic Type to a Traffic Class (TC) based
 * on the number of queues configured on the NIC. The mapping is based on the
 * example provided by IEEE 802.1Q-2022 in Annex I "I.3 Traffic type to traffic
 * class mapping" and Table I-1 "Traffic type to traffic class mapping".
 *
 * Return: Traffic Class corresponding to the given Traffic Type or negative
 * value in case of error.
 */
int ieee8021q_tt_to_tc(enum ieee8021q_traffic_type tt, unsigned int num_queues)
{
	if (tt < 0 || tt >= IEEE8021Q_TT_MAX) {
		pr_err("Requested Traffic Type (%d) is out of range (%d)\n", tt,
		       IEEE8021Q_TT_MAX);
		return -EINVAL;
	}

	switch (num_queues) {
	case 8:
		compiletime_assert(ARRAY_SIZE(ieee8021q_8queue_tt_tc_map) !=
				   IEEE8021Q_TT_MAX - 1,
				   "ieee8021q_8queue_tt_tc_map != max - 1");
		return ieee8021q_8queue_tt_tc_map[tt];
	case 7:
		compiletime_assert(ARRAY_SIZE(ieee8021q_7queue_tt_tc_map) !=
				   IEEE8021Q_TT_MAX - 1,
				   "ieee8021q_7queue_tt_tc_map != max - 1");

		return ieee8021q_7queue_tt_tc_map[tt];
	case 6:
		compiletime_assert(ARRAY_SIZE(ieee8021q_6queue_tt_tc_map) !=
				   IEEE8021Q_TT_MAX - 1,
				   "ieee8021q_6queue_tt_tc_map != max - 1");

		return ieee8021q_6queue_tt_tc_map[tt];
	case 5:
		compiletime_assert(ARRAY_SIZE(ieee8021q_5queue_tt_tc_map) !=
				   IEEE8021Q_TT_MAX - 1,
				   "ieee8021q_5queue_tt_tc_map != max - 1");

		return ieee8021q_5queue_tt_tc_map[tt];
	case 4:
		compiletime_assert(ARRAY_SIZE(ieee8021q_4queue_tt_tc_map) !=
				   IEEE8021Q_TT_MAX - 1,
				   "ieee8021q_4queue_tt_tc_map != max - 1");

		return ieee8021q_4queue_tt_tc_map[tt];
	case 3:
		compiletime_assert(ARRAY_SIZE(ieee8021q_3queue_tt_tc_map) !=
				   IEEE8021Q_TT_MAX - 1,
				   "ieee8021q_3queue_tt_tc_map != max - 1");

		return ieee8021q_3queue_tt_tc_map[tt];
	case 2:
		compiletime_assert(ARRAY_SIZE(ieee8021q_2queue_tt_tc_map) !=
				   IEEE8021Q_TT_MAX - 1,
				   "ieee8021q_2queue_tt_tc_map != max - 1");

		return ieee8021q_2queue_tt_tc_map[tt];
	case 1:
		compiletime_assert(ARRAY_SIZE(ieee8021q_1queue_tt_tc_map) !=
				   IEEE8021Q_TT_MAX - 1,
				   "ieee8021q_1queue_tt_tc_map != max - 1");

		return ieee8021q_1queue_tt_tc_map[tt];
	}

	pr_err("Invalid number of queues %d\n", num_queues);

	return -EINVAL;
}
EXPORT_SYMBOL_GPL(ieee8021q_tt_to_tc);

/**
 * ietf_dscp_to_ieee8021q_tt - Map IETF DSCP to IEEE 802.1Q Traffic Type
 * @dscp: IETF DSCP value
 *
 * This function maps an IETF DSCP value to an IEEE 802.1Q Traffic Type (TT).
 * Since there is no corresponding mapping between DSCP and IEEE 802.1Q Traffic
 * Type, this function is inspired by the RFC8325 documentation which describe
 * the mapping between DSCP and 802.11 User Priority (UP) values.
 *
 * Return: IEEE 802.1Q Traffic Type corresponding to the given DSCP value
 */
int ietf_dscp_to_ieee8021q_tt(u8 dscp)
{
	switch (dscp) {
	case DSCP_CS0:
	/* Comment from RFC8325:
	 * [RFC4594], Section 4.8, recommends High-Throughput Data be marked
	 * AF1x (that is, AF11, AF12, and AF13, according to the rules defined
	 * in [RFC2475]).
	 *
	 * By default (as described in Section 2.3), High-Throughput Data will
	 * map to UP 1 and, thus, to the Background Access Category (AC_BK),
	 * which is contrary to the intent expressed in [RFC4594].

	 * Unfortunately, there really is no corresponding fit for the High-
	 * Throughput Data service class within the constrained 4 Access
	 * Category [IEEE.802.11-2016] model.  If the High-Throughput Data
	 * service class is assigned to the Best Effort Access Category (AC_BE),
	 * then it would contend with Low-Latency Data (while [RFC4594]
	 * recommends a distinction in servicing between these service classes)
	 * as well as with the default service class; alternatively, if it is
	 * assigned to the Background Access Category (AC_BK), then it would
	 * receive a less-then-best-effort service and contend with Low-Priority
	 * Data (as discussed in Section 4.2.10).
	 *
	 * As such, since there is no directly corresponding fit for the High-
	 * Throughout Data service class within the [IEEE.802.11-2016] model, it
	 * is generally RECOMMENDED to map High-Throughput Data to UP 0, thereby
	 * admitting it to the Best Effort Access Category (AC_BE).
	 *
	 * Note: The above text is from RFC8325 which is describing the mapping
	 * between DSCP and 802.11 User Priority (UP) values. The mapping
	 * between UP and IEEE 802.1Q Traffic Type is not defined in the RFC but
	 * the 802.11 AC_BK and AC_BE are closely related to the IEEE 802.1Q
	 * Traffic Types BE and BK.
	 */
	case DSCP_AF11:
	case DSCP_AF12:
	case DSCP_AF13:
		return IEEE8021Q_TT_BE;
	/* Comment from RFC8325:
	 * RFC3662 and RFC4594 both recommend Low-Priority Data be marked
	 * with DSCP CS1. The Low-Priority Data service class loosely
	 * corresponds to the [IEEE.802.11-2016] Background Access Category
	 */
	case DSCP_CS1:
		return IEEE8021Q_TT_BK;
	case DSCP_CS2:
	case DSCP_AF21:
	case DSCP_AF22:
	case DSCP_AF23:
		return IEEE8021Q_TT_EE;
	case DSCP_CS3:
	case DSCP_AF31:
	case DSCP_AF32:
	case DSCP_AF33:
		return IEEE8021Q_TT_CA;
	case DSCP_CS4:
	case DSCP_AF41:
	case DSCP_AF42:
	case DSCP_AF43:
		return IEEE8021Q_TT_VI;
	case DSCP_CS5:
	case DSCP_EF:
	case DSCP_VOICE_ADMIT:
		return IEEE8021Q_TT_VO;
	case DSCP_CS6:
		return IEEE8021Q_TT_IC;
	case DSCP_CS7:
		return IEEE8021Q_TT_NC;
	}

	return SIMPLE_IETF_DSCP_TO_IEEE8021Q_TT(dscp);
}
EXPORT_SYMBOL_GPL(ietf_dscp_to_ieee8021q_tt);