Skip to content

Commit db0b023

Browse files
committed
fix(usb): skip port check for already attached devices
Check free USBIP ports only for new attachments, not for devices already attached in KVVMI. This prevents resetting attached: true to false when ports are exhausted but device is already working. Fixes the issue where attached USB devices were marked as detached due to 'no free USBIP ports available' logs. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
1 parent 4984fec commit db0b023

1 file changed

Lines changed: 27 additions & 35 deletions

File tree

images/virtualization-artifact/pkg/controller/vm/internal/usb_device_attach_handler.go

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,6 @@ func (h *USBDeviceAttachHandler) Handle(ctx context.Context, s state.VirtualMach
9595
var kvvmi *virtv1.VirtualMachineInstance
9696
var hostDeviceReadyByName map[string]bool
9797

98-
// Lazy-loaded node for USBIP port check
99-
var nodeLoaded bool
100-
var node *corev1.Node
101-
10298
var nextStatusRefs []v1alpha2.USBDeviceStatusRef
10399
for _, usbDeviceRef := range vm.Spec.USBDevices {
104100
deviceName := usbDeviceRef.Name
@@ -136,37 +132,7 @@ func (h *USBDeviceAttachHandler) Handle(ctx context.Context, s state.VirtualMach
136132
continue
137133
}
138134

139-
// 3) Check free USBIP ports for devices from other nodes (USBIP scenario)
140-
if usbDevice.Status.NodeName != "" && usbDevice.Status.NodeName != vm.Status.Node {
141-
if !nodeLoaded && vm.Status.Node != "" {
142-
node = &corev1.Node{}
143-
if err := h.client.Get(ctx, client.ObjectKey{Name: vm.Status.Node}, node); err != nil {
144-
if !apierrors.IsNotFound(err) {
145-
return reconcile.Result{}, fmt.Errorf("failed to get node %s: %w", vm.Status.Node, err)
146-
}
147-
node = nil
148-
}
149-
nodeLoaded = true
150-
}
151-
152-
if node != nil {
153-
hasFreePort, err := usb.CheckFreePort(node.Annotations, usbDevice.Status.Attributes.Speed)
154-
if err != nil {
155-
log.Error("failed to check free USBIP ports", "error", err, "device", deviceName, "node", vm.Status.Node)
156-
nextStatusRefs = append(nextStatusRefs, h.buildDetachedStatus(existingStatus, deviceName, isReady))
157-
continue
158-
}
159-
if !hasFreePort {
160-
log.Info("no free USBIP ports available", "device", deviceName, "speed", usbDevice.Status.Attributes.Speed, "node", vm.Status.Node)
161-
// Return requeue to retry after 5 seconds
162-
nextStatusRefs = append(nextStatusRefs, h.buildDetachedStatus(existingStatus, deviceName, isReady))
163-
changed.Status.USBDevices = nextStatusRefs
164-
return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
165-
}
166-
}
167-
}
168-
169-
// 4) Runtime evidence from KVVMI and attach action.
135+
// 3) Runtime evidence from KVVMI and attach action.
170136
if !kvvmiLoaded {
171137
fetchedKVVMI, err := s.KVVMI(ctx)
172138
if err != nil {
@@ -180,6 +146,7 @@ func (h *USBDeviceAttachHandler) Handle(ctx context.Context, s state.VirtualMach
180146
hostDeviceReadyByName = h.hostDeviceReadyByName(kvvmi)
181147
}
182148

149+
// If device is already attached in KVVMI - preserve status, skip port check.
183150
if hostDeviceReadyByName[deviceName] {
184151
address := h.getUSBAddressFromKVVMI(deviceName, kvvmi)
185152
isHotplugged := vm.Status.Phase == v1alpha2.MachineRunning
@@ -196,6 +163,31 @@ func (h *USBDeviceAttachHandler) Handle(ctx context.Context, s state.VirtualMach
196163
continue
197164
}
198165

166+
// 4) Check free USBIP ports for new attachments from other nodes.
167+
if usbDevice.Status.NodeName != "" && usbDevice.Status.NodeName != vm.Status.Node {
168+
node := &corev1.Node{}
169+
if err := h.client.Get(ctx, client.ObjectKey{Name: vm.Status.Node}, node); err != nil {
170+
if !apierrors.IsNotFound(err) {
171+
return reconcile.Result{}, fmt.Errorf("failed to get node %s: %w", vm.Status.Node, err)
172+
}
173+
nextStatusRefs = append(nextStatusRefs, h.buildDetachedStatus(existingStatus, deviceName, isReady))
174+
continue
175+
}
176+
177+
hasFreePort, err := usb.CheckFreePort(node.Annotations, usbDevice.Status.Attributes.Speed)
178+
if err != nil {
179+
log.Error("failed to check free USBIP ports", "error", err, "device", deviceName, "node", vm.Status.Node)
180+
nextStatusRefs = append(nextStatusRefs, h.buildDetachedStatus(existingStatus, deviceName, isReady))
181+
continue
182+
}
183+
if !hasFreePort {
184+
log.Info("no free USBIP ports available", "device", deviceName, "speed", usbDevice.Status.Attributes.Speed, "node", vm.Status.Node)
185+
nextStatusRefs = append(nextStatusRefs, h.buildDetachedStatus(existingStatus, deviceName, isReady))
186+
changed.Status.USBDevices = nextStatusRefs
187+
return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
188+
}
189+
}
190+
199191
requestName := h.getResourceClaimRequestName(deviceName)
200192
err := h.attachUSBDevice(ctx, vm, deviceName, templateName, requestName)
201193
if err != nil && !apierrors.IsAlreadyExists(err) && !strings.Contains(err.Error(), "already exists") {

0 commit comments

Comments
 (0)