mirror of
				https://github.com/prometheus/node_exporter.git
				synced 2025-08-20 18:33:52 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			232 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package netlink
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/mdlayher/netlink/nlenc"
 | |
| )
 | |
| 
 | |
| // Various errors which may occur when attempting to marshal or unmarshal
 | |
| // a Message to and from its binary form.
 | |
| var (
 | |
| 	errIncorrectMessageLength = errors.New("netlink message header length incorrect")
 | |
| 	errShortMessage           = errors.New("not enough data to create a netlink message")
 | |
| 	errUnalignedMessage       = errors.New("input data is not properly aligned for netlink message")
 | |
| )
 | |
| 
 | |
| // HeaderFlags specify flags which may be present in a Header.
 | |
| type HeaderFlags uint16
 | |
| 
 | |
| const (
 | |
| 	// General netlink communication flags.
 | |
| 
 | |
| 	// HeaderFlagsRequest indicates a request to netlink.
 | |
| 	HeaderFlagsRequest HeaderFlags = 1
 | |
| 
 | |
| 	// HeaderFlagsMulti indicates a multi-part message, terminated
 | |
| 	// by HeaderTypeDone on the last message.
 | |
| 	HeaderFlagsMulti HeaderFlags = 2
 | |
| 
 | |
| 	// HeaderFlagsAcknowledge requests that netlink reply with
 | |
| 	// an acknowledgement using HeaderTypeError and, if needed,
 | |
| 	// an error code.
 | |
| 	HeaderFlagsAcknowledge HeaderFlags = 4
 | |
| 
 | |
| 	// HeaderFlagsEcho requests that netlink echo this request
 | |
| 	// back to the sender.
 | |
| 	HeaderFlagsEcho HeaderFlags = 8
 | |
| 
 | |
| 	// HeaderFlagsDumpInterrupted indicates that a dump was
 | |
| 	// inconsistent due to a sequence change.
 | |
| 	HeaderFlagsDumpInterrupted HeaderFlags = 16
 | |
| 
 | |
| 	// HeaderFlagsDumpFiltered indicates that a dump was filtered
 | |
| 	// as requested.
 | |
| 	HeaderFlagsDumpFiltered HeaderFlags = 32
 | |
| 
 | |
| 	// Flags used to retrieve data from netlink.
 | |
| 
 | |
| 	// HeaderFlagsRoot requests that netlink return a complete table instead
 | |
| 	// of a single entry.
 | |
| 	HeaderFlagsRoot HeaderFlags = 0x100
 | |
| 
 | |
| 	// HeaderFlagsMatch requests that netlink return a list of all matching
 | |
| 	// entries.
 | |
| 	HeaderFlagsMatch HeaderFlags = 0x200
 | |
| 
 | |
| 	// HeaderFlagsAtomic requests that netlink send an atomic snapshot of
 | |
| 	// its entries.  Requires CAP_NET_ADMIN or an effective UID of 0.
 | |
| 	HeaderFlagsAtomic HeaderFlags = 0x400
 | |
| 
 | |
| 	// HeaderFlagsDump requests that netlink return a complete list of
 | |
| 	// all entries.
 | |
| 	HeaderFlagsDump HeaderFlags = HeaderFlagsRoot | HeaderFlagsMatch
 | |
| )
 | |
| 
 | |
| // String returns the string representation of a HeaderFlags.
 | |
| func (f HeaderFlags) String() string {
 | |
| 	names := []string{
 | |
| 		"request",
 | |
| 		"multi",
 | |
| 		"acknowledge",
 | |
| 		"echo",
 | |
| 		"dumpinterrupted",
 | |
| 		"dumpfiltered",
 | |
| 		"1<<6",
 | |
| 		"1<<7",
 | |
| 		"root",
 | |
| 		"match",
 | |
| 		"atomic",
 | |
| 	}
 | |
| 
 | |
| 	var s string
 | |
| 	for i, name := range names {
 | |
| 		if f&(1<<uint(i)) != 0 {
 | |
| 			if s != "" {
 | |
| 				s += "|"
 | |
| 			}
 | |
| 
 | |
| 			s += name
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if s == "" {
 | |
| 		s = "0"
 | |
| 	}
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| // HeaderType specifies the type of a Header.
 | |
| type HeaderType uint16
 | |
| 
 | |
| const (
 | |
| 	// HeaderTypeNoop indicates that no action was taken.
 | |
| 	HeaderTypeNoop HeaderType = 0x1
 | |
| 
 | |
| 	// HeaderTypeError indicates an error code is present, which is also
 | |
| 	// used to indicate success when the code is 0.
 | |
| 	HeaderTypeError HeaderType = 0x2
 | |
| 
 | |
| 	// HeaderTypeDone indicates the end of a multi-part message.
 | |
| 	HeaderTypeDone HeaderType = 0x3
 | |
| 
 | |
| 	// HeaderTypeOverrun indicates that data was lost from this message.
 | |
| 	HeaderTypeOverrun HeaderType = 0x4
 | |
| )
 | |
| 
 | |
| // String returns the string representation of a HeaderType.
 | |
| func (t HeaderType) String() string {
 | |
| 	switch t {
 | |
| 	case HeaderTypeNoop:
 | |
| 		return "noop"
 | |
| 	case HeaderTypeError:
 | |
| 		return "error"
 | |
| 	case HeaderTypeDone:
 | |
| 		return "done"
 | |
| 	case HeaderTypeOverrun:
 | |
| 		return "overrun"
 | |
| 	default:
 | |
| 		return fmt.Sprintf("unknown(%d)", t)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NB: the memory layout of Header and Linux's syscall.NlMsgHdr must be
 | |
| // exactly the same.  Cannot reorder, change data type, add, or remove fields.
 | |
| // Named types of the same size (e.g. HeaderFlags is a uint16) are okay.
 | |
| 
 | |
| // A Header is a netlink header.  A Header is sent and received with each
 | |
| // Message to indicate metadata regarding a Message.
 | |
| type Header struct {
 | |
| 	// Length of a Message, including this Header.
 | |
| 	Length uint32
 | |
| 
 | |
| 	// Contents of a Message.
 | |
| 	Type HeaderType
 | |
| 
 | |
| 	// Flags which may be used to modify a request or response.
 | |
| 	Flags HeaderFlags
 | |
| 
 | |
| 	// The sequence number of a Message.
 | |
| 	Sequence uint32
 | |
| 
 | |
| 	// The process ID of the sending process.
 | |
| 	PID uint32
 | |
| }
 | |
| 
 | |
| // A Message is a netlink message.  It contains a Header and an arbitrary
 | |
| // byte payload, which may be decoded using information from the Header.
 | |
| //
 | |
| // Data is encoded in the native endianness of the host system.  For easier
 | |
| // of encoding and decoding of integers, use package nlenc.
 | |
| type Message struct {
 | |
| 	Header Header
 | |
| 	Data   []byte
 | |
| }
 | |
| 
 | |
| // MarshalBinary marshals a Message into a byte slice.
 | |
| func (m Message) MarshalBinary() ([]byte, error) {
 | |
| 	ml := nlmsgAlign(int(m.Header.Length))
 | |
| 	if ml < nlmsgHeaderLen || ml != int(m.Header.Length) {
 | |
| 		return nil, errIncorrectMessageLength
 | |
| 	}
 | |
| 
 | |
| 	b := make([]byte, ml)
 | |
| 
 | |
| 	nlenc.PutUint32(b[0:4], m.Header.Length)
 | |
| 	nlenc.PutUint16(b[4:6], uint16(m.Header.Type))
 | |
| 	nlenc.PutUint16(b[6:8], uint16(m.Header.Flags))
 | |
| 	nlenc.PutUint32(b[8:12], m.Header.Sequence)
 | |
| 	nlenc.PutUint32(b[12:16], m.Header.PID)
 | |
| 	copy(b[16:], m.Data)
 | |
| 
 | |
| 	return b, nil
 | |
| }
 | |
| 
 | |
| // UnmarshalBinary unmarshals the contents of a byte slice into a Message.
 | |
| func (m *Message) UnmarshalBinary(b []byte) error {
 | |
| 	if len(b) < nlmsgHeaderLen {
 | |
| 		return errShortMessage
 | |
| 	}
 | |
| 	if len(b) != nlmsgAlign(len(b)) {
 | |
| 		return errUnalignedMessage
 | |
| 	}
 | |
| 
 | |
| 	// Don't allow misleading length
 | |
| 	m.Header.Length = nlenc.Uint32(b[0:4])
 | |
| 	if int(m.Header.Length) != len(b) {
 | |
| 		return errShortMessage
 | |
| 	}
 | |
| 
 | |
| 	m.Header.Type = HeaderType(nlenc.Uint16(b[4:6]))
 | |
| 	m.Header.Flags = HeaderFlags(nlenc.Uint16(b[6:8]))
 | |
| 	m.Header.Sequence = nlenc.Uint32(b[8:12])
 | |
| 	m.Header.PID = nlenc.Uint32(b[12:16])
 | |
| 	m.Data = b[16:]
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // checkMessage checks a single Message for netlink errors.
 | |
| func checkMessage(m Message) error {
 | |
| 	const success = 0
 | |
| 
 | |
| 	// HeaderTypeError may indicate an error code, or success
 | |
| 	if m.Header.Type != HeaderTypeError {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	if len(m.Data) < 4 {
 | |
| 		return errShortErrorMessage
 | |
| 	}
 | |
| 
 | |
| 	if c := nlenc.Int32(m.Data[0:4]); c != success {
 | |
| 		// Error code is a negative integer, convert it into
 | |
| 		// an OS-specific system call error
 | |
| 		return newError(-1 * int(c))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |