func()

in pkg/ipamd/datastore/data_store.go [615:665]


func (ds *DataStore) AssignPodIPv6Address(ipamKey IPAMKey, ipamMetadata IPAMMetadata) (ipv6Address string, deviceNumber int, err error) {
	ds.lock.Lock()
	defer ds.lock.Unlock()

	if !ds.isPDEnabled {
		return "", -1, fmt.Errorf("PD is not enabled. V6 is only supported in PD mode")
	}
	ds.log.Debugf("AssignPodIPv6Address: IPv6 address pool stats: assigned %d", ds.assigned)

	if eni, _, addr := ds.eniPool.FindAddressForSandbox(ipamKey); addr != nil {
		ds.log.Infof("AssignPodIPv6Address: duplicate pod assign for sandbox %s", ipamKey)
		return addr.Address, eni.DeviceNumber, nil
	}

	// In IPv6 Prefix Delegation mode, eniPool will only have Primary ENI.
	for _, eni := range ds.eniPool {
		if len(eni.IPv6Cidrs) == 0 {
			continue
		}
		for _, V6Cidr := range eni.IPv6Cidrs {
			if !V6Cidr.IsPrefix {
				continue
			}
			ipv6Address, err = ds.getFreeIPv6AddrFromCidr(V6Cidr)
			if err != nil {
				ds.log.Debugf("Unable to get IP address from prefix: %v", err)
				//In v6 mode, we (should) only have one CIDR/Prefix. So, we can bail out but we will let the loop
				//exit instead.
				continue
			}
			ds.log.Debugf("New v6 IP from PD pool- %s", ipv6Address)
			addr := &AddressInfo{Address: ipv6Address}
			V6Cidr.IPAddresses[ipv6Address] = addr

			ds.assignPodIPAddressUnsafe(addr, ipamKey, ipamMetadata, time.Now())
			if err := ds.writeBackingStoreUnsafe(); err != nil {
				ds.log.Warnf("Failed to update backing store: %v", err)
				// Important! Unwind assignment
				ds.unassignPodIPAddressUnsafe(addr)
				//Remove the IP from eni DB
				delete(V6Cidr.IPAddresses, addr.Address)
				return "", -1, err
			}
			// Increment ENI IP usage on pod IPv6 allocation
			prometheusmetrics.EniIPsInUse.WithLabelValues(eni.ID).Inc()
			return addr.Address, eni.DeviceNumber, nil
		}
	}
	prometheusmetrics.NoAvailableIPAddrs.Inc()
	return "", -1, errors.New("AssignPodIPv6Address: no available IP addresses")
}