Skip to content

Commit 6f4100d

Browse files
authored
cni-server: check ipv6 dadfailed flag (#5042)
Signed-off-by: zhangzujian <zhangzujian.7@gmail.com>
1 parent b1c5f25 commit 6f4100d

File tree

5 files changed

+104
-54
lines changed

5 files changed

+104
-54
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ kind-network-create-underlay:
379379
$(eval UNDERLAY_NETWORK_ID = $(shell docker network ls -f name='^kind-underlay$$' --format '{{.ID}}'))
380380
@if [ -z "$(UNDERLAY_NETWORK_ID)" ]; then \
381381
docker network create --attachable -d bridge \
382-
--ipv6 --subnet fc00:adb1:b29b:608d::/64 --gateway fc00:adb1:b29b:608d::1 \
382+
--ipv6 --subnet fc00:19fa:9eea:6085::/64 --gateway fc00:19fa:9eea:6085::1 \
383383
-o com.docker.network.bridge.enable_ip_masquerade=true \
384384
-o com.docker.network.driver.mtu=1500 kind-underlay; \
385385
fi

pkg/daemon/handler.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ func (csh cniServerHandler) handleAdd(req *restful.Request, resp *restful.Respon
249249
u2oInterconnectionIP = podSubnet.Status.U2OInterconnectionIP
250250
}
251251

252+
var vmMigration bool
252253
subnetHasVlan := podSubnet.Spec.Vlan != ""
253-
detectIPConflict := csh.Config.EnableArpDetectIPConflict && subnetHasVlan
254254
// skip ping check gateway for pods during live migration
255255
if pod.Annotations[util.MigrationJobAnnotation] == "" {
256256
if subnetHasVlan && !podSubnet.Spec.LogicalGateway {
@@ -267,8 +267,7 @@ func (csh cniServerHandler) handleAdd(req *restful.Request, resp *restful.Respon
267267
}
268268
}
269269
} else {
270-
// do not perform ipv4 conflict detection during VM live migration
271-
detectIPConflict = false
270+
vmMigration = true
272271
}
273272
if pod.Annotations[fmt.Sprintf(util.ActivationStrategyTemplate, podRequest.Provider)] != "" {
274273
gatewayCheckMode = gatewayCheckModeDisabled
@@ -308,12 +307,12 @@ func (csh cniServerHandler) handleAdd(req *restful.Request, resp *restful.Respon
308307
podNicName = ifName
309308
switch nicType {
310309
case util.InternalType:
311-
podNicName, routes, err = csh.configureNicWithInternalPort(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, detectIPConflict, routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, podRequest.DeviceID, nicType, latency, limit, loss, jitter, gatewayCheckMode, u2oInterconnectionIP)
310+
podNicName, routes, err = csh.configureNicWithInternalPort(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, vmMigration, routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, podRequest.DeviceID, nicType, latency, limit, loss, jitter, gatewayCheckMode, u2oInterconnectionIP)
312311
case util.DpdkType:
313312
err = csh.configureDpdkNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, ingress, egress, getShortSharedDir(pod.UID, podRequest.VhostUserSocketVolumeName), podRequest.VhostUserSocketName, podRequest.VhostUserSocketConsumption)
314313
routes = nil
315314
default:
316-
routes, err = csh.configureNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, podRequest.VfDriver, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, detectIPConflict, routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, podRequest.DeviceID, nicType, latency, limit, loss, jitter, gatewayCheckMode, u2oInterconnectionIP, oldPodName)
315+
routes, err = csh.configureNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, podRequest.VfDriver, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, vmMigration, routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, podRequest.DeviceID, nicType, latency, limit, loss, jitter, gatewayCheckMode, u2oInterconnectionIP, oldPodName)
317316
}
318317
if err != nil {
319318
errMsg := fmt.Errorf("configure nic %s for pod %s/%s failed: %w", ifName, podRequest.PodName, podRequest.PodNamespace, err)

pkg/daemon/ovs_linux.go

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (csh cniServerHandler) configureDpdkNic(podName, podNamespace, provider, ne
6868
return ovs.SetInterfaceBandwidth(podName, podNamespace, ifaceID, egress, ingress)
6969
}
7070

71-
func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, containerID, vfDriver, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute, detectIPConflict bool, routes []request.Route, _, _ []string, ingress, egress, deviceID, nicType, latency, limit, loss, jitter string, gwCheckMode int, u2oInterconnectionIP, oldPodName string) ([]request.Route, error) {
71+
func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, containerID, vfDriver, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute, vmMigration bool, routes []request.Route, _, _ []string, ingress, egress, deviceID, nicType, latency, limit, loss, jitter string, gwCheckMode int, u2oInterconnectionIP, oldPodName string) ([]request.Route, error) {
7272
var err error
7373
var hostNicName, containerNicName, pfPci string
7474
var vfID int
@@ -197,7 +197,7 @@ func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns,
197197
klog.Error(err)
198198
return nil, err
199199
}
200-
finalRoutes, err := csh.configureContainerNic(podName, podNamespace, containerNicName, ifName, ip, gateway, isDefaultRoute, detectIPConflict, routes, macAddr, podNS, mtu, nicType, gwCheckMode, u2oInterconnectionIP)
200+
finalRoutes, err := csh.configureContainerNic(podName, podNamespace, containerNicName, ifName, ip, gateway, isDefaultRoute, vmMigration, routes, macAddr, podNS, mtu, nicType, gwCheckMode, u2oInterconnectionIP)
201201
if err != nil {
202202
klog.Error(err)
203203
return nil, err
@@ -380,7 +380,7 @@ func configureHostNic(nicName string) error {
380380
return nil
381381
}
382382

383-
func (csh cniServerHandler) configureContainerNic(podName, podNamespace, nicName, ifName, ipAddr, gateway string, isDefaultRoute, detectIPConflict bool, routes []request.Route, macAddr net.HardwareAddr, netns ns.NetNS, mtu int, nicType string, gwCheckMode int, u2oInterconnectionIP string) ([]request.Route, error) {
383+
func (csh cniServerHandler) configureContainerNic(podName, podNamespace, nicName, ifName, ipAddr, gateway string, isDefaultRoute, vmMigration bool, routes []request.Route, macAddr net.HardwareAddr, netns ns.NetNS, mtu int, nicType string, gwCheckMode int, u2oInterconnectionIP string) ([]request.Route, error) {
384384
containerLink, err := netlink.LinkByName(nicName)
385385
if err != nil {
386386
return nil, fmt.Errorf("can not find container nic %s: %w", nicName, err)
@@ -397,9 +397,14 @@ func (csh cniServerHandler) configureContainerNic(podName, podNamespace, nicName
397397
return nil, fmt.Errorf("failed to move link to netns: %w", err)
398398
}
399399

400+
// do not perform ipv4/ipv6 duplicate address detection during VM live migration
401+
checkIPv6DAD := !vmMigration
402+
detectIPv4Conflict := !vmMigration && csh.Config.EnableArpDetectIPConflict
400403
var finalRoutes []request.Route
401404
err = ns.WithNetNSPath(netns.Path(), func(_ ns.NetNS) error {
405+
interfaceName := nicName
402406
if nicType != util.InternalType {
407+
interfaceName = ifName
403408
if err = netlink.LinkSetName(containerLink, ifName); err != nil {
404409
klog.Error(err)
405410
return err
@@ -415,12 +420,12 @@ func (csh cniServerHandler) configureContainerNic(podName, podNamespace, nicName
415420
klog.Error(err)
416421
return err
417422
}
418-
if err = configureNic(nicName, ipAddr, macAddr, mtu, detectIPConflict, false, false); err != nil {
423+
if err = configureNic(nicName, ipAddr, macAddr, mtu, detectIPv4Conflict, false, false); err != nil {
419424
klog.Error(err)
420425
return err
421426
}
422427
} else {
423-
if err = configureNic(ifName, ipAddr, macAddr, mtu, detectIPConflict, true, false); err != nil {
428+
if err = configureNic(ifName, ipAddr, macAddr, mtu, detectIPv4Conflict, true, false); err != nil {
424429
klog.Error(err)
425430
return err
426431
}
@@ -501,22 +506,35 @@ func (csh cniServerHandler) configureContainerNic(podName, podNamespace, nicName
501506
}
502507

503508
if gwCheckMode != gatewayCheckModeDisabled {
504-
var (
505-
underlayGateway = gwCheckMode == gatewayCheckModeArping || gwCheckMode == gatewayCheckModeArpingNotConcerned
506-
interfaceName = nicName
507-
)
509+
underlayGateway := gwCheckMode == gatewayCheckModeArping || gwCheckMode == gatewayCheckModeArpingNotConcerned
510+
if u2oInterconnectionIP != "" {
511+
if err = csh.checkGatewayReady(podName, podNamespace, gwCheckMode, interfaceName, ipAddr, u2oInterconnectionIP, false, true); err != nil {
512+
klog.Error(err)
513+
return err
514+
}
515+
}
516+
if err = csh.checkGatewayReady(podName, podNamespace, gwCheckMode, interfaceName, ipAddr, gateway, underlayGateway, true); err != nil {
517+
klog.Error(err)
518+
return err
519+
}
520+
}
508521

509-
if nicType != util.InternalType {
510-
interfaceName = ifName
522+
if checkIPv6DAD {
523+
// check whether the ipv6 address has a dadfailed flag
524+
addresses, err := netlink.AddrList(containerLink, netlink.FAMILY_V6)
525+
if err != nil {
526+
err = fmt.Errorf("failed to get ipv6 addresses of link %s: %w", interfaceName, err)
527+
klog.Error(err)
528+
return err
511529
}
512530

513-
if u2oInterconnectionIP != "" {
514-
if err := csh.checkGatewayReady(podName, podNamespace, gwCheckMode, interfaceName, ipAddr, u2oInterconnectionIP, false, true); err != nil {
531+
for _, addr := range addresses {
532+
if addr.Flags&syscall.IFA_F_DADFAILED != 0 {
533+
err = fmt.Errorf("IPv6 address %s has a dadfailed flag, please check whether it has been used by another host", addr.IP.String())
515534
klog.Error(err)
516535
return err
517536
}
518537
}
519-
return csh.checkGatewayReady(podName, podNamespace, gwCheckMode, interfaceName, ipAddr, gateway, underlayGateway, true)
520538
}
521539

522540
return nil
@@ -1122,7 +1140,7 @@ func macToLinkLocalIPv6(mac net.HardwareAddr) (net.IP, error) {
11221140
return linkLocalIPv6, nil
11231141
}
11241142

1125-
func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int, detectIPConflict, setUfoOff, ipv6LinkLocalOn bool) error {
1143+
func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int, detectIPv4Conflict, setUfoOff, ipv6LinkLocalOn bool) error {
11261144
nodeLink, err := netlink.LinkByName(link)
11271145
if err != nil {
11281146
klog.Error(err)
@@ -1207,22 +1225,23 @@ func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int, detectIPCo
12071225
}
12081226
}
12091227
for ip, addr := range ipAddMap {
1210-
if detectIPConflict && addr.IP.To4() != nil {
1211-
ip := addr.IP.String()
1212-
mac, err := util.ArpDetectIPConflict(link, ip, macAddr)
1213-
if err != nil {
1214-
err = fmt.Errorf("failed to detect address conflict for %s on link %s: %w", ip, link, err)
1215-
klog.Error(err)
1216-
return err
1217-
}
1218-
if mac != nil {
1219-
return fmt.Errorf("IP address %s has already been used by host with MAC %s", ip, mac)
1220-
}
1221-
}
1222-
if addr.IP.To4() != nil && !detectIPConflict {
1223-
// when detectIPConflict is true, free arp is already broadcast in the step of announcement
1224-
if err := util.AnnounceArpAddress(link, addr.IP.String(), macAddr, 1, 1*time.Second); err != nil {
1225-
klog.Warningf("failed to broadcast free arp with err %v", err)
1228+
if addr.IP.To4() != nil {
1229+
if detectIPv4Conflict {
1230+
ip := addr.IP.String()
1231+
mac, err := util.ArpDetectIPConflict(link, ip, macAddr)
1232+
if err != nil {
1233+
err = fmt.Errorf("failed to detect address conflict for %s on link %s: %w", ip, link, err)
1234+
klog.Error(err)
1235+
return err
1236+
}
1237+
if mac != nil {
1238+
return fmt.Errorf("IP address %s has already been used by host with MAC %s", ip, mac)
1239+
}
1240+
} else {
1241+
// when detectIPConflict is true, free arp is already broadcast in the step of announcement
1242+
if err := util.AnnounceArpAddress(link, addr.IP.String(), macAddr, 1, 1*time.Second); err != nil {
1243+
klog.Warningf("failed to broadcast free arp with err %v", err)
1244+
}
12261245
}
12271246
}
12281247

pkg/daemon/ovs_windows.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func (csh cniServerHandler) configureNicWithInternalPort(podName, podNamespace,
2929
return ifName, routes, err
3030
}
3131

32-
func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, containerID, vfDriver, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute, detectIPConflict bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, DeviceID, nicType, latency, limit, loss, jitter string, gwCheckMode int, u2oInterconnectionIP, _ string) ([]request.Route, error) {
32+
func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, containerID, vfDriver, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute, vmMigration bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, DeviceID, nicType, latency, limit, loss, jitter string, gwCheckMode int, u2oInterconnectionIP, _ string) ([]request.Route, error) {
3333
if DeviceID != "" {
3434
return nil, errors.New("SR-IOV is not supported on Windows")
3535
}

test/e2e/kube-ovn/underlay/underlay.go

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,11 @@ var _ = framework.SerialDescribe("[group:underlay]", func() {
447447
framework.ExpectEqual(links[0].Mtu, docker.MTU)
448448
})
449449

450-
framework.ConformanceIt("should be able to detect IPv4 address conflict", func() {
451-
if !f.IsIPv4() {
452-
ginkgo.Skip("Address conflict detection only supports IPv4")
450+
framework.ConformanceIt("should be able to detect duplicate address", func() {
451+
f.SkipVersionPriorTo(1, 9, "Duplicate address detection was introduced in v1.9")
452+
if !f.HasIPv4() {
453+
f.SkipVersionPriorTo(1, 14, "Duplicate address detection for IPv6 was introduced in v1.14")
453454
}
454-
f.SkipVersionPriorTo(1, 9, "Address conflict detection was introduced in v1.9")
455455

456456
ginkgo.By("Creating provider network " + providerNetworkName)
457457
pn := makeProviderNetwork(providerNetworkName, false, linkMap)
@@ -463,7 +463,7 @@ var _ = framework.SerialDescribe("[group:underlay]", func() {
463463

464464
containerName := "container-" + framework.RandomSuffix()
465465
ginkgo.By("Creating container " + containerName)
466-
cmd := []string{"sh", "-c", "sleep 600"}
466+
cmd := []string{"sleep", "infinity"}
467467
containerInfo, err := docker.ContainerCreate(containerName, f.KubeOVNImage, dockerNetworkName, cmd)
468468
framework.ExpectNoError(err)
469469
containerID = containerInfo.ID
@@ -473,35 +473,67 @@ var _ = framework.SerialDescribe("[group:underlay]", func() {
473473
_ = vlanClient.Create(vlan)
474474

475475
ginkgo.By("Creating subnet " + subnetName)
476-
cidr := make([]string, 0, 2)
477-
gateway := make([]string, 0, 2)
476+
var cidrV4, cidrV6, gatewayV4, gatewayV6 string
478477
for _, config := range dockerNetwork.IPAM.Config {
479-
if util.CheckProtocol(config.Subnet) == apiv1.ProtocolIPv4 {
480-
cidr = append(cidr, config.Subnet)
481-
gateway = append(gateway, config.Gateway)
482-
break
478+
switch util.CheckProtocol(config.Subnet) {
479+
case apiv1.ProtocolIPv4:
480+
if f.HasIPv4() {
481+
cidrV4 = config.Subnet
482+
gatewayV4 = config.Gateway
483+
}
484+
case apiv1.ProtocolIPv6:
485+
if f.HasIPv6() {
486+
cidrV6 = config.Subnet
487+
gatewayV6 = config.Gateway
488+
}
483489
}
484490
}
491+
cidr := make([]string, 0, 2)
492+
gateway := make([]string, 0, 2)
493+
if f.HasIPv4() {
494+
cidr = append(cidr, cidrV4)
495+
gateway = append(gateway, gatewayV4)
496+
}
497+
if f.HasIPv6() {
498+
cidr = append(cidr, cidrV6)
499+
gateway = append(gateway, gatewayV6)
500+
}
485501
excludeIPs := make([]string, 0, len(network.Containers)*2)
486502
for _, container := range network.Containers {
487-
if container.IPv4Address != "" {
503+
if f.HasIPv4() && container.IPv4Address != "" {
488504
excludeIPs = append(excludeIPs, strings.Split(container.IPv4Address, "/")[0])
489505
}
506+
if f.HasIPv6() && container.IPv6Address != "" {
507+
excludeIPs = append(excludeIPs, strings.Split(container.IPv6Address, "/")[0])
508+
}
490509
}
491510
subnet := framework.MakeSubnet(subnetName, vlanName, strings.Join(cidr, ","), strings.Join(gateway, ","), "", "", excludeIPs, nil, []string{namespaceName})
492511
_ = subnetClient.CreateSync(subnet)
493512

494-
ip := containerInfo.NetworkSettings.Networks[dockerNetworkName].IPAddress
495-
mac := containerInfo.NetworkSettings.Networks[dockerNetworkName].MacAddress
513+
networkInfo := containerInfo.NetworkSettings.Networks[dockerNetworkName]
514+
ips := make([]string, 0, 2)
515+
if f.HasIPv4() {
516+
ips = append(ips, networkInfo.IPAddress)
517+
}
518+
if f.HasIPv6() {
519+
ips = append(ips, networkInfo.GlobalIPv6Address)
520+
}
521+
ip := strings.Join(ips, ",")
522+
mac := networkInfo.MacAddress
496523
ginkgo.By("Creating pod " + podName + " with IP address " + ip)
497524
annotations := map[string]string{util.IPAddressAnnotation: ip}
498-
pod := framework.MakePod(namespaceName, podName, nil, annotations, f.KubeOVNImage, cmd, nil)
525+
pod := framework.MakePod(namespaceName, podName, nil, annotations, "", nil, nil)
499526
pod.Spec.TerminationGracePeriodSeconds = nil
500527
_ = podClient.Create(pod)
501528

502529
ginkgo.By("Waiting for pod events")
503530
events := eventClient.WaitToHaveEvent("Pod", podName, "Warning", "FailedCreatePodSandBox", "kubelet", "")
504-
message := fmt.Sprintf("IP address %s has already been used by host with MAC %s", ip, mac)
531+
var message string
532+
if f.HasIPv4() {
533+
message = fmt.Sprintf("IP address %s has already been used by host with MAC %s", networkInfo.IPAddress, mac)
534+
} else {
535+
message = "dadfailed"
536+
}
505537
var found bool
506538
for _, event := range events {
507539
if strings.Contains(event.Message, message) {

0 commit comments

Comments
 (0)