Skip to content

Commit

Permalink
feature: cross-container named pipes
Browse files Browse the repository at this point in the history
Add support for cross-container pipes for Xenon WCOW
containers.

Extend the logic of `IsPipe` and `GetContainerPipeMapping` to
also handle cross-container pipes within the UVM. The syntax
is the same as for sandbox mounts:

```
{
  "host_path": "sandbox://\\\\.\\pipe\\uvmPipe",
  "container_path": "\\\\.\\pipe\\containerPipe"
}
```

Containers sharing the pipe need to have the same "host_path".

Signed-off-by: Maksim An <maksiman@microsoft.com>
  • Loading branch information
anmaxvl committed Jan 17, 2025
1 parent 20e8795 commit e1ff3a9
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 5 deletions.
2 changes: 1 addition & 1 deletion internal/hcsoci/hcsdoc_wcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ 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) {
Expand Down
9 changes: 8 additions & 1 deletion internal/hcsoci/resources_wcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,16 @@ 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.
// - sandbox://\\.\pipe\uvmNamedPipe destination: \\.\pipe\containerNamedPipe
//
// so first convert to a path in the sandboxmounts path itself.
if uvm.IsPipe(mount.Source) {
// When mapping UVM named pipe into container, we don't need to do anything else, since it'll be
// handled via `createMountsConfig`.
continue
}
sandboxPath := convertToWCOWSandboxMountPath(mount.Source)

// Now we need to exec a process in the vm that will make these directories as theres
Expand Down
27 changes: 24 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,38 @@ func (uvm *UtilityVM) RemovePipe(ctx context.Context, hostPath string) error {
return nil
}

// IsPipe returns true if the given path references a named pipe.
// SandboxNamedPipe returns a named pipe in UVM, which will be shared across containers.
func (uvm *UtilityVM) SandboxNamedPipe(hostPath string) string {
podID := strings.TrimPrefix(uvm.id, "@vm")
if uvm.operatingSystem == "windows" {
uvmPipeName := strings.TrimPrefix(hostPath, pipePrefix)
return fmt.Sprintf(`%s%s\%s`, pipePrefix, podID, uvmPipeName)
}
return fmt.Sprintf("%s-%s", podID, hostPath)
}

// IsPipe returns true if the given path references a named pipe. The pipe can be:
// - host named pipe shared via VSMB
// - UVM named pipe
func IsPipe(hostPath string) bool {
if sandboxMount, ok := strings.CutPrefix(hostPath, guestpath.SandboxMountPrefix); ok {
return strings.HasPrefix(sandboxMount, pipePrefix)
}
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.SandboxMountPrefix); ok {
src = uvm.SandboxNamedPipe(uvmPipe)
} else {
src = vsmbSharePrefix + `IPC$\` + strings.TrimPrefix(mount.Source, pipePrefix)
}
}
dst = strings.TrimPrefix(mount.Destination, pipePrefix)
return src, dst
Expand Down

0 comments on commit e1ff3a9

Please sign in to comment.