handle: get/set receive buffer size

When receiving a lot of route changes (10,000 routes are enough), the
default receive buffer size (value of
`/proc/sys/net/core/rmem_default`) is too small and we get a `ENOBUF`
error. A user may want to increase the buffer size up to the value of
`/proc/sys/net/core/rmem_max` (by default, this is the same value). A
`SetSocketReceiveBufferSize()` function is provided to this
destination.

Possible improvements:

 1. automatically increase receive buffer size in higher level
    functions until we hit a maximum (get an error and/or the current
    value is smaller than expected)

 2. accept a "force" argument to use `SO_RCVBUFFORCE` to increase the
    value over `rmem_max` value
This commit is contained in:
Vincent Bernat 2017-09-12 08:32:37 +02:00 committed by Vish (Ishaya) Abrams
parent ef2b2c42e6
commit ef84ebb87b
2 changed files with 57 additions and 0 deletions

View File

@ -55,6 +55,38 @@ func (h *Handle) SetSocketTimeout(to time.Duration) error {
return nil return nil
} }
// SetSocketReceiveBufferSize sets the receive buffer size for each
// socket in the netlink handle. The maximum value is capped by
// /proc/sys/net/core/rmem_max.
func (h *Handle) SetSocketReceiveBufferSize(size int) error {
for _, sh := range h.sockets {
fd := sh.Socket.GetFd()
err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, size)
if err != nil {
return err
}
}
return nil
}
// GetSocketReceiveBufferSize gets the receiver buffer size for each
// socket in the netlink handle. The retrieved value should be the
// double to the one set for SetSocketReceiveBufferSize.
func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) {
results := make([]int, len(h.sockets))
i := 0
for _, sh := range h.sockets {
fd := sh.Socket.GetFd()
size, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF)
if err != nil {
return nil, err
}
results[i] = size
i++
}
return results, nil
}
// NewHandle returns a netlink handle on the network namespace // NewHandle returns a netlink handle on the network namespace
// specified by ns. If ns=netns.None(), current network namespace // specified by ns. If ns=netns.None(), current network namespace
// will be assumed // will be assumed

View File

@ -132,6 +132,31 @@ func TestHandleTimeout(t *testing.T) {
} }
} }
func TestHandleReceiveBuffer(t *testing.T) {
h, err := NewHandle()
if err != nil {
t.Fatal(err)
}
defer h.Delete()
if err := h.SetSocketReceiveBufferSize(65536); err != nil {
t.Fatal(err)
}
sizes, err := h.GetSocketReceiveBufferSize()
if err != nil {
t.Fatal(err)
}
if len(sizes) != len(h.sockets) {
t.Fatalf("Unexpected number of socket buffer sizes: %d (expected %d)",
len(sizes), len(h.sockets))
}
for _, s := range sizes {
if s < 65536 || s > 2*65536 {
t.Fatalf("Unexpected socket receive buffer size: %d (expected around %d)",
s, 65536)
}
}
}
func verifySockTimeVal(t *testing.T, fd int, tv syscall.Timeval) { func verifySockTimeVal(t *testing.T, fd int, tv syscall.Timeval) {
var ( var (
tr syscall.Timeval tr syscall.Timeval