[bug-n1wxwkrtcnds] add pod link-local NUD source
flock PR validation / validate (pull_request) Successful in 1m54s
flock PR validation / validate (pull_request) Successful in 1m54s
Co-Authored-By: Codex (GPT-5) <noreply@openai.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
"github.com/vishvananda/netlink"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// SetupRequest is the netlink setup input for one pod.
|
||||
@@ -37,6 +38,11 @@ type SetupRequest struct {
|
||||
// LL DAD on the host side.
|
||||
var linkLocalGW = net.ParseIP("fe80::1")
|
||||
|
||||
// linkLocalPod is the deterministic pod-side address used for IPv6 neighbor
|
||||
// discovery. Without a link-local source, gateway NUD probes use the pod's
|
||||
// global /128 and the host does not answer them reliably after neighbor expiry.
|
||||
var linkLocalPod = net.ParseIP("fe80::2")
|
||||
|
||||
// v4ProxyGW is the well-known link-local IPv4 used by container CNIs as a
|
||||
// next-hop for proxy-arp gateways (cilium, calico, kindnet — all use this).
|
||||
var v4ProxyGW = net.IPv4(169, 254, 1, 1)
|
||||
@@ -210,6 +216,14 @@ func configurePodSide(req SetupRequest) error {
|
||||
}
|
||||
|
||||
if req.IP6 != nil {
|
||||
// Keep automatic address generation disabled, but give every IPv6 pod
|
||||
// veth a deterministic link-local address. This makes NUD for the
|
||||
// fe80::1 gateway use an on-link source and prevents the default-route
|
||||
// neighbor from aging into FAILED. DAD is unnecessary on a veth pair.
|
||||
if err := netlink.AddrAdd(eth0, podLinkLocalAddr()); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return fmt.Errorf("pod link-local add: %w", err)
|
||||
}
|
||||
|
||||
a := &netlink.Addr{IPNet: &net.IPNet{IP: req.IP6, Mask: net.CIDRMask(128, 128)}}
|
||||
if err := netlink.AddrAdd(eth0, a); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return fmt.Errorf("pod ip6 add: %w", err)
|
||||
@@ -295,6 +309,13 @@ func configurePodSide(req SetupRequest) error {
|
||||
})
|
||||
}
|
||||
|
||||
func podLinkLocalAddr() *netlink.Addr {
|
||||
return &netlink.Addr{
|
||||
IPNet: &net.IPNet{IP: linkLocalPod, Mask: net.CIDRMask(64, 128)},
|
||||
Flags: unix.IFA_F_NODAD,
|
||||
}
|
||||
}
|
||||
|
||||
func setHostRoute(linkIndex int, ip net.IP, prefix int) error {
|
||||
r := &netlink.Route{
|
||||
LinkIndex: linkIndex,
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//go:build linux
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func TestPodLinkLocalAddr(t *testing.T) {
|
||||
addr := podLinkLocalAddr()
|
||||
if got, want := addr.IP.String(), "fe80::2"; got != want {
|
||||
t.Fatalf("pod link-local IP = %s, want %s", got, want)
|
||||
}
|
||||
if ones, bits := addr.Mask.Size(); ones != 64 || bits != 128 {
|
||||
t.Fatalf("pod link-local mask = %d/%d, want 64/128", ones, bits)
|
||||
}
|
||||
if addr.Flags&unix.IFA_F_NODAD == 0 {
|
||||
t.Fatal("pod link-local address must disable DAD")
|
||||
}
|
||||
if addr.IP.Equal(linkLocalGW) {
|
||||
t.Fatal("pod and gateway link-local addresses must differ")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user