@@ -19,6 +19,8 @@ package e2enode
19
19
import (
20
20
"fmt"
21
21
"io/ioutil"
22
+ "os"
23
+ "path/filepath"
22
24
"sort"
23
25
"strconv"
24
26
"strings"
@@ -44,8 +46,7 @@ func (R *numaPodResources) CheckAlignment() bool {
44
46
}
45
47
}
46
48
for _ , devNode := range R .PCIDevsToNUMANode {
47
- // TODO: explain -1
48
- if devNode != - 1 && nodeNum != devNode {
49
+ if nodeNum != devNode {
49
50
return false
50
51
}
51
52
}
@@ -88,7 +89,7 @@ func getCPUsPerNUMANode(nodeNum int) ([]int, error) {
88
89
return cpus .ToSlice (), nil
89
90
}
90
91
91
- func getCPUToNUMANodeMapFromEnv (f * framework.Framework , pod * v1.Pod , environ map [string ]string , numaNodes int ) (map [int ]int , error ) {
92
+ func getCPUToNUMANodeMapFromEnv (f * framework.Framework , pod * v1.Pod , cnt * v1. Container , environ map [string ]string , numaNodes int ) (map [int ]int , error ) {
92
93
var cpuIDs []int
93
94
cpuListAllowedEnvVar := "CPULIST_ALLOWED"
94
95
@@ -102,12 +103,12 @@ func getCPUToNUMANodeMapFromEnv(f *framework.Framework, pod *v1.Pod, environ map
102
103
}
103
104
}
104
105
if len (cpuIDs ) == 0 {
105
- return nil , fmt .Errorf ("variable %q found in environ" , cpuListAllowedEnvVar )
106
+ return nil , fmt .Errorf ("variable %q not found in environ" , cpuListAllowedEnvVar )
106
107
}
107
108
108
109
cpusPerNUMA := make (map [int ][]int )
109
110
for numaNode := 0 ; numaNode < numaNodes ; numaNode ++ {
110
- nodeCPUList := f .ExecCommandInContainer (pod .Name , pod . Spec . Containers [ 0 ] .Name ,
111
+ nodeCPUList := f .ExecCommandInContainer (pod .Name , cnt .Name ,
111
112
"/bin/cat" , fmt .Sprintf ("/sys/devices/system/node/node%d/cpulist" , numaNode ))
112
113
113
114
cpus , err := cpuset .Parse (nodeCPUList )
@@ -137,7 +138,7 @@ func getCPUToNUMANodeMapFromEnv(f *framework.Framework, pod *v1.Pod, environ map
137
138
return CPUMap , nil
138
139
}
139
140
140
- func getPCIDeviceToNumaNodeMapFromEnv (f * framework.Framework , pod * v1.Pod , environ map [string ]string ) (map [string ]int , error ) {
141
+ func getPCIDeviceToNumaNodeMapFromEnv (f * framework.Framework , pod * v1.Pod , cnt * v1. Container , environ map [string ]string ) (map [string ]int , error ) {
141
142
pciDevPrefix := "PCIDEVICE_"
142
143
// at this point we don't care which plugin selected the device,
143
144
// we only need to know which devices were assigned to the POD.
@@ -152,19 +153,11 @@ func getPCIDeviceToNumaNodeMapFromEnv(f *framework.Framework, pod *v1.Pod, envir
152
153
// a single plugin can allocate more than a single device
153
154
pciDevs := strings .Split (value , "," )
154
155
for _ , pciDev := range pciDevs {
155
- pciDevNUMANode := f .ExecCommandInContainer (pod .Name , pod . Spec . Containers [ 0 ] .Name ,
156
+ pciDevNUMANode := f .ExecCommandInContainer (pod .Name , cnt .Name ,
156
157
"/bin/cat" , fmt .Sprintf ("/sys/bus/pci/devices/%s/numa_node" , pciDev ))
157
-
158
- nodeNum , err := strconv .Atoi (pciDevNUMANode )
159
- if err != nil {
160
- return nil , err
161
- }
162
- NUMAPerDev [pciDev ] = nodeNum
158
+ NUMAPerDev [pciDev ] = numaNodeFromSysFsEntry (pciDevNUMANode )
163
159
}
164
160
}
165
- if len (NUMAPerDev ) == 0 {
166
- return nil , fmt .Errorf ("no PCI devices found in environ" )
167
- }
168
161
return NUMAPerDev , nil
169
162
}
170
163
@@ -184,29 +177,97 @@ func makeEnvMap(logs string) (map[string]string, error) {
184
177
return envMap , nil
185
178
}
186
179
187
- func checkNUMAAlignment (f * framework.Framework , pod * v1.Pod , logs string , numaNodes int ) (numaPodResources , error ) {
180
+ type testEnvInfo struct {
181
+ numaNodes int
182
+ sriovResourceName string
183
+ policy string
184
+ }
185
+
186
+ func containerWantsDevices (cnt * v1.Container , envInfo * testEnvInfo ) bool {
187
+ _ , found := cnt .Resources .Requests [v1 .ResourceName (envInfo .sriovResourceName )]
188
+ return found
189
+ }
190
+
191
+ func checkNUMAAlignment (f * framework.Framework , pod * v1.Pod , cnt * v1.Container , logs string , envInfo * testEnvInfo ) (* numaPodResources , error ) {
192
+ var err error
188
193
podEnv , err := makeEnvMap (logs )
189
194
if err != nil {
190
- return numaPodResources {} , err
195
+ return nil , err
191
196
}
192
197
193
- CPUToNUMANode , err := getCPUToNUMANodeMapFromEnv (f , pod , podEnv , numaNodes )
198
+ CPUToNUMANode , err := getCPUToNUMANodeMapFromEnv (f , pod , cnt , podEnv , envInfo . numaNodes )
194
199
if err != nil {
195
- return numaPodResources {} , err
200
+ return nil , err
196
201
}
197
202
198
- PCIDevsToNUMANode , err := getPCIDeviceToNumaNodeMapFromEnv (f , pod , podEnv )
203
+ PCIDevsToNUMANode , err := getPCIDeviceToNumaNodeMapFromEnv (f , pod , cnt , podEnv )
199
204
if err != nil {
200
- return numaPodResources {} , err
205
+ return nil , err
201
206
}
202
207
208
+ if containerWantsDevices (cnt , envInfo ) && len (PCIDevsToNUMANode ) == 0 {
209
+ return nil , fmt .Errorf ("no PCI devices found in environ" )
210
+ }
203
211
numaRes := numaPodResources {
204
212
CPUToNUMANode : CPUToNUMANode ,
205
213
PCIDevsToNUMANode : PCIDevsToNUMANode ,
206
214
}
207
215
aligned := numaRes .CheckAlignment ()
208
216
if ! aligned {
209
- return numaRes , fmt .Errorf ("NUMA resources not aligned" )
217
+ err = fmt .Errorf ("NUMA resources not aligned" )
210
218
}
211
- return numaRes , nil
219
+ return & numaRes , err
220
+ }
221
+
222
+ type pciDeviceInfo struct {
223
+ Address string
224
+ NUMANode int
225
+ IsPhysFn bool
226
+ IsVFn bool
227
+ }
228
+
229
+ func getPCIDeviceInfo (sysPCIDir string ) ([]pciDeviceInfo , error ) {
230
+ var pciDevs []pciDeviceInfo
231
+
232
+ entries , err := ioutil .ReadDir (sysPCIDir )
233
+ if err != nil {
234
+ return nil , err
235
+ }
236
+
237
+ for _ , entry := range entries {
238
+ isPhysFn := false
239
+ isVFn := false
240
+ if _ , err := os .Stat (filepath .Join (sysPCIDir , entry .Name (), "sriov_numvfs" )); err == nil {
241
+ isPhysFn = true
242
+ } else if ! os .IsNotExist (err ) {
243
+ // unexpected error. Bail out
244
+ return nil , err
245
+ }
246
+ if _ , err := os .Stat (filepath .Join (sysPCIDir , entry .Name (), "physfn" )); err == nil {
247
+ isVFn = true
248
+ } else if ! os .IsNotExist (err ) {
249
+ // unexpected error. Bail out
250
+ return nil , err
251
+ }
252
+
253
+ content , err := ioutil .ReadFile (filepath .Join (sysPCIDir , entry .Name (), "numa_node" ))
254
+ if err != nil {
255
+ return nil , err
256
+ }
257
+
258
+ pciDevs = append (pciDevs , pciDeviceInfo {
259
+ Address : entry .Name (),
260
+ NUMANode : numaNodeFromSysFsEntry (string (content )),
261
+ IsPhysFn : isPhysFn ,
262
+ IsVFn : isVFn ,
263
+ })
264
+ }
265
+
266
+ return pciDevs , nil
267
+ }
268
+
269
+ func numaNodeFromSysFsEntry (content string ) int {
270
+ nodeNum , err := strconv .Atoi (strings .TrimSpace (content ))
271
+ framework .ExpectNoError (err , "error detecting the device numa_node from sysfs: %v" , err )
272
+ return nodeNum
212
273
}
0 commit comments