1
2
3
4
19
20 package iptables
21
22 import (
23 "fmt"
24 "testing"
25 "time"
26
27 v1 "k8s.io/api/core/v1"
28 discovery "k8s.io/api/discovery/v1"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/apimachinery/pkg/util/intstr"
31 iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
32 netutils "k8s.io/utils/net"
33 "k8s.io/utils/ptr"
34 )
35
36
37
38
39
40
41
42
43
44
45
46
47
48 func TestNumberIptablesRules(t *testing.T) {
49 testCases := []struct {
50 name string
51 epsFunc func(eps *discovery.EndpointSlice)
52 svcFunc func(svc *v1.Service)
53 services int
54 epPerService int
55 expectedFilterRules int
56 expectedNatRules int
57 }{
58 {
59 name: "0 Services 0 EndpointsPerService - ClusterIP",
60 services: 0,
61 epPerService: 0,
62 expectedFilterRules: 4,
63 expectedNatRules: 5,
64 },
65 {
66 name: "1 Services 0 EndpointPerService - ClusterIP",
67 services: 1,
68 epPerService: 0,
69 expectedFilterRules: 5,
70 expectedNatRules: 5,
71 },
72 {
73 name: "1 Services 1 EndpointPerService - ClusterIP",
74 services: 1,
75 epPerService: 1,
76 expectedFilterRules: 4,
77 expectedNatRules: 10,
78 },
79 {
80 name: "1 Services 2 EndpointPerService - ClusterIP",
81 services: 1,
82 epPerService: 2,
83 expectedFilterRules: 4,
84 expectedNatRules: 13,
85 },
86 {
87 name: "1 Services 10 EndpointPerService - ClusterIP",
88 services: 1,
89 epPerService: 10,
90 expectedFilterRules: 4,
91 expectedNatRules: 37,
92 },
93 {
94 name: "10 Services 0 EndpointsPerService - ClusterIP",
95 services: 10,
96 epPerService: 0,
97 expectedFilterRules: 14,
98 expectedNatRules: 5,
99 },
100 {
101 name: "10 Services 1 EndpointPerService - ClusterIP",
102 services: 10,
103 epPerService: 1,
104 expectedFilterRules: 4,
105 expectedNatRules: 55,
106 },
107 {
108 name: "10 Services 2 EndpointPerService - ClusterIP",
109 services: 10,
110 epPerService: 2,
111 expectedFilterRules: 4,
112 expectedNatRules: 85,
113 },
114 {
115 name: "10 Services 10 EndpointPerService - ClusterIP",
116 services: 10,
117 epPerService: 10,
118 expectedFilterRules: 4,
119 expectedNatRules: 325,
120 },
121
122 {
123 name: "0 Services 0 EndpointsPerService - LoadBalancer",
124 svcFunc: func(svc *v1.Service) {
125 svc.Spec.Type = v1.ServiceTypeLoadBalancer
126 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
127 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
128 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
129 IP: "1.2.3.4",
130 }}
131 },
132 services: 0,
133 epPerService: 0,
134 expectedFilterRules: 4,
135 expectedNatRules: 5,
136 },
137 {
138 name: "1 Services 0 EndpointPerService - LoadBalancer",
139 svcFunc: func(svc *v1.Service) {
140 svc.Spec.Type = v1.ServiceTypeLoadBalancer
141 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
142 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
143 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
144 IP: "1.2.3.4",
145 }}
146 },
147 services: 1,
148 epPerService: 0,
149 expectedFilterRules: 8,
150 expectedNatRules: 5,
151 },
152 {
153 name: "1 Services 1 EndpointPerService - LoadBalancer",
154 svcFunc: func(svc *v1.Service) {
155 svc.Spec.Type = v1.ServiceTypeLoadBalancer
156 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
157 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
158 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
159 IP: "1.2.3.4",
160 }}
161 },
162 services: 1,
163 epPerService: 1,
164 expectedFilterRules: 5,
165 expectedNatRules: 17,
166 },
167 {
168 name: "1 Services 2 EndpointPerService - LoadBalancer",
169 svcFunc: func(svc *v1.Service) {
170 svc.Spec.Type = v1.ServiceTypeLoadBalancer
171 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
172 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
173 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
174 IP: "1.2.3.4",
175 }}
176 },
177 services: 1,
178 epPerService: 2,
179 expectedFilterRules: 5,
180 expectedNatRules: 20,
181 },
182 {
183 name: "1 Services 10 EndpointPerService - LoadBalancer",
184 svcFunc: func(svc *v1.Service) {
185 svc.Spec.Type = v1.ServiceTypeLoadBalancer
186 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
187 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
188 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
189 IP: "1.2.3.4",
190 }}
191 },
192 services: 1,
193 epPerService: 10,
194 expectedFilterRules: 5,
195 expectedNatRules: 44,
196 },
197 {
198 name: "10 Services 0 EndpointsPerService - LoadBalancer",
199 svcFunc: func(svc *v1.Service) {
200 svc.Spec.Type = v1.ServiceTypeLoadBalancer
201 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
202 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
203 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
204 IP: "1.2.3.4",
205 }}
206 },
207 services: 10,
208 epPerService: 0,
209 expectedFilterRules: 44,
210 expectedNatRules: 5,
211 },
212 {
213 name: "10 Services 1 EndpointPerService - LoadBalancer",
214 svcFunc: func(svc *v1.Service) {
215 svc.Spec.Type = v1.ServiceTypeLoadBalancer
216 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
217 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
218 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
219 IP: "1.2.3.4",
220 }}
221 },
222 services: 10,
223 epPerService: 1,
224 expectedFilterRules: 14,
225 expectedNatRules: 125,
226 },
227 {
228 name: "10 Services 2 EndpointPerService - LoadBalancer",
229 svcFunc: func(svc *v1.Service) {
230 svc.Spec.Type = v1.ServiceTypeLoadBalancer
231 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
232 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
233 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
234 IP: "1.2.3.4",
235 }}
236 },
237 services: 10,
238 epPerService: 2,
239 expectedFilterRules: 14,
240 expectedNatRules: 155,
241 },
242 {
243 name: "10 Services 10 EndpointPerService - LoadBalancer",
244 svcFunc: func(svc *v1.Service) {
245 svc.Spec.Type = v1.ServiceTypeLoadBalancer
246 svc.Spec.ExternalIPs = []string{"1.2.3.4"}
247 svc.Spec.LoadBalancerSourceRanges = []string{" 1.2.3.4/28"}
248 svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
249 IP: "1.2.3.4",
250 }}
251 },
252 services: 10,
253 epPerService: 10,
254 expectedFilterRules: 14,
255 expectedNatRules: 395,
256 },
257 }
258
259 for _, test := range testCases {
260 t.Run(test.name, func(t *testing.T) {
261 ipt := iptablestest.NewFake()
262 fp := NewFakeProxier(ipt)
263
264 svcs, eps := generateServiceEndpoints(test.services, test.epPerService, test.epsFunc, test.svcFunc)
265
266 makeServiceMap(fp, svcs...)
267 populateEndpointSlices(fp, eps...)
268
269 now := time.Now()
270 fp.syncProxyRules()
271 t.Logf("time to sync rule: %v", time.Since(now))
272 t.Logf("iptables data size: %d bytes", fp.iptablesData.Len())
273
274 if fp.filterRules.Lines() != test.expectedFilterRules {
275 t.Errorf("expected number of Filter rules: %d, got: %d", test.expectedFilterRules, fp.filterRules.Lines())
276 }
277
278 if fp.natRules.Lines() != test.expectedNatRules {
279 t.Errorf("expected number of NAT rules: %d, got: %d", test.expectedNatRules, fp.natRules.Lines())
280 }
281
282
283
284 })
285 }
286 }
287
288 func Test_generateServiceEndpoints(t *testing.T) {
289 testCases := []struct {
290 name string
291 services int
292 epPerService int
293 svcType v1.ServiceType
294 }{
295 {
296 name: "Generate 10 Services with 10 Endpoints per Service and LoadBalancer Type",
297 services: 10,
298 epPerService: 10,
299 svcType: v1.ServiceTypeLoadBalancer,
300 },
301 {
302 name: "Generate 10 Services with 20 Endpoints per Service and NodePort Type",
303 services: 10,
304 epPerService: 20,
305 svcType: v1.ServiceTypeNodePort,
306 },
307 }
308
309 for _, test := range testCases {
310 t.Run(test.name, func(t *testing.T) {
311
312 svcFunc := func(svc *v1.Service) {
313 svc.Spec.Type = test.svcType
314 }
315
316 epsFunc := func(eps *discovery.EndpointSlice) {
317 for i := range eps.Endpoints {
318 nodeName := fmt.Sprintf("node-%d", i)
319 eps.Endpoints[i].NodeName = &nodeName
320 }
321 }
322
323 svcs, eps := generateServiceEndpoints(test.services, test.epPerService, epsFunc, svcFunc)
324
325 if len(svcs) != test.services {
326 t.Fatalf("expected %d service, received %d", test.services, len(svcs))
327 }
328 if len(eps) != test.services {
329 t.Fatalf("expected %d endpoint slice , received %d", test.services, len(eps))
330 }
331
332 for i := 0; i < test.services; i++ {
333 if svcs[i].Spec.Type != test.svcType {
334 t.Fatalf("expected Service Type %s, got %s", test.svcType, svcs[i].Spec.Type)
335 }
336 if eps[i].ObjectMeta.Labels[discovery.LabelServiceName] != svcs[i].Name {
337 t.Fatalf("endpoint slice reference %s instead of Service %s", eps[i].ObjectMeta.Labels[discovery.LabelServiceName], svcs[i].Name)
338 }
339 if len(eps[i].Endpoints) != test.epPerService {
340 t.Fatalf("expected %d endpoints per slice , received %d", test.epPerService, len(eps[i].Endpoints))
341 }
342 for j := 0; j < test.epPerService; j++ {
343 nodeName := fmt.Sprintf("node-%d", j)
344 if *eps[i].Endpoints[j].NodeName != nodeName {
345 t.Errorf("Endpoint %d on EndpointSlice %d expected Nodename %s, got %s", j, i, nodeName, *eps[i].Endpoints[j].NodeName)
346 }
347 }
348 }
349 })
350 }
351
352 }
353
354
355 func generateServiceEndpoints(nServices, nEndpoints int, epsFunc func(eps *discovery.EndpointSlice), svcFunc func(svc *v1.Service)) ([]*v1.Service, []*discovery.EndpointSlice) {
356 services := make([]*v1.Service, nServices)
357 endpointSlices := make([]*discovery.EndpointSlice, nServices)
358
359
360 basePort := 80
361 base := netutils.BigForIP(netutils.ParseIPSloppy("10.0.0.1"))
362
363
364 baseEp := netutils.BigForIP(netutils.ParseIPSloppy("172.16.0.1"))
365 epPort := 8080
366
367 eps := &discovery.EndpointSlice{
368 ObjectMeta: metav1.ObjectMeta{
369 Name: "ep",
370 Namespace: "namespace",
371 },
372 AddressType: discovery.AddressTypeIPv4,
373 Endpoints: []discovery.Endpoint{},
374 Ports: []discovery.EndpointPort{{
375 Name: ptr.To(fmt.Sprintf("%d", epPort)),
376 Port: ptr.To(int32(epPort)),
377 Protocol: ptr.To(v1.ProtocolTCP),
378 }},
379 }
380
381 for j := 0; j < nEndpoints; j++ {
382 ipEp := netutils.AddIPOffset(baseEp, j)
383 eps.Endpoints = append(eps.Endpoints, discovery.Endpoint{
384 Addresses: []string{ipEp.String()},
385 })
386 }
387
388 if epsFunc != nil {
389 epsFunc(eps)
390 }
391
392
393 svc := &v1.Service{
394 ObjectMeta: metav1.ObjectMeta{
395 Name: "svc",
396 Namespace: "namespace",
397 },
398 Spec: v1.ServiceSpec{
399 Type: v1.ServiceTypeClusterIP,
400 },
401 }
402
403 if svcFunc != nil {
404 svcFunc(svc)
405 }
406
407
408 for i := 0; i < nServices; i++ {
409 ip := netutils.AddIPOffset(base, i)
410 services[i] = svc.DeepCopy()
411 services[i].Name = fmt.Sprintf("svc%d", i)
412 services[i].Spec.ClusterIP = ip.String()
413 services[i].Spec.Ports = []v1.ServicePort{
414 {
415 Name: fmt.Sprintf("%d", epPort),
416 Protocol: v1.ProtocolTCP,
417 Port: int32(basePort + i),
418 TargetPort: intstr.FromInt32(int32(epPort)),
419 },
420 }
421
422 if svc.Spec.Type == v1.ServiceTypeNodePort || svc.Spec.Type == v1.ServiceTypeLoadBalancer {
423 services[i].Spec.Ports[0].NodePort = int32(30000 + i)
424
425 }
426 if svc.Spec.Type == v1.ServiceTypeLoadBalancer {
427 services[i].Spec.HealthCheckNodePort = int32(32000 + nServices + i)
428 }
429
430 endpointSlices[i] = eps.DeepCopy()
431 endpointSlices[i].Name = services[i].Name
432 endpointSlices[i].ObjectMeta.Labels = map[string]string{
433 discovery.LabelServiceName: services[i].Name,
434 }
435
436 }
437
438 return services, endpointSlices
439 }
440
View as plain text