[[qos-dscp-pcp]] == QoS, DSCP/TOS, Priority and IEEE 802.1q PCP In many use cases operators want to apply different QoS classes for user plane vs. control plane traffic. IP Routers, Ethernet switches and other network gear can then perform intelligent queue management as required for the respective service. For example, voice user plane frames need a rather stable and short latency, while IP user plane and control plane traffic has less critical latency requirements. === IP Level (DSCP) At IP level, different priorities / classes of traffic are expressed in accordance to <> by the DSCP (Differentiated Services Code Point) field of the IP header. DSCP resembles the upper 6 bits of the field formerly known as the TOS bits as per <>. On Linux and other operating systems with BSD-style sockets API, the applications can request a specific DSCP value to be used for packets generated by those sockets. Osmocom CNI software such as osmo-bts and osmo-mgw support setting the DSCP value via VTY commands, see e.g. the `rtp ip-dscp` setting of the `bts` node in osmo-bts. === Packet Priority In the Linux network stack, every packet is represented by `struct sk_buff`, which has an associated _priority_. Furthermore, every socket through which applications send data have an associated _socket priority_. Each time a packet is transmitted through a given socket, the packet inherits the packet priority from the socket priority. Furthermore, there is a mapping table that maps DSCP/TOS bits to priority. The sixteen different TOS bit values are mapped to priority values as follows: .Linux kernel default DSCP/TOS -> priority mapping [options="header",width="50%"] |=== |TOS (binary)|DSCP (binary)|Priority (decimal) |xxx0000x|xxx000|0 |xxx0001x|xxx000|0 |xxx0010x|xxx001|0 |xxx0011x|xxx001|0 |xxx0100x|xxx010|2 |xxx0101x|xxx010|2 |xxx0110x|xxx011|2 |xxx0111x|xxx011|2 |xxx1000x|xxx100|6 |xxx1001x|xxx100|6 |xxx1010x|xxx101|6 |xxx1011x|xxx101|6 |xxx1100x|xxx110|4 |xxx1101x|xxx110|4 |xxx1110x|xxx111|4 |xxx1111x|xxx111|4 |=== This table of default DSCP/TOS -> priority bit mappings cannot be modified. However, the per-packet _priority_ values can be set by various means of network policy, including * by packet filter rules (iptables, ip6tables, nftables) ** if you use `iptables`, using `CLASSIFY --set-class` in the `mangle` table ** if you use `nftables`, using `meta priority set` in the `mangle` table * by the application using the SO_PRIORITY socket option (currently not yet supported by Osmocom CNI) === Ethernet Level (PCP) At Ethernet level, different priorities / QoS classes are expressed by the so-called PCP (Priority Code Point) field in the IEEE 802.1q (VLAN) header. NOTE:: This means that PCP functionality requires the use of IEEE 802.q VLAN. You cannot use PCP without VLAN. The Linux kernel assigns IEEE 802.1q PCP bits based on a _mapping_ between the _priority_ and the PCP value. Each VLAN network device maintains a separate map for both egress (transmit) and ingress (receive) path. The current priority mappings can be inspected via the `/proc` filesystem. For example, if you have a VLAN device `eth0.9` for VLAN ID 9 on the net-device `eth0`, you can use the following example: .Example: Inspecting the current egress QoS map ---- $ sudo cat /proc/net/vlan/eth0.9<1> eth0.9 VID: 9 REORDER_HDR: 1 dev->priv_flags: 1021 total frames received 123340 total bytes received 40668066 Broadcast/Multicast Rcvd 1106 total frames transmitted 10499 total bytes transmitted 1570809 Device: eth0 INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 <2> EGRESS priority mappings: <3> ---- <1> make sure to specify your specific VLAN interface name here instead of `eth0.9` <2> ingress priority mappings (all PCP values mapped to priority 0) <3> egress priority mappings (empty) As we can see in the above example, there are no egress priority mappings yet. Let's create three new mappings, mapping _priority_ value 1 to PCP 1, _priority_ 2 to PCP 2, and _priority_ 3 to PCP 3: .Example: Creating three new egress QoS mappings ---- $ sudo ip link set dev eth0.9<1> type vlan egress-qos-map 1:1 2:2 3:3 <2> $ sudo cat /proc/net/vlan/eth0.9 <3> eth0.9 VID: 9 REORDER_HDR: 1 dev->priv_flags: 1021 total frames received 123898 total bytes received 40843611 Broadcast/Multicast Rcvd 1106 total frames transmitted 10517 total bytes transmitted 1574357 Device: eth0 INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 EGRESS priority mappings: 1:1 2:2 3:3 <4> ---- <1> make sure to specify your specific VLAN interface name here instead of `eth0.9` <2> command to define three new egress QoS maps <3> command to re-display the current status <4> three new egress mappings are shown as given in `ip` command NOTE:: The settings of the `ip` command are volatile and only active until the next reboot (or the network device or VLAN is removed). Please refer to the documentation of your specific Linux distribution in order to find out how to make such settings persistent by means of an `ifup` hook whenever the interface comes up. For CentOS/RHEL 8 this can e.g. be achieved by means of an `/sbin/ifup-local script` (when using `network-scripts` and not NetworkManager). For Debian or Ubuntu, this typically involves adding `up` lines to `/etc/network/interfaces` or a `/etc/network/if-up.d` script. === Putting things together Assuming one needs to set both the DSCP bits as well as the PCP for certain traffic, the above-mentioned mechanisms need to be combined as follows: . configure the osmocom program to set the DSCP value . use the default DSCP -> priority mapping, if possible . configure an egress QoS map to map from priority to PCP If the desired combination of DSCP + PCP cannot be achieved that way, due to the rather static default kernel mapping table, one needs to go one step further: . configure the osmocom program to set the DSCP value . use packet filter rules to set the priority based on DSCP . configure an egress QoS map to map from priority to PCP include::{srcdir}/chapters/qos-example.adoc[]