go.ligato.io/vpp-agent/v3@v3.5.0/tests/e2e/050_nat_test.go (about)

     1  //  Copyright (c) 2019 Cisco and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  package e2e
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"testing"
    22  
    23  	. "github.com/onsi/gomega"
    24  
    25  	"go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler"
    26  	linux_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces"
    27  	linux_l3 "go.ligato.io/vpp-agent/v3/proto/ligato/linux/l3"
    28  	linux_namespace "go.ligato.io/vpp-agent/v3/proto/ligato/linux/namespace"
    29  	vpp_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    30  	vpp_l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3"
    31  	vpp_nat "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/nat"
    32  	. "go.ligato.io/vpp-agent/v3/tests/e2e/e2etest"
    33  )
    34  
    35  // Simulate public and private networks using two microservices and test
    36  // source-NAT in-between.
    37  func TestSourceNAT(t *testing.T) {
    38  	ctx := Setup(t)
    39  	defer ctx.Teardown()
    40  
    41  	const (
    42  		// public network
    43  		vppTap1Name       = "vpp-tap1"
    44  		vppTap1IP         = "80.80.80.20"
    45  		linuxTap1Name     = "linux-tap1"
    46  		linuxTap1Hostname = "tap"
    47  		linuxTap1IP       = "80.80.80.10"
    48  
    49  		// private network
    50  		vppTap2Name       = "vpp-tap2"
    51  		vppTap2IP         = "192.168.1.1"
    52  		linuxTap2Name     = "linux-tap2"
    53  		linuxTap2Hostname = "tap"
    54  		linuxTap2IP       = "192.168.1.2"
    55  
    56  		// nat
    57  		sNatAddr1 = vppTap1IP
    58  		sNatAddr2 = "80.80.80.21"
    59  		sNatAddr3 = "80.80.80.22"
    60  
    61  		netMask = "/24"
    62  		ms1Name = "microservice1"
    63  		ms2Name = "microservice2"
    64  	)
    65  
    66  	vppTap1 := &vpp_interfaces.Interface{
    67  		Name:        vppTap1Name,
    68  		Type:        vpp_interfaces.Interface_TAP,
    69  		Enabled:     true,
    70  		IpAddresses: []string{vppTap1IP + netMask},
    71  		Link: &vpp_interfaces.Interface_Tap{
    72  			Tap: &vpp_interfaces.TapLink{
    73  				Version:        2,
    74  				ToMicroservice: MsNamePrefix + ms1Name,
    75  			},
    76  		},
    77  	}
    78  	linuxTap1 := &linux_interfaces.Interface{
    79  		Name:        linuxTap1Name,
    80  		Type:        linux_interfaces.Interface_TAP_TO_VPP,
    81  		Enabled:     true,
    82  		IpAddresses: []string{linuxTap1IP + netMask},
    83  		HostIfName:  linuxTap1Hostname,
    84  		Link: &linux_interfaces.Interface_Tap{
    85  			Tap: &linux_interfaces.TapLink{
    86  				VppTapIfName: vppTap1Name,
    87  			},
    88  		},
    89  		Namespace: &linux_namespace.NetNamespace{
    90  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
    91  			Reference: MsNamePrefix + ms1Name,
    92  		},
    93  	}
    94  
    95  	vppTap2 := &vpp_interfaces.Interface{
    96  		Name:        vppTap2Name,
    97  		Type:        vpp_interfaces.Interface_TAP,
    98  		Enabled:     true,
    99  		IpAddresses: []string{vppTap2IP + netMask},
   100  		Link: &vpp_interfaces.Interface_Tap{
   101  			Tap: &vpp_interfaces.TapLink{
   102  				Version:        2,
   103  				ToMicroservice: MsNamePrefix + ms2Name,
   104  			},
   105  		},
   106  	}
   107  	linuxTap2 := &linux_interfaces.Interface{
   108  		Name:        linuxTap2Name,
   109  		Type:        linux_interfaces.Interface_TAP_TO_VPP,
   110  		Enabled:     true,
   111  		IpAddresses: []string{linuxTap2IP + netMask},
   112  		HostIfName:  linuxTap2Hostname,
   113  		Link: &linux_interfaces.Interface_Tap{
   114  			Tap: &linux_interfaces.TapLink{
   115  				VppTapIfName: vppTap2Name,
   116  			},
   117  		},
   118  		Namespace: &linux_namespace.NetNamespace{
   119  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   120  			Reference: MsNamePrefix + ms2Name,
   121  		},
   122  	}
   123  
   124  	ms2DefaultRoute := &linux_l3.Route{
   125  		OutgoingInterface: linuxTap2Name,
   126  		Scope:             linux_l3.Route_GLOBAL,
   127  		DstNetwork:        "0.0.0.0/0",
   128  		GwAddr:            vppTap2IP,
   129  	}
   130  
   131  	natGlobal := &vpp_nat.Nat44Global{
   132  		Forwarding: true,
   133  	}
   134  	natInterface := &vpp_nat.Nat44Interface{
   135  		Name:          vppTap1Name,
   136  		OutputFeature: true,
   137  	}
   138  	// Looks like VPP versions > 22.02 changed the output feature
   139  	// (or in newer versions output interface) API so that OutputFeature
   140  	// and Inside/Outside flags are mutually exclusive
   141  	if ctx.VppRelease() <= "22.02" {
   142  		natInterface.NatOutside = true
   143  	}
   144  	natPool := &vpp_nat.Nat44AddressPool{
   145  		FirstIp: sNatAddr1,
   146  		LastIp:  sNatAddr3,
   147  	}
   148  
   149  	nat44Addresses := func() (string, error) {
   150  		return ctx.ExecVppctl("show", "nat44", "addresses")
   151  	}
   152  	connectTCP := func() error {
   153  		return ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP,
   154  			8000, 8000, false, Tapv2InputNode)
   155  	}
   156  	connectUDP := func() error {
   157  		return ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP,
   158  			8000, 8000, true, Tapv2InputNode)
   159  	}
   160  	ping := func() error {
   161  		return ctx.PingFromMs(ms2Name, linuxTap1IP)
   162  	}
   163  
   164  	ctx.StartMicroservice(ms1Name)
   165  	ctx.StartMicroservice(ms2Name)
   166  	ctx.Expect(nat44Addresses()).ShouldNot(SatisfyAny(
   167  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   168  	req := ctx.GenericClient().ChangeRequest()
   169  	err := req.Update(
   170  		vppTap1,
   171  		linuxTap1,
   172  		vppTap2,
   173  		linuxTap2,
   174  		ms2DefaultRoute,
   175  		natGlobal,
   176  		natInterface,
   177  		natPool,
   178  	).Send(context.Background())
   179  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating public and private networks failed")
   180  
   181  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   182  		"TAP attached to a newly started microservice1 should be eventually configured")
   183  	ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   184  		"TAP attached to a newly started microservice2 should be eventually configured")
   185  
   186  	ctx.Expect(nat44Addresses()).Should(SatisfyAll(
   187  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   188  	ctx.Expect(ping()).Should(Succeed())
   189  	ctx.Expect(connectTCP()).Should(Succeed())
   190  	ctx.Expect(connectUDP()).Should(Succeed())
   191  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   192  
   193  	// remove S-NAT configuration
   194  	req = ctx.GenericClient().ChangeRequest()
   195  	err = req.Delete(
   196  		natGlobal,
   197  		natInterface,
   198  		natPool,
   199  	).Send(context.Background())
   200  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction removing S-NAT failed")
   201  
   202  	// check configuration
   203  	ctx.Expect(nat44Addresses()).ShouldNot(SatisfyAny(
   204  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   205  	ctx.Expect(ping()).ShouldNot(Succeed())
   206  	ctx.Expect(connectTCP()).ShouldNot(Succeed())
   207  	ctx.Expect(connectUDP()).ShouldNot(Succeed())
   208  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   209  
   210  	// get back the S-NAT configuration
   211  	req = ctx.GenericClient().ChangeRequest()
   212  	err = req.Update(
   213  		natGlobal,
   214  		natInterface,
   215  		natPool,
   216  	).Send(context.Background())
   217  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating S-NAT failed")
   218  
   219  	ctx.Expect(nat44Addresses()).Should(SatisfyAll(
   220  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   221  	ctx.Expect(ping()).Should(Succeed())
   222  	ctx.Expect(connectTCP()).Should(Succeed())
   223  	ctx.Expect(connectUDP()).Should(Succeed())
   224  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   225  
   226  	// restart microservice with S-NAT attached
   227  	ctx.StopMicroservice(ms1Name)
   228  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_PENDING),
   229  		"Without microservice, the associated VPP-TAP should be pending")
   230  	ctx.StartMicroservice(ms1Name)
   231  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   232  		"VPP-TAP attached to a re-started microservice1 should be eventually configured")
   233  
   234  	ctx.Expect(nat44Addresses()).Should(SatisfyAll(
   235  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   236  	ctx.Expect(ping()).Should(Succeed())
   237  	ctx.Expect(connectTCP()).Should(Succeed())
   238  	ctx.Expect(connectUDP()).Should(Succeed())
   239  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   240  }
   241  
   242  // Tests NAT pool CRUD operation and NAT pool resync.
   243  func TestNATPools(t *testing.T) {
   244  	// variable/helper method initialization
   245  	const addressCount = 7
   246  	addresses := make([]string, addressCount)
   247  	for i := 0; i < addressCount; i++ {
   248  		addresses[i] = fmt.Sprintf("80.80.80.%d", i)
   249  	}
   250  	nat44Addresses := func(ctx *TestCtx) func() (string, error) {
   251  		return func() (string, error) {
   252  			return ctx.ExecVppctl("show", "nat44", "addresses")
   253  		}
   254  	}
   255  	mustBeInVPP := func(ctx *TestCtx, addrs []string) {
   256  		for _, addr := range addrs { // Eventually is needed due to VPP-Agent to VPP configuration delay
   257  			ctx.Eventually(nat44Addresses(ctx)).Should(ContainSubstring(addr))
   258  		}
   259  	}
   260  	cantBeInVPP := func(ctx *TestCtx, addrs []string) {
   261  		for _, addr := range addrs { // Eventually is needed due to VPP-Agent to VPP configuration delay
   262  			ctx.Eventually(nat44Addresses(ctx)).ShouldNot(ContainSubstring(addr))
   263  		}
   264  	}
   265  
   266  	// tests
   267  	tests := []struct {
   268  		name               string
   269  		createNATPool      *vpp_nat.Nat44AddressPool
   270  		checkAfterCreation func(ctx *TestCtx)
   271  		updateNATPool      *vpp_nat.Nat44AddressPool
   272  		checkAfterUpdate   func(ctx *TestCtx)
   273  		checkAfterDelete   func(ctx *TestCtx)
   274  	}{
   275  		{
   276  			name: "CRUD for named pool",
   277  			createNATPool: &vpp_nat.Nat44AddressPool{
   278  				Name:    "myPool",
   279  				FirstIp: addresses[0],
   280  				LastIp:  addresses[2],
   281  			},
   282  			checkAfterCreation: func(ctx *TestCtx) {
   283  				mustBeInVPP(ctx, addresses[0:3]) // initial creation
   284  			},
   285  			updateNATPool: &vpp_nat.Nat44AddressPool{
   286  				Name:    "myPool",
   287  				FirstIp: addresses[4],
   288  				LastIp:  addresses[6],
   289  			},
   290  			checkAfterUpdate: func(ctx *TestCtx) {
   291  				cantBeInVPP(ctx, addresses[0:3]) // old addresses are deleted
   292  				mustBeInVPP(ctx, addresses[4:7]) // new addresses are created
   293  			},
   294  			checkAfterDelete: func(ctx *TestCtx) {
   295  				cantBeInVPP(ctx, addresses) // empty pool after deleting only pool
   296  			},
   297  		},
   298  		{
   299  			name: "CRUD for unnamed pool",
   300  			createNATPool: &vpp_nat.Nat44AddressPool{
   301  				FirstIp: addresses[0],
   302  				LastIp:  addresses[2],
   303  			},
   304  			checkAfterCreation: func(ctx *TestCtx) {
   305  				mustBeInVPP(ctx, addresses[0:3]) // initial creation
   306  			},
   307  			updateNATPool: &vpp_nat.Nat44AddressPool{
   308  				FirstIp: addresses[4],
   309  				LastIp:  addresses[6],
   310  			},
   311  			checkAfterUpdate: func(ctx *TestCtx) {
   312  				// unnamed pools are not tied by name in key
   313  				// -> update with different ip addresses == create another pool
   314  				mustBeInVPP(ctx, addresses[0:3])
   315  				mustBeInVPP(ctx, addresses[4:7])
   316  			},
   317  			checkAfterDelete: func(ctx *TestCtx) {
   318  				mustBeInVPP(ctx, addresses[0:3]) // original create won't get deleted
   319  				cantBeInVPP(ctx, addresses[4:7]) // the updated is deleted
   320  			},
   321  		},
   322  	}
   323  
   324  	for _, test := range tests {
   325  		t.Run(test.name, func(t *testing.T) {
   326  			ctx := Setup(t)
   327  			defer ctx.Teardown()
   328  
   329  			// check empty pool state
   330  			cantBeInVPP(ctx, addresses)
   331  
   332  			// create NAT pool
   333  			req := ctx.GenericClient().ChangeRequest()
   334  			err := req.Update(
   335  				&vpp_nat.Nat44Global{},
   336  				test.createNATPool,
   337  			).Send(context.Background())
   338  			ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating nat pool failed")
   339  			test.checkAfterCreation(ctx)
   340  			ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") // resync
   341  
   342  			// update NAT pool
   343  			req = ctx.GenericClient().ChangeRequest()
   344  			err = req.Update(
   345  				test.updateNATPool,
   346  			).Send(context.Background())
   347  			ctx.Expect(err).ToNot(HaveOccurred(), "Transaction updating nat pool failed")
   348  			test.checkAfterUpdate(ctx)
   349  			ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") // resync
   350  
   351  			// delete NAT pool
   352  			req = ctx.GenericClient().ChangeRequest()
   353  			err = req.Delete(
   354  				test.updateNATPool,
   355  			).Send(context.Background())
   356  			ctx.Expect(err).ToNot(HaveOccurred(), "Transaction deleting NAT pool failed")
   357  			test.checkAfterDelete(ctx)
   358  			ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") // resync
   359  		})
   360  	}
   361  }
   362  
   363  // Simulate use-case in which a service located in a private network is published
   364  // on a publicly accessible IP address.
   365  func TestNATStaticMappings(t *testing.T) {
   366  	ctx := Setup(t)
   367  	defer ctx.Teardown()
   368  
   369  	const (
   370  		// public network
   371  		vppTap1Name       = "vpp-tap1"
   372  		vppTap1IP         = "80.80.80.20"
   373  		linuxTap1Name     = "linux-tap1"
   374  		linuxTap1Hostname = "tap"
   375  		linuxTap1IP       = "80.80.80.10"
   376  
   377  		// private network
   378  		vppTap2Name       = "vpp-tap2"
   379  		vppTap2IP         = "192.168.1.1"
   380  		linuxTap2Name     = "linux-tap2"
   381  		linuxTap2Hostname = "tap"
   382  		linuxTap2IP       = "192.168.1.2"
   383  
   384  		// nat
   385  		tcpSvcLabel     = "tcp-service"
   386  		tcpSvcExtIP     = "80.80.80.30"
   387  		tcpSvcExtPort   = 8888
   388  		tcpSvcLocalPort = 8000
   389  		udpSvcLabel     = "udp-service"
   390  		udpSvcExtIP     = "80.80.80.50"
   391  		udpSvcExtPort   = 9999
   392  		udpSvcLocalPort = 9000
   393  
   394  		netMask = "/24"
   395  		ms1Name = "microservice1"
   396  		ms2Name = "microservice2"
   397  	)
   398  
   399  	vppTap1 := &vpp_interfaces.Interface{
   400  		Name:        vppTap1Name,
   401  		Type:        vpp_interfaces.Interface_TAP,
   402  		Enabled:     true,
   403  		IpAddresses: []string{vppTap1IP + netMask},
   404  		Link: &vpp_interfaces.Interface_Tap{
   405  			Tap: &vpp_interfaces.TapLink{
   406  				Version:        2,
   407  				ToMicroservice: MsNamePrefix + ms1Name,
   408  			},
   409  		},
   410  	}
   411  	linuxTap1 := &linux_interfaces.Interface{
   412  		Name:        linuxTap1Name,
   413  		Type:        linux_interfaces.Interface_TAP_TO_VPP,
   414  		Enabled:     true,
   415  		IpAddresses: []string{linuxTap1IP + netMask},
   416  		HostIfName:  linuxTap1Hostname,
   417  		Link: &linux_interfaces.Interface_Tap{
   418  			Tap: &linux_interfaces.TapLink{
   419  				VppTapIfName: vppTap1Name,
   420  			},
   421  		},
   422  		Namespace: &linux_namespace.NetNamespace{
   423  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   424  			Reference: MsNamePrefix + ms1Name,
   425  		},
   426  	}
   427  
   428  	vppTap2 := &vpp_interfaces.Interface{
   429  		Name:        vppTap2Name,
   430  		Type:        vpp_interfaces.Interface_TAP,
   431  		Enabled:     true,
   432  		IpAddresses: []string{vppTap2IP + netMask},
   433  		Link: &vpp_interfaces.Interface_Tap{
   434  			Tap: &vpp_interfaces.TapLink{
   435  				Version:        2,
   436  				ToMicroservice: MsNamePrefix + ms2Name,
   437  			},
   438  		},
   439  	}
   440  	linuxTap2 := &linux_interfaces.Interface{
   441  		Name:        linuxTap2Name,
   442  		Type:        linux_interfaces.Interface_TAP_TO_VPP,
   443  		Enabled:     true,
   444  		IpAddresses: []string{linuxTap2IP + netMask},
   445  		HostIfName:  linuxTap2Hostname,
   446  		Link: &linux_interfaces.Interface_Tap{
   447  			Tap: &linux_interfaces.TapLink{
   448  				VppTapIfName: vppTap2Name,
   449  			},
   450  		},
   451  		Namespace: &linux_namespace.NetNamespace{
   452  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   453  			Reference: MsNamePrefix + ms2Name,
   454  		},
   455  	}
   456  
   457  	ms2DefaultRoute := &linux_l3.Route{
   458  		OutgoingInterface: linuxTap2Name,
   459  		Scope:             linux_l3.Route_GLOBAL,
   460  		DstNetwork:        "0.0.0.0/0",
   461  		GwAddr:            vppTap2IP,
   462  	}
   463  
   464  	natGlobal := &vpp_nat.Nat44Global{
   465  		Forwarding: true,
   466  	}
   467  	natInterface1 := &vpp_nat.Nat44Interface{
   468  		Name:       vppTap1Name,
   469  		NatOutside: true,
   470  	}
   471  	natInterface2 := &vpp_nat.Nat44Interface{
   472  		Name:      vppTap2Name,
   473  		NatInside: true,
   474  	}
   475  
   476  	tcpSvc := &vpp_nat.DNat44{
   477  		Label: tcpSvcLabel,
   478  		StMappings: []*vpp_nat.DNat44_StaticMapping{
   479  			{
   480  				ExternalIp:   tcpSvcExtIP,
   481  				ExternalPort: tcpSvcExtPort,
   482  				Protocol:     vpp_nat.DNat44_TCP,
   483  				LocalIps: []*vpp_nat.DNat44_StaticMapping_LocalIP{
   484  					{
   485  						LocalIp:   linuxTap2IP,
   486  						LocalPort: tcpSvcLocalPort,
   487  					},
   488  				},
   489  			},
   490  		},
   491  	}
   492  
   493  	udpSvc := &vpp_nat.DNat44{
   494  		Label: udpSvcLabel,
   495  		StMappings: []*vpp_nat.DNat44_StaticMapping{
   496  			{
   497  				ExternalIp:   udpSvcExtIP,
   498  				ExternalPort: udpSvcExtPort,
   499  				Protocol:     vpp_nat.DNat44_UDP,
   500  				LocalIps: []*vpp_nat.DNat44_StaticMapping_LocalIP{
   501  					{
   502  						LocalIp:   linuxTap2IP,
   503  						LocalPort: udpSvcLocalPort,
   504  					},
   505  				},
   506  			},
   507  		},
   508  	}
   509  
   510  	// without proxy ARP, the client running from microservice1 (public net),
   511  	// will not get any response for ARP requests concerning service external IPs
   512  	// from VPP
   513  	svcExtIPsProxyArp := &vpp_l3.ProxyARP{
   514  		Interfaces: []*vpp_l3.ProxyARP_Interface{
   515  			{
   516  				Name: vppTap1Name,
   517  			},
   518  		},
   519  		Ranges: []*vpp_l3.ProxyARP_Range{
   520  			{
   521  				FirstIpAddr: tcpSvcExtIP,
   522  				LastIpAddr:  tcpSvcExtIP,
   523  			},
   524  			{
   525  				FirstIpAddr: udpSvcExtIP,
   526  				LastIpAddr:  udpSvcExtIP,
   527  			},
   528  		},
   529  	}
   530  
   531  	staticMappings := func() (string, error) {
   532  		str, err := ctx.ExecVppctl("show", "nat44", "static", "mappings")
   533  		if err != nil {
   534  			return "", err
   535  		}
   536  		// NOTE: This is a workaround, because case changed in VPP 22.02 (tcp -> TCP)
   537  		return strings.ToLower(str), nil
   538  	}
   539  	containTCP := ContainSubstring(
   540  		"tcp local %s:%d external %s:%d vrf 0  out2in-only",
   541  		linuxTap2IP, tcpSvcLocalPort, tcpSvcExtIP, tcpSvcExtPort)
   542  
   543  	containUDP := ContainSubstring(
   544  		"udp local %s:%d external %s:%d vrf 0  out2in-only",
   545  		linuxTap2IP, udpSvcLocalPort, udpSvcExtIP, udpSvcExtPort)
   546  
   547  	connectTCP := func() error {
   548  		return ctx.TestConnection(ms1Name, ms2Name, tcpSvcExtIP, linuxTap2IP,
   549  			tcpSvcExtPort, tcpSvcLocalPort, false, Tapv2InputNode)
   550  	}
   551  	connectUDP := func() error {
   552  		return ctx.TestConnection(ms1Name, ms2Name, udpSvcExtIP, linuxTap2IP,
   553  			udpSvcExtPort, udpSvcLocalPort, true, Tapv2InputNode)
   554  	}
   555  
   556  	ctx.StartMicroservice(ms1Name)
   557  	ctx.StartMicroservice(ms2Name)
   558  	ctx.Expect(staticMappings()).ShouldNot(SatisfyAny(containTCP, containUDP))
   559  	req := ctx.GenericClient().ChangeRequest()
   560  	err := req.Update(
   561  		vppTap1,
   562  		linuxTap1,
   563  		vppTap2,
   564  		linuxTap2,
   565  		ms2DefaultRoute,
   566  		svcExtIPsProxyArp,
   567  		natGlobal,
   568  		natInterface1,
   569  		natInterface2,
   570  		tcpSvc, udpSvc,
   571  	).Send(context.Background())
   572  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating public and private networks failed")
   573  
   574  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   575  		"TAP attached to a newly started microservice1 should be eventually configured")
   576  	ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   577  		"TAP attached to a newly started microservice2 should be eventually configured")
   578  
   579  	ctx.Expect(staticMappings()).Should(SatisfyAll(containTCP, containUDP))
   580  	ctx.Expect(connectTCP()).Should(Succeed())
   581  	ctx.Expect(connectUDP()).Should(Succeed())
   582  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   583  
   584  	// remove static mappings
   585  	req = ctx.GenericClient().ChangeRequest()
   586  	err = req.Delete(
   587  		tcpSvc, udpSvc,
   588  	).Send(context.Background())
   589  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction removing NAT static mappings failed")
   590  
   591  	ctx.Expect(staticMappings()).ShouldNot(SatisfyAny(containTCP, containUDP))
   592  	ctx.Expect(connectTCP()).ShouldNot(Succeed())
   593  	ctx.Expect(connectUDP()).ShouldNot(Succeed())
   594  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   595  
   596  	// get back the NAT configuration
   597  	req = ctx.GenericClient().ChangeRequest()
   598  	err = req.Update(
   599  		tcpSvc, udpSvc,
   600  	).Send(context.Background())
   601  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating NAT static mappings failed")
   602  
   603  	ctx.Expect(staticMappings()).Should(SatisfyAll(containTCP, containUDP))
   604  	ctx.Expect(connectTCP()).Should(Succeed())
   605  	ctx.Expect(connectUDP()).Should(Succeed())
   606  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   607  
   608  	// restart both microservices
   609  	ctx.StopMicroservice(ms1Name)
   610  	ctx.StopMicroservice(ms2Name)
   611  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_PENDING),
   612  		"Without microservice, the associated VPP-TAP should be pending")
   613  	ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_PENDING),
   614  		"Without microservice, the associated VPP-TAP should be pending")
   615  	ctx.StartMicroservice(ms1Name)
   616  	ctx.StartMicroservice(ms2Name)
   617  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   618  		"VPP-TAP attached to a re-started microservice1 should be eventually configured")
   619  	ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   620  		"VPP-TAP attached to a re-started microservice1 should be eventually configured")
   621  
   622  	ctx.Expect(staticMappings()).Should(SatisfyAll(containTCP, containUDP))
   623  	ctx.Expect(connectTCP()).Should(Succeed())
   624  	ctx.Expect(connectUDP()).Should(Succeed())
   625  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   626  }
   627  
   628  // Simulate public and private networks using two microservices and test
   629  // source-NAT in-between. Uses deprecated API for NatInterfaces and AddressPool in Nat44Global.
   630  func TestSourceNATDeprecatedAPI(t *testing.T) {
   631  	ctx := Setup(t)
   632  	defer ctx.Teardown()
   633  
   634  	if ctx.VppRelease() >= "22.02" {
   635  		t.Skipf("SKIP testing of deprecated NAT API for VPP>=22.02")
   636  	}
   637  
   638  	const (
   639  		// public network
   640  		vppTap1Name       = "vpp-tap1"
   641  		vppTap1IP         = "80.80.80.20"
   642  		linuxTap1Name     = "linux-tap1"
   643  		linuxTap1Hostname = "tap"
   644  		linuxTap1IP       = "80.80.80.10"
   645  
   646  		// private network
   647  		vppTap2Name       = "vpp-tap2"
   648  		vppTap2IP         = "192.168.1.1"
   649  		linuxTap2Name     = "linux-tap2"
   650  		linuxTap2Hostname = "tap"
   651  		linuxTap2IP       = "192.168.1.2"
   652  
   653  		// nat
   654  		sNatAddr1 = vppTap1IP
   655  		sNatAddr2 = "80.80.80.30"
   656  		sNatAddr3 = "80.80.80.40"
   657  
   658  		netMask = "/24"
   659  		ms1Name = "microservice1"
   660  		ms2Name = "microservice2"
   661  	)
   662  
   663  	vppTap1 := &vpp_interfaces.Interface{
   664  		Name:        vppTap1Name,
   665  		Type:        vpp_interfaces.Interface_TAP,
   666  		Enabled:     true,
   667  		IpAddresses: []string{vppTap1IP + netMask},
   668  		Link: &vpp_interfaces.Interface_Tap{
   669  			Tap: &vpp_interfaces.TapLink{
   670  				Version:        2,
   671  				ToMicroservice: MsNamePrefix + ms1Name,
   672  			},
   673  		},
   674  	}
   675  	linuxTap1 := &linux_interfaces.Interface{
   676  		Name:        linuxTap1Name,
   677  		Type:        linux_interfaces.Interface_TAP_TO_VPP,
   678  		Enabled:     true,
   679  		IpAddresses: []string{linuxTap1IP + netMask},
   680  		HostIfName:  linuxTap1Hostname,
   681  		Link: &linux_interfaces.Interface_Tap{
   682  			Tap: &linux_interfaces.TapLink{
   683  				VppTapIfName: vppTap1Name,
   684  			},
   685  		},
   686  		Namespace: &linux_namespace.NetNamespace{
   687  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   688  			Reference: MsNamePrefix + ms1Name,
   689  		},
   690  	}
   691  
   692  	vppTap2 := &vpp_interfaces.Interface{
   693  		Name:        vppTap2Name,
   694  		Type:        vpp_interfaces.Interface_TAP,
   695  		Enabled:     true,
   696  		IpAddresses: []string{vppTap2IP + netMask},
   697  		Link: &vpp_interfaces.Interface_Tap{
   698  			Tap: &vpp_interfaces.TapLink{
   699  				Version:        2,
   700  				ToMicroservice: MsNamePrefix + ms2Name,
   701  			},
   702  		},
   703  	}
   704  	linuxTap2 := &linux_interfaces.Interface{
   705  		Name:        linuxTap2Name,
   706  		Type:        linux_interfaces.Interface_TAP_TO_VPP,
   707  		Enabled:     true,
   708  		IpAddresses: []string{linuxTap2IP + netMask},
   709  		HostIfName:  linuxTap2Hostname,
   710  		Link: &linux_interfaces.Interface_Tap{
   711  			Tap: &linux_interfaces.TapLink{
   712  				VppTapIfName: vppTap2Name,
   713  			},
   714  		},
   715  		Namespace: &linux_namespace.NetNamespace{
   716  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   717  			Reference: MsNamePrefix + ms2Name,
   718  		},
   719  	}
   720  
   721  	ms2DefaultRoute := &linux_l3.Route{
   722  		OutgoingInterface: linuxTap2Name,
   723  		Scope:             linux_l3.Route_GLOBAL,
   724  		DstNetwork:        "0.0.0.0/0",
   725  		GwAddr:            vppTap2IP,
   726  	}
   727  
   728  	sourceNat := &vpp_nat.Nat44Global{
   729  		Forwarding: true,
   730  		NatInterfaces: []*vpp_nat.Nat44Global_Interface{
   731  			{
   732  				Name:          vppTap1Name,
   733  				IsInside:      false,
   734  				OutputFeature: true,
   735  			},
   736  		},
   737  		AddressPool: []*vpp_nat.Nat44Global_Address{
   738  			{
   739  				Address: sNatAddr1,
   740  			},
   741  			{
   742  				Address: sNatAddr2,
   743  			},
   744  			{
   745  				Address: sNatAddr3,
   746  			},
   747  		},
   748  	}
   749  
   750  	nat44Addresses := func() (string, error) {
   751  		return ctx.ExecVppctl("show", "nat44", "addresses")
   752  	}
   753  	connectTCP := func() error {
   754  		return ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP,
   755  			8000, 8000, false, Tapv2InputNode)
   756  	}
   757  	connectUDP := func() error {
   758  		return ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP,
   759  			8000, 8000, true, Tapv2InputNode)
   760  	}
   761  	ping := func() error {
   762  		return ctx.PingFromMs(ms2Name, linuxTap1IP)
   763  	}
   764  
   765  	ctx.StartMicroservice(ms1Name)
   766  	ctx.StartMicroservice(ms2Name)
   767  	ctx.Expect(nat44Addresses()).ShouldNot(SatisfyAny(
   768  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   769  	req := ctx.GenericClient().ChangeRequest()
   770  	err := req.Update(
   771  		vppTap1,
   772  		linuxTap1,
   773  		vppTap2,
   774  		linuxTap2,
   775  		ms2DefaultRoute,
   776  		sourceNat,
   777  	).Send(context.Background())
   778  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating public and private networks failed")
   779  
   780  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   781  		"TAP attached to a newly started microservice1 should be eventually configured")
   782  	ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   783  		"TAP attached to a newly started microservice2 should be eventually configured")
   784  
   785  	ctx.Expect(nat44Addresses()).Should(SatisfyAll(
   786  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   787  	ctx.Expect(ping()).Should(Succeed())
   788  	ctx.Expect(connectTCP()).Should(Succeed())
   789  	ctx.Expect(connectUDP()).Should(Succeed())
   790  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   791  
   792  	// remove S-NAT configuration
   793  	req = ctx.GenericClient().ChangeRequest()
   794  	err = req.Delete(
   795  		sourceNat,
   796  	).Send(context.Background())
   797  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction removing S-NAT failed")
   798  
   799  	// check configuration
   800  	ctx.Expect(nat44Addresses()).ShouldNot(SatisfyAny(
   801  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   802  	ctx.Expect(ping()).ShouldNot(Succeed())
   803  	ctx.Expect(connectTCP()).ShouldNot(Succeed())
   804  	ctx.Expect(connectUDP()).ShouldNot(Succeed())
   805  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   806  
   807  	// get back the S-NAT configuration
   808  	req = ctx.GenericClient().ChangeRequest()
   809  	err = req.Update(
   810  		sourceNat,
   811  	).Send(context.Background())
   812  	ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating S-NAT failed")
   813  
   814  	ctx.Expect(nat44Addresses()).Should(SatisfyAll(
   815  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   816  	ctx.Expect(ping()).Should(Succeed())
   817  	ctx.Expect(connectTCP()).Should(Succeed())
   818  	ctx.Expect(connectUDP()).Should(Succeed())
   819  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   820  
   821  	// restart microservice with S-NAT attached
   822  	ctx.StopMicroservice(ms1Name)
   823  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_PENDING),
   824  		"Without microservice, the associated VPP-TAP should be pending")
   825  	ctx.StartMicroservice(ms1Name)
   826  	ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED),
   827  		"VPP-TAP attached to a re-started microservice1 should be eventually configured")
   828  
   829  	ctx.Expect(nat44Addresses()).Should(SatisfyAll(
   830  		ContainSubstring(sNatAddr1), ContainSubstring(sNatAddr2), ContainSubstring(sNatAddr3)))
   831  	ctx.Expect(ping()).Should(Succeed())
   832  	ctx.Expect(connectTCP()).Should(Succeed())
   833  	ctx.Expect(connectUDP()).Should(Succeed())
   834  	ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync")
   835  }