Skip to content

Commit

Permalink
Bugfix: Fix incorrect Pod MTU when WireGuard enabled
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
hjiajing committed Jan 22, 2024
1 parent 48d7f7b commit c2c3d32
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 14 deletions.
2 changes: 1 addition & 1 deletion cmd/antrea-agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func run(o *Options) error {
IPsecConfig: config.IPsecConfig{
AuthenticationMode: ipsecAuthenticationMode,
},
EnableMulticlusterGW: enableMulticlusterGW,
MulticlusterConfig: o.config.Multicluster,
}

wireguardConfig := &config.WireGuardConfig{
Expand Down
4 changes: 0 additions & 4 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
29 changes: 21 additions & 8 deletions pkg/agent/config/node_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ package config
import (
"fmt"
"net"
"strings"

agentConfig "antrea.io/antrea/pkg/config/agent"
"antrea.io/antrea/pkg/ovs/ovsconfig"
)

Expand Down Expand Up @@ -201,14 +203,15 @@ 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.
// For Encap and Hybrid mode, InterfaceMTU will be adjusted to account for
// encap header.
InterfaceMTU int
EnableMulticlusterGW bool
MulticlusterConfig agentConfig.MulticlusterConfig
}

// IsIPv4Enabled returns true if the cluster network supports IPv4. Legal cases are:
Expand Down Expand Up @@ -265,23 +268,33 @@ func (nc *NetworkConfig) NeedsDirectRoutingToPeer(peerIP net.IP, localIP *net.IP
}

func (nc *NetworkConfig) CalculateMTUDeduction(isIPv6 bool) int {
var mtuDeduction int
// 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
nc.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.
Expand Down
20 changes: 20 additions & 0 deletions pkg/agent/config/node_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/stretchr/testify/assert"

agentConfig "antrea.io/antrea/pkg/config/agent"
"antrea.io/antrea/pkg/ovs/ovsconfig"
)

Expand Down Expand Up @@ -306,6 +307,25 @@ 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,
},
}

for _, tt := range tests {
Expand Down
2 changes: 1 addition & 1 deletion pkg/agent/multicluster/mc_route_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.networkConfig.MTUDeduction,
}
}
controller.gwInformer.Informer().AddEventHandlerWithResyncPeriod(
Expand Down
51 changes: 51 additions & 0 deletions test/e2e/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -2481,6 +2481,57 @@ func (data *TestData) GetTransportInterface() (string, error) {
return "", fmt.Errorf("no interface was assigned with Node IP %s", nodeIP)
}

func (data *TestData) GetPodInterfaceName(nodeName string, podName string) (string, error) {
antreaPod, err := data.getAntreaPodOnNode(nodeName)
if err != nil {
return "", fmt.Errorf("failed to get Antrea Pod on Node %s: %v", nodeName, err)
}
cmd := []string{"ip", "-br", "addr", "show"}
stdout, stderr, err := data.RunCommandFromPod(antreaNamespace, antreaPod, agentContainerName, cmd)
if stdout == "" || stderr != "" || err != nil {
return "", fmt.Errorf("failed to show ip address, stdout: %s, stderr: %s, err: %v", stdout, stderr, err)
}

lines := strings.Split(strings.TrimSpace(stdout), "\n")
for _, line := range lines {
if strings.Contains(line, podName) {
fields := strings.Fields(line)
name, _, _ := strings.Cut(fields[0], "@")
return name, nil
}
}

return "", fmt.Errorf("no interface was assigned with Pod %s", podName)
}

func (data *TestData) GetInterfaceMTU(nodeName string, interfaceName string) (int, error) {
antreaPod, err := data.getAntreaPodOnNode(nodeName)
if err != nil {
return 0, fmt.Errorf("failed to get Antrea Pod on Node %s: %v", nodeName, err)
}
cmd := []string{"ip", "link", "show", interfaceName}
stdout, stderr, err := data.RunCommandFromPod(antreaNamespace, antreaPod, agentContainerName, cmd)
if stdout == "" || stderr != "" || err != nil {
return 0, fmt.Errorf("failed to get interface MTU, stdout: %s, stderr: %s, err: %v", stdout, stderr, err)
}

// Example stdout:
// 22: vxlan-29acf3@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master ovs-system state UP mode DEFAULT group default
// link/ether be:41:93:69:87:02 brd ff:ff:ff:ff:ff:ff link-netns cni-320ae61f-5e51-d123-0169-9f1807390500
fields := strings.Fields(strings.Split(strings.TrimSpace(stdout), "\n")[0])
// Get the value of "mtu"
for i := 0; i < len(fields)-1; i++ {
if fields[i] == "mtu" {
mtu, err := strconv.Atoi(fields[i+1])
if err != nil {
return 0, fmt.Errorf("failed to convert MTU to int: %v", err)
}
return mtu, nil
}
}
return 0, fmt.Errorf("failed to get MTU from stdout: %s", stdout)
}

func (data *TestData) GetNodeMACAddress(node, device string) (string, error) {
antreaPod, err := data.getAntreaPodOnNode(node)
if err != nil {
Expand Down
Loading

0 comments on commit c2c3d32

Please sign in to comment.