mirror of
				https://github.com/prometheus/node_exporter.git
				synced 2025-08-20 18:33:52 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			123 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package netlink
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 
 | |
| 	"github.com/mdlayher/netlink/nlenc"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// errInvalidAttribute specifies if an Attribute's length is incorrect.
 | |
| 	errInvalidAttribute = errors.New("invalid attribute; length too short or too large")
 | |
| )
 | |
| 
 | |
| // An Attribute is a netlink attribute.  Attributes are packed and unpacked
 | |
| // to and from the Data field of Message for some netlink protocol families.
 | |
| type Attribute struct {
 | |
| 	// Length of an Attribute, including this field and Type.
 | |
| 	Length uint16
 | |
| 
 | |
| 	// The type of this Attribute, typically matched to a constant.
 | |
| 	Type uint16
 | |
| 
 | |
| 	// An arbitrary payload which is specified by Type.
 | |
| 	Data []byte
 | |
| }
 | |
| 
 | |
| // MarshalBinary marshals an Attribute into a byte slice.
 | |
| func (a Attribute) MarshalBinary() ([]byte, error) {
 | |
| 	if int(a.Length) < nlaHeaderLen {
 | |
| 		return nil, errInvalidAttribute
 | |
| 	}
 | |
| 
 | |
| 	b := make([]byte, nlaAlign(int(a.Length)))
 | |
| 
 | |
| 	nlenc.PutUint16(b[0:2], a.Length)
 | |
| 	nlenc.PutUint16(b[2:4], a.Type)
 | |
| 	copy(b[4:], a.Data)
 | |
| 
 | |
| 	return b, nil
 | |
| }
 | |
| 
 | |
| // UnmarshalBinary unmarshals the contents of a byte slice into an Attribute.
 | |
| func (a *Attribute) UnmarshalBinary(b []byte) error {
 | |
| 	if len(b) < nlaHeaderLen {
 | |
| 		return errInvalidAttribute
 | |
| 	}
 | |
| 
 | |
| 	a.Length = nlenc.Uint16(b[0:2])
 | |
| 	a.Type = nlenc.Uint16(b[2:4])
 | |
| 
 | |
| 	if nlaAlign(int(a.Length)) > len(b) {
 | |
| 		return errInvalidAttribute
 | |
| 	}
 | |
| 
 | |
| 	switch {
 | |
| 	// No length, no data
 | |
| 	case a.Length == 0:
 | |
| 		a.Data = make([]byte, 0)
 | |
| 	// Not enough length for any data
 | |
| 	case a.Length < 4:
 | |
| 		return errInvalidAttribute
 | |
| 	// Data present
 | |
| 	case a.Length >= 4:
 | |
| 		a.Data = make([]byte, len(b[4:a.Length]))
 | |
| 		copy(a.Data, b[4:a.Length])
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // MarshalAttributes packs a slice of Attributes into a single byte slice.
 | |
| // 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) {
 | |
| 	var c int
 | |
| 	for _, a := range attrs {
 | |
| 		c += nlaAlign(len(a.Data))
 | |
| 	}
 | |
| 
 | |
| 	b := make([]byte, 0, c)
 | |
| 	for _, a := range attrs {
 | |
| 		if a.Length == 0 {
 | |
| 			a.Length = uint16(nlaHeaderLen + len(a.Data))
 | |
| 		}
 | |
| 
 | |
| 		ab, err := a.MarshalBinary()
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		b = append(b, ab...)
 | |
| 	}
 | |
| 
 | |
| 	return b, nil
 | |
| }
 | |
| 
 | |
| // UnmarshalAttributes unpacks a slice of Attributes from a single byte slice.
 | |
| func UnmarshalAttributes(b []byte) ([]Attribute, error) {
 | |
| 	var attrs []Attribute
 | |
| 	var i int
 | |
| 	for {
 | |
| 		if len(b[i:]) == 0 {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		var a Attribute
 | |
| 		if err := (&a).UnmarshalBinary(b[i:]); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		if a.Length == 0 {
 | |
| 			i += nlaHeaderLen
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		i += nlaAlign(int(a.Length))
 | |
| 
 | |
| 		attrs = append(attrs, a)
 | |
| 	}
 | |
| 
 | |
| 	return attrs, nil
 | |
| }
 |