Skip to content
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
2 changes: 1 addition & 1 deletion build/components/versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ firmware:
libvirt: v10.9.0
edk2: stable202411
core:
3p-kubevirt: v1.6.2-v12n.23
3p-kubevirt: feat/vm/disable-tap-veth-bridge
3p-containerized-data-importer: v1.60.3-v12n.18
distribution: 2.8.3
package:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ func main() {
os.Exit(1)
}

networkSettings := appconfig.LoadNetworkSettingsFromEnv()

// Get a config to talk to the apiserver
cfg, err := config.GetConfig()
if err != nil {
Expand Down Expand Up @@ -347,7 +349,7 @@ func main() {
}

vmLogger := logger.NewControllerLogger(vm.ControllerName, logLevel, logOutput, logDebugVerbosity, logDebugControllerList)
if err = vm.SetupController(ctx, mgr, virtClient, vmLogger, dvcrSettings, firmwareImage); err != nil {
if err = vm.SetupController(ctx, mgr, virtClient, vmLogger, dvcrSettings, firmwareImage, networkSettings.DisableTapVethBridge); err != nil {
log.Error(err.Error())
os.Exit(1)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ const (

// AnnVMRestartRequested is an annotation on KVVM that represents a request to restart a virtual machine.
AnnVMRestartRequested = AnnAPIGroupV + "/vm-restart-requested"
// AnnDisableTapVethBridge disables tap-veth-bridge wiring for the VMI network setup in KubeVirt.
AnnDisableTapVethBridge = AnnAPIGroupV + "/disable-tap-veth-bridge"

// AnnVMOPWorkloadUpdate is an annotation on vmop that represents a vmop created by workload-updater controller.
AnnVMOPWorkloadUpdate = AnnAPIGroupV + "/workload-update"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2026 Flant JSC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package config

import "os"

const DisableTapVethBridgeVar = "DISABLE_TAP_VETH_BRIDGE"

type NetworkSettings struct {
DisableTapVethBridge bool
}

func LoadNetworkSettingsFromEnv() NetworkSettings {
return NetworkSettings{
DisableTapVethBridge: os.Getenv(DisableTapVethBridgeVar) == "true",
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const (
type KVVMOptions struct {
EnableParavirtualization bool
OsType v1alpha2.OsType
DisableTapVethBridge bool

// These options are for local development mode
DisableHypervSyNIC bool
Expand All @@ -92,6 +93,10 @@ func DefaultOptions(current *v1alpha2.VirtualMachine) KVVMOptions {
}
}

func (b *KVVM) Options() KVVMOptions {
return b.opts
}

func NewEmptyKVVM(name types.NamespacedName, opts KVVMOptions) *KVVM {
return &KVVM{
opts: opts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ func ApplyVirtualMachineSpec(

kvvm.SetUSBMigrationStrategy()
kvvm.SetMetadata(vm.ObjectMeta)
if kvvm.Options().DisableTapVethBridge {
kvvm.SetKVVMIAnnotation(annotations.AnnDisableTapVethBridge, "true")
} else {
kvvm.RemoveKVVMIAnnotation(annotations.AnnDisableTapVethBridge)
}
setNetwork(kvvm, networkSpec)
kvvm.SetTablet("default-0")
kvvm.SetNodeSelector(vm.Spec.NodeSelector, class.Spec.NodeSelector.MatchLabels)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ var _ = Describe("MigratingHandler", func() {
}

reconcile := func() {
h := NewMigratingHandler(vmservice.NewMigrationVolumesService(fakeClient, MakeKVVMFromVMSpec, 10*time.Second))
h := NewMigratingHandler(vmservice.NewMigrationVolumesService(fakeClient, MakeKVVMFromVMSpec, 10*time.Second, false))
_, err := h.Handle(ctx, vmState)
Expect(err).NotTo(HaveOccurred())
err = resource.Update(context.Background())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,20 @@ import (
)

type MigrationVolumesService struct {
client client.Client
makeKVVMFromSpec func(ctx context.Context, s state.VirtualMachineState) (*virtv1.VirtualMachine, error)
delay map[types.UID]time.Time
delayDuration time.Duration
client client.Client
makeKVVMFromSpec func(ctx context.Context, s state.VirtualMachineState, disableTapVethBridge bool) (*virtv1.VirtualMachine, error)
delay map[types.UID]time.Time
delayDuration time.Duration
disableTapVethBridge bool
}

func NewMigrationVolumesService(client client.Client, makeKVVMFromSpec func(ctx context.Context, s state.VirtualMachineState) (*virtv1.VirtualMachine, error), delayDuration time.Duration) *MigrationVolumesService {
func NewMigrationVolumesService(client client.Client, makeKVVMFromSpec func(ctx context.Context, s state.VirtualMachineState, disableTapVethBridge bool) (*virtv1.VirtualMachine, error), delayDuration time.Duration, disableTapVethBridge bool) *MigrationVolumesService {
return &MigrationVolumesService{
client: client,
makeKVVMFromSpec: makeKVVMFromSpec,
delay: make(map[types.UID]time.Time),
delayDuration: delayDuration,
client: client,
makeKVVMFromSpec: makeKVVMFromSpec,
delay: make(map[types.UID]time.Time),
delayDuration: delayDuration,
disableTapVethBridge: disableTapVethBridge,
}
}

Expand Down Expand Up @@ -476,7 +478,7 @@ func (s MigrationVolumesService) fillContainerDiskImagePullPolicies(kvvm *virtv1
}

func (s MigrationVolumesService) makeKVVMFromVirtualMachineSpec(ctx context.Context, vmState state.VirtualMachineState) (*virtv1.VirtualMachine, *virtv1.VirtualMachine, error) {
kvvm, err := s.makeKVVMFromSpec(ctx, vmState)
kvvm, err := s.makeKVVMFromSpec(ctx, vmState, s.disableTapVethBridge)
if err != nil {
return nil, nil, err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,25 @@ func NewSyncKvvmHandler(
recorder eventrecord.EventRecorderLogger,
featureGate featuregate.FeatureGate,
syncVolumesService syncVolumesService,
disableTapVethBridge bool,
) *SyncKvvmHandler {
return &SyncKvvmHandler{
dvcrSettings: dvcrSettings,
client: client,
recorder: recorder,
featureGate: featureGate,
syncVolumesService: syncVolumesService,
dvcrSettings: dvcrSettings,
client: client,
recorder: recorder,
featureGate: featureGate,
syncVolumesService: syncVolumesService,
disableTapVethBridge: disableTapVethBridge,
}
}

type SyncKvvmHandler struct {
client client.Client
recorder eventrecord.EventRecorderLogger
dvcrSettings *dvcr.Settings
featureGate featuregate.FeatureGate
syncVolumesService syncVolumesService
client client.Client
recorder eventrecord.EventRecorderLogger
dvcrSettings *dvcr.Settings
featureGate featuregate.FeatureGate
syncVolumesService syncVolumesService
disableTapVethBridge bool
}

func (h *SyncKvvmHandler) Handle(ctx context.Context, s state.VirtualMachineState) (reconcile.Result, error) {
Expand Down Expand Up @@ -343,7 +346,7 @@ func (h *SyncKvvmHandler) createKVVM(ctx context.Context, s state.VirtualMachine
if s.VirtualMachine().IsEmpty() {
return fmt.Errorf("the virtual machine is empty, please report a bug")
}
kvvm, err := MakeKVVMFromVMSpec(ctx, s)
kvvm, err := MakeKVVMFromVMSpec(ctx, s, h.disableTapVethBridge)
if err != nil {
return fmt.Errorf("failed to make the internal virtual machine: %w", err)
}
Expand Down Expand Up @@ -372,7 +375,7 @@ func (h *SyncKvvmHandler) updateKVVM(ctx context.Context, s state.VirtualMachine
return fmt.Errorf("the virtual machine is empty, please report a bug")
}

newKVVM, err := MakeKVVMFromVMSpec(ctx, s)
newKVVM, err := MakeKVVMFromVMSpec(ctx, s, h.disableTapVethBridge)
if err != nil {
return fmt.Errorf("update internal virtual machine: make kvvm from the virtual machine spec: %w", err)
}
Expand Down Expand Up @@ -438,14 +441,15 @@ func saveKVVMDomainMemoryForPatching(prevKVVM, newKVVM *virtv1.VirtualMachine) *
return nil
}

func MakeKVVMFromVMSpec(ctx context.Context, s state.VirtualMachineState) (*virtv1.VirtualMachine, error) {
func MakeKVVMFromVMSpec(ctx context.Context, s state.VirtualMachineState, disableTapVethBridge bool) (*virtv1.VirtualMachine, error) {
if s.VirtualMachine().IsEmpty() {
return nil, nil
}
current := s.VirtualMachine().Current()
kvvmName := object.NamespacedName(current)

kvvmOpts := kvbuilder.DefaultOptions(current)
kvvmOpts.DisableTapVethBridge = disableTapVethBridge

kvvm, err := s.KVVM(ctx)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ var _ = Describe("SyncKvvmHandler", func() {
}

reconcile := func() {
h := NewSyncKvvmHandler(nil, fakeClient, recorder, featuregates.Default(), vmservice.NewMigrationVolumesService(fakeClient, MakeKVVMFromVMSpec, 10*time.Second))
h := NewSyncKvvmHandler(nil, fakeClient, recorder, featuregates.Default(), vmservice.NewMigrationVolumesService(fakeClient, MakeKVVMFromVMSpec, 10*time.Second, false), false)
_, err := h.Handle(ctx, vmState)
Expect(err).NotTo(HaveOccurred())
err = resource.Update(context.Background())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ func SetupController(
log *log.Logger,
dvcrSettings *dvcr.Settings,
firmwareImage string,
disableTapVethBridge bool,
) error {
recorder := eventrecord.NewEventRecorderLogger(mgr, ControllerName)
mgrCache := mgr.GetCache()
client := mgr.GetClient()
blockDeviceService := service.NewBlockDeviceService(client)
vmClassService := service.NewVirtualMachineClassService(client)

migrateVolumesService := vmservice.NewMigrationVolumesService(client, internal.MakeKVVMFromVMSpec, 10*time.Second)
migrateVolumesService := vmservice.NewMigrationVolumesService(client, internal.MakeKVVMFromVMSpec, 10*time.Second, disableTapVethBridge)

handlers := []Handler{
internal.NewMaintenanceHandler(client),
Expand All @@ -76,7 +77,7 @@ func SetupController(
internal.NewPodHandler(client),
internal.NewSizePolicyHandler(),
internal.NewNetworkInterfaceHandler(featuregates.Default()),
internal.NewSyncKvvmHandler(dvcrSettings, client, recorder, featuregates.Default(), migrateVolumesService),
internal.NewSyncKvvmHandler(dvcrSettings, client, recorder, featuregates.Default(), migrateVolumesService, disableTapVethBridge),
internal.NewSyncPowerStateHandler(client, recorder),
internal.NewSyncMetadataHandler(client),
internal.NewLifeCycleHandler(client, recorder),
Expand Down
13 changes: 13 additions & 0 deletions openapi/config-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,19 @@ properties:
type: string
minLength: 1
x-examples: ["sc-1", "sc-2"]
network:
type: object
description: |
Virtual machine networking settings.
properties:
disableTapVethBridge:
type: boolean
default: false
description: |
Disable tap-veth-bridge wiring for KubeVirt bridge interfaces.

When enabled, the virtualization controller adds the `virtualization.deckhouse.io/disable-tap-veth-bridge=true` annotation to the KubeVirt VirtualMachineInstance template.
The KubeVirt network setup then skips creating the tap-veth-bridge wiring and bridge DHCP configurator for such VMIs.
logLevel:
type: string
description: |
Expand Down
2 changes: 2 additions & 0 deletions templates/virtualization-controller/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ true
value: "1"
- name: DISABLE_HYPERV_SYNIC
value: "1"
- name: DISABLE_TAP_VETH_BRIDGE
value: {{ dig "network" "disableTapVethBridge" false .Values.virtualization.internal.moduleConfig | toString | quote }}
- name: POD_NAMESPACE
valueFrom:
fieldRef:
Expand Down
Loading