{"record":{"id":"007c19ef5932292d","repo":"slackhq/nebula","slug":"unable-to-set-so-reuseport-w","errorCode":null,"errorMessage":"unable to set SO_REUSEPORT: %w","messagePattern":"unable to set SO_REUSEPORT: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"udp/udp_linux.go","lineNumber":54,"sourceCode":"func NewListener(l *slog.Logger, s Settings) (Conn, error) {\n\taf := unix.AF_INET6\n\tif s.Listen.Addr().Is4() {\n\t\taf = unix.AF_INET\n\t}\n\tsyscall.ForkLock.RLock()\n\tfd, err := unix.Socket(af, unix.SOCK_DGRAM, unix.IPPROTO_UDP)\n\tif err == nil {\n\t\tunix.CloseOnExec(fd)\n\t}\n\tsyscall.ForkLock.RUnlock()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to open socket: %w\", err)\n\t}\n\n\tif s.Multi {\n\t\tif err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {\n\t\t\t_ = unix.Close(fd)\n\t\t\treturn nil, fmt.Errorf(\"unable to set SO_REUSEPORT: %w\", err)\n\t\t}\n\t}\n\n\tvar sa unix.Sockaddr\n\tport := int(s.Listen.Port())\n\tif s.Listen.Addr().Is4() {\n\t\tsa4 := &unix.SockaddrInet4{Port: port}\n\t\tsa4.Addr = s.Listen.Addr().As4()\n\t\tsa = sa4\n\t} else {\n\t\tsa6 := &unix.SockaddrInet6{Port: port}\n\t\tsa6.Addr = s.Listen.Addr().As16()\n\t\tsa = sa6\n\t}\n\tif err = unix.Bind(fd, sa); err != nil {\n\t\t_ = unix.Close(fd)\n\t\treturn nil, fmt.Errorf(\"unable to bind to socket: %w\", err)\n\t}","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/udp/udp_linux.go#L36-L72","documentation":"NewListener sets SO_REUSEPORT so multiple nebula processes/threads can bind the same UDP port, and wraps the setsockopt(2) errno if the kernel rejects it. The fd is closed and listener creation aborts. The wrapped value is the raw errno from unix.SetsockoptInt.","triggerScenarios":"Calling udp.NewListener with Multi=true (or config enabling multiple UDP listeners) when setsockopt(SO_REUSEPORT) fails on the fresh fd.","commonSituations":"Kernels or OS builds without SO_REUSEPORT support; seccomp filters blocking setsockopt; running under an OS emulation layer (e.g. old WSL1) that does not implement the option.","solutions":["Check the wrapped errno to identify the exact failure and confirm the kernel supports SO_REUSEPORT (Linux >= 3.9)","Disable the multi-listener option so Multi=false and SO_REUSEPORT is not requested","Update to a newer kernel or run on a platform with full setsockopt support","Audit seccomp/AppArmor profiles to allow setsockopt on SOL_SOCKET"],"exampleFix":"// before\nlisteners:\n  batch: 64\n  multi: true\n// after\nlisteners:\n  batch: 64\n  multi: false","handlingStrategy":"try-catch","validationCode":"// feature check before enabling multi\nif runtime.GOOS == \"linux\" {\n    var kv kernel.Version // from uname\n    if kv.LessThan(3, 9, 0) { disableMulti() }\n}","typeGuard":null,"tryCatchPattern":"l, err := udp.NewListener(...)\nif err != nil {\n    var soErr *fmt.Error // wrapped setsockopt errno\n    if strings.Contains(err.Error(), \"SO_REUSEPORT\") {\n        // fall back to single-listener config and retry\n    }\n    return err\n}","preventionTips":["Only enable multi when all target kernels support SO_REUSEPORT (Linux >= 3.9)","Keep seccomp profiles permissive for setsockopt on SOL_SOCKET","Test on the oldest supported kernel in your fleet","Prefer default (multi off) unless you need SO_REUSEPORT load spreading"],"tags":["udp","linux","so-reuseport","setsockopt"],"backgroundTag":"so-reuseport-failed","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}