in pkg/awsutils/awsutils.go [596:768]
func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadata, error) {
ctx := context.TODO()
log.Debugf("Found ENI MAC address: %s", eniMAC)
var err error
var deviceNum int
eniID, err := cache.imds.GetInterfaceID(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetInterfaceID", err)
return ENIMetadata{}, err
}
deviceNum, err = cache.imds.GetDeviceNumber(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetDeviceNumber", err)
return ENIMetadata{}, err
}
primaryMAC, err := cache.imds.GetMAC(ctx)
if err != nil {
awsAPIErrInc("GetMAC", err)
return ENIMetadata{}, err
}
if eniMAC == primaryMAC && deviceNum != 0 {
// Can this even happen? To be backwards compatible, we will always use 0 here and log an error.
log.Errorf("Device number of primary ENI is %d! Forcing it to be 0 as expected", deviceNum)
deviceNum = 0
}
log.Debugf("Found ENI: %s, MAC %s, device %d", eniID, eniMAC, deviceNum)
// Get IMDS fields for the interface
macImdsFields, err := cache.imds.GetMACImdsFields(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetMACImdsFields", err)
return ENIMetadata{}, err
}
ipv4Available := false
ipv6Available := false
// Efa-only interfaces do not have any ipv4s or ipv6s associated with it. If we don't find any local-ipv4 or ipv6 info in imds we assume it to be efa-only interface and validate this later via ec2 call
for _, field := range macImdsFields {
if field == "local-ipv4s" {
imdsIPv4s, err := cache.imds.GetLocalIPv4s(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetLocalIPv4s", err)
return ENIMetadata{}, err
}
if len(imdsIPv4s) > 0 {
ipv4Available = true
log.Debugf("Found IPv4 addresses associated with interface. This is not efa-only interface")
}
}
if field == "ipv6s" {
imdsIPv6s, err := cache.imds.GetIPv6s(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetIPv6s", err)
} else if len(imdsIPv6s) > 0 {
ipv6Available = true
log.Debugf("Found IPv6 addresses associated with interface. This is not efa-only interface")
}
}
}
if !ipv4Available && !ipv6Available {
return ENIMetadata{
ENIID: eniID,
MAC: eniMAC,
DeviceNumber: deviceNum,
SubnetIPv4CIDR: "",
IPv4Addresses: make([]ec2types.NetworkInterfacePrivateIpAddress, 0),
IPv4Prefixes: make([]ec2types.Ipv4PrefixSpecification, 0),
SubnetIPv6CIDR: "",
IPv6Addresses: make([]ec2types.NetworkInterfaceIpv6Address, 0),
IPv6Prefixes: make([]ec2types.Ipv6PrefixSpecification, 0),
}, nil
}
// Get IPv4 and IPv6 addresses assigned to interface
var ec2ip4s []ec2types.NetworkInterfacePrivateIpAddress
var subnetV4Cidr string
if ipv4Available {
cidr, err := cache.imds.GetSubnetIPv4CIDRBlock(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetSubnetIPv4CIDRBlock", err)
return ENIMetadata{}, err
}
subnetV4Cidr = cidr.String()
imdsIPv4s, err := cache.imds.GetLocalIPv4s(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetLocalIPv4s", err)
return ENIMetadata{}, err
}
ec2ip4s = make([]ec2types.NetworkInterfacePrivateIpAddress, len(imdsIPv4s))
for i, ip4 := range imdsIPv4s {
ec2ip4s[i] = ec2types.NetworkInterfacePrivateIpAddress{
Primary: aws.Bool(i == 0),
PrivateIpAddress: aws.String(ip4.String()),
}
}
}
var ec2ip6s []ec2types.NetworkInterfaceIpv6Address
var subnetV6Cidr string
if cache.v6Enabled {
// For IPv6 ENIs, do not error on missing IPv6 information
v6cidr, err := cache.imds.GetSubnetIPv6CIDRBlocks(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetSubnetIPv6CIDRBlocks", err)
} else {
subnetV6Cidr = v6cidr.String()
}
imdsIPv6s, err := cache.imds.GetIPv6s(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetIPv6s", err)
} else {
ec2ip6s = make([]ec2types.NetworkInterfaceIpv6Address, len(imdsIPv6s))
for i, ip6 := range imdsIPv6s {
ec2ip6s[i] = ec2types.NetworkInterfaceIpv6Address{
Ipv6Address: aws.String(ip6.String()),
}
}
}
}
var ec2ipv4Prefixes []ec2types.Ipv4PrefixSpecification
var ec2ipv6Prefixes []ec2types.Ipv6PrefixSpecification
// If IPv6 is enabled, get attached v6 prefixes.
if cache.v6Enabled {
imdsIPv6Prefixes, err := cache.imds.GetIPv6Prefixes(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetIPv6Prefixes", err)
return ENIMetadata{}, err
}
for _, ipv6prefix := range imdsIPv6Prefixes {
ec2ipv6Prefixes = append(ec2ipv6Prefixes, ec2types.Ipv6PrefixSpecification{
Ipv6Prefix: aws.String(ipv6prefix.String()),
})
}
} else if cache.v4Enabled && ((eniMAC == primaryMAC && !cache.useCustomNetworking) || (eniMAC != primaryMAC)) {
// Get prefix on primary ENI when custom networking is enabled is not needed.
// If primary ENI has prefixes attached and then we move to custom networking, we don't need to fetch
// the prefix since recommendation is to terminate the nodes and that would have deleted the prefix on the
// primary ENI.
imdsIPv4Prefixes, err := cache.imds.GetIPv4Prefixes(ctx, eniMAC)
if err != nil {
awsAPIErrInc("GetIPv4Prefixes", err)
return ENIMetadata{}, err
}
for _, ipv4prefix := range imdsIPv4Prefixes {
ec2ipv4Prefixes = append(ec2ipv4Prefixes, ec2types.Ipv4PrefixSpecification{
Ipv4Prefix: aws.String(ipv4prefix.String()),
})
}
}
return ENIMetadata{
ENIID: eniID,
MAC: eniMAC,
DeviceNumber: deviceNum,
SubnetIPv4CIDR: subnetV4Cidr,
IPv4Addresses: ec2ip4s,
IPv4Prefixes: ec2ipv4Prefixes,
SubnetIPv6CIDR: subnetV6Cidr,
IPv6Addresses: ec2ip6s,
IPv6Prefixes: ec2ipv6Prefixes,
}, nil
}