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.28
3p-kubevirt: feat/vm/disable-tap-veth-bridge
3p-containerized-data-importer: v1.60.3-v12n.18
distribution: 2.8.3
package:
Expand Down
24 changes: 23 additions & 1 deletion images/virt-artifact/werf.inc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ secrets:
- id: SOURCE_REPO
value: {{ $.SOURCE_REPO }}
shell:
installCacheVersion: "{{ now | date "Mon Jan 2 15:04:05 MST 2006" }}"
install:
- |
echo "$date ------- "
echo "Git clone {{ $gitRepoName }} repository..."
git clone --depth=1 $(cat /run/secrets/SOURCE_REPO)/{{ $gitRepoUrl }} --branch {{ $tag }} /src/kubevirt

Expand All @@ -28,6 +30,8 @@ altPackages:
- pkg-config
- libtool
- gcc-c++
- clang
- libbpf-devel
packages:
- libmnl
- ncurses
Expand Down Expand Up @@ -113,6 +117,7 @@ shell:
- export GOOS=linux
- export GOARCH=amd64
- export CGO_ENABLED=0
- export BPF_CLANG=clang

- echo ============== Build container-disk ===================
{{- $_ := set $ "ProjectName" (list .ImageName "container-disk" | join "/") }}
Expand Down Expand Up @@ -197,10 +202,27 @@ shell:
{{- include "image-build.build" (set $ "BuildCommand" `go build -ldflags="-s -w" -o /kubevirt-binaries/virt-operator ./cmd/virt-operator/`) | nindent 6 }}

- echo ============== Build sidecars =========================
{{- $_ := set $ "ProjectName" (list .ImageName "sidecars" | join "/") }}
- |
cd /kubevirt
echo "Sidecars cmd list:"
ls -la cmd/sidecars/
echo "---"
{{- $_ := set $ "ProjectName" (list $.ImageName "sidecars" | join "/") }}
- |
{{- include "image-build.build" (set $ "BuildCommand" `go build -ldflags="-s -w" -o /kubevirt-binaries/sidecars ./cmd/sidecars/`) | nindent 6 }}

- echo ============== Build network-bpf-bridge-binding =======
{{- $_ := set $ "ProjectName" (list $.ImageName "network-bpf-bridge-binding" | join "/") }}
- |
{{- include "image-build.build" (set $ "BuildCommand" `go build -ldflags="-s -w" -o /kubevirt-binaries/network-bpf-bridge-binding ./cmd/sidecars/network-bpf-bridge-binding/`) | nindent 6 }}

- echo ============== Build bpf_bridge.o =====================
{{- $_ := set $ "ProjectName" (list $.ImageName "bpf-bridge-obj" | join "/") }}
- mkdir -p /kubevirt-binaries/network-bpf-bridge-binding-assets
- |
{{- include "image-build.build" (set $ "BuildCommand" `clang -O2 -g -target bpf -I/usr/include -c ./cmd/sidecars/network-bpf-bridge-binding/bpf/bpf_bridge.c -o /kubevirt-binaries/network-bpf-bridge-binding-assets/bpf_bridge.o`) | nindent 6 }}
- echo "Built bpf object:" && ls -l /kubevirt-binaries/network-bpf-bridge-binding-assets/ && file /kubevirt-binaries/network-bpf-bridge-binding-assets/bpf_bridge.o || true

- echo ============== Build virtctl ==========================
{{- $_ := set $ "ProjectName" (list .ImageName "virtctl" | join "/") }}
- |
Expand Down
27 changes: 27 additions & 0 deletions images/virt-launcher/werf.inc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ altLibs:
- psmisc
- msulogin
- strace
- iproute2
binaries:
# GNU utils (required to run swtpm).
- /usr/bin/certtool
Expand Down Expand Up @@ -196,11 +197,18 @@ import:
before: setup
includePaths:
- container-disk
- network-bpf-bridge-binding
- virt-freezer
- virt-launcher
- virt-launcher-monitor
- virt-probe
- virt-tail
- image: {{ .ModuleNamePrefix }}virt-artifact
add: /kubevirt-binaries/network-bpf-bridge-binding-assets/
to: /relocate/opt/network-bpf-bridge-binding
before: setup
includePaths:
- bpf_bridge.o
- image: {{ .ModuleNamePrefix }}virt-artifact
add: /kubevirt-binaries
to: /relocate/etc/libvirt/hooks/qemu
Expand Down Expand Up @@ -246,6 +254,8 @@ import:
after: setup
includePaths:
- sbin/tc
- usr/include
- usr/lib

- image: {{ .ModuleNamePrefix }}{{ .ImageName }}-cbuilder
add: /bins
Expand Down Expand Up @@ -392,6 +402,23 @@ shell:
echo "Create symlink for run -> var/run "
ln -s var/run run

echo "Copy system tc and runtime dirs"
mkdir -p /relocate/usr/sbin
cp -a /usr/sbin/tc /relocate/usr/sbin/tc
if [ -d /usr/lib/tc ]; then
mkdir -p /relocate/usr/lib
cp -a /usr/lib/tc /relocate/usr/lib/tc
fi
if [ -d /usr/lib64/tc ]; then
mkdir -p /relocate/usr/lib64
cp -a /usr/lib64/tc /relocate/usr/lib64/tc
fi

- |
echo "iproute2 runtime contents in /relocate/usr:"
find /relocate/usr \( -path "/relocate/usr/sbin/tc" -o -path "/relocate/usr/lib/tc" -o -path "/relocate/usr/lib/tc/*" -o -path "/relocate/usr/lib64/tc" -o -path "/relocate/usr/lib64/tc/*" \) | sort || true
ls -ld /relocate/usr/lib/tc /relocate/usr/lib64/tc 2>/dev/null || true

# /etc/libvirt-init will be copied back into /etc/libvirt at runtime. This is necessary because we configure libvirt to mount /etc/libvirt and set readOnlyRootFilesystem for other directories.
# DO NOT REMOVE. node-labeler.sh uses /etc/libvirt.
- |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,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 @@ -360,7 +362,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, networkSettings.DisableDHCP); 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,10 @@ 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"
// AnnDisableDHCP disables bridge DHCP configurator for the VMI network setup in KubeVirt.
AnnDisableDHCP = AnnAPIGroupV + "/disable-dhcp"

// AnnVMOPWorkloadUpdate is an annotation on vmop that represents a vmop created by workload-updater controller.
AnnVMOPWorkloadUpdate = AnnAPIGroupV + "/workload-update"
Expand Down
10 changes: 10 additions & 0 deletions images/virtualization-artifact/pkg/common/network/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ func CreateNetworkSpec(vm *v1alpha2.VirtualMachine, vmmacs []*v1alpha2.VirtualMa
macPool := NewMacAddressPool(vm, vmmacs)
var specs InterfaceSpecList

if len(vm.Spec.Networks) == 0 {
return InterfaceSpecList{{
ID: 1,
Type: v1alpha2.NetworksTypeMain,
Name: "",
InterfaceName: NameDefaultInterface,
MAC: "",
}}
}

for _, net := range vm.Spec.Networks {
if net.Type == v1alpha2.NetworksTypeMain {
specs = append(specs, createMainInterfaceSpec(net))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
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"
DisableDHCPVar = "DISABLE_DHCP"
)

type NetworkSettings struct {
DisableTapVethBridge bool
DisableDHCP bool
}

func LoadNetworkSettingsFromEnv() NetworkSettings {
return NetworkSettings{
DisableTapVethBridge: os.Getenv(DisableTapVethBridgeVar) == "true",
DisableDHCP: os.Getenv(DisableDHCPVar) == "true",
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/klog/v2"
"k8s.io/utils/ptr"
virtv1 "kubevirt.io/api/core/v1"

Expand Down Expand Up @@ -67,6 +68,8 @@ const (
type KVVMOptions struct {
EnableParavirtualization bool
OsType v1alpha2.OsType
DisableTapVethBridge bool
DisableDHCP bool

// These options are for local development mode
DisableHypervSyNIC bool
Expand All @@ -92,6 +95,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 Expand Up @@ -740,8 +747,10 @@ func (b *KVVM) GetOSSettings() map[string]interface{} {
}

func (b *KVVM) ClearNetworkInterfaces() {
klog.Infof("kvbuilder: ClearNetworkInterfaces before ifaces=%d nets=%d", len(b.Resource.Spec.Template.Spec.Domain.Devices.Interfaces), len(b.Resource.Spec.Template.Spec.Networks))
b.Resource.Spec.Template.Spec.Networks = nil
b.Resource.Spec.Template.Spec.Domain.Devices.Interfaces = nil
klog.Infof("kvbuilder: ClearNetworkInterfaces after ifaces=%d nets=%d", len(b.Resource.Spec.Template.Spec.Domain.Devices.Interfaces), len(b.Resource.Spec.Template.Spec.Networks))
}

func (b *KVVM) SetNetworkInterface(name, macAddress string, acpiIndex int) {
Expand All @@ -765,7 +774,13 @@ func (b *KVVM) SetNetworkInterface(name, macAddress string, acpiIndex int) {
Model: devPreset.InterfaceModel,
ACPIIndex: acpiIndex,
}
iface.Bridge = &virtv1.InterfaceBridge{}
if name == "default" {
iface.Binding = &virtv1.PluginBinding{Name: "bpfbridge"}
klog.Infof("kvbuilder: using bpfbridge binding for default interface %q", name)
} else {
iface.Bridge = &virtv1.InterfaceBridge{}
klog.Infof("kvbuilder: using bridge binding for non-default interface %q", name)
}
if macAddress != "" {
iface.MacAddress = macAddress
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"
"k8s.io/utils/ptr"
virtv1 "kubevirt.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -96,6 +97,7 @@ func ApplyVirtualMachineSpec(
ipAddress string,
networkSpec network.InterfaceSpecList,
) error {
klog.Infof("kvbuilder: ApplyVirtualMachineSpec start vm=%s/%s networks=%d existingIfaces=%d", vm.Namespace, vm.Name, len(networkSpec), len(kvvm.Resource.Spec.Template.Spec.Domain.Devices.Interfaces))
if err := kvvm.SetRunPolicy(vm.Spec.RunPolicy); err != nil {
return err
}
Expand All @@ -111,6 +113,16 @@ func ApplyVirtualMachineSpec(

kvvm.SetUSBMigrationStrategy()
kvvm.SetMetadata(vm.ObjectMeta)
if kvvm.Options().DisableTapVethBridge {
kvvm.SetKVVMIAnnotation(annotations.AnnDisableTapVethBridge, "true")
} else {
kvvm.RemoveKVVMIAnnotation(annotations.AnnDisableTapVethBridge)
}
if kvvm.Options().DisableDHCP {
kvvm.SetKVVMIAnnotation(annotations.AnnDisableDHCP, "true")
} else {
kvvm.RemoveKVVMIAnnotation(annotations.AnnDisableDHCP)
}
setNetwork(kvvm, networkSpec)
kvvm.SetTablet("default-0")
kvvm.SetNodeSelector(vm.Spec.NodeSelector, class.Spec.NodeSelector.MatchLabels)
Expand Down Expand Up @@ -355,10 +367,24 @@ func ApplyMigrationVolumes(kvvm *KVVM, vm *v1alpha2.VirtualMachine, vdsByName ma
}

func setNetwork(kvvm *KVVM, networkSpec network.InterfaceSpecList) {
klog.Infof("kvbuilder: setNetwork start specLen=%d currentIfaces=%d currentNets=%d", len(networkSpec), len(kvvm.Resource.Spec.Template.Spec.Domain.Devices.Interfaces), len(kvvm.Resource.Spec.Template.Spec.Networks))
for idx, n := range networkSpec {
klog.Infof("kvbuilder: setNetwork spec[%d] ifName=%q mac=%q id=%d type=%q", idx, n.InterfaceName, n.MAC, n.ID, n.Type)
}
kvvm.ClearNetworkInterfaces()
klog.Infof("kvbuilder: after ClearNetworkInterfaces ifaces=%d nets=%d", len(kvvm.Resource.Spec.Template.Spec.Domain.Devices.Interfaces), len(kvvm.Resource.Spec.Template.Spec.Networks))
for _, n := range networkSpec {
kvvm.SetNetworkInterface(n.InterfaceName, n.MAC, n.ID)
}
klog.Infof("kvbuilder: setNetwork done resultingIfaces=%d resultingNets=%d", len(kvvm.Resource.Spec.Template.Spec.Domain.Devices.Interfaces), len(kvvm.Resource.Spec.Template.Spec.Networks))
for idx, iface := range kvvm.Resource.Spec.Template.Spec.Domain.Devices.Interfaces {
bindingName := ""
if iface.Binding != nil {
bindingName = iface.Binding.Name
}
isBridge := iface.Bridge != nil
klog.Infof("kvbuilder: resulting iface[%d] name=%q bridge=%t binding=%q", idx, iface.Name, isBridge, bindingName)
}
}

func setNetworksAnnotation(kvvm *KVVM, networkSpec network.InterfaceSpecList) error {
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, 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,22 @@ 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, disableDHCP bool) (*virtv1.VirtualMachine, error)
delay map[types.UID]time.Time
delayDuration time.Duration
disableTapVethBridge bool
disableDHCP 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, disableDHCP bool) (*virtv1.VirtualMachine, error), delayDuration time.Duration, disableTapVethBridge, disableDHCP 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,
disableDHCP: disableDHCP,
}
}

Expand Down Expand Up @@ -476,7 +480,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, s.disableDHCP)
if err != nil {
return nil, nil, err
}
Expand Down
Loading
Loading