Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for finding net adapters that were assigned with vpci #1196

Merged
merged 2 commits into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions internal/guest/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,23 @@ import (
"strings"
"time"

"github.com/Microsoft/hcsshim/internal/guest/storage"
"github.com/Microsoft/hcsshim/internal/guest/storage/pci"
"github.com/Microsoft/hcsshim/internal/guest/storage/vmbus"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
)

// mock out calls for testing
var (
pciFindDeviceFullPath = pci.FindDeviceFullPath
storageWaitForFileMatchingPattern = storage.WaitForFileMatchingPattern
vmbusWaitForDevicePath = vmbus.WaitForDevicePath
ioutilReadDir = ioutil.ReadDir
)

// maxDNSSearches is limited to 6 in `man 5 resolv.conf`
const maxDNSSearches = 6

Expand Down Expand Up @@ -104,20 +114,33 @@ func MergeValues(first, second []string) []string {
// Windows host) to its corresponding interface name (e.g. "eth0").
//
// Will retry the operation until `ctx` is exceeded or canceled.
func InstanceIDToName(ctx context.Context, id string) (_ string, err error) {
func InstanceIDToName(ctx context.Context, id string, vpciAssigned bool) (_ string, err error) {
ctx, span := trace.StartSpan(ctx, "network::InstanceIDToName")
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()

id = strings.ToLower(id)
span.AddAttributes(trace.StringAttribute("adapterInstanceID", id))
vmBusID := strings.ToLower(id)
span.AddAttributes(trace.StringAttribute("adapterInstanceID", vmBusID))

vmBusSubPath := filepath.Join(id, "net")
devicePath, err := vmbus.WaitForDevicePath(ctx, vmBusSubPath)
netDevicePath := ""
if vpciAssigned {
pciDevicePath, err := pciFindDeviceFullPath(ctx, vmBusID)
if err != nil {
return "", err
}
pciNetDirPattern := filepath.Join(pciDevicePath, "net")
netDevicePath, err = storageWaitForFileMatchingPattern(ctx, pciNetDirPattern)
} else {
vmBusNetSubPath := filepath.Join(vmBusID, "net")
netDevicePath, err = vmbusWaitForDevicePath(ctx, vmBusNetSubPath)
}
dcantah marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return "", errors.Wrapf(err, "failed to find adapter %v sysfs path", vmBusID)
}

var deviceDirs []os.FileInfo
for {
deviceDirs, err = ioutil.ReadDir(devicePath)
deviceDirs, err = ioutilReadDir(netDevicePath)
if err != nil {
if os.IsNotExist(err) {
select {
Expand All @@ -128,16 +151,16 @@ func InstanceIDToName(ctx context.Context, id string) (_ string, err error) {
continue
}
} else {
return "", errors.Wrapf(err, "failed to read vmbus network device from /sys filesystem for adapter %s", id)
return "", errors.Wrapf(err, "failed to read vmbus network device from /sys filesystem for adapter %s", vmBusID)
}
}
break
}
if len(deviceDirs) == 0 {
return "", errors.Errorf("no interface name found for adapter %s", id)
return "", errors.Errorf("no interface name found for adapter %s", vmBusID)
}
if len(deviceDirs) > 1 {
return "", errors.Errorf("multiple interface names found for adapter %s", id)
return "", errors.Errorf("multiple interface names found for adapter %s", vmBusID)
}
ifname := deviceDirs[0].Name()
log.G(ctx).WithField("ifname", ifname).Debug("resolved ifname")
Expand Down
95 changes: 95 additions & 0 deletions internal/guest/network/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ package network

import (
"context"
"io/fs"
dcantah marked this conversation as resolved.
Show resolved Hide resolved
"os"
"path/filepath"
"testing"
"time"
)

func Test_GenerateResolvConfContent(t *testing.T) {
Expand Down Expand Up @@ -165,3 +169,94 @@ ff02::2 ip6-allrouters
})
}
}

// create a test FileInfo so we can return back a value to ReadDir
type testFileInfo struct {
FileName string
IsDirectory bool
}

func (t *testFileInfo) Name() string {
return t.FileName
}
func (t *testFileInfo) Size() int64 {
return 0
}
func (t *testFileInfo) Mode() fs.FileMode {
if t.IsDirectory {
return fs.ModeDir
}
return 0
}
func (t *testFileInfo) ModTime() time.Time {
return time.Now()
}
func (t *testFileInfo) IsDir() bool {
return t.IsDirectory
}
func (t *testFileInfo) Sys() interface{} {
return nil
}

var _ = (os.FileInfo)(&testFileInfo{})

func Test_InstanceIDToName(t *testing.T) {
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)

vmBusGUID := "1111-2222-3333-4444"
testIfName := "test-eth0"

vmbusWaitForDevicePath = func(_ context.Context, vmBusGUIDPattern string) (string, error) {
vmBusPath := filepath.Join("/sys/bus/vmbus/devices", vmBusGUIDPattern)
return vmBusPath, nil
}

storageWaitForFileMatchingPattern = func(_ context.Context, pattern string) (string, error) {
return pattern, nil
}

ioutilReadDir = func(dirname string) ([]os.FileInfo, error) {
info := &testFileInfo{
FileName: testIfName,
IsDirectory: false,
}
return []fs.FileInfo{info}, nil
}
actualIfName, err := InstanceIDToName(ctx, vmBusGUID, false)
if err != nil {
t.Fatalf("expected no error, instead got %v", err)
}
if actualIfName != testIfName {
t.Fatalf("expected to get %v ifname, instead got %v", testIfName, actualIfName)
}
}

func Test_InstanceIDToName_VPCI(t *testing.T) {
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)

vmBusGUID := "1111-2222-3333-4444"
testIfName := "test-eth0-vpci"

pciFindDeviceFullPath = func(_ context.Context, vmBusGUID string) (string, error) {
return filepath.Join("/sys/bus/vmbus/devices", vmBusGUID), nil
}

storageWaitForFileMatchingPattern = func(_ context.Context, pattern string) (string, error) {
return pattern, nil
}

ioutilReadDir = func(dirname string) ([]os.FileInfo, error) {
info := &testFileInfo{
FileName: testIfName,
IsDirectory: false,
}
return []os.FileInfo{info}, nil
}
actualIfName, err := InstanceIDToName(ctx, vmBusGUID, true)
if err != nil {
t.Fatalf("expected no error, instead got %v", err)
}
if actualIfName != testIfName {
t.Fatalf("expected to get %v ifname, instead got %v", testIfName, actualIfName)
}
}
1 change: 1 addition & 0 deletions internal/guest/prot/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ type NetworkAdapterV2 struct {
DNSServerList string `json:",omitempty"`
EnableLowMetric bool `json:",omitempty"`
EncapOverhead uint16 `json:",omitempty"`
VPCIAssigned bool `json:",omitempty"`
}

// MappedVirtualDisk represents a disk on the host which is mapped into a
Expand Down
2 changes: 1 addition & 1 deletion internal/guest/runtime/hcsv2/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (n *namespace) AddAdapter(ctx context.Context, adp *prot.NetworkAdapterV2)

resolveCtx, cancel := context.WithTimeout(ctx, time.Second*5)
defer cancel()
ifname, err := networkInstanceIDToName(resolveCtx, adp.ID)
ifname, err := networkInstanceIDToName(resolveCtx, adp.ID, adp.VPCIAssigned)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/guest/runtime/hcsv2/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func Test_removeNetworkNamespace_HasAdapters(t *testing.T) {

ns := getOrAddNetworkNamespace(t.Name())

networkInstanceIDToName = func(ctx context.Context, id string) (string, error) {
networkInstanceIDToName = func(ctx context.Context, id string, _ bool) (string, error) {
return "/dev/sdz", nil
}
err := ns.AddAdapter(context.Background(), &prot.NetworkAdapterV2{ID: "test"})
Expand Down
19 changes: 12 additions & 7 deletions internal/guest/storage/pci/pci.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,24 @@ func WaitForPCIDeviceFromVMBusGUID(ctx context.Context, vmBusGUID string) error
// FindDeviceBusLocationFromVMBusGUID finds device bus location by
// reading /sys/bus/vmbus/devices/<vmBusGUID>/... for pci specific directories
func FindDeviceBusLocationFromVMBusGUID(ctx context.Context, vmBusGUID string) (string, error) {
pciDir, err := findVMBusPCIDir(ctx, vmBusGUID)
fullPath, err := FindDeviceFullPath(ctx, vmBusGUID)
if err != nil {
return "", err
}

pciDeviceLocation, err := findVMBusPCIDevice(ctx, pciDir)
_, busFile := filepath.Split(fullPath)
return busFile, nil
}

// FindDeviceFullPath finds the full PCI device path in the form of
// /sys/bus/vmbus/devices/<vmBusGUID>/pciXXXX:XX/XXXX:XX*
func FindDeviceFullPath(ctx context.Context, vmBusGUID string) (string, error) {
pciDir, err := findVMBusPCIDir(ctx, vmBusGUID)
if err != nil {
return "", err
}
return pciDeviceLocation, nil

return findVMBusPCIDevice(ctx, pciDir)
}

// findVMBusPCIDir waits for the pci bus directory matching pattern
Expand All @@ -50,15 +58,12 @@ func findVMBusPCIDevice(ctx context.Context, pciDirFullPath string) (string, err
// trim /sys/bus/vmbus/devices/<vmBusGUID>/pciXXXX:XX to XXXX:XX
_, pciDirName := filepath.Split(pciDirFullPath)
busPrefix := strings.TrimPrefix(pciDirName, "pci")

// under /sys/bus/vmbus/devices/<vmBusGUID>/pciXXXX:XX/ look for directory matching XXXX:XX* pattern
busPathPattern := filepath.Join(pciDirFullPath, fmt.Sprintf("%s*", busPrefix))
busFileFullPath, err := storageWaitForFileMatchingPattern(ctx, busPathPattern)
if err != nil {
return "", err
}

// return the resulting XXXX:XX:YY.Y pci bus location
_, busFile := filepath.Split(busFileFullPath)
return busFile, nil
return busFileFullPath, nil
}
1 change: 1 addition & 0 deletions internal/guestrequest/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ type LCOWNetworkAdapter struct {
DNSServerList string `json:",omitempty"`
EnableLowMetric bool `json:",omitempty"`
EncapOverhead uint16 `json:",omitempty"`
VPCIAssigned bool `json:",omitempty"`
}

type LCOWContainerConstraints struct {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.