diff --git a/net/tcp/listen.go b/net/tcp/listen.go index 45efc19c..45a217e3 100644 --- a/net/tcp/listen.go +++ b/net/tcp/listen.go @@ -9,7 +9,7 @@ import ( ) type ListenerFactoryI interface { - NewListener(v *vrf.VRF, laddr *net.TCPAddr, ttl uint8) (ListenerI, error) + NewListener(v *vrf.VRF, laddr *net.TCPAddr, ttl uint8, reuseport bool) (ListenerI, error) } type ListenerFactory struct{} @@ -30,7 +30,7 @@ type Listener struct { } // NewListener starts a TCPListener -func (lf *ListenerFactory) NewListener(v *vrf.VRF, laddr *net.TCPAddr, ttl uint8) (ListenerI, error) { +func (lf *ListenerFactory) NewListener(v *vrf.VRF, laddr *net.TCPAddr, ttl uint8, reuseport bool) (ListenerI, error) { l := &Listener{ laddr: laddr, } @@ -57,7 +57,14 @@ func (lf *ListenerFactory) NewListener(v *vrf.VRF, laddr *net.TCPAddr, ttl uint8 err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) if err != nil { unix.Close(fd) - return nil, fmt.Errorf("unable to get SO_REUSEADDR %w", err) + return nil, fmt.Errorf("unable to set SO_REUSEADDR %w", err) + } + + if reuseport { + if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil { + unix.Close(fd) + return nil, fmt.Errorf("unable to set SO_REUSEPORT %w", err) + } } if ttl != 0 { @@ -147,7 +154,7 @@ type MockListener struct { connCh chan *MockConn } -func (lf *MockListenerFactory) NewListener(v *vrf.VRF, laddr *net.TCPAddr, ttl uint8) (ListenerI, error) { +func (lf *MockListenerFactory) NewListener(v *vrf.VRF, laddr *net.TCPAddr, ttl uint8, reusePort bool) (ListenerI, error) { return &MockListener{ localAddr: laddr.IP, localPort: uint16(laddr.Port), diff --git a/net/tcp/listener_manager.go b/net/tcp/listener_manager.go index 102d0423..c5a05842 100644 --- a/net/tcp/listener_manager.go +++ b/net/tcp/listener_manager.go @@ -27,14 +27,16 @@ type ListenerManager struct { listenersByVRFmu sync.RWMutex acceptCh chan ConnWithVRF listenerFactory ListenerFactoryI + reusePort bool } -func NewListenerManager(listenAddrsByVRF map[string][]string) *ListenerManager { +func NewListenerManager(listenAddrsByVRF map[string][]string, reusePort bool) *ListenerManager { return &ListenerManager{ listenAddrsByVRF: listenAddrsByVRF, listenersByVRF: make(map[string][]ListenerI), listenerFactory: NewListenerFactory(), acceptCh: make(chan ConnWithVRF), + reusePort: reusePort, } } @@ -93,7 +95,7 @@ func (lm *ListenerManager) _addListener(vrf *vrf.VRF, addr string, ch chan ConnW } log.Infof("Listener manager: Starting TCP listener on %s in VRF %s", addr, vrf.Name()) - l, err := lm.listenerFactory.NewListener(vrf, tcpaddr, 255) + l, err := lm.listenerFactory.NewListener(vrf, tcpaddr, 255, lm.reusePort) if err != nil { return err } diff --git a/protocols/bgp/server/server.go b/protocols/bgp/server/server.go index 1bba09ff..fc065e7c 100644 --- a/protocols/bgp/server/server.go +++ b/protocols/bgp/server/server.go @@ -29,6 +29,7 @@ type BGPServerConfig struct { // Optional attributes DefaultLocalPreference *uint32 + ReusePort bool } type bgpServer struct { @@ -68,7 +69,7 @@ func newBGPServer(config BGPServerConfig) *bgpServer { server := &bgpServer{ config: config, peers: newPeerManager(), - listenerManager: tcp.NewListenerManager(config.ListenAddrsByVRF), + listenerManager: tcp.NewListenerManager(config.ListenAddrsByVRF, config.ReusePort), } server.metrics = &metricsService{server} diff --git a/tests/bgp_integration_test.go b/tests/bgp_integration_test.go index 6356ddcf..27e7a09d 100644 --- a/tests/bgp_integration_test.go +++ b/tests/bgp_integration_test.go @@ -28,7 +28,7 @@ func TestBGP(t *testing.T) { "main": { "0.0.0.0:179", }, - }) + }, false) lm.SetListenerFactory(tcp.NewMockListenerFactory()) b.SetListenerManager(lm)