Skip to content

Unable To Route to IPv6 Service VIPs from Same Node #1698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
aauren opened this issue Jul 5, 2024 · 0 comments · Fixed by #1700
Closed

Unable To Route to IPv6 Service VIPs from Same Node #1698

aauren opened this issue Jul 5, 2024 · 0 comments · Fixed by #1700
Labels

Comments

@aauren
Copy link
Collaborator

aauren commented Jul 5, 2024

What happened?

When the traffic is originating from the same host that carries a copy of the IPv6 service VIP on one of its interfaces, kube-router is not able to successfully get a response.

This does not happen with IPv4 and appears to only affect IPv6 service VIPs.

What did you expect to happen?

kube-router service VIPs should always be available and testable from the host OS regardless of whether or not the IP address exists on that node or not. This assists in troubleshooting and has long been the case for IPv4 addresses.

How can we reproduce the behavior you experienced?

Steps to reproduce the behavior:

  1. Enable IPv6 mode in kube-router (--enable-ipv6=true)
  2. Add an IPv6 service Cluster IP range (--service-cluster-ip-range=2001:db8:42:1::/112)
  3. Create a test service that has DualStack configured that selects some pods:
apiVersion: v1
kind: Service
metadata:
  annotations:
    kube-router.io/service.local: "true"
    purpose: "Creates a VIP for balancing an application"
  labels:
    name: whoami
  name: whoami
  namespace: default
spec:
  ports:
  - name: flask
    port: 5000
    protocol: TCP
    targetPort: 5000
  ipFamilyPolicy: PreferDualStack
  selector:
    name: whoami
  type: ClusterIP

---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: whoami
  namespace: default
spec:
  selector:
    matchLabels:
      name: whoami
  template:
    metadata:
      labels:
        name: whoami
    spec:
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
      tolerations:
      - key: "node-role.kubernetes.io/master"
        operator: "Exists"
        effect: "NoSchedule"
      - key: "node-role.kubernetes.io/control-plane"
        operator: "Exists"
        effect: "NoSchedule"
      containers:
        - name: whoami
          image: "docker.io/containous/whoami"
          imagePullPolicy: Always
          command: ["/whoami"]
          args: ["--port", "5000"]
  1. Attempt to route to the IPv4 Service VIP from on the node and see that it succeeds:
% kubectl get service -n default whoami -o jsonpath='{.spec.clusterIPs[0]}'
10.96.104.78

% curl "http://10.96.104.78:5000"         
Hostname: whoami-ghshw
IP: 127.0.0.1
IP: ::1
IP: 10.242.0.4
IP: 2001:db8:42:1000::4
IP: fe80::29:a2ff:fe53:166
RemoteAddr: 10.95.0.131:43788
GET / HTTP/1.1
Host: 10.96.104.78:5000
User-Agent: curl/7.81.0
Accept: */*
  1. Attempt to route to the IPv6 Service VIP from on the node and see that it fails:
% curl --max-time 2 "http://[2001:db8:42:1::d45a]:5000"
curl: (28) Connection timed out after 2001 milliseconds

System Information (please complete the following information)

  • Kube-Router Version (kube-router --version): v2.1.2 (although it is likely present in all versions of kube-router)
  • Kube-Router Parameters:
--run-router=true --run-firewall=true --run-service-proxy=true --bgp-graceful-restart=true --kubeconfig=/var/lib/kube-router/kubeconfig --peer-router-ips=10.95.0.171 --peer-router-asns=4200000001 --runtime-endpoint=unix:///run/containerd/containerd.sock --cluster-asn=4200000001 --service-cluster-ip-range=10.96.0.0/16 --enable-ipv6=true --service-cluster-ip-range=2001:db8:42:1::/112 --service-external-ip-range=2001:db8:42:1100::/56 --run-loadbalancer=true --advertise-loadbalancer-ip=true --loadbalancer-ip-range=2001:db8:42:1200::/56 --loadbalancer-ip-range=10.243.1.0/24 --service-external-ip-range=10.243.0.0/24 --advertise-external-ip=true -v=1
  • Kubernetes Version (kubectl version) : v1.30.2
  • Cloud Type: aws
  • Kubernetes Deployment Type: kubeadm
  • Kube-Router Deployment Type: DaemonSet
  • Cluster Size: 3 nodes

Additional context

When kube-router adds Service VIP addresses to the kube-dummy-if interface it has always added an extra local route which mutates the traffic to look like it comes from the primary node IP address: https://github.com/cloudnativelabs/kube-router/blob/master/pkg/controllers/proxy/linux_networking.go#L170-L178

Like the comment there says, this keeps Linux routing from trying to emit the source traffic for local traffic routing patterns from the VIP itself, which won't ever route back to the originating process.

There appears to be a difference in the way that iproute2 adds IPv4 and IPv6 addresses. When it creates IPv4 addresses we see the following output:

% ip route show table all | grep $(kubectl get service -n default whoami -o jsonpath='{.spec.clusterIPs[0]}')
local 10.96.104.78 dev kube-dummy-if table local proto kernel scope host src 10.95.0.131

This represents only the route that kube-router adds and nothing else.

However, if we look at an IPv6 address we see the following:

 ip -6 route show table all | grep $(kubectl get service -n default whoami -o jsonpath='{.spec.clusterIPs[1]}')
2001:db8:42:1::d45a dev kube-dummy-if proto kernel metric 256 pref medium
local 2001:db8:42:1::d45a dev kube-dummy-if table local proto kernel metric 0 pref medium
local 2001:db8:42:1::d45a dev kube-dummy-if table local proto kernel src 2600:1f18:5302:3d00:d710:3df9:102b:67d7 metric 1024 pref medium

Only the last route is our route, and the first 2 routes seem to be added by iproute2 itself for some reason. If these two routes are removed, then the traffic flows as it should:

% sudo ip -6 route del 2001:db8:42:1::d45a dev kube-dummy-if proto kernel metric 256 pref medium

% curl --max-time 2 "http://[2001:db8:42:1::d45a]:5000"                                         
curl: (28) Connection timed out after 2000 milliseconds

% sudo ip -6 route del local 2001:db8:42:1::d45a dev kube-dummy-if table local proto kernel metric 0 pref medium

% curl --max-time 2 "http://[2001:db8:42:1::d45a]:5000"                                                         
Hostname: whoami-ghshw
IP: 127.0.0.1
IP: ::1
IP: 10.242.0.4
IP: 2001:db8:42:1000::4
IP: fe80::29:a2ff:fe53:166
RemoteAddr: [2600:1f18:5302:3d00:d710:3df9:102b:67d7]:48476
GET / HTTP/1.1
Host: [2001:db8:42:1::d45a]:5000
User-Agent: curl/7.81.0
Accept: */*
@aauren aauren added the bug label Jul 5, 2024
aauren added a commit that referenced this issue Jul 5, 2024
Remove extra routes added by iproute2 when addresses are added to
interfaces which block IPv6 service VIPs from routing from the host.

See: #1698
aauren added a commit that referenced this issue Jul 5, 2024
Remove extra routes added by iproute2 when addresses are added to
interfaces which block IPv6 service VIPs from routing from the host.

See: #1698
aauren added a commit that referenced this issue Jul 5, 2024
Remove extra routes added by iproute2 when addresses are added to
interfaces which block IPv6 service VIPs from routing from the host.

See: #1698
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant