Skip to content

Commit 546b351

Browse files
authored
Add TCP connection support for OVS (#330)
- Extend OVS connection options beyond Unix sockets - Implement TCP endpoint configuration for marker binary - Use -ovs-socket flag with format "tcp:<IP>:<PORT>" 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:<IP>:<PORT>". ``` Signed-off-by: Tarek Abu-Hariri <[email protected]>
1 parent 9a93db0 commit 546b351

File tree

1 file changed

+101
-29
lines changed

1 file changed

+101
-29
lines changed

cmd/marker/main.go

+101-29
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package main
1717
import (
1818
"flag"
1919
"fmt"
20+
"net"
2021
"os"
2122
"reflect"
2223
"strings"
@@ -29,6 +30,12 @@ import (
2930
"github.com/k8snetworkplumbingwg/ovs-cni/pkg/marker"
3031
)
3132

33+
const (
34+
UnixSocketType = "unix"
35+
TcpSocketType = "tcp"
36+
SocketConnectionTimeout = time.Minute
37+
)
38+
3239
func main() {
3340
nodeName := flag.String("node-name", "", "name of kubernetes node")
3441
ovsSocket := flag.String("ovs-socket", "", "address of openvswitch database connection")
@@ -54,38 +61,16 @@ func main() {
5461
if *ovsSocket == "" {
5562
glog.Fatal("ovs-socket must be set")
5663
}
57-
58-
var socketType, path string
59-
ovsSocketTokens := strings.Split(*ovsSocket, ":")
60-
if len(ovsSocketTokens) < 2 {
61-
/*
62-
* ovsSocket should consist of comma separated socket type and socket
63-
* detail. If no socket type is specified, it is assumed to be a unix
64-
* domain socket, for backwards compatibility.
65-
*/
66-
socketType = "unix"
67-
path = *ovsSocket
68-
} else {
69-
socketType = ovsSocketTokens[0]
70-
path = ovsSocketTokens[1]
64+
socketType, address, err := parseOvsSocket(ovsSocket)
65+
if err != nil {
66+
glog.Fatalf("Failed to parse ovs socket: %v", err)
7167
}
72-
73-
if socketType == "unix" {
74-
for {
75-
_, err := os.Stat(path)
76-
if err == nil {
77-
glog.Info("Found the OVS socket")
78-
break
79-
} else if os.IsNotExist(err) {
80-
glog.Infof("Given ovs-socket %q was not found, waiting for the socket to appear", path)
81-
time.Sleep(time.Minute)
82-
} else {
83-
glog.Fatalf("Failed opening the OVS socket with: %v", err)
84-
}
85-
}
68+
if err = validateOvsSocketConnection(socketType, address); err != nil {
69+
glog.Fatal("Failed to connect to ovs: %v", err)
8670
}
71+
endpoint := fmt.Sprintf("%s:%s", socketType, address)
8772

88-
markerApp, err := marker.NewMarker(*nodeName, socketType+":"+path)
73+
markerApp, err := marker.NewMarker(*nodeName, endpoint)
8974
if err != nil {
9075
glog.Fatalf("Failed to create a new marker object: %v", err)
9176
}
@@ -137,3 +122,90 @@ func keepAlive(healthCheckFile string, healthCheckInterval int) {
137122

138123
}, time.Duration(healthCheckInterval)*time.Second)
139124
}
125+
126+
/*
127+
takes an OVS socket string and returns the socket
128+
type, address, and any parsing error.
129+
*/
130+
func parseOvsSocket(ovsSocket *string) (string, string, error) {
131+
var socketType, address string
132+
ovsSocketTokens := strings.Split(*ovsSocket, ":")
133+
if len(ovsSocketTokens) < 2 {
134+
/*
135+
* ovsSocket should consist of comma separated socket type and socket
136+
* detail. If no socket type is specified, it is assumed to be a unix
137+
* domain socket, for backwards compatibility.
138+
*/
139+
socketType = UnixSocketType
140+
address = *ovsSocket
141+
} else {
142+
socketType = ovsSocketTokens[0]
143+
if socketType == TcpSocketType {
144+
if len(ovsSocketTokens) != 3 {
145+
return "", "", fmt.Errorf("failed to parse OVS %s socket, must be in this format %s:<host>:<port>", socketType, socketType)
146+
}
147+
address = fmt.Sprintf("%s:%s", ovsSocketTokens[1], ovsSocketTokens[2])
148+
} else {
149+
// unix socket
150+
socketType = UnixSocketType
151+
address = ovsSocketTokens[1]
152+
}
153+
}
154+
return socketType, address, nil
155+
}
156+
157+
func validateOvsSocketConnection(socketType, address string) error {
158+
validator, err := getOvsSocketValidator(socketType)
159+
if err != nil {
160+
return err
161+
}
162+
return validator(address)
163+
}
164+
165+
func getOvsSocketValidator(socketType string) (func(string) error, error) {
166+
switch socketType {
167+
case UnixSocketType:
168+
return validateOvsUnixConnection, nil
169+
case TcpSocketType:
170+
return validateOvsTcpConnection, nil
171+
default:
172+
return nil, fmt.Errorf("unsupported ovs socket type: %s", socketType)
173+
}
174+
}
175+
176+
func validateOvsUnixConnection(address string) error {
177+
for {
178+
_, err := os.Stat(address)
179+
if err == nil {
180+
glog.Info("Found the OVS socket")
181+
break
182+
} else if os.IsNotExist(err) {
183+
glog.Infof("Given ovs-socket %q was not found, waiting for the socket to appear", address)
184+
time.Sleep(SocketConnectionTimeout)
185+
} else {
186+
return fmt.Errorf("failed opening the OVS socket with: %v", err)
187+
}
188+
}
189+
return nil
190+
}
191+
192+
func validateOvsTcpConnection(address string) error {
193+
conn, err := net.DialTimeout(TcpSocketType, address, SocketConnectionTimeout)
194+
if err == nil {
195+
glog.Info("Successfully connected to TCP socket")
196+
conn.Close()
197+
return nil
198+
}
199+
200+
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
201+
return fmt.Errorf("connection to %s timed out", address)
202+
} else if opErr, ok := err.(*net.OpError); ok {
203+
if opErr.Op == "dial" {
204+
return fmt.Errorf("connection to %s failed: %v", address, err)
205+
} else {
206+
return fmt.Errorf("unexpected error when connecting to %s: %v", address, err)
207+
}
208+
} else {
209+
return fmt.Errorf("unexpected error when connecting to %s: %v", address, err)
210+
}
211+
}

0 commit comments

Comments
 (0)