-
Notifications
You must be signed in to change notification settings - Fork 3
/
device.go
91 lines (78 loc) · 1.78 KB
/
device.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package ra
import (
"context"
"net"
"github.com/vishvananda/netlink"
)
type deviceState struct {
isUp bool
v6LLAddrAssigned bool
addr net.HardwareAddr
}
type deviceWatcher interface {
watch(ctx context.Context, name string) (<-chan deviceState, error)
}
type netlinkDeviceWatcher struct{}
var _ deviceWatcher = &netlinkDeviceWatcher{}
func newDeviceWatcher() deviceWatcher {
return &netlinkDeviceWatcher{}
}
func (w *netlinkDeviceWatcher) watch(ctx context.Context, name string) (<-chan deviceState, error) {
linkCh := make(chan netlink.LinkUpdate)
addrCh := make(chan netlink.AddrUpdate)
if err := netlink.LinkSubscribeWithOptions(
linkCh,
ctx.Done(),
netlink.LinkSubscribeOptions{
ErrorCallback: func(err error) {},
ListExisting: true,
},
); err != nil {
return nil, err
}
if err := netlink.AddrSubscribeWithOptions(
addrCh,
ctx.Done(),
netlink.AddrSubscribeOptions{
ErrorCallback: func(err error) {},
ListExisting: true,
},
); err != nil {
return nil, err
}
devCh := make(chan deviceState)
go func() {
currentState := deviceState{}
for {
select {
case <-ctx.Done():
return
case link := <-linkCh:
if link.Attrs().Name != name {
continue
}
currentState.isUp = link.Flags&uint32(net.FlagUp) != 0
currentState.addr = link.Attrs().HardwareAddr
devCh <- currentState
case addr := <-addrCh:
iface, err := net.InterfaceByIndex(addr.LinkIndex)
if err != nil {
continue
}
if iface.Name != name {
continue
}
if !addr.LinkAddress.IP.IsLinkLocalUnicast() {
continue
}
if addr.NewAddr {
currentState.v6LLAddrAssigned = true
} else {
currentState.v6LLAddrAssigned = false
}
devCh <- currentState
}
}
}()
return devCh, nil
}