Skip to content
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ internal/integration/integration.test
netlink.test
netlink-fuzz.zip
testdata/
go.work
go.work.sum
8 changes: 8 additions & 0 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type Socket interface {
Close() error
Send(m Message) error
SendMessages(m []Message) error
SendMessagesScatter(m []Message) error
Receive() ([]Message, error)
}

Expand Down Expand Up @@ -176,6 +177,13 @@ func (c *Conn) SendMessages(msgs []Message) ([]Message, error) {
return msgs, nil
}

// SendMessagesScatter sends multiple Messages to netlink using scatter-gather I/O.
// Each message is marshaled to its own buffer, avoiding a single large
// contiguous allocation. All messages are sent as one datagram.
func (c *Conn) SendMessagesScatter(msgs []Message) ([]Message, error) {
return c.SendMessages(msgs)
}

// Send sends a single Message to netlink. In most cases, a Header's Length,
// Sequence, and PID fields should be set to 0, so they can be populated
// automatically before the Message is sent. On success, Send returns a copy
Expand Down
19 changes: 18 additions & 1 deletion conn_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,23 @@ func (c *conn) SendMessages(messages []Message) error {
return err
}

// SendMessagesScatter sends multiple messages using scatter-gather I/O.
// Each message is marshaled to its own buffer, avoiding a single large
// contiguous allocation. All messages are sent as one datagram.
func (c *conn) SendMessagesScatter(messages []Message) error {
buffers := make([][]byte, len(messages))
for i, m := range messages {
b, err := m.MarshalBinary()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I believe the issue discussed in google/nftables#350 now points to these buffers instead of the socket ones.

I think there is a limit on how many of these buffers you can use. Check getconf IOV_MAX

if err != nil {
return err
}
buffers[i] = b
}
sa := &unix.SockaddrNetlink{Family: unix.AF_NETLINK}
_, err := c.s.SendmsgBuffers(context.Background(), buffers, nil, sa, 0)
return err
}

// Send sends a single Message to netlink.
func (c *conn) Send(m Message) error {
b, err := m.MarshalBinary()
Expand Down Expand Up @@ -208,7 +225,7 @@ func (c *conn) SetWriteDeadline(t time.Time) error { return c.s.SetWriteDeadline
// associated with the Conn.
func (c *conn) SetReadBuffer(bytes int) error { return c.s.SetReadBuffer(bytes) }

// SetReadBuffer sets the size of the operating system's transmit buffer
// SetWriteBuffer sets the size of the operating system's transmit buffer
// associated with the Conn.
func (c *conn) SetWriteBuffer(bytes int) error { return c.s.SetWriteBuffer(bytes) }

Expand Down
9 changes: 5 additions & 4 deletions conn_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ type conn struct{}
func dial(_ int, _ *Config) (*conn, uint32, error) { return nil, 0, errUnimplemented }
func newError(_ int) error { return errUnimplemented }

func (c *conn) Send(_ Message) error { return errUnimplemented }
func (c *conn) SendMessages(_ []Message) error { return errUnimplemented }
func (c *conn) Receive() ([]Message, error) { return nil, errUnimplemented }
func (c *conn) Close() error { return errUnimplemented }
func (c *conn) Send(_ Message) error { return errUnimplemented }
func (c *conn) SendMessages(_ []Message) error { return errUnimplemented }
func (c *conn) SendMessagesScatter(_ []Message) error { return errUnimplemented }
func (c *conn) Receive() ([]Message, error) { return nil, errUnimplemented }
func (c *conn) Close() error { return errUnimplemented }
4 changes: 4 additions & 0 deletions conn_others_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ func TestOthersConnUnimplemented(t *testing.T) {
t.Fatalf("unexpected error during c.SendMessages:\n- want: %v\n- got: %v",
want, got)
}
if got := c.SendMessagesScatter(nil); want != got {
t.Fatalf("unexpected error during c.SendMessagesScatter:\n- want: %v\n- got: %v",
want, got)
}

if _, got := c.Receive(); want != got {
t.Fatalf("unexpected error during c.Receive:\n- want: %v\n- got: %v",
Expand Down