forked from squat/kilo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcilium.go
More file actions
145 lines (129 loc) · 4.82 KB
/
cilium.go
File metadata and controls
145 lines (129 loc) · 4.82 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2019 the Kilo authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package encapsulation
import (
"fmt"
"net"
"github.com/vishvananda/netlink"
"github.com/cozystack/kilo/pkg/iproute"
"github.com/cozystack/kilo/pkg/iptables"
)
const (
ciliumHostIface = "cilium_host"
// ciliumTunlIface is the kernel's default IPIP tunnel (tunl0) renamed
// by Cilium when enable-ipip-termination is active. Unlike cilium_ipip4,
// which is receive-only (for DSR), cilium_tunl supports both TX and RX.
ciliumTunlIface = "cilium_tunl"
)
type cilium struct {
iface int
strategy Strategy
ownsTunnel bool
}
// NewCilium returns an encapsulator that uses IPIP tunnels
// routed through Cilium's VxLAN overlay.
func NewCilium(strategy Strategy) Encapsulator {
return &cilium{strategy: strategy}
}
// CleanUp will remove any created IPIP devices.
// If the tunnel is owned by Cilium, skip removal.
func (c *cilium) CleanUp() error {
if !c.ownsTunnel {
return nil
}
if err := iproute.DeleteAddresses(c.iface); err != nil {
return err
}
return iproute.RemoveInterface(c.iface)
}
// Gw returns the correct gateway IP associated with the given node.
// It returns the Cilium internal IP so that the IPIP outer packets are routed
// through Cilium's VxLAN overlay rather than the host network.
func (c *cilium) Gw(_, _, ciliumIP net.IP, subnet *net.IPNet) net.IP {
if ciliumIP != nil {
return ciliumIP
}
return subnet.IP
}
// LocalIP returns the IP address of the cilium_host interface.
// This IP is advertised to other nodes so they can route IPIP outer
// packets through Cilium's overlay.
func (c *cilium) LocalIP() net.IP {
iface, err := net.InterfaceByName(ciliumHostIface)
if err != nil {
return nil
}
addrs, err := iface.Addrs()
if err != nil {
return nil
}
for _, a := range addrs {
if ipNet, ok := a.(*net.IPNet); ok && ipNet.IP.To4() != nil {
return ipNet.IP
}
}
return nil
}
// Index returns the index of the IPIP tunnel interface.
func (c *cilium) Index() int {
return c.iface
}
// Init initializes the IPIP tunnel interface.
// When Cilium's enable-ipip-termination is active, it renames the kernel's
// tunl0 to cilium_tunl and creates a receive-only cilium_ipip4 device.
// We use cilium_tunl because it supports both sending and receiving IPIP
// traffic, whereas cilium_ipip4 only handles incoming packets (DSR).
func (c *cilium) Init(base int) error {
if link, err := netlink.LinkByName(ciliumTunlIface); err == nil {
c.iface = link.Attrs().Index
c.ownsTunnel = false
return nil
}
iface, err := iproute.NewIPIPWithName(base, ciliumTunlIface)
if err != nil {
return fmt.Errorf("failed to create tunnel interface: %v", err)
}
if err := iproute.Set(iface, true); err != nil {
return fmt.Errorf("failed to set tunnel interface up: %v", err)
}
c.iface = iface
c.ownsTunnel = true
return nil
}
// Rules returns a set of iptables rules that are necessary
// when traffic between nodes must be encapsulated.
func (c *cilium) Rules(nodes []*net.IPNet) iptables.RuleSet {
rules := iptables.RuleSet{}
proto := ipipProtocolName()
rules.AddToAppend(iptables.NewIPv4Chain("filter", "KILO-IPIP"))
rules.AddToAppend(iptables.NewIPv6Chain("filter", "KILO-IPIP"))
rules.AddToAppend(iptables.NewIPv4Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: jump to IPIP chain", "-j", "KILO-IPIP"))
rules.AddToAppend(iptables.NewIPv6Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: jump to IPIP chain", "-j", "KILO-IPIP"))
for _, n := range nodes {
// Accept encapsulated traffic from peers.
rules.AddToPrepend(iptables.NewRule(iptables.GetProtocol(n.IP), "filter", "KILO-IPIP", "-s", n.String(), "-m", "comment", "--comment", "Kilo: allow IPIP traffic", "-j", "ACCEPT"))
}
// Drop all other IPIP traffic.
rules.AddToAppend(iptables.NewIPv4Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: reject other IPIP traffic", "-j", "DROP"))
rules.AddToAppend(iptables.NewIPv6Rule("filter", "INPUT", "-p", proto, "-m", "comment", "--comment", "Kilo: reject other IPIP traffic", "-j", "DROP"))
return rules
}
// Set sets the IP address of the IPIP tunnel interface.
func (c *cilium) Set(cidr *net.IPNet) error {
return iproute.SetAddress(c.iface, cidr)
}
// Strategy returns the configured strategy for encapsulation.
func (c *cilium) Strategy() Strategy {
return c.strategy
}