|
| 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); |
0 commit comments