Skip to content

Commit 180a6e4

Browse files
committed
Introduce VSOCK link type
This address family is used in communication between virtual machines and their hosts. Advantages include that no virtual ethernet adapter and their respective address configuration and routing need to be setup. Rather, with this new link type, only a single yggdrasil interface can exist inside of the virtual machine. It can also be used inside of containers. There, the advantage over existing link types like unix sockets include, that no mount point need to be shared with the host and container. This provides more isolation. More information: https://man7.org/linux/man-pages/man7/vsock.7.html https://gist.github.com/nrdmn/7971be650919b112343b1cb2757a3fe6
1 parent d252278 commit 180a6e4

File tree

5 files changed

+88
-0
lines changed

5 files changed

+88
-0
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2626
- in case of vulnerabilities.
2727
-->
2828

29+
## [0.5.xx] - 2025-xx-xx
30+
31+
### Added
32+
33+
* VSOCK support for peerings, by using the new `vsock://` scheme in `Listen` and `Peers`.
34+
* Use e.g. `vsock://local:1234`.
35+
2936
## [0.5.12] - 2024-12-18
3037

3138
* Go 1.22 is now required to build Yggdrasil

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/hashicorp/go-syslog v1.0.0
1212
github.com/hjson/hjson-go/v4 v4.4.0
1313
github.com/kardianos/minwinsvc v1.0.2
14+
github.com/mdlayher/vsock v1.2.1
1415
github.com/quic-go/quic-go v0.48.2
1516
github.com/vishvananda/netlink v1.3.0
1617
github.com/wlynxg/anet v0.0.5
@@ -29,6 +30,7 @@ require (
2930
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
3031
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
3132
github.com/mattn/go-colorable v0.1.13 // indirect
33+
github.com/mdlayher/socket v0.4.1 // indirect
3234
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
3335
github.com/rivo/uniseg v0.2.0 // indirect
3436
go.uber.org/mock v0.4.0 // indirect

go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
5050
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
5151
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
5252
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
53+
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
54+
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
55+
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
56+
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
5357
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
5458
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
5559
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=

src/core/link.go

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type links struct {
4040
quic *linkQUIC // QUIC interface support
4141
ws *linkWS // WS interface support
4242
wss *linkWSS // WSS interface support
43+
vsock *linkVSOCK // VSOCK interface support
4344
// _links can only be modified safely from within the links actor
4445
_links map[linkInfo]*link // *link is nil if connection in progress
4546
_listeners map[*Listener]context.CancelFunc
@@ -96,6 +97,7 @@ func (l *links) init(c *Core) error {
9697
l.quic = l.newLinkQUIC()
9798
l.ws = l.newLinkWS()
9899
l.wss = l.newLinkWSS()
100+
l.vsock = l.newLinkVSOCK()
99101
l._links = make(map[linkInfo]*link)
100102
l._listeners = make(map[*Listener]context.CancelFunc)
101103

@@ -444,6 +446,8 @@ func (l *links) listen(u *url.URL, sintf string, local bool) (*Listener, error)
444446
protocol = l.ws
445447
case "wss":
446448
protocol = l.wss
449+
case "vsock":
450+
protocol = l.vsock
447451
default:
448452
ctxcancel()
449453
return nil, ErrLinkUnrecognisedSchema
@@ -595,6 +599,8 @@ func (l *links) connect(ctx context.Context, u *url.URL, info linkInfo, options
595599
dialer = l.ws
596600
case "wss":
597601
dialer = l.wss
602+
case "vsock":
603+
dialer = l.vsock
598604
default:
599605
return nil, ErrLinkUnrecognisedSchema
600606
}

src/core/link_vsock.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package core
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net"
7+
"net/url"
8+
"strconv"
9+
"strings"
10+
11+
"github.com/Arceliar/phony"
12+
"github.com/mdlayher/vsock"
13+
)
14+
15+
type linkVSOCK struct {
16+
phony.Inbox
17+
*links
18+
}
19+
20+
func (l *links) newLinkVSOCK() *linkVSOCK {
21+
lt := &linkVSOCK{
22+
links: l,
23+
}
24+
return lt
25+
}
26+
27+
func (l *linkVSOCK) dial(ctx context.Context, url *url.URL, info linkInfo, options linkOptions) (net.Conn, error) {
28+
localPort, err := strconv.ParseUint(url.Port(), 10, 32)
29+
if err != nil {
30+
return nil, fmt.Errorf("no VSOCK port specified: %w", err)
31+
}
32+
contextID, err := urlParseContextID(url)
33+
if err != nil {
34+
return nil, fmt.Errorf("Unknown VSOCK host and cannot parse as numerical contextID: %w", err)
35+
}
36+
return vsock.Dial(contextID, uint32(localPort), nil)
37+
}
38+
39+
func (l *linkVSOCK) listen(ctx context.Context, url *url.URL, _ string) (net.Listener, error) {
40+
localPort, err := strconv.ParseUint(url.Port(), 10, 32)
41+
if err != nil {
42+
return nil, fmt.Errorf("no VSOCK port specified: %w", err)
43+
}
44+
contextID, err := urlParseContextID(url)
45+
if err != nil {
46+
return nil, fmt.Errorf("Unknown VSOCK host and cannot parse as numerical contextID: %w", err)
47+
}
48+
return vsock.ListenContextID(contextID, uint32(localPort), nil)
49+
}
50+
51+
func urlParseContextID(u *url.URL) (uint32, error) {
52+
var contextID uint32
53+
54+
switch strings.ToLower(u.Hostname()) {
55+
case "hypervisor":
56+
contextID = vsock.Hypervisor
57+
case "local":
58+
contextID = vsock.Local
59+
case "host":
60+
contextID = vsock.Host
61+
default:
62+
parsedHost, err := strconv.Atoi(u.Hostname())
63+
if err != nil {
64+
return 0, err
65+
}
66+
contextID = uint32(parsedHost)
67+
}
68+
return contextID, nil
69+
}

0 commit comments

Comments
 (0)