]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - net/xdp/xsk.c
xsk: add user memory registration support sockopt
[mirror_ubuntu-jammy-kernel.git] / net / xdp / xsk.c
CommitLineData
c0c77d8f
BT
1// SPDX-License-Identifier: GPL-2.0
2/* XDP sockets
3 *
4 * AF_XDP sockets allows a channel between XDP programs and userspace
5 * applications.
6 * Copyright(c) 2018 Intel Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * Author(s): Björn Töpel <bjorn.topel@intel.com>
18 * Magnus Karlsson <magnus.karlsson@intel.com>
19 */
20
21#define pr_fmt(fmt) "AF_XDP: %s: " fmt, __func__
22
23#include <linux/if_xdp.h>
24#include <linux/init.h>
25#include <linux/sched/mm.h>
26#include <linux/sched/signal.h>
27#include <linux/sched/task.h>
28#include <linux/socket.h>
29#include <linux/file.h>
30#include <linux/uaccess.h>
31#include <linux/net.h>
32#include <linux/netdevice.h>
33#include <net/xdp_sock.h>
34
35#include "xdp_umem.h"
36
37static struct xdp_sock *xdp_sk(struct sock *sk)
38{
39 return (struct xdp_sock *)sk;
40}
41
42static int xsk_release(struct socket *sock)
43{
44 struct sock *sk = sock->sk;
45 struct net *net;
46
47 if (!sk)
48 return 0;
49
50 net = sock_net(sk);
51
52 local_bh_disable();
53 sock_prot_inuse_add(net, sk->sk_prot, -1);
54 local_bh_enable();
55
56 sock_orphan(sk);
57 sock->sk = NULL;
58
59 sk_refcnt_debug_release(sk);
60 sock_put(sk);
61
62 return 0;
63}
64
65static int xsk_setsockopt(struct socket *sock, int level, int optname,
66 char __user *optval, unsigned int optlen)
67{
68 struct sock *sk = sock->sk;
69 struct xdp_sock *xs = xdp_sk(sk);
70 int err;
71
72 if (level != SOL_XDP)
73 return -ENOPROTOOPT;
74
75 switch (optname) {
76 case XDP_UMEM_REG:
77 {
78 struct xdp_umem_reg mr;
79 struct xdp_umem *umem;
80
81 if (xs->umem)
82 return -EBUSY;
83
84 if (copy_from_user(&mr, optval, sizeof(mr)))
85 return -EFAULT;
86
87 mutex_lock(&xs->mutex);
88 err = xdp_umem_create(&umem);
89
90 err = xdp_umem_reg(umem, &mr);
91 if (err) {
92 kfree(umem);
93 mutex_unlock(&xs->mutex);
94 return err;
95 }
96
97 /* Make sure umem is ready before it can be seen by others */
98 smp_wmb();
99
100 xs->umem = umem;
101 mutex_unlock(&xs->mutex);
102 return 0;
103 }
104 default:
105 break;
106 }
107
108 return -ENOPROTOOPT;
109}
110
111static struct proto xsk_proto = {
112 .name = "XDP",
113 .owner = THIS_MODULE,
114 .obj_size = sizeof(struct xdp_sock),
115};
116
117static const struct proto_ops xsk_proto_ops = {
118 .family = PF_XDP,
119 .owner = THIS_MODULE,
120 .release = xsk_release,
121 .bind = sock_no_bind,
122 .connect = sock_no_connect,
123 .socketpair = sock_no_socketpair,
124 .accept = sock_no_accept,
125 .getname = sock_no_getname,
126 .poll = sock_no_poll,
127 .ioctl = sock_no_ioctl,
128 .listen = sock_no_listen,
129 .shutdown = sock_no_shutdown,
130 .setsockopt = xsk_setsockopt,
131 .getsockopt = sock_no_getsockopt,
132 .sendmsg = sock_no_sendmsg,
133 .recvmsg = sock_no_recvmsg,
134 .mmap = sock_no_mmap,
135 .sendpage = sock_no_sendpage,
136};
137
138static void xsk_destruct(struct sock *sk)
139{
140 struct xdp_sock *xs = xdp_sk(sk);
141
142 if (!sock_flag(sk, SOCK_DEAD))
143 return;
144
145 xdp_put_umem(xs->umem);
146
147 sk_refcnt_debug_dec(sk);
148}
149
150static int xsk_create(struct net *net, struct socket *sock, int protocol,
151 int kern)
152{
153 struct sock *sk;
154 struct xdp_sock *xs;
155
156 if (!ns_capable(net->user_ns, CAP_NET_RAW))
157 return -EPERM;
158 if (sock->type != SOCK_RAW)
159 return -ESOCKTNOSUPPORT;
160
161 if (protocol)
162 return -EPROTONOSUPPORT;
163
164 sock->state = SS_UNCONNECTED;
165
166 sk = sk_alloc(net, PF_XDP, GFP_KERNEL, &xsk_proto, kern);
167 if (!sk)
168 return -ENOBUFS;
169
170 sock->ops = &xsk_proto_ops;
171
172 sock_init_data(sock, sk);
173
174 sk->sk_family = PF_XDP;
175
176 sk->sk_destruct = xsk_destruct;
177 sk_refcnt_debug_inc(sk);
178
179 xs = xdp_sk(sk);
180 mutex_init(&xs->mutex);
181
182 local_bh_disable();
183 sock_prot_inuse_add(net, &xsk_proto, 1);
184 local_bh_enable();
185
186 return 0;
187}
188
189static const struct net_proto_family xsk_family_ops = {
190 .family = PF_XDP,
191 .create = xsk_create,
192 .owner = THIS_MODULE,
193};
194
195static int __init xsk_init(void)
196{
197 int err;
198
199 err = proto_register(&xsk_proto, 0 /* no slab */);
200 if (err)
201 goto out;
202
203 err = sock_register(&xsk_family_ops);
204 if (err)
205 goto out_proto;
206
207 return 0;
208
209out_proto:
210 proto_unregister(&xsk_proto);
211out:
212 return err;
213}
214
215fs_initcall(xsk_init);