diff --git a/pkg/daemon/ovs_linux.go b/pkg/daemon/ovs_linux.go index a4eab057b92..e7f919308bc 100644 --- a/pkg/daemon/ovs_linux.go +++ b/pkg/daemon/ovs_linux.go @@ -259,11 +259,11 @@ func configureContainerNic(nicName, ifName, ipAddr, gateway string, isDefaultRou if err = configureAdditionalNic(ifName, ipAddr); err != nil { return err } - if err = configureNic(nicName, ipAddr, macAddr, mtu, detectIPConflict, false); err != nil { + if err = configureNic(nicName, ipAddr, macAddr, mtu, detectIPConflict, false, false); err != nil { return err } } else { - if err = configureNic(ifName, ipAddr, macAddr, mtu, detectIPConflict, true); err != nil { + if err = configureNic(ifName, ipAddr, macAddr, mtu, detectIPConflict, true, false); err != nil { return err } } @@ -417,7 +417,7 @@ func configureNodeNic(portName, ip, gw, joinCIDR string, macAddr net.HardwareAdd return errors.New(raw) } - if err = configureNic(util.NodeNic, ip, macAddr, mtu, false, false); err != nil { + if err = configureNic(util.NodeNic, ip, macAddr, mtu, false, false, true); err != nil { return err } @@ -598,7 +598,7 @@ func configureNodeGwNic(portName, ip, gw string, macAddr net.HardwareAddr, mtu i klog.V(3).Infof("node external nic %q already in ns %s", util.NodeGwNic, util.NodeGwNsPath) } return ns.WithNetNSPath(gwNS.Path(), func(_ ns.NetNS) error { - if err = configureNic(util.NodeGwNic, ip, macAddr, mtu, true, false); err != nil { + if err = configureNic(util.NodeGwNic, ip, macAddr, mtu, true, false, false); err != nil { klog.Errorf("failed to congigure node gw nic %s, %v", util.NodeGwNic, err) return err } @@ -835,7 +835,30 @@ func configureMirrorLink(portName string, _ int) error { return nil } -func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int, detectIPConflict, setUfoOff bool) error { +// Convert MAC address to EUI-64 and generate link-local IPv6 address +func macToLinkLocalIPv6(mac net.HardwareAddr) (net.IP, error) { + if len(mac) != 6 { + return nil, fmt.Errorf("invalid MAC address length") + } + + // Create EUI-64 format + eui64 := make([]byte, 8) + copy(eui64[0:3], mac[0:3]) // Copy the first 3 bytes + eui64[3] = 0xff // Insert ff + eui64[4] = 0xfe // Insert fe + copy(eui64[5:], mac[3:]) // Copy the last 3 bytes + + // Flip the 7th bit of the first byte + eui64[0] ^= 0x02 + + // Prepend the link-local prefix + linkLocalIPv6 := net.IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + copy(linkLocalIPv6[8:], eui64) + + return linkLocalIPv6, nil +} + +func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int, detectIPConflict, setUfoOff, ipv6LinkLocalOn bool) error { nodeLink, err := netlink.LinkByName(link) if err != nil { return fmt.Errorf("can not find nic %s: %v", link, err) @@ -868,14 +891,32 @@ func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int, detectIPCo if err != nil { return fmt.Errorf("can not get addr %s: %v", nodeLink, err) } + + isIPv6LinkLocalExist := false for _, ipAddr := range ipAddrs { if ipAddr.IP.IsLinkLocalUnicast() { // skip 169.254.0.0/16 and fe80::/10 + if util.CheckProtocol(ipAddr.IP.String()) == kubeovnv1.ProtocolIPv6 { + isIPv6LinkLocalExist = true + } continue } ipDelMap[ipAddr.IPNet.String()] = ipAddr } + if ipv6LinkLocalOn && !isIPv6LinkLocalExist { + linkLocal, err := macToLinkLocalIPv6(macAddr) + if err != nil { + return fmt.Errorf("failed to generate link-local address: %v", err) + } + ipAddMap[linkLocal.String()] = netlink.Addr{ + IPNet: &net.IPNet{ + IP: linkLocal, + Mask: net.CIDRMask(64, 128), + }, + } + } + for _, ipStr := range strings.Split(ip, ",") { // Do not reassign same address for link if _, ok := ipDelMap[ipStr]; ok { @@ -896,6 +937,7 @@ func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int, detectIPCo return fmt.Errorf("delete address %s: %v", addr, err) } } + for ip, addr := range ipAddMap { if detectIPConflict && addr.IP.To4() != nil { ip := addr.IP.String()