]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
sock: support SO_PRIORITY cmsg
authorAnna Emese Nyiri <annaemesenyiri@gmail.com>
Fri, 13 Dec 2024 08:44:55 +0000 (09:44 +0100)
committerJakub Kicinski <kuba@kernel.org>
Tue, 17 Dec 2024 02:13:44 +0000 (18:13 -0800)
The Linux socket API currently allows setting SO_PRIORITY at the
socket level, applying a uniform priority to all packets sent through
that socket. The exception to this is IP_TOS, when the priority value
is calculated during the handling of
ancillary data, as implemented in commit f02db315b8d8 ("ipv4: IP_TOS
and IP_TTL can be specified as ancillary data").
However, this is a computed
value, and there is currently no mechanism to set a custom priority
via control messages prior to this patch.

According to this patch, if SO_PRIORITY is specified as ancillary data,
the packet is sent with the priority value set through
sockc->priority, overriding the socket-level values
set via the traditional setsockopt() method. This is analogous to
the existing support for SO_MARK, as implemented in
commit c6af0c227a22 ("ip: support SO_MARK cmsg").

If both cmsg SO_PRIORITY and IP_TOS are passed, then the one that
takes precedence is the last one in the cmsg list.

This patch has the side effect that raw_send_hdrinc now interprets cmsg
IP_TOS.

Reviewed-by: Willem de Bruijn <willemb@google.com>
Suggested-by: Ferenc Fejes <fejes@inf.elte.hu>
Signed-off-by: Anna Emese Nyiri <annaemesenyiri@gmail.com>
Link: https://patch.msgid.link/20241213084457.45120-3-annaemesenyiri@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
13 files changed:
include/net/inet_sock.h
include/net/ip.h
include/net/sock.h
net/can/raw.c
net/core/sock.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/raw.c
net/ipv6/ip6_output.c
net/ipv6/ping.c
net/ipv6/raw.c
net/ipv6/udp.c
net/packet/af_packet.c

index 56d8bc5593d3dfffd5f94cf7c6383948881917df..3ccbad881d74f7b9aefc7c81f107a60c8ea0b050 100644 (file)
@@ -172,7 +172,7 @@ struct inet_cork {
        u8                      tx_flags;
        __u8                    ttl;
        __s16                   tos;
-       char                    priority;
+       u32                     priority;
        __u16                   gso_size;
        u32                     ts_opt_id;
        u64                     transmit_time;
index 0e548c1f2a0ecd6dd6616a456c6cf9284d1c6203..9f5e33e371fcdd8ea88c54584b8d4b6c50e7d0c9 100644 (file)
@@ -81,7 +81,6 @@ struct ipcm_cookie {
        __u8                    protocol;
        __u8                    ttl;
        __s16                   tos;
-       char                    priority;
        __u16                   gso_size;
 };
 
@@ -96,6 +95,7 @@ static inline void ipcm_init_sk(struct ipcm_cookie *ipcm,
        ipcm_init(ipcm);
 
        ipcm->sockc.mark = READ_ONCE(inet->sk.sk_mark);
+       ipcm->sockc.priority = READ_ONCE(inet->sk.sk_priority);
        ipcm->sockc.tsflags = READ_ONCE(inet->sk.sk_tsflags);
        ipcm->oif = READ_ONCE(inet->sk.sk_bound_dev_if);
        ipcm->addr = inet->inet_saddr;
index 7464e9f9f47c503c5a41fd64e9f15c15f3c2c812..316a34d6c48b733ee9f7fdf137a1dec69a39d61f 100644 (file)
@@ -1814,13 +1814,15 @@ struct sockcm_cookie {
        u32 mark;
        u32 tsflags;
        u32 ts_opt_id;
+       u32 priority;
 };
 
 static inline void sockcm_init(struct sockcm_cookie *sockc,
                               const struct sock *sk)
 {
        *sockc = (struct sockcm_cookie) {
-               .tsflags = READ_ONCE(sk->sk_tsflags)
+               .tsflags = READ_ONCE(sk->sk_tsflags),
+               .priority = READ_ONCE(sk->sk_priority),
        };
 }
 
index 255c0a8f39d6bae2e14b6e8a0f1d1a0a2d2a1e99..46e8ed9d64da397ae2dd86c0bd10e5d8e1307cb8 100644 (file)
@@ -962,7 +962,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        }
 
        skb->dev = dev;
-       skb->priority = READ_ONCE(sk->sk_priority);
+       skb->priority = sockc.priority;
        skb->mark = READ_ONCE(sk->sk_mark);
        skb->tstamp = sockc.transmit_time;
 
index 9016f984d44ebd158ef6427c8d3a51080b11102f..a3d9941c1d3257eb9edc8f3f1abed783a4009037 100644 (file)
@@ -2947,6 +2947,13 @@ int __sock_cmsg_send(struct sock *sk, struct cmsghdr *cmsg,
        case SCM_RIGHTS:
        case SCM_CREDENTIALS:
                break;
+       case SO_PRIORITY:
+               if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32)))
+                       return -EINVAL;
+               if (!sk_set_prio_allowed(sk, *(u32 *)CMSG_DATA(cmsg)))
+                       return -EPERM;
+               sockc->priority = *(u32 *)CMSG_DATA(cmsg);
+               break;
        default:
                return -EINVAL;
        }
index a59204a8d85053a9b8c9e86a404aa4bf2f0d2416..f45a083f2c13bf091da7909b0690c893028b6ffa 100644 (file)
@@ -1333,7 +1333,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
        cork->ttl = ipc->ttl;
        cork->tos = ipc->tos;
        cork->mark = ipc->sockc.mark;
-       cork->priority = ipc->priority;
+       cork->priority = ipc->sockc.priority;
        cork->transmit_time = ipc->sockc.transmit_time;
        cork->tx_flags = 0;
        sock_tx_timestamp(sk, &ipc->sockc, &cork->tx_flags);
@@ -1470,7 +1470,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
                ip_options_build(skb, opt, cork->addr, rt);
        }
 
-       skb->priority = (cork->tos != -1) ? cork->priority: READ_ONCE(sk->sk_priority);
+       skb->priority = cork->priority;
        skb->mark = cork->mark;
        if (sk_is_tcp(sk))
                skb_set_delivery_time(skb, cork->transmit_time, SKB_CLOCK_MONOTONIC);
index cf377377b52d83fbc7ac979b02b5ca9a7d9abf4a..f6a03b418ddec727f3644531f62832a6d4e25db2 100644 (file)
@@ -315,7 +315,7 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
                        if (val < 0 || val > 255)
                                return -EINVAL;
                        ipc->tos = val;
-                       ipc->priority = rt_tos2priority(ipc->tos);
+                       ipc->sockc.priority = rt_tos2priority(ipc->tos);
                        break;
                case IP_PROTOCOL:
                        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
index 0e9e01967ec9411b92595aaffd0a0895711fbb1f..4304a68d1db058f87fe0672049e06a86e1962454 100644 (file)
@@ -358,7 +358,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
        skb_reserve(skb, hlen);
 
        skb->protocol = htons(ETH_P_IP);
-       skb->priority = READ_ONCE(sk->sk_priority);
+       skb->priority = sockc->priority;
        skb->mark = sockc->mark;
        skb_set_delivery_type_by_clockid(skb, sockc->transmit_time, sk->sk_clockid);
        skb_dst_set(skb, &rt->dst);
index 3d672dea9f56284e7a8ebabec037e04e7f3d19f4..993106876604b525e41d0bacddbe6992ca51f7b3 100644 (file)
@@ -1401,6 +1401,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
        cork->base.gso_size = ipc6->gso_size;
        cork->base.tx_flags = 0;
        cork->base.mark = ipc6->sockc.mark;
+       cork->base.priority = ipc6->sockc.priority;
        sock_tx_timestamp(sk, &ipc6->sockc, &cork->base.tx_flags);
        if (ipc6->sockc.tsflags & SOCKCM_FLAG_TS_OPT_ID) {
                cork->base.flags |= IPCORK_TS_OPT_ID;
@@ -1942,7 +1943,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
        hdr->saddr = fl6->saddr;
        hdr->daddr = *final_dst;
 
-       skb->priority = READ_ONCE(sk->sk_priority);
+       skb->priority = cork->base.priority;
        skb->mark = cork->base.mark;
        if (sk_is_tcp(sk))
                skb_set_delivery_time(skb, cork->base.transmit_time, SKB_CLOCK_MONOTONIC);
index 88b3fcacd4f948218608e9bc210c177d59a8312a..46b8adf6e7f8e2a37b23286515d2a91e1756e16a 100644 (file)
@@ -119,6 +119,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                return -EINVAL;
 
        ipcm6_init_sk(&ipc6, sk);
+       ipc6.sockc.priority = READ_ONCE(sk->sk_priority);
        ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
        ipc6.sockc.mark = READ_ONCE(sk->sk_mark);
 
index 8476a3944a884b8176e20520077f42cb531b9b06..a45aba090aa41a246efe2849450cc5127e3f789c 100644 (file)
@@ -619,7 +619,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
        skb_reserve(skb, hlen);
 
        skb->protocol = htons(ETH_P_IPV6);
-       skb->priority = READ_ONCE(sk->sk_priority);
+       skb->priority = sockc->priority;
        skb->mark = sockc->mark;
        skb_set_delivery_type_by_clockid(skb, sockc->transmit_time, sk->sk_clockid);
 
@@ -780,6 +780,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        ipcm6_init(&ipc6);
        ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
        ipc6.sockc.mark = fl6.flowi6_mark;
+       ipc6.sockc.priority = READ_ONCE(sk->sk_priority);
 
        if (sin6) {
                if (addr_len < SIN6_LEN_RFC2133)
index d766fd798ecf9916f4581a39aaea609ee7e864a6..7c14c449804cbdb8afdc713d49d21514ce963fef 100644 (file)
@@ -1448,6 +1448,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        ipc6.gso_size = READ_ONCE(up->gso_size);
        ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
        ipc6.sockc.mark = READ_ONCE(sk->sk_mark);
+       ipc6.sockc.priority = READ_ONCE(sk->sk_priority);
 
        /* destination address check */
        if (sin6) {
index 886c0dd47b66210e4bbaf8e78f1778c2d25b896e..f8d87d622699db2f32b4f93457cd1c44fec0b4c5 100644 (file)
@@ -3126,7 +3126,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 
        skb->protocol = proto;
        skb->dev = dev;
-       skb->priority = READ_ONCE(sk->sk_priority);
+       skb->priority = sockc.priority;
        skb->mark = sockc.mark;
        skb_set_delivery_type_by_clockid(skb, sockc.transmit_time, sk->sk_clockid);