-
Notifications
You must be signed in to change notification settings - Fork 772
Fix fetching enimetadata #3035
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix fetching enimetadata #3035
Changes from all commits
cc6f1c0
bd9966a
f5a7fcb
7ee590a
c6a4e1b
26009a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -585,6 +585,12 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat | |
return ENIMetadata{}, err | ||
} | ||
|
||
networkCard, err := cache.imds.GetNetworkCard(ctx, eniMAC) | ||
if err != nil { | ||
awsAPIErrInc("GetNetworkCard", err) | ||
return ENIMetadata{}, err | ||
} | ||
|
||
deviceNum, err = cache.imds.GetDeviceNumber(ctx, eniMAC) | ||
if err != nil { | ||
awsAPIErrInc("GetDeviceNumber", err) | ||
|
@@ -602,90 +608,99 @@ func (cache *EC2InstanceMetadataCache) getENIMetadata(eniMAC string) (ENIMetadat | |
deviceNum = 0 | ||
} | ||
|
||
log.Debugf("Found ENI: %s, MAC %s, device %d", eniID, eniMAC, deviceNum) | ||
|
||
// Get IPv4 and IPv6 addresses assigned to interface | ||
cidr, err := cache.imds.GetSubnetIPv4CIDRBlock(ctx, eniMAC) | ||
if err != nil { | ||
awsAPIErrInc("GetSubnetIPv4CIDRBlock", err) | ||
return ENIMetadata{}, err | ||
} | ||
|
||
imdsIPv4s, err := cache.imds.GetLocalIPv4s(ctx, eniMAC) | ||
if err != nil { | ||
awsAPIErrInc("GetLocalIPv4s", err) | ||
return ENIMetadata{}, err | ||
} | ||
|
||
ec2ip4s := make([]*ec2.NetworkInterfacePrivateIpAddress, len(imdsIPv4s)) | ||
for i, ip4 := range imdsIPv4s { | ||
ec2ip4s[i] = &ec2.NetworkInterfacePrivateIpAddress{ | ||
Primary: aws.Bool(i == 0), | ||
PrivateIpAddress: aws.String(ip4.String()), | ||
} | ||
} | ||
log.Debugf("Found ENI: %s, MAC %s, device %d, network card %d", eniID, eniMAC, deviceNum, networkCard) | ||
|
||
var subnetV4Cidr string | ||
var ec2ip4s []*ec2.NetworkInterfacePrivateIpAddress | ||
var ec2ip6s []*ec2.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() | ||
} | ||
var ec2ipv4Prefixes []*ec2.Ipv4PrefixSpecification | ||
var ec2ipv6Prefixes []*ec2.Ipv6PrefixSpecification | ||
|
||
imdsIPv6s, err := cache.imds.GetIPv6s(ctx, eniMAC) | ||
// CNI only manages ENI's on network card 0. We need to get complete metadata info only for ENI's on network card 0. | ||
// For ENI's on other network cards, there might not be IP related info present at all like 'efa-only' interfaces | ||
// So we are skipping fetching IP related info for all ENI's other than card 0 | ||
if networkCard == 0 { | ||
// Get IPv4 and IPv6 addresses assigned to interface | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to remove IPv6 from the comment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jayanthvn we are fetching both IPv4 and IPv6 addresses for ENI's on network card 0. Comment is same as earlier to this change. Github side by side comparison is a bit messed for this PR |
||
cidr, err := cache.imds.GetSubnetIPv4CIDRBlock(ctx, eniMAC) | ||
if err != nil { | ||
awsAPIErrInc("GetIPv6s", err) | ||
awsAPIErrInc("GetSubnetIPv4CIDRBlock", err) | ||
return ENIMetadata{}, err | ||
} else { | ||
ec2ip6s = make([]*ec2.NetworkInterfaceIpv6Address, len(imdsIPv6s)) | ||
for i, ip6 := range imdsIPv6s { | ||
ec2ip6s[i] = &ec2.NetworkInterfaceIpv6Address{ | ||
Ipv6Address: aws.String(ip6.String()), | ||
} | ||
} | ||
subnetV4Cidr = cidr.String() | ||
} | ||
} | ||
|
||
var ec2ipv4Prefixes []*ec2.Ipv4PrefixSpecification | ||
var ec2ipv6Prefixes []*ec2.Ipv6PrefixSpecification | ||
|
||
// If IPv6 is enabled, get attached v6 prefixes. | ||
if cache.v6Enabled { | ||
imdsIPv6Prefixes, err := cache.imds.GetIPv6Prefixes(ctx, eniMAC) | ||
imdsIPv4s, err := cache.imds.GetLocalIPv4s(ctx, eniMAC) | ||
if err != nil { | ||
awsAPIErrInc("GetIPv6Prefixes", err) | ||
awsAPIErrInc("GetLocalIPv4s", err) | ||
return ENIMetadata{}, err | ||
} | ||
for _, ipv6prefix := range imdsIPv6Prefixes { | ||
ec2ipv6Prefixes = append(ec2ipv6Prefixes, &ec2.Ipv6PrefixSpecification{ | ||
Ipv6Prefix: aws.String(ipv6prefix.String()), | ||
}) | ||
|
||
ec2ip4s = make([]*ec2.NetworkInterfacePrivateIpAddress, len(imdsIPv4s)) | ||
for i, ip4 := range imdsIPv4s { | ||
ec2ip4s[i] = &ec2.NetworkInterfacePrivateIpAddress{ | ||
Primary: aws.Bool(i == 0), | ||
PrivateIpAddress: aws.String(ip4.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 | ||
|
||
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([]*ec2.NetworkInterfaceIpv6Address, len(imdsIPv6s)) | ||
for i, ip6 := range imdsIPv6s { | ||
ec2ip6s[i] = &ec2.NetworkInterfaceIpv6Address{ | ||
Ipv6Address: aws.String(ip6.String()), | ||
} | ||
} | ||
} | ||
} | ||
for _, ipv4prefix := range imdsIPv4Prefixes { | ||
ec2ipv4Prefixes = append(ec2ipv4Prefixes, &ec2.Ipv4PrefixSpecification{ | ||
Ipv4Prefix: aws.String(ipv4prefix.String()), | ||
}) | ||
|
||
// 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, &ec2.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, &ec2.Ipv4PrefixSpecification{ | ||
Ipv4Prefix: aws.String(ipv4prefix.String()), | ||
}) | ||
} | ||
} | ||
} | ||
|
||
return ENIMetadata{ | ||
ENIID: eniID, | ||
MAC: eniMAC, | ||
DeviceNumber: deviceNum, | ||
SubnetIPv4CIDR: cidr.String(), | ||
SubnetIPv4CIDR: subnetV4Cidr, | ||
IPv4Addresses: ec2ip4s, | ||
IPv4Prefixes: ec2ipv4Prefixes, | ||
SubnetIPv6CIDR: subnetV6Cidr, | ||
|
@@ -1356,7 +1371,7 @@ func (cache *EC2InstanceMetadataCache) DescribeAllENIs() (DescribeAllENIsResult, | |
if interfaceType == "trunk" { | ||
trunkENI = eniID | ||
} | ||
if interfaceType == "efa" { | ||
if interfaceType == "efa" || interfaceType == "efa-only" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. eventually we should move the interfaceType to some enum for trunk, efa, efa-only.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense @jayanthvn. I will add a backlog task for this |
||
efaENIs[eniID] = true | ||
} | ||
// Check IPv4 addresses | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are we verifying with a
if networkCard == 0
here?Also, we need to test this change in some variety of instances - Multi Card Instance, regular instance, and ensuring this is not leading to any unexpected behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@orsenthil Thanks for the review
On a multicard instance this condition would be false for non-0 cards. For non-0 cards we are just getting basic eni info and not fetching any ip related info as some of the efa interfaces might not have ip info
Here https://github.com/aws/amazon-vpc-cni-k8s/blob/master/pkg/awsutils/awsutils.go#L1344 we already assume CNI always manages only network card 0 and rest are just added as unmanaged ENI's so it is safe to make the assumption that we need complete ENIMetadata only for network card 0
I have tested this on multiple instances including multi-card, single card, different efa interfaces and verified the functionality.
I will add comments in code explaining why we are checking for network card 0