Skip to content

Commit a5933f6

Browse files
a-r-ncopybara-github
authored andcommitted
networkconfig: fix IDPF IRQ vector parsing and RDMA IRQ handling
Support IDPF combined TxRx vectors and ignore non-queue control IRQs. Skip device IRQ handling for RDMA NICs. PiperOrigin-RevId: 951568517
1 parent 1f1f236 commit a5933f6

1 file changed

Lines changed: 92 additions & 17 deletions

File tree

test_suites/networkconfig/deviceconfig_test.go

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ var (
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.
237262
func 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+
409455
func 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

Comments
 (0)