Skip to content

Commit 6f8192c

Browse files
authored
Merge pull request #314 from sunya-ch/upgrade-multi-nicd-ginkgo
chore: increase test coverage in multi-nicd to 60%
2 parents 785d61f + 94bf0aa commit 6f8192c

10 files changed

Lines changed: 663 additions & 322 deletions

File tree

daemon/src/allocator/allocator.go

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ type allocateRecord struct {
8080
LastOffset int
8181
}
8282

83+
type allocation struct {
84+
backend.Allocation
85+
interfaceName string
86+
}
87+
8388
func (r *allocateRecord) Expired() bool {
8489
curr := time.Now()
8590
return curr.Sub(r.Time).Seconds() > HISTORY_TIMEOUT
@@ -143,6 +148,10 @@ func getIPValue(address string) IPValue {
143148
return IPValue{Address: address, Value: addrToValue(ip)}
144149
}
145150

151+
// getAddressByIndex returns IP addres in string according to CIDR and index.
152+
// 1. getIPValue from CIDR for IPValue (with int value)
153+
// 2. add index to value in int
154+
// 3. convert int back to string with valueToAddrStr
146155
func getAddressByIndex(cidr string, index int) string {
147156
startIPInIpValue := getIPValue(cidr)
148157
addressByIndex := startIPInIpValue.Value + int64(index)
@@ -154,10 +163,7 @@ type ExcludeRange struct {
154163
MaxIndex int
155164
}
156165

157-
func (r ExcludeRange) Contains(index int) bool {
158-
return index >= r.MinIndex && index <= r.MaxIndex
159-
}
160-
166+
// getExcludeRanges returns ExcludeRange with min/max indexes within given CIDR.
161167
func getExcludeRanges(cidr string, excludes []string) []ExcludeRange {
162168
exludeRanges := []ExcludeRange{}
163169
startIPInIpValue := getIPValue(cidr)
@@ -180,7 +186,6 @@ func getExcludeRanges(cidr string, excludes []string) []ExcludeRange {
180186
MaxIndex: excludeStartIndex + maxIndex,
181187
}
182188
exludeRanges = append(exludeRanges, r)
183-
184189
}
185190
}
186191
return exludeRanges
@@ -226,9 +231,22 @@ func AllocateIP(req IPRequest) []IPResponse {
226231
}
227232
ippoolSpecMap, err := IppoolHandler.ListIPPool(listOptions)
228233
if err != nil {
234+
allocatorLock.Unlock()
229235
return responses
230236
}
237+
newAllocations := allocateIP(podName, podNamespace, interfaceNames, offset, ippoolSpecMap)
238+
responses = applyNewAllocations(ippoolSpecMap, newAllocations)
239+
allocatorLock.Unlock()
240+
241+
elapsed := time.Since(startAllocate)
242+
log.Println(fmt.Sprintf("Allocate elapsed: %d us", int64(elapsed/time.Microsecond)))
243+
return responses
244+
}
245+
246+
func allocateIP(podName, podNamespace string, interfaceNames []string, offset int,
247+
ippoolSpecMap map[string]backend.IPPoolType) map[string]allocation {
231248

249+
newAllocations := make(map[string]allocation)
232250
for ippoolName, _ := range ippoolSpecMap {
233251
if len(interfaceNames) == 0 {
234252
// no more interfaces to allocate
@@ -303,39 +321,49 @@ func AllocateIP(req IPRequest) []IPResponse {
303321
Address: nextAddress,
304322
}
305323
log.Println(newAllocation)
306-
toInsertIndex := -1
307-
for allocationIndex, allocation := range allocations {
308-
if allocation.Index > newAllocation.Index {
309-
toInsertIndex = allocationIndex
310-
}
324+
newAllocations[ippoolName] = allocation{
325+
Allocation: newAllocation,
326+
interfaceName: originalInterfaceName,
311327
}
312-
if toInsertIndex == -1 {
313-
allocations = append(allocations, newAllocation)
314-
} else {
315-
appendedAllocation := append(allocations[0:toInsertIndex], newAllocation)
316-
allocations = append(appendedAllocation, allocations[toInsertIndex:]...)
328+
} else {
329+
log.Println(fmt.Sprintf("Cannot get NextAddress for %s", podCIDR))
330+
}
331+
}
332+
return newAllocations
333+
}
334+
335+
func applyNewAllocations(ippoolSpecMap map[string]backend.IPPoolType, newAllocations map[string]allocation) []IPResponse {
336+
var responses []IPResponse
337+
for ippoolName, newAllocation := range newAllocations {
338+
spec := ippoolSpecMap[ippoolName]
339+
allocations := spec.Allocations
340+
341+
toInsertIndex := -1
342+
for allocationIndex, allocation := range allocations {
343+
if allocation.Index > newAllocation.Index {
344+
toInsertIndex = allocationIndex
317345
}
346+
}
347+
if toInsertIndex == -1 {
348+
allocations = append(allocations, newAllocation.Allocation)
349+
} else {
350+
appendedAllocation := append(allocations[0:toInsertIndex], newAllocation.Allocation)
351+
allocations = append(appendedAllocation, allocations[toInsertIndex:]...)
352+
}
318353

319-
_, err = IppoolHandler.PatchIPPool(ippoolName, allocations)
320-
if err == nil {
321-
response := IPResponse{
322-
InterfaceName: originalInterfaceName, // Use original VF name instead of PF name
323-
IPAddress: nextAddress,
324-
VLANBlockSize: strings.Split(spec.VlanCIDR, "/")[1],
325-
}
326-
log.Println(fmt.Sprintf("Append response %v (ip=%s)", response, nextAddress))
327-
responses = append(responses, response)
328-
} else {
329-
log.Println(fmt.Sprintf("Cannot patch IPPool: %v", err))
354+
_, err := IppoolHandler.PatchIPPool(ippoolName, allocations)
355+
if err == nil {
356+
response := IPResponse{
357+
InterfaceName: newAllocation.interfaceName, // Use original VF name instead of PF name
358+
IPAddress: newAllocation.Address,
359+
VLANBlockSize: strings.Split(spec.VlanCIDR, "/")[1],
330360
}
361+
log.Println(fmt.Sprintf("Append response %v (ip=%s)", response, newAllocation.Address))
362+
responses = append(responses, response)
331363
} else {
332-
log.Println(fmt.Sprintf("Cannot get NextAddress for %s", podCIDR))
364+
log.Println(fmt.Sprintf("Cannot patch IPPool: %v", err))
333365
}
334366
}
335-
allocatorLock.Unlock()
336-
337-
elapsed := time.Since(startAllocate)
338-
log.Println(fmt.Sprintf("Allocate elapsed: %d us", int64(elapsed/time.Microsecond)))
339367
return responses
340368
}
341369

@@ -449,4 +477,3 @@ func FlushExpiredHistory() {
449477
}
450478
}
451479
}
452-

daemon/src/allocator/allocator_test.go

Lines changed: 151 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -32,69 +32,165 @@ func genAllocation(indexes []int) []backend.Allocation {
3232
}
3333

3434
var _ = Describe("Test Allocator", func() {
35-
initIndexes := []int{1, 2, 3, 8, 13, 18}
36-
allocations := genAllocation(initIndexes)
3735

38-
It("find simple next available index", func() {
39-
indexes := []int{1, 2, 3, 8, 13, 18}
40-
nextIndex := FindAvailableIndex(indexes, 0)
41-
Expect(nextIndex).To(Equal(4))
42-
})
36+
Context("Allocate", func() {
37+
initIndexes := []int{1, 2, 3, 8, 13, 18}
38+
allocations := genAllocation(initIndexes)
4339

44-
It("find next available index with exclude range over consecutive order", func() {
45-
excludes := []ExcludeRange{
46-
ExcludeRange{
47-
MinIndex: 4,
48-
MaxIndex: 6,
40+
DescribeTable("FindAvailableIndex",
41+
func(excludes []ExcludeRange, expectedIndex []int, expected int) {
42+
indexes := GenerateAllocateIndexes(allocations, 20, excludes)
43+
Expect(indexes).To(Equal(expectedIndex))
44+
nextIndex := FindAvailableIndex(indexes, 0)
45+
Expect(nextIndex).To(Equal(expected))
4946
},
50-
}
51-
indexes := GenerateAllocateIndexes(allocations, 20, excludes)
52-
Expect(indexes).To(Equal([]int{1, 2, 3, 4, 5, 6, 8, 13, 18}))
53-
nextIndex := FindAvailableIndex(indexes, 0)
54-
Expect(nextIndex).To(Equal(7))
55-
})
56-
It("find next available index with exclude range over non-consecutive order", func() {
57-
excludes := []ExcludeRange{
58-
ExcludeRange{
59-
MinIndex: 4,
60-
MaxIndex: 7,
47+
Entry("no excludes", []ExcludeRange{}, []int{1, 2, 3, 8, 13, 18}, 4),
48+
Entry("excludes consecutive order", []ExcludeRange{
49+
ExcludeRange{
50+
MinIndex: 4,
51+
MaxIndex: 6,
52+
},
6153
},
62-
}
63-
64-
indexes := GenerateAllocateIndexes(allocations, 20, excludes)
65-
Expect(indexes).To(Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 13, 18}))
66-
nextIndex := FindAvailableIndex(indexes, 0)
67-
Expect(nextIndex).To(Equal(9))
68-
})
69-
70-
It("find next available index with exclude range over non-consecutive and then consecutive order", func() {
71-
excludes := []ExcludeRange{
72-
ExcludeRange{
73-
MinIndex: 4,
74-
MaxIndex: 7,
54+
[]int{1, 2, 3, 4, 5, 6, 8, 13, 18},
55+
7,
56+
),
57+
Entry("excludes non-consecutive order", []ExcludeRange{
58+
ExcludeRange{
59+
MinIndex: 4,
60+
MaxIndex: 7,
61+
},
7562
},
76-
ExcludeRange{
77-
MinIndex: 9,
78-
MaxIndex: 12,
63+
[]int{1, 2, 3, 4, 5, 6, 7, 8, 13, 18},
64+
9,
65+
),
66+
Entry("excludes non-consecutive and then consecutive order", []ExcludeRange{
67+
ExcludeRange{
68+
MinIndex: 4,
69+
MaxIndex: 7,
70+
},
71+
ExcludeRange{
72+
MinIndex: 9,
73+
MaxIndex: 12,
74+
},
7975
},
80-
}
81-
82-
indexes := GenerateAllocateIndexes(allocations, 20, excludes)
83-
Expect(indexes).To(Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 18}))
84-
nextIndex := FindAvailableIndex(indexes, 0)
85-
Expect(nextIndex).To(Equal(14))
76+
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 18},
77+
14,
78+
),
79+
)
80+
81+
DescribeTable("getAddressByIndex", func(cidr string, index int, expectedIP string) {
82+
result := getAddressByIndex(cidr, index)
83+
Expect(result).To(Equal(expectedIP))
84+
},
85+
Entry("zero index", "10.0.0.0/16", 0, "10.0.0.0"),
86+
Entry("first index", "10.0.0.0/16", 1, "10.0.0.1"),
87+
Entry("shifted index", "10.0.0.0/16", 256, "10.0.1.0"),
88+
)
89+
90+
DescribeTable("getExcludeRanges", func(cidr string, excludes []string, expected []ExcludeRange) {
91+
result := getExcludeRanges(cidr, excludes)
92+
Expect(result).To(BeEquivalentTo(expected))
93+
},
94+
Entry("empty", "10.0.0.0/16", []string{}, []ExcludeRange{}),
95+
Entry("inner exclude", "10.0.0.0/16", []string{"10.0.0.0/24"},
96+
[]ExcludeRange{
97+
ExcludeRange{
98+
MinIndex: 0,
99+
MaxIndex: 255,
100+
},
101+
},
102+
),
103+
Entry("multiple inner excludes", "10.0.0.0/16", []string{"10.0.0.0/24", "10.0.1.1/32"},
104+
[]ExcludeRange{
105+
ExcludeRange{
106+
MinIndex: 0,
107+
MaxIndex: 255,
108+
},
109+
ExcludeRange{
110+
MinIndex: 257,
111+
MaxIndex: 257,
112+
},
113+
},
114+
),
115+
Entry("outer exclude", "10.0.0.0/24", []string{"10.0.0.0/23"},
116+
[]ExcludeRange{
117+
ExcludeRange{
118+
MinIndex: 0,
119+
MaxIndex: 511,
120+
},
121+
},
122+
),
123+
)
124+
125+
DescribeTable("allocateIP", func(interfaceNames []string, ippoolSpecMap map[string]backend.IPPoolType, expectedAddress map[string]string) {
126+
newAllocations := allocateIP("test-pod", "test-namespace", interfaceNames, 1, ippoolSpecMap)
127+
Expect(newAllocations).To(HaveLen(len(expectedAddress)))
128+
for ippoolName, allocation := range newAllocations {
129+
address, found := expectedAddress[ippoolName]
130+
Expect(found).To(BeTrue())
131+
Expect(allocation.Address).To(BeEquivalentTo(address))
132+
}
133+
},
134+
Entry("no interface name", []string{}, map[string]backend.IPPoolType{
135+
"eth0": backend.IPPoolType{InterfaceName: "eth0", PodCIDR: "192.168.0.0/24"},
136+
}, map[string]string{}),
137+
Entry("no ippool", []string{"eth0"}, map[string]backend.IPPoolType{}, map[string]string{}),
138+
Entry("first allocation", []string{"eth0"}, map[string]backend.IPPoolType{
139+
"eth0": backend.IPPoolType{InterfaceName: "eth0", PodCIDR: "192.168.0.0/24"},
140+
}, map[string]string{
141+
"eth0": "192.168.0.1",
142+
}),
143+
Entry("second allocation", []string{"eth0"}, map[string]backend.IPPoolType{
144+
"eth0": backend.IPPoolType{
145+
InterfaceName: "eth0",
146+
PodCIDR: "192.168.0.0/24",
147+
Allocations: []backend.Allocation{
148+
{
149+
Pod: "dummy",
150+
Namespace: "test-namespace",
151+
Index: 1,
152+
Address: "192.168.0.1"},
153+
},
154+
},
155+
}, map[string]string{
156+
"eth0": "192.168.0.2",
157+
}),
158+
Entry("reuse allocation", []string{"eth0"}, map[string]backend.IPPoolType{
159+
"eth0": backend.IPPoolType{
160+
InterfaceName: "eth0",
161+
PodCIDR: "192.168.0.0/24",
162+
Allocations: []backend.Allocation{
163+
{
164+
Pod: "dummy",
165+
Namespace: "test-namespace",
166+
Index: 255,
167+
Address: "192.168.0.255"},
168+
},
169+
},
170+
}, map[string]string{
171+
"eth0": "192.168.0.1",
172+
}),
173+
)
86174
})
87175

88-
It("force expired", func() {
89-
podName := "A"
90-
deallocateHistory[podName] = &allocateRecord{
91-
Time: time.Now(),
92-
LastOffset: 1,
93-
}
94-
Expect(deallocateHistory[podName].Expired()).To(Equal(false))
95-
deallocateHistory[podName].Time = deallocateHistory[podName].Time.Add(time.Duration(-HISTORY_TIMEOUT-1) * time.Second)
96-
Expect(deallocateHistory[podName].Expired()).To(Equal(true))
176+
Context("Deallocate", func() {
177+
178+
It("force expired", func() {
179+
podName := "A"
180+
deallocateHistory[podName] = &allocateRecord{
181+
Time: time.Now(),
182+
LastOffset: 1,
183+
}
184+
Expect(deallocateHistory[podName].Expired()).To(Equal(false))
185+
deallocateHistory[podName].Time = deallocateHistory[podName].Time.Add(time.Duration(-HISTORY_TIMEOUT-1) * time.Second)
186+
Expect(deallocateHistory[podName].Expired()).To(Equal(true))
187+
FlushExpiredHistory()
188+
_, found := deallocateHistory[podName]
189+
Expect(found).To(BeFalse())
190+
})
191+
97192
})
193+
98194
})
99195

100196
var _ = Describe("Test VF/PF Interface Mapping", func() {
@@ -210,7 +306,6 @@ var _ = Describe("Test VF/PF Interface Mapping", func() {
210306
Expect(result).To(Equal("ens9f0np0"))
211307
})
212308

213-
214309
})
215310

216311
Describe("Interface matching logic", func() {
@@ -226,7 +321,7 @@ var _ = Describe("Test VF/PF Interface Mapping", func() {
226321
// Mock the VF detection functions
227322
originalIsVF := isVF
228323
originalGetPF := getPFInterfaceName
229-
defer func() {
324+
defer func() {
230325
isVF = originalIsVF
231326
getPFInterfaceName = originalGetPF
232327
}()
@@ -377,4 +472,3 @@ var _ = Describe("Test VF/PF Interface Mapping", func() {
377472
})
378473
})
379474
})
380-

0 commit comments

Comments
 (0)