From: Jiayuan Chen jiayuan.chen@linux.dev Date: Thu, 1 May 2025 11:51:08 +0800
For some services we are using "established-over-unconnected" model.
''' // create unconnected socket and 'listen()' srv_fd = socket(AF_INET, SOCK_DGRAM) setsockopt(srv_fd, SO_REUSEPORT) bind(srv_fd, SERVER_ADDR, SERVER_PORT)
// 'accept()' data, client_addr = recvmsg(srv_fd)
// create a connected socket for this request cli_fd = socket(AF_INET, SOCK_DGRAM) setsockopt(cli_fd, SO_REUSEPORT) bind(cli_fd, SERVER_ADDR, SERVER_PORT) connect(cli, client_addr) ... // do handshake with cli_fd '''
This programming pattern simulates accept() using UDP, creating a new socket for each client request. The server can then use separate sockets to handle client requests, avoiding the need to use a single UDP socket for I/O transmission.
But there is a race condition between the bind() and connect() of the connected socket: We might receive unexpected packets belonging to the unconnected socket before connect() is executed, which is not what we need. (Of course, before connect(), the unconnected socket will also receive packets from the connected socket, which is easily resolved because upper-layer protocols typically require explicit boundaries, and we receive a complete packet before creating a connected socket.)
Before this patch, the connected socket had to filter requests at recvmsg time, acting as a dispatcher to some extent. With this patch, we can consider the bind and connect operations to be atomic.
SO_ATTACH_REUSEPORT_EBPF is what you want.
The socket won't receive any packets until the socket is added to the BPF map.
No need to reinvent a subset of BPF functionalities.