Skip to content

Commit 965a990

Browse files
magnus-karlssonAlexei Starovoitov
authored andcommitted
xsk: add support for bind for Rx
Here, the bind syscall is added. Binding an AF_XDP socket, means associating the socket to an umem, a netdev and a queue index. This can be done in two ways. The first way, creating a "socket from scratch". Create the umem using the XDP_UMEM_REG setsockopt and an associated fill queue with XDP_UMEM_FILL_QUEUE. Create the Rx queue using the XDP_RX_QUEUE setsockopt. Call bind passing ifindex and queue index ("channel" in ethtool speak). The second way to bind a socket, is simply skipping the umem/netdev/queue index, and passing another already setup AF_XDP socket. The new socket will then have the same umem/netdev/queue index as the parent so it will share the same umem. You must also set the flags field in the socket address to XDP_SHARED_UMEM. v2: Use PTR_ERR instead of passing error variable explicitly. Signed-off-by: Magnus Karlsson <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent b9b6b68 commit 965a990

File tree

7 files changed

+150
-1
lines changed

7 files changed

+150
-1
lines changed

include/net/xdp_sock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct xdp_sock {
2828
struct xsk_queue *rx;
2929
struct net_device *dev;
3030
struct xdp_umem *umem;
31+
u16 queue_id;
3132
/* Protects multiple processes in the control path */
3233
struct mutex mutex;
3334
};

include/uapi/linux/if_xdp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@
2121

2222
#include <linux/types.h>
2323

24+
/* Options for the sxdp_flags field */
25+
#define XDP_SHARED_UMEM 1
26+
27+
struct sockaddr_xdp {
28+
__u16 sxdp_family;
29+
__u32 sxdp_ifindex;
30+
__u32 sxdp_queue_id;
31+
__u32 sxdp_shared_umem_fd;
32+
__u16 sxdp_flags;
33+
};
34+
2435
/* XDP socket options */
2536
#define XDP_RX_RING 1
2637
#define XDP_UMEM_REG 3

net/xdp/xdp_umem.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,8 @@ int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
248248
put_pid(umem->pid);
249249
return err;
250250
}
251+
252+
bool xdp_umem_validate_queues(struct xdp_umem *umem)
253+
{
254+
return umem->fq;
255+
}

net/xdp/xdp_umem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct xdp_umem {
3939
struct work_struct work;
4040
};
4141

42+
bool xdp_umem_validate_queues(struct xdp_umem *umem);
4243
int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr);
4344
void xdp_get_umem(struct xdp_umem *umem);
4445
void xdp_put_umem(struct xdp_umem *umem);

net/xdp/xsk.c

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,18 @@ static int xsk_init_queue(u32 entries, struct xsk_queue **queue,
5757
return 0;
5858
}
5959

60+
static void __xsk_release(struct xdp_sock *xs)
61+
{
62+
/* Wait for driver to stop using the xdp socket. */
63+
synchronize_net();
64+
65+
dev_put(xs->dev);
66+
}
67+
6068
static int xsk_release(struct socket *sock)
6169
{
6270
struct sock *sk = sock->sk;
71+
struct xdp_sock *xs = xdp_sk(sk);
6372
struct net *net;
6473

6574
if (!sk)
@@ -71,6 +80,11 @@ static int xsk_release(struct socket *sock)
7180
sock_prot_inuse_add(net, sk->sk_prot, -1);
7281
local_bh_enable();
7382

83+
if (xs->dev) {
84+
__xsk_release(xs);
85+
xs->dev = NULL;
86+
}
87+
7488
sock_orphan(sk);
7589
sock->sk = NULL;
7690

@@ -80,6 +94,114 @@ static int xsk_release(struct socket *sock)
8094
return 0;
8195
}
8296

97+
static struct socket *xsk_lookup_xsk_from_fd(int fd)
98+
{
99+
struct socket *sock;
100+
int err;
101+
102+
sock = sockfd_lookup(fd, &err);
103+
if (!sock)
104+
return ERR_PTR(-ENOTSOCK);
105+
106+
if (sock->sk->sk_family != PF_XDP) {
107+
sockfd_put(sock);
108+
return ERR_PTR(-ENOPROTOOPT);
109+
}
110+
111+
return sock;
112+
}
113+
114+
static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
115+
{
116+
struct sockaddr_xdp *sxdp = (struct sockaddr_xdp *)addr;
117+
struct sock *sk = sock->sk;
118+
struct net_device *dev, *dev_curr;
119+
struct xdp_sock *xs = xdp_sk(sk);
120+
struct xdp_umem *old_umem = NULL;
121+
int err = 0;
122+
123+
if (addr_len < sizeof(struct sockaddr_xdp))
124+
return -EINVAL;
125+
if (sxdp->sxdp_family != AF_XDP)
126+
return -EINVAL;
127+
128+
mutex_lock(&xs->mutex);
129+
dev_curr = xs->dev;
130+
dev = dev_get_by_index(sock_net(sk), sxdp->sxdp_ifindex);
131+
if (!dev) {
132+
err = -ENODEV;
133+
goto out_release;
134+
}
135+
136+
if (!xs->rx) {
137+
err = -EINVAL;
138+
goto out_unlock;
139+
}
140+
141+
if (sxdp->sxdp_queue_id >= dev->num_rx_queues) {
142+
err = -EINVAL;
143+
goto out_unlock;
144+
}
145+
146+
if (sxdp->sxdp_flags & XDP_SHARED_UMEM) {
147+
struct xdp_sock *umem_xs;
148+
struct socket *sock;
149+
150+
if (xs->umem) {
151+
/* We have already our own. */
152+
err = -EINVAL;
153+
goto out_unlock;
154+
}
155+
156+
sock = xsk_lookup_xsk_from_fd(sxdp->sxdp_shared_umem_fd);
157+
if (IS_ERR(sock)) {
158+
err = PTR_ERR(sock);
159+
goto out_unlock;
160+
}
161+
162+
umem_xs = xdp_sk(sock->sk);
163+
if (!umem_xs->umem) {
164+
/* No umem to inherit. */
165+
err = -EBADF;
166+
sockfd_put(sock);
167+
goto out_unlock;
168+
} else if (umem_xs->dev != dev ||
169+
umem_xs->queue_id != sxdp->sxdp_queue_id) {
170+
err = -EINVAL;
171+
sockfd_put(sock);
172+
goto out_unlock;
173+
}
174+
175+
xdp_get_umem(umem_xs->umem);
176+
old_umem = xs->umem;
177+
xs->umem = umem_xs->umem;
178+
sockfd_put(sock);
179+
} else if (!xs->umem || !xdp_umem_validate_queues(xs->umem)) {
180+
err = -EINVAL;
181+
goto out_unlock;
182+
}
183+
184+
/* Rebind? */
185+
if (dev_curr && (dev_curr != dev ||
186+
xs->queue_id != sxdp->sxdp_queue_id)) {
187+
__xsk_release(xs);
188+
if (old_umem)
189+
xdp_put_umem(old_umem);
190+
}
191+
192+
xs->dev = dev;
193+
xs->queue_id = sxdp->sxdp_queue_id;
194+
195+
xskq_set_umem(xs->rx, &xs->umem->props);
196+
197+
out_unlock:
198+
if (err)
199+
dev_put(dev);
200+
out_release:
201+
mutex_unlock(&xs->mutex);
202+
return err;
203+
}
204+
83205
static int xsk_setsockopt(struct socket *sock, int level, int optname,
84206
char __user *optval, unsigned int optlen)
85207
{
@@ -203,7 +325,7 @@ static const struct proto_ops xsk_proto_ops = {
203325
.family = PF_XDP,
204326
.owner = THIS_MODULE,
205327
.release = xsk_release,
206-
.bind = sock_no_bind,
328+
.bind = xsk_bind,
207329
.connect = sock_no_connect,
208330
.socketpair = sock_no_socketpair,
209331
.accept = sock_no_accept,

net/xdp/xsk_queue.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616

1717
#include "xsk_queue.h"
1818

19+
void xskq_set_umem(struct xsk_queue *q, struct xdp_umem_props *umem_props)
20+
{
21+
if (!q)
22+
return;
23+
24+
q->umem_props = *umem_props;
25+
}
26+
1927
static u32 xskq_umem_get_ring_size(struct xsk_queue *q)
2028
{
2129
return sizeof(struct xdp_umem_ring) + q->nentries * sizeof(u32);

net/xdp/xsk_queue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct xsk_queue {
3232
u64 invalid_descs;
3333
};
3434

35+
void xskq_set_umem(struct xsk_queue *q, struct xdp_umem_props *umem_props);
3536
struct xsk_queue *xskq_create(u32 nentries, bool umem_queue);
3637
void xskq_destroy(struct xsk_queue *q);
3738

0 commit comments

Comments
 (0)