From d8dbf0b5611be814b83e5175a07d30c671e0c151 Mon Sep 17 00:00:00 2001 From: Jiajing Hu Date: Sun, 21 Jan 2024 18:02:47 +0800 Subject: [PATCH] Bugfix: Fix incorrect Pod MTU when WireGuard enabled The default tunnel type is GENEVE, when the WireGuard encryption is enabled, the Pod MTU calculator still deducts the GENEVE overhead directly, which causes a MTU error. This patch will calculate all MTU deduction in function CalculateMTUDeduction, including WireGuard and Multicluster. Signed-off-by: Jiajing Hu --- cmd/antrea-agent/agent.go | 1 + pkg/agent/agent.go | 4 - pkg/agent/config/node_config.go | 33 ++++-- pkg/agent/config/node_config_test.go | 37 +++++- pkg/agent/multicluster/mc_route_controller.go | 2 +- .../secondary_network_test.go | 2 +- test/e2e/antreaipam_test.go | 4 +- test/e2e/connectivity_test.go | 112 ++++++++++++++---- test/e2e/framework.go | 28 ++++- test/e2e/ipsec_test.go | 14 ++- test/e2e/traceflow_test.go | 4 +- test/e2e/vmagent_test.go | 2 +- test/e2e/wireguard_test.go | 7 +- 13 files changed, 199 insertions(+), 51 deletions(-) diff --git a/cmd/antrea-agent/agent.go b/cmd/antrea-agent/agent.go index fba691bdd76..fdb99444e69 100644 --- a/cmd/antrea-agent/agent.go +++ b/cmd/antrea-agent/agent.go @@ -206,6 +206,7 @@ func run(o *Options) error { AuthenticationMode: ipsecAuthenticationMode, }, EnableMulticlusterGW: enableMulticlusterGW, + MulticlusterConfig: o.config.Multicluster, } wireguardConfig := &config.WireGuardConfig{ diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 791e18b890f..86b41009869 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -1194,10 +1194,6 @@ func (i *Initializer) getInterfaceMTU(transportInterface *net.Interface) (int, e isIPv6 := i.nodeConfig.NodeIPv6Addr != nil mtu -= i.networkConfig.CalculateMTUDeduction(isIPv6) - - if i.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeIPSec { - mtu -= config.IPSecESPOverhead - } return mtu, nil } diff --git a/pkg/agent/config/node_config.go b/pkg/agent/config/node_config.go index ebba7f3da9e..32ee0999011 100644 --- a/pkg/agent/config/node_config.go +++ b/pkg/agent/config/node_config.go @@ -17,7 +17,9 @@ package config import ( "fmt" "net" + "strings" + agentConfig "antrea.io/antrea/pkg/config/agent" "antrea.io/antrea/pkg/ovs/ovsconfig" ) @@ -36,7 +38,7 @@ const ( const ( vxlanOverhead = 50 geneveOverhead = 50 - greOverhead = 38 + greOverhead = 42 ipv6ExtraOverhead = 20 WireGuardOverhead = 80 @@ -201,7 +203,7 @@ type NetworkConfig struct { TransportIfaceCIDRs []string IPv4Enabled bool IPv6Enabled bool - // MTUDeduction only counts IPv4 tunnel overhead, no IPsec and WireGuard overhead. + // MTUDeduction is the MTU deduction for encapsulation and encryption in cluster. MTUDeduction int // Set by the defaultMTU config option or auto discovered. // Auto discovery will use MTU value of the Node's transport interface. @@ -209,6 +211,7 @@ type NetworkConfig struct { // encap header. InterfaceMTU int EnableMulticlusterGW bool + MulticlusterConfig agentConfig.MulticlusterConfig } // IsIPv4Enabled returns true if the cluster network supports IPv4. Legal cases are: @@ -265,23 +268,33 @@ func (nc *NetworkConfig) NeedsDirectRoutingToPeer(peerIP net.IP, localIP *net.IP } func (nc *NetworkConfig) CalculateMTUDeduction(isIPv6 bool) int { - var mtuDeduction int + if nc.TrafficEncapMode.SupportsEncap() && isIPv6 { + nc.MTUDeduction += ipv6ExtraOverhead + } + // When WireGuard is enabled, NetworkConfig.TunnelType will be ignored, so we deduct MTU based on WireGuardOverhead. + if nc.TrafficEncryptionMode == TrafficEncryptionModeWireGuard { + nc.MTUDeduction = WireGuardOverhead + return nc.MTUDeduction + } else if nc.TrafficEncryptionMode == TrafficEncryptionModeIPSec { + nc.MTUDeduction = IPSecESPOverhead + } + // When Multi-cluster Gateway is enabled, we need to reduce MTU for potential cross-cluster traffic. if nc.TrafficEncapMode.SupportsEncap() || nc.EnableMulticlusterGW { if nc.TunnelType == ovsconfig.VXLANTunnel { - mtuDeduction = vxlanOverhead + nc.MTUDeduction += vxlanOverhead } else if nc.TunnelType == ovsconfig.GeneveTunnel { - mtuDeduction = geneveOverhead + nc.MTUDeduction += geneveOverhead } else if nc.TunnelType == ovsconfig.GRETunnel { - mtuDeduction = greOverhead + nc.MTUDeduction += greOverhead } } - if nc.TrafficEncapMode.SupportsEncap() && isIPv6 { - mtuDeduction += ipv6ExtraOverhead + // When multi-cluster WireGuard is enabled, we need to reduce MTU for potential cross-cluster traffic. + if nc.EnableMulticlusterGW && strings.EqualFold(nc.MulticlusterConfig.TrafficEncryptionMode, TrafficEncryptionModeWireGuard.String()) { + nc.MTUDeduction += WireGuardOverhead } - nc.MTUDeduction = mtuDeduction - return mtuDeduction + return nc.MTUDeduction } // ServiceConfig includes K8s Service CIDR and available IP addresses for NodePort. diff --git a/pkg/agent/config/node_config_test.go b/pkg/agent/config/node_config_test.go index 081ce053c7f..524093d7150 100644 --- a/pkg/agent/config/node_config_test.go +++ b/pkg/agent/config/node_config_test.go @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/assert" + agentConfig "antrea.io/antrea/pkg/config/agent" "antrea.io/antrea/pkg/ovs/ovsconfig" ) @@ -298,7 +299,7 @@ func TestCalculateMTUDeduction(t *testing.T) { { name: "GRE encap without IPv6", nc: &NetworkConfig{TunnelType: ovsconfig.GRETunnel}, - expectedMTUDeduction: 38, + expectedMTUDeduction: 42, }, { name: "Default encap with IPv6", @@ -306,6 +307,40 @@ func TestCalculateMTUDeduction(t *testing.T) { isIPv6: true, expectedMTUDeduction: 70, }, + { + name: "WireGuard enabled", + nc: &NetworkConfig{TrafficEncryptionMode: TrafficEncryptionModeWireGuard}, + expectedMTUDeduction: 80, + }, + { + name: "Multicluster enabled with Geneve encap", + nc: &NetworkConfig{TunnelType: ovsconfig.GeneveTunnel, EnableMulticlusterGW: true}, + expectedMTUDeduction: 50, + }, + { + name: "Geneve encap with Multicluster WireGuard enabled", + nc: &NetworkConfig{ + TunnelType: ovsconfig.GeneveTunnel, + EnableMulticlusterGW: true, + MulticlusterConfig: agentConfig.MulticlusterConfig{TrafficEncryptionMode: "wireGuard"}, + }, + expectedMTUDeduction: 130, + }, + { + name: "Geneve encap with IPSec enabled", + nc: &NetworkConfig{TunnelType: ovsconfig.GeneveTunnel, TrafficEncryptionMode: TrafficEncryptionModeIPSec}, + expectedMTUDeduction: 88, + }, + { + name: "VXLan encap with IPSec enabled", + nc: &NetworkConfig{TunnelType: ovsconfig.VXLANTunnel, TrafficEncryptionMode: TrafficEncryptionModeIPSec}, + expectedMTUDeduction: 88, + }, + { + name: "GRE encap with IPSec enabled", + nc: &NetworkConfig{TunnelType: ovsconfig.GRETunnel, TrafficEncryptionMode: TrafficEncryptionModeIPSec}, + expectedMTUDeduction: 80, + }, } for _, tt := range tests { diff --git a/pkg/agent/multicluster/mc_route_controller.go b/pkg/agent/multicluster/mc_route_controller.go index 568371329d5..a0e6d521fef 100644 --- a/pkg/agent/multicluster/mc_route_controller.go +++ b/pkg/agent/multicluster/mc_route_controller.go @@ -129,7 +129,7 @@ func NewMCDefaultRouteController( controller.wireGuardConfig = &config.WireGuardConfig{ Port: multiclusterConfig.WireGuard.Port, Name: multiclusterWireGuardInterface, - MTU: controller.nodeConfig.NodeTransportInterfaceMTU - controller.networkConfig.MTUDeduction - config.WireGuardOverhead, + MTU: controller.nodeConfig.NodeTransportInterfaceMTU, } } controller.gwInformer.Informer().AddEventHandlerWithResyncPeriod( diff --git a/test/e2e-secondary-network/secondary_network_test.go b/test/e2e-secondary-network/secondary_network_test.go index e5caff7cd77..b67d2974ce4 100644 --- a/test/e2e-secondary-network/secondary_network_test.go +++ b/test/e2e-secondary-network/secondary_network_test.go @@ -198,7 +198,7 @@ func (data *TestData) pingBetweenInterfaces(t *testing.T) error { } else { IPToPing = antreae2e.PodIPs{IPv6: &ip} } - err := data.e2eTestData.RunPingCommandFromTestPod(antreae2e.PodInfo{Name: podData[sourcePod].nameOfPods, OS: osType, NodeName: clusterInfo.controlPlaneNodeName, Namespace: nameSpace}, nameSpace, &IPToPing, ctrName, count, size) + err := data.e2eTestData.RunPingCommandFromTestPod(antreae2e.PodInfo{Name: podData[sourcePod].nameOfPods, OS: osType, NodeName: clusterInfo.controlPlaneNodeName, Namespace: nameSpace}, nameSpace, &IPToPing, ctrName, count, size, true) if err == nil { logs.Infof("Ping '%s' -> '%s'( Interface: %s, IP Address: %s): OK", podData[sourcePod].nameOfPods, podData[targetPod].nameOfPods, podData[targetPod].nameOfInterfacePerPod[targetInterface], secondaryIpAddress) } else { diff --git a/test/e2e/antreaipam_test.go b/test/e2e/antreaipam_test.go index f1cec366f73..cf96d1306d9 100644 --- a/test/e2e/antreaipam_test.go +++ b/test/e2e/antreaipam_test.go @@ -282,7 +282,7 @@ func testAntreaIPAMPodConnectivitySameNode(t *testing.T, data *TestData) { defer deletePodWrapper(t, data, PodInfos[i].Namespace, PodInfos[i].Name) } - data.runPingMesh(t, PodInfos, agnhostContainerName) + data.runPingMesh(t, PodInfos, agnhostContainerName, 0, true) } func testAntreaIPAMPodConnectivityDifferentNodes(t *testing.T, data *TestData) { @@ -296,7 +296,7 @@ func testAntreaIPAMPodConnectivityDifferentNodes(t *testing.T, data *TestData) { } PodInfos = append(PodInfos, createdPodInfos...) } - data.runPingMesh(t, PodInfos, agnhostContainerName) + data.runPingMesh(t, PodInfos, agnhostContainerName, 0, true) } func testAntreaIPAMStatefulSet(t *testing.T, data *TestData, dedicatedIPPoolKey *string) { diff --git a/test/e2e/connectivity_test.go b/test/e2e/connectivity_test.go index f2d42363384..5dcdb8ba4bd 100644 --- a/test/e2e/connectivity_test.go +++ b/test/e2e/connectivity_test.go @@ -28,10 +28,22 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "antrea.io/antrea/pkg/agent/config" + agentconfig "antrea.io/antrea/pkg/config/agent" + "antrea.io/antrea/pkg/features" "antrea.io/antrea/pkg/util/k8s" ) -const pingCount = 5 +const ( + pingCount = 5 + + IPHeaderSize = 20 + ICMPHeaderSize = 8 +) + +type trafficConfig struct { + tunnelType string + multiclusterTrafficEncryptionMode string +} // TestConnectivity is the top-level test which contains all subtests for // Connectivity related test cases so they can share setup, teardown. @@ -42,17 +54,21 @@ func TestConnectivity(t *testing.T) { } defer teardownTest(t, data) - t.Run("testPodConnectivityOnSameNode", func(t *testing.T) { - testPodConnectivityOnSameNode(t, data) + t.Run("testPodConnectivityWithDifferentTrafficConfig", func(t *testing.T) { + trafficConfigs := []trafficConfig{ + {tunnelType: "geneve", multiclusterTrafficEncryptionMode: "none"}, + {tunnelType: "vxlan", multiclusterTrafficEncryptionMode: "none"}, + {tunnelType: "gre", multiclusterTrafficEncryptionMode: "none"}, + {tunnelType: "geneve", multiclusterTrafficEncryptionMode: "wireguard"}, + {tunnelType: "vxlan", multiclusterTrafficEncryptionMode: "wireguard"}, + {tunnelType: "gre", multiclusterTrafficEncryptionMode: "wireguard"}, + } + testPodConnectivityWithDifferentTrafficConfigs(t, data, trafficConfigs) }) t.Run("testHostPortPodConnectivity", func(t *testing.T) { skipIfHasWindowsNodes(t) testHostPortPodConnectivity(t, data) }) - t.Run("testPodConnectivityDifferentNodes", func(t *testing.T) { - skipIfNumNodesLessThan(t, 2) - testPodConnectivityDifferentNodes(t, data) - }) t.Run("testPodConnectivityAfterAntreaRestart", func(t *testing.T) { skipIfHasWindowsNodes(t) testPodConnectivityAfterAntreaRestart(t, data, data.testNamespace) @@ -72,6 +88,48 @@ func TestConnectivity(t *testing.T) { }) } +func testPodConnectivityWithDifferentTrafficConfigs(t *testing.T, data *TestData, trafficConfigs []trafficConfig) { + var previousTunnelType string + var previousMulticlusterTrafficEncryptionMode string + var previousEnableMulticlusterGW bool + var previousMulticlusterEnable bool + defer func() { + ac := func(config *agentconfig.AgentConfig) { + config.TunnelType = previousTunnelType + config.Multicluster.TrafficEncryptionMode = previousMulticlusterTrafficEncryptionMode + config.Multicluster.EnableGateway = previousEnableMulticlusterGW + config.FeatureGates[string(features.Multicluster)] = previousMulticlusterEnable + } + if err := data.mutateAntreaConfigMap(nil, ac, false, true); err != nil { + t.Errorf("Failed to restore Antrea Agent Config: %v", err) + } + }() + for _, conf := range trafficConfigs { + t.Logf("Testing connectivity with TunnelType %s and multicluster.TrafficEncrptionMode %s", conf.tunnelType, conf.multiclusterTrafficEncryptionMode) + ac := func(config *agentconfig.AgentConfig) { + previousTunnelType = config.TunnelType + previousMulticlusterTrafficEncryptionMode = config.Multicluster.TrafficEncryptionMode + previousEnableMulticlusterGW = config.Multicluster.EnableGateway + previousMulticlusterEnable = config.FeatureGates[string(features.Multicluster)] + config.TunnelType = conf.tunnelType + config.Multicluster.TrafficEncryptionMode = conf.multiclusterTrafficEncryptionMode + config.Multicluster.EnableGateway = true + config.FeatureGates[string(features.Multicluster)] = true + } + if err := data.mutateAntreaConfigMap(nil, ac, false, true); err != nil { + t.Fatalf("Failed to enable tunnelType %s, multicluster.TrafficEncryptionMode %s: %v", conf.tunnelType, conf.multiclusterTrafficEncryptionMode, err) + } + + t.Run("testPodConnectivityOnSameNode", func(t *testing.T) { + testPodConnectivityOnSameNode(t, data) + }) + t.Run("testPodConnectivityDifferentNodes", func(t *testing.T) { + skipIfNumNodesLessThan(t, 2) + testPodConnectivityDifferentNodes(t, data) + }) + } +} + func waitForPodIPs(t *testing.T, data *TestData, podInfos []PodInfo) map[string]*PodIPs { t.Logf("Waiting for Pods to be ready and retrieving IPs") podIPs := make(map[string]*PodIPs) @@ -92,8 +150,9 @@ func waitForPodIPs(t *testing.T, data *TestData, podInfos []PodInfo) map[string] } // runPingMesh runs a ping mesh between all the provided Pods after first retrieving their IP -// addresses. -func (data *TestData) runPingMesh(t *testing.T, podInfos []PodInfo, ctrname string) { +// addresses. If mtu is non-zero, the ping command will be run with the provided MTU value. +// If mtu is zero, the ping command will be run with the default MTU value. +func (data *TestData) runPingMesh(t *testing.T, podInfos []PodInfo, ctrname string, mtu int, fragment bool) { podIPs := waitForPodIPs(t, data, podInfos) t.Logf("Ping mesh test between all Pods") @@ -110,7 +169,8 @@ func (data *TestData) runPingMesh(t *testing.T, podInfos []PodInfo, ctrname stri if pi2.Namespace != "" { pod2Namespace = pi2.Namespace } - if err := data.RunPingCommandFromTestPod(pi1, podNamespace, podIPs[pi2.Name], ctrname, pingCount, 0); err != nil { + + if err := data.RunPingCommandFromTestPod(pi1, podNamespace, podIPs[pi2.Name], ctrname, pingCount, mtu, fragment); err != nil { t.Errorf("Ping '%s' -> '%s': ERROR (%v)", k8s.NamespacedName(podNamespace, pi1.Name), k8s.NamespacedName(pod2Namespace, pi2.Name), err) } else { t.Logf("Ping '%s' -> '%s': OK", k8s.NamespacedName(podNamespace, pi1.Name), k8s.NamespacedName(pod2Namespace, pi2.Name)) @@ -131,16 +191,20 @@ func (data *TestData) testPodConnectivitySameNode(t *testing.T) { workerNode = workerNodeName(clusterInfo.windowsNodes[0]) } - t.Logf("Creating %d agnhost Pods on '%s'", numPods, workerNode) + t.Logf("Creating %d toolbox Pods on '%s'", numPods, workerNode) for i := range podInfos { podInfos[i].OS = clusterInfo.nodesOS[workerNode] - if err := data.createAgnhostPodOnNode(podInfos[i].Name, data.testNamespace, workerNode, false); err != nil { - t.Fatalf("Error when creating agnhost test Pod '%s': %v", podInfos[i], err) + if err := data.createToolboxPodOnNode(podInfos[i].Name, data.testNamespace, workerNode, false); err != nil { + t.Fatalf("Error when creating toolbox test Pod '%s': %v", podInfos[i], err) } defer deletePodWrapper(t, data, data.testNamespace, podInfos[i].Name) } + mtu, err := data.GetPodInterfaceMTU(podInfos[0].Name, data.testNamespace) + if err != nil { + t.Fatalf("Error when retrieving MTU for Pod '%s': %v", podInfos[0].Name, err) + } - data.runPingMesh(t, podInfos, agnhostContainerName) + data.runPingMesh(t, podInfos, toolboxContainerName, mtu-IPHeaderSize-ICMPHeaderSize, false) } // testPodConnectivityOnSameNode checks that Pods running on the same Node can reach each other, by @@ -185,13 +249,13 @@ func testHostPortPodConnectivity(t *testing.T, data *TestData) { data.testHostPortPodConnectivity(t, data.testNamespace, data.testNamespace) } -// createPodsOnDifferentNodes creates agnhost Pods through a DaemonSet. This function returns information of the created +// createPodsOnDifferentNodes creates toolbox Pods through a DaemonSet. This function returns information of the created // Pods as well as a function which will delete the Pods when called. Since Pods can be on Nodes of different OSes, podInfo // slice instead of PodName slice is used to inform caller of correct commands and options. Linux and Windows Pods are // alternating in this podInfo slice so that the test can cover different connectivity cases between different OSes. func createPodsOnDifferentNodes(t *testing.T, data *TestData, namespace, tag string) (podInfos []PodInfo, cleanup func() error) { dsName := "connectivity-test" + tag - _, deleteDaemonSet, err := data.createDaemonSet(dsName, namespace, agnhostContainerName, agnhostImage, []string{"sleep", "3600"}, nil) + _, deleteDaemonSet, err := data.createDaemonSet(dsName, namespace, toolboxContainerName, toolboxImage, []string{"sleep", "3600"}, nil) if err != nil { t.Fatalf("Error when creating DaemonSet '%s': %v", dsName, err) } @@ -264,7 +328,11 @@ func (data *TestData) testPodConnectivityDifferentNodes(t *testing.T) { if len(podInfos) > maxPods { podInfos = podInfos[:maxPods] } - data.runPingMesh(t, podInfos[:numPods], agnhostContainerName) + mtu, err := data.GetPodInterfaceMTU(podInfos[0].Name, data.testNamespace) + if err != nil { + t.Fatalf("Error when retrieving MTU for Pod '%s': %v", podInfos[0].Name, err) + } + data.runPingMesh(t, podInfos[:numPods], toolboxContainerName, mtu-IPHeaderSize-ICMPHeaderSize, false) } // testPodConnectivityDifferentNodes checks that Pods running on different Nodes can reach each @@ -315,11 +383,11 @@ func testPodConnectivityAfterAntreaRestart(t *testing.T, data *TestData, namespa podInfos, deletePods := createPodsOnDifferentNodes(t, data, namespace, "antrearestart") defer deletePods() - data.runPingMesh(t, podInfos[:numPods], agnhostContainerName) + data.runPingMesh(t, podInfos[:numPods], agnhostContainerName, 0, true) data.redeployAntrea(t, deployAntreaDefault) - data.runPingMesh(t, podInfos[:numPods], agnhostContainerName) + data.runPingMesh(t, podInfos[:numPods], agnhostContainerName, 0, true) } // testOVSRestartSameNode verifies that datapath flows are not removed when the Antrea Agent Pod is @@ -405,7 +473,7 @@ func testOVSFlowReplay(t *testing.T, data *TestData, namespace string) { defer deletePodWrapper(t, data, namespace, podInfos[i].Name) } - data.runPingMesh(t, podInfos, busyboxContainerName) + data.runPingMesh(t, podInfos, busyboxContainerName, 0, true) var antreaPodName string var err error @@ -487,7 +555,7 @@ func testOVSFlowReplay(t *testing.T, data *TestData, namespace string) { // This should give Antrea ~10s to restore flows, since we generate 10 "pings" with a 1s // interval. t.Logf("Running second ping mesh to check that flows have been restored") - data.runPingMesh(t, podInfos, busyboxContainerName) + data.runPingMesh(t, podInfos, busyboxContainerName, 0, true) flows2, groups2 := dumpFlows(), dumpGroups() numFlows2, numGroups2 := len(flows2), len(groups2) @@ -515,7 +583,7 @@ func testPingLargeMTU(t *testing.T, data *TestData) { pingSize := 2000 t.Logf("Running ping with size %d between Pods %s and %s", pingSize, podInfos[0].Name, podInfos[1].Name) - if err := data.RunPingCommandFromTestPod(podInfos[0], data.testNamespace, podIPs[podInfos[1].Name], agnhostContainerName, pingCount, pingSize); err != nil { + if err := data.RunPingCommandFromTestPod(podInfos[0], data.testNamespace, podIPs[podInfos[1].Name], agnhostContainerName, pingCount, pingSize, true); err != nil { t.Error(err) } } diff --git a/test/e2e/framework.go b/test/e2e/framework.go index 8eba90cd07f..aa42b1235d0 100644 --- a/test/e2e/framework.go +++ b/test/e2e/framework.go @@ -2232,18 +2232,18 @@ func parseArpingStdout(out string) (sent uint32, received uint32, loss float32, return sent, received, loss, nil } -func (data *TestData) RunPingCommandFromTestPod(podInfo PodInfo, ns string, targetPodIPs *PodIPs, ctrName string, count int, size int) error { +func (data *TestData) RunPingCommandFromTestPod(podInfo PodInfo, ns string, targetPodIPs *PodIPs, ctrName string, count int, size int, fragment bool) error { if podInfo.OS != "windows" && podInfo.OS != "linux" { return fmt.Errorf("OS of Pod '%s' is not clear", podInfo.Name) } if targetPodIPs.IPv4 != nil { - cmdV4 := getPingCommand(count, size, podInfo.OS, targetPodIPs.IPv4) + cmdV4 := getPingCommand(count, size, podInfo.OS, targetPodIPs.IPv4, fragment) if stdout, stderr, err := data.RunCommandFromPod(ns, podInfo.Name, ctrName, cmdV4); err != nil { return fmt.Errorf("error when running ping command '%s': %v - stdout: %s - stderr: %s", strings.Join(cmdV4, " "), err, stdout, stderr) } } if targetPodIPs.IPv6 != nil { - cmdV6 := getPingCommand(count, size, podInfo.OS, targetPodIPs.IPv6) + cmdV6 := getPingCommand(count, size, podInfo.OS, targetPodIPs.IPv6, fragment) if stdout, stderr, err := data.RunCommandFromPod(ns, podInfo.Name, ctrName, cmdV6); err != nil { return fmt.Errorf("error when running ping command '%s': %v - stdout: %s - stderr: %s", strings.Join(cmdV6, " "), err, stdout, stderr) } @@ -2481,6 +2481,20 @@ func (data *TestData) GetTransportInterface() (string, error) { return "", fmt.Errorf("no interface was assigned with Node IP %s", nodeIP) } +func (data *TestData) GetPodInterfaceMTU(podName string, namespace string) (int, error) { + cmd := []string{"cat", "/sys/class/net/eth0/mtu"} + stdout, stderr, err := data.RunCommandFromPod(namespace, podName, toolboxContainerName, cmd) + if stdout == "" || stderr != "" || err != nil { + return 0, fmt.Errorf("failed to get interface MTU, stdout: %s, stderr: %s, err: %v", stdout, stderr, err) + } + + mtu, err := strconv.Atoi(strings.TrimSpace(stdout)) + if err != nil { + return 0, fmt.Errorf("failed to convert MTU to int: %v", err) + } + return mtu, nil +} + func (data *TestData) GetNodeMACAddress(node, device string) (string, error) { antreaPod, err := data.getAntreaPodOnNode(node) if err != nil { @@ -3059,8 +3073,8 @@ func (data *TestData) checkAntreaAgentInfo(interval time.Duration, timeout time. return err } -func getPingCommand(count int, size int, os string, ip *net.IP) []string { - countOption, sizeOption := "-c", "-s" +func getPingCommand(count int, size int, os string, ip *net.IP, fragment bool) []string { + countOption, sizeOption, fragmentOption := "-c", "-s", "-M" if os == "windows" { countOption = "-n" sizeOption = "-l" @@ -3069,6 +3083,10 @@ func getPingCommand(count int, size int, os string, ip *net.IP) []string { if size != 0 { cmd = append(cmd, sizeOption, strconv.Itoa(size)) } + if !fragment { + cmd = append(cmd, fragmentOption) + cmd = append(cmd, "do") + } if ip.To4() != nil { cmd = append(cmd, "-4", ip.String()) } else { diff --git a/test/e2e/ipsec_test.go b/test/e2e/ipsec_test.go index c51cd5375da..7c260676e18 100644 --- a/test/e2e/ipsec_test.go +++ b/test/e2e/ipsec_test.go @@ -79,6 +79,14 @@ func TestIPSec(t *testing.T) { }) t.Run("testIPSecDeleteStaleTunnelPorts", func(t *testing.T) { testIPSecDeleteStaleTunnelPorts(t, data) }) + t.Run("testPodConnectivityWithDifferentTrafficConfig", func(t *testing.T) { + trafficConfigs := []trafficConfig{ + {tunnelType: "geneve", multiclusterTrafficEncryptionMode: "none"}, + {tunnelType: "vxlan", multiclusterTrafficEncryptionMode: "none"}, + {tunnelType: "gre", multiclusterTrafficEncryptionMode: "none"}, + } + testPodConnectivityWithDifferentTrafficConfigs(t, data, trafficConfigs) + }) } func (data *TestData) readSecurityAssociationsStatus(nodeName string) (up int, connecting int, isCertAuth bool, err error) { @@ -137,7 +145,11 @@ func testIPSecTunnelConnectivity(t *testing.T, data *TestData, certAuth bool) { podInfos, deletePods := createPodsOnDifferentNodes(t, data, data.testNamespace, tag) defer deletePods() t.Logf("Executing ping tests across Nodes: '%s' <-> '%s'", podInfos[0].NodeName, podInfos[1].NodeName) - data.runPingMesh(t, podInfos[:2], agnhostContainerName) + mtu, err := data.GetPodInterfaceMTU(podInfos[0].Name, podInfos[0].Namespace) + if err != nil { + t.Fatalf("Error when retrieving MTU for Pod '%s': %v", podInfos[0].Name, err) + } + data.runPingMesh(t, podInfos[:2], toolboxContainerName, mtu, false) // Check that there is at least one 'up' Security Association on the Node nodeName := podInfos[0].NodeName diff --git a/test/e2e/traceflow_test.go b/test/e2e/traceflow_test.go index 6b3f069a986..b23399bdd8b 100644 --- a/test/e2e/traceflow_test.go +++ b/test/e2e/traceflow_test.go @@ -1167,7 +1167,7 @@ func testTraceflowInterNode(t *testing.T, data *TestData) { podInfos[1].Name = node2Pods[2] podInfos[1].Namespace = data.testNamespace podInfos[1].OS = "windows" - data.runPingMesh(t, podInfos, agnhostContainerName) + data.runPingMesh(t, podInfos, agnhostContainerName, 0, true) } // Setup 2 NetworkPolicies: @@ -2507,7 +2507,7 @@ func runTestTraceflow(t *testing.T, data *TestData, tc testcase) { // Give a little time for Nodes to install OVS flows. time.Sleep(time.Second * 2) // Send an ICMP echo packet from the source Pod to the destination. - if err := data.RunPingCommandFromTestPod(PodInfo{srcPod, osString, "", ""}, data.testNamespace, dstPodIPs, agnhostContainerName, 2, 0); err != nil { + if err := data.RunPingCommandFromTestPod(PodInfo{srcPod, osString, "", ""}, data.testNamespace, dstPodIPs, agnhostContainerName, 2, 0, true); err != nil { t.Logf("Ping '%s' -> '%v' failed: ERROR (%v)", srcPod, *dstPodIPs, err) } } diff --git a/test/e2e/vmagent_test.go b/test/e2e/vmagent_test.go index 6036a88b2de..59a491d00a8 100644 --- a/test/e2e/vmagent_test.go +++ b/test/e2e/vmagent_test.go @@ -656,7 +656,7 @@ func createANPWithFQDN(t *testing.T, data *TestData, name string, namespace stri func runPingCommandOnVM(data *TestData, dstVM vmInfo, connected bool) error { dstIP := net.ParseIP(dstVM.ip) - cmd := getPingCommand(pingCount, 0, strings.ToLower(linuxOS), &dstIP) + cmd := getPingCommand(pingCount, 0, strings.ToLower(linuxOS), &dstIP, true) cmdStr := strings.Join(cmd, " ") expCount := pingCount if !connected { diff --git a/test/e2e/wireguard_test.go b/test/e2e/wireguard_test.go index b746ffe07a7..ab6639de4b8 100644 --- a/test/e2e/wireguard_test.go +++ b/test/e2e/wireguard_test.go @@ -69,7 +69,12 @@ func testPodConnectivity(t *testing.T, data *TestData) { podInfos, deletePods := createPodsOnDifferentNodes(t, data, data.testNamespace, "differentnodes") defer deletePods() numPods := 2 - data.runPingMesh(t, podInfos[:numPods], agnhostContainerName) + + mtu, err := data.GetPodInterfaceMTU(podInfos[0].Name, podInfos[0].Namespace) + if err != nil { + t.Fatalf("Failed to get MTU of Pod %s: %v", podInfos[0].Name, err) + } + data.runPingMesh(t, podInfos[:numPods], toolboxContainerName, mtu-IPHeaderSize-ICMPHeaderSize, false) // Make sure that route to Pod on peer Node and route to peer gateway is targeting the WireGuard device. srcPod, err := data.getAntreaPodOnNode(nodeName(0))