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")
}