Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,29 @@ Setting `ENABLE_BANDWIDTH_PLUGIN` to `true` will update `10-aws.conflist` to inc

NOTE: Kubernetes Network Policy is supported in Amazon VPC CNI starting with version v1.14.0. Note that bandwidth plugin is not compatible with Amazon VPC CNI based Network policy. Network Policy agent uses TC (traffic classifier) system to enforce configured network policies for the pods. The policy enforcement will fail if bandwidth plugin is enabled due to conflict between TC configuration of bandwidth plugin and Network policy agent. We're exploring options to support bandwidth plugin along with Network policy feature and the issue is tracked [here](https://github.com/aws/aws-network-policy-agent/issues/68)

#### `ENABLE_TUNING_PLUGIN`

Type: Boolean as a String

Default: `false`

Setting `ENABLE_TUNING_PLUGIN` to `true` will update `10-aws.conflist` to include the upstream [tuning plugin](https://www.cni.dev/plugins/current/meta/tuning/) as a chained plugin. The tuning plugin allows you to configure sysctl settings in the pod network namespace. Use this in combination with `TUNING_SYSCTLS` to specify which sysctls to set.

#### `TUNING_SYSCTLS`

Type: JSON-encoded string

Default: `""`

A JSON-encoded map of sysctl settings to apply in the pod network namespace. When this variable is set (non-empty), the tuning plugin will be automatically chained regardless of the `ENABLE_TUNING_PLUGIN` setting.

Example:
```
TUNING_SYSCTLS='{"net.core.somaxconn":"1024","net.ipv4.tcp_max_syn_backlog":"2048"}'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TOL does user have to provide value through env var? what will be experience if we had config map?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wasn't completely sure about. I was thinking env var however config map could work too however I didn't want to add a whole new config map just for this because it seems over kill

```

Note: The `DISABLE_POD_V6` environment variable also enables the tuning plugin with IPv6 disable sysctls. If both `DISABLE_POD_V6` and `TUNING_SYSCTLS` are set, the sysctls will be merged, with `TUNING_SYSCTLS` values taking precedence for any overlapping keys.

#### `ANNOTATE_POD_IP` (v1.9.3+)

Type: Boolean as a String
Expand Down
2 changes: 2 additions & 0 deletions charts/aws-vpc-cni/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ env:
NETWORK_POLICY_ENFORCING_MODE: "standard"
ENABLE_IMDS_ONLY_MODE: "false"
ENABLE_MULTI_NIC: "false"
# ENABLE_TUNING_PLUGIN: "false"
# TUNING_SYSCTLS: '{"net.core.somaxconn":"1024"}'

# Add env from configMap or from secrets
# - name: ENV_VAR1
Expand Down
45 changes: 36 additions & 9 deletions cmd/aws-vpc-cni/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const (
defaultIPCooldownPeriod = 30
defaultDisablePodV6 = false
defaultEnableMultiNICSupport = false
defaultEnableTuningPlugin = false

envHostCniBinPath = "HOST_CNI_BIN_PATH"
envHostCniConfDirPath = "HOST_CNI_CONFDIR_PATH"
Expand All @@ -108,6 +109,8 @@ const (
envIPCooldownPeriod = "IP_COOLDOWN_PERIOD"
envDisablePodV6 = "DISABLE_POD_V6"
envEnableMultiNICSupport = "ENABLE_MULTI_NIC"
envEnableTuningPlugin = "ENABLE_TUNING_PLUGIN"
envTuningSysctls = "TUNING_SYSCTLS"
)

// NetConfList describes an ordered list of networks.
Expand Down Expand Up @@ -288,7 +291,13 @@ func generateJSON(jsonFile string, outFile string, getPrimaryIP func(ipv4 bool)
// Chain any requested CNI plugins
enBandwidthPlugin := utils.GetBoolAsStringEnvVar(envEnBandwidthPlugin, defaultEnBandwidthPlugin)
disablePodV6 := utils.GetBoolAsStringEnvVar(envDisablePodV6, defaultDisablePodV6)
if enBandwidthPlugin || disablePodV6 {
enableTuningPlugin := utils.GetBoolAsStringEnvVar(envEnableTuningPlugin, defaultEnableTuningPlugin)
tuningSysctls := utils.GetEnv(envTuningSysctls, "")

// Determine if we need to chain the tuning plugin
chainTuningPlugin := disablePodV6 || enableTuningPlugin || tuningSysctls != ""

if enBandwidthPlugin || chainTuningPlugin {
// Unmarshall current conflist into data
data := NetConfList{}
err = json.Unmarshal(byteValue, &data)
Expand All @@ -305,15 +314,33 @@ func generateJSON(jsonFile string, outFile string, getPrimaryIP func(ipv4 bool)
data.Plugins = append(data.Plugins, &bwPlugin)
}

// Chain the tuning plugin (configured to disable IPv6 in pod network namespace) when requested
if disablePodV6 {
// Chain the tuning plugin when enabled via DISABLE_POD_V6, ENABLE_TUNING_PLUGIN, or TUNING_SYSCTLS
if chainTuningPlugin {
sysctls := make(map[string]string)

// Add IPv6 disable sysctls when DISABLE_POD_V6 is enabled
if disablePodV6 {
sysctls["net.ipv6.conf.all.disable_ipv6"] = "1"
Copy link
Contributor

@yash97 yash97 Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to explicitly add these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because VPC CNI currently use tuning CN plugin to disable ipv6. This is just keeping that feature

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if i need to move this lower and override any tuning configs

sysctls["net.ipv6.conf.default.disable_ipv6"] = "1"
sysctls["net.ipv6.conf.lo.disable_ipv6"] = "1"
}

// Parse and merge custom sysctls from TUNING_SYSCTLS environment variable
if tuningSysctls != "" {
customSysctls := make(map[string]string)
err = json.Unmarshal([]byte(tuningSysctls), &customSysctls)
if err != nil {
log.Errorf("Failed to parse TUNING_SYSCTLS: %v", err)
return err
}
for k, v := range customSysctls {
sysctls[k] = v
}
}

tuningPlugin := NetConf{
Type: "tuning",
Sysctl: map[string]string{
"net.ipv6.conf.all.disable_ipv6": "1",
"net.ipv6.conf.default.disable_ipv6": "1",
"net.ipv6.conf.lo.disable_ipv6": "1",
},
Type: "tuning",
Sysctl: sysctls,
}
data.Plugins = append(data.Plugins, &tuningPlugin)
}
Expand Down
94 changes: 94 additions & 0 deletions cmd/aws-vpc-cni/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,100 @@ func TestGenerateJSONPlusBandwidthAndTuning(t *testing.T) {
assert.NoError(t, err)
}

// Validate that generateJSON runs without error when ENABLE_TUNING_PLUGIN is set
func TestGenerateJSONWithEnableTuningPlugin(t *testing.T) {
_ = os.Setenv(envEnableTuningPlugin, "true")
defer os.Unsetenv(envEnableTuningPlugin)
err := generateJSON(awsConflist, devNull, getPrimaryIPMock)
assert.NoError(t, err)
}

// Validate that generateJSON runs without error when TUNING_SYSCTLS is set
func TestGenerateJSONWithTuningSysctls(t *testing.T) {
_ = os.Setenv(envTuningSysctls, `{"net.core.somaxconn":"1024"}`)
defer os.Unsetenv(envTuningSysctls)
err := generateJSON(awsConflist, devNull, getPrimaryIPMock)
assert.NoError(t, err)
}

// Validate that custom sysctls are applied to the conflist
func TestGenerateJSONWithCustomSysctls(t *testing.T) {
_ = os.Setenv(envTuningSysctls, `{"net.core.somaxconn":"1024","net.ipv4.tcp_max_syn_backlog":"2048"}`)
defer os.Unsetenv(envTuningSysctls)

// Use a temporary file for the parsed output.
tmpfile, err := os.CreateTemp("", "temp-aws-vpc-cni.conflist")
assert.NoError(t, err)
defer os.Remove(tmpfile.Name())

err = generateJSON(awsConflist, tmpfile.Name(), getPrimaryIPMock)
assert.NoError(t, err)

// Read the json file and verify the tuning plugin is present with custom sysctls
var jsonData map[string]interface{}
jsonFile, err := os.ReadFile(tmpfile.Name())
assert.NoError(t, err)

err = json.Unmarshal(jsonFile, &jsonData)
assert.NoError(t, err)

plugins, _ := jsonData["plugins"].([]interface{})
// Find the tuning plugin (should be last)
lastPlugin := plugins[len(plugins)-1].(map[string]interface{})
assert.Equal(t, "tuning", lastPlugin["type"])

sysctls := lastPlugin["sysctl"].(map[string]interface{})
assert.Equal(t, "1024", sysctls["net.core.somaxconn"])
assert.Equal(t, "2048", sysctls["net.ipv4.tcp_max_syn_backlog"])
}

// Validate that DISABLE_POD_V6 and custom sysctls can be combined
func TestGenerateJSONWithDisablePodV6AndCustomSysctls(t *testing.T) {
_ = os.Setenv(envDisablePodV6, "true")
_ = os.Setenv(envTuningSysctls, `{"net.core.somaxconn":"1024"}`)
defer func() {
os.Unsetenv(envDisablePodV6)
os.Unsetenv(envTuningSysctls)
}()

// Use a temporary file for the parsed output.
tmpfile, err := os.CreateTemp("", "temp-aws-vpc-cni.conflist")
assert.NoError(t, err)
defer os.Remove(tmpfile.Name())

err = generateJSON(awsConflist, tmpfile.Name(), getPrimaryIPMock)
assert.NoError(t, err)

// Read the json file and verify the tuning plugin has both IPv6 disable and custom sysctls
var jsonData map[string]interface{}
jsonFile, err := os.ReadFile(tmpfile.Name())
assert.NoError(t, err)

err = json.Unmarshal(jsonFile, &jsonData)
assert.NoError(t, err)

plugins, _ := jsonData["plugins"].([]interface{})
// Find the tuning plugin (should be last)
lastPlugin := plugins[len(plugins)-1].(map[string]interface{})
assert.Equal(t, "tuning", lastPlugin["type"])

sysctls := lastPlugin["sysctl"].(map[string]interface{})
// Custom sysctl
assert.Equal(t, "1024", sysctls["net.core.somaxconn"])
// IPv6 disable sysctls
assert.Equal(t, "1", sysctls["net.ipv6.conf.all.disable_ipv6"])
assert.Equal(t, "1", sysctls["net.ipv6.conf.default.disable_ipv6"])
assert.Equal(t, "1", sysctls["net.ipv6.conf.lo.disable_ipv6"])
}

// Validate that invalid JSON in TUNING_SYSCTLS returns an error
func TestGenerateJSONWithInvalidTuningSysctls(t *testing.T) {
_ = os.Setenv(envTuningSysctls, `{invalid json}`)
defer os.Unsetenv(envTuningSysctls)
err := generateJSON(awsConflist, devNull, getPrimaryIPMock)
assert.Error(t, err)
}

// Validate setting environment POD_MTU/AWS_VPC_ENI_MTU, takes effect for egress-cni plugin
func TestEgressCNIPluginIPv4EgressTakesMTUEnvVar(t *testing.T) {
_ = os.Setenv(envEnIPv4Egress, "true")
Expand Down
Loading