| 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 | |