Skip to content

Commit

Permalink
feat: add vsock network type support (dragonflyoss#1303)
Browse files Browse the repository at this point in the history
So we support connecting dfdaemon running on host outside of VM via
virtio-vsock device.

Signed-off-by: Eryu Guan <[email protected]>
  • Loading branch information
eryugey authored May 16, 2022
1 parent 8f26e32 commit 0bc0d3b
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 5 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ require (
github.com/jarcoal/httpmock v1.0.8
github.com/looplab/fsm v0.3.0
github.com/mcuadros/go-gin-prometheus v0.1.0
github.com/mdlayher/vsock v1.1.1
github.com/mitchellh/mapstructure v1.4.1
github.com/montanaflynn/stats v0.6.6
github.com/onsi/ginkgo/v2 v2.1.0
Expand Down Expand Up @@ -155,6 +156,7 @@ require (
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mdlayher/socket v0.2.0 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,10 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mcuadros/go-gin-prometheus v0.1.0 h1:JNoWKvw/u9tyRJ8BL9ZJvfiXU8IHUw8gCvcf/5L8tnI=
github.com/mcuadros/go-gin-prometheus v0.1.0/go.mod h1:ezECAsiHtCRIa+6Ii8THg7G7RJvpO4S19d499UkEE3s=
github.com/mdlayher/socket v0.2.0 h1:EY4YQd6hTAg2tcXF84p5DTHazShE50u5HeBzBaNgjkA=
github.com/mdlayher/socket v0.2.0/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
github.com/mdlayher/vsock v1.1.1 h1:8lFuiXQnmICBrCIIA9PMgVSke6Fg6V4+r0v7r55k88I=
github.com/mdlayher/vsock v1.1.1/go.mod h1:Y43jzcy7KM3QB+/FK15pfqGxDMCMzUXWegEfIbSM18U=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
Expand Down
15 changes: 11 additions & 4 deletions pkg/dfnet/dfnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ import (
type NetworkType string

const (
TCP NetworkType = "tcp"
UNIX NetworkType = "unix"
TCP NetworkType = "tcp"
UNIX NetworkType = "unix"
VSOCK NetworkType = "vsock"

TCPEndpointPrefix string = "dns:///"
UnixEndpointPrefix string = "unix://"
VsockEndpointPrefix string = "vsock://"
)

type NetAddr struct {
Expand All @@ -39,9 +44,11 @@ type NetAddr struct {
func (n NetAddr) GetEndpoint() string {
switch n.Type {
case UNIX:
return "unix://" + n.Addr
return UnixEndpointPrefix + n.Addr
case VSOCK:
return VsockEndpointPrefix + n.Addr
default:
return "dns:///" + n.Addr
return TCPEndpointPrefix + n.Addr
}
}

Expand Down
7 changes: 6 additions & 1 deletion pkg/rpc/dfdaemon/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ func GetClientByAddr(addrs []dfnet.NetAddr, opts ...grpc.DialOption) (DaemonClie
if len(addrs) == 0 {
return nil, errors.New("address list of daemon is empty")
}

dialOpts, err := rpc.VsockDialerOption(addrs, opts)
if err != nil {
return nil, err
}
dc := &daemonClient{
rpc.NewConnection(context.Background(), "daemon-static", addrs, []rpc.ConnOption{
rpc.WithConnExpireTime(60 * time.Second),
rpc.WithDialOption(opts),
rpc.WithDialOption(dialOpts),
}),
}
return dc, nil
Expand Down
79 changes: 79 additions & 0 deletions pkg/rpc/vsock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2022 The Dragonfly Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package rpc

import (
"context"
"fmt"
"net"
"strconv"
"strings"

"github.com/mdlayher/vsock"
"github.com/pkg/errors"
"google.golang.org/grpc"

"d7y.io/dragonfly/v2/pkg/dfnet"
)

// VsockDialer is the dialer for vsock, it expects `address` to be in dfnet.NetAddr.GetEndpoint()
// format, that is "vsock://cid:port"
func VsockDialer(_ctx context.Context, address string) (net.Conn, error) {
addrStr := strings.TrimPrefix(address, dfnet.VsockEndpointPrefix)
addr := strings.Split(addrStr, ":")
if len(addr) != 2 {
return nil, fmt.Errorf("invalid vsock address (%s), expected %scid:port", address, dfnet.VsockEndpointPrefix)
}

cid, err := strconv.ParseUint(addr[0], 10, 32)
if err != nil {
return nil, errors.Wrapf(err, "failed to convert %q to vsock cid", addr[0])
}
port, err := strconv.ParseUint(addr[1], 10, 32)
if err != nil {
return nil, errors.Wrapf(err, "failed to convert %q to vsock port", addr[1])
}

conn, err := vsock.Dial(uint32(cid), uint32(port), nil)
if err != nil {
return nil, errors.Wrapf(err, "failed to dial vsock %v:%v, address %s", uint32(cid), uint32(port), address)
}
return conn, nil
}

// If `addrs` are all vsock addresses, add rpc.VsockDialer to DialOption, and return error if addrs
// have mixed vsock and other connection types.
func VsockDialerOption(addrs []dfnet.NetAddr, opts []grpc.DialOption) ([]grpc.DialOption, error) {
var prevType dfnet.NetworkType
hasVsock := false
for n, a := range addrs {
if a.Type != dfnet.VSOCK {
prevType = a.Type
continue
}
hasVsock = true
if n > 0 && prevType != dfnet.VSOCK {
return nil, fmt.Errorf("addrs(%v) have mixed vsock and other types", addrs)
}
prevType = a.Type
}
dialOpts := opts
if hasVsock {
dialOpts = append(opts, grpc.WithContextDialer(VsockDialer))
}
return dialOpts, nil
}

0 comments on commit 0bc0d3b

Please sign in to comment.