5050 gveNotifyIRQRe = regexp .MustCompile (`gve-ntfy-blk(\d+)@.*` )
5151 gveOlderNotifyIRQRe = regexp .MustCompile (`.*-ntfy-block\.(\d+)` )
5252
53- txQueueRe = regexp .MustCompile (`tx-(\d+)` )
53+ txQueueRe = regexp .MustCompile (`tx-(\d+)` )
54+ idpfTxRxIRQRe = regexp .MustCompile (`.*TxRx-(\d+)` )
5455)
5556
5657//go:embed config_expectations/config_expectations.textproto
@@ -123,7 +124,7 @@ func deviceIRQs(ifaceName string) ([]int, error) {
123124
124125 baseAsInt , err := strconv .Atoi (d .Name ())
125126 if err != nil {
126- return fmt .Errorf ("unexpected non-integer device IRQ name %q: %w" , d .Name (), err )
127+ return fmt .Errorf ("unexpected non-integer device IRQ name %q in %q : %w" , d .Name (), deviceIRQsPath , err )
127128 }
128129
129130 allegedProcPath := fmt .Sprintf ("/proc/irq/%d" , baseAsInt )
@@ -138,6 +139,9 @@ func deviceIRQs(ifaceName string) ([]int, error) {
138139 if err != nil {
139140 return nil , fmt .Errorf ("walking device IRQs path %q: %w" , deviceIRQsPath , err )
140141 }
142+ if len (irqs ) == 0 {
143+ return nil , fmt .Errorf ("deviceIRQs found no active proc IRQs in %q" , deviceIRQsPath )
144+ }
141145
142146 return irqs , nil
143147}
@@ -221,17 +225,38 @@ func gveQueueIndex(irqPath string, isRX bool, queueCounts *networkutils.EthtoolQ
221225 //
222226 // Note that the number of notify blocks is based on the maximum number of queues, not
223227 // the currently configured number.
224- if isRX && index >= queueCounts .MaxTXQueues {
225- index -= queueCounts .MaxTXQueues
228+ maxTX := queueCounts .EffectiveMaxTXQueues ()
229+ if isRX && index >= maxTX {
230+ index -= maxTX
226231 return true , index , nil
227232 }
228- if ! isRX && index < queueCounts . MaxTXQueues {
233+ if ! isRX && index < maxTX {
229234 return true , index , nil
230235 }
231236
232237 return false , 0 , nil
233238}
234239
240+ func idpfQueueIndex (irqPath string ) (bool , int , error ) {
241+ fileName , err := findFileWithRegex (irqPath , idpfTxRxIRQRe )
242+ if err != nil {
243+ return false , 0 , err
244+ }
245+ if fileName == "" {
246+ return false , 0 , nil
247+ }
248+ index , err := strconv .Atoi (fileName )
249+ if err != nil {
250+ return false , 0 , err
251+ }
252+ // Linux idpf driver uses 1-based vector indices (e.g. TxRx-1 .. TxRx-16).
253+ // Convert 1-based index (>= 1) to 0-based (index - 1).
254+ if index >= 1 {
255+ index --
256+ }
257+ return true , index , nil
258+ }
259+
235260// rxQueueIndex returns the index of the RX queue for the given IRQ path.
236261// Returns -1 if no RX queue is found, or an error if the calculation fails unexpectedly.
237262func rxQueueIndex (irqPath string , queueCounts * networkutils.EthtoolQueueCounts ) (int , error ) {
@@ -247,6 +272,12 @@ func rxQueueIndex(irqPath string, queueCounts *networkutils.EthtoolQueueCounts)
247272 return index , nil
248273 }
249274
275+ if found , index , err := idpfQueueIndex (irqPath ); err != nil {
276+ return - 1 , err
277+ } else if found {
278+ return index , nil
279+ }
280+
250281 return - 1 , nil
251282}
252283
@@ -265,6 +296,12 @@ func txQueueIndex(irqPath string, queueCounts *networkutils.EthtoolQueueCounts)
265296 return index , nil
266297 }
267298
299+ if found , index , err := idpfQueueIndex (irqPath ); err != nil {
300+ return - 1 , err
301+ } else if found {
302+ return index , nil
303+ }
304+
268305 return - 1 , nil
269306}
270307
@@ -307,10 +344,10 @@ func queueIndexToIRQs(irqs []int, queueCounts *networkutils.EthtoolQueueCounts)
307344 return nil , err
308345 }
309346
310- if rxQueueIndex >= 0 && rxQueueIndex < queueCounts .CurrentRXQueues {
347+ if rxQueueIndex >= 0 && rxQueueIndex < queueCounts .EffectiveCurrentRXQueues () {
311348 irqCPUListsMap .rxIRQAffinity [rxQueueIndex ] = cpuListStr
312349 }
313- if txQueueIndex >= 0 && txQueueIndex < queueCounts .CurrentTXQueues {
350+ if txQueueIndex >= 0 && txQueueIndex < queueCounts .EffectiveCurrentTXQueues () {
314351 irqCPUListsMap .txIRQAffinity [txQueueIndex ] = cpuListStr
315352 }
316353 }
@@ -406,6 +443,15 @@ func queueCountsForInterface(ifaceName string) (*networkutils.EthtoolQueueCounts
406443 return networkutils .ParseEthtoolLOutput (string (out ))
407444}
408445
446+ func ringSizesForInterface (ifaceName string ) (* networkutils.EthtoolRingSizes , error ) {
447+ cmd := exec .Command ("ethtool" , "-g" , ifaceName )
448+ out , err := cmd .Output ()
449+ if err != nil {
450+ return nil , fmt .Errorf ("failed to run `ethtool -g %q`: %w" , ifaceName , err )
451+ }
452+ return networkutils .ParseEthtoolGOutput (string (out ))
453+ }
454+
409455func buildQueuesXPSOnly (txQueueToXPS map [int ]string ) ([]* pb.TxQueue , error ) {
410456 var txQueues []* pb.TxQueue
411457 for txQueueIndex , xpsCPUListStr := range txQueueToXPS {
@@ -474,13 +520,16 @@ func thisSystemConfig(mdsIfaces []networkutils.NetworkInterface) (*pb.SystemConf
474520 return nil , fmt .Errorf ("parsing ethtool -l output for %q: %w" , nicName , err )
475521 }
476522
477- irqs , err := deviceIRQs (nicName )
478- if err != nil {
479- return nil , fmt .Errorf ("getting device IRQs for %q: %w" , nicName , err )
480- }
481- queueToIRQs , err := queueIndexToIRQs (irqs , queueCounts )
482- if err != nil {
483- return nil , fmt .Errorf ("converting IRQs to queue index to IRQs for %q: %w" , nicName , err )
523+ var queueToIRQs * irqCPULists
524+ if nicType != networkutils .NICTypeIRDMA && nicType != networkutils .NICTypeMRDMA {
525+ irqs , err := deviceIRQs (nicName )
526+ if err != nil {
527+ return nil , fmt .Errorf ("getting device IRQs for %q: %w" , nicName , err )
528+ }
529+ queueToIRQs , err = queueIndexToIRQs (irqs , queueCounts )
530+ if err != nil {
531+ return nil , fmt .Errorf ("converting IRQs to queue index to IRQs for %q: %w" , nicName , err )
532+ }
484533 }
485534
486535 txQueueToXPS , err := queueIndexToXPS (nicName )
@@ -493,12 +542,24 @@ func thisSystemConfig(mdsIfaces []networkutils.NetworkInterface) (*pb.SystemConf
493542 return nil , fmt .Errorf ("building queues for %q: %w" , nicName , err )
494543 }
495544
496- nic := pb.NicExpectation_builder {
545+ nicBuilder := pb.NicExpectation_builder {
497546 Type : proto .String (nicType ),
498547 TxQueues : txQueues ,
499548 RxQueues : rxQueues ,
500- }.Build ()
501- nics = append (nics , nic )
549+ }
550+
551+ if rings , err := ringSizesForInterface (nicName ); err == nil {
552+ if rings .CurrentRX >= 0 {
553+ nicBuilder .RxRingSize = proto .Int32 (int32 (rings .CurrentRX ))
554+ }
555+ if rings .CurrentTX >= 0 {
556+ nicBuilder .TxRingSize = proto .Int32 (int32 (rings .CurrentTX ))
557+ }
558+ } else {
559+ return nil , fmt .Errorf ("getting ring sizes for %q: %w" , nicName , err )
560+ }
561+
562+ nics = append (nics , nicBuilder .Build ())
502563 }
503564
504565 return pb.SystemConfig_builder {
@@ -543,6 +604,20 @@ func TestDeviceConfig(t *testing.T) {
543604 t .Fatalf ("thisSystemConfig(mdsIfaces) = err: %v, want nil" , err )
544605 }
545606
607+ // Only assert the ring size if they're set in the expected config.
608+ for i , wantNic := range wantSystemConfig .GetNics () {
609+ if i >= len (gotSystemConfig .GetNics ()) {
610+ break
611+ }
612+ gotNic := gotSystemConfig .GetNics ()[i ]
613+ if ! wantNic .HasRxRingSize () {
614+ gotNic .ClearRxRingSize ()
615+ }
616+ if ! wantNic .HasTxRingSize () {
617+ gotNic .ClearTxRingSize ()
618+ }
619+ }
620+
546621 if diff := cmp .Diff (wantSystemConfig , gotSystemConfig ,
547622 protocmp .Transform (),
548623 protocmp .SortRepeatedFields (& pb.NicExpectation {}, "tx_queues" ),
0 commit comments