Skip to content

Commit

Permalink
Gateway: react to liqo.host mac address changes
Browse files Browse the repository at this point in the history
  • Loading branch information
giorio94 authored and adamjensenbot committed Jun 10, 2022
1 parent 45d492b commit 42d2cb4
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 13 deletions.
21 changes: 17 additions & 4 deletions internal/liqonet/tunnel-operator/tunnel-operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,6 @@ func (tc *TunnelController) SetUpRouteManager() error {
}

func (tc *TunnelController) setUpGWNetns(hostVethName, gatewayVethName string, vethMtu int) error {
var err error

// Create veth pair to connect the two namespaces.
hostVeth, gatewayVeth, err := liqonetns.CreateVethPair(hostVethName, gatewayVethName, tc.hostNetns, tc.gatewayNetns, vethMtu)
if err != nil {
Expand All @@ -444,12 +442,27 @@ func (tc *TunnelController) setUpGWNetns(hostVethName, gatewayVethName string, v
tc.gatewayVeth = gatewayVeth

// Configure hostveth.
if err = liqonetns.ConfigureVeth(&hostVeth, liqoconst.GatewayVethIPAddr, gatewayVeth.HardwareAddr, tc.hostNetns); err != nil {
if err = liqonetns.ConfigureVeth(&hostVeth, liqoconst.GatewayVethIPAddr, tc.hostNetns); err != nil {
return err
}

// Configure gatewayveth.
return liqonetns.ConfigureVeth(&gatewayVeth, liqoconst.HostVethIPAddr, hostVeth.HardwareAddr, tc.gatewayNetns)
if err = liqonetns.ConfigureVeth(&gatewayVeth, liqoconst.HostVethIPAddr, tc.gatewayNetns); err != nil {
return err
}

// Configure the static neighbor entries, and subscribe to the events to perform updates in case the veth MAC address changes.
return liqonetns.RegisterOnVethHwAddrChangeHandler(tc.hostNetns, hostVethName, func(hwaddr net.HardwareAddr) error {
if err := liqonetns.ConfigureVethNeigh(&hostVeth, liqoconst.GatewayVethIPAddr, gatewayVeth.HardwareAddr, tc.hostNetns); err != nil {
return err
}

if err := liqonetns.ConfigureVethNeigh(&gatewayVeth, liqoconst.HostVethIPAddr, hwaddr, tc.gatewayNetns); err != nil {
return err
}

return nil
})
}

func (tc *TunnelController) updateStatus(con *netv1alpha1.Connection, tep *netv1alpha1.TunnelEndpoint) error {
Expand Down
76 changes: 67 additions & 9 deletions pkg/liqonet/netns/veth.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
package netns

import (
"context"
"fmt"
"net"
"time"

"github.com/containernetworking/plugins/pkg/ip"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
Expand Down Expand Up @@ -81,7 +83,7 @@ func CreateVethPair(hostVethName, gatewayVethName string, hostNetns, gatewayNetn

// ConfigureVeth configures the veth interface passed as argument. If the veth interface is the one
// living the gateway netns then additional actions are carried out.
func ConfigureVeth(veth *net.Interface, gatewayIP string, gatewayMAC net.HardwareAddr, netNS ns.NetNS) error {
func ConfigureVeth(veth *net.Interface, gatewayIP string, netNS ns.NetNS) error {
var defaultCIDR = "0.0.0.0/0"

gwIP := net.ParseIP(gatewayIP)
Expand Down Expand Up @@ -115,14 +117,6 @@ func ConfigureVeth(veth *net.Interface, gatewayIP string, gatewayMAC net.Hardwar
klog.V(5).Infof("route for ip {%s} correctly configured on device {%s} with index {%d}",
gatewayIP, veth.Name, veth.Index)

// Add static/permanent neighbor entry for the gateway IP address.
if _, err := AddNeigh(gwIP, gatewayMAC, veth); err != nil {
return fmt.Errorf("unable to add neighbor entry for ip {%s} and MAC {%s} on device {%s} with index {%d}",
gatewayIP, gatewayMAC.String(), veth.Name, veth.Index)
}
klog.V(5).Infof("neighbor entry for ip {%s} and MAC {%s} correctly configured on device {%s} with index {%d}",
gatewayIP, gatewayMAC.String(), veth.Name, veth.Index)

// The following configuration is done only for the veth pair living in the gateway network namespace.
if veth.Name == liqoconst.GatewayVethName {
// Add default route to use the veth interface.
Expand All @@ -147,3 +141,67 @@ func ConfigureVeth(veth *net.Interface, gatewayIP string, gatewayMAC net.Hardwar

return netNS.Do(configuration)
}

// ConfigureVethNeigh configures an entry in the ARP table, according to the specified parameters.
func ConfigureVethNeigh(veth *net.Interface, gatewayIP string, gatewayMAC net.HardwareAddr, netNS ns.NetNS) error {
gwIP := net.ParseIP(gatewayIP)
if gwIP == nil {
return &liqoneterrors.ParseIPError{IPToBeParsed: gatewayIP}
}

return netNS.Do(func(nn ns.NetNS) error {
// Add static/permanent neighbor entry for the gateway IP address.
if _, err := AddNeigh(gwIP, gatewayMAC, veth); err != nil {
return fmt.Errorf("unable to add neighbor entry for ip {%s} and MAC {%s} on device {%s} with index {%d} in ns {%s}: %w",
gatewayIP, gatewayMAC.String(), veth.Name, veth.Index, nn.Path(), err)
}

klog.V(5).Infof("neighbor entry for ip {%s} and MAC {%s} correctly configured on device {%s} with index {%d}",
gatewayIP, gatewayMAC.String(), veth.Name, veth.Index)

return nil
})
}

// RegisterOnVethHwAddrChangeHandler registers a handler to be executed whenever an attribute of the given veth interface changes.
// The handler is always executed once upon registration.
func RegisterOnVethHwAddrChangeHandler(namespace ns.NetNS, vethName string, handler func(net.HardwareAddr) error) error {
updates := make(chan netlink.LinkUpdate)

if err := netlink.LinkSubscribeAt(netns.NsHandle(namespace.Fd()), updates, context.Background().Done()); err != nil {
return err
}

// Immediately execute the handler, retrieving the updated value for the MAC address. This also ensures that the update is performed
// once in the main thread, returning an appropriate error in case it fails.
// Since we already subscribed to events, we can be sure that the handler will be executed again in case of further changes.
veth, err := netlink.LinkByName(vethName)
if err != nil {
return fmt.Errorf("unable to retrieve veth interface {%s} in namespace {%s}: %w", vethName, namespace.Path(), err)
}

if err := handler(veth.Attrs().HardwareAddr); err != nil {
return err
}

go func() {
for {
update := <-updates
if update.Attrs().Name != vethName || (update.Attrs().Flags&net.FlagUp) == 0 {
// Skip updates related to other interfaces, or in case it is down.
continue
}

klog.V(5).Infof("received update for device {%s} with index {%d}, and hardware address {%s}",
update.Attrs().Name, update.Attrs().Index, update.Attrs().HardwareAddr)

if err := retry.OnError(retry.DefaultRetry, func(error) bool { return true },
func() error { return handler(update.Attrs().HardwareAddr) }); err != nil {
klog.Errorf("failed to handle MAC address change for veth {%s} with index {%d}: %v",
update.Attrs().Name, update.Attrs().Index, err)
}
}
}()

return nil
}

0 comments on commit 42d2cb4

Please sign in to comment.