https://github.com/msantos/reuseport
SO_REUSEPORT socket load distribution using LD_PRELOAD
https://github.com/msantos/reuseport
fd ldpreload reuseport socket
Last synced: about 1 year ago
JSON representation
SO_REUSEPORT socket load distribution using LD_PRELOAD
- Host: GitHub
- URL: https://github.com/msantos/reuseport
- Owner: msantos
- License: mit
- Created: 2018-11-17T17:04:12.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2025-03-12T11:26:37.000Z (over 1 year ago)
- Last Synced: 2025-03-30T11:41:41.108Z (about 1 year ago)
- Topics: fd, ldpreload, reuseport, socket
- Language: C
- Homepage:
- Size: 25.4 KB
- Stars: 18
- Watchers: 2
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# libreuseport
libreuseport is a small library for socket load distribution (aka port
sharding).
The library works by intercepting calls to `bind(2)` using
`LD_PRELOAD`. Before `bind(2)`ing, `setsockopt(2)` is called with the
`SO_REUSEPORT` option.
libreuseport requires the program to be dynamically linked. libreuseport
will not work with statically linked programs or programs that directly
make syscalls.
## Build
```
make
```
## Environment Variables
`LIBREUSEPORT_ADDR`
: Set socket option only if the socket matches the specified IPv4 or
IPv6 address (default: any address).
```
LIBREUSEPORT_ADDR="127.0.0.1"
```
`LIBREUSEPORT_PORT`
: Set socket option only if the socket matches the specified port
(default: any port).
```
LIBREUSEPORT_PORT="80"
```
`SO_REUSEPORT`
: Enable or disable `SO_REUSEPORT` socket option (default: 1)
```
0 : disable
1 : enable (default)
-1 : use system default
```
`SO_REUSEADDR`
: Enable or disable `SO_REUSEADDR` socket option (default: -1)
```
0 : disable
1 : enable
-1 : use system default (default)
```
`SO_BINDTODEVICE`
: On a system with multiple interfaces, bind the socket to a specific
interface (default: disabled)
```
SO_BINDTODEVICE="eth0"
```
`LIBREUSEPORT_DEBUG`
: Output errors to stderr
```
LIBREUSEPORT_DEBUG="1"
```
## Using
* python HTTP server
```
# run in a shell
$ LD_PRELOAD=./libreuseport.so python3 -m http.server 8000
# in another shell
$ LD_PRELOAD=./libreuseport.so python3 -m http.server 8000
# yet another shell
while :; do curl http://0.0.0.0:8000; sleep 1; done
```
* erlang
```erlang
$ LD_PRELOAD=./libreuseport.so erl
1> {ok, L1} = gen_tcp:listen(5678, [binary, {packet,0}, {active,true}]).
{ok,#Port<0.6>}
2> {ok, L2} = gen_tcp:listen(5678, [binary, {packet,0}, {active,true}]).
{ok,#Port<0.7>}
3> Accept = fun Loop(L) -> {ok, S} = gen_tcp:accept(L), io:format("~p->~p~n", [{listen, L}, {socket, S}]), gen_tcp:close(S), Loop(L) end.
#Fun
4> spawn(fun() -> Accept(L1) end).
<0.86.0>
5> spawn(fun() -> Accept(L2) end).
<0.88.0>
% run: nc -z 127.0.0.1 5678
{listen,#Port<0.6>}->{socket,#Port<0.8>}
{listen,#Port<0.6>}->{socket,#Port<0.9>}
{listen,#Port<0.6>}->{socket,#Port<0.10>}
{listen,#Port<0.7>}->{socket,#Port<0.11>}
{listen,#Port<0.6>}->{socket,#Port<0.12>}
{listen,#Port<0.7>}->{socket,#Port<0.13>}
{listen,#Port<0.6>}->{socket,#Port<0.14>}
{listen,#Port<0.6>}->{socket,#Port<0.15>}
{listen,#Port<0.6>}->{socket,#Port<0.16>}
{listen,#Port<0.6>}->{socket,#Port<0.17>}
{listen,#Port<0.7>}->{socket,#Port<0.18>}
{listen,#Port<0.6>}->{socket,#Port<0.19>}
{listen,#Port<0.7>}->{socket,#Port<0.20>}
{listen,#Port<0.7>}->{socket,#Port<0.21>}
{listen,#Port<0.7>}->{socket,#Port<0.22>}
```
## See Also
* Using `LD_PRELOAD` to bind an application to an interface:
https://gist.github.com/markusfisch/51b1ce6c3ca9ce67e081
* Linux port sharding demo
https://github.com/joewalnes/port-sharding