Skip to content
Open
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
42 changes: 42 additions & 0 deletions internal/controller/network/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//go:build windows

// Package network provides a controller for managing the network lifecycle of a pod
// running inside a Utility VM (UVM).
//
// It handles attaching an HCN namespace and its endpoints to the guest VM,
// and tearing them down on pod removal. The [Controller] interface is the
// primary entry point, with [Manager] as its concrete implementation.
//
// # Lifecycle
//
// A network follows the state machine below.
//
// ┌────────────────────┐
// │ StateNotConfigured │
// └───┬────────────┬───┘
// Setup ok │ │ Setup fails
// ▼ ▼
// ┌─────────────────┐ ┌──────────────┐
// │ StateConfigured │ │ StateInvalid │
// └────────┬────────┘ └──────┬───────┘
// │ Teardown │ Teardown
// ▼ ▼
// ┌─────────────────────────────────────┐
// │ StateTornDown │
// └─────────────────────────────────────┘
//
// State descriptions:
//
// - [StateNotConfigured]: initial state; no namespace or NICs have been configured.
// - [StateConfigured]: after [Controller.Setup] succeeds; the HCN namespace is attached
// and all endpoints are wired up inside the guest.
// - [StateInvalid]: entered when [Controller.Setup] fails mid-way; best-effort
// cleanup should be performed via [Controller.Teardown].
// - [StateTornDown]: terminal state reached after [Controller.Teardown] completes.
//
// # Platform Variants
//
// Guest-side operations differ between LCOW and WCOW and are implemented in
// platform-specific source files selected via build tags
// (default for LCOW shim, "wcow" tag for WCOW shim).
package network
54 changes: 54 additions & 0 deletions internal/controller/network/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//go:build windows

package network

import (
"context"

"github.com/Microsoft/hcsshim/hcn"
)

// SetStateForTest sets the Manager's state. Test-only.
func (m *Manager) SetStateForTest(s State) {
m.netState = s
}

// StateForTest returns the Manager's current state. Test-only.
func (m *Manager) StateForTest() State {
return m.netState
}

// SetNamespaceIDForTest sets the namespace ID on the Manager. Test-only.
func (m *Manager) SetNamespaceIDForTest(id string) {
m.namespaceID = id
}

// AddEndpointForTest adds a NIC→endpoint mapping to the internal tracking map. Test-only.
func (m *Manager) AddEndpointForTest(nicID string, ep *hcn.HostComputeEndpoint) {
m.vmEndpoints[nicID] = ep
}

// EndpointsForTest returns the current vmEndpoints map. Test-only.
func (m *Manager) EndpointsForTest() map[string]*hcn.HostComputeEndpoint {
return m.vmEndpoints
}

// IsNamespaceSupportedForTest returns the cached namespace-support flag. Test-only.
func (m *Manager) IsNamespaceSupportedForTest() bool {
return m.isNamespaceSupportedByGuest
}

// AddEndpointToGuestNamespaceForTest exposes addEndpointToGuestNamespace for testing.
func (m *Manager) AddEndpointToGuestNamespaceForTest(ctx context.Context, nicID string, endpoint *hcn.HostComputeEndpoint, policyBasedRouting bool) error {
return m.addEndpointToGuestNamespace(ctx, nicID, endpoint, policyBasedRouting)
}

// RemoveEndpointFromGuestNamespaceForTest exposes removeEndpointFromGuestNamespace for testing.
func (m *Manager) RemoveEndpointFromGuestNamespaceForTest(ctx context.Context, nicID string, endpoint *hcn.HostComputeEndpoint) error {
return m.removeEndpointFromGuestNamespace(ctx, nicID, endpoint)
}

// AddNetNSInsideGuestForTest exposes addNetNSInsideGuest for testing.
func (m *Manager) AddNetNSInsideGuestForTest(ctx context.Context, ns *hcn.HostComputeNamespace) error {
return m.addNetNSInsideGuest(ctx, ns)
}
42 changes: 42 additions & 0 deletions internal/controller/network/helpers_wcow_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//go:build windows && wcow

package network_test

import (
"errors"
"testing"

"github.com/Microsoft/hcsshim/internal/controller/network"
netmock "github.com/Microsoft/hcsshim/internal/controller/network/mock"
gcsmock "github.com/Microsoft/hcsshim/internal/gcs/mock"

"go.uber.org/mock/gomock"
)

var errTest = errors.New("test error")

// newWCOWTestManager creates a Manager wired with WCOW mock dependencies.
func newWCOWTestManager(t *testing.T, ctrl *gomock.Controller, namespaceSupportEnabled bool) (
*network.Manager,
*netmock.MockvmNetworkManager,
*netmock.MocklinuxGuestNetworkManager,
*netmock.MockwindowsGuestNetworkManager,
) {
t.Helper()

mockVM := netmock.NewMockvmNetworkManager(ctrl)
mockLinuxGuest := netmock.NewMocklinuxGuestNetworkManager(ctrl)
mockWinGuest := netmock.NewMockwindowsGuestNetworkManager(ctrl)
mockCaps := netmock.NewMockcapabilitiesProvider(ctrl)

if namespaceSupportEnabled {
mockGuestCaps := gcsmock.NewMockGuestDefinedCapabilities(ctrl)
mockGuestCaps.EXPECT().IsNamespaceAddRequestSupported().Return(true)
mockCaps.EXPECT().Capabilities().Return(mockGuestCaps)
} else {
mockCaps.EXPECT().Capabilities().Return(nil)
}

m := network.New(mockVM, mockLinuxGuest, mockWinGuest, mockCaps)
return m, mockVM, mockLinuxGuest, mockWinGuest
}
76 changes: 76 additions & 0 deletions internal/controller/network/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//go:build windows

package network

//go:generate go tool mockgen -source=interface.go -build_constraint=windows -package=mock -destination=mock/mock_network.go

import (
"context"

"github.com/Microsoft/hcsshim/hcn"
"github.com/Microsoft/hcsshim/internal/gcs"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
"github.com/Microsoft/hcsshim/internal/protocol/guestrequest"
"github.com/Microsoft/hcsshim/internal/protocol/guestresource"
)

// Controller manages the network lifecycle for a single pod running inside a UVM.
type Controller interface {
// Setup attaches the HCN namespace and its endpoints to the guest VM.
Setup(ctx context.Context, opts *SetupOptions) error

// Teardown removes all guest-side NICs and the network namespace from the VM.
// It is idempotent: calling it on an already torn-down or unconfigured network is a no-op.
Teardown(ctx context.Context) error
}

// SetupOptions holds the configuration required to set up the network for a pod.
type SetupOptions struct {
// NetworkNamespace is the HCN namespace ID to attach to the guest.
NetworkNamespace string

// PolicyBasedRouting controls whether policy-based routing is configured
// for the endpoints added to the guest. Only relevant for LCOW.
PolicyBasedRouting bool
}

// capabilitiesProvider is a narrow interface satisfied by guestmanager.Manager.
// It exists so callers pass the guest manager scoped only to Capabilities(),
// avoiding a hard dependency on the full guestmanager.Manager interface here.
type capabilitiesProvider interface {
Capabilities() gcs.GuestDefinedCapabilities
}

// vmNetworkManager manages adding and removing network adapters for a Utility VM.
// Implemented by vmmanager.UtilityVM.
type vmNetworkManager interface {
// AddNIC adds a network adapter to the Utility VM. `nicID` should be a string representation of a
// Windows GUID.
AddNIC(ctx context.Context, nicID string, settings *hcsschema.NetworkAdapter) error

// RemoveNIC removes a network adapter from the Utility VM. `nicID` should be a string representation of a
// Windows GUID.
RemoveNIC(ctx context.Context, nicID string, settings *hcsschema.NetworkAdapter) error
}

// linuxGuestNetworkManager exposes linux guest network operations.
// Implemented by guestmanager.Guest.
type linuxGuestNetworkManager interface {
// AddLCOWNetworkInterface adds a network interface to the LCOW guest.
AddLCOWNetworkInterface(ctx context.Context, settings *guestresource.LCOWNetworkAdapter) error
// RemoveLCOWNetworkInterface removes a network interface from the LCOW guest.
RemoveLCOWNetworkInterface(ctx context.Context, settings *guestresource.LCOWNetworkAdapter) error
}

// windowsGuestNetworkManager exposes windows guest network operations.
// Implemented by guestmanager.Guest.
type windowsGuestNetworkManager interface {
// AddNetworkNamespace adds a network namespace to the WCOW guest.
AddNetworkNamespace(ctx context.Context, settings *hcn.HostComputeNamespace) error
// RemoveNetworkNamespace removes a network namespace from the WCOW guest.
RemoveNetworkNamespace(ctx context.Context, settings *hcn.HostComputeNamespace) error
// AddNetworkInterface adds a network interface to the WCOW guest.
AddNetworkInterface(ctx context.Context, adapterID string, requestType guestrequest.RequestType, settings *hcn.HostComputeEndpoint) error
// RemoveNetworkInterface removes a network interface from the WCOW guest.
RemoveNetworkInterface(ctx context.Context, adapterID string, requestType guestrequest.RequestType, settings *hcn.HostComputeEndpoint) error
}
Loading
Loading