-
Notifications
You must be signed in to change notification settings - Fork 103
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added vxlan overlay network and test suite
- Loading branch information
Showing
3 changed files
with
446 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package overlay | ||
|
||
import ( | ||
"net" | ||
"testing" | ||
|
||
"github.com/vishvananda/netlink" | ||
|
||
"github.com/liqotech/liqo/pkg/liqonet" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var ( | ||
defaultIfaceIP net.IP | ||
) | ||
|
||
func TestOverlay(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "Overlay Suite") | ||
} | ||
|
||
var _ = BeforeSuite(func() { | ||
var err error | ||
defaultIfaceIP, err = getIFaceIP("0.0.0.0") | ||
Expect(err).ShouldNot(HaveOccurred()) | ||
Expect(defaultIfaceIP).ShouldNot(BeNil()) | ||
// Create dummy link | ||
err = netlink.LinkAdd(&netlink.Dummy{LinkAttrs: netlink.LinkAttrs{Name: "dummy-link"}}) | ||
Expect(err).ShouldNot(HaveOccurred()) | ||
}) | ||
|
||
/*var _ = AfterSuite(func() { | ||
})*/ | ||
|
||
func getIFaceIP(ipAddress string) (net.IP, error) { | ||
var ifaceIndex int | ||
// Convert the given IP address from string to net.IP format | ||
ip := net.ParseIP(ipAddress) | ||
if ip == nil { | ||
return nil, &liqonet.ParseIPError{ | ||
IPToBeParsed: ipAddress, | ||
} | ||
} | ||
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// Find the route whose destination contains our IP address. | ||
for i := range routes { | ||
if routes[i].Scope == netlink.SCOPE_UNIVERSE { | ||
ifaceIndex = routes[i].LinkIndex | ||
} | ||
} | ||
if ifaceIndex == 0 { | ||
return nil, &liqonet.NoRouteFound{IPAddress: ipAddress} | ||
} | ||
// Get link. | ||
link, err := netlink.LinkByIndex(ifaceIndex) | ||
if err != nil { | ||
return nil, err | ||
} | ||
ips, err := netlink.AddrList(link, netlink.FAMILY_V4) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return ips[0].IP, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package overlay | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"reflect" | ||
"syscall" | ||
|
||
"github.com/vishvananda/netlink" | ||
"golang.org/x/sys/unix" | ||
"k8s.io/klog/v2" | ||
) | ||
|
||
// VxlanDeviceAttrs configuration for a new vxlan device. | ||
type VxlanDeviceAttrs struct { | ||
Vni int | ||
Name string | ||
VtepPort int | ||
VtepAddr net.IP | ||
Mtu int | ||
} | ||
|
||
// VxlanDevice struct that holds a vxlan link. | ||
type VxlanDevice struct { | ||
Link *netlink.Vxlan | ||
} | ||
|
||
// Neighbor struct that holds information for an fdb entry. | ||
type Neighbor struct { | ||
MAC net.HardwareAddr | ||
IP net.IP | ||
} | ||
|
||
// NewVxlanDevice takes as argument a struct of type VxlanDeviceAttrs and returns a VxlanDevice or error. | ||
func NewVxlanDevice(devAttrs *VxlanDeviceAttrs) (*VxlanDevice, error) { | ||
link := &netlink.Vxlan{ | ||
LinkAttrs: netlink.LinkAttrs{ | ||
Name: devAttrs.Name, | ||
MTU: devAttrs.Mtu, | ||
Flags: net.FlagUp, | ||
}, | ||
VxlanId: devAttrs.Vni, | ||
SrcAddr: devAttrs.VtepAddr, | ||
Port: devAttrs.VtepPort, | ||
Learning: true, | ||
} | ||
|
||
link, err := createVxLanLink(link) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &VxlanDevice{ | ||
Link: link, | ||
}, nil | ||
} | ||
|
||
func createVxLanLink(link *netlink.Vxlan) (*netlink.Vxlan, error) { | ||
err := netlink.LinkAdd(link) | ||
if err == syscall.EEXIST { | ||
existing, err := netlink.LinkByName(link.Name) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to retrieve Link with name %s: %v", link.Name, err) | ||
} | ||
if isVxlanConfigTheSame(link, existing) { | ||
klog.V(4).Infof("vxlan device with the same configuration already exists") | ||
link = existing.(*netlink.Vxlan) | ||
return link, nil | ||
} | ||
// If we come here it means that the config of the existing vxlan device does not match with the new one. | ||
// We delete it and then recreate. | ||
if err = netlink.LinkDel(existing); err != nil { | ||
return nil, fmt.Errorf("failed to delete the existing vxlan device with name %s: %v", existing.Attrs().Name, err) | ||
} | ||
if err = netlink.LinkAdd(link); err != nil { | ||
return nil, fmt.Errorf("failed to re-create the vxlan interface: %v", err) | ||
} | ||
} else if err != nil { | ||
return nil, fmt.Errorf("failed to create the vxlan interface: %v", err) | ||
} | ||
ifindex := link.Index | ||
vxlan, err := netlink.LinkByIndex(ifindex) | ||
if err != nil { | ||
return nil, fmt.Errorf("can't locate created vxlan device with index %v, %v", ifindex, err) | ||
} | ||
return vxlan.(*netlink.Vxlan), nil | ||
} | ||
|
||
// If a vxlan exists with the same name then we use this function to check if the configuration is the same. | ||
func isVxlanConfigTheSame(new, current netlink.Link) bool { | ||
if new.Type() != current.Type() { | ||
klog.V(4).Infof("different types for the interfaces: new -> %v, current -> %v", new.Type(), current.Type()) | ||
return false | ||
} | ||
newNetlinkVxlan := new.(*netlink.Vxlan) | ||
currentNetlinkVxlan := current.(*netlink.Vxlan) | ||
|
||
if newNetlinkVxlan.VxlanId != currentNetlinkVxlan.VxlanId { | ||
klog.V(4).Infof("different vxlan ID for the interfaces: new -> %d, current -> %d", newNetlinkVxlan.VxlanId, currentNetlinkVxlan.VxlanId) | ||
return false | ||
} | ||
if !reflect.DeepEqual(newNetlinkVxlan.SrcAddr, currentNetlinkVxlan.SrcAddr) { | ||
klog.V(4).Infof("different Source Addresses for the interfaces: new -> %v, current -> %v", newNetlinkVxlan.SrcAddr, currentNetlinkVxlan.SrcAddr) | ||
return false | ||
} | ||
if newNetlinkVxlan.Port != currentNetlinkVxlan.Port { | ||
klog.V(4).Infof("different Vxlan Port for the interfaces: new -> %d, current -> %d", newNetlinkVxlan.Port, currentNetlinkVxlan.Port) | ||
return false | ||
} | ||
klog.V(4).Infof("the existing interface is already configured") | ||
return true | ||
} | ||
|
||
// AddFDB adds a fdb entry for the given neighbour into the current vxlan device. | ||
func (vxlan *VxlanDevice) AddFDB(n Neighbor) error { | ||
klog.V(4).Infof("calling AppendFDB: %v, %v", n.IP, n.MAC) | ||
err := netlink.NeighAdd(&netlink.Neigh{ | ||
LinkIndex: vxlan.Link.Index, | ||
State: netlink.NUD_PERMANENT | netlink.NUD_NOARP, | ||
Family: syscall.AF_BRIDGE, | ||
Flags: netlink.NTF_SELF, | ||
Type: netlink.NDA_DST, | ||
IP: n.IP, | ||
HardwareAddr: n.MAC, | ||
}) | ||
if err == unix.EEXIST { | ||
return nil | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// DelFDB deletes a fdb entry for the given neighbour from the current vxlan device. | ||
func (vxlan *VxlanDevice) DelFDB(n Neighbor) error { | ||
klog.V(4).Infof("calling DelFDB: %v, %v", n.IP, n.MAC) | ||
err := netlink.NeighDel(&netlink.Neigh{ | ||
LinkIndex: vxlan.Link.Index, | ||
State: netlink.NUD_PERMANENT | netlink.NUD_NOARP, | ||
Family: syscall.AF_BRIDGE, | ||
Flags: netlink.NTF_SELF, | ||
Type: netlink.NDA_DST, | ||
IP: n.IP, | ||
HardwareAddr: n.MAC, | ||
}) | ||
if err == unix.ENOENT { | ||
return nil | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
Oops, something went wrong.