1 package netlink
2
3 import (
4 "bytes"
5 "encoding/binary"
6 "fmt"
7 "net"
8
9 "github.com/vishvananda/netlink/nl"
10 "golang.org/x/sys/unix"
11 )
12
13
14 type RdmaLinkAttrs struct {
15 Index uint32
16 Name string
17 FirmwareVersion string
18 NodeGuid string
19 SysImageGuid string
20 }
21
22
23 type RdmaLink struct {
24 Attrs RdmaLinkAttrs
25 }
26
27 func getProtoField(clientType int, op int) int {
28 return ((clientType << nl.RDMA_NL_GET_CLIENT_SHIFT) | op)
29 }
30
31 func uint64ToGuidString(guid uint64) string {
32
33 sysGuidBytes := new(bytes.Buffer)
34 binary.Write(sysGuidBytes, binary.LittleEndian, guid)
35
36
37 sysGuidNet := net.HardwareAddr(sysGuidBytes.Bytes())
38
39
40 return sysGuidNet.String()
41 }
42
43 func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) {
44
45 link := RdmaLink{}
46
47 reader := bytes.NewReader(data)
48 for reader.Len() >= 4 {
49 _, attrType, len, value := parseNfAttrTLV(reader)
50
51 switch attrType {
52 case nl.RDMA_NLDEV_ATTR_DEV_INDEX:
53 var Index uint32
54 r := bytes.NewReader(value)
55 binary.Read(r, nl.NativeEndian(), &Index)
56 link.Attrs.Index = Index
57 case nl.RDMA_NLDEV_ATTR_DEV_NAME:
58 link.Attrs.Name = string(value[0 : len-1])
59 case nl.RDMA_NLDEV_ATTR_FW_VERSION:
60 link.Attrs.FirmwareVersion = string(value[0 : len-1])
61 case nl.RDMA_NLDEV_ATTR_NODE_GUID:
62 var guid uint64
63 r := bytes.NewReader(value)
64 binary.Read(r, nl.NativeEndian(), &guid)
65 link.Attrs.NodeGuid = uint64ToGuidString(guid)
66 case nl.RDMA_NLDEV_ATTR_SYS_IMAGE_GUID:
67 var sysGuid uint64
68 r := bytes.NewReader(value)
69 binary.Read(r, nl.NativeEndian(), &sysGuid)
70 link.Attrs.SysImageGuid = uint64ToGuidString(sysGuid)
71 }
72 if (len % 4) != 0 {
73
74 reader.Seek(int64(4-(len%4)), seekCurrent)
75 }
76 }
77 return &link, nil
78 }
79
80 func execRdmaSetLink(req *nl.NetlinkRequest) error {
81
82 _, err := req.Execute(unix.NETLINK_RDMA, 0)
83 return err
84 }
85
86
87
88 func RdmaLinkList() ([]*RdmaLink, error) {
89 return pkgHandle.RdmaLinkList()
90 }
91
92
93
94 func (h *Handle) RdmaLinkList() ([]*RdmaLink, error) {
95 proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
96 req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
97
98 msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
99 if err != nil {
100 return nil, err
101 }
102
103 var res []*RdmaLink
104 for _, m := range msgs {
105 link, err := executeOneGetRdmaLink(m)
106 if err != nil {
107 return nil, err
108 }
109 res = append(res, link)
110 }
111
112 return res, nil
113 }
114
115
116
117 func RdmaLinkByName(name string) (*RdmaLink, error) {
118 return pkgHandle.RdmaLinkByName(name)
119 }
120
121
122
123 func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) {
124 links, err := h.RdmaLinkList()
125 if err != nil {
126 return nil, err
127 }
128 for _, link := range links {
129 if link.Attrs.Name == name {
130 return link, nil
131 }
132 }
133 return nil, fmt.Errorf("Rdma device %v not found", name)
134 }
135
136
137
138
139 func RdmaLinkSetName(link *RdmaLink, name string) error {
140 return pkgHandle.RdmaLinkSetName(link, name)
141 }
142
143
144
145
146 func (h *Handle) RdmaLinkSetName(link *RdmaLink, name string) error {
147 proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
148 req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
149
150 b := make([]byte, 4)
151 native.PutUint32(b, uint32(link.Attrs.Index))
152 data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b)
153 req.AddData(data)
154
155 b = make([]byte, len(name)+1)
156 copy(b, name)
157 data = nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, b)
158 req.AddData(data)
159
160 return execRdmaSetLink(req)
161 }
162
163 func netnsModeToString(mode uint8) string {
164 switch mode {
165 case 0:
166 return "exclusive"
167 case 1:
168 return "shared"
169 default:
170 return "unknown"
171 }
172 }
173
174 func executeOneGetRdmaNetnsMode(data []byte) (string, error) {
175 reader := bytes.NewReader(data)
176 for reader.Len() >= 4 {
177 _, attrType, len, value := parseNfAttrTLV(reader)
178
179 switch attrType {
180 case nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE:
181 var mode uint8
182 r := bytes.NewReader(value)
183 binary.Read(r, nl.NativeEndian(), &mode)
184 return netnsModeToString(mode), nil
185 }
186 if (len % 4) != 0 {
187
188 reader.Seek(int64(4-(len%4)), seekCurrent)
189 }
190 }
191 return "", fmt.Errorf("Invalid netns mode")
192 }
193
194
195
196
197
198 func RdmaSystemGetNetnsMode() (string, error) {
199 return pkgHandle.RdmaSystemGetNetnsMode()
200 }
201
202
203
204
205
206 func (h *Handle) RdmaSystemGetNetnsMode() (string, error) {
207
208 proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_GET)
209 req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
210
211 msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
212 if err != nil {
213 return "", err
214 }
215 if len(msgs) == 0 {
216 return "", fmt.Errorf("No valid response from kernel")
217 }
218 return executeOneGetRdmaNetnsMode(msgs[0])
219 }
220
221 func netnsModeStringToUint8(mode string) (uint8, error) {
222 switch mode {
223 case "exclusive":
224 return 0, nil
225 case "shared":
226 return 1, nil
227 default:
228 return 0, fmt.Errorf("Invalid mode; %q", mode)
229 }
230 }
231
232
233
234
235 func RdmaSystemSetNetnsMode(NewMode string) error {
236 return pkgHandle.RdmaSystemSetNetnsMode(NewMode)
237 }
238
239
240
241
242 func (h *Handle) RdmaSystemSetNetnsMode(NewMode string) error {
243 value, err := netnsModeStringToUint8(NewMode)
244 if err != nil {
245 return err
246 }
247
248 proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_SET)
249 req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
250
251 data := nl.NewRtAttr(nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE, []byte{value})
252 req.AddData(data)
253
254 _, err = req.Execute(unix.NETLINK_RDMA, 0)
255 return err
256 }
257
258
259
260
261 func RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
262 return pkgHandle.RdmaLinkSetNsFd(link, fd)
263 }
264
265
266
267
268 func (h *Handle) RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
269 proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
270 req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
271
272 data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX,
273 nl.Uint32Attr(link.Attrs.Index))
274 req.AddData(data)
275
276 data = nl.NewRtAttr(nl.RDMA_NLDEV_NET_NS_FD, nl.Uint32Attr(fd))
277 req.AddData(data)
278
279 return execRdmaSetLink(req)
280 }
281
282
283
284
285
286 func RdmaLinkDel(name string) error {
287 return pkgHandle.RdmaLinkDel(name)
288 }
289
290
291 func (h *Handle) RdmaLinkDel(name string) error {
292 link, err := h.RdmaLinkByName(name)
293 if err != nil {
294 return err
295 }
296
297 proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_DELLINK)
298 req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
299
300 b := make([]byte, 4)
301 native.PutUint32(b, link.Attrs.Index)
302 req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b))
303
304 _, err = req.Execute(unix.NETLINK_RDMA, 0)
305 return err
306 }
307
308
309
310
311
312
313
314
315
316
317 func RdmaLinkAdd(linkName, linkType, netdev string) error {
318 return pkgHandle.RdmaLinkAdd(linkName, linkType, netdev)
319 }
320
321
322 func (h *Handle) RdmaLinkAdd(linkName string, linkType string, netdev string) error {
323 proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_NEWLINK)
324 req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
325
326 req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, nl.ZeroTerminated(linkName)))
327 req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_LINK_TYPE, nl.ZeroTerminated(linkType)))
328 req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_NDEV_NAME, nl.ZeroTerminated(netdev)))
329 _, err := req.Execute(unix.NETLINK_RDMA, 0)
330 return err
331 }
332
View as plain text