mirror of https://github.com/vishvananda/netlink
Add ReceiveBufferSize and force option to *Subscribe
When there are a large number of existing results for the link, neighbor, and address subscribe functions with ListExisting are likely to fail with ENOBUFS. This takes the AddrSubscribeOptions ReceiveBufferSize, already applied to LinkSubscribeOptions, and applies it to NeighSubscribeOptions and RouteSubscribeOptions. The ReceiveTimeout option was also added to each. Added a SetReceiveBufferSize to the nl_linux socket API. The existing addr_linux subscribe function was modified so instead of setting the ReceiveBufferSize on the netlink pkghandle, it is set on the socket associated with the subscription. The new implementations also only change the receive buffer size on the socket. Lastly, a new ReceiveBufferForceSize option was applied to all four of the modified Subscribe functions.
This commit is contained in:
parent
3cc961ec4d
commit
229a10237c
|
@ -296,13 +296,13 @@ type AddrUpdate struct {
|
|||
// AddrSubscribe takes a chan down which notifications will be sent
|
||||
// when addresses change. Close the 'done' chan to stop subscription.
|
||||
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
|
||||
return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil)
|
||||
return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil, false)
|
||||
}
|
||||
|
||||
// AddrSubscribeAt works like AddrSubscribe plus it allows the caller
|
||||
// to choose the network namespace in which to subscribe (ns).
|
||||
func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
|
||||
return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil)
|
||||
return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil, false)
|
||||
}
|
||||
|
||||
// AddrSubscribeOptions contains a set of options to use with
|
||||
|
@ -312,6 +312,7 @@ type AddrSubscribeOptions struct {
|
|||
ErrorCallback func(error)
|
||||
ListExisting bool
|
||||
ReceiveBufferSize int
|
||||
ReceiveBufferForceSize bool
|
||||
ReceiveTimeout *unix.Timeval
|
||||
}
|
||||
|
||||
|
@ -323,10 +324,12 @@ func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, option
|
|||
none := netns.None()
|
||||
options.Namespace = &none
|
||||
}
|
||||
return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize, options.ReceiveTimeout)
|
||||
return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting,
|
||||
options.ReceiveBufferSize, options.ReceiveTimeout, options.ReceiveBufferForceSize)
|
||||
}
|
||||
|
||||
func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int, rcvTimeout *unix.Timeval) error {
|
||||
func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool,
|
||||
rcvbuf int, rcvTimeout *unix.Timeval, rcvBufForce bool) error {
|
||||
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -336,19 +339,18 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if rcvbuf != 0 {
|
||||
err = s.SetReceiveBufferSize(rcvbuf, rcvBufForce)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if done != nil {
|
||||
go func() {
|
||||
<-done
|
||||
s.Close()
|
||||
}()
|
||||
}
|
||||
if rcvbuf != 0 {
|
||||
err = pkgHandle.SetSocketReceiveBufferSize(rcvbuf, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if listExisting {
|
||||
req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
|
||||
unix.NLM_F_DUMP)
|
||||
|
|
|
@ -2276,13 +2276,13 @@ type LinkUpdate struct {
|
|||
// LinkSubscribe takes a chan down which notifications will be sent
|
||||
// when links change. Close the 'done' chan to stop subscription.
|
||||
func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
|
||||
return linkSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0)
|
||||
return linkSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil, false)
|
||||
}
|
||||
|
||||
// LinkSubscribeAt works like LinkSubscribe plus it allows the caller
|
||||
// to choose the network namespace in which to subscribe (ns).
|
||||
func LinkSubscribeAt(ns netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}) error {
|
||||
return linkSubscribeAt(ns, netns.None(), ch, done, nil, false, 0)
|
||||
return linkSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil, false)
|
||||
}
|
||||
|
||||
// LinkSubscribeOptions contains a set of options to use with
|
||||
|
@ -2292,6 +2292,8 @@ type LinkSubscribeOptions struct {
|
|||
ErrorCallback func(error)
|
||||
ListExisting bool
|
||||
ReceiveBufferSize int
|
||||
ReceiveBufferForceSize bool
|
||||
ReceiveTimeout *unix.Timeval
|
||||
}
|
||||
|
||||
// LinkSubscribeWithOptions work like LinkSubscribe but enable to
|
||||
|
@ -2302,14 +2304,27 @@ func LinkSubscribeWithOptions(ch chan<- LinkUpdate, done <-chan struct{}, option
|
|||
none := netns.None()
|
||||
options.Namespace = &none
|
||||
}
|
||||
return linkSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize)
|
||||
return linkSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting,
|
||||
options.ReceiveBufferSize, options.ReceiveTimeout, options.ReceiveBufferForceSize)
|
||||
}
|
||||
|
||||
func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int) error {
|
||||
func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}, cberr func(error), listExisting bool,
|
||||
rcvbuf int, rcvTimeout *unix.Timeval, rcvbufForce bool) error {
|
||||
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_LINK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rcvTimeout != nil {
|
||||
if err := s.SetReceiveTimeout(rcvTimeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if rcvbuf != 0 {
|
||||
err = s.SetReceiveBufferSize(rcvbuf, rcvbufForce)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if done != nil {
|
||||
go func() {
|
||||
<-done
|
||||
|
@ -2325,12 +2340,6 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
|
|||
return err
|
||||
}
|
||||
}
|
||||
if rcvbuf != 0 {
|
||||
err = pkgHandle.SetSocketReceiveBufferSize(rcvbuf, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
defer close(ch)
|
||||
for {
|
||||
|
|
|
@ -339,13 +339,13 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
|
|||
// NeighSubscribe takes a chan down which notifications will be sent
|
||||
// when neighbors are added or deleted. Close the 'done' chan to stop subscription.
|
||||
func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error {
|
||||
return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
|
||||
return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil, false)
|
||||
}
|
||||
|
||||
// NeighSubscribeAt works like NeighSubscribe plus it allows the caller
|
||||
// to choose the network namespace in which to subscribe (ns).
|
||||
func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error {
|
||||
return neighSubscribeAt(ns, netns.None(), ch, done, nil, false)
|
||||
return neighSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil, false)
|
||||
}
|
||||
|
||||
// NeighSubscribeOptions contains a set of options to use with
|
||||
|
@ -354,6 +354,11 @@ type NeighSubscribeOptions struct {
|
|||
Namespace *netns.NsHandle
|
||||
ErrorCallback func(error)
|
||||
ListExisting bool
|
||||
|
||||
// max size is based on value of /proc/sys/net/core/rmem_max
|
||||
ReceiveBufferSize int
|
||||
ReceiveBufferForceSize bool
|
||||
ReceiveTimeout *unix.Timeval
|
||||
}
|
||||
|
||||
// NeighSubscribeWithOptions work like NeighSubscribe but enable to
|
||||
|
@ -364,10 +369,12 @@ func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, opti
|
|||
none := netns.None()
|
||||
options.Namespace = &none
|
||||
}
|
||||
return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
|
||||
return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting,
|
||||
options.ReceiveBufferSize, options.ReceiveTimeout, options.ReceiveBufferForceSize)
|
||||
}
|
||||
|
||||
func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
|
||||
func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool,
|
||||
rcvbuf int, rcvTimeout *unix.Timeval, rcvbufForce bool) error {
|
||||
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
|
||||
makeRequest := func(family int) error {
|
||||
req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
|
||||
|
@ -381,6 +388,17 @@ func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rcvTimeout != nil {
|
||||
if err := s.SetReceiveTimeout(rcvTimeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if rcvbuf != 0 {
|
||||
err = s.SetReceiveBufferSize(rcvbuf, rcvbufForce)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if done != nil {
|
||||
go func() {
|
||||
<-done
|
||||
|
|
|
@ -806,6 +806,15 @@ func (s *NetlinkSocket) SetReceiveTimeout(timeout *unix.Timeval) error {
|
|||
return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, timeout)
|
||||
}
|
||||
|
||||
// SetReceiveBufferSize allows to set a receive buffer size on the socket
|
||||
func (s *NetlinkSocket) SetReceiveBufferSize(size int, force bool) error {
|
||||
opt := unix.SO_RCVBUF
|
||||
if force {
|
||||
opt = unix.SO_RCVBUFFORCE
|
||||
}
|
||||
return unix.SetsockoptInt(int(s.fd), unix.SOL_SOCKET, opt, size)
|
||||
}
|
||||
|
||||
// SetExtAck requests error messages to be reported on the socket
|
||||
func (s *NetlinkSocket) SetExtAck(enable bool) error {
|
||||
var enableN int
|
||||
|
|
|
@ -1458,13 +1458,13 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
|
|||
// RouteSubscribe takes a chan down which notifications will be sent
|
||||
// when routes are added or deleted. Close the 'done' chan to stop subscription.
|
||||
func RouteSubscribe(ch chan<- RouteUpdate, done <-chan struct{}) error {
|
||||
return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
|
||||
return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil, false)
|
||||
}
|
||||
|
||||
// RouteSubscribeAt works like RouteSubscribe plus it allows the caller
|
||||
// to choose the network namespace in which to subscribe (ns).
|
||||
func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error {
|
||||
return routeSubscribeAt(ns, netns.None(), ch, done, nil, false)
|
||||
return routeSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil, false)
|
||||
}
|
||||
|
||||
// RouteSubscribeOptions contains a set of options to use with
|
||||
|
@ -1473,6 +1473,9 @@ type RouteSubscribeOptions struct {
|
|||
Namespace *netns.NsHandle
|
||||
ErrorCallback func(error)
|
||||
ListExisting bool
|
||||
ReceiveBufferSize int
|
||||
ReceiveBufferForceSize bool
|
||||
ReceiveTimeout *unix.Timeval
|
||||
}
|
||||
|
||||
// RouteSubscribeWithOptions work like RouteSubscribe but enable to
|
||||
|
@ -1483,14 +1486,27 @@ func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, opti
|
|||
none := netns.None()
|
||||
options.Namespace = &none
|
||||
}
|
||||
return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
|
||||
return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting,
|
||||
options.ReceiveBufferSize, options.ReceiveTimeout, options.ReceiveBufferForceSize)
|
||||
}
|
||||
|
||||
func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
|
||||
func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error), listExisting bool,
|
||||
rcvbuf int, rcvTimeout *unix.Timeval, rcvbufForce bool) error {
|
||||
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_ROUTE, unix.RTNLGRP_IPV6_ROUTE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rcvTimeout != nil {
|
||||
if err := s.SetReceiveTimeout(rcvTimeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if rcvbuf != 0 {
|
||||
err = s.SetReceiveBufferSize(rcvbuf, rcvbufForce)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if done != nil {
|
||||
go func() {
|
||||
<-done
|
||||
|
|
Loading…
Reference in New Issue