Skip to content
2 changes: 2 additions & 0 deletions api/core/v1alpha2/virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ const (
)

type NetworksSpec struct {
Id int `json:"id,omitempty"`
Type string `json:"type"`
Name string `json:"name,omitempty"`
VirtualMachineMACAddressName string `json:"virtualMachineMACAddressName,omitempty"`
Expand Down Expand Up @@ -423,6 +424,7 @@ type Versions struct {
}

type NetworksStatus struct {
Id int `json:"id,omitempty"`
Type string `json:"type"`
Name string `json:"name,omitempty"`
MAC string `json:"macAddress,omitempty"`
Expand Down
6 changes: 6 additions & 0 deletions crds/doc-ru-virtualmachines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,9 @@ spec:
Список конфигураций сетевых интерфейсов.
items:
properties:
id:
description: |
ID сетевого интерфейса.
type:
description: |
Тип сетевого интерфейса.
Expand Down Expand Up @@ -743,6 +746,9 @@ spec:
Список сетевых интерфейсов, подключенных к ВМ.
items:
properties:
id:
description: |
ID сетевого интерфейса.
type:
description: |
Тип сетевого интерфейса.
Expand Down
8 changes: 8 additions & 0 deletions crds/virtualmachines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,10 @@ spec:
required:
- type
properties:
id:
type: integer
description: |
Network interface ID.
type:
type: string
description: |
Expand Down Expand Up @@ -1333,6 +1337,10 @@ spec:
required:
- type
properties:
id:
type: integer
description: |
Network interface ID.
type:
type: string
description: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func HasMainNetworkSpec(networks []v1alpha2.NetworksSpec) bool {
}

type InterfaceSpec struct {
ID int `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
InterfaceName string `json:"ifName"`
Expand Down Expand Up @@ -96,6 +97,7 @@ func CreateNetworkSpec(vm *v1alpha2.VirtualMachine, vmmacs []*v1alpha2.VirtualMa
for _, n := range vm.Spec.Networks {
if n.Type == v1alpha2.NetworksTypeMain {
res = append(res, InterfaceSpec{
ID: n.Id,
Type: n.Type,
Name: n.Name,
InterfaceName: NameDefaultInterface,
Expand All @@ -117,6 +119,7 @@ func CreateNetworkSpec(vm *v1alpha2.VirtualMachine, vmmacs []*v1alpha2.VirtualMa
}
if mac != "" {
res = append(res, InterfaceSpec{
ID: n.Id,
Type: n.Type,
Name: n.Name,
InterfaceName: generateInterfaceName(mac, n.Type),
Expand Down
158 changes: 158 additions & 0 deletions images/virtualization-artifact/pkg/common/network/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ var _ = Describe("Network Config Generation", func() {
Expect(configs[0].Name).To(Equal(""))
Expect(configs[0].InterfaceName).To(HavePrefix("default"))
Expect(configs[0].MAC).To(HavePrefix(""))
Expect(configs[0].ID).To(Equal(0))
})

It("should generate correct interface name for Network type", func() {
Expand All @@ -97,10 +98,12 @@ var _ = Describe("Network Config Generation", func() {
Expect(configs[0].Name).To(Equal(""))
Expect(configs[0].InterfaceName).To(HavePrefix("default"))
Expect(configs[0].MAC).To(HavePrefix(""))
Expect(configs[0].ID).To(Equal(0))

Expect(configs[1].Type).To(Equal(v1alpha2.NetworksTypeNetwork))
Expect(configs[1].Name).To(Equal("mynet"))
Expect(configs[1].InterfaceName).To(HavePrefix("veth_n"))
Expect(configs[1].ID).To(Equal(0))
})

It("should generate correct interface name for ClusterNetwork type", func() {
Expand Down Expand Up @@ -281,4 +284,159 @@ var _ = Describe("Network Config Generation", func() {
Expect(configs[3].Name).To(Equal("name1"))
Expect(configs[3].MAC).To(Equal("00:1A:2B:3C:4D:6A"))
})

It("should preserve id from spec for Main network", func() {
vm.Spec.Networks = []v1alpha2.NetworksSpec{
{
Type: v1alpha2.NetworksTypeMain,
Id: 1,
},
}

configs := CreateNetworkSpec(vm, vmmacs)

Expect(configs).To(HaveLen(1))
Expect(configs[0].ID).To(Equal(1))
})

It("should preserve id from spec for Main network", func() {
vm.Spec.Networks = []v1alpha2.NetworksSpec{
{
Type: v1alpha2.NetworksTypeMain,
Id: 1,
},
}

configs := CreateNetworkSpec(vm, vmmacs)

Expect(configs).To(HaveLen(1))
Expect(configs[0].ID).To(Equal(1))
})

It("should preserve id from spec for Network type with MAC", func() {
vm.Status.Networks = []v1alpha2.NetworksStatus{
{
Type: v1alpha2.NetworksTypeNetwork,
Name: "mynet",
MAC: "00:1A:2B:3C:4D:5E",
},
}
vmmac1 := newMACAddress("mac1", "00:1A:2B:3C:4D:5E", v1alpha2.VirtualMachineMACAddressPhaseAttached, "vm1")
vmmacs = []*v1alpha2.VirtualMachineMACAddress{vmmac1}

vm.Spec.Networks = []v1alpha2.NetworksSpec{
{
Type: v1alpha2.NetworksTypeMain,
Id: 1,
},
{
Type: v1alpha2.NetworksTypeNetwork,
Name: "mynet",
Id: 5,
},
}

configs := CreateNetworkSpec(vm, vmmacs)

Expect(configs).To(HaveLen(2))
Expect(configs[0].ID).To(Equal(1))
Expect(configs[1].ID).To(Equal(5))
})

It("should preserve id from spec for ClusterNetwork type with MAC", func() {
vm.Status.Networks = []v1alpha2.NetworksStatus{
{
Type: v1alpha2.NetworksTypeClusterNetwork,
Name: "clusternet",
MAC: "00:1A:2B:3C:4D:5E",
},
}
vmmac1 := newMACAddress("mac1", "00:1A:2B:3C:4D:5E", v1alpha2.VirtualMachineMACAddressPhaseAttached, "vm1")
vmmacs = []*v1alpha2.VirtualMachineMACAddress{vmmac1}

vm.Spec.Networks = []v1alpha2.NetworksSpec{
{
Type: v1alpha2.NetworksTypeMain,
Id: 1,
},
{
Type: v1alpha2.NetworksTypeClusterNetwork,
Name: "clusternet",
Id: 20,
},
}

configs := CreateNetworkSpec(vm, vmmacs)

Expect(configs).To(HaveLen(2))
Expect(configs[0].ID).To(Equal(1))
Expect(configs[1].ID).To(Equal(20))
})

It("should preserve different ids for multiple networks with MACs", func() {
vm.Status.Networks = []v1alpha2.NetworksStatus{
{
Type: v1alpha2.NetworksTypeNetwork,
Name: "net1",
MAC: "00:1A:2B:3C:4D:5E",
},
{
Type: v1alpha2.NetworksTypeNetwork,
Name: "net2",
MAC: "00:1A:2B:3C:4D:5F",
},
{
Type: v1alpha2.NetworksTypeClusterNetwork,
Name: "cluster1",
MAC: "00:1A:2B:3C:4D:6A",
},
}
vmmac1 := newMACAddress("mac1", "00:1A:2B:3C:4D:5E", v1alpha2.VirtualMachineMACAddressPhaseAttached, "vm1")
vmmac2 := newMACAddress("mac2", "00:1A:2B:3C:4D:5F", v1alpha2.VirtualMachineMACAddressPhaseAttached, "vm1")
vmmac3 := newMACAddress("mac3", "00:1A:2B:3C:4D:6A", v1alpha2.VirtualMachineMACAddressPhaseAttached, "vm1")
vmmacs = []*v1alpha2.VirtualMachineMACAddress{vmmac1, vmmac2, vmmac3}

vm.Spec.Networks = []v1alpha2.NetworksSpec{
{
Type: v1alpha2.NetworksTypeMain,
Id: 1,
},
{
Type: v1alpha2.NetworksTypeNetwork,
Name: "net1",
Id: 2,
},
{
Type: v1alpha2.NetworksTypeNetwork,
Name: "net2",
Id: 3,
},
{
Type: v1alpha2.NetworksTypeClusterNetwork,
Name: "cluster1",
Id: 4,
},
}

configs := CreateNetworkSpec(vm, vmmacs)

Expect(configs).To(HaveLen(4))
Expect(configs[0].ID).To(Equal(1))
Expect(configs[1].ID).To(Equal(2))
Expect(configs[2].ID).To(Equal(3))
Expect(configs[3].ID).To(Equal(4))
})

It("should set id to zero when not specified", func() {
vm.Spec.Networks = []v1alpha2.NetworksSpec{
{
Type: v1alpha2.NetworksTypeMain,
},
}

configs := CreateNetworkSpec(vm, vmmacs)

Expect(configs).To(HaveLen(1))
Expect(configs[0].ID).To(Equal(0))
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ func (b *KVVM) ClearNetworkInterfaces() {
b.Resource.Spec.Template.Spec.Domain.Devices.Interfaces = nil
}

func (b *KVVM) SetNetworkInterface(name, macAddress string) {
func (b *KVVM) SetNetworkInterface(name, macAddress string, acpiIndex int) {
net := virtv1.Network{
Name: name,
NetworkSource: virtv1.NetworkSource{
Expand All @@ -571,8 +571,9 @@ func (b *KVVM) SetNetworkInterface(name, macAddress string) {
devPreset := DeviceOptionsPresets.Find(b.opts.EnableParavirtualization)

iface := virtv1.Interface{
Name: name,
Model: devPreset.InterfaceModel,
Name: name,
Model: devPreset.InterfaceModel,
ACPIIndex: acpiIndex,
}
iface.InterfaceBindingMethod.Bridge = &virtv1.InterfaceBridge{}
if macAddress != "" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ func ApplyVirtualMachineSpec(
vdByName map[string]*v1alpha2.VirtualDisk,
viByName map[string]*v1alpha2.VirtualImage,
cviByName map[string]*v1alpha2.ClusterVirtualImage,
vmbdas map[v1alpha2.VMBDAObjectRef][]*v1alpha2.VirtualMachineBlockDeviceAttachment,
class *v1alpha2.VirtualMachineClass,
ipAddress string,
networkSpec network.InterfaceSpecList,
Expand Down Expand Up @@ -356,7 +355,7 @@ func ApplyMigrationVolumes(kvvm *KVVM, vm *v1alpha2.VirtualMachine, vdsByName ma
func setNetwork(kvvm *KVVM, networkSpec network.InterfaceSpecList) {
kvvm.ClearNetworkInterfaces()
for _, n := range networkSpec {
kvvm.SetNetworkInterface(n.InterfaceName, n.MAC)
kvvm.SetNetworkInterface(n.InterfaceName, n.MAC, n.ID)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,41 @@ func (h *NetworkInterfaceHandler) Handle(ctx context.Context, s state.VirtualMac
}
}

h.lazyInitialization(vm)
return h.UpdateNetworkStatus(ctx, s, vm)
}

func (h *NetworkInterfaceHandler) lazyInitialization(vm *v1alpha2.VirtualMachine) {
// First pass: assign id=1 to Main network if it has id=0
for i := range vm.Spec.Networks {
if vm.Spec.Networks[i].Type == v1alpha2.NetworksTypeMain && vm.Spec.Networks[i].Id == 0 {
vm.Spec.Networks[i].Id = 1
}
}

// Second pass: assign sequential ids starting from 2 to other networks with id=0
nextID := 2
for i := range vm.Spec.Networks {
if vm.Spec.Networks[i].Type != v1alpha2.NetworksTypeMain && vm.Spec.Networks[i].Id == 0 {
vm.Spec.Networks[i].Id = nextID
nextID++
// Ensure we never use id=1 (reserved for Main)
if nextID == 1 {
nextID = 2
}
} else if vm.Spec.Networks[i].Id > 0 {
// Track the highest ID used to avoid conflicts
if vm.Spec.Networks[i].Id >= nextID {
nextID = vm.Spec.Networks[i].Id + 1
// Ensure we never use id=1 (reserved for Main)
if nextID == 1 {
nextID = 2
}
}
}
}
}

func hasOnlyDefaultNetwork(vm *v1alpha2.VirtualMachine) bool {
nets := vm.Spec.Networks
return len(nets) == 0 || (len(nets) == 1 && nets[0].Type == v1alpha2.NetworksTypeMain)
Expand All @@ -118,6 +150,7 @@ func (h *NetworkInterfaceHandler) UpdateNetworkStatus(ctx context.Context, s sta
if hasOnlyDefaultNetwork(vm) {
vm.Status.Networks = []v1alpha2.NetworksStatus{
{
Id: 1,
Type: v1alpha2.NetworksTypeMain,
Name: network.NameDefaultInterface,
},
Expand Down Expand Up @@ -153,13 +186,15 @@ func (h *NetworkInterfaceHandler) UpdateNetworkStatus(ctx context.Context, s sta
for _, interfaceSpec := range network.CreateNetworkSpec(vm, vmmacs) {
if interfaceSpec.Type == v1alpha2.NetworksTypeMain {
networksStatus = append(networksStatus, v1alpha2.NetworksStatus{
Id: interfaceSpec.ID,
Type: v1alpha2.NetworksTypeMain,
Name: network.NameDefaultInterface,
})
continue
}

networksStatus = append(networksStatus, v1alpha2.NetworksStatus{
Id: interfaceSpec.ID,
Type: interfaceSpec.Type,
Name: interfaceSpec.Name,
MAC: macAddressesByInterfaceName[interfaceSpec.InterfaceName],
Expand Down
Loading
Loading