Node_Exporter/vendor/github.com/mdlayher/genetlink/family_linux.go
Matt Layher d84873727f vendor: bump github.com/mdlayher/wifi and dependencies (#1045)
Signed-off-by: Matt Layher <mdlayher@gmail.com>
2018-08-14 21:15:07 +02:00

172 lines
3.6 KiB
Go

//+build linux
package genetlink
import (
"errors"
"fmt"
"math"
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/nlenc"
"golang.org/x/sys/unix"
)
var (
// errInvalidFamilyVersion is returned when a family's version is greater
// than an 8-bit integer.
errInvalidFamilyVersion = errors.New("invalid family version attribute")
)
// getFamily retrieves a generic netlink family with the specified name.
func (c *Conn) getFamily(name string) (Family, error) {
b, err := netlink.MarshalAttributes([]netlink.Attribute{{
Type: unix.CTRL_ATTR_FAMILY_NAME,
Data: nlenc.Bytes(name),
}})
if err != nil {
return Family{}, err
}
req := Message{
Header: Header{
Command: unix.CTRL_CMD_GETFAMILY,
// TODO(mdlayher): grab nlctrl version?
Version: 1,
},
Data: b,
}
msgs, err := c.Execute(req, unix.GENL_ID_CTRL, netlink.HeaderFlagsRequest)
if err != nil {
return Family{}, err
}
// TODO(mdlayher): consider interpreting generic netlink header values
families, err := buildFamilies(msgs)
if err != nil {
return Family{}, err
}
if len(families) != 1 {
// If this were to ever happen, netlink must be in a state where
// its answers cannot be trusted
panic(fmt.Sprintf("netlink returned multiple families for name: %q", name))
}
return families[0], nil
}
// listFamilies retrieves all registered generic netlink families.
func (c *Conn) listFamilies() ([]Family, error) {
req := Message{
Header: Header{
Command: unix.CTRL_CMD_GETFAMILY,
// TODO(mdlayher): grab nlctrl version?
Version: 1,
},
}
flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump
msgs, err := c.Execute(req, unix.GENL_ID_CTRL, flags)
if err != nil {
return nil, err
}
return buildFamilies(msgs)
}
// buildFamilies builds a slice of Families by parsing attributes from the
// input Messages.
func buildFamilies(msgs []Message) ([]Family, error) {
families := make([]Family, 0, len(msgs))
for _, m := range msgs {
var f Family
if err := (&f).parseAttributes(m.Data); err != nil {
return nil, err
}
families = append(families, f)
}
return families, nil
}
// parseAttributes decodes netlink attributes into a Family's fields.
func (f *Family) parseAttributes(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
for ad.Next() {
switch ad.Type() {
case unix.CTRL_ATTR_FAMILY_ID:
f.ID = ad.Uint16()
case unix.CTRL_ATTR_FAMILY_NAME:
f.Name = ad.String()
case unix.CTRL_ATTR_VERSION:
v := ad.Uint32()
if v > math.MaxUint8 {
return errInvalidFamilyVersion
}
f.Version = uint8(v)
case unix.CTRL_ATTR_MCAST_GROUPS:
ad.Do(func(b []byte) error {
groups, err := parseMulticastGroups(b)
if err != nil {
return err
}
f.Groups = groups
return nil
})
}
}
return ad.Err()
}
// parseMulticastGroups parses an array of multicast group nested attributes
// into a slice of MulticastGroups.
func parseMulticastGroups(b []byte) ([]MulticastGroup, error) {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return nil, err
}
var groups []MulticastGroup
for ad.Next() {
ad.Do(func(b []byte) error {
adi, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
var g MulticastGroup
for adi.Next() {
switch adi.Type() {
case unix.CTRL_ATTR_MCAST_GRP_NAME:
g.Name = adi.String()
case unix.CTRL_ATTR_MCAST_GRP_ID:
g.ID = adi.Uint32()
}
}
if err := ad.Err(); err != nil {
return err
}
groups = append(groups, g)
return nil
})
}
if err := ad.Err(); err != nil {
return nil, err
}
return groups, nil
}