func()

in pkg/ipamd/datastore/data_store.go [669:736]


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

	ds.log.Debugf("AssignPodIPv4Address: IP address pool stats: total %d, assigned %d", ds.total, ds.assigned)

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

	for _, eni := range ds.eniPool {
		for _, availableCidr := range eni.AvailableIPv4Cidrs {
			var addr *AddressInfo
			var strPrivateIPv4 string
			var err error

			if (ds.isPDEnabled && availableCidr.IsPrefix) || (!ds.isPDEnabled && !availableCidr.IsPrefix) {
				strPrivateIPv4, err = ds.getFreeIPv4AddrfromCidr(availableCidr)
				if err != nil {
					ds.log.Debugf("Unable to get IP address from CIDR: %v", err)
					// Check in next CIDR
					continue
				}
				ds.log.Debugf("New IP from CIDR pool- %s", strPrivateIPv4)
				if availableCidr.IPAddresses == nil {
					availableCidr.IPAddresses = make(map[string]*AddressInfo)
				}
				// Update prometheus for ips per cidr
				// Secondary IP mode will have /32:1 and Prefix mode will have /28:<number of /32s>
				prometheusmetrics.IpsPerCidr.With(prometheus.Labels{"cidr": availableCidr.Cidr.String()}).Inc()
			} else {
				// This can happen during upgrade or PD enable/disable knob toggle
				// ENI can have prefixes attached and no space for SIPs or vice versa
				continue
			}

			addr = availableCidr.IPAddresses[strPrivateIPv4]
			if addr == nil {
				// addr is nil when we are using a new IP from prefix or SIP pool
				// if addr is out of cooldown or not assigned, we can reuse addr
				addr = &AddressInfo{Address: strPrivateIPv4}
			}

			availableCidr.IPAddresses[strPrivateIPv4] = 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(availableCidr.IPAddresses, addr.Address)
				// Update prometheus for ips per cidr
				prometheusmetrics.IpsPerCidr.With(prometheus.Labels{"cidr": availableCidr.Cidr.String()}).Dec()
				return "", -1, err
			}
			// Increment ENI IP usage on pod IPv4 allocation
			prometheusmetrics.EniIPsInUse.WithLabelValues(eni.ID).Inc()
			return addr.Address, eni.DeviceNumber, nil
		}
		ds.log.Debugf("AssignPodIPv4Address: ENI %s does not have available addresses", eni.ID)
	}

	prometheusmetrics.NoAvailableIPAddrs.Inc()
	ds.log.Errorf("DataStore has no available IP/Prefix addresses")
	return "", -1, errors.New("AssignPodIPv4Address: no available IP/Prefix addresses")
}