| // 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); |