Multiple Linux sockets can bind the same local address when every participating socket enables SO_REUSEPORT before bind(). Incoming traffic is then assigned to a member of the resulting reuseport group rather than delivered to every socket. The shared address is therefore a kernel selection boundary, not a broadcast endpoint.
This behavior supports independent receive or accept loops without forcing all work through one listening descriptor. It also creates a distinct operational property: group membership and the selection policy determine which socket receives a packet or connection.
Group membership starts at the shared bind
For AF_INET and AF_INET6, SO_REUSEPORT permits multiple sockets to bind an identical address. Linux requires the option on each participating socket, including the first, before bind().
Linux also requires processes binding the same address this way to have the same effective UID. That restriction prevents an unrelated process from joining an existing reuseport endpoint merely by setting the option.
The option differs from SO_REUSEADDR. SO_REUSEPORT explicitly creates a set of sockets eligible for selection on the same local address; it is not only a rule for relaxing address reuse during bind processing.
TCP distributes connections across listeners
With TCP, separate listening sockets can occupy the same address and port. Each listener can belong to a different worker thread or process and run its own accept() loop.
The kernel selects a listener for an incoming connection. Once the connection has been assigned and accepted, the resulting connected socket follows ordinary TCP semantics. The reuseport group is relevant to listener selection; it does not turn established connections into shared objects across every listener.
This arrangement removes a single shared listening file descriptor from the application-level dispatch path. Scheduling effects still remain: uneven connection characteristics, worker load, CPU placement, and the kernel’s selection logic can all affect observed balance.
UDP selection is per datagram
For UDP, sockets in a reuseport group are candidates for incoming datagrams addressed to the shared local endpoint. A datagram is selected for one socket rather than copied to every group member.
That property makes reuseport different from application fan-out. If several consumers must all receive the same payload, a reuseport group does not provide that semantic. It provides distribution among eligible sockets.
Flow affinity can also make traffic distribution differ from simple packet-by-packet round robin. Applications should treat the kernel selection algorithm as a distribution mechanism, not as a contractual fairness schedule.
BPF can replace the default selector
Linux exposes SO_ATTACH_REUSEPORT_CBPF and SO_ATTACH_REUSEPORT_EBPF for reuseport groups. A classic BPF program can return an index from 0 through N-1, where N is the current group size, to select the receiving socket.
Extended BPF can use the socket-filter form with the same index model. A BPF_PROG_TYPE_SK_REUSEPORT program can instead use bpf_sk_select_reuseport() to select a socket from a reuseport socket array.
If an index-returning program produces an invalid index, Linux falls back to the ordinary SO_REUSEPORT selection mechanism. The attached program therefore controls selection only within the interface contract.
A newly added socket inherits the BPF program already associated with the group. Replacing the program through a socket in the group changes the selector used by the group rather than creating an isolated per-socket policy.
Numeric socket indexes are mutable membership positions
For the index-based BPF interface, sockets are numbered by the order in which they enter the group: bind() order for UDP and listen() order for TCP.
Those indexes are not durable socket identities. When a socket is removed, Linux moves the last socket in the group into the vacated position. A selector that stores external meaning against a numeric index must account for that compaction.
This detail separates stable application identity from reuseport membership position. A worker number, CPU number, or shard identifier is not automatically equivalent to the current reuseport index after membership changes.
Selection does not remove backpressure
Reuseport distributes arrivals, but each selected socket still has its own queues and application consumer. A slow worker can therefore accumulate pressure on traffic assigned to its socket even while another member has spare capacity.
A custom BPF selector can incorporate policy beyond the default mechanism, but the selection hook is not a general transaction across worker state. Any state used for steering needs its own consistency and lifecycle rules.
The central boundary remains narrow: SO_REUSEPORT makes multiple sockets eligible at one local address and moves initial receive selection into the kernel. It does not merge their queues, guarantee equal work, or make group indexes permanent.