1 package netlink
2
3 import (
4 "fmt"
5 "net"
6 "syscall"
7 "unsafe"
8
9 "github.com/vishvananda/netlink/nl"
10 "github.com/vishvananda/netns"
11 "golang.org/x/sys/unix"
12 )
13
14 const (
15 NDA_UNSPEC = iota
16 NDA_DST
17 NDA_LLADDR
18 NDA_CACHEINFO
19 NDA_PROBES
20 NDA_VLAN
21 NDA_PORT
22 NDA_VNI
23 NDA_IFINDEX
24 NDA_MASTER
25 NDA_LINK_NETNSID
26 NDA_SRC_VNI
27 NDA_PROTOCOL
28 NDA_NH_ID
29 NDA_FDB_EXT_ATTRS
30 NDA_FLAGS_EXT
31 NDA_MAX = NDA_FLAGS_EXT
32 )
33
34
35 const (
36 NUD_NONE = 0x00
37 NUD_INCOMPLETE = 0x01
38 NUD_REACHABLE = 0x02
39 NUD_STALE = 0x04
40 NUD_DELAY = 0x08
41 NUD_PROBE = 0x10
42 NUD_FAILED = 0x20
43 NUD_NOARP = 0x40
44 NUD_PERMANENT = 0x80
45 )
46
47
48 const (
49 NTF_USE = 0x01
50 NTF_SELF = 0x02
51 NTF_MASTER = 0x04
52 NTF_PROXY = 0x08
53 NTF_EXT_LEARNED = 0x10
54 NTF_OFFLOADED = 0x20
55 NTF_STICKY = 0x40
56 NTF_ROUTER = 0x80
57 )
58
59
60 const (
61 NTF_EXT_MANAGED = 0x00000001
62 )
63
64
65 type Ndmsg struct {
66 Family uint8
67 Index uint32
68 State uint16
69 Flags uint8
70 Type uint8
71 }
72
73 func deserializeNdmsg(b []byte) *Ndmsg {
74 var dummy Ndmsg
75 return (*Ndmsg)(unsafe.Pointer(&b[0:unsafe.Sizeof(dummy)][0]))
76 }
77
78 func (msg *Ndmsg) Serialize() []byte {
79 return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:]
80 }
81
82 func (msg *Ndmsg) Len() int {
83 return int(unsafe.Sizeof(*msg))
84 }
85
86
87
88 func NeighAdd(neigh *Neigh) error {
89 return pkgHandle.NeighAdd(neigh)
90 }
91
92
93
94 func (h *Handle) NeighAdd(neigh *Neigh) error {
95 return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
96 }
97
98
99
100 func NeighSet(neigh *Neigh) error {
101 return pkgHandle.NeighSet(neigh)
102 }
103
104
105
106 func (h *Handle) NeighSet(neigh *Neigh) error {
107 return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_REPLACE)
108 }
109
110
111
112 func NeighAppend(neigh *Neigh) error {
113 return pkgHandle.NeighAppend(neigh)
114 }
115
116
117
118 func (h *Handle) NeighAppend(neigh *Neigh) error {
119 return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_APPEND)
120 }
121
122
123
124 func neighAdd(neigh *Neigh, mode int) error {
125 return pkgHandle.neighAdd(neigh, mode)
126 }
127
128
129
130 func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
131 req := h.newNetlinkRequest(unix.RTM_NEWNEIGH, mode|unix.NLM_F_ACK)
132 return neighHandle(neigh, req)
133 }
134
135
136
137 func NeighDel(neigh *Neigh) error {
138 return pkgHandle.NeighDel(neigh)
139 }
140
141
142
143 func (h *Handle) NeighDel(neigh *Neigh) error {
144 req := h.newNetlinkRequest(unix.RTM_DELNEIGH, unix.NLM_F_ACK)
145 return neighHandle(neigh, req)
146 }
147
148 func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
149 var family int
150
151 if neigh.Family > 0 {
152 family = neigh.Family
153 } else {
154 family = nl.GetIPFamily(neigh.IP)
155 }
156
157 msg := Ndmsg{
158 Family: uint8(family),
159 Index: uint32(neigh.LinkIndex),
160 State: uint16(neigh.State),
161 Type: uint8(neigh.Type),
162 Flags: uint8(neigh.Flags),
163 }
164 req.AddData(&msg)
165
166 ipData := neigh.IP.To4()
167 if ipData == nil {
168 ipData = neigh.IP.To16()
169 }
170
171 dstData := nl.NewRtAttr(NDA_DST, ipData)
172 req.AddData(dstData)
173
174 if neigh.LLIPAddr != nil {
175 llIPData := nl.NewRtAttr(NDA_LLADDR, neigh.LLIPAddr.To4())
176 req.AddData(llIPData)
177 } else if neigh.HardwareAddr != nil {
178 hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
179 req.AddData(hwData)
180 }
181
182 if neigh.FlagsExt != 0 {
183 flagsExtData := nl.NewRtAttr(NDA_FLAGS_EXT, nl.Uint32Attr(uint32(neigh.FlagsExt)))
184 req.AddData(flagsExtData)
185 }
186
187 if neigh.Vlan != 0 {
188 vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
189 req.AddData(vlanData)
190 }
191
192 if neigh.VNI != 0 {
193 vniData := nl.NewRtAttr(NDA_VNI, nl.Uint32Attr(uint32(neigh.VNI)))
194 req.AddData(vniData)
195 }
196
197 if neigh.MasterIndex != 0 {
198 masterData := nl.NewRtAttr(NDA_MASTER, nl.Uint32Attr(uint32(neigh.MasterIndex)))
199 req.AddData(masterData)
200 }
201
202 _, err := req.Execute(unix.NETLINK_ROUTE, 0)
203 return err
204 }
205
206
207
208
209 func NeighList(linkIndex, family int) ([]Neigh, error) {
210 return pkgHandle.NeighList(linkIndex, family)
211 }
212
213
214
215
216 func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
217 return pkgHandle.NeighProxyList(linkIndex, family)
218 }
219
220
221
222
223 func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
224 return h.NeighListExecute(Ndmsg{
225 Family: uint8(family),
226 Index: uint32(linkIndex),
227 })
228 }
229
230
231
232
233 func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
234 return h.NeighListExecute(Ndmsg{
235 Family: uint8(family),
236 Index: uint32(linkIndex),
237 Flags: NTF_PROXY,
238 })
239 }
240
241
242 func NeighListExecute(msg Ndmsg) ([]Neigh, error) {
243 return pkgHandle.NeighListExecute(msg)
244 }
245
246
247 func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
248 req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
249 req.AddData(&msg)
250
251 msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
252 if err != nil {
253 return nil, err
254 }
255
256 var res []Neigh
257 for _, m := range msgs {
258 ndm := deserializeNdmsg(m)
259 if msg.Index != 0 && ndm.Index != msg.Index {
260
261 continue
262 }
263 if msg.Family != 0 && ndm.Family != msg.Family {
264 continue
265 }
266 if msg.State != 0 && ndm.State != msg.State {
267 continue
268 }
269 if msg.Type != 0 && ndm.Type != msg.Type {
270 continue
271 }
272 if msg.Flags != 0 && ndm.Flags != msg.Flags {
273 continue
274 }
275
276 neigh, err := NeighDeserialize(m)
277 if err != nil {
278 continue
279 }
280
281 res = append(res, *neigh)
282 }
283
284 return res, nil
285 }
286
287 func NeighDeserialize(m []byte) (*Neigh, error) {
288 msg := deserializeNdmsg(m)
289
290 neigh := Neigh{
291 LinkIndex: int(msg.Index),
292 Family: int(msg.Family),
293 State: int(msg.State),
294 Type: int(msg.Type),
295 Flags: int(msg.Flags),
296 }
297
298 attrs, err := nl.ParseRouteAttr(m[msg.Len():])
299 if err != nil {
300 return nil, err
301 }
302
303 for _, attr := range attrs {
304 switch attr.Attr.Type {
305 case NDA_DST:
306 neigh.IP = net.IP(attr.Value)
307 case NDA_LLADDR:
308
309
310
311 attrLen := attr.Attr.Len - unix.SizeofRtAttr
312 if attrLen == 4 {
313 neigh.LLIPAddr = net.IP(attr.Value)
314 } else if attrLen == 16 {
315
316 link, err := LinkByIndex(neigh.LinkIndex)
317 if err == nil && link.Attrs().EncapType == "tunnel6" {
318 neigh.IP = net.IP(attr.Value)
319 } else {
320 neigh.HardwareAddr = net.HardwareAddr(attr.Value)
321 }
322 } else {
323 neigh.HardwareAddr = net.HardwareAddr(attr.Value)
324 }
325 case NDA_FLAGS_EXT:
326 neigh.FlagsExt = int(native.Uint32(attr.Value[0:4]))
327 case NDA_VLAN:
328 neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
329 case NDA_VNI:
330 neigh.VNI = int(native.Uint32(attr.Value[0:4]))
331 case NDA_MASTER:
332 neigh.MasterIndex = int(native.Uint32(attr.Value[0:4]))
333 }
334 }
335
336 return &neigh, nil
337 }
338
339
340
341 func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error {
342 return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil, false)
343 }
344
345
346
347 func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error {
348 return neighSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil, false)
349 }
350
351
352
353 type NeighSubscribeOptions struct {
354 Namespace *netns.NsHandle
355 ErrorCallback func(error)
356 ListExisting bool
357
358
359 ReceiveBufferSize int
360 ReceiveBufferForceSize bool
361 ReceiveTimeout *unix.Timeval
362 }
363
364
365
366
367 func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
368 if options.Namespace == nil {
369 none := netns.None()
370 options.Namespace = &none
371 }
372 return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting,
373 options.ReceiveBufferSize, options.ReceiveTimeout, options.ReceiveBufferForceSize)
374 }
375
376 func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool,
377 rcvbuf int, rcvTimeout *unix.Timeval, rcvbufForce bool) error {
378 s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
379 makeRequest := func(family int) error {
380 req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
381 ndmsg := &Ndmsg{Family: uint8(family)}
382 req.AddData(ndmsg)
383 if err := s.Send(req); err != nil {
384 return err
385 }
386 return nil
387 }
388 if err != nil {
389 return err
390 }
391 if rcvTimeout != nil {
392 if err := s.SetReceiveTimeout(rcvTimeout); err != nil {
393 return err
394 }
395 }
396 if rcvbuf != 0 {
397 err = s.SetReceiveBufferSize(rcvbuf, rcvbufForce)
398 if err != nil {
399 return err
400 }
401 }
402 if done != nil {
403 go func() {
404 <-done
405 s.Close()
406 }()
407 }
408 if listExisting {
409 if err := makeRequest(unix.AF_UNSPEC); err != nil {
410 return err
411 }
412
413 }
414 go func() {
415 defer close(ch)
416 for {
417 msgs, from, err := s.Receive()
418 if err != nil {
419 if cberr != nil {
420 cberr(err)
421 }
422 return
423 }
424 if from.Pid != nl.PidKernel {
425 if cberr != nil {
426 cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
427 }
428 continue
429 }
430 for _, m := range msgs {
431 if m.Header.Type == unix.NLMSG_DONE {
432 if listExisting {
433
434
435
436 if err := makeRequest(unix.AF_BRIDGE); err != nil {
437 if cberr != nil {
438 cberr(err)
439 }
440 return
441 }
442 listExisting = false
443 }
444 continue
445 }
446 if m.Header.Type == unix.NLMSG_ERROR {
447 nError := int32(native.Uint32(m.Data[0:4]))
448 if nError == 0 {
449 continue
450 }
451 if cberr != nil {
452 cberr(syscall.Errno(-nError))
453 }
454 return
455 }
456 neigh, err := NeighDeserialize(m.Data)
457 if err != nil {
458 if cberr != nil {
459 cberr(err)
460 }
461 return
462 }
463 ch <- NeighUpdate{Type: m.Header.Type, Neigh: *neigh}
464 }
465 }
466 }()
467
468 return nil
469 }
470
View as plain text