Skip to content

Commit 522130a

Browse files
committed
sandbox: support vsock connection to task api
Signed-off-by: Abel Feng <[email protected]>
1 parent 67ff3db commit 522130a

35 files changed

+3730
-1
lines changed

core/runtime/v2/shim/util_unix.go

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,24 @@
1919
package shim
2020

2121
import (
22+
"bufio"
2223
"context"
2324
"crypto/sha256"
2425
"fmt"
26+
"io"
27+
"math"
2528
"net"
2629
"os"
2730
"path/filepath"
2831
"runtime"
32+
"strconv"
2933
"strings"
3034
"syscall"
3135
"time"
3236

37+
"github.com/containerd/log"
38+
"github.com/mdlayher/vsock"
39+
3340
"github.com/containerd/containerd/v2/defaults"
3441
"github.com/containerd/containerd/v2/pkg/namespaces"
3542
"github.com/containerd/containerd/v2/pkg/sys"
@@ -38,6 +45,9 @@ import (
3845
const (
3946
shimBinaryFormat = "containerd-shim-%s-%s"
4047
socketPathLimit = 106
48+
protoVsock = "vsock"
49+
protoHybridVsock = "hvsock"
50+
protoUnix = "unix"
4151
)
4252

4353
func getSysProcAttr() *syscall.SysProcAttr {
@@ -76,7 +86,21 @@ func SocketAddress(ctx context.Context, socketPath, id string) (string, error) {
7686

7787
// AnonDialer returns a dialer for a socket
7888
func AnonDialer(address string, timeout time.Duration) (net.Conn, error) {
79-
return net.DialTimeout("unix", socket(address).path(), timeout)
89+
proto, addr, ok := strings.Cut(address, "://")
90+
if !ok {
91+
return net.DialTimeout("unix", socket(address).path(), timeout)
92+
}
93+
switch proto {
94+
case protoVsock:
95+
// vsock dialer can not set timeout
96+
return dialVsock(addr)
97+
case protoHybridVsock:
98+
return dialHybridVsock(addr, timeout)
99+
case protoUnix:
100+
return net.DialTimeout("unix", socket(address).path(), timeout)
101+
default:
102+
return nil, fmt.Errorf("unsupported protocol: %s", proto)
103+
}
80104
}
81105

82106
// AnonReconnectDialer returns a dialer for an existing socket on reconnection
@@ -177,3 +201,88 @@ func CanConnect(address string) bool {
177201
conn.Close()
178202
return true
179203
}
204+
205+
func hybridVsockDialer(addr string, port uint64, timeout time.Duration) (net.Conn, error) {
206+
timeoutCh := time.After(timeout)
207+
// Do 10 retries before timeout
208+
retryInterval := timeout / 10
209+
for {
210+
conn, err := net.DialTimeout("unix", addr, timeout)
211+
if err != nil {
212+
return nil, err
213+
}
214+
if _, err = conn.Write([]byte(fmt.Sprintf("CONNECT %d\n", port))); err != nil {
215+
conn.Close()
216+
return nil, err
217+
}
218+
errChan := make(chan error, 1)
219+
go func() {
220+
reader := bufio.NewReader(conn)
221+
response, err := reader.ReadString('\n')
222+
if err != nil {
223+
errChan <- err
224+
return
225+
}
226+
if strings.Contains(response, "OK") {
227+
errChan <- nil
228+
} else {
229+
errChan <- fmt.Errorf("hybrid vsock handshake response error: %s", response)
230+
}
231+
}()
232+
select {
233+
case err = <-errChan:
234+
if err != nil {
235+
conn.Close()
236+
// When it is EOF, maybe the server side is not ready.
237+
if err == io.EOF {
238+
log.G(context.Background()).Warnf("Read hybrid vsock got EOF, server may not ready")
239+
time.Sleep(retryInterval)
240+
continue
241+
}
242+
return nil, err
243+
}
244+
return conn, nil
245+
case <-timeoutCh:
246+
conn.Close()
247+
return nil, fmt.Errorf("timeout waiting for hybrid vsocket handshake of %s:%d", addr, port)
248+
}
249+
}
250+
251+
}
252+
253+
func dialVsock(address string) (net.Conn, error) {
254+
contextIDString, portString, ok := strings.Cut(address, ":")
255+
if !ok {
256+
return nil, fmt.Errorf("invalid vsock address %s", address)
257+
}
258+
contextID, err := strconv.ParseUint(contextIDString, 10, 0)
259+
if err != nil {
260+
return nil, fmt.Errorf("failed to parse vsock context id %s, %v", contextIDString, err)
261+
}
262+
if contextID > math.MaxUint32 {
263+
return nil, fmt.Errorf("vsock context id %d is invalid", contextID)
264+
}
265+
port, err := strconv.ParseUint(portString, 10, 0)
266+
if err != nil {
267+
return nil, fmt.Errorf("failed to parse vsock port %s, %v", portString, err)
268+
}
269+
if port > math.MaxUint32 {
270+
return nil, fmt.Errorf("vsock port %d is invalid", port)
271+
}
272+
return vsock.Dial(uint32(contextID), uint32(port), &vsock.Config{})
273+
}
274+
275+
func dialHybridVsock(address string, timeout time.Duration) (net.Conn, error) {
276+
addr, portString, ok := strings.Cut(address, ":")
277+
if !ok {
278+
return nil, fmt.Errorf("invalid hybrid vsock address %s", address)
279+
}
280+
port, err := strconv.ParseUint(portString, 10, 0)
281+
if err != nil {
282+
return nil, fmt.Errorf("failed to parse hybrid vsock port %s, %v", portString, err)
283+
}
284+
if port > math.MaxUint32 {
285+
return nil, fmt.Errorf("hybrid vsock port %d is invalid", port)
286+
}
287+
return hybridVsockDialer(addr, port, timeout)
288+
}

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ require (
3636
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0
3737
github.com/intel/goresctrl v0.6.0
3838
github.com/klauspost/compress v1.17.6
39+
github.com/mdlayher/vsock v1.2.1
3940
github.com/minio/sha256-simd v1.0.1
4041
github.com/moby/locker v1.0.1
4142
github.com/moby/sys/mountinfo v0.7.1
@@ -103,6 +104,7 @@ require (
103104
github.com/json-iterator/go v1.1.12 // indirect
104105
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
105106
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
107+
github.com/mdlayher/socket v0.4.1 // indirect
106108
github.com/moby/spdystream v0.2.0 // indirect
107109
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
108110
github.com/modern-go/reflect2 v1.0.2 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
284284
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
285285
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
286286
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
287+
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
288+
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
289+
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
290+
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
287291
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
288292
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
289293
github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs=

vendor/github.com/mdlayher/socket/CHANGELOG.md

Lines changed: 80 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/mdlayher/socket/LICENSE.md

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/mdlayher/socket/README.md

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/mdlayher/socket/accept.go

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/mdlayher/socket/accept4.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)