github.com/vishvananda/netlink@v1.3.1/genetlink_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"syscall"
     7  
     8  	"github.com/vishvananda/netlink/nl"
     9  	"golang.org/x/sys/unix"
    10  )
    11  
    12  type GenlOp struct {
    13  	ID    uint32
    14  	Flags uint32
    15  }
    16  
    17  type GenlMulticastGroup struct {
    18  	ID   uint32
    19  	Name string
    20  }
    21  
    22  type GenlFamily struct {
    23  	ID      uint16
    24  	HdrSize uint32
    25  	Name    string
    26  	Version uint32
    27  	MaxAttr uint32
    28  	Ops     []GenlOp
    29  	Groups  []GenlMulticastGroup
    30  }
    31  
    32  func parseOps(b []byte) ([]GenlOp, error) {
    33  	attrs, err := nl.ParseRouteAttr(b)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	ops := make([]GenlOp, 0, len(attrs))
    38  	for _, a := range attrs {
    39  		nattrs, err := nl.ParseRouteAttr(a.Value)
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  		var op GenlOp
    44  		for _, na := range nattrs {
    45  			switch na.Attr.Type {
    46  			case nl.GENL_CTRL_ATTR_OP_ID:
    47  				op.ID = native.Uint32(na.Value)
    48  			case nl.GENL_CTRL_ATTR_OP_FLAGS:
    49  				op.Flags = native.Uint32(na.Value)
    50  			}
    51  		}
    52  		ops = append(ops, op)
    53  	}
    54  	return ops, nil
    55  }
    56  
    57  func parseMulticastGroups(b []byte) ([]GenlMulticastGroup, error) {
    58  	attrs, err := nl.ParseRouteAttr(b)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	groups := make([]GenlMulticastGroup, 0, len(attrs))
    63  	for _, a := range attrs {
    64  		nattrs, err := nl.ParseRouteAttr(a.Value)
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  		var g GenlMulticastGroup
    69  		for _, na := range nattrs {
    70  			switch na.Attr.Type {
    71  			case nl.GENL_CTRL_ATTR_MCAST_GRP_NAME:
    72  				g.Name = nl.BytesToString(na.Value)
    73  			case nl.GENL_CTRL_ATTR_MCAST_GRP_ID:
    74  				g.ID = native.Uint32(na.Value)
    75  			}
    76  		}
    77  		groups = append(groups, g)
    78  	}
    79  	return groups, nil
    80  }
    81  
    82  func (f *GenlFamily) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
    83  	for _, a := range attrs {
    84  		switch a.Attr.Type {
    85  		case nl.GENL_CTRL_ATTR_FAMILY_NAME:
    86  			f.Name = nl.BytesToString(a.Value)
    87  		case nl.GENL_CTRL_ATTR_FAMILY_ID:
    88  			f.ID = native.Uint16(a.Value)
    89  		case nl.GENL_CTRL_ATTR_VERSION:
    90  			f.Version = native.Uint32(a.Value)
    91  		case nl.GENL_CTRL_ATTR_HDRSIZE:
    92  			f.HdrSize = native.Uint32(a.Value)
    93  		case nl.GENL_CTRL_ATTR_MAXATTR:
    94  			f.MaxAttr = native.Uint32(a.Value)
    95  		case nl.GENL_CTRL_ATTR_OPS:
    96  			ops, err := parseOps(a.Value)
    97  			if err != nil {
    98  				return err
    99  			}
   100  			f.Ops = ops
   101  		case nl.GENL_CTRL_ATTR_MCAST_GROUPS:
   102  			groups, err := parseMulticastGroups(a.Value)
   103  			if err != nil {
   104  				return err
   105  			}
   106  			f.Groups = groups
   107  		}
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  func parseFamilies(msgs [][]byte) ([]*GenlFamily, error) {
   114  	families := make([]*GenlFamily, 0, len(msgs))
   115  	for _, m := range msgs {
   116  		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   117  		if err != nil {
   118  			return nil, err
   119  		}
   120  		family := &GenlFamily{}
   121  		if err := family.parseAttributes(attrs); err != nil {
   122  			return nil, err
   123  		}
   124  
   125  		families = append(families, family)
   126  	}
   127  	return families, nil
   128  }
   129  
   130  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   131  // or incomplete.
   132  func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
   133  	msg := &nl.Genlmsg{
   134  		Command: nl.GENL_CTRL_CMD_GETFAMILY,
   135  		Version: nl.GENL_CTRL_VERSION,
   136  	}
   137  	req := h.newNetlinkRequest(nl.GENL_ID_CTRL, unix.NLM_F_DUMP)
   138  	req.AddData(msg)
   139  	msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
   140  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   141  		return nil, executeErr
   142  	}
   143  	families, err := parseFamilies(msgs)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	return families, executeErr
   148  }
   149  
   150  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   151  // or incomplete.
   152  func GenlFamilyList() ([]*GenlFamily, error) {
   153  	return pkgHandle.GenlFamilyList()
   154  }
   155  
   156  func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
   157  	msg := &nl.Genlmsg{
   158  		Command: nl.GENL_CTRL_CMD_GETFAMILY,
   159  		Version: nl.GENL_CTRL_VERSION,
   160  	}
   161  	req := h.newNetlinkRequest(nl.GENL_ID_CTRL, 0)
   162  	req.AddData(msg)
   163  	req.AddData(nl.NewRtAttr(nl.GENL_CTRL_ATTR_FAMILY_NAME, nl.ZeroTerminated(name)))
   164  	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  	families, err := parseFamilies(msgs)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	if len(families) != 1 {
   173  		return nil, fmt.Errorf("invalid response for GENL_CTRL_CMD_GETFAMILY")
   174  	}
   175  	return families[0], nil
   176  }
   177  
   178  func GenlFamilyGet(name string) (*GenlFamily, error) {
   179  	return pkgHandle.GenlFamilyGet(name)
   180  }