From cb84b0fb02ce4f118b9c7f4ee6b8af7ef798fb33 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Tue, 3 Jan 2023 09:03:39 +0000 Subject: [PATCH 1/4] katautils: run prestart hooks after starting VM So that we can pass the hypervisor pid to the hook instead of the runtime process's. Signed-off-by: Peng Tao --- src/runtime/pkg/katautils/create.go | 30 ++++++++++++++++++++--------- src/runtime/pkg/katautils/hook.go | 12 +++++++++++- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/runtime/pkg/katautils/create.go b/src/runtime/pkg/katautils/create.go index ffcaa07154..d2c9c69cfb 100644 --- a/src/runtime/pkg/katautils/create.go +++ b/src/runtime/pkg/katautils/create.go @@ -162,6 +162,21 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec specs.Spec, runtimeCo ociSpec.Annotations["nerdctl/network-namespace"] = sandboxConfig.NetworkConfig.NetworkID sandboxConfig.Annotations["nerdctl/network-namespace"] = ociSpec.Annotations["nerdctl/network-namespace"] + sandbox, err := vci.CreateSandbox(ctx, sandboxConfig) + if err != nil { + return nil, vc.Process{}, err + } + + hid, err := sandbox.GetHypervisorPid() + if err != nil { + return nil, vc.Process{}, err + } + ctx = context.WithValue(ctx, "hypervisor-pid", hid) + + sid := sandbox.ID() + kataUtilsLogger = kataUtilsLogger.WithField("sandbox", sid) + katatrace.AddTags(span, "sandbox_id", sid) + // Run pre-start OCI hooks, in the runtime namespace. if err := PreStartHooks(ctx, ociSpec, containerID, bundlePath); err != nil { return nil, vc.Process{}, err @@ -172,15 +187,6 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec specs.Spec, runtimeCo return nil, vc.Process{}, err } - sandbox, err := vci.CreateSandbox(ctx, sandboxConfig) - if err != nil { - return nil, vc.Process{}, err - } - - sid := sandbox.ID() - kataUtilsLogger = kataUtilsLogger.WithField("sandbox", sid) - katatrace.AddTags(span, "sandbox_id", sid) - containers := sandbox.GetAllContainers() if len(containers) != 1 { return nil, vc.Process{}, fmt.Errorf("BUG: Container list from sandbox is wrong, expecting only one container, found %d containers", len(containers)) @@ -255,6 +261,12 @@ func CreateContainer(ctx context.Context, sandbox vc.VCSandbox, ociSpec specs.Sp return vc.Process{}, err } + hid, err := sandbox.GetHypervisorPid() + if err != nil { + return vc.Process{}, err + } + ctx = context.WithValue(ctx, HypervisorPidKey{}, hid) + // Run pre-start OCI hooks. err = EnterNetNS(sandbox.GetNetNs(), func() error { return PreStartHooks(ctx, ociSpec, containerID, bundlePath) diff --git a/src/runtime/pkg/katautils/hook.go b/src/runtime/pkg/katautils/hook.go index 50ac95cb85..02a4f75973 100644 --- a/src/runtime/pkg/katautils/hook.go +++ b/src/runtime/pkg/katautils/hook.go @@ -28,6 +28,8 @@ var hookTracingTags = map[string]string{ "subsystem": "hook", } +type HypervisorPidKey struct{} + // Logger returns a logrus logger appropriate for logging hook messages func hookLogger() *logrus.Entry { return kataUtilsLogger.WithField("subsystem", "hook") @@ -38,8 +40,16 @@ func runHook(ctx context.Context, spec specs.Spec, hook specs.Hook, cid, bundleP defer span.End() katatrace.AddTags(span, "path", hook.Path, "args", hook.Args) + pid, ok := ctx.Value(HypervisorPidKey{}).(int) + if !ok || pid == 0 { + hookLogger().Info("no hypervisor pid") + + pid = syscallWrapper.Gettid() + } + hookLogger().Infof("hypervisor pid %v", pid) + state := specs.State{ - Pid: syscallWrapper.Gettid(), + Pid: pid, Bundle: bundlePath, ID: cid, Annotations: spec.Annotations, From 578a9c25f05c53525319a968f379ca718e8c9db7 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Tue, 3 Jan 2023 09:43:45 +0000 Subject: [PATCH 2/4] vc: rescan network endpoints after running prestart hooks Moby relies on the prestart hooks to configure network endpoints. We should rescan the netns after running them so that the newly added endpoints can be found and plugged to the guest. Fixes: #5941 Signed-off-by: Peng Tao --- src/runtime/pkg/katautils/create.go | 30 +++++++++----------- src/runtime/pkg/katautils/hook.go | 5 ++-- src/runtime/virtcontainers/api.go | 8 +++--- src/runtime/virtcontainers/implementation.go | 4 +-- src/runtime/virtcontainers/interfaces.go | 2 +- src/runtime/virtcontainers/sandbox.go | 22 ++++++++++++-- 6 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/runtime/pkg/katautils/create.go b/src/runtime/pkg/katautils/create.go index d2c9c69cfb..3c3bf05c8d 100644 --- a/src/runtime/pkg/katautils/create.go +++ b/src/runtime/pkg/katautils/create.go @@ -162,31 +162,27 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec specs.Spec, runtimeCo ociSpec.Annotations["nerdctl/network-namespace"] = sandboxConfig.NetworkConfig.NetworkID sandboxConfig.Annotations["nerdctl/network-namespace"] = ociSpec.Annotations["nerdctl/network-namespace"] - sandbox, err := vci.CreateSandbox(ctx, sandboxConfig) - if err != nil { - return nil, vc.Process{}, err - } + sandbox, err := vci.CreateSandbox(ctx, sandboxConfig, func(ctx context.Context) error { + // Run pre-start OCI hooks, in the runtime namespace. + if err := PreStartHooks(ctx, ociSpec, containerID, bundlePath); err != nil { + return err + } - hid, err := sandbox.GetHypervisorPid() + // Run create runtime OCI hooks, in the runtime namespace. + if err := CreateRuntimeHooks(ctx, ociSpec, containerID, bundlePath); err != nil { + return err + } + + return nil + }) if err != nil { return nil, vc.Process{}, err } - ctx = context.WithValue(ctx, "hypervisor-pid", hid) sid := sandbox.ID() kataUtilsLogger = kataUtilsLogger.WithField("sandbox", sid) katatrace.AddTags(span, "sandbox_id", sid) - // Run pre-start OCI hooks, in the runtime namespace. - if err := PreStartHooks(ctx, ociSpec, containerID, bundlePath); err != nil { - return nil, vc.Process{}, err - } - - // Run create runtime OCI hooks, in the runtime namespace. - if err := CreateRuntimeHooks(ctx, ociSpec, containerID, bundlePath); err != nil { - return nil, vc.Process{}, err - } - containers := sandbox.GetAllContainers() if len(containers) != 1 { return nil, vc.Process{}, fmt.Errorf("BUG: Container list from sandbox is wrong, expecting only one container, found %d containers", len(containers)) @@ -265,7 +261,7 @@ func CreateContainer(ctx context.Context, sandbox vc.VCSandbox, ociSpec specs.Sp if err != nil { return vc.Process{}, err } - ctx = context.WithValue(ctx, HypervisorPidKey{}, hid) + ctx = context.WithValue(ctx, vc.HypervisorPidKey{}, hid) // Run pre-start OCI hooks. err = EnterNetNS(sandbox.GetNetNs(), func() error { diff --git a/src/runtime/pkg/katautils/hook.go b/src/runtime/pkg/katautils/hook.go index 02a4f75973..8ed6361ae1 100644 --- a/src/runtime/pkg/katautils/hook.go +++ b/src/runtime/pkg/katautils/hook.go @@ -17,6 +17,7 @@ import ( "github.com/kata-containers/kata-containers/src/runtime/pkg/katautils/katatrace" syscallWrapper "github.com/kata-containers/kata-containers/src/runtime/pkg/syscall" + vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers" "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" ) @@ -28,8 +29,6 @@ var hookTracingTags = map[string]string{ "subsystem": "hook", } -type HypervisorPidKey struct{} - // Logger returns a logrus logger appropriate for logging hook messages func hookLogger() *logrus.Entry { return kataUtilsLogger.WithField("subsystem", "hook") @@ -40,7 +39,7 @@ func runHook(ctx context.Context, spec specs.Spec, hook specs.Hook, cid, bundleP defer span.End() katatrace.AddTags(span, "path", hook.Path, "args", hook.Args) - pid, ok := ctx.Value(HypervisorPidKey{}).(int) + pid, ok := ctx.Value(vc.HypervisorPidKey{}).(int) if !ok || pid == 0 { hookLogger().Info("no hypervisor pid") diff --git a/src/runtime/virtcontainers/api.go b/src/runtime/virtcontainers/api.go index 437c926a7e..1927d4d077 100644 --- a/src/runtime/virtcontainers/api.go +++ b/src/runtime/virtcontainers/api.go @@ -44,16 +44,16 @@ func SetLogger(ctx context.Context, logger *logrus.Entry) { // CreateSandbox is the virtcontainers sandbox creation entry point. // CreateSandbox creates a sandbox and its containers. It does not start them. -func CreateSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factory) (VCSandbox, error) { +func CreateSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factory, prestartHookFunc func(context.Context) error) (VCSandbox, error) { span, ctx := katatrace.Trace(ctx, virtLog, "CreateSandbox", apiTracingTags) defer span.End() - s, err := createSandboxFromConfig(ctx, sandboxConfig, factory) + s, err := createSandboxFromConfig(ctx, sandboxConfig, factory, prestartHookFunc) return s, err } -func createSandboxFromConfig(ctx context.Context, sandboxConfig SandboxConfig, factory Factory) (_ *Sandbox, err error) { +func createSandboxFromConfig(ctx context.Context, sandboxConfig SandboxConfig, factory Factory, prestartHookFunc func(context.Context) error) (_ *Sandbox, err error) { span, ctx := katatrace.Trace(ctx, virtLog, "createSandboxFromConfig", apiTracingTags) defer span.End() @@ -88,7 +88,7 @@ func createSandboxFromConfig(ctx context.Context, sandboxConfig SandboxConfig, f } // Start the VM - if err = s.startVM(ctx); err != nil { + if err = s.startVM(ctx, prestartHookFunc); err != nil { return nil, err } diff --git a/src/runtime/virtcontainers/implementation.go b/src/runtime/virtcontainers/implementation.go index 177797ebd2..f48e939e41 100644 --- a/src/runtime/virtcontainers/implementation.go +++ b/src/runtime/virtcontainers/implementation.go @@ -31,8 +31,8 @@ func (impl *VCImpl) SetFactory(ctx context.Context, factory Factory) { } // CreateSandbox implements the VC function of the same name. -func (impl *VCImpl) CreateSandbox(ctx context.Context, sandboxConfig SandboxConfig) (VCSandbox, error) { - return CreateSandbox(ctx, sandboxConfig, impl.factory) +func (impl *VCImpl) CreateSandbox(ctx context.Context, sandboxConfig SandboxConfig, hookFunc func(context.Context) error) (VCSandbox, error) { + return CreateSandbox(ctx, sandboxConfig, impl.factory, hookFunc) } // CleanupContainer is used by shimv2 to stop and delete a container exclusively, once there is no container diff --git a/src/runtime/virtcontainers/interfaces.go b/src/runtime/virtcontainers/interfaces.go index 7664f0281f..492d3f35a7 100644 --- a/src/runtime/virtcontainers/interfaces.go +++ b/src/runtime/virtcontainers/interfaces.go @@ -23,7 +23,7 @@ type VC interface { SetLogger(ctx context.Context, logger *logrus.Entry) SetFactory(ctx context.Context, factory Factory) - CreateSandbox(ctx context.Context, sandboxConfig SandboxConfig) (VCSandbox, error) + CreateSandbox(ctx context.Context, sandboxConfig SandboxConfig, hookFunc func(context.Context) error) (VCSandbox, error) CleanupContainer(ctx context.Context, sandboxID, containerID string, force bool) error } diff --git a/src/runtime/virtcontainers/sandbox.go b/src/runtime/virtcontainers/sandbox.go index 025537fed9..9f87cc2ffe 100644 --- a/src/runtime/virtcontainers/sandbox.go +++ b/src/runtime/virtcontainers/sandbox.go @@ -92,6 +92,9 @@ var ( errSandboxNotRunning = errors.New("Sandbox not running") ) +// HypervisorPidKey is the context key for hypervisor pid +type HypervisorPidKey struct{} + // SandboxStatus describes a sandbox status. type SandboxStatus struct { ContainersStatus []ContainerStatus @@ -1194,7 +1197,7 @@ func (s *Sandbox) cleanSwap(ctx context.Context) { } // startVM starts the VM. -func (s *Sandbox) startVM(ctx context.Context) (err error) { +func (s *Sandbox) startVM(ctx context.Context, prestartHookFunc func(context.Context) error) (err error) { span, ctx := katatrace.Trace(ctx, s.Logger(), "startVM", sandboxTracingTags, map[string]string{"sandbox_id": s.id}) defer span.End() @@ -1234,9 +1237,24 @@ func (s *Sandbox) startVM(ctx context.Context) (err error) { return err } + if prestartHookFunc != nil { + hid, err := s.GetHypervisorPid() + if err != nil { + return err + } + s.Logger().Infof("hypervisor pid is %v", hid) + ctx = context.WithValue(ctx, HypervisorPidKey{}, hid) + + if err := prestartHookFunc(ctx); err != nil { + return err + } + } + // In case of vm factory, network interfaces are hotplugged // after vm is started. - if s.factory != nil { + // In case of prestartHookFunc, network config might have been changed. + // We need to rescan and handle the change. + if s.factory != nil || prestartHookFunc != nil { if _, err := s.network.AddEndpoints(ctx, s, nil, true); err != nil { return err } From d085389127d08aa840a1fd6c3731ad928e9335d4 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Tue, 3 Jan 2023 10:13:20 +0000 Subject: [PATCH 3/4] vc: fix up UT for CreateSandbox API change Need to adapt the UT as well. Signed-off-by: Peng Tao --- src/runtime/pkg/containerd-shim-v2/create_test.go | 2 +- src/runtime/pkg/katautils/create_test.go | 2 +- src/runtime/virtcontainers/api_test.go | 10 +++++----- src/runtime/virtcontainers/example_pod_run_test.go | 2 +- src/runtime/virtcontainers/pkg/vcmock/mock.go | 4 ++-- src/runtime/virtcontainers/pkg/vcmock/mock_test.go | 8 ++++---- src/runtime/virtcontainers/pkg/vcmock/types.go | 2 +- src/runtime/virtcontainers/sandbox_test.go | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/runtime/pkg/containerd-shim-v2/create_test.go b/src/runtime/pkg/containerd-shim-v2/create_test.go index 121d5ea4db..75638b5186 100644 --- a/src/runtime/pkg/containerd-shim-v2/create_test.go +++ b/src/runtime/pkg/containerd-shim-v2/create_test.go @@ -41,7 +41,7 @@ func TestCreateSandboxSuccess(t *testing.T) { }, } - testingImpl.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) { + testingImpl.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig, hookFunc func(context.Context) error) (vc.VCSandbox, error) { return sandbox, nil } diff --git a/src/runtime/pkg/katautils/create_test.go b/src/runtime/pkg/katautils/create_test.go index b1e4cf2a90..2608003784 100644 --- a/src/runtime/pkg/katautils/create_test.go +++ b/src/runtime/pkg/katautils/create_test.go @@ -274,7 +274,7 @@ func TestCreateSandboxAnnotations(t *testing.T) { rootFs := vc.RootFs{Mounted: true} - testingImpl.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) { + testingImpl.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig, hookFunc func(context.Context) error) (vc.VCSandbox, error) { return &vcmock.Sandbox{ MockID: testSandboxID, MockContainers: []*vcmock.Container{ diff --git a/src/runtime/virtcontainers/api_test.go b/src/runtime/virtcontainers/api_test.go index 0268ab1259..0af9aec5d6 100644 --- a/src/runtime/virtcontainers/api_test.go +++ b/src/runtime/virtcontainers/api_test.go @@ -145,7 +145,7 @@ func TestCreateSandboxNoopAgentSuccessful(t *testing.T) { config := newTestSandboxConfigNoop() ctx := WithNewAgentFunc(context.Background(), newMockAgent) - p, err := CreateSandbox(ctx, config, nil) + p, err := CreateSandbox(ctx, config, nil, nil) assert.NoError(err) assert.NotNil(p) @@ -178,7 +178,7 @@ func TestCreateSandboxKataAgentSuccessful(t *testing.T) { defer hybridVSockTTRPCMock.Stop() ctx := WithNewAgentFunc(context.Background(), newMockAgent) - p, err := CreateSandbox(ctx, config, nil) + p, err := CreateSandbox(ctx, config, nil, nil) assert.NoError(err) assert.NotNil(p) @@ -199,7 +199,7 @@ func TestCreateSandboxFailing(t *testing.T) { config := SandboxConfig{} ctx := WithNewAgentFunc(context.Background(), newMockAgent) - p, err := CreateSandbox(ctx, config, nil) + p, err := CreateSandbox(ctx, config, nil, nil) assert.Error(err) assert.Nil(p.(*Sandbox)) } @@ -227,7 +227,7 @@ func createAndStartSandbox(ctx context.Context, config SandboxConfig) (sandbox V err error) { // Create sandbox - sandbox, err = CreateSandbox(ctx, config, nil) + sandbox, err = CreateSandbox(ctx, config, nil, nil) if sandbox == nil || err != nil { return nil, "", err } @@ -260,7 +260,7 @@ func TestReleaseSandbox(t *testing.T) { config := newTestSandboxConfigNoop() ctx := WithNewAgentFunc(context.Background(), newMockAgent) - s, err := CreateSandbox(ctx, config, nil) + s, err := CreateSandbox(ctx, config, nil, nil) assert.NoError(t, err) assert.NotNil(t, s) diff --git a/src/runtime/virtcontainers/example_pod_run_test.go b/src/runtime/virtcontainers/example_pod_run_test.go index cc12ddaed7..79706b0a2e 100644 --- a/src/runtime/virtcontainers/example_pod_run_test.go +++ b/src/runtime/virtcontainers/example_pod_run_test.go @@ -64,7 +64,7 @@ func Example_createAndStartSandbox() { } // Create the sandbox - s, err := vc.CreateSandbox(context.Background(), sandboxConfig, nil) + s, err := vc.CreateSandbox(context.Background(), sandboxConfig, nil, nil) if err != nil { fmt.Printf("Could not create sandbox: %s", err) return diff --git a/src/runtime/virtcontainers/pkg/vcmock/mock.go b/src/runtime/virtcontainers/pkg/vcmock/mock.go index 3b18151669..39305e244e 100644 --- a/src/runtime/virtcontainers/pkg/vcmock/mock.go +++ b/src/runtime/virtcontainers/pkg/vcmock/mock.go @@ -42,9 +42,9 @@ func (m *VCMock) SetFactory(ctx context.Context, factory vc.Factory) { } // CreateSandbox implements the VC function of the same name. -func (m *VCMock) CreateSandbox(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) { +func (m *VCMock) CreateSandbox(ctx context.Context, sandboxConfig vc.SandboxConfig, hookFunc func(context.Context) error) (vc.VCSandbox, error) { if m.CreateSandboxFunc != nil { - return m.CreateSandboxFunc(ctx, sandboxConfig) + return m.CreateSandboxFunc(ctx, sandboxConfig, hookFunc) } return nil, fmt.Errorf("%s: %s (%+v): sandboxConfig: %v", mockErrorPrefix, getSelf(), m, sandboxConfig) diff --git a/src/runtime/virtcontainers/pkg/vcmock/mock_test.go b/src/runtime/virtcontainers/pkg/vcmock/mock_test.go index 9043b168da..7558b8d1b0 100644 --- a/src/runtime/virtcontainers/pkg/vcmock/mock_test.go +++ b/src/runtime/virtcontainers/pkg/vcmock/mock_test.go @@ -120,22 +120,22 @@ func TestVCMockCreateSandbox(t *testing.T) { assert.Nil(m.CreateSandboxFunc) ctx := context.Background() - _, err := m.CreateSandbox(ctx, vc.SandboxConfig{}) + _, err := m.CreateSandbox(ctx, vc.SandboxConfig{}, nil) assert.Error(err) assert.True(IsMockError(err)) - m.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) { + m.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig, hookFunc func(context.Context) error) (vc.VCSandbox, error) { return &Sandbox{}, nil } - sandbox, err := m.CreateSandbox(ctx, vc.SandboxConfig{}) + sandbox, err := m.CreateSandbox(ctx, vc.SandboxConfig{}, nil) assert.NoError(err) assert.Equal(sandbox, &Sandbox{}) // reset m.CreateSandboxFunc = nil - _, err = m.CreateSandbox(ctx, vc.SandboxConfig{}) + _, err = m.CreateSandbox(ctx, vc.SandboxConfig{}, nil) assert.Error(err) assert.True(IsMockError(err)) } diff --git a/src/runtime/virtcontainers/pkg/vcmock/types.go b/src/runtime/virtcontainers/pkg/vcmock/types.go index 05a0a98592..16b811cd52 100644 --- a/src/runtime/virtcontainers/pkg/vcmock/types.go +++ b/src/runtime/virtcontainers/pkg/vcmock/types.go @@ -88,6 +88,6 @@ type VCMock struct { SetLoggerFunc func(ctx context.Context, logger *logrus.Entry) SetFactoryFunc func(ctx context.Context, factory vc.Factory) - CreateSandboxFunc func(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) + CreateSandboxFunc func(ctx context.Context, sandboxConfig vc.SandboxConfig, hookFunc func(context.Context) error) (vc.VCSandbox, error) CleanupContainerFunc func(ctx context.Context, sandboxID, containerID string, force bool) error } diff --git a/src/runtime/virtcontainers/sandbox_test.go b/src/runtime/virtcontainers/sandbox_test.go index 59ed24c1aa..3d5154eaea 100644 --- a/src/runtime/virtcontainers/sandbox_test.go +++ b/src/runtime/virtcontainers/sandbox_test.go @@ -1348,7 +1348,7 @@ func TestSandboxCreationFromConfigRollbackFromCreateSandbox(t *testing.T) { // Ensure hypervisor doesn't exist assert.NoError(os.Remove(hConf.HypervisorPath)) - _, err := createSandboxFromConfig(ctx, sConf, nil) + _, err := createSandboxFromConfig(ctx, sConf, nil, nil) // Fail at createSandbox: QEMU path does not exist, it is expected. Then rollback is called assert.Error(err) From 8bb68a9f280579dcbf5ff4244b272391d4a9070e Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Wed, 4 Jan 2023 06:08:10 +0000 Subject: [PATCH 4/4] vc/network: skip existing endpoints when scanning for new ones So that addAllEndpoints() becomes re-entrant and we can use it to scan netns changes. Signed-off-by: Peng Tao --- src/runtime/virtcontainers/network_linux.go | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/runtime/virtcontainers/network_linux.go b/src/runtime/virtcontainers/network_linux.go index 3d9f7b7d2c..30819bb30b 100644 --- a/src/runtime/virtcontainers/network_linux.go +++ b/src/runtime/virtcontainers/network_linux.go @@ -252,6 +252,22 @@ func (n *LinuxNetwork) removeSingleEndpoint(ctx context.Context, s *Sandbox, idx return nil } +func (n *LinuxNetwork) endpointAlreadyAdded(netInfo *NetworkInfo) bool { + for _, ep := range n.eps { + // Existing endpoint + if ep.Name() == netInfo.Iface.Name { + return true + } + pair := ep.NetworkPair() + // Existing virtual endpoints + if pair != nil && (pair.TapInterface.Name == netInfo.Iface.Name || pair.TapInterface.TAPIface.Name == netInfo.Iface.Name || pair.VirtIface.Name == netInfo.Iface.Name) { + return true + } + } + + return false +} + // Scan the networking namespace through netlink and then: // 1. Create the endpoints for the relevant interfaces found there. // 2. Attach them to the VM. @@ -292,6 +308,12 @@ func (n *LinuxNetwork) addAllEndpoints(ctx context.Context, s *Sandbox, hotplug continue } + // Skip any interfaces that are already added + if n.endpointAlreadyAdded(&netInfo) { + networkLogger().WithField("endpoint", netInfo.Iface.Name).Info("already added") + continue + } + if err := doNetNS(n.netNSPath, func(_ ns.NetNS) error { _, err = n.addSingleEndpoint(ctx, s, netInfo, hotplug) return err