in pkg/provider/ip/eni/eni.go [121:245]
func (e *eniManager) CreateIPV4Resource(required int, resourceType config.ResourceType, ec2APIHelper api.EC2APIHelper, log logr.Logger) ([]string, error) {
e.lock.Lock()
defer e.lock.Unlock()
var assignedIPv4Resources []string
log = log.WithValues("node name", e.instance.Name())
// Loop till we reach the last available ENI and list of assigned IPv4 resources is equal to the required resources
for index := 0; index < len(e.attachedENIs) && len(assignedIPv4Resources) < required; index++ {
remainingCapacity := e.attachedENIs[index].remainingCapacity
if remainingCapacity > 0 {
canAssign := 0
// Number of resources wanted is the number of resources required minus the number of resources assigned till now
want := required - len(assignedIPv4Resources)
// Cannot fulfil the entire request using this ENI, allocate whatever the ENI can assign
if remainingCapacity < want {
canAssign = remainingCapacity
} else {
canAssign = want
}
// Assign the IPv4 resource from this ENI
assigned, err := ec2APIHelper.AssignIPv4ResourcesAndWaitTillReady(e.attachedENIs[index].eniID, resourceType, canAssign)
if err != nil && len(assigned) == 0 {
// Return the list of resources that were actually created along with the error
return assigned, err
} else if err != nil {
// Just log and continue processing the assigned resources
log.Error(err, "failed to assign all the requested resources",
"requested", want, "got", len(assigned))
}
// Update the remaining capacity, assigned can be empty while err is nil
e.attachedENIs[index].remainingCapacity = remainingCapacity - len(assigned)
// Append the assigned IPs on this ENI to the list of IPs created across all the ENIs
assignedIPv4Resources = append(assignedIPv4Resources, assigned...)
// Add the mapping from IP to ENI, so that we can easily delete the IP and increment the remaining IP count
// on the ENI
for _, resource := range assigned {
e.resourceToENIMap[resource] = e.attachedENIs[index]
}
log.Info("assigned IPv4 resources", "resource type", resourceType, "resources", assigned,
"eni", e.attachedENIs[index].eniID, "want", want, "can provide upto", canAssign)
}
}
// TODO: Windows doesn't support multi-ENI yet, commenting out code that creates new ENI. Uncomment once multi-ENI is supported.
//// Number of secondary IPs or IPv4 prefixes supported minus the primary IP
//ipLimit := vpc.Limits[e.instance.Type()].IPv4PerInterface - 1
//eniLimit := vpc.Limits[e.instance.Type()].Interface
//
//// If the existing ENIs could not assign the required resources, loop till the new ENIs can assign the required
//// number of IPv4 resources
//for len(assignedIPv4Resources) < required &&
// len(e.attachedENIs) < eniLimit {
//
// deviceIndex, err := e.instance.GetHighestUnusedDeviceIndex()
// if err != nil {
// // TODO: Refresh device index for linux nodes only
// return assignedIPv4Resources, err
// }
// want := required - len(assignedIPv4Resources)
// if want > ipLimit {
// want = ipLimit
// }
//
// // Create new ENI and store newly assigned resources into map
// switch resourceType {
// case config.ResourceTypeIPv4Address:
// ipResourceCount := &config.IPResourceCount{SecondaryIPv4Count: want}
// nwInterface, err := ec2APIHelper.CreateAndAttachNetworkInterface(aws.String(e.instance.InstanceID()),
// aws.String(e.instance.SubnetID()), e.instance.CurrentInstanceSecurityGroups(), nil, aws.Int64(deviceIndex),
// &ENIDescription, nil, ipResourceCount)
// if err != nil {
// // TODO: Check if any clean up is required here for linux nodes only?
// return assignedIPv4Resources, err
// }
// eni := &eni{
// remainingCapacity: ipLimit - want,
// eniID: *nwInterface.NetworkInterfaceId,
// }
// e.attachedENIs = append(e.attachedENIs, eni)
// for _, assignedIP := range nwInterface.PrivateIpAddresses {
// if !*assignedIP.Primary {
// assignedIPv4Resources = append(assignedIPv4Resources, *assignedIP.PrivateIpAddress)
// // Also add the mapping from IP to ENI
// e.resourceToENIMap[*assignedIP.PrivateIpAddress] = eni
// }
// }
//
// case config.ResourceTypeIPv4Prefix:
// ipResourceCount := &config.IPResourceCount{IPv4PrefixCount: want}
// nwInterface, err := ec2APIHelper.CreateAndAttachNetworkInterface(aws.String(e.instance.InstanceID()),
// aws.String(e.instance.SubnetID()), e.instance.CurrentInstanceSecurityGroups(), nil, aws.Int64(deviceIndex),
// &ENIDescription, nil, ipResourceCount)
// if err != nil {
// // TODO: Check if any clean up is required here for linux nodes only?
// return assignedIPv4Resources, err
// }
// eni := &eni{
// remainingCapacity: ipLimit - want,
// eniID: *nwInterface.NetworkInterfaceId,
// }
// e.attachedENIs = append(e.attachedENIs, eni)
// for _, assignedPrefix := range nwInterface.Ipv4Prefixes {
// assignedIPv4Resources = append(assignedIPv4Resources, *assignedPrefix.Ipv4Prefix)
// // Also add the mapping from Prefix to ENI
// e.resourceToENIMap[*assignedPrefix.Ipv4Prefix] = eni
// }
// }
//}
var err error
// This can happen if the subnet doesn't have remaining IPs
if len(assignedIPv4Resources) < required {
err = fmt.Errorf("not able to create the desired number of %s, required %d, created %d",
resourceType, required, len(assignedIPv4Resources))
}
// add subnet mask to assigned IP
if resourceType == config.ResourceTypeIPv4Address {
assignedIPv4Resources = e.addSubnetMaskToIPSlice(assignedIPv4Resources)
}
return assignedIPv4Resources, err
}