/
kernel_linux.go
123 lines (99 loc) · 2.21 KB
/
kernel_linux.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package kernel
import (
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
"github.com/pkg/errors"
"github.com/vishvananda/netlink"
bnet "github.com/bio-routing/bio-rd/net"
)
const (
protoBio = 45
)
func (k *Kernel) init() error {
lk, err := newLinuxKernel()
if err != nil {
return errors.Wrap(err, "Unable to initialize linux kernel")
}
err = lk.init()
if err != nil {
return errors.Wrap(err, "Init failed")
}
k.osKernel = lk
return nil
}
type linuxKernel struct {
h *netlink.Handle
routes map[*bnet.Prefix]struct{}
}
func newLinuxKernel() (*linuxKernel, error) {
h, err := netlink.NewHandle()
if err != nil {
return nil, errors.Wrap(err, "Unable to get Netlink handle")
}
return &linuxKernel{
h: h,
routes: make(map[*bnet.Prefix]struct{}),
}, nil
}
func (lk *linuxKernel) init() error {
err := lk.cleanup()
if err != nil {
return errors.Wrap(err, "Cleanup failed")
}
return nil
}
func (lk *linuxKernel) uninit() error {
return lk.cleanup()
}
func (lk *linuxKernel) cleanup() error {
filter := &netlink.Route{
Protocol: protoBio,
}
routes, err := lk.h.RouteListFiltered(0, filter, netlink.RT_FILTER_PROTOCOL)
if err != nil {
return errors.Wrap(err, "Unable to get routes")
}
for i := range routes {
err = lk.h.RouteDel(&routes[i])
if err != nil {
return errors.Wrap(err, "Unable to remove route")
}
}
return nil
}
func (lk *linuxKernel) AddPath(pfx *net.Prefix, path *route.Path) error {
r := &netlink.Route{
Protocol: protoBio,
Dst: pfx.GetIPNet(),
Gw: path.NextHop().ToNetIP(),
}
if _, found := lk.routes[pfx]; !found {
err := lk.h.RouteAdd(r)
if err != nil {
return errors.Wrap(err, "Unable to add route")
}
lk.routes[pfx] = struct{}{}
return nil
}
err := lk.h.RouteReplace(r)
if err != nil {
return errors.Wrap(err, "Unable to replace route")
}
return nil
}
func (lk *linuxKernel) RemovePath(pfx *net.Prefix, path *route.Path) bool {
if _, found := lk.routes[pfx]; !found {
return false
}
r := &netlink.Route{
Protocol: protoBio,
Dst: pfx.GetIPNet(),
Gw: path.NextHop().ToNetIP(),
}
err := lk.h.RouteDel(r)
if err != nil {
return false
}
delete(lk.routes, pfx)
return true
}