Update vendoring (#1105)
* Update vendor github.com/sirupsen/logrus@v1.1.1 * Update vendor github.com/coreos/go-systemd/dbus@v17 * Update vendor github.com/golang/protobuf/proto@v1.2.0 * Update vendor github.com/konsorten/go-windows-terminal-sequences@v1.0.1 * Update vendor github.com/mdlayher/... * Update vendor github.com/prometheus/procfs/... * Update vendor golang.org/x/... Signed-off-by: Ben Kochie <superq@gmail.com>
This commit is contained in:
parent
f0d2a06b11
commit
9cf508e673
279 changed files with 54502 additions and 15108 deletions
182
vendor/github.com/mdlayher/netlink/attribute.go
generated
vendored
182
vendor/github.com/mdlayher/netlink/attribute.go
generated
vendored
|
|
@ -26,24 +26,22 @@ type Attribute struct {
|
|||
Data []byte
|
||||
}
|
||||
|
||||
// MarshalBinary marshals an Attribute into a byte slice.
|
||||
func (a Attribute) MarshalBinary() ([]byte, error) {
|
||||
// marshal marshals the contents of a into b and returns the number of bytes
|
||||
// written to b, including attribute alignment padding.
|
||||
func (a *Attribute) marshal(b []byte) (int, error) {
|
||||
if int(a.Length) < nlaHeaderLen {
|
||||
return nil, errInvalidAttribute
|
||||
return 0, errInvalidAttribute
|
||||
}
|
||||
|
||||
b := make([]byte, nlaAlign(int(a.Length)))
|
||||
|
||||
nlenc.PutUint16(b[0:2], a.Length)
|
||||
nlenc.PutUint16(b[2:4], a.Type)
|
||||
n := copy(b[nlaHeaderLen:], a.Data)
|
||||
|
||||
copy(b[nlaHeaderLen:], a.Data)
|
||||
|
||||
return b, nil
|
||||
return nlaHeaderLen + nlaAlign(n), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary unmarshals the contents of a byte slice into an Attribute.
|
||||
func (a *Attribute) UnmarshalBinary(b []byte) error {
|
||||
// unmarshal unmarshals the contents of a byte slice into an Attribute.
|
||||
func (a *Attribute) unmarshal(b []byte) error {
|
||||
if len(b) < nlaHeaderLen {
|
||||
return errInvalidAttribute
|
||||
}
|
||||
|
|
@ -75,23 +73,27 @@ func (a *Attribute) UnmarshalBinary(b []byte) error {
|
|||
// In most cases, the Length field of each Attribute should be set to 0, so it
|
||||
// can be calculated and populated automatically for each Attribute.
|
||||
func MarshalAttributes(attrs []Attribute) ([]byte, error) {
|
||||
// Count how many bytes we should allocate to store each attribute's contents.
|
||||
var c int
|
||||
for _, a := range attrs {
|
||||
c += nlaAlign(len(a.Data))
|
||||
c += nlaHeaderLen + nlaAlign(len(a.Data))
|
||||
}
|
||||
|
||||
b := make([]byte, 0, c)
|
||||
// Advance through b with idx to place attribute data at the correct offset.
|
||||
var idx int
|
||||
b := make([]byte, c)
|
||||
for _, a := range attrs {
|
||||
// Infer the length of attribute if zero.
|
||||
if a.Length == 0 {
|
||||
a.Length = uint16(nlaHeaderLen + len(a.Data))
|
||||
}
|
||||
|
||||
ab, err := a.MarshalBinary()
|
||||
// Marshal a into b and advance idx to show many bytes are occupied.
|
||||
n, err := a.marshal(b[idx:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = append(b, ab...)
|
||||
idx += n
|
||||
}
|
||||
|
||||
return b, nil
|
||||
|
|
@ -110,7 +112,7 @@ func UnmarshalAttributes(b []byte) ([]Attribute, error) {
|
|||
}
|
||||
|
||||
var a Attribute
|
||||
if err := (&a).UnmarshalBinary(b[i:]); err != nil {
|
||||
if err := (&a).unmarshal(b[i:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -207,6 +209,14 @@ func (ad *AttributeDecoder) Err() error {
|
|||
return ad.err
|
||||
}
|
||||
|
||||
// Bytes returns the raw bytes of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) Bytes() []byte {
|
||||
src := ad.data()
|
||||
dest := make([]byte, len(src))
|
||||
copy(dest, src)
|
||||
return dest
|
||||
}
|
||||
|
||||
// String returns the string representation of the current Attribute's data.
|
||||
func (ad *AttributeDecoder) String() string {
|
||||
if ad.err != nil {
|
||||
|
|
@ -296,3 +306,143 @@ func (ad *AttributeDecoder) Do(fn func(b []byte) error) {
|
|||
ad.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// An AttributeEncoder provides a safe way to encode attributes.
|
||||
//
|
||||
// It is recommended to use an AttributeEncoder where possible instead of
|
||||
// calling MarshalAttributes or using package nlenc directly.
|
||||
//
|
||||
// Errors from intermediate encoding steps are returned in the call to
|
||||
// Encode.
|
||||
type AttributeEncoder struct {
|
||||
// ByteOrder defines a specific byte order to use when processing integer
|
||||
// attributes. ByteOrder should be set immediately after creating the
|
||||
// AttributeEncoder: before any attributes are encoded.
|
||||
//
|
||||
// If not set, the native byte order will be used.
|
||||
ByteOrder binary.ByteOrder
|
||||
|
||||
attrs []Attribute
|
||||
err error
|
||||
}
|
||||
|
||||
// NewAttributeEncoder creates an AttributeEncoder that encodes Attributes.
|
||||
func NewAttributeEncoder() *AttributeEncoder {
|
||||
return &AttributeEncoder{
|
||||
ByteOrder: nlenc.NativeEndian(),
|
||||
}
|
||||
}
|
||||
|
||||
// Uint8 encodes uint8 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint8(typ uint16, v uint8) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: []byte{v},
|
||||
})
|
||||
}
|
||||
|
||||
// Uint16 encodes uint16 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint16(typ uint16, v uint16) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 2)
|
||||
ae.ByteOrder.PutUint16(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Uint32 encodes uint32 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint32(typ uint16, v uint32) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 4)
|
||||
ae.ByteOrder.PutUint32(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Uint64 encodes uint64 data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Uint64(typ uint16, v uint64) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 8)
|
||||
ae.ByteOrder.PutUint64(b, v)
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// String encodes string s as a null-terminated string into an Attribute
|
||||
// specified by typ.
|
||||
func (ae *AttributeEncoder) String(typ uint16, s string) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: nlenc.Bytes(s),
|
||||
})
|
||||
}
|
||||
|
||||
// Bytes embeds raw byte data into an Attribute specified by typ.
|
||||
func (ae *AttributeEncoder) Bytes(typ uint16, b []byte) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Do is a general purpose function to encode arbitrary data into an attribute
|
||||
// specified by typ.
|
||||
//
|
||||
// Do is especially helpful in encoding nested attributes, attribute arrays,
|
||||
// or encoding arbitrary types (such as C structures) which don't fit cleanly
|
||||
// into an unsigned integer value.
|
||||
func (ae *AttributeEncoder) Do(typ uint16, fn func() ([]byte, error)) {
|
||||
if ae.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b, err := fn()
|
||||
if err != nil {
|
||||
ae.err = err
|
||||
return
|
||||
}
|
||||
|
||||
ae.attrs = append(ae.attrs, Attribute{
|
||||
Type: typ,
|
||||
Data: b,
|
||||
})
|
||||
}
|
||||
|
||||
// Encode returns the encoded bytes representing the attributes.
|
||||
func (ae *AttributeEncoder) Encode() ([]byte, error) {
|
||||
if ae.err != nil {
|
||||
return nil, ae.err
|
||||
}
|
||||
|
||||
return MarshalAttributes(ae.attrs)
|
||||
}
|
||||
|
|
|
|||
120
vendor/github.com/mdlayher/netlink/conn.go
generated
vendored
120
vendor/github.com/mdlayher/netlink/conn.go
generated
vendored
|
|
@ -6,6 +6,7 @@ import (
|
|||
"math/rand"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
|
|
@ -25,6 +26,8 @@ var (
|
|||
errMulticastGroupsNotSupported = errors.New("multicast groups not supported")
|
||||
errBPFFiltersNotSupported = errors.New("BPF filters not supported")
|
||||
errOptionsNotSupported = errors.New("options not supported")
|
||||
errSetBufferNotSupported = errors.New("setting buffer sizes not supported")
|
||||
errSyscallConnNotSupported = errors.New("syscall.RawConn operation not supported")
|
||||
)
|
||||
|
||||
// A Conn is a connection to netlink. A Conn can be used to send and
|
||||
|
|
@ -76,7 +79,7 @@ func Dial(family int, config *Config) (*Conn, error) {
|
|||
//
|
||||
// NewConn is primarily useful for tests. Most applications should use
|
||||
// Dial instead.
|
||||
func NewConn(c Socket, pid uint32) *Conn {
|
||||
func NewConn(sock Socket, pid uint32) *Conn {
|
||||
// Seed the sequence number using a random number generator.
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
seq := r.Uint32()
|
||||
|
|
@ -88,7 +91,7 @@ func NewConn(c Socket, pid uint32) *Conn {
|
|||
}
|
||||
|
||||
return &Conn{
|
||||
sock: c,
|
||||
sock: sock,
|
||||
seq: &seq,
|
||||
pid: pid,
|
||||
d: d,
|
||||
|
|
@ -115,8 +118,8 @@ func (c *Conn) Close() error {
|
|||
//
|
||||
// See the documentation of Conn.Send, Conn.Receive, and Validate for details about
|
||||
// each function.
|
||||
func (c *Conn) Execute(m Message) ([]Message, error) {
|
||||
req, err := c.Send(m)
|
||||
func (c *Conn) Execute(message Message) ([]Message, error) {
|
||||
req, err := c.Send(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -148,7 +151,8 @@ func (c *Conn) fixMsg(m *Message, ml int) {
|
|||
}
|
||||
|
||||
// SendMessages sends multiple Messages to netlink. The handling of
|
||||
// m.Header.Length, Sequence and PID is the same as when calling Send.
|
||||
// a Header's Length, Sequence and PID fields is the same as when
|
||||
// calling Send.
|
||||
func (c *Conn) SendMessages(messages []Message) ([]Message, error) {
|
||||
for idx, m := range messages {
|
||||
ml := nlmsgLength(len(m.Data))
|
||||
|
|
@ -178,34 +182,34 @@ func (c *Conn) SendMessages(messages []Message) ([]Message, error) {
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
// Send sends a single Message to netlink. In most cases, m.Header's Length,
|
||||
// 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
|
||||
// of the Message with all parameters populated, for later validation.
|
||||
//
|
||||
// If m.Header.Length is 0, it will be automatically populated using the
|
||||
// If Header.Length is 0, it will be automatically populated using the
|
||||
// correct length for the Message, including its payload.
|
||||
//
|
||||
// If m.Header.Sequence is 0, it will be automatically populated using the
|
||||
// If Header.Sequence is 0, it will be automatically populated using the
|
||||
// next sequence number for this connection.
|
||||
//
|
||||
// If m.Header.PID is 0, it will be automatically populated using a PID
|
||||
// If Header.PID is 0, it will be automatically populated using a PID
|
||||
// assigned by netlink.
|
||||
func (c *Conn) Send(m Message) (Message, error) {
|
||||
ml := nlmsgLength(len(m.Data))
|
||||
func (c *Conn) Send(message Message) (Message, error) {
|
||||
ml := nlmsgLength(len(message.Data))
|
||||
|
||||
// TODO(mdlayher): fine-tune this limit.
|
||||
if ml > (1024 * 32) {
|
||||
return Message{}, errors.New("netlink message data too large")
|
||||
}
|
||||
|
||||
c.fixMsg(&m, ml)
|
||||
c.fixMsg(&message, ml)
|
||||
|
||||
c.debug(func(d *debugger) {
|
||||
d.debugf(1, "send: %+v", m)
|
||||
d.debugf(1, "send: %+v", message)
|
||||
})
|
||||
|
||||
if err := c.sock.Send(m); err != nil {
|
||||
if err := c.sock.Send(message); err != nil {
|
||||
c.debug(func(d *debugger) {
|
||||
d.debugf(1, "send: err: %v", err)
|
||||
})
|
||||
|
|
@ -213,7 +217,7 @@ func (c *Conn) Send(m Message) (Message, error) {
|
|||
return Message{}, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
return message, nil
|
||||
}
|
||||
|
||||
// Receive receives one or more messages from netlink. Multi-part messages are
|
||||
|
|
@ -419,6 +423,80 @@ func (c *Conn) SetOption(option ConnOption, enable bool) error {
|
|||
return fc.SetOption(option, enable)
|
||||
}
|
||||
|
||||
// A bufferSetter is a Socket that supports setting connection buffer sizes.
|
||||
type bufferSetter interface {
|
||||
Socket
|
||||
SetReadBuffer(bytes int) error
|
||||
SetWriteBuffer(bytes int) error
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetReadBuffer(bytes int) error {
|
||||
conn, ok := c.sock.(bufferSetter)
|
||||
if !ok {
|
||||
return errSetBufferNotSupported
|
||||
}
|
||||
|
||||
return conn.SetReadBuffer(bytes)
|
||||
}
|
||||
|
||||
// SetWriteBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *Conn) SetWriteBuffer(bytes int) error {
|
||||
conn, ok := c.sock.(bufferSetter)
|
||||
if !ok {
|
||||
return errSetBufferNotSupported
|
||||
}
|
||||
|
||||
return conn.SetWriteBuffer(bytes)
|
||||
}
|
||||
|
||||
var _ syscall.Conn = &Conn{}
|
||||
|
||||
// TODO(mdlayher): mutex or similar to enforce syscall.RawConn contract of
|
||||
// FD remaining valid for duration of calls?
|
||||
|
||||
// SyscallConn returns a raw network connection. This implements the
|
||||
// syscall.Conn interface.
|
||||
//
|
||||
// Only the Control method of the returned syscall.RawConn is currently
|
||||
// implemented.
|
||||
//
|
||||
// SyscallConn is intended for advanced use cases, such as getting and setting
|
||||
// arbitrary socket options using the netlink socket's file descriptor.
|
||||
//
|
||||
// Once invoked, it is the caller's responsibility to ensure that operations
|
||||
// performed using Conn and the syscall.RawConn do not conflict with
|
||||
// each other.
|
||||
func (c *Conn) SyscallConn() (syscall.RawConn, error) {
|
||||
conn, ok := c.sock.(fder)
|
||||
if !ok {
|
||||
return nil, errSyscallConnNotSupported
|
||||
}
|
||||
|
||||
return &rawConn{
|
||||
fd: uintptr(conn.FD()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ syscall.RawConn = &rawConn{}
|
||||
|
||||
// A rawConn is a syscall.RawConn.
|
||||
type rawConn struct {
|
||||
fd uintptr
|
||||
}
|
||||
|
||||
func (rc *rawConn) Control(f func(fd uintptr)) error {
|
||||
f(rc.fd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(mdlayher): implement Read and Write?
|
||||
|
||||
func (rc *rawConn) Read(_ func(fd uintptr) (done bool)) error { return errSyscallConnNotSupported }
|
||||
func (rc *rawConn) Write(_ func(fd uintptr) (done bool)) error { return errSyscallConnNotSupported }
|
||||
|
||||
// nextSequence atomically increments Conn's sequence number and returns
|
||||
// the incremented value.
|
||||
func (c *Conn) nextSequence() uint32 {
|
||||
|
|
@ -455,13 +533,7 @@ type Config struct {
|
|||
// no multicast group subscriptions will be made.
|
||||
Groups uint32
|
||||
|
||||
// Experimental: do not lock the internal system call handling goroutine
|
||||
// to its OS thread. This may result in a speed-up of system call handling,
|
||||
// but may cause unexpected behavior when sending and receiving a large number
|
||||
// of messages.
|
||||
//
|
||||
// This should almost certainly be set to false, but if you come up with a
|
||||
// valid reason for using this, please file an issue at
|
||||
// https://github.com/mdlayher/netlink to discuss your thoughts.
|
||||
NoLockThread bool
|
||||
// Network namespace the Conn needs to operate in. If set to 0,
|
||||
// no network namespace will be entered.
|
||||
NetNS int
|
||||
}
|
||||
|
|
|
|||
181
vendor/github.com/mdlayher/netlink/conn_linux.go
generated
vendored
181
vendor/github.com/mdlayher/netlink/conn_linux.go
generated
vendored
|
|
@ -50,8 +50,10 @@ func dial(family int, config *Config) (*conn, uint32, error) {
|
|||
config = &Config{}
|
||||
}
|
||||
|
||||
lockThread := !config.NoLockThread
|
||||
sock := newSysSocket(lockThread)
|
||||
sock, err := newSysSocket(config)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := sock.Socket(family); err != nil {
|
||||
return nil, 0, err
|
||||
|
|
@ -260,6 +262,32 @@ func (c *conn) SetOption(option ConnOption, enable bool) error {
|
|||
)
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer
|
||||
// associated with the Conn.
|
||||
func (c *conn) SetReadBuffer(bytes int) error {
|
||||
v := uint32(bytes)
|
||||
|
||||
return c.s.SetSockopt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_RCVBUF,
|
||||
unsafe.Pointer(&v),
|
||||
uint32(unsafe.Sizeof(v)),
|
||||
)
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's transmit buffer
|
||||
// associated with the Conn.
|
||||
func (c *conn) SetWriteBuffer(bytes int) error {
|
||||
v := uint32(bytes)
|
||||
|
||||
return c.s.SetSockopt(
|
||||
unix.SOL_SOCKET,
|
||||
unix.SO_SNDBUF,
|
||||
unsafe.Pointer(&v),
|
||||
uint32(unsafe.Sizeof(v)),
|
||||
)
|
||||
}
|
||||
|
||||
// linuxOption converts a ConnOption to its Linux value.
|
||||
func linuxOption(o ConnOption) (int, bool) {
|
||||
switch o {
|
||||
|
|
@ -299,11 +327,16 @@ type sysSocket struct {
|
|||
|
||||
wg *sync.WaitGroup
|
||||
funcC chan<- func()
|
||||
|
||||
mu sync.RWMutex
|
||||
|
||||
done bool
|
||||
doneC chan<- bool
|
||||
}
|
||||
|
||||
// newSysSocket creates a sysSocket that optionally locks its internal goroutine
|
||||
// to a single thread.
|
||||
func newSysSocket(lockThread bool) *sysSocket {
|
||||
func newSysSocket(config *Config) (*sysSocket, error) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
|
|
@ -312,52 +345,98 @@ func newSysSocket(lockThread bool) *sysSocket {
|
|||
// Gophers Slack for providing this useful link.
|
||||
|
||||
funcC := make(chan func())
|
||||
doneC := make(chan bool)
|
||||
errC := make(chan error)
|
||||
|
||||
go func() {
|
||||
// It is important to lock this goroutine to its OS thread for the duration
|
||||
// of the netlink socket being used, or else the kernel may end up routing
|
||||
// messages to the wrong places.
|
||||
// See: http://lists.infradead.org/pipermail/libnl/2017-February/002293.html.
|
||||
//
|
||||
// But since this is very experimental, we'll leave it as a configurable at
|
||||
// this point.
|
||||
if lockThread {
|
||||
// The intent is to never unlock the OS thread, so that the thread
|
||||
// will terminate when the goroutine exits starting in Go 1.10:
|
||||
// https://go-review.googlesource.com/c/go/+/46038.
|
||||
//
|
||||
// However, due to recent instability and a potential bad interaction
|
||||
// with the Go runtime for threads which are not unlocked, we have
|
||||
// elected to temporarily unlock the thread:
|
||||
// https://github.com/golang/go/issues/25128#issuecomment-410764489.
|
||||
//
|
||||
// If we ever allow a Conn to set its own network namespace, we must
|
||||
// either ensure that the namespace is restored on exit here or that
|
||||
// the thread is properly terminated at some point in the future.
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
}
|
||||
// The intent is to never unlock the OS thread, so that the thread
|
||||
// will terminate when the goroutine exits starting in Go 1.10:
|
||||
// https://go-review.googlesource.com/c/go/+/46038.
|
||||
//
|
||||
// However, due to recent instability and a potential bad interaction
|
||||
// with the Go runtime for threads which are not unlocked, we have
|
||||
// elected to temporarily unlock the thread when the goroutine terminates:
|
||||
// https://github.com/golang/go/issues/25128#issuecomment-410764489.
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
defer wg.Done()
|
||||
|
||||
for f := range funcC {
|
||||
f()
|
||||
// The user requested the Conn to operate in a non-default network namespace.
|
||||
if config.NetNS != 0 {
|
||||
|
||||
// Get the current namespace of the thread the goroutine is locked to.
|
||||
origNetNS, err := getThreadNetNS()
|
||||
if err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Set the network namespace of the current thread using
|
||||
// the file descriptor provided by the user.
|
||||
err = setThreadNetNS(config.NetNS)
|
||||
if err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Once the thread's namespace has been successfully manipulated,
|
||||
// make sure we change it back when the goroutine returns.
|
||||
defer setThreadNetNS(origNetNS)
|
||||
}
|
||||
|
||||
// Signal to caller that initialization was successful.
|
||||
errC <- nil
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-doneC:
|
||||
return
|
||||
case f := <-funcC:
|
||||
f()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for the goroutine to return err or nil.
|
||||
if err := <-errC; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &sysSocket{
|
||||
wg: &wg,
|
||||
funcC: funcC,
|
||||
}
|
||||
doneC: doneC,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// do runs f in a worker goroutine which can be locked to one thread.
|
||||
func (s *sysSocket) do(f func()) {
|
||||
func (s *sysSocket) do(f func()) error {
|
||||
done := make(chan bool, 1)
|
||||
|
||||
// All operations handled by this function are assumed to only
|
||||
// read from s.done.
|
||||
s.mu.RLock()
|
||||
|
||||
if s.done {
|
||||
s.mu.RUnlock()
|
||||
return syscall.EBADF
|
||||
}
|
||||
|
||||
s.funcC <- func() {
|
||||
f()
|
||||
done <- true
|
||||
}
|
||||
<-done
|
||||
|
||||
s.mu.RUnlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sysSocket) Socket(family int) error {
|
||||
|
|
@ -366,13 +445,16 @@ func (s *sysSocket) Socket(family int) error {
|
|||
err error
|
||||
)
|
||||
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
fd, err = unix.Socket(
|
||||
unix.AF_NETLINK,
|
||||
unix.SOCK_RAW,
|
||||
family,
|
||||
)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -383,21 +465,35 @@ func (s *sysSocket) Socket(family int) error {
|
|||
|
||||
func (s *sysSocket) Bind(sa unix.Sockaddr) error {
|
||||
var err error
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
err = unix.Bind(s.fd, sa)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *sysSocket) Close() error {
|
||||
var err error
|
||||
s.do(func() {
|
||||
err = unix.Close(s.fd)
|
||||
})
|
||||
|
||||
close(s.funcC)
|
||||
// Be sure to acquire a write lock because we need to stop any other
|
||||
// goroutines from sending system call requests after close.
|
||||
// Any invocation of do() after this write lock unlocks is guaranteed
|
||||
// to find s.done being true.
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// Close the socket from the main thread, this operation has no risk
|
||||
// of routing data to the wrong socket.
|
||||
err := unix.Close(s.fd)
|
||||
s.done = true
|
||||
|
||||
// Signal the syscall worker to exit, wait for the WaitGroup to join,
|
||||
// and close the job channel only when the worker is guaranteed to have stopped.
|
||||
close(s.doneC)
|
||||
s.wg.Wait()
|
||||
close(s.funcC)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
@ -410,12 +506,16 @@ func (s *sysSocket) Getsockname() (unix.Sockaddr, error) {
|
|||
err error
|
||||
)
|
||||
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
sa, err = unix.Getsockname(s.fd)
|
||||
})
|
||||
if doErr != nil {
|
||||
return nil, doErr
|
||||
}
|
||||
|
||||
return sa, err
|
||||
}
|
||||
|
||||
func (s *sysSocket) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Sockaddr, error) {
|
||||
var (
|
||||
n, oobn, recvflags int
|
||||
|
|
@ -423,27 +523,36 @@ func (s *sysSocket) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Socka
|
|||
err error
|
||||
)
|
||||
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
n, oobn, recvflags, from, err = unix.Recvmsg(s.fd, p, oob, flags)
|
||||
})
|
||||
if doErr != nil {
|
||||
return 0, 0, 0, nil, doErr
|
||||
}
|
||||
|
||||
return n, oobn, recvflags, from, err
|
||||
}
|
||||
|
||||
func (s *sysSocket) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error {
|
||||
var err error
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
err = unix.Sendmsg(s.fd, p, oob, to, flags)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *sysSocket) SetSockopt(level, name int, v unsafe.Pointer, l uint32) error {
|
||||
var err error
|
||||
s.do(func() {
|
||||
doErr := s.do(func() {
|
||||
err = setsockopt(s.fd, level, name, v, l)
|
||||
})
|
||||
if doErr != nil {
|
||||
return doErr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
21
vendor/github.com/mdlayher/netlink/message.go
generated
vendored
21
vendor/github.com/mdlayher/netlink/message.go
generated
vendored
|
|
@ -233,17 +233,16 @@ func (m *Message) UnmarshalBinary(b []byte) error {
|
|||
func checkMessage(m Message) error {
|
||||
const success = 0
|
||||
|
||||
// Both "done" and "error" can contain error codes.
|
||||
isDone := m.Header.Type == HeaderTypeDone
|
||||
isError := m.Header.Type == HeaderTypeError
|
||||
|
||||
switch {
|
||||
// "done" with no data means success.
|
||||
case isDone && len(m.Data) == 0:
|
||||
return nil
|
||||
case isError, isDone:
|
||||
break
|
||||
default:
|
||||
// Per libnl documentation, only messages that indicate type error can
|
||||
// contain error codes:
|
||||
// https://www.infradead.org/~tgr/libnl/doc/core.html#core_errmsg.
|
||||
//
|
||||
// However, at one point, this package checked both done and error for
|
||||
// error codes. Because there was no issue associated with the change,
|
||||
// it is unknown whether this change was correct or not. If you run into
|
||||
// a problem with your application because of this change, please file
|
||||
// an issue.
|
||||
if m.Header.Type != HeaderTypeError {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
27
vendor/github.com/mdlayher/netlink/netns_linux.go
generated
vendored
Normal file
27
vendor/github.com/mdlayher/netlink/netns_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//+build linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// getThreadNetNS gets the network namespace file descriptor of the thread the current goroutine
|
||||
// is running on. Make sure to call runtime.LockOSThread() before this so the goroutine does not
|
||||
// get scheduled on another thread in the meantime.
|
||||
func getThreadNetNS() (int, error) {
|
||||
file, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/net", unix.Getpid(), unix.Gettid()))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return int(file.Fd()), nil
|
||||
}
|
||||
|
||||
// setThreadNetNS sets the network namespace of the thread of the current goroutine to
|
||||
// the namespace described by the user-provided file descriptor.
|
||||
func setThreadNetNS(fd int) error {
|
||||
return unix.Setns(fd, unix.CLONE_NEWNET)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue