Skip to content

Commit

Permalink
added vxlan operator which configures the vxlan interface on each node
Browse files Browse the repository at this point in the history
  • Loading branch information
alacuku committed Jun 15, 2021
1 parent 017d367 commit f84cb22
Show file tree
Hide file tree
Showing 8 changed files with 729 additions and 11 deletions.
6 changes: 6 additions & 0 deletions go.sum
Expand Up @@ -65,6 +65,7 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20200415212048-7901bc822317/go.mod h1:DF8FZRxMHMGv/vP2lQP6h+dYzzjpuRn24VeRiYn3qjQ=
Expand Down Expand Up @@ -250,6 +251,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
Expand Down Expand Up @@ -300,6 +302,7 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1 h1:yY9rWGoXv1U5pl4gxqlULARMQD7x0QG85lqEXTWysik=
github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
Expand Down Expand Up @@ -990,6 +993,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
Expand Down Expand Up @@ -1063,6 +1067,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -1436,6 +1441,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
inet.af/netaddr v0.0.0-20210313195008-843b4240e319 h1:cSGjHEjS/Nu6pts6yZfSYsRqcfW5ieqSrQI+XcZQObM=
inet.af/netaddr v0.0.0-20210313195008-843b4240e319/go.mod h1:I2i9ONCXRZDnG1+7O8fSuYzjcPxHQXrIfzD/IkR87x4=
Expand Down
3 changes: 3 additions & 0 deletions internal/liqonet/route-operator/doc.go
@@ -0,0 +1,3 @@
// Package routeoperator contains the needed k8s operators in order to configure each
// k8s node to send traffic to the gateway pod when destined to a remote cluster.
package routeoperator
227 changes: 227 additions & 0 deletions internal/liqonet/route-operator/overlayOperator.go
@@ -0,0 +1,227 @@
package routeoperator

import (
"context"
"net"

corev1 "k8s.io/api/core/v1"
k8sApiErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/klog"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/predicate"

liqoerrors "github.com/liqotech/liqo/pkg/liqonet/errors"
"github.com/liqotech/liqo/pkg/liqonet/overlay"
)

var (
// This labels are the ones set during the deployment of liqo using the helm chart.
// Any change to those labels on the helm chart has also to be reflected here.
podInstanceLabelKey = "app.kubernetes.io/instance"
podInstanceLabelValue = "liqo-route"
podNameLabelKey = "app.kubernetes.io/name"
podNameLabelValue = "route"
// vxlanMACAddressKey annotation key the mac address of vxlan interface.
vxlanMACAddressKey = "net.liqo.io/vxlan.mac.address"
// PodLabelSelector label selector used to track only the route pods.
PodLabelSelector = &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: podInstanceLabelKey,
Operator: metav1.LabelSelectorOpIn,
Values: []string{podInstanceLabelValue},
},
{
Key: podNameLabelKey,
Operator: metav1.LabelSelectorOpIn,
Values: []string{podNameLabelValue},
},
},
}
)

// OverlayController reconciles pods objects, in our case the route operators pods.
type OverlayController struct {
vxlanDev overlay.VxlanDevice
client.Client
podName string
podIP string
podSelector labels.Selector
vxlanPeers map[string]*overlay.Neighbor
}

// Reconcile for a given pod it checks if it is our pod or not. If it is our pod than annotates
// it with mac address of the current vxlan device. If it is a pod running in a different node
// then based on the type of event:
// event.Create/Update it adds the peer to the vxlan overlay network if it does not exist.
// event.Delete it removes the peer from the vxlan overlay network if it does exist.
func (ovc *OverlayController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
var pod corev1.Pod
var err error
err = ovc.Get(ctx, req.NamespacedName, &pod)
if err != nil && !k8sApiErrors.IsNotFound(err) {
klog.Errorf("an error occurred while getting pod %s: %v", req.NamespacedName, err)
return ctrl.Result{}, err
}
if k8sApiErrors.IsNotFound(err) {
// Remove the peer.
deleted, err := ovc.delPeer(req)
if err != nil {
return ctrl.Result{}, err
}
if deleted {
klog.Infof("successfully removed peer %s from vxlan overlay network", req.String())
}
return ctrl.Result{}, nil
}
// If it is our pod than add the mac address annotation.
if ovc.podIP == pod.Status.PodIP {
if ovc.addAnnotation(&pod, vxlanMACAddressKey, ovc.vxlanDev.Link.HardwareAddr.String()) {
if err := ovc.Update(ctx, &pod); err != nil {
klog.Errorf("an error occurred while adding mac address annotation to pod %s: %v", req.String(), err)
return ctrl.Result{}, err
}
klog.Infof("successfully annotated pod %s with mac address %s", req.String(), ovc.vxlanDev.Link.HardwareAddr.String())
}
return ctrl.Result{}, nil
}

// If it is not our pod, then add peer to the vxlan network.
added, err := ovc.addPeer(req, &pod)
if err != nil {
klog.Errorf("an error occurred while adding peer %s with IP address %s and MAC address %s to the vxlan overlay network: %v",
req.String(), pod.Status.PodIP, ovc.getAnnotationValue(&pod, vxlanMACAddressKey), err)
return ctrl.Result{}, err
}
if added {
klog.Errorf("successfully added peer %s with IP address %s and MAC address %s to the vxlan overlay network",
req.String(), pod.Status.PodIP, ovc.getAnnotationValue(&pod, vxlanMACAddressKey))
}
return ctrl.Result{}, nil
}

// NewOverlayController returns a new controller ready to be setup and started with the controller manager.
func NewOverlayController(podName, podIP string, podSelector *metav1.LabelSelector,
vxlanDevice overlay.VxlanDevice, cl client.Client) (*OverlayController, error) {
selector, err := metav1.LabelSelectorAsSelector(podSelector)
if err != nil {
return nil, err
}
if vxlanDevice.Link == nil {
return nil, &liqoerrors.WrongParameter{
Reason: liqoerrors.NotNil,
Parameter: "vxlanDevice.Link",
}
}
return &OverlayController{
vxlanDev: vxlanDevice,
Client: cl,
podName: podName,
podIP: podIP,
podSelector: selector,
vxlanPeers: make(map[string]*overlay.Neighbor),
}, nil
}

// addPeer for a given pod it adds the fdb entry for the current vxlan device.
// It return true when the entry does not exist and is added, false if the entry does already exist,
// and error if something goes wrong.
func (ovc *OverlayController) addPeer(req ctrl.Request, pod *corev1.Pod) (bool, error) {
peerIP := pod.Status.PodIP
peerMAC := pod.GetAnnotations()[vxlanMACAddressKey]
ip := net.ParseIP(peerIP)
if ip == nil {
return false, &liqoerrors.ParseIPError{IPToBeParsed: peerIP}
}
mac, err := net.ParseMAC(peerMAC)
if err != nil {
return false, err
}
peer := overlay.Neighbor{
MAC: mac,
IP: ip,
}

added, err := ovc.vxlanDev.AddFDB(peer)
if err != nil {
return added, err
}
ovc.vxlanPeers[req.String()] = &peer
return added, nil
}

// delPeer for a given pod it removes the fdb entry for the current vxlan device.
// It return true when the entry exists and is removed, false if the entry does not exist,
// and error if something goes wrong.
func (ovc *OverlayController) delPeer(req ctrl.Request) (bool, error) {
peer, ok := ovc.vxlanPeers[req.String()]
if !ok {
return false, nil
}
deleted, err := ovc.vxlanDev.DelFDB(*peer)
if err != nil {
return deleted, err
}
delete(ovc.vxlanPeers, req.String())
return deleted, nil
}

// addAnnotation for a given object it adds the annotation with the given key and value.
// It return a bool which is true when the annotations has been added or false if the
// annotation is already present.
func (ovc *OverlayController) addAnnotation(obj client.Object, aKey, aValue string) bool {
annotations := obj.GetAnnotations()
oldAnnValue, ok := annotations[aKey]
// If the annotations does not exist or is outdated then set it.
if !ok || oldAnnValue != aValue {
annotations[aKey] = aValue
obj.SetAnnotations(annotations)
return true
}
return false
}

// getAnnotationValue all objects passed to this function has the annotations set.
// The podFilter functions makes sure that we reconcile only objects with the annotation set.
func (ovc *OverlayController) getAnnotationValue(obj client.Object, akey string) string {
return obj.GetAnnotations()[akey]
}

// podFilter used to filter out all the pods that are not instances of the route operator
// daemon set. It checks that pods are route operator instances, and has the vxlanMACAddressKey
// annotation set or that the current pod we are considering is our same pod. In this case
// we add the vxlanMACAddressKey annotation in order for the other nodes to add as to the overlay network.
func (ovc *OverlayController) podFilter(obj client.Object) bool {
// Check if the object is a pod.
p, ok := obj.(*corev1.Pod)
if !ok {
klog.Infof("object %s is not of type corev1.Pod", obj.GetName())
return false
}
// Filter by labels.
if match := ovc.podSelector.Matches(labels.Set(obj.GetLabels())); !match {
return false
}
// If it is our pod then process it.
if ovc.podIP == p.Status.PodIP {
return true
}
// If it is not our pod then check if the vxlan mac address has been set.
annotations := obj.GetAnnotations()
if _, ok := annotations[vxlanMACAddressKey]; ok {
return true
}
klog.V(4).Infof("route-operator pod {%s} in namespace {%s} running on node {%s} does not have {%s} annotation set",
p.Name, p.Namespace, p.Spec.NodeName, vxlanMACAddressKey)
return false
}

// SetupWithManager used to set up the controller with a given manager.
func (ovc *OverlayController) SetupWithManager(mgr ctrl.Manager) error {
p := predicate.NewPredicateFuncs(ovc.podFilter)
return ctrl.NewControllerManagedBy(mgr).For(&corev1.Pod{}).WithEventFilter(p).
Complete(ovc)
}

0 comments on commit f84cb22

Please sign in to comment.