aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/ovn4nfvk8s-cni/app/helper_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/ovn4nfvk8s-cni/app/helper_linux.go')
-rw-r--r--cmd/ovn4nfvk8s-cni/app/helper_linux.go160
1 files changed, 160 insertions, 0 deletions
diff --git a/cmd/ovn4nfvk8s-cni/app/helper_linux.go b/cmd/ovn4nfvk8s-cni/app/helper_linux.go
new file mode 100644
index 0000000..1a98a61
--- /dev/null
+++ b/cmd/ovn4nfvk8s-cni/app/helper_linux.go
@@ -0,0 +1,160 @@
+// +build linux
+
+package app
+
+import (
+ "fmt"
+ "net"
+ "os/exec"
+ "regexp"
+ "strings"
+
+ "github.com/sirupsen/logrus"
+
+ "github.com/containernetworking/cni/pkg/skel"
+ "github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/ip"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/vishvananda/netlink"
+)
+
+func renameLink(curName, newName string) error {
+ link, err := netlink.LinkByName(curName)
+ if err != nil {
+ return err
+ }
+
+ if err := netlink.LinkSetDown(link); err != nil {
+ return err
+ }
+ if err := netlink.LinkSetName(link, newName); err != nil {
+ return err
+ }
+ if err := netlink.LinkSetUp(link); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, gatewayIP, defaultGateway string, mtu int) (*current.Interface, *current.Interface, error) {
+ hostIface := &current.Interface{}
+ contIface := &current.Interface{}
+
+ var oldHostVethName string
+ err := netns.Do(func(hostNS ns.NetNS) error {
+ // create the veth pair in the container and move host end into host netns
+ hostVeth, containerVeth, err := ip.SetupVeth(ifName, mtu, hostNS)
+ if err != nil {
+ return fmt.Errorf("failed to setup veth %s: %v", ifName, err)
+ //return err
+ }
+ hostIface.Mac = hostVeth.HardwareAddr.String()
+ contIface.Name = containerVeth.Name
+
+ link, err := netlink.LinkByName(contIface.Name)
+ if err != nil {
+ return fmt.Errorf("failed to lookup %s: %v", contIface.Name, err)
+ }
+
+ hwAddr, err := net.ParseMAC(macAddress)
+ if err != nil {
+ return fmt.Errorf("failed to parse mac address for %s: %v", contIface.Name, err)
+ }
+ err = netlink.LinkSetHardwareAddr(link, hwAddr)
+ if err != nil {
+ return fmt.Errorf("failed to add mac address %s to %s: %v", macAddress, contIface.Name, err)
+ }
+ contIface.Mac = macAddress
+ contIface.Sandbox = netns.Path()
+
+ addr, err := netlink.ParseAddr(ipAddress)
+ if err != nil {
+ return err
+ }
+ err = netlink.AddrAdd(link, addr)
+ if err != nil {
+ return fmt.Errorf("failed to add IP addr %s to %s: %v", ipAddress, contIface.Name, err)
+ }
+
+ if defaultGateway == "true" {
+ gw := net.ParseIP(gatewayIP)
+ if gw == nil {
+ return fmt.Errorf("parse ip of gateway failed")
+ }
+ err = ip.AddRoute(nil, gw, link)
+ if err != nil {
+ logrus.Errorf("ip.AddRoute failed %v gw %v link %v", err, gw, link)
+ return err
+ }
+ }
+ oldHostVethName = hostVeth.Name
+
+ return nil
+ })
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // rename the host end of veth pair
+ re := regexp.MustCompile("(\\d+)\\D*\\z")
+ index := re.FindAllString(ifName, -1)
+ hostIface.Name = containerID[:14] + index[0]
+ if err := renameLink(oldHostVethName, hostIface.Name); err != nil {
+ return nil, nil, fmt.Errorf("failed to rename %s to %s: %v", oldHostVethName, hostIface.Name, err)
+ }
+
+ return hostIface, contIface, nil
+}
+
+// ConfigureInterface sets up the container interface
+var ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, mtu int) ([]*current.Interface, error) {
+ netns, err := ns.GetNS(args.Netns)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open netns %q: %v", args.Netns, err)
+ }
+ defer netns.Close()
+ hostIface, contIface, err := setupInterface(netns, args.ContainerID, interfaceName, macAddress, ipAddress, gatewayIP, defaultGateway, mtu)
+ if err != nil {
+ return nil, err
+ }
+ var ifaceID string
+ if interfaceName != "" {
+ ifaceID = fmt.Sprintf("%s_%s_%s", namespace, podName, interfaceName)
+ } else {
+ ifaceID = fmt.Sprintf("%s_%s", namespace, podName)
+ }
+
+ ovsArgs := []string{
+ "add-port", "br-int", hostIface.Name, "--", "set",
+ "interface", hostIface.Name,
+ fmt.Sprintf("external_ids:attached_mac=%s", macAddress),
+ fmt.Sprintf("external_ids:iface-id=%s", ifaceID),
+ fmt.Sprintf("external_ids:ip_address=%s", ipAddress),
+ fmt.Sprintf("external_ids:sandbox=%s", args.ContainerID),
+ }
+
+ var out []byte
+ out, err = exec.Command("ovs-vsctl", ovsArgs...).CombinedOutput()
+ if err != nil {
+ return nil, fmt.Errorf("failure in plugging pod interface: %v\n %q", err, string(out))
+ }
+
+ return []*current.Interface{hostIface, contIface}, nil
+}
+
+// PlatformSpecificCleanup deletes the OVS port
+func PlatformSpecificCleanup(ifaceName string) (bool, error) {
+ done := false
+ ovsArgs := []string{
+ "del-port", "br-int", ifaceName,
+ }
+ out, err := exec.Command("ovs-vsctl", ovsArgs...).CombinedOutput()
+ if err != nil && !strings.Contains(string(out), "no port named") {
+ // DEL should be idempotent; don't return an error just log it
+ logrus.Warningf("failed to delete OVS port %s: %v\n %q", ifaceName, err, string(out))
+ done = true
+ }
+
+ return done, nil
+}