diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-03-25 17:55:35 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-03-25 17:55:35 +0900 |
| commit | 372d509e5c72775bcd44d40e31a31bbdfd6a3f00 (patch) | |
| tree | 60fd7430c0ea08e5fa0282d6b95446279276e6ee /internal/netlink/netlink.go | |
| parent | d62516ed1ee148c58eed60c4fa38c5dc2c3b9622 (diff) | |
internal/netlink: expose multicast groups
This also gets rid of the cached pid value for port since that prevents multiple sockets from being open at once.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/netlink/netlink.go')
| -rw-r--r-- | internal/netlink/netlink.go | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/internal/netlink/netlink.go b/internal/netlink/netlink.go index 89f692a5..857259f1 100644 --- a/internal/netlink/netlink.go +++ b/internal/netlink/netlink.go @@ -5,33 +5,29 @@ import ( "context" "fmt" "os" - "sync" "syscall" "time" "unsafe" ) -// AF_NETLINK socket is never shared -var ( - nlPid uint32 - nlPidOnce sync.Once -) - -// getpid returns a cached pid value. -func getpid() uint32 { - nlPidOnce.Do(func() { nlPid = uint32(os.Getpid()) }) - return nlPid -} - // net/netlink/af_netlink.c const maxRecvmsgLen = 32768 +const ( + // stateOpen denotes an open conn. + stateOpen uint32 = 1 << iota +) + // A conn represents resources associated to a netlink socket. type conn struct { // AF_NETLINK socket. f *os.File // For using runtime polling via f. raw syscall.RawConn + // Port ID assigned by the kernel. + port uint32 + // Internal connection status. + state uint32 // Kernel module or netlink group to communicate with. family int // Message sequence number. @@ -49,7 +45,7 @@ type conn struct { } // dial returns the address of a newly connected conn of specified family. -func dial(family int) (*conn, error) { +func dial(family int, groups uint32) (*conn, error) { var c conn if fd, err := syscall.Socket( syscall.AF_NETLINK, @@ -59,17 +55,32 @@ func dial(family int) (*conn, error) { return nil, os.NewSyscallError("socket", err) } else if err = syscall.Bind(fd, &syscall.SockaddrNetlink{ Family: syscall.AF_NETLINK, - Pid: getpid(), + Groups: groups, }); err != nil { _ = syscall.Close(fd) return nil, os.NewSyscallError("bind", err) } else { + var addr syscall.Sockaddr + if addr, err = syscall.Getsockname(fd); err != nil { + _ = syscall.Close(fd) + return nil, os.NewSyscallError("getsockname", err) + } + switch a := addr.(type) { + case *syscall.SockaddrNetlink: + c.port = a.Pid + + default: // unreachable + _ = syscall.Close(fd) + return nil, syscall.ENOTRECOVERABLE + } + c.family = family c.f = os.NewFile(uintptr(fd), "netlink") if c.raw, err = c.f.SyscallConn(); err != nil { _ = c.f.Close() return nil, err } + c.state |= stateOpen } c.pos = syscall.NLMSG_HDRLEN @@ -78,14 +89,14 @@ func dial(family int) (*conn, error) { } // ok returns whether conn is still open. -func (c *conn) ok() bool { return c.family >= 0 } +func (c *conn) ok() bool { return c.state&stateOpen != 0 } // Close closes the underlying socket. func (c *conn) Close() error { if !c.ok() { return syscall.EINVAL } - c.family = -1 + c.state &= ^stateOpen return c.f.Close() } @@ -231,7 +242,7 @@ func (c *conn) pending() []byte { Type: c.typ, Flags: c.flags, Seq: c.seq, - Pid: getpid(), + Pid: c.port, } return buf } @@ -266,8 +277,8 @@ func (c *conn) receive(ctx context.Context, f HandlerFunc, flags int) error { for i := range resp { header := &resp[i].Header - if header.Seq != c.seq || header.Pid != getpid() { - return &InconsistentError{*header, c.seq, getpid()} + if header.Seq != c.seq || header.Pid != c.port { + return &InconsistentError{*header, c.seq, c.port} } } if err = f(resp); err != nil { |
