Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
06272cb
add release-note for warmup aggression change (#58339)
zirain Nov 20, 2025
ef7f23f
Prevent route resource status conflict in multi-revision installs (#5…
lcopi Nov 20, 2025
0d3127e
tests: add integration tests for BackendTLSPolicy applied to ServiceE…
jewertow Nov 20, 2025
36ead83
Automator: update proxy@master in istio/istio@master (#58358)
istio-testing Nov 21, 2025
148ac5f
Automator: update istio/client-go@master dependency in istio/istio@ma…
istio-testing Nov 21, 2025
6834b28
xds: fix cache key for cluster (#58368)
howardjohn Nov 21, 2025
e8f5a9d
bump go-control-plane (#58370)
zirain Nov 21, 2025
2e6a915
fix unerasonable variable setting (#58371)
my-git9 Nov 21, 2025
d3cb3af
Automator: update proxy@master in istio/istio@master (#58375)
istio-testing Nov 21, 2025
f2fd76a
Automator: update ztunnel@master in istio/istio@master (#58378)
istio-testing Nov 22, 2025
a694f72
Automator: update proxy@master in istio/istio@master (#58380)
istio-testing Nov 22, 2025
2abdd2f
Automator: update proxy@master in istio/istio@master (#58382)
istio-testing Nov 23, 2025
b2f713a
Automator: update proxy@master in istio/istio@master (#58383)
istio-testing Nov 23, 2025
dadf621
Gateway supports custom cipher suites (#58381)
fraenkel Nov 24, 2025
03c8892
Add timeout and headers support to Zipkin tracing provider (#58307)
prashanthjos Nov 24, 2025
3463a6d
Automator: update proxy@master in istio/istio@master (#58386)
istio-testing Nov 24, 2025
1ad6422
Fix kubelet detection on MicroK8s with nftables backend (#58314)
sridhargaddam Nov 24, 2025
42c2c72
Support multiple targetPorts on an InferencePool (#58238)
dgn Nov 25, 2025
e2903b1
tests: add more unit tests for InferencePools with >1 targetPort (#58…
dgn Nov 25, 2025
0ed2882
Fix racy test (#58377)
keithmattix Nov 25, 2025
ecedf8a
refactor: replace context.WithCancel with t.Context (#58391)
vicerace Nov 25, 2025
85ee6b6
tests: properly split yaml docs (#58405)
howardjohn Nov 26, 2025
960f60c
telemetry: add support for Formatter custom tag (#58372)
zirain Nov 26, 2025
4822be3
cni repair: improve the time to find the proc (#58404)
fraenkel Nov 26, 2025
bbfa566
Automator: update proxy@master in istio/istio@master (#58413)
istio-testing Nov 26, 2025
96b385a
Automator: update proxy@master in istio/istio@master (#58422)
istio-testing Nov 26, 2025
4c126b0
filter failed pods to prevent Istiod from OOMKills (#58250)
ramaraochavali Nov 26, 2025
63f6c9f
Gateway API - Replace v1beta1 for v1 (#58110)
rikatz Nov 26, 2025
2cb6b77
rename NewInformerFiltered to NewFilteredInformer (#58385)
ramaraochavali Nov 27, 2025
9d6ad68
timeout in zipkin is optional (#58406)
zirain Nov 27, 2025
fc7dec2
istioctl waypoint status: support specify whether to wait for waypoin…
my-git9 Nov 27, 2025
90b77e3
xlistenerset: fix namespace selector (#58360)
howardjohn Nov 27, 2025
7e3a76e
Propagate trust domain to e/w gateway (#58428)
keithmattix Nov 27, 2025
3b6a0e6
istioctl: support show all namespaces waypoint status (#58394)
my-git9 Nov 27, 2025
4318ea6
Automator: update proxy@master in istio/istio@master (#58437)
istio-testing Nov 28, 2025
0109480
Automator: update proxy@master in istio/istio@master (#58439)
istio-testing Nov 30, 2025
6de93e6
Automator: update istio/client-go@master dependency in istio/istio@ma…
istio-testing Nov 30, 2025
7052269
Automator: update proxy@master in istio/istio@master (#58446)
istio-testing Dec 1, 2025
d064568
Add istiod_remote_cluster_sync_status metric (#58384)
martinbaillie Dec 1, 2025
df91d3c
Adapt TestInferencePoolMultipleTargetPorts test to Openshift (#58448)
MaxBab Dec 1, 2025
783e855
nds: fix missing IP addresses in headless nametable entries when pods…
leosarra Dec 1, 2025
417b458
`istioctl`: Display proxy cert serial numbers with trailing zeros (#5…
aleks-andr Dec 1, 2025
943fea8
add indication for the requests count (#58454)
LiorLieberman Dec 1, 2025
cda5289
addons: Bump addons version (#58443)
my-git9 Dec 2, 2025
d16be7b
Automator: update proxy@master in istio/istio@master (#58458)
istio-testing Dec 2, 2025
5245b4c
krt: aggregate Join events for conflicting keys (#58324)
stevenctl Dec 2, 2025
5c8a578
Support safe migration from iptables to nftables in Ambient (#58354)
sridhargaddam Dec 3, 2025
f4a9fd1
fix proxy version check for built-in formatters (#58469)
ramaraochavali Dec 3, 2025
9aed894
improve the istioctl waypoint status describe and example (#58482)
my-git9 Dec 4, 2025
da480ff
Automator: update common-files@master in istio/istio@master (#58495)
istio-testing Dec 4, 2025
e8b2548
Fix ambient multi-cluster integration tests (#58466)
krinkinmu Dec 4, 2025
2ece87e
pilot: watch meshConfig in remote clusters (#58455)
jewertow Dec 4, 2025
ba29528
Automator: update ztunnel@master in istio/istio@master (#58480)
istio-testing Dec 5, 2025
277f6ec
update min k8s version (#58485)
hanxiaop Dec 5, 2025
1441efa
chore: make gofumpt didn't change fiter_types.gen (#58513)
zirain Dec 6, 2025
bb1b3c2
cache default retry policy (#58515)
ramaraochavali Dec 6, 2025
878795a
optimize configmeta generation (#58521)
ramaraochavali Dec 8, 2025
19ba6ec
charts/gateway: allow "enabled" field in the schema (#58278)
tomasz-sodzawiczny Dec 8, 2025
4fd833c
multi-network: HBONE matching prefers hostname over VIP (#58512)
stevenctl Dec 8, 2025
a65889d
fix goroutine leaks in ambient index DelayedInformers. (#58479)
PetrMc Dec 8, 2025
84f506a
samples: add a demo for SPIRE and trust domain federation (#58462)
jewertow Dec 9, 2025
2efb699
codegen kebab case conversion (#58529)
ramaraochavali Dec 9, 2025
2f793fd
waypoint interop: specify Equals when waypointed services change (#58…
stevenctl Dec 10, 2025
d4ef8b2
Automator: update istio/client-go@master dependency in istio/istio@ma…
istio-testing Dec 10, 2025
ad5cc84
Automator: merge upstream changes to openshift-service-mesh/istio@master
Dec 11, 2025
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
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "istio build-tools",
"image": "gcr.io/istio-testing/build-tools:master-8dcf63149d5bdaa83d1407a121098e8e8d1626dd",
"image": "gcr.io/istio-testing/build-tools:master-3858f8db549f6f7f73de4b55fba5075f71d2651d",
"privileged": true,
"remoteEnv": {
"USE_GKE_GCLOUD_AUTH_PLUGIN": "True",
Expand Down
3 changes: 1 addition & 2 deletions cni/pkg/install/cniconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,7 @@ func TestGetCNIConfigFilepath(t *testing.T) {

// Handle chained CNI plugin cases
// Call with goroutine to test fsnotify watcher
parent, cancel := context.WithCancel(context.Background())
defer cancel()
parent := t.Context()
resultChan, errChan := make(chan string, 1), make(chan error, 1)
go func(resultChan chan string, errChan chan error, ctx context.Context, cniConfName, mountedCNINetDir string, chained bool) {
result, err := getCNIConfigFilepath(ctx, cniConfName, mountedCNINetDir, chained)
Expand Down
3 changes: 1 addition & 2 deletions cni/pkg/install/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@ func TestSleepCheckInstall(t *testing.T) {
tempDir := t.TempDir()

// Initialize parameters
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()

if c.istioOwnedCNIConfig && len(c.istioOwnedCNIConfigFilename) == 0 {
c.istioOwnedCNIConfigFilename = "02-istio-conf.conflist"
Expand Down
63 changes: 37 additions & 26 deletions cni/pkg/nftables/kubeletuid_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import (
"github.com/prometheus/procfs"
)

// getKubeletUIDFromPath finds the kubelet process UID by inspecting the proc filesystem path.
// getKubeletUIDFromPath finds the kubelet or kubelite process UID by inspecting the proc filesystem path.
// In standard Kubernetes distributions, it looks for the "kubelet" process.
// On some platforms like MicroK8s, where multiple k8s components are consolidated, it looks for the "kubelite" process.
func getKubeletUIDFromPath(procPath string) (string, error) {
fs, err := procfs.NewFS(procPath)
if err != nil {
Expand All @@ -34,44 +36,53 @@ func getKubeletUIDFromPath(procPath string) (string, error) {
return "", fmt.Errorf("failed to read processes from %s: %v", procPath, err)
}

// Find kubelet process
// List of process names to search for, in order of preference
processNames := []string{"kubelet", "kubelite"}

for _, proc := range procs {
comm, err := proc.Comm()
if err != nil {
// Process might have exited, skip
continue
}

if comm == "kubelet" {
// Lets check the command line to ensure it's really kubelet
cmdline, err := proc.CmdLine()
if err != nil {
continue
}
for _, targetName := range processNames {
if comm == targetName {
// Lets check the command line to ensure it's really the target process
cmdline, err := proc.CmdLine()
if err != nil {
continue
}

kubeletFound := false
for _, arg := range cmdline {
if strings.Contains(strings.ToLower(arg), "kubelet") {
kubeletFound = true
break
// Verify that this process is actually related to kubelet by checking
// if "kubelet" appears in any of the command line arguments.
// This works for both:
// - Standard kubelet: /usr/bin/kubelet [args...]
// - MicroK8s kubelite: /snap/microk8s/.../kubelite --kubelet-args-file=...
processFound := false
for _, arg := range cmdline {
if strings.Contains(strings.ToLower(arg), "kubelet") {
processFound = true
break
}
}
if !processFound {
continue
}
}
if !kubeletFound {
continue
}

// Get process status with UIDs
status, err := proc.NewStatus()
if err != nil {
continue
}
// Get process status with UIDs
status, err := proc.NewStatus()
if err != nil {
continue
}

realUID := status.UIDs[0]
realUIDStr := strconv.FormatUint(realUID, 10)
realUID := status.UIDs[0]
realUIDStr := strconv.FormatUint(realUID, 10)

return realUIDStr, nil
return realUIDStr, nil
}
}
}

return "", fmt.Errorf("kubelet process not found in %s", procPath)
return "", fmt.Errorf("kubelet or kubelite process not found in %s", procPath)
}
2 changes: 1 addition & 1 deletion cni/pkg/nftables/nftables.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ func (cfg *NftablesConfigurator) CreateHostRulesForHealthChecks() error {
//
// Challenge: In nftables, there is no direct equivalent to "--socket-exists", so we explored multiple alternatives
// - Option-1 (UID-based matching): Since kubelet runs as a specific process with a known UID, we can use
// meta skuid to identify traffic originating from kubelet.
// meta skuid to identify traffic originating from kubelet (or kubelite in MicroK8s).
//
// - Option-2: Match on kubelet’s source IP (node IP). This works in theory but is a bit unsafe as
// other host processes can also send traffic from the node IP, and nodes can have multiple IPs making the
Expand Down
102 changes: 102 additions & 0 deletions cni/pkg/nodeagent/detect_artifacts_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package nodeagent

import (
"fmt"
"strings"

"github.com/vishvananda/netlink"

"istio.io/istio/cni/pkg/config"
"istio.io/istio/cni/pkg/ipset"
"istio.io/istio/cni/pkg/util"
)

// detectIptablesArtifacts checks for the presence of Istio iptables artifacts (specifically IPsets)
// on the host network to determine if a previous iptables-based deployment exists.
// Returns:
// - true if iptables artifacts (IPsets) are detected
// - false if no artifacts are detected or if detection fails
// - error if there was a failure during detection
func detectIptablesArtifacts(enableIPv6 bool) (bool, error) {
var detected bool
var detectionErr error

// Run the detection in the host network namespace
err := util.RunAsHost(func() error {
// Check if the IPv4 IPset exists
v4Name := fmt.Sprintf(ipset.V4Name, config.ProbeIPSet)
v4Exists, err := ipsetExists(v4Name)
if err != nil {
log.Debugf("failed to check for v4 IPset %s: %v", v4Name, err)
detectionErr = fmt.Errorf("v4 IPset detection failed: %w", err)
// Lets continue checking for v6 (if enabled)
}

if v4Exists {
log.Infof("detected iptables artifact: IPset %s exists", v4Name)
detected = true
// Found v4 artifact, no need to check for v6
return nil
}

// Check if the IPv6 IPset exists
if enableIPv6 {
v6Name := fmt.Sprintf(ipset.V6Name, config.ProbeIPSet)
v6Exists, err := ipsetExists(v6Name)
if err != nil {
log.Debugf("failed to check for v6 IPset %s: %v", v6Name, err)
if detectionErr != nil {
detectionErr = fmt.Errorf("%w; v6 IPset detection failed: %w", detectionErr, err)
} else {
detectionErr = fmt.Errorf("v6 IPset detection failed: %w", err)
}
}

if v6Exists {
log.Infof("detected iptables artifact: IPset %s exists", v6Name)
detected = true
}
}

return nil
})
if err != nil {
return false, fmt.Errorf("failed to run detection in host namespace: %w", err)
}

return detected, detectionErr
}

// ipsetExists checks if an IPset with the given name exists on the host.
// Returns:
// - true, nil if the IPset exists
// - false, nil if the IPset does not exist (expected for clean/fresh setup)
// - false, error for any errors
func ipsetExists(name string) (bool, error) {
_, err := netlink.IpsetList(name)
if err == nil {
// IPset exists
return true, nil
}

if strings.Contains(err.Error(), "no such file") {
// IPSet does not exist
return false, nil
}

return false, err
}
154 changes: 154 additions & 0 deletions cni/pkg/nodeagent/detect_artifacts_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package nodeagent

import (
"fmt"
"strings"
"sync"
"testing"

// Create a new network namespace. This will have the 'lo' interface ready but nothing else.
_ "github.com/howardjohn/unshare-go/netns"
// Create a new user namespace. This will map the current UID/GID to 0.
"github.com/howardjohn/unshare-go/userns"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"

"istio.io/istio/cni/pkg/config"
"istio.io/istio/cni/pkg/ipset"
"istio.io/istio/pkg/test/util/assert"
)

// TestDetectIptablesArtifacts is an e2e test that validates the iptable artifacts on the network.
// It runs in an isolated network namespace created by unshare-go, which provides a clean environment
// with root-like capabilities for netlink operations. It validates the upgrade path from iptables to
// nftables backend by simulating various scenarios.
func TestDetectIptablesArtifacts(t *testing.T) {
setup(t)

tests := []struct {
name string
enableIPv6 bool
setupFunc func(t *testing.T)
cleanupFunc func(t *testing.T)
expectedDetected bool
description string
}{
{
name: "v4_ipset_exists",
enableIPv6: false,
setupFunc: func(t *testing.T) {
v4Name := fmt.Sprintf(ipset.V4Name, config.ProbeIPSet)
err := netlink.IpsetCreate(v4Name, "hash:ip", netlink.IpsetCreateOptions{Replace: true})
if err != nil && !strings.Contains(err.Error(), "exist") {
t.Fatalf("failed to create v4 ipset: %v", err)
}
t.Logf("Created v4 IPset: %s", v4Name)
},
cleanupFunc: func(t *testing.T) {
v4Name := fmt.Sprintf(ipset.V4Name, config.ProbeIPSet)
_ = netlink.IpsetDestroy(v4Name)
},
expectedDetected: true,
description: "Should detect when v4 IPset exists (simulates an existing iptables deployment)",
},
{
name: "v6_ipset_exists",
enableIPv6: true,
setupFunc: func(t *testing.T) {
v6Name := fmt.Sprintf(ipset.V6Name, config.ProbeIPSet)
err := netlink.IpsetCreate(v6Name, "hash:ip", netlink.IpsetCreateOptions{
Family: unix.AF_INET6,
Replace: true,
})
if err != nil && !strings.Contains(err.Error(), "exist") {
t.Fatalf("failed to create v6 ipset: %v", err)
}
t.Logf("Created v6 IPset: %s", v6Name)
},
cleanupFunc: func(t *testing.T) {
v6Name := fmt.Sprintf(ipset.V6Name, config.ProbeIPSet)
_ = netlink.IpsetDestroy(v6Name)
},
expectedDetected: true,
description: "Should detect when v6 IPset exists",
},
{
name: "both_v4_and_v6_ipsets_exist",
enableIPv6: true,
setupFunc: func(t *testing.T) {
v4Name := fmt.Sprintf(ipset.V4Name, config.ProbeIPSet)
v6Name := fmt.Sprintf(ipset.V6Name, config.ProbeIPSet)

err := netlink.IpsetCreate(v4Name, "hash:ip", netlink.IpsetCreateOptions{Replace: true})
if err != nil && !strings.Contains(err.Error(), "exist") {
t.Fatalf("failed to create v4 ipset: %v", err)
}

err = netlink.IpsetCreate(v6Name, "hash:ip", netlink.IpsetCreateOptions{
Family: unix.AF_INET6,
Replace: true,
})
if err != nil && !strings.Contains(err.Error(), "exist") {
t.Fatalf("failed to create v6 ipset: %v", err)
}
t.Logf("Created both v4 and v6 IPsets")
},
cleanupFunc: func(t *testing.T) {
v4Name := fmt.Sprintf(ipset.V4Name, config.ProbeIPSet)
v6Name := fmt.Sprintf(ipset.V6Name, config.ProbeIPSet)
_ = netlink.IpsetDestroy(v4Name)
_ = netlink.IpsetDestroy(v6Name)
},
expectedDetected: true,
description: "Should detect when both v4 and v6 IPsets exist",
},
{
name: "no_ipsets_exist",
enableIPv6: true,
setupFunc: func(t *testing.T) {},
cleanupFunc: func(t *testing.T) {},
expectedDetected: false,
description: "Should not detect artifacts in clean state (simulates a fresh setup)",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Log(tt.description)

tt.setupFunc(t)
defer tt.cleanupFunc(t)

detected, _ := detectIptablesArtifacts(tt.enableIPv6)
assert.Equal(t, detected, tt.expectedDetected)
})
}
}

var initialized = &sync.Once{}

// setup initializes the test environment using unshare-go.
// Importing "github.com/howardjohn/unshare-go/netns" causes the test to run in an isolated network
// namespace and userns provides user namespace mapping.
func setup(t *testing.T) {
initialized.Do(func() {
// Map current GID to root (0) in the user namespace
// This gives us the necessary privileges for netlink operations (CAP_NET_ADMIN)
assert.NoError(t, userns.WriteGroupMap(map[uint32]uint32{userns.OriginalGID(): 0}))
t.Log("Successfully initialized an isolated test network namespace with root capabilities")
})
}
Loading