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