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

feature: cross-container named pipes #2358

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
5 changes: 3 additions & 2 deletions cmd/containerd-shim-runhcs-v1/task_hcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -988,10 +988,11 @@ func isMountTypeSupported(hostPath, mountType string) bool {
hcsoci.MountTypeVirtualDisk, hcsoci.MountTypeExtensibleVirtualDisk:
return false
default:
// Ensure that host path is not sandbox://, hugepages://
// Ensure that host path is not sandbox://, hugepages://, \\.\pipe, uvm://
if strings.HasPrefix(hostPath, guestpath.SandboxMountPrefix) ||
strings.HasPrefix(hostPath, guestpath.HugePagesMountPrefix) ||
strings.HasPrefix(hostPath, guestpath.PipePrefix) {
strings.HasPrefix(hostPath, guestpath.PipePrefix) ||
strings.HasPrefix(hostPath, guestpath.UVMMountPrefix) {
return false
} else {
// hcsshim treats mountType == "" as a normal directory mount
Expand Down
3 changes: 3 additions & 0 deletions internal/guestpath/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const (
// BlockDevMountPrefix is mount prefix used in container spec to mark a
// block-device mount.
BlockDevMountPrefix = "blockdev://"
// UVMMountPrefix is mount prefix used in container spec to mark a UVM mount
// into container.
UVMMountPrefix = "uvm://"
// PipePrefix is the mount prefix used in container spec to mark a named pipe
PipePrefix = `\\.\pipe`
// LCOWMountPathPrefixFmt is the path format in the LCOW UVM where
Expand Down
10 changes: 9 additions & 1 deletion internal/hcsoci/hcsdoc_wcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,20 @@ func createMountsConfig(ctx context.Context, coi *createOptionsInternal) (*mount
}
mdv2.HostPath = src
} else if mount.Type == MountTypeVirtualDisk || mount.Type == MountTypePhysicalDisk || mount.Type == MountTypeExtensibleVirtualDisk {
// For v2 schema containers, any disk mounts will be part of coi.additionalMounts.
// For v2 schema containers, any disk mounts will be part of coi.windowsAdditionalMounts.
// For v1 schema containers, we don't even get here, since there is no HostingSystem.
continue
} else if strings.HasPrefix(mount.Source, guestpath.SandboxMountPrefix) {
// Convert to the path in the guest that was asked for.
mdv2.HostPath = convertToWCOWSandboxMountPath(mount.Source)
} else if strings.HasPrefix(mount.Source, guestpath.UVMMountPrefix) {
if uvm.IsPipe(strings.TrimPrefix(mount.Source, guestpath.UVMMountPrefix)) {
src, dst := uvm.GetContainerPipeMapping(coi.HostingSystem, mount)
config.mpsv1 = append(config.mpsv1, schema1.MappedPipe{HostPath: src, ContainerPipeName: dst})
config.mpsv2 = append(config.mpsv2, hcsschema.MappedPipe{HostPath: src, ContainerPipeName: dst})
} else {
return nil, fmt.Errorf("unsupported UVM mount source: %s", mount.Source)
}
} else {
// vsmb mount
uvmPath, err := coi.HostingSystem.GetVSMBUvmPath(ctx, mount.Source, readOnly)
Expand Down
3 changes: 2 additions & 1 deletion internal/hcsoci/resources_wcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ func setupMounts(ctx context.Context, coi *createOptionsInternal, r *resources.R
} else if strings.HasPrefix(mount.Source, guestpath.SandboxMountPrefix) {
// Mounts that map to a path in the UVM are specified with a 'sandbox://' prefix.
//
// Example: sandbox:///a/dirInUvm destination:C:\\dirInContainer.
// Example:
// - sandbox:///a/dirInUvm destination:C:\\dirInContainer.
//
// so first convert to a path in the sandboxmounts path itself.
sandboxPath := convertToWCOWSandboxMountPath(mount.Source)
Expand Down
24 changes: 21 additions & 3 deletions internal/uvm/pipes.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (
"fmt"
"strings"

"github.com/Microsoft/hcsshim/internal/guestpath"
"github.com/Microsoft/hcsshim/internal/hcs/resourcepaths"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
"github.com/Microsoft/hcsshim/internal/protocol/guestrequest"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-spec/specs-go"
)

const pipePrefix = `\\.\pipe\`
Expand Down Expand Up @@ -54,18 +55,35 @@ func (uvm *UtilityVM) RemovePipe(ctx context.Context, hostPath string) error {
return nil
}

// IsPipe returns true if the given path references a named pipe.
// UVMNamedPipe returns a named pipe in UVM, which will be shared across containers.
func (uvm *UtilityVM) UVMNamedPipe(hostPath string) string {
podID := strings.TrimSuffix(uvm.id, "@vm")
if uvm.operatingSystem == "windows" {
uvmPipeName := strings.TrimPrefix(hostPath, pipePrefix)
return fmt.Sprintf(`%s%s\%s`, pipePrefix, podID, uvmPipeName)
}
// TODO (anmaxvl): LCOW doesn't support UVM named pipes at the moment
return hostPath
}

// IsPipe returns true if the given path references a named pipe. The pipe can be:
// - host named pipe shared via VSMB
func IsPipe(hostPath string) bool {
return strings.HasPrefix(hostPath, pipePrefix)
}

// GetContainerPipeMapping returns the source and destination to use for a given
// pipe mount in a container.
// The pipe mount can be either a host pipe shared via VSMB or a UVM pipe.
func GetContainerPipeMapping(uvm *UtilityVM, mount specs.Mount) (src string, dst string) {
if uvm == nil {
src = mount.Source
} else {
src = vsmbSharePrefix + `IPC$\` + strings.TrimPrefix(mount.Source, pipePrefix)
if uvmPipe, ok := strings.CutPrefix(mount.Source, guestpath.UVMMountPrefix); ok {
src = uvm.UVMNamedPipe(uvmPipe)
} else {
src = vsmbSharePrefix + `IPC$\` + strings.TrimPrefix(mount.Source, pipePrefix)
}
}
dst = strings.TrimPrefix(mount.Destination, pipePrefix)
return src, dst
Expand Down