1 package netplan
2
3 import (
4 "bytes"
5 "context"
6 "errors"
7 "fmt"
8 "net"
9 "os"
10 "path/filepath"
11 "testing"
12 "time"
13
14 "github.com/spf13/afero"
15 "github.com/stretchr/testify/assert"
16 "github.com/vishvananda/netns"
17 yaml "gopkg.in/yaml.v3"
18 v1 "k8s.io/api/core/v1"
19 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20 kruntime "k8s.io/apimachinery/pkg/runtime"
21 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
22 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
23 "sigs.k8s.io/controller-runtime/pkg/client"
24 "sigs.k8s.io/controller-runtime/pkg/client/fake"
25
26 edgeconst "edge-infra.dev/pkg/edge/constants"
27 calico "edge-infra.dev/pkg/k8s/net/calico"
28 testnetns "edge-infra.dev/pkg/lib/kernel/netlink/netns"
29 "edge-infra.dev/pkg/lib/uuid"
30 v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1"
31 "edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/config"
32 "edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/plugins/networking/netplan/internal"
33 nodemeta "edge-infra.dev/pkg/sds/ien/node"
34 "edge-infra.dev/pkg/sds/ien/topology"
35 "edge-infra.dev/pkg/sds/lib/networking"
36 "edge-infra.dev/pkg/sds/lib/networking/routing"
37 "edge-infra.dev/test/f2"
38 )
39
40 var (
41 nodeIP = "192.168.1.2"
42 nodeCIDR = "192.168.1.2/24"
43 gateway = "192.168.1.1"
44 dns = "8.8.8.8"
45 iface = "ens4"
46 )
47
48 type netplanMock struct {
49 err error
50 }
51
52 func (nm *netplanMock) Apply() (bool, error) {
53 if nm.err != nil {
54 return false, nm.err
55 }
56 return true, nil
57 }
58
59 func (nm *netplanMock) Close() error {
60 return nil
61 }
62
63 func (nm *netplanMock) Connect() error {
64 return nil
65 }
66
67 var f f2.Framework
68
69 func TestMain(m *testing.M) {
70 f = f2.New(context.Background(), f2.WithExtensions()).
71 Setup().
72 Teardown()
73 os.Exit(f.Run(m))
74 }
75
76 func TestStaticNodeConfiguration_Egress_Gateway_Disabled(t *testing.T) {
77 var kclient client.Client
78 var ienode *v1ien.IENode
79 var ns netns.NsHandle
80 var tearDownFunction func()
81 var macAddress string
82 const gatewayEnabled = false
83
84 feature := f2.NewFeature("netplan with static ip configuration").
85 Setup("Create fake client", func(ctx f2.Context, t *testing.T) f2.Context {
86 ienode = staticIPWorkerNode()
87 workerNode := k8sNode(ienode, metav1.NewTime(metav1.Now().Add(time.Duration(2)*time.Minute)))
88
89 ns, tearDownFunction = testnetns.NewTestingNetworkNamespace(t)
90 assert.NoError(t, testnetns.CreateDummyLink())
91
92 dev, err := testnetns.GetDummyLink()
93 assert.NoError(t, err)
94
95 macAddress = dev.Attrs().HardwareAddr.String()
96 ienode.Spec.Network[0].MacAddress = macAddress
97 ienode.Spec.PrimaryInterface.MacAddresses = append(ienode.Spec.PrimaryInterface.MacAddresses, macAddress)
98
99 kclient = fake.NewClientBuilder().WithScheme(createScheme()).WithObjects(workerNode, createTopologyInfoConfigMap(gatewayEnabled)).Build()
100 return ctx
101 }).
102 Test("netplan applies static configuration with no gateway configuration", func(ctx f2.Context, t *testing.T) f2.Context {
103 assert.NoError(t, netns.Set(ns))
104
105 memFS, err := createMemFS()
106 assert.NoError(t, err)
107
108 netMock := &netplanMock{}
109 cfg := config.NewConfig(kclient, nil, nil, config.Flags{}).WithFs(memFS).WithNetplanAPI(netMock)
110
111 _, err = Plugin{}.Reconcile(ctx, ienode, cfg)
112 assert.NoError(t, err)
113
114 contents, err := afero.ReadFile(memFS, netplanFile)
115 assert.NoError(t, err)
116
117 networkConfig := Template()
118 err = yaml.Unmarshal(contents, networkConfig)
119 assert.NoError(t, err)
120
121 assert.Equal(t, networkConfig.Ethernets[iface].Addresses[0], nodeCIDR)
122 assert.Equal(t, networkConfig.Ethernets[iface].Match.MacAddress, macAddress)
123 assert.Equal(t, networkConfig.Ethernets[iface].Nameservers.Addresses[0], dns)
124 assert.False(t, networkConfig.Ethernets[iface].DHCP4)
125 assert.False(t, networkConfig.Ethernets[iface].Routes[0].OnLink)
126
127
128 assert.Equal(t, networkConfig.Tunnels, map[string]Tunnel{})
129
130 return ctx
131 }).
132 Test("netplan fails and reverts changes to netplan to original file contents", func(ctx f2.Context, t *testing.T) f2.Context {
133 assert.NoError(t, netns.Set(ns))
134
135 memFS, err := createMemFS()
136 assert.NoError(t, err)
137
138 netMock := &netplanMock{err: errors.New("netplan file failed")}
139 cfg := config.NewConfig(kclient, nil, nil, config.Flags{}).WithFs(memFS).WithNetplanAPI(netMock)
140
141 _, err = Plugin{}.Reconcile(ctx, ienode, cfg)
142 assert.Error(t, err)
143
144 contents, err := afero.ReadFile(memFS, netplanFile)
145 assert.NoError(t, err)
146
147 networkConfig := Template()
148 err = yaml.Unmarshal(contents, networkConfig)
149 assert.NoError(t, err)
150
151
152
153 assert.Equal(t, map[string]Ethernet{}, networkConfig.Ethernets)
154
155 sysctlRPFilterConfAsExpected(t, memFS, gatewayEnabled, ienode.Spec.IsGatewayNode(), nil)
156
157 return ctx
158 }).
159 Teardown("teardown testing namespace", func(ctx f2.Context, _ *testing.T) f2.Context {
160 tearDownFunction()
161 return ctx
162 }).Feature()
163
164 f.Test(t, feature)
165 }
166
167 func TestStaticNodeConfiguration_Gateway_Enabled(t *testing.T) {
168 var kclient client.Client
169 var controlPlaneIENode *v1ien.IENode
170 var workerIENode *v1ien.IENode
171 var cfg config.Config
172 var memFs afero.Fs
173 var ns netns.NsHandle
174 var tearDownFunction func()
175 var macAddress string
176 var netServicesCM *v1.ConfigMap
177 const gatewayEnabled = true
178 feature := f2.NewFeature("netplan with static ip configuration").
179 Setup("Create fake client", func(ctx f2.Context, t *testing.T) f2.Context {
180 workerIENode = staticIPWorkerNode()
181 controlPlaneIENode = staticIPControlPlaneNode()
182 controlPlaneNode := k8sNode(controlPlaneIENode, metav1.Now())
183 workerNode := k8sNode(workerIENode, metav1.NewTime(metav1.Now().Add(time.Duration(2)*time.Minute)))
184 netServicesCM = createNetworkServicesConfigMap()
185
186 ns, tearDownFunction = testnetns.NewTestingNetworkNamespace(t)
187 assert.NoError(t, testnetns.CreateDummyLink())
188
189 dev, err := testnetns.GetDummyLink()
190 assert.NoError(t, err)
191
192 macAddress = dev.Attrs().HardwareAddr.String()
193
194 workerIENode.Spec.Network[0].MacAddress = macAddress
195 controlPlaneIENode.Spec.Network[0].MacAddress = macAddress
196 workerIENode.Spec.PrimaryInterface.MacAddresses = append(workerIENode.Spec.PrimaryInterface.MacAddresses, macAddress)
197 controlPlaneIENode.Spec.PrimaryInterface.MacAddresses = append(controlPlaneIENode.Spec.PrimaryInterface.MacAddresses, macAddress)
198
199 kclient = fake.NewClientBuilder().WithScheme(createScheme()).WithObjects(createTopologyInfoConfigMap(gatewayEnabled), controlPlaneNode, workerNode, netServicesCM).Build()
200
201 memoryFS, err := createMemFS()
202 assert.NoError(t, err)
203 memFs = memoryFS
204
205 cfg = config.NewConfig(kclient, nil, nil, config.Flags{}).WithFs(memFs).WithNetplanAPI(&netplanMock{})
206
207 return ctx
208 }).
209 Test("netplan applies static gateway configuration for worker nodes", func(ctx f2.Context, t *testing.T) f2.Context {
210 assert.NoError(t, netns.Set(ns))
211 _, err := Plugin{}.Reconcile(ctx, workerIENode, cfg)
212 assert.NoError(t, err)
213
214 contents, err := afero.ReadFile(memFs, netplanFile)
215 assert.NoError(t, err)
216
217 networkConfig := Template()
218 err = yaml.Unmarshal(contents, networkConfig)
219 assert.NoError(t, err)
220
221 assert.Equal(t, networkConfig.Ethernets[iface].Addresses[0], nodeCIDR)
222 assert.Equal(t, networkConfig.Ethernets[iface].Nameservers.Addresses[0], dns)
223 assert.False(t, networkConfig.Ethernets[iface].DHCP4)
224
225 assert.Contains(t, networkConfig.Tunnels, "tun1")
226 tun := networkConfig.Tunnels["tun1"]
227 assert.Equal(t, "192.168.70.3/31", tun.Addresses[0])
228 assert.Equal(t, "ipip", tun.Mode)
229 assert.Len(t, tun.RoutingPolicies, 1)
230 assert.Len(t, tun.Routes, 1)
231
232 sysctlRPFilterConfAsExpected(t, memFs, gatewayEnabled, workerIENode.Spec.IsGatewayNode(), []string{"tun1"})
233
234 return ctx
235 }).
236 Test("netplan applies static gateway configuration for gateway nodes", func(ctx f2.Context, t *testing.T) f2.Context {
237 assert.NoError(t, netns.Set(ns))
238 netServicesCM.Data = map[string]string{}
239
240 _, err := Plugin{}.Reconcile(ctx, controlPlaneIENode, cfg)
241 assert.NoError(t, err)
242
243 contents, err := afero.ReadFile(memFs, netplanFile)
244 assert.NoError(t, err)
245
246 networkConfig := Template()
247 err = yaml.Unmarshal(contents, networkConfig)
248 assert.NoError(t, err)
249
250 assert.Equal(t, networkConfig.Ethernets[iface].Addresses[0], nodeCIDR)
251 assert.Equal(t, networkConfig.Ethernets[iface].Match.MacAddress, macAddress)
252 assert.Equal(t, networkConfig.Ethernets[iface].Nameservers.Addresses[0], dns)
253 assert.False(t, networkConfig.Ethernets[iface].DHCP4)
254
255 assert.Contains(t, networkConfig.Tunnels, "tun1")
256 tun := networkConfig.Tunnels["tun1"]
257 assert.Equal(t, "192.168.70.2/31", tun.Addresses[0])
258 assert.Equal(t, "ipip", tun.Mode)
259 assert.Len(t, tun.RoutingPolicies, 1)
260 assert.Len(t, tun.Routes, 1)
261
262 sysctlRPFilterConfAsExpected(t, memFs, gatewayEnabled, controlPlaneIENode.Spec.IsGatewayNode(), nil)
263
264 return ctx
265 }).
266 Teardown("teardown testing namespace", func(ctx f2.Context, _ *testing.T) f2.Context {
267 tearDownFunction()
268 return ctx
269 }).Feature()
270
271 f.Test(t, feature)
272 }
273
274 func TestStaticNodeConfiguration_Fallback_CIDR(t *testing.T) {
275 var kclient client.Client
276 var controlPlaneIENode *v1ien.IENode
277 var workerIENode *v1ien.IENode
278 var cfg config.Config
279 var memFs afero.Fs
280 var ns netns.NsHandle
281 var tearDownFunction func()
282 var macAddress string
283 const gatewayEnabled = true
284
285 feature := f2.NewFeature("netplan with static ip using fallback CIDR").
286 Setup("Create fake client", func(ctx f2.Context, t *testing.T) f2.Context {
287
288 workerIENode = staticIPWorkerNode()
289 controlPlaneIENode = staticIPControlPlaneNode()
290 controlPlaneNode := k8sNode(controlPlaneIENode, metav1.Now())
291 workerNode := k8sNode(workerIENode, metav1.NewTime(metav1.Now().Add(time.Duration(2)*time.Minute)))
292
293 ns, tearDownFunction = testnetns.NewTestingNetworkNamespace(t)
294 assert.NoError(t, testnetns.CreateDummyLink())
295
296 dev, err := testnetns.GetDummyLink()
297 assert.NoError(t, err)
298
299 macAddress = dev.Attrs().HardwareAddr.String()
300
301 workerIENode.Spec.Network[0].MacAddress = macAddress
302 controlPlaneIENode.Spec.Network[0].MacAddress = macAddress
303 workerIENode.Spec.PrimaryInterface.MacAddresses = append(workerIENode.Spec.PrimaryInterface.MacAddresses, macAddress)
304 controlPlaneIENode.Spec.PrimaryInterface.MacAddresses = append(controlPlaneIENode.Spec.PrimaryInterface.MacAddresses, macAddress)
305
306 kclient = fake.NewClientBuilder().WithScheme(createScheme()).WithObjects(createTopologyInfoConfigMap(gatewayEnabled), controlPlaneNode, workerNode).Build()
307
308 memoryFS, err := createMemFS()
309 assert.NoError(t, err)
310 memFs = memoryFS
311
312 cfg = config.NewConfig(kclient, nil, nil, config.Flags{}).WithFs(memFs).WithNetplanAPI(&netplanMock{})
313
314 return ctx
315 }).
316 Test("netplan applies static gateway configuration for worker nodes", func(ctx f2.Context, t *testing.T) f2.Context {
317 assert.NoError(t, netns.Set(ns))
318
319 _, err := Plugin{}.Reconcile(ctx, workerIENode, cfg)
320 assert.NoError(t, err)
321
322 contents, err := afero.ReadFile(memFs, netplanFile)
323 assert.NoError(t, err)
324
325 networkConfig := Template()
326 err = yaml.Unmarshal(contents, networkConfig)
327 assert.NoError(t, err)
328
329 assert.Contains(t, networkConfig.Tunnels, "tun1")
330 tun := networkConfig.Tunnels["tun1"]
331 assert.Equal(t, "10.80.0.3/31", tun.Addresses[0])
332 assert.Equal(t, "ipip", tun.Mode)
333 assert.Len(t, tun.RoutingPolicies, 1)
334 assert.Len(t, tun.Routes, 1)
335
336 sysctlRPFilterConfAsExpected(t, memFs, gatewayEnabled, workerIENode.Spec.IsGatewayNode(), []string{"tun1"})
337
338 return ctx
339 }).
340 Teardown("teardown testing namespace", func(ctx f2.Context, _ *testing.T) f2.Context {
341 tearDownFunction()
342 return ctx
343 }).Feature()
344
345 f.Test(t, feature)
346 }
347
348 func TestTunnelIPConfiguration(t *testing.T) {
349 var numberWorkers = 19
350 var controlPlaneIENode *v1ien.IENode
351 var nodes = make([]v1.Node, numberWorkers+1)
352 var ienNodes = make([]v1ien.IENode, numberWorkers+1)
353
354 feature := f2.NewFeature("netplan tunnel configuration test with gateway configured").
355 Setup("create nodes", func(ctx f2.Context, _ *testing.T) f2.Context {
356 controlPlaneIENode = staticIPControlPlaneNode()
357 controlPlaneNode := k8sNode(controlPlaneIENode, metav1.Now())
358
359 nodes[0] = *controlPlaneNode
360 ienNodes[0] = *controlPlaneIENode
361
362 for i := 1; i <= numberWorkers; i++ {
363 workerIENode := staticIPWorkerNode()
364 workerNode := k8sNode(workerIENode, metav1.NewTime(metav1.Now().Add(time.Duration(2)*time.Minute)))
365 nodes[i] = *workerNode
366 ienNodes[i] = *workerIENode
367 }
368
369 return ctx
370 }).
371 Test("20 node egress gateway configuration test", func(ctx f2.Context, t *testing.T) f2.Context {
372 nodes = sortK8sNodesByCreationTimestamp(nodes)
373 gatewayNodeIndexes, nonGatewayNodeIndexes, err := filterGatewayNodeIndexes(nodes)
374 assert.NoError(t, err)
375
376 cpNetplanConfig := Template()
377 _, cidr, _ := net.ParseCIDR("10.0.0.65/26")
378 subnets, err := internal.PairTunnelIPs(cidr)
379 assert.NoError(t, err)
380
381 cpConfig, err := configureGatewayNodeTunnels(cpNetplanConfig, controlPlaneIENode, nodes, nonGatewayNodeIndexes, subnets)
382 assert.NoError(t, err)
383
384 for idx := range ienNodes {
385 if idx == 0 {
386 continue
387 }
388
389 ienNode := &ienNodes[idx]
390 workerNetplanConfig := Template()
391 workerConfig, err := configureNonGatewayNodeTunnels(workerNetplanConfig, ienNode, nodes, gatewayNodeIndexes, subnets)
392 assert.NoError(t, err)
393
394 tunName := fmt.Sprintf("tun%d", idx)
395
396 tunnelFromCP, ok := cpConfig.Tunnels[tunName]
397 assert.True(t, ok)
398 expected, err := expectedTunnelFromCP(subnets[idx])
399 assert.NoError(t, err)
400 assert.Equal(t, expected, tunnelFromCP)
401
402 tunnelFromTP, ok := workerConfig.Tunnels[tunName]
403 assert.True(t, ok)
404 expected, err = expectedTunnelFromTP(subnets[idx])
405 assert.NoError(t, err)
406 assert.Equal(t, expected, tunnelFromTP)
407
408 _, pairTunnelSubnet, err := net.ParseCIDR(tunnelFromCP.Addresses[0])
409 assert.NoError(t, err)
410
411 workerIP, _, err := net.ParseCIDR(tunnelFromTP.Addresses[0])
412 assert.NoError(t, err)
413
414 assert.True(t, pairTunnelSubnet.Contains(workerIP))
415 }
416 return ctx
417 }).Feature()
418
419 f.Test(t, feature)
420 }
421
422 func createMemFS() (afero.Fs, error) {
423 fs := afero.NewMemMapFs()
424 netplanContents, err := generateNetplanConfig()
425 if err != nil {
426 return nil, err
427 }
428 if err := afero.WriteFile(fs, netplanFile, netplanContents, 0644); err != nil {
429 return nil, err
430 }
431 return fs, nil
432 }
433
434 func createTopologyInfoConfigMap(gatewayEnabled bool) *v1.ConfigMap {
435 tpInfo := topology.New()
436 tpInfo.EgressGatewayEnabled = gatewayEnabled
437 return tpInfo.ToConfigMap()
438 }
439
440 func createNetworkServicesConfigMap() *v1.ConfigMap {
441 return &v1.ConfigMap{
442 TypeMeta: metav1.TypeMeta{
443 Kind: "ConfigMap",
444 APIVersion: v1.SchemeGroupVersion.String(),
445 },
446 ObjectMeta: metav1.ObjectMeta{
447 Name: edgeconst.NetworkServicesCM,
448 Namespace: edgeconst.SdsNamespace,
449 },
450 Data: map[string]string{
451 edgeconst.ServiceTypeEgressTunnelsCIDR: "192.168.70.0/24",
452 },
453 }
454 }
455
456 func generateNetplanConfig() ([]byte, error) {
457 conf := Template()
458 return formatNetplan(conf)
459 }
460
461 func staticIPWorkerNode() *v1ien.IENode {
462 return &v1ien.IENode{
463 ObjectMeta: metav1.ObjectMeta{
464 Name: uuid.New().UUID,
465 },
466 Spec: v1ien.IENodeSpec{
467 Role: v1ien.Worker,
468 Lane: "1",
469 NetworkServices: v1ien.NetworkServices{
470 DNSServers: []string{dns},
471 },
472 PrimaryInterface: &v1ien.PrimaryInterface{
473 InterfaceID: uuid.New().UUID,
474 MacAddresses: []string{},
475 },
476 Network: []v1ien.Network{
477 {
478 MacAddress: "",
479 Addresses: []string{nodeCIDR},
480 Gateway4: gateway,
481 DHCP4: false,
482 },
483 },
484 },
485 Status: &v1ien.IENodeStatus{
486 Conditions: []metav1.Condition{
487 {
488 Type: "iptables",
489 Status: metav1.ConditionTrue,
490 },
491 },
492 },
493 }
494 }
495
496 func staticIPControlPlaneNode() *v1ien.IENode {
497 return &v1ien.IENode{
498 ObjectMeta: metav1.ObjectMeta{
499 Name: uuid.New().UUID,
500 },
501 Spec: v1ien.IENodeSpec{
502 Role: v1ien.ControlPlane,
503 Lane: "1",
504 NetworkServices: v1ien.NetworkServices{
505 DNSServers: []string{dns},
506 },
507 PrimaryInterface: &v1ien.PrimaryInterface{
508 InterfaceID: uuid.New().UUID,
509 MacAddresses: []string{},
510 },
511 Network: []v1ien.Network{
512 {
513 MacAddress: "",
514 Addresses: []string{nodeCIDR},
515 Gateway4: gateway,
516 DHCP4: false,
517 },
518 },
519 },
520 Status: &v1ien.IENodeStatus{
521 Conditions: []metav1.Condition{
522 {
523 Type: "iptables",
524 Status: metav1.ConditionTrue,
525 },
526 },
527 },
528 }
529 }
530
531 func createScheme() *kruntime.Scheme {
532 scheme := kruntime.NewScheme()
533 utilruntime.Must(clientgoscheme.AddToScheme(scheme))
534 utilruntime.Must(v1.AddToScheme(scheme))
535 utilruntime.Must(v1ien.AddToScheme(scheme))
536 return scheme
537 }
538
539 func formatNetplan(netConfig *Config) ([]byte, error) {
540 var b bytes.Buffer
541 yamlEncoder := yaml.NewEncoder(&b)
542 yamlEncoder.SetIndent(2)
543 err := yamlEncoder.Encode(netConfig)
544 return b.Bytes(), err
545 }
546
547 func k8sNode(ienode *v1ien.IENode, createdTime metav1.Time) *v1.Node {
548 return &v1.Node{
549 ObjectMeta: metav1.ObjectMeta{
550 Name: ienode.ObjectMeta.Name,
551 CreationTimestamp: createdTime,
552 Annotations: map[string]string{
553 calico.IPAnnotation: ienode.Spec.Network[0].Addresses[0],
554 },
555 Labels: map[string]string{
556 nodemeta.RoleLabel: string(ienode.Spec.Role),
557 },
558 },
559 Spec: v1.NodeSpec{},
560 }
561 }
562
563 func expectedTunnelFromTP(subnet *net.IPNet) (Tunnel, error) {
564
565 tunnelIP, err := networking.GetAddressFromSubnet(subnet, 1)
566 if err != nil {
567 return Tunnel{}, err
568 }
569
570
571 gatewayTunnelCIDR, err := networking.GetAddressFromSubnet(subnet, 0)
572 if err != nil {
573 return Tunnel{}, err
574 }
575
576 gatewayTunnelIP, _, err := net.ParseCIDR(gatewayTunnelCIDR)
577 if err != nil {
578 return Tunnel{}, err
579 }
580 return Tunnel{
581 Mode: "ipip",
582 Local: nodeIP,
583 Remote: nodeIP,
584 Addresses: []string{tunnelIP},
585 Routes: []Route{
586 {
587 To: "default",
588 Via: gatewayTunnelIP.String(),
589 Table: routing.EgressGatewayTable,
590 },
591 },
592 RoutingPolicies: []RoutingPolicy{
593 {
594 Mark: 512,
595 To: "0.0.0.0/0",
596 Table: routing.EgressGatewayTable,
597 Priority: 32765,
598 },
599 },
600 }, nil
601 }
602
603 func expectedTunnelFromCP(subnet *net.IPNet) (Tunnel, error) {
604
605 tunnelIP, err := networking.GetAddressFromSubnet(subnet, 0)
606 if err != nil {
607 return Tunnel{}, err
608 }
609 return Tunnel{
610 Mode: "ipip",
611 Local: nodeIP,
612 Remote: nodeIP,
613 Addresses: []string{tunnelIP},
614 }, nil
615 }
616
617 func sysctlRPFilterConfAsExpected(t *testing.T, fs afero.Fs, gatewayEnabled bool, isGatewayNode bool, ifaceList []string) {
618 actual, err := afero.ReadFile(fs, filepath.Join(sysctlDir, rpFilterConf))
619 if !gatewayEnabled || isGatewayNode {
620 assert.ErrorIs(t, err, os.ErrNotExist)
621 assert.Empty(t, ifaceList)
622 return
623 }
624 assert.NoError(t, err)
625 expected := generateRPFilterConfig(routing.RPFilterLoose, ifaceList)
626 assert.Equal(t, expected, actual)
627 }
628
View as plain text