Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for SO_REUSEPORT #89

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"

reuse "github.com/libp2p/go-reuseport"
)

var (
Expand All @@ -19,8 +21,7 @@ var (
Port: 5353,
}
mdnsWildcardAddrIPv6 = &net.UDPAddr{
IP: net.ParseIP("ff02::"),
// IP: net.ParseIP("fd00::12d3:26e7:48db:e7d"),
IP: net.ParseIP("ff02::"),
Port: 5353,
}

Expand All @@ -36,7 +37,7 @@ var (
)

func joinUdp6Multicast(interfaces []net.Interface) (*ipv6.PacketConn, error) {
udpConn, err := net.ListenUDP("udp6", mdnsWildcardAddrIPv6)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need SO_REUSEPORT? For multicast address, SO_REUSEPORT is the same as SO_REUSEADDR which was already set by default when you call net.ListenUDP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Debian Linux system I am running this on, I have a few other mdns services. When starting a service using this library net.ListenUDP would fail due to the port already being in use.

After switching it to use SO_REUSEPORT to be inline with all the other mDNS services I was able to successfully run it with the other services at the same time without issue. [1,2]

It is my understanding that SO_REUSEPORT is not needed if all the services are part of the same program (PID), but if they are not; SO_REUSEPORT is required to tell the kernel it is ok for different processes to share the same address/port. Which is required for mDNS.

[1] https://github.com/udp-redux/udp-broadcast-relay-redux/blob/master/main.c#L382
[2] https://github.com/lathiat/avahi/blob/d1e71b320d96d0f213ecb0885c8313039a09f693/avahi-core/socket.c#L178

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @lanrat for the details. After some digging and exercises, I agree that set both SO_REUSEADDR and SO_REUSEPORT is better than just setting SO_REUSEADDR.
I think the reason net.LIstenUDP failed in your env is some other mdns services running only enabled SO_REUSEPORT.

"It is my understanding that SO_REUSEPORT is not needed if all the services are part of the same program (PID), but if they are not; SO_REUSEPORT is required to tell the kernel it is ok for different processes to share the same address/port. Which is required for mDNS."
-> I don't agree with above comments. Based on my test, SO_REUSEADDR works quite well for multiple processes for mDNS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"It is my understanding that SO_REUSEPORT is not needed if all the services are part of the same program (PID), but if they are not; SO_REUSEPORT is required to tell the kernel it is ok for different processes to share the same address/port. Which is required for mDNS."
-> I don't agree with above comments. Based on my test, SO_REUSEADDR works quite well for multiple processes for mDNS.

This comment was based on the results of the limited testing I did, so I could very well be wrong here. I'll research this a bit more to fully understand what's going on.

Either way, adding SO_REUSEPORT does appear to fix the problem as I'm running 5+ mdns services on the same host.

udpConn, err := reuse.ListenPacket("udp6", mdnsWildcardAddrIPv6.String())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -66,7 +67,7 @@ func joinUdp6Multicast(interfaces []net.Interface) (*ipv6.PacketConn, error) {
}

func joinUdp4Multicast(interfaces []net.Interface) (*ipv4.PacketConn, error) {
udpConn, err := net.ListenUDP("udp4", mdnsWildcardAddrIPv4)
udpConn, err := reuse.ListenPacket("udp4", mdnsWildcardAddrIPv4.String())
if err != nil {
// log.Printf("[ERR] bonjour: Failed to bind to udp4 mutlicast: %v", err)
return nil, err
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.13

require (
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/libp2p/go-reuseport v0.0.2
github.com/miekg/dns v1.1.41
github.com/pkg/errors v0.9.1
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6
Expand Down
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU=
github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk=
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -18,3 +28,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=