net: add example SOCKET_URING_OP_SIOCINQ/SOCKET_URING_OP_SIOCOUTQ io_uring-fops.v6
authorJens Axboe <axboe@kernel.dk>
Fri, 18 Dec 2020 22:12:46 +0000 (15:12 -0700)
committerJens Axboe <axboe@kernel.dk>
Fri, 13 Aug 2021 14:32:18 +0000 (08:32 -0600)
This adds support for these sample ioctls for tcp/udp/raw ipv4/ipv6.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
include/net/raw.h
include/net/tcp.h
include/net/udp.h
include/uapi/linux/net.h
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/raw.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c

index 8ad8df5948536483c3467bff68ec0796b0712e67..27098db724dd28989b865399fda4dd026a553213 100644 (file)
@@ -82,4 +82,7 @@ static inline bool raw_sk_bound_dev_eq(struct net *net, int bound_dev_if,
 #endif
 }
 
+int raw_uring_cmd(struct sock *sk, struct io_uring_cmd *cmd,
+                       enum io_uring_cmd_flags issue_flags);
+
 #endif /* _RAW_H */
index 784d5c3ef1c5be0b54194711ff7f306d271d95c3..dd71a101a0a8f796d20df563a7df2eac893388be 100644 (file)
@@ -350,6 +350,8 @@ void tcp_twsk_destructor(struct sock *sk);
 ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
                        struct pipe_inode_info *pipe, size_t len,
                        unsigned int flags);
+int tcp_uring_cmd(struct sock *sk, struct io_uring_cmd *cmd,
+                       enum io_uring_cmd_flags issue_flags);
 
 void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks);
 static inline void tcp_dec_quickack_mode(struct sock *sk,
index 360df454356cbd956c9dd19655d1f667a0e621a9..f29556769d1889e26626649b7f8c1fc19e710cf6 100644 (file)
@@ -331,6 +331,8 @@ struct sock *udp6_lib_lookup_skb(const struct sk_buff *skb,
                                 __be16 sport, __be16 dport);
 int udp_read_sock(struct sock *sk, read_descriptor_t *desc,
                  sk_read_actor_t recv_actor);
+int udp_uring_cmd(struct sock *sk, struct io_uring_cmd *cmd,
+                       enum io_uring_cmd_flags issue_flags);
 
 /* UDP uses skb->dev_scratch to cache as much information as possible and avoid
  * possibly multiple cache miss on dequeue()
index 4dabec6bd957d604dd3f18f7b9896c82a789eb87..5e8d604e4cc6875f62b2c2f666487f7f6cc60c66 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef _UAPI_LINUX_NET_H
 #define _UAPI_LINUX_NET_H
 
+#include <linux/types.h>
 #include <linux/socket.h>
 #include <asm/socket.h>
 
@@ -55,4 +56,20 @@ typedef enum {
 
 #define __SO_ACCEPTCON (1 << 16)       /* performed a listen           */
 
+enum {
+       SOCKET_URING_OP_SIOCINQ         = 0,
+       SOCKET_URING_OP_SIOCOUTQ,
+
+       /*
+        * This is reserved for custom sub protocol
+        */
+       SOCKET_URING_OP_SUBPROTO_CMD    = 0xffff,
+};
+
+struct sock_uring_cmd {
+       __u16   op;
+       __u16   unused[3];
+       __u64   unused2[4];
+};
+
 #endif /* _UAPI_LINUX_NET_H */
index bb446e60cf58057b448f094b4d6f48d6e91d113c..d54a044f98ab09255cb8d720fa036c7d0afc6f7b 100644 (file)
@@ -75,6 +75,7 @@
 #include <linux/netfilter_ipv4.h>
 #include <linux/compat.h>
 #include <linux/uio.h>
+#include <linux/io_uring.h>
 
 struct raw_frag_vec {
        struct msghdr *msg;
@@ -878,6 +879,31 @@ static int raw_getsockopt(struct sock *sk, int level, int optname,
        return do_raw_getsockopt(sk, level, optname, optval, optlen);
 }
 
+int raw_uring_cmd(struct sock *sk, struct io_uring_cmd *cmd,
+                 enum io_uring_cmd_flags issue_flags)
+{
+       struct sock_uring_cmd *scmd = (struct sock_uring_cmd *)&cmd->pdu;
+
+       switch (scmd->op) {
+       case SOCKET_URING_OP_SIOCOUTQ:
+               return sk_wmem_alloc_get(sk);
+       case SOCKET_URING_OP_SIOCINQ: {
+               struct sk_buff *skb;
+               int amount = 0;
+
+               spin_lock_bh(&sk->sk_receive_queue.lock);
+               skb = skb_peek(&sk->sk_receive_queue);
+               if (skb)
+                       amount = skb->len;
+               spin_unlock_bh(&sk->sk_receive_queue.lock);
+               return amount;
+               }
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+EXPORT_SYMBOL_GPL(raw_uring_cmd);
+
 static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        switch (cmd) {
@@ -956,6 +982,7 @@ struct proto raw_prot = {
        .release_cb        = ip4_datagram_release_cb,
        .hash              = raw_hash_sk,
        .unhash            = raw_unhash_sk,
+       .uring_cmd         = raw_uring_cmd,
        .obj_size          = sizeof(struct raw_sock),
        .useroffset        = offsetof(struct raw_sock, filter),
        .usersize          = sizeof_field(struct raw_sock, filter),
index 8cb44040ec68b52d18f455d04a26aa2363ede7ce..0b703a37359365014a6916187690b9767737829e 100644 (file)
 #include <linux/uaccess.h>
 #include <asm/ioctls.h>
 #include <net/busy_poll.h>
+#include <linux/io_uring.h>
 
 /* Track pending CMSGs. */
 enum {
@@ -601,6 +602,41 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
 }
 EXPORT_SYMBOL(tcp_poll);
 
+int tcp_uring_cmd(struct sock *sk, struct io_uring_cmd *cmd,
+                 enum io_uring_cmd_flags issue_flags)
+{
+       struct sock_uring_cmd *scmd = (struct sock_uring_cmd *)&cmd->pdu;
+       struct tcp_sock *tp = tcp_sk(sk);
+       bool slow;
+       int ret;
+
+       switch (scmd->op) {
+       case SOCKET_URING_OP_SIOCINQ:
+               if (sk->sk_state == TCP_LISTEN)
+                       return -EINVAL;
+
+               slow = lock_sock_fast(sk);
+               ret = tcp_inq(sk);
+               unlock_sock_fast(sk, slow);
+               break;
+       case SOCKET_URING_OP_SIOCOUTQ:
+               if (sk->sk_state == TCP_LISTEN)
+                       return -EINVAL;
+
+               if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
+                       ret = 0;
+               else
+                       ret = READ_ONCE(tp->write_seq) - tp->snd_una;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(tcp_uring_cmd);
+
 int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index a692626c19e443343027b09d04eaa6f8ce24cca2..0169d50671f8e3b39263466575769f129cf48424 100644 (file)
@@ -2817,6 +2817,7 @@ struct proto tcp_prot = {
        .disconnect             = tcp_disconnect,
        .accept                 = inet_csk_accept,
        .ioctl                  = tcp_ioctl,
+       .uring_cmd              = tcp_uring_cmd,
        .init                   = tcp_v4_init_sock,
        .destroy                = tcp_v4_destroy_sock,
        .shutdown               = tcp_shutdown,
index 1a742b710e543e68e4ef4cb56c0c28d9597057a4..e407d3a3e952656379fa5ad7926fe21ea9d1e5de 100644 (file)
 #include <net/sock_reuseport.h>
 #include <net/addrconf.h>
 #include <net/udp_tunnel.h>
+#include <linux/io_uring.h>
 #if IS_ENABLED(CONFIG_IPV6)
 #include <net/ipv6_stubs.h>
 #endif
@@ -1695,6 +1696,22 @@ static int first_packet_length(struct sock *sk)
        return res;
 }
 
+int udp_uring_cmd(struct sock *sk, struct io_uring_cmd *cmd,
+                 enum io_uring_cmd_flags issue_flags)
+{
+       struct sock_uring_cmd *scmd = (struct sock_uring_cmd *)&cmd->pdu;
+
+       switch (scmd->op) {
+       case SOCKET_URING_OP_SIOCINQ:
+               return max_t(int, 0, first_packet_length(sk));
+       case SOCKET_URING_OP_SIOCOUTQ:
+               return sk_wmem_alloc_get(sk);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+EXPORT_SYMBOL_GPL(udp_uring_cmd);
+
 /*
  *     IOCTL requests applicable to the UDP protocol
  */
@@ -2900,6 +2917,7 @@ struct proto udp_prot = {
        .connect                = ip4_datagram_connect,
        .disconnect             = udp_disconnect,
        .ioctl                  = udp_ioctl,
+       .uring_cmd              = udp_uring_cmd,
        .init                   = udp_init_sock,
        .destroy                = udp_destroy_sock,
        .setsockopt             = udp_setsockopt,
index 60f1e4f5be5aaeded68aa44b22f6507c7ccdbc01..4cdaa055737d1ffd94d90b908cbff3033bfdb32c 100644 (file)
@@ -1235,6 +1235,7 @@ struct proto rawv6_prot = {
        .connect           = ip6_datagram_connect_v6_only,
        .disconnect        = __udp_disconnect,
        .ioctl             = rawv6_ioctl,
+       .uring_cmd         = raw_uring_cmd,
        .init              = rawv6_init_sk,
        .setsockopt        = rawv6_setsockopt,
        .getsockopt        = rawv6_getsockopt,
index 0ce52d46e4f81b221a6acd4a0dd7b0d462dbac7a..6990d166e2d9e1f6def1f8ede3cfc1a65c6c34be 100644 (file)
@@ -2161,6 +2161,7 @@ struct proto tcpv6_prot = {
        .disconnect             = tcp_disconnect,
        .accept                 = inet_csk_accept,
        .ioctl                  = tcp_ioctl,
+       .uring_cmd              = tcp_uring_cmd,
        .init                   = tcp_v6_init_sock,
        .destroy                = tcp_v6_destroy_sock,
        .shutdown               = tcp_shutdown,
index c5e15e94bb004244f4d3a42426ec9ccaef66778f..2f9afd230de707b5ff734603a8f25391a334a594 100644 (file)
@@ -1719,6 +1719,7 @@ struct proto udpv6_prot = {
        .connect                = ip6_datagram_connect,
        .disconnect             = udp_disconnect,
        .ioctl                  = udp_ioctl,
+       .uring_cmd              = udp_uring_cmd,
        .init                   = udp_init_sock,
        .destroy                = udpv6_destroy_sock,
        .setsockopt             = udpv6_setsockopt,