func (p *ENIPool) AssignedIPv4Addresses() int {
	count := 0
	for _, eni := range *p {
		count += eni.AssignedIPv4Addresses()
	}
	return count
}
AssignedIPv4Addresses is the number of IP addresses already assigned
package datastore
import (
	"fmt"
	"net"
	"os"
	"sync"
	"time"
	"github.com/aws/amazon-vpc-cni-k8s/pkg/cri"
	"github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
)
const (
	minENILifeTime = 1 * time.Minute
	addressCoolingPeriod = 30 * time.Second
	DuplicatedENIError = "data store: duplicate ENI"
	IPAlreadyInStoreError = "datastore: IP already in data store"
	UnknownIPError = "datastore: unknown IP"
	IPInUseError = "datastore: IP is used and can not be deleted"
	ENIInUseError = "datastore: ENI is used and can not be deleted"
	UnknownENIError = "datastore: unknown ENI"
)
const checkpointMigrationPhase = 1
const backfillNetworkName = "_migrated-from-cri"
const backfillNetworkIface = "unknown"
var ErrUnknownPod = errors.New("datastore: unknown pod")
var (
	enis = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "awscni_eni_allocated",
			Help: "The number of ENIs allocated",
		},
	)
	totalIPs = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "awscni_total_ip_addresses",
			Help: "The total number of IP addresses",
		},
	)
	assignedIPs = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "awscni_assigned_ip_addresses",
			Help: "The number of IP addresses assigned to pods",
		},
	)
	forceRemovedENIs = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "awscni_force_removed_enis",
			Help: "The number of ENIs force removed while they had assigned pods",
		},
	)
	forceRemovedIPs = prometheus.NewCounter(
		prometheus.CounterOpts{
			Name: "awscni_force_removed_ips",
			Help: "The number of IPs force removed while they had assigned pods",
		},
	)
	totalPrefixes = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "awscni_total_ipv4_prefixes",
			Help: "The total number of IPv4 prefixes",
		},
	)
	ipsPerCidr = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "awscni_assigned_ip_per_cidr",
			Help: "The total number of IP addresses assigned per cidr",
		},
		[]string{"cidr"},
	)
	prometheusRegistered = false
)
type IPAMKey struct {
	NetworkName string `json:"networkName"`
	ContainerID string `json:"containerID"`
	IfName      string `json:"ifName"`
}
func (k IPAMKey) IsZero() bool {
	return k == IPAMKey{}
}
func (k IPAMKey) String() string {
	return fmt.Sprintf("%s/%s/%s", k.NetworkName, k.ContainerID, k.IfName)
}
type ENI struct {
	ID         string
	createTime time.Time
	IsPrimary bool
	IsTrunk bool
	IsEFA bool
	DeviceNumber int
	AvailableIPv4Cidrs map[string]*CidrInfo
	IPv6Cidrs map[string]*CidrInfo
}
type AddressInfo struct {
	IPAMKey        IPAMKey
	Address        string
	UnassignedTime time.Time
}
type CidrInfo struct {
	Cidr net.IPNet
	IPAddresses map[string]*AddressInfo
	IsPrefix bool
	AddressFamily string
}
func (cidr *CidrInfo) Size() int {
	ones, bits := cidr.Cidr.Mask.Size()
	return (1 << (bits - ones))
}
func (e *ENI) findAddressForSandbox(ipamKey IPAMKey) (*CidrInfo, *AddressInfo) {
	for _, availableCidr := range e.AvailableIPv4Cidrs {
		for _, addr := range availableCidr.IPAddresses {
			if addr.IPAMKey == ipamKey {
				return availableCidr, addr
			}
		}
	}
	for _, availableCidr := range e.IPv6Cidrs {
		for _, addr := range availableCidr.IPAddresses {
			if addr.IPAMKey == ipamKey {
				return availableCidr, addr
			}
		}
	}
	return nil, nil
}
func (e *ENI) AssignedIPv4Addresses() int {
	count := 0
	for _, availableCidr := range e.AvailableIPv4Cidrs {
		count += availableCidr.AssignedIPAddressesInCidr()
	}
	return count
}
func (cidr *CidrInfo) AssignedIPAddressesInCidr() int {
	count := 0
	for _, addr := range cidr.IPAddresses {
		if addr.Assigned() {
			count++
		}
	}
	return count
}
func (cidr *CidrInfo) GetIPStatsFromCidr() (int, int) {
	assignedIPs := 0
	cooldownIPs := 0
	for _, addr := range cidr.IPAddresses {
		if addr.Assigned() {
			assignedIPs++
		} else if addr.inCoolingPeriod() {
			cooldownIPs++
		}
	}
	return assignedIPs, cooldownIPs
}
func (addr AddressInfo) Assigned() bool {
	return !addr.IPAMKey.IsZero()
}
func (addr AddressInfo) inCoolingPeriod() bool {
	return time.Since(addr.UnassignedTime) <= addressCoolingPeriod
}
type ENIPool map[string]*ENI