github.phpd.cn/cilium/cilium@v1.6.12/test/runtime/connectivity.go (about)

     1  package RuntimeTest
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"time"
     8  
     9  	. "github.com/cilium/cilium/test/ginkgo-ext"
    10  	"github.com/cilium/cilium/test/helpers"
    11  	"github.com/cilium/cilium/test/helpers/constants"
    12  
    13  	. "github.com/onsi/gomega"
    14  	"github.com/onsi/gomega/types"
    15  )
    16  
    17  func runOnNetNextOnly(f func()) func() {
    18  	if helpers.RunsOnNetNext() {
    19  		return f
    20  	}
    21  	return func() {}
    22  }
    23  
    24  var _ = Describe("RuntimeConnectivityInVethModeTest", runtimeConnectivityTest("veth"))
    25  var _ = Describe("RuntimeConnectivityInIpvlanModeTest", runOnNetNextOnly(runtimeConnectivityTest("ipvlan")))
    26  
    27  // TODO(brb) Either create a dummy netdev or determine the master device at runtime
    28  const ipvlanMasterDevice = "enp0s8"
    29  
    30  var runtimeConnectivityTest = func(datapathMode string) func() {
    31  	return func() {
    32  		var (
    33  			vm          *helpers.SSHMeta
    34  			monitorStop = func() error { return nil }
    35  		)
    36  
    37  		BeforeAll(func() {
    38  			vm = helpers.InitRuntimeHelper(helpers.Runtime, logger)
    39  
    40  			if datapathMode == "ipvlan" {
    41  				vm.SetUpCiliumInIpvlanMode(ipvlanMasterDevice)
    42  				// cilium-docker has to be restarted because the datapath mode
    43  				// has changed
    44  				vm.Exec("sudo systemctl restart cilium-docker")
    45  			}
    46  
    47  			ExpectCiliumReady(vm)
    48  		})
    49  
    50  		JustBeforeEach(func() {
    51  			monitorStop = vm.MonitorStart()
    52  		})
    53  
    54  		AfterAll(func() {
    55  			// Restore the datapath mode and cilium-docker
    56  			if datapathMode == "ipvlan" {
    57  				vm.SetUpCilium()
    58  				vm.Exec("sudo systemctl restart cilium-docker")
    59  			}
    60  			vm.CloseSSHClient()
    61  		})
    62  
    63  		removeContainer := func(containerName string) {
    64  			By("removing container %s", containerName)
    65  			res := vm.ContainerRm(containerName)
    66  			ExpectWithOffset(1, res).To(helpers.CMDSuccess(), "cannot delete container")
    67  		}
    68  
    69  		AfterEach(func() {
    70  			vm.PolicyDelAll().ExpectSuccess("Policies cannot be deleted")
    71  		})
    72  
    73  		JustAfterEach(func() {
    74  			vm.ValidateNoErrorsInLogs(CurrentGinkgoTestDescription().Duration)
    75  			Expect(monitorStop()).To(BeNil(), "cannot stop monitor command")
    76  		})
    77  
    78  		AfterFailed(func() {
    79  			vm.ReportFailed()
    80  		})
    81  
    82  		Context("Basic Connectivity test", func() {
    83  
    84  			BeforeEach(func() {
    85  				vm.ContainerCreate(helpers.Client, constants.NetperfImage, helpers.CiliumDockerNetwork, "-l id.client")
    86  				vm.ContainerCreate(helpers.Server, constants.NetperfImage, helpers.CiliumDockerNetwork, "-l id.server")
    87  				vm.PolicyDelAll()
    88  				vm.WaitEndpointsReady()
    89  				err := helpers.WithTimeout(func() bool {
    90  					if data, _ := vm.GetEndpointsNames(); len(data) < 2 {
    91  						logger.Info("Waiting for endpoints to be ready")
    92  						return false
    93  					}
    94  					return true
    95  				}, "Endpoints are not ready", &helpers.TimeoutConfig{Timeout: 150 * time.Second})
    96  				Expect(err).Should(BeNil())
    97  
    98  				err = helpers.WithTimeout(func() bool {
    99  					res := vm.ContainerExec(helpers.Server, "netperf -H 127.0.0.1 -l 1")
   100  					if !res.WasSuccessful() {
   101  						logger.Info("Waiting for netserver to come up")
   102  					}
   103  					return res.WasSuccessful()
   104  				}, "netserver did not come up in time", &helpers.TimeoutConfig{Timeout: 20 * time.Second})
   105  				Expect(err).Should(BeNil(), "timeout while waiting for netserver to start inside netperf container")
   106  			}, 150)
   107  
   108  			AfterEach(func() {
   109  				removeContainer(helpers.Client)
   110  				removeContainer(helpers.Server)
   111  				return
   112  			})
   113  
   114  			It("Test connectivity between containers without policies imported", func() {
   115  				// TODO: this code is duplicated in the next "It" in this file. refactor it into a function.
   116  				// See if we can make the "Filter" strings for getting IPv4 and IPv6 addresses into constants.
   117  				By("inspecting container %s", helpers.Server)
   118  				serverData := vm.ContainerInspect(helpers.Server)
   119  				serverIP, err := serverData.Filter(fmt.Sprintf("{[0].NetworkSettings.Networks.%s.IPAddress}", helpers.CiliumDockerNetwork))
   120  				Expect(err).Should(BeNil())
   121  
   122  				By("serverIP: %q", serverIP)
   123  				serverIPv6, err := serverData.Filter(fmt.Sprintf("{[0].NetworkSettings.Networks.%s.GlobalIPv6Address}", helpers.CiliumDockerNetwork))
   124  				By("serverIPv6: %q", serverIPv6)
   125  				Expect(err).Should(BeNil())
   126  
   127  				By("checking %q can ping to %q IPv6", helpers.Client, helpers.Server)
   128  				res := vm.ContainerExec(helpers.Client, helpers.Ping6(serverIPv6.String()))
   129  				res.ExpectSuccess()
   130  
   131  				By("checking %q can ping to %q IPv4", helpers.Client, helpers.Server)
   132  				res = vm.ContainerExec(helpers.Client, helpers.Ping(serverIP.String()))
   133  				res.ExpectSuccess()
   134  
   135  				// TODO: remove this hardcoding ; it is not clean. Have command wrappers that take maps of strings.
   136  				By("netperf to %q from %q IPv6", helpers.Server, helpers.Client)
   137  				cmd := fmt.Sprintf(
   138  					"netperf -c -C -t TCP_SENDFILE -H %s", serverIPv6)
   139  
   140  				res = vm.ContainerExec(helpers.Client, cmd)
   141  				res.ExpectSuccess()
   142  			}, 300)
   143  
   144  			It("Test connectivity between containers with policy imported", func() {
   145  				policyID, err := vm.PolicyImportAndWait(
   146  					fmt.Sprintf("%s/test.policy", vm.ManifestsPath()), 150*time.Second)
   147  				Expect(err).Should(BeNil())
   148  				logger.Debugf("New policy created with id '%d'", policyID)
   149  
   150  				serverData := vm.ContainerInspect(helpers.Server)
   151  				serverIP, err := serverData.Filter(fmt.Sprintf("{[0].NetworkSettings.Networks.%s.IPAddress}", helpers.CiliumDockerNetwork))
   152  				Expect(err).Should(BeNil())
   153  				By("serverIP: %q", serverIP)
   154  				serverIPv6, err := serverData.Filter(fmt.Sprintf("{[0].NetworkSettings.Networks.%s.GlobalIPv6Address}", helpers.CiliumDockerNetwork))
   155  				By("serverIPv6: %q", serverIPv6)
   156  				Expect(err).Should(BeNil())
   157  
   158  				By("%q can ping to %q IPV6", helpers.Client, helpers.Server)
   159  				res := vm.ContainerExec(helpers.Client, helpers.Ping6(serverIPv6.String()))
   160  				res.ExpectSuccess()
   161  
   162  				By("%s can ping to %s IPv4", helpers.Client, helpers.Server)
   163  				res = vm.ContainerExec(helpers.Client, helpers.Ping(serverIP.String()))
   164  				res.ExpectSuccess()
   165  
   166  				By("netperf to %q from %q (should succeed)", helpers.Server, helpers.Client)
   167  				cmd := fmt.Sprintf("netperf -c -C -H %s", serverIP)
   168  				res = vm.ContainerExec(helpers.Client, cmd)
   169  
   170  				// TODO: remove this hardcoding ; it is not clean. Have command wrappers that take maps of strings.
   171  				By("netperf to %q from %q IPv6 with -t TCP_SENDFILE", helpers.Server, helpers.Client)
   172  				cmd = fmt.Sprintf(
   173  					"netperf -c -C -t TCP_SENDFILE -H %s", serverIPv6)
   174  
   175  				res = vm.ContainerExec(helpers.Client, cmd)
   176  				res.ExpectSuccess()
   177  
   178  				By("super_netperf to %q from %q (should succeed)", helpers.Server, helpers.Client)
   179  				cmd = fmt.Sprintf("super_netperf 10 -c -C -t TCP_SENDFILE -H %s", serverIP)
   180  				res = vm.ContainerExec(helpers.Client, cmd)
   181  				res.ExpectSuccess()
   182  
   183  				By("ping from %q to %q", helpers.Host, helpers.Server)
   184  				res = vm.Exec(helpers.Ping(serverIP.String()))
   185  				res.ExpectSuccess()
   186  			}, 300)
   187  
   188  			It("Test NAT46 connectivity between containers", func() {
   189  				if datapathMode == "ipvlan" {
   190  					Skip("NAT64 is not implemented in the ipvlan mode")
   191  				}
   192  				endpoints, err := vm.GetEndpointsIds()
   193  				Expect(err).Should(BeNil(), "could not get endpoint IDs")
   194  
   195  				server, err := vm.ContainerInspectNet(helpers.Server)
   196  				Expect(err).Should(BeNil())
   197  				By("server: %q", server)
   198  
   199  				client, err := vm.ContainerInspectNet(helpers.Client)
   200  				Expect(err).Should(BeNil())
   201  				By("client: %q", client)
   202  
   203  				status := vm.EndpointSetConfig(endpoints[helpers.Client], "NAT46", helpers.OptionEnabled)
   204  				Expect(status).Should(BeTrue())
   205  
   206  				areEndpointsReady := vm.WaitEndpointsReady()
   207  				Expect(areEndpointsReady).Should(BeTrue(), "Endpoints not ready after timeout")
   208  
   209  				res := vm.ContainerExec(helpers.Client, helpers.Ping6(fmt.Sprintf(
   210  					"::FFFF:%s", server[helpers.IPv4])))
   211  
   212  				res.ExpectSuccess()
   213  
   214  				res = vm.ContainerExec(helpers.Server,
   215  					helpers.Ping6(fmt.Sprintf("::FFFF:%s", client[helpers.IPv4])))
   216  				res.ExpectFail(fmt.Sprintf("unexpectedly succeeded pinging IPv6 %s from %s",
   217  					client[helpers.IPv4], helpers.Server))
   218  			})
   219  		})
   220  
   221  		Context("With CNI", func() {
   222  			var (
   223  				cniPlugin = "/opt/cni/bin/cilium-cni"
   224  				cniServer = "cni-server"
   225  				cniClient = "cni-client"
   226  				netDPath  = "/etc/cni/net.d/"
   227  				tmpDir    *helpers.CmdRes
   228  			)
   229  
   230  			BeforeAll(func() {
   231  				// Remove any CNI plugin installed in the provision server. This
   232  				// helps to avoid issues on installing the new CNI
   233  				_ = vm.ExecWithSudo(fmt.Sprintf("rm -rf %[1]s/*.conf", netDPath)).ExpectSuccess(
   234  					"CNI config cannot be deleted")
   235  
   236  				tmpDir = vm.Exec("mktemp -d")
   237  				tmpDir.ExpectSuccess("TMP folder cannot be created %s", tmpDir.Output())
   238  			})
   239  
   240  			AfterAll(func() {
   241  				vm.Exec(fmt.Sprintf("rm -rf %s", tmpDir.Output()))
   242  			})
   243  
   244  			BeforeEach(func() {
   245  				vm.PolicyDelAll().ExpectSuccess("Policies cannot be deleted")
   246  			})
   247  
   248  			AfterEach(func() {
   249  				vm.ContainerRm(cniServer)
   250  				vm.ContainerRm(cniClient)
   251  				vm.Exec(fmt.Sprintf("docker rm -f $(docker ps --filter ancestor=%s --format '{{.ID}}')", constants.BusyboxImage))
   252  			})
   253  
   254  			runCNIContainer := func(name string, label string) {
   255  				res := vm.Exec(fmt.Sprintf("docker run -t -d --net=none -l %s %s", label, constants.BusyboxImage))
   256  				res.ExpectSuccess()
   257  				containerID := res.SingleOut()
   258  
   259  				pid := vm.Exec(fmt.Sprintf("docker inspect -f '{{ .State.Pid }}' %s", containerID))
   260  				pid.ExpectSuccess()
   261  				netnspath := fmt.Sprintf("/proc/%s/ns/net", pid.SingleOut())
   262  
   263  				res = vm.Exec(fmt.Sprintf(
   264  					"sudo -E PATH=$PATH:/opt/cni/bin -E CNI_PATH=%[1]s/bin %[1]s/cni/scripts/exec-plugins.sh add %s %s",
   265  					tmpDir.SingleOut(), containerID, netnspath))
   266  				res.ExpectSuccess("CNI exec-plugins did not work correctly")
   267  
   268  				res = vm.ContainerCreate(
   269  					name, constants.NetperfImage,
   270  					fmt.Sprintf("container:%s", containerID), fmt.Sprintf("-l %s", label))
   271  				res.ExpectSuccess("Container %s cannot be created", name)
   272  			}
   273  
   274  			It("Basic connectivity test", func() {
   275  				filename := "05-cilium-cni.conf"
   276  				cniConf := `{"name": "cilium",
   277  				"type": "cilium-cni"}`
   278  				err := helpers.RenderTemplateToFile(filename, cniConf, os.ModePerm)
   279  				Expect(err).To(BeNil())
   280  
   281  				cmd := vm.ExecWithSudo(fmt.Sprintf("mv %s %s",
   282  					helpers.GetFilePath(filename),
   283  					filepath.Join(netDPath, filename)))
   284  				cmd.ExpectSuccess("cannot install cilium cni plugin conf")
   285  				script := fmt.Sprintf(`
   286  				cd %s && \
   287  				git clone https://github.com/containernetworking/cni -b v0.5.2 --single-branch && \
   288  				cd cni && \
   289  				./build.sh
   290  			`, tmpDir.SingleOut())
   291  				vm.Exec(script).ExpectSuccess("Cannot install cni")
   292  				vm.Exec(fmt.Sprintf("cp %s %s", cniPlugin, filepath.Join(tmpDir.SingleOut(), "bin")))
   293  
   294  				By("Importing policy")
   295  				policyFileName := "CNI-policy.json"
   296  				policy := `
   297  				[{
   298  					"endpointSelector": {"matchLabels":{"id.server":""}},
   299  					"ingress": [{
   300  						"fromEndpoints": [
   301  						{"matchLabels":{"reserved:host":""}},
   302  						{"matchLabels":{"id.client":""}}
   303  					]
   304  					}]
   305  				}]`
   306  				err = helpers.RenderTemplateToFile(policyFileName, policy, os.ModePerm)
   307  				Expect(err).Should(BeNil())
   308  				_, err = vm.PolicyImportAndWait(helpers.GetFilePath(policyFileName), helpers.HelperTimeout)
   309  				Expect(err).Should(BeNil(), fmt.Sprintf("Cannot import policy %s", policyFileName))
   310  
   311  				By("Adding containers")
   312  
   313  				runCNIContainer(cniServer, "id.server")
   314  				runCNIContainer(cniClient, "id.client")
   315  
   316  				areEndpointsReady := vm.WaitEndpointsReady()
   317  				Expect(areEndpointsReady).Should(BeTrue())
   318  
   319  				serverIPv4 := vm.ContainerExec(
   320  					cniServer,
   321  					`ip -4 a show dev eth0 scope global | grep inet | sed -e 's%.*inet \(.*\)\/.*%\1%'`)
   322  
   323  				serverIPv6 := vm.ContainerExec(
   324  					cniServer,
   325  					`ip -6 a show dev eth0 scope global | grep inet6 | sed -e 's%.*inet6 \(.*\)\/.*%\1%'`)
   326  
   327  				vm.ContainerExec(cniClient, helpers.Ping(serverIPv4.SingleOut())).ExpectSuccess(
   328  					"cannot ping from client to server %q", serverIPv4.SingleOut())
   329  
   330  				vm.ContainerExec(cniClient, helpers.Ping6(serverIPv6.SingleOut())).ExpectSuccess(
   331  					"cannot ping6 from client to server %q", serverIPv6.SingleOut())
   332  			})
   333  		})
   334  	}
   335  }
   336  
   337  var _ = Describe("RuntimeConntrackInVethModeTest", runtimeConntrackTest("veth"))
   338  var _ = Describe("RuntimeConntrackInIpvlanModeTest", runOnNetNextOnly(runtimeConntrackTest("ipvlan")))
   339  
   340  var runtimeConntrackTest = func(datapathMode string) func() {
   341  	return func() {
   342  		var (
   343  			vm          *helpers.SSHMeta
   344  			monitorStop = func() error { return nil }
   345  
   346  			curl1ContainerName             = "curl"
   347  			curl2ContainerName             = "curl2"
   348  			CTPolicyConntrackLocalDisabled = "ct-test-policy-conntrack-local-disabled.json"
   349  		)
   350  
   351  		type conntestCases struct {
   352  			from        string
   353  			to          string
   354  			destination string
   355  			assert      func() types.GomegaMatcher
   356  		}
   357  
   358  		BeforeAll(func() {
   359  			vm = helpers.InitRuntimeHelper(helpers.Runtime, logger)
   360  
   361  			if datapathMode == "ipvlan" {
   362  				vm.SetUpCiliumInIpvlanMode(ipvlanMasterDevice)
   363  				// cilium-docker has to be restarted because the datapath mode
   364  				// has changed
   365  				vm.Exec("sudo systemctl restart cilium-docker")
   366  			}
   367  
   368  			ExpectCiliumReady(vm)
   369  
   370  			ExpectPolicyEnforcementUpdated(vm, helpers.PolicyEnforcementAlways)
   371  		})
   372  
   373  		AfterAll(func() {
   374  			// Restore the datapath mode and cilium-docker
   375  			if datapathMode == "ipvlan" {
   376  				vm.SetUpCilium()
   377  				vm.Exec("sudo systemctl restart cilium-docker")
   378  			}
   379  			vm.CloseSSHClient()
   380  		})
   381  
   382  		clientServerConnectivity := func() {
   383  			By("============= Starting Connectivity Test ============= ")
   384  
   385  			By("Getting IPs of each spawned container")
   386  			clientDockerNetworking, err := vm.ContainerInspectNet(helpers.Client)
   387  			ExpectWithOffset(1, err).Should(BeNil(),
   388  				"could not get metadata for container %q", helpers.Client)
   389  			By("client container Docker networking: %q", clientDockerNetworking)
   390  
   391  			serverDockerNetworking, err := vm.ContainerInspectNet(helpers.Server)
   392  			ExpectWithOffset(1, err).Should(BeNil(),
   393  				"could not get metadata for container %q", helpers.Server)
   394  			By("server container Docker networking: %q", serverDockerNetworking)
   395  
   396  			httpdDockerNetworking, err := vm.ContainerInspectNet(helpers.Httpd1)
   397  			ExpectWithOffset(1, err).Should(BeNil(),
   398  				"could not get metadata for container %q", helpers.Httpd1)
   399  			By("httpd1 container Docker networking: %q", httpdDockerNetworking)
   400  
   401  			httpd2DockerNetworking, err := vm.ContainerInspectNet(helpers.Httpd2)
   402  			ExpectWithOffset(1, err).Should(BeNil(),
   403  				"could not get metadata for container %q", helpers.Httpd2)
   404  			By("httpd2 container Docker networking: %q", httpd2DockerNetworking)
   405  
   406  			curl1DockerNetworking, err := vm.ContainerInspectNet(curl1ContainerName)
   407  			ExpectWithOffset(1, err).Should(BeNil(),
   408  				"could not get metadata for container %q", curl1ContainerName)
   409  			By("curl1 container Docker networking: %q", curl1DockerNetworking)
   410  
   411  			curl2DockerNetworking, err := vm.ContainerInspectNet(curl2ContainerName)
   412  			ExpectWithOffset(1, err).Should(BeNil(),
   413  				"could not get metadata for container %q", curl2ContainerName)
   414  			By("httpd1 container Docker networking: %q", curl2DockerNetworking)
   415  
   416  			By("Showing policies imported to Cilium")
   417  			res := vm.PolicyGetAll()
   418  			GinkgoPrint(res.CombineOutput().String())
   419  
   420  			testCases := []conntestCases{
   421  				{
   422  					from:        curl1ContainerName,
   423  					to:          helpers.CurlFail("http://[%s]:80", httpdDockerNetworking[helpers.IPv6]),
   424  					destination: helpers.Httpd1,
   425  					assert:      BeTrue,
   426  				},
   427  				{
   428  					from:        curl1ContainerName,
   429  					to:          helpers.CurlFail("http://%s:80", httpdDockerNetworking[helpers.IPv4]),
   430  					destination: helpers.Httpd1,
   431  					assert:      BeTrue,
   432  				},
   433  				{
   434  					from:        curl2ContainerName,
   435  					to:          helpers.CurlFail("http://[%s]:80", httpdDockerNetworking[helpers.IPv6]),
   436  					destination: helpers.Httpd1,
   437  					assert:      BeFalse,
   438  				},
   439  				{
   440  					from:        curl2ContainerName,
   441  					to:          helpers.CurlFail("http://%s:80", httpdDockerNetworking[helpers.IPv4]),
   442  					destination: helpers.Httpd1,
   443  					assert:      BeFalse,
   444  				},
   445  				{
   446  					from:        curl1ContainerName,
   447  					to:          helpers.CurlFail("http://[%s]:80", httpd2DockerNetworking[helpers.IPv6]),
   448  					destination: helpers.Httpd2,
   449  					assert:      BeFalse,
   450  				},
   451  				{
   452  					from:        curl1ContainerName,
   453  					to:          helpers.CurlFail("http://%s:80", httpd2DockerNetworking[helpers.IPv4]),
   454  					destination: helpers.Httpd2,
   455  					assert:      BeFalse,
   456  				},
   457  				{
   458  					from:        curl2ContainerName,
   459  					to:          helpers.CurlFail("http://[%s]:80", httpdDockerNetworking[helpers.IPv6]),
   460  					destination: helpers.Httpd2,
   461  					assert:      BeFalse,
   462  				},
   463  				{
   464  					from:        curl2ContainerName,
   465  					to:          helpers.CurlFail("http://%s:80", httpdDockerNetworking[helpers.IPv4]),
   466  					destination: helpers.Httpd2,
   467  					assert:      BeFalse,
   468  				},
   469  				{
   470  					from:        helpers.Client,
   471  					to:          helpers.Ping6(serverDockerNetworking[helpers.IPv6]),
   472  					destination: helpers.Server,
   473  					assert:      BeTrue,
   474  				},
   475  				{
   476  					from:        helpers.Client,
   477  					to:          helpers.Ping(serverDockerNetworking[helpers.IPv4]),
   478  					destination: helpers.Server,
   479  					assert:      BeTrue,
   480  				},
   481  				{
   482  					from:        helpers.Client,
   483  					to:          helpers.Netcat("%s 777", serverDockerNetworking[helpers.IPv6]),
   484  					destination: helpers.Server,
   485  					assert:      BeFalse,
   486  				},
   487  				{
   488  					from:        helpers.Client,
   489  					to:          helpers.Netcat("%s 777", serverDockerNetworking[helpers.IPv4]),
   490  					destination: helpers.Server,
   491  					assert:      BeFalse,
   492  				},
   493  
   494  				{
   495  					from:        helpers.Client,
   496  					to:          helpers.Netperf(serverDockerNetworking[helpers.IPv6], helpers.TCP_RR),
   497  					destination: helpers.Server,
   498  					assert:      BeTrue,
   499  				},
   500  				{
   501  					from:        helpers.Client,
   502  					to:          helpers.Netperf(serverDockerNetworking[helpers.IPv4], helpers.TCP_RR),
   503  					destination: helpers.Server,
   504  					assert:      BeTrue,
   505  				},
   506  				{
   507  					from:        helpers.Client,
   508  					to:          helpers.Netperf(serverDockerNetworking[helpers.IPv6], helpers.UDP_RR),
   509  					destination: helpers.Server,
   510  					assert:      BeTrue,
   511  				},
   512  				{
   513  					from:        helpers.Client,
   514  					to:          helpers.Netperf(serverDockerNetworking[helpers.IPv4], helpers.UDP_RR),
   515  					destination: helpers.Server,
   516  					assert:      BeTrue,
   517  				},
   518  			}
   519  
   520  			for _, test := range testCases {
   521  				By("Container %q test connectivity to %q", test.from, test.destination)
   522  				res = vm.ContainerExec(test.from, test.to)
   523  				ExpectWithOffset(1, res.WasSuccessful()).To(test.assert(),
   524  					"The result of %q from container %q to %s does not match", test.to, test.from, test.destination)
   525  			}
   526  
   527  			By("Testing bidirectional connectivity from client to server")
   528  
   529  			By("container %s pinging %s IPv6 (should NOT work)", helpers.Server, helpers.Client)
   530  			res = vm.ContainerExec(helpers.Server, helpers.Ping6(clientDockerNetworking[helpers.IPv6]))
   531  			ExpectWithOffset(1, res).ShouldNot(helpers.CMDSuccess(),
   532  				"container %q unexpectedly was able to ping to %q IP:%q", helpers.Server, helpers.Client, clientDockerNetworking[helpers.IPv6])
   533  
   534  			By("container %s pinging %s IPv4 (should NOT work)", helpers.Server, helpers.Client)
   535  			res = vm.ContainerExec(helpers.Server, helpers.Ping(clientDockerNetworking[helpers.IPv4]))
   536  			ExpectWithOffset(1, res).ShouldNot(helpers.CMDSuccess(),
   537  				"%q was unexpectedly able to ping to %q IP:%q", helpers.Server, helpers.Client, clientDockerNetworking[helpers.IPv4])
   538  
   539  			By("============= Finished Connectivity Test ============= ")
   540  		}
   541  
   542  		clientServerL3Connectivity := func() {
   543  			By("============= Starting Connectivity Test ============= ")
   544  
   545  			By("Getting IPs of each spawned container")
   546  			clientDockerNetworking, err := vm.ContainerInspectNet(helpers.Client)
   547  			ExpectWithOffset(1, err).Should(BeNil(),
   548  				"could not get metadata for container %q", helpers.Client)
   549  			By("client container Docker networking: %s", clientDockerNetworking)
   550  
   551  			serverDockerNetworking, err := vm.ContainerInspectNet(helpers.Server)
   552  			ExpectWithOffset(1, err).Should(BeNil(),
   553  				"could not get metadata for container %q", helpers.Server)
   554  			By("server container Docker networking: %s", serverDockerNetworking)
   555  
   556  			httpdDockerNetworking, err := vm.ContainerInspectNet(helpers.Httpd1)
   557  			ExpectWithOffset(1, err).Should(BeNil(),
   558  				"could not get metadata for container %q", helpers.Httpd1)
   559  			By("httpd1 container Docker networking: %s", httpdDockerNetworking)
   560  
   561  			httpd2DockerNetworking, err := vm.ContainerInspectNet(helpers.Httpd2)
   562  			ExpectWithOffset(1, err).Should(BeNil(),
   563  				"could not get metadata for container %q", helpers.Httpd2)
   564  			By("httpd2 container Docker networking: %s", httpd2DockerNetworking)
   565  
   566  			curl1DockerNetworking, err := vm.ContainerInspectNet(curl1ContainerName)
   567  			ExpectWithOffset(1, err).Should(BeNil(),
   568  				"could not get metadata for container %q", curl1ContainerName)
   569  			By("curl1 container Docker networking: %s", curl1DockerNetworking)
   570  
   571  			curl2DockerNetworking, err := vm.ContainerInspectNet(curl2ContainerName)
   572  			ExpectWithOffset(1, err).Should(BeNil(),
   573  				"could not get metadata for container %q", curl2ContainerName)
   574  			By("httpd1 container Docker networking: %s", curl2DockerNetworking)
   575  
   576  			By("Showing policies imported to Cilium")
   577  			res := vm.PolicyGetAll()
   578  			GinkgoPrint(res.CombineOutput().String())
   579  
   580  			testCases := []conntestCases{
   581  				{
   582  					from:        curl1ContainerName,
   583  					to:          helpers.CurlFail("http://[%s]:80", httpdDockerNetworking[helpers.IPv6]),
   584  					destination: helpers.Httpd1,
   585  					assert:      BeTrue,
   586  				},
   587  				{
   588  					from:        curl1ContainerName,
   589  					to:          helpers.CurlFail("http://%s:80", httpdDockerNetworking[helpers.IPv4]),
   590  					destination: helpers.Httpd1,
   591  					assert:      BeTrue,
   592  				},
   593  				{
   594  					from:        curl2ContainerName,
   595  					to:          helpers.CurlFail("http://[%s]:80", httpdDockerNetworking[helpers.IPv6]),
   596  					destination: helpers.Httpd1,
   597  					assert:      BeFalse,
   598  				},
   599  				{
   600  					from:        curl2ContainerName,
   601  					to:          helpers.CurlFail("http://%s:80", httpdDockerNetworking[helpers.IPv4]),
   602  					destination: helpers.Httpd1,
   603  					assert:      BeFalse,
   604  				},
   605  				{
   606  					from:        curl1ContainerName,
   607  					to:          helpers.CurlFail("http://[%s]:80", httpd2DockerNetworking[helpers.IPv6]),
   608  					destination: helpers.Httpd2,
   609  					assert:      BeFalse,
   610  				},
   611  				{
   612  					from:        curl1ContainerName,
   613  					to:          helpers.CurlFail("http://%s:80", httpd2DockerNetworking[helpers.IPv4]),
   614  					destination: helpers.Httpd2,
   615  					assert:      BeFalse,
   616  				},
   617  				{
   618  					from:        curl2ContainerName,
   619  					to:          helpers.CurlFail("http://[%s]:80", httpd2DockerNetworking[helpers.IPv6]),
   620  					destination: helpers.Httpd2,
   621  					assert:      BeFalse,
   622  				},
   623  				{
   624  					from:        curl2ContainerName,
   625  					to:          helpers.CurlFail("http://%s:80", httpd2DockerNetworking[helpers.IPv4]),
   626  					destination: helpers.Httpd2,
   627  					assert:      BeFalse,
   628  				},
   629  				{
   630  					from:        helpers.Client,
   631  					to:          helpers.Ping6(serverDockerNetworking[helpers.IPv6]),
   632  					destination: helpers.Server,
   633  					assert:      BeTrue,
   634  				},
   635  				{
   636  					from:        helpers.Client,
   637  					to:          helpers.Ping(serverDockerNetworking[helpers.IPv4]),
   638  					destination: helpers.Server,
   639  					assert:      BeTrue,
   640  				},
   641  				{
   642  					from:        helpers.Client,
   643  					to:          helpers.Netperf(serverDockerNetworking[helpers.IPv6], helpers.TCP_RR),
   644  					destination: helpers.Server,
   645  					assert:      BeTrue,
   646  				},
   647  				{
   648  					from:        helpers.Client,
   649  					to:          helpers.Netperf(serverDockerNetworking[helpers.IPv4], helpers.TCP_RR),
   650  					destination: helpers.Server,
   651  					assert:      BeTrue,
   652  				},
   653  				{
   654  					from:        helpers.Client,
   655  					to:          helpers.Netperf(serverDockerNetworking[helpers.IPv6], helpers.UDP_RR),
   656  					destination: helpers.Server,
   657  					assert:      BeTrue,
   658  				},
   659  				{
   660  					from:        helpers.Client,
   661  					to:          helpers.Netperf(serverDockerNetworking[helpers.IPv4], helpers.UDP_RR),
   662  					destination: helpers.Server,
   663  					assert:      BeTrue,
   664  				},
   665  			}
   666  
   667  			for _, test := range testCases {
   668  				By("Container %q test connectivity to %q", test.from, test.destination)
   669  				res = vm.ContainerExec(test.from, test.to)
   670  				ExpectWithOffset(1, res.WasSuccessful()).To(test.assert(),
   671  					"The result of %q from container %q to %s does not match", test.to, test.from, test.destination)
   672  			}
   673  
   674  			By("============= Finished Connectivity Test ============= ")
   675  		}
   676  
   677  		BeforeEach(func() {
   678  			// TODO: provide map[string]string instead of one string representing KV pair.
   679  			vm.ContainerCreate(helpers.Client, constants.NetperfImage, helpers.CiliumDockerNetwork, "-l id.client")
   680  			vm.ContainerCreate(helpers.Server, constants.NetperfImage, helpers.CiliumDockerNetwork, "-l id.server")
   681  			vm.ContainerCreate(helpers.Httpd1, constants.HttpdImage, helpers.CiliumDockerNetwork, "-l id.httpd")
   682  			vm.ContainerCreate(helpers.Httpd2, constants.HttpdImage, helpers.CiliumDockerNetwork, "-l id.httpd_deny")
   683  			vm.ContainerCreate(curl1ContainerName, constants.NetperfImage, helpers.CiliumDockerNetwork, "-l id.curl")
   684  			vm.ContainerCreate(curl2ContainerName, constants.NetperfImage, helpers.CiliumDockerNetwork, "-l id.curl2")
   685  
   686  			vm.PolicyDelAll().ExpectSuccess("cannot delete all policies")
   687  
   688  			_, err := vm.PolicyImportAndWait(vm.GetFullPath("ct-test-policy.json"), helpers.HelperTimeout)
   689  			Expect(err).Should(BeNil())
   690  
   691  		})
   692  
   693  		JustBeforeEach(func() {
   694  			monitorStop = vm.MonitorStart()
   695  		})
   696  
   697  		AfterEach(func() {
   698  			containersToRm := []string{helpers.Client, helpers.Server, helpers.Httpd1, helpers.Httpd2, curl1ContainerName, curl2ContainerName}
   699  			for _, containerToRm := range containersToRm {
   700  				vm.ContainerRm(containerToRm)
   701  			}
   702  			vm.PolicyDelAll().ExpectSuccess("Policies cannot be deleted")
   703  
   704  			ExpectPolicyEnforcementUpdated(vm, helpers.PolicyEnforcementDefault)
   705  		})
   706  
   707  		JustAfterEach(func() {
   708  			vm.ValidateNoErrorsInLogs(CurrentGinkgoTestDescription().Duration)
   709  			Expect(monitorStop()).To(BeNil(), "cannot stop monitor command")
   710  		})
   711  
   712  		AfterFailed(func() {
   713  			vm.ReportFailed("cilium policy get")
   714  		})
   715  
   716  		It("Conntrack-related configuration options for endpoints", func() {
   717  			By("Getting Endpoint IDs")
   718  			endpoints, err := vm.GetEndpointsIds()
   719  			Expect(err).Should(BeNil(), "could not get endpoint IDs")
   720  
   721  			// Check that endpoint IDs exist in map.
   722  			for _, endpointName := range []string{helpers.Server, helpers.Client} {
   723  				_, exists := endpoints[endpointName]
   724  				Expect(exists).To(BeTrue(), "unable to retrieve endpoint ID for endpoint %s", endpointName)
   725  				By("Endpoint ID for %q = %q", endpointName, endpoints[endpointName])
   726  
   727  			}
   728  
   729  			endpointsToConfigure := []string{endpoints[helpers.Server], endpoints[helpers.Client]}
   730  
   731  			// Iterate through possible values to configure ConntrackLocal option,
   732  			// apply to both endpoints, verify the option configuration change matches
   733  			// what was performed, and then run connectivity test with endpoints.
   734  			conntrackLocalOptionModes := []string{helpers.OptionDisabled, helpers.OptionEnabled}
   735  			for _, conntrackLocalOptionMode := range conntrackLocalOptionModes {
   736  				By("Testing with endpoint configuration option: ConntrackLocal=%s", conntrackLocalOptionMode)
   737  
   738  				for _, endpointToConfigure := range endpointsToConfigure {
   739  					err := vm.SetAndWaitForEndpointConfiguration(
   740  						endpointToConfigure, helpers.OptionConntrackLocal, conntrackLocalOptionMode)
   741  					Expect(err).To(BeNil(), "Cannot set ConnTrackLocal=%q for endpoint %q",
   742  						conntrackLocalOptionMode, endpointToConfigure)
   743  				}
   744  				areEndpointsReady := vm.WaitEndpointsReady()
   745  				Expect(areEndpointsReady).Should(BeTrue(), "Endpoints are not ready after timeout")
   746  				clientServerConnectivity()
   747  			}
   748  
   749  			By("Testing Conntrack endpoint configuration option disabled")
   750  
   751  			// Delete all L4 policy so we can disable connection tracking
   752  			vm.PolicyDelAll().ExpectSuccess("Policies cannot be deleted")
   753  
   754  			for _, endpointToConfigure := range endpointsToConfigure {
   755  				// ConntrackLocal must be disabled as it depends on Conntrack
   756  				err := vm.SetAndWaitForEndpointConfiguration(endpointToConfigure, helpers.OptionConntrackLocal, helpers.OptionDisabled)
   757  				Expect(err).To(BeNil(), "Cannot disable ConntrackLocal for the endpoint %q", endpointToConfigure)
   758  				err = vm.SetAndWaitForEndpointConfiguration(endpointToConfigure, helpers.OptionConntrack, helpers.OptionDisabled)
   759  				Expect(err).To(BeNil(), "Cannot disable ConnTrack for the endpoint %q", endpointToConfigure)
   760  			}
   761  
   762  			// Need to add policy that allows communication in both directions.
   763  			_, err = vm.PolicyImportAndWait(
   764  				vm.GetFullPath(CTPolicyConntrackLocalDisabled),
   765  				helpers.HelperTimeout)
   766  			Expect(err).Should(BeNil(), "cannot import %s", CTPolicyConntrackLocalDisabled)
   767  
   768  			clientServerL3Connectivity()
   769  		})
   770  
   771  	}
   772  }