From 9158a6fed118ab92d801e76d16ac52d5879c18c6 Mon Sep 17 00:00:00 2001 From: Tarek Abu-Hariri Date: Thu, 7 Nov 2024 12:37:20 +0200 Subject: [PATCH] Add TCP connection support for OVS - Extend OVS connection options beyond Unix sockets - Implement TCP endpoint configuration for marker binary - Use -ovs-socket flag with format "tcp::" Example usage: -ovs-socket tcp:127.0.0.1:6640 **What this PR does / why we need it**: Add Support for ovs tcp connection **Special notes for your reviewer**: **Release note**: ```release-note This feature allows for remote OVS connections, enhancing flexibility in network configurations. User will be allowed to use tcp connection to OVS by specifying OVS socket endpoint by using -ovs-socket flag with tcp endpoint "tcp::". ``` Signed-off-by: Tarek Abu-Hariri --- cmd/marker/main.go | 109 +++++++++++++++++++++++---------- hack/docker-builder/Dockerfile | 2 +- 2 files changed, 77 insertions(+), 34 deletions(-) diff --git a/cmd/marker/main.go b/cmd/marker/main.go index 581037a2..c145a8cf 100644 --- a/cmd/marker/main.go +++ b/cmd/marker/main.go @@ -17,6 +17,7 @@ package main import ( "flag" "fmt" + "net" "os" "reflect" "strings" @@ -29,6 +30,12 @@ import ( "github.com/k8snetworkplumbingwg/ovs-cni/pkg/marker" ) +const ( + UnixSocketType = "unix" + TcpSocketType = "tcp" + SocketConnectionTimeout = time.Minute +) + func main() { nodeName := flag.String("node-name", "", "name of kubernetes node") ovsSocket := flag.String("ovs-socket", "", "address of openvswitch database connection") @@ -51,41 +58,12 @@ func main() { glog.Fatal("node-name must be set") } - if *ovsSocket == "" { - glog.Fatal("ovs-socket must be set") - } - - var socketType, path string - ovsSocketTokens := strings.Split(*ovsSocket, ":") - if len(ovsSocketTokens) < 2 { - /* - * ovsSocket should consist of comma separated socket type and socket - * detail. If no socket type is specified, it is assumed to be a unix - * domain socket, for backwards compatibility. - */ - socketType = "unix" - path = *ovsSocket - } else { - socketType = ovsSocketTokens[0] - path = ovsSocketTokens[1] - } - - if socketType == "unix" { - for { - _, err := os.Stat(path) - if err == nil { - glog.Info("Found the OVS socket") - break - } else if os.IsNotExist(err) { - glog.Infof("Given ovs-socket %q was not found, waiting for the socket to appear", path) - time.Sleep(time.Minute) - } else { - glog.Fatalf("Failed opening the OVS socket with: %v", err) - } - } + endpoint, err := parseOvsSocket(ovsSocket) + if err != nil { + glog.Fatalf("Failed to parse ovs socket: %v", err) } - markerApp, err := marker.NewMarker(*nodeName, socketType+":"+path) + markerApp, err := marker.NewMarker(*nodeName, endpoint) if err != nil { glog.Fatalf("Failed to create a new marker object: %v", err) } @@ -137,3 +115,68 @@ func keepAlive(healthCheckFile string, healthCheckInterval int) { }, time.Duration(healthCheckInterval)*time.Second) } + +func parseOvsSocket(ovsSocket *string) (string, error) { + if *ovsSocket == "" { + return "", fmt.Errorf("ovs-socket must be set") + } + + var socketType, address string + ovsSocketTokens := strings.Split(*ovsSocket, ":") + if len(ovsSocketTokens) < 2 { + /* + * ovsSocket should consist of comma separated socket type and socket + * detail. If no socket type is specified, it is assumed to be a unix + * domain socket, for backwards compatibility. + */ + socketType = UnixSocketType + address = *ovsSocket + } else { + socketType = ovsSocketTokens[0] + if socketType == TcpSocketType { + if len(ovsSocketTokens) != 3 { + return "", fmt.Errorf("failed to parse OVS %s socket, must be in this format %s::", socketType, socketType) + } + address = fmt.Sprintf("%s:%s", ovsSocketTokens[1], ovsSocketTokens[2]) + } else { + // unix socket + address = ovsSocketTokens[1] + } + } + endpoint := fmt.Sprintf("%s:%s", socketType, address) + + if socketType == UnixSocketType { + for { + _, err := os.Stat(address) + if err == nil { + glog.Info("Found the OVS socket") + break + } else if os.IsNotExist(err) { + glog.Infof("Given ovs-socket %q was not found, waiting for the socket to appear", address) + time.Sleep(SocketConnectionTimeout) + } else { + return "", fmt.Errorf("failed opening the OVS socket with: %v", err) + } + } + } else if socketType == TcpSocketType { + conn, err := net.DialTimeout(socketType, address, SocketConnectionTimeout) + if err == nil { + glog.Info("Successfully connected to TCP socket") + conn.Close() + return endpoint, nil + } + + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + return "", fmt.Errorf("connection to %s timed out", address) + } else if opErr, ok := err.(*net.OpError); ok { + if opErr.Op == "dial" { + return "", fmt.Errorf("connection to %s failed: %v", address, err) + } else { + return "", fmt.Errorf("unexpected error when connecting to %s: %v", address, err) + } + } else { + return "", fmt.Errorf("unexpected error when connecting to %s: %v", address, err) + } + } + return endpoint, nil +} diff --git a/hack/docker-builder/Dockerfile b/hack/docker-builder/Dockerfile index 17d2aeb7..4210dc6d 100644 --- a/hack/docker-builder/Dockerfile +++ b/hack/docker-builder/Dockerfile @@ -27,7 +27,7 @@ RUN \ tar -xzf cni-plugins-linux-amd64-v1.0.1.tgz && \ rm -f cni-plugins-linux-amd64-v1.0.1.tgz -RUN go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo +RUN go install github.com/onsi/ginkgo/v2/ginkgo@latest ADD entrypoint.sh /entrypoint.sh