1package netlink 2 3import ( 4 "fmt" 5 "time" 6 7 "github.com/vishvananda/netlink/nl" 8 "github.com/vishvananda/netns" 9 "golang.org/x/sys/unix" 10) 11 12// Empty handle used by the netlink package methods 13var pkgHandle = &Handle{} 14 15// Handle is an handle for the netlink requests on a 16// specific network namespace. All the requests on the 17// same netlink family share the same netlink socket, 18// which gets released when the handle is deleted. 19type Handle struct { 20 sockets map[int]*nl.SocketHandle 21 lookupByDump bool 22} 23 24// SupportsNetlinkFamily reports whether the passed netlink family is supported by this Handle 25func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool { 26 _, ok := h.sockets[nlFamily] 27 return ok 28} 29 30// NewHandle returns a netlink handle on the current network namespace. 31// Caller may specify the netlink families the handle should support. 32// If no families are specified, all the families the netlink package 33// supports will be automatically added. 34func NewHandle(nlFamilies ...int) (*Handle, error) { 35 return newHandle(netns.None(), netns.None(), nlFamilies...) 36} 37 38// SetSocketTimeout sets the send and receive timeout for each socket in the 39// netlink handle. Although the socket timeout has granularity of one 40// microsecond, the effective granularity is floored by the kernel timer tick, 41// which default value is four milliseconds. 42func (h *Handle) SetSocketTimeout(to time.Duration) error { 43 if to < time.Microsecond { 44 return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond) 45 } 46 tv := unix.NsecToTimeval(to.Nanoseconds()) 47 for _, sh := range h.sockets { 48 if err := sh.Socket.SetSendTimeout(&tv); err != nil { 49 return err 50 } 51 if err := sh.Socket.SetReceiveTimeout(&tv); err != nil { 52 return err 53 } 54 } 55 return nil 56} 57 58// SetSocketReceiveBufferSize sets the receive buffer size for each 59// socket in the netlink handle. The maximum value is capped by 60// /proc/sys/net/core/rmem_max. 61func (h *Handle) SetSocketReceiveBufferSize(size int, force bool) error { 62 opt := unix.SO_RCVBUF 63 if force { 64 opt = unix.SO_RCVBUFFORCE 65 } 66 for _, sh := range h.sockets { 67 fd := sh.Socket.GetFd() 68 err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, opt, size) 69 if err != nil { 70 return err 71 } 72 } 73 return nil 74} 75 76// GetSocketReceiveBufferSize gets the receiver buffer size for each 77// socket in the netlink handle. The retrieved value should be the 78// double to the one set for SetSocketReceiveBufferSize. 79func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) { 80 results := make([]int, len(h.sockets)) 81 i := 0 82 for _, sh := range h.sockets { 83 fd := sh.Socket.GetFd() 84 size, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_RCVBUF) 85 if err != nil { 86 return nil, err 87 } 88 results[i] = size 89 i++ 90 } 91 return results, nil 92} 93 94// NewHandleAt returns a netlink handle on the network namespace 95// specified by ns. If ns=netns.None(), current network namespace 96// will be assumed 97func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error) { 98 return newHandle(ns, netns.None(), nlFamilies...) 99} 100 101// NewHandleAtFrom works as NewHandle but allows client to specify the 102// new and the origin netns Handle. 103func NewHandleAtFrom(newNs, curNs netns.NsHandle) (*Handle, error) { 104 return newHandle(newNs, curNs) 105} 106 107func newHandle(newNs, curNs netns.NsHandle, nlFamilies ...int) (*Handle, error) { 108 h := &Handle{sockets: map[int]*nl.SocketHandle{}} 109 fams := nl.SupportedNlFamilies 110 if len(nlFamilies) != 0 { 111 fams = nlFamilies 112 } 113 for _, f := range fams { 114 s, err := nl.GetNetlinkSocketAt(newNs, curNs, f) 115 if err != nil { 116 return nil, err 117 } 118 h.sockets[f] = &nl.SocketHandle{Socket: s} 119 } 120 return h, nil 121} 122 123// Delete releases the resources allocated to this handle 124func (h *Handle) Delete() { 125 for _, sh := range h.sockets { 126 sh.Close() 127 } 128 h.sockets = nil 129} 130 131func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest { 132 // Do this so that package API still use nl package variable nextSeqNr 133 if h.sockets == nil { 134 return nl.NewNetlinkRequest(proto, flags) 135 } 136 return &nl.NetlinkRequest{ 137 NlMsghdr: unix.NlMsghdr{ 138 Len: uint32(unix.SizeofNlMsghdr), 139 Type: uint16(proto), 140 Flags: unix.NLM_F_REQUEST | uint16(flags), 141 }, 142 Sockets: h.sockets, 143 } 144} 145