@@ -17,95 +17,106 @@ package encapsulation
1717import (
1818 "fmt"
1919 "net"
20- "sync"
21-
22- "github.com/vishvananda/netlink"
2320
21+ "github.com/cozystack/kilo/pkg/iproute"
2422 "github.com/cozystack/kilo/pkg/iptables"
2523)
2624
27- const ciliumDeviceName = "cilium_host"
25+ const ciliumHostIface = "cilium_host"
2826
2927type cilium struct {
3028 iface int
3129 strategy Strategy
32- ch chan netlink.LinkUpdate
33- done chan struct {}
34- // mu guards updates to the iface field.
35- mu sync.Mutex
3630}
3731
38- // NewCilium returns an encapsulator that uses Cilium.
32+ // NewCilium returns an encapsulator that uses IPIP tunnels
33+ // routed through Cilium's VxLAN overlay.
3934func NewCilium (strategy Strategy ) Encapsulator {
40- return & cilium {
41- ch : make (chan netlink.LinkUpdate ),
42- done : make (chan struct {}),
43- strategy : strategy ,
44- }
35+ return & cilium {strategy : strategy }
4536}
4637
47- // CleanUp close done channel
48- func (f * cilium ) CleanUp () error {
49- close (f .done )
50- return nil
38+ // CleanUp will remove any created IPIP devices.
39+ func (c * cilium ) CleanUp () error {
40+ if err := iproute .DeleteAddresses (c .iface ); err != nil {
41+ return err
42+ }
43+ return iproute .RemoveInterface (c .iface )
5144}
5245
5346// Gw returns the correct gateway IP associated with the given node.
54- func (f * cilium ) Gw (_ , _ net.IP , subnet * net.IPNet ) net.IP {
47+ // It returns the Cilium internal IP so that the IPIP outer packets are routed
48+ // through Cilium's VxLAN overlay rather than the host network.
49+ func (c * cilium ) Gw (_ , _ , ciliumIP net.IP , subnet * net.IPNet ) net.IP {
50+ if ciliumIP != nil {
51+ return ciliumIP
52+ }
5553 return subnet .IP
5654}
5755
58- // Index returns the index of the Cilium interface.
59- func (f * cilium ) Index () int {
60- f .mu .Lock ()
61- defer f .mu .Unlock ()
62- return f .iface
63- }
64-
65- // Init finds the Cilium interface index.
66- func (f * cilium ) Init (_ int ) error {
67- if err := netlink .LinkSubscribe (f .ch , f .done ); err != nil {
68- return fmt .Errorf ("failed to subscribe to updates to %s: %v" , ciliumDeviceName , err )
69- }
70- go func () {
71- var lu netlink.LinkUpdate
72- for {
73- select {
74- case lu = <- f .ch :
75- if lu .Attrs ().Name == ciliumDeviceName {
76- f .mu .Lock ()
77- f .iface = lu .Attrs ().Index
78- f .mu .Unlock ()
79- }
80- case <- f .done :
81- return
82- }
83- }
84- }()
85- i , err := netlink .LinkByName (ciliumDeviceName )
86- if _ , ok := err .(netlink.LinkNotFoundError ); ok {
56+ // LocalIP returns the IP address of the cilium_host interface.
57+ // This IP is advertised to other nodes so they can route IPIP outer
58+ // packets through Cilium's overlay.
59+ func (c * cilium ) LocalIP () net.IP {
60+ iface , err := net .InterfaceByName (ciliumHostIface )
61+ if err != nil {
8762 return nil
8863 }
64+ addrs , err := iface .Addrs ()
8965 if err != nil {
90- return fmt .Errorf ("failed to query for Cilium interface: %v" , err )
66+ return nil
67+ }
68+ for _ , a := range addrs {
69+ if ipNet , ok := a .(* net.IPNet ); ok && ipNet .IP .To4 () != nil {
70+ return ipNet .IP
71+ }
9172 }
92- f .mu .Lock ()
93- f .iface = i .Attrs ().Index
94- f .mu .Unlock ()
9573 return nil
9674}
9775
98- // Rules is a no-op .
99- func (f * cilium ) Rules ( _ [] * net. IPNet ) iptables. RuleSet {
100- return iptables. RuleSet {}
76+ // Index returns the index of the IPIP tunnel interface .
77+ func (c * cilium ) Index () int {
78+ return c . iface
10179}
10280
103- // Set is a no-op.
104- func (f * cilium ) Set (_ * net.IPNet ) error {
81+ // Init initializes the IPIP tunnel interface.
82+ func (c * cilium ) Init (base int ) error {
83+ iface , err := iproute .NewIPIP (base )
84+ if err != nil {
85+ return fmt .Errorf ("failed to create tunnel interface: %v" , err )
86+ }
87+ if err := iproute .Set (iface , true ); err != nil {
88+ return fmt .Errorf ("failed to set tunnel interface up: %v" , err )
89+ }
90+ c .iface = iface
10591 return nil
10692}
10793
94+ // Rules returns a set of iptables rules that are necessary
95+ // when traffic between nodes must be encapsulated.
96+ func (c * cilium ) Rules (nodes []* net.IPNet ) iptables.RuleSet {
97+ rules := iptables.RuleSet {}
98+ proto := ipipProtocolName ()
99+ rules .AddToAppend (iptables .NewIPv4Chain ("filter" , "KILO-IPIP" ))
100+ rules .AddToAppend (iptables .NewIPv6Chain ("filter" , "KILO-IPIP" ))
101+ rules .AddToAppend (iptables .NewIPv4Rule ("filter" , "INPUT" , "-p" , proto , "-m" , "comment" , "--comment" , "Kilo: jump to IPIP chain" , "-j" , "KILO-IPIP" ))
102+ rules .AddToAppend (iptables .NewIPv6Rule ("filter" , "INPUT" , "-p" , proto , "-m" , "comment" , "--comment" , "Kilo: jump to IPIP chain" , "-j" , "KILO-IPIP" ))
103+ for _ , n := range nodes {
104+ // Accept encapsulated traffic from peers.
105+ rules .AddToPrepend (iptables .NewRule (iptables .GetProtocol (n .IP ), "filter" , "KILO-IPIP" , "-s" , n .String (), "-m" , "comment" , "--comment" , "Kilo: allow IPIP traffic" , "-j" , "ACCEPT" ))
106+ }
107+ // Drop all other IPIP traffic.
108+ rules .AddToAppend (iptables .NewIPv4Rule ("filter" , "INPUT" , "-p" , proto , "-m" , "comment" , "--comment" , "Kilo: reject other IPIP traffic" , "-j" , "DROP" ))
109+ rules .AddToAppend (iptables .NewIPv6Rule ("filter" , "INPUT" , "-p" , proto , "-m" , "comment" , "--comment" , "Kilo: reject other IPIP traffic" , "-j" , "DROP" ))
110+
111+ return rules
112+ }
113+
114+ // Set sets the IP address of the IPIP tunnel interface.
115+ func (c * cilium ) Set (cidr * net.IPNet ) error {
116+ return iproute .SetAddress (c .iface , cidr )
117+ }
118+
108119// Strategy returns the configured strategy for encapsulation.
109- func (f * cilium ) Strategy () Strategy {
110- return f .strategy
120+ func (c * cilium ) Strategy () Strategy {
121+ return c .strategy
111122}
0 commit comments