Skip to content
Closed
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
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,21 @@ For documentation and more examples please take a look at [![PkgGoDev](https://p
## Requirements

* A version of Go that is [supported by upstream](https://golang.org/doc/devel/release.html#policy)

## Advanced Configuration

### Socket Buffer Size

For high-throughput scenarios, you may need to increase the socket receive buffer size:

```go
config := nflog.Config{
Group: 100,
Copymode: nflog.CopyPacket,
SockBufSize: 2097152, // 2MB socket buffer
}

nf, err := nflog.Open(&config)
```

Note: Setting a large socket buffer may require CAP_NET_ADMIN capability or increased system limits.
30 changes: 30 additions & 0 deletions nflog.go
Comment thread
DineshI-MS marked this conversation as resolved.
Copy link
Copy Markdown
Owner

@florianl florianl Sep 15, 2025

Choose a reason for hiding this comment

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

@DineshI-MS Looking more at this approach. It might be easier to just provide an API to set the receiver buffer:

// SetReadBuffer SetReadBuffer sets the size of the receive buffer associated with this socket.
func (nflog *Nflog) SetReadBuffer(bytes int) error {
	return nflog.Con.SetReadBuffer(bytes)
}

This would redude the complexity of configuration and would also users allow to change it any time. Would you be open to update your PR with such an approach?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for providing this suggestion. I was able to set the buffer size this way without making any additional changes. I wasn’t aware of the API functions that are already part of netlink.Conn

  nf, err := nflog.Open(&config)
   if err != nil {
       return fmt.Errorf("failed to open nflog: %w", err)
   }
   defer nf.Close()

   reqSocketBufferSize := (512 * 1024) // set default as 512 KB

   if err := nf.Con.SetReadBuffer(reqSocketBufferSize); err != nil {
       return fmt.Errorf("failed to set read buffer: %w", err)
   }

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@DineshI-MS Would you be open to update your PR with this new approach?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

As Nflog already exposes *netlink.Conn, it might be best to just improve documentation. I might open a new PR in a few days improving documentation, if this PR becomes stale.

Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,36 @@
}
nflog.Con = con

// Set socket receive buffer size if specified
if config.SockBufSize > 0 {
// Linux doubles the buffer size, so request half of what user wants
requestSize := config.SockBufSize / 2

// Get the underlying file descriptor
rawConn, err := con.SyscallConn()
if err != nil {
con.Close()
return nil, fmt.Errorf("failed to get raw connection: %w", err)
}

var sockErr error
err = rawConn.Control(func(fd uintptr) {
// Try SO_RCVBUFFORCE first (bypasses limits with CAP_NET_ADMIN)
sockErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, int(requestSize))

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.23.x, macos-latest)

undefined: unix.SO_RCVBUFFORCE

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.23.x, macos-latest)

undefined: unix.SOL_SOCKET

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.23.x, macos-latest)

undefined: unix.SetsockoptInt

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.13.x, ubuntu-latest)

undefined: "github.com/florianl/go-nflog/v2/internal/unix".SO_RCVBUFFORCE

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.13.x, ubuntu-latest)

undefined: "github.com/florianl/go-nflog/v2/internal/unix".SOL_SOCKET

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.13.x, ubuntu-latest)

undefined: "github.com/florianl/go-nflog/v2/internal/unix".SetsockoptInt

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, ubuntu-latest)

undefined: unix.SO_RCVBUFFORCE

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, ubuntu-latest)

undefined: unix.SOL_SOCKET

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, ubuntu-latest)

undefined: unix.SetsockoptInt

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, macos-latest)

undefined: unix.SO_RCVBUFFORCE

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, macos-latest)

undefined: unix.SOL_SOCKET

Check failure on line 96 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, macos-latest)

undefined: unix.SetsockoptInt
if sockErr != nil {
// Fall back to SO_RCVBUF
sockErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, int(requestSize))

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.23.x, macos-latest)

undefined: unix.SO_RCVBUF

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.23.x, macos-latest)

undefined: unix.SOL_SOCKET

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.23.x, macos-latest)

undefined: unix.SetsockoptInt

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.13.x, ubuntu-latest)

undefined: "github.com/florianl/go-nflog/v2/internal/unix".SO_RCVBUF

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.13.x, ubuntu-latest)

undefined: "github.com/florianl/go-nflog/v2/internal/unix".SOL_SOCKET

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.13.x, ubuntu-latest)

undefined: "github.com/florianl/go-nflog/v2/internal/unix".SetsockoptInt

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, ubuntu-latest)

undefined: unix.SO_RCVBUF

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, ubuntu-latest)

undefined: unix.SOL_SOCKET

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, ubuntu-latest)

undefined: unix.SetsockoptInt

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, macos-latest)

undefined: unix.SO_RCVBUF

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, macos-latest)

undefined: unix.SOL_SOCKET

Check failure on line 99 in nflog.go

View workflow job for this annotation

GitHub Actions / test (1.24.x, macos-latest)

undefined: unix.SetsockoptInt
if sockErr != nil && config.Logger != nil {
config.Logger.Errorf("Failed to set socket buffer size to %d: %v", requestSize, sockErr)
}
}
})
if err != nil {
con.Close()
return nil, fmt.Errorf("failed to control socket: %w", err)
}
}

if config.Logger == nil {
nflog.logger = new(devNull)
} else {
Expand Down
60 changes: 60 additions & 0 deletions nflog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
package nflog

import (
"os"
"testing"

"golang.org/x/sys/unix"
)

func TestOpen(t *testing.T) {
Expand Down Expand Up @@ -33,3 +36,60 @@ func TestOpen(t *testing.T) {
})
}
}

func TestSockBufSize(t *testing.T) {
// Skip if not root
if os.Getuid() != 0 {
t.Skip("Test requires root privileges")
}

config := &Config{
Group: 1,
Copymode: CopyPacket,
SockBufSize: 2097152, // 2MB
}

nf, err := Open(config)
if err != nil {
t.Fatalf("failed to open nflog: %v", err)
}
defer nf.Close()

// Verify buffer size was applied
rawConn, err := nf.Con.SyscallConn()
if err != nil {
t.Fatalf("failed to get raw connection: %v", err)
}

var bufsize int
var sockErr error
err = rawConn.Control(func(fd uintptr) {
bufsize, sockErr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF)
})
if err != nil {
t.Fatalf("failed to control socket: %v", err)
}
if sockErr != nil {
t.Fatalf("failed to get socket buffer size: %v", sockErr)
}

// Linux doubles the value internally, so we check if it's at least our requested size
if bufsize < int(config.SockBufSize) {
t.Errorf("socket buffer size not applied correctly: got %d, want at least %d",
bufsize, config.SockBufSize)
}
}

func TestSockBufSizeDefault(t *testing.T) {
config := &Config{
Group: 1,
Copymode: CopyPacket,
SockBufSize: 0,
}

nf, err := Open(config)
if err != nil {
t.Fatalf("failed to open nflog with default socket buffer: %v", err)
}
defer nf.Close()
}
4 changes: 4 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ type Config struct {
// that will be copied to userspace.
Bufsize uint32

// Size of the socket receive buffer (in bytes)
// If set to 0, the system default will be used
SockBufSize uint32

// Optional settings to enable/disable features
Settings uint16

Expand Down
Loading