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 }