node_exporter/vendor/github.com/mdlayher/netlink/attribute.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
}