]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
socket-util: introduce tos_to_priority()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 2 May 2026 13:31:03 +0000 (22:31 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Sun, 3 May 2026 09:17:20 +0000 (10:17 +0100)
This maps from TOS, which can be used for setsockopt(IPPROTO_IP, IP_TOS),
to socket priority, which can be used for setsockopt(SOL_SOCKET, SO_PRIORITY).

With this, we can set priority like the following:
```
uint8_t tos = IPTOS_CLASS_CS6;
setsockopt_int(fd, IPPROTO_IP, IP_TOS, tos);
setsockopt_int(fd, SOL_SOCKET, SO_PRIORITY, tos_to_priority(tos));
```

Co-authored with Google Gemini.

src/basic/socket-util.c
src/basic/socket-util.h
src/test/test-socket-util.c

index 698aa69a4b0f170663b13e64730b17957430de74..2e0ee684ff98bcfe392d7a91b4406ac7c814c514 100644 (file)
@@ -3,6 +3,7 @@
 #include <fcntl.h>
 #include <linux/if.h>
 #include <linux/if_arp.h>
+#include <linux/pkt_sched.h>
 #include <mqueue.h>
 #include <net/if.h>
 #include <netdb.h>
@@ -1873,3 +1874,29 @@ void cmsg_close_all(struct msghdr *mh) {
                 }
         }
 }
+
+int tos_to_priority(uint8_t tos) {
+        /* Map the IP Precedence (top 3 bits of the TOS field) to Linux internal packet priorities
+         * (TC_PRIO_*). This exactly mirrors the standard Linux kernel IP precedence-to-priority mapping
+         * (rt_tos2priority) to ensure consistent behavior when explicitly setting SO_PRIORITY. */
+        switch (IPTOS_PREC(tos)) {
+        case IPTOS_PREC_NETCONTROL:      /* 0xc0 (CS7) - Network Control. Used for infrastructure control (e.g., STP, keepalives). */
+        case IPTOS_PREC_INTERNETCONTROL: /* 0xe0 (CS6) - Internetwork Control. Used for routing protocols (e.g., OSPF, BGP) and DHCP. */
+                return TC_PRIO_CONTROL;
+
+        case IPTOS_PREC_CRITIC_ECP:      /* 0xa0 (CS5) - Critical. Used for delay-sensitive traffic like Voice over IP (VoIP). */
+        case IPTOS_PREC_FLASHOVERRIDE:   /* 0x80 (CS4) - Flash Override. Used for interactive video and multimedia. */
+                return TC_PRIO_INTERACTIVE;
+
+        case IPTOS_PREC_FLASH:           /* 0x60 (CS3) - Flash. Used for broadcast video and call signaling (e.g., SIP). */
+        case IPTOS_PREC_IMMEDIATE:       /* 0x40 (CS2) - Immediate. Used for OAM (Operations, Administration, and Management) and transactional data. */
+                return TC_PRIO_INTERACTIVE_BULK;
+
+        case IPTOS_PREC_PRIORITY:        /* 0x20 (CS1) - Priority. Used for background traffic and bulk data transfers. */
+                return TC_PRIO_BULK;
+
+        case IPTOS_PREC_ROUTINE:         /* 0x00 (CS0) - Routine. Best effort traffic. */
+        default:
+                return TC_PRIO_BESTEFFORT;
+        }
+}
index 78b948ad461b57ea09751e128b4e92eb7fbb23a1..208eb7ac077bed00c5166196522cf0c7fc935017 100644 (file)
@@ -270,3 +270,5 @@ int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_
 int socket_get_cookie(int fd, uint64_t *ret);
 
 void cmsg_close_all(struct msghdr *mh);
+
+int tos_to_priority(uint8_t tos);
index 090839ac0684298490b380ada78b72eff95b689f..713844b09b720ceb24b92d8958052112cef65c94 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <fcntl.h>
 #include <grp.h>
+#include <linux/pkt_sched.h>
+#include <netinet/ip.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -530,4 +532,22 @@ TEST(getpeerpidref) {
         ASSERT_TRUE(!pidref_equal(&pidref0, &pidref_pid1));
 }
 
+TEST(tos_to_priority) {
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS7), TC_PRIO_CONTROL);
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS6), TC_PRIO_CONTROL);
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS5), TC_PRIO_INTERACTIVE);
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS4), TC_PRIO_INTERACTIVE);
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS3), TC_PRIO_INTERACTIVE_BULK);
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS2), TC_PRIO_INTERACTIVE_BULK);
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS1), TC_PRIO_BULK);
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS0), TC_PRIO_BESTEFFORT);
+
+        /* check if lower bits are correctly filtered. */
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS7 | IPTOS_LOWDELAY), TC_PRIO_CONTROL);
+        ASSERT_EQ(tos_to_priority(IPTOS_CLASS_CS1 | IPTOS_LOWCOST), TC_PRIO_BULK);
+
+        ASSERT_EQ(tos_to_priority(0x00), TC_PRIO_BESTEFFORT);
+        ASSERT_EQ(tos_to_priority(0xff), TC_PRIO_CONTROL);
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);