in pkg/provider/branch/trunk/trunk.go [158:264]
func (t *trunkENI) InitTrunk(instance ec2.EC2Instance, podList []v1.Pod) error {
instanceID := t.instance.InstanceID()
log := t.log.WithValues("request", "initialize", "instance ID", instance)
nwInterfaces, err := t.ec2ApiHelper.GetInstanceNetworkInterface(&instanceID)
if err != nil {
trunkENIOperationsErrCount.WithLabelValues("describe_instance_nw_interface").Inc()
return err
}
// Get trunk network interface
for _, nwInterface := range nwInterfaces {
// It's possible to get an empty network interface response if the instnace
// is being deleted.
if nwInterface == nil || nwInterface.InterfaceType == nil {
return fmt.Errorf("received an empty network interface response "+
"from EC2 %+v", nwInterface)
}
if *nwInterface.InterfaceType == "trunk" {
t.trunkENIId = *nwInterface.NetworkInterfaceId
}
}
// Trunk interface doesn't exists, try to create a new trunk interface
if t.trunkENIId == "" {
freeIndex, err := instance.GetHighestUnusedDeviceIndex()
if err != nil {
trunkENIOperationsErrCount.WithLabelValues("find_free_index").Inc()
log.Error(err, "failed to find free device index")
return err
}
trunk, err := t.ec2ApiHelper.CreateAndAttachNetworkInterface(&instanceID, aws.String(t.instance.SubnetID()),
t.instance.InstanceSecurityGroup(), nil, &freeIndex, &TrunkEniDescription, &InterfaceTypeTrunk, 0)
if err != nil {
trunkENIOperationsErrCount.WithLabelValues("create_trunk_eni").Inc()
log.Error(err, "failed to create trunk interface")
return err
}
t.trunkENIId = *trunk.NetworkInterfaceId
log.Info("created a new trunk interface", "trunk id", t.trunkENIId)
return nil
}
// Get the list of branch ENIs
branchInterfaces, err := t.ec2ApiHelper.GetBranchNetworkInterface(&t.trunkENIId)
if err != nil {
return err
}
// Convert the list of interfaces to a set
associatedBranchInterfaces := make(map[string]*awsEC2.NetworkInterface)
for _, branchInterface := range branchInterfaces {
associatedBranchInterfaces[*branchInterface.NetworkInterfaceId] = branchInterface
}
// From the list of pods on the given node, and the branch ENIs from EC2 API call rebuild the internal cache
for _, pod := range podList {
eniListFromPod := t.getBranchInterfacesUsedByPod(&pod)
if len(eniListFromPod) == 0 {
continue
}
var branchENIs []*ENIDetails
for _, eni := range eniListFromPod {
_, isPresent := associatedBranchInterfaces[eni.ID]
if !isPresent {
t.log.Error(fmt.Errorf("eni allocated to pod not found in ec2"), "eni not found", "eni", eni)
trunkENIOperationsErrCount.WithLabelValues("get_branch_eni_from_ec2").Inc()
continue
}
// Mark the Vlan ID from the pod's annotation
t.markVlanAssigned(eni.VlanID)
branchENIs = append(branchENIs, eni)
delete(associatedBranchInterfaces, eni.ID)
}
t.uidToBranchENIMap[string(pod.UID)] = branchENIs
}
// Delete the branch ENI that don't belong to any pod.
for _, branchInterface := range associatedBranchInterfaces {
t.log.Info("pushing eni to delete queue as no pod owns it", "eni",
*branchInterface.NetworkInterfaceId)
vlanId, err := t.getVlanIdFromTag(branchInterface.TagSet)
if err != nil {
trunkENIOperationsErrCount.WithLabelValues("get_vlan_from_tag").Inc()
log.Error(err, "failed to find vlan id", "interface", *branchInterface.NetworkInterfaceId)
continue
}
// Even thought the ENI is going to be deleted still mark Vlan ID assigned as ENI will sit in cool down queue for a while
t.markVlanAssigned(vlanId)
t.pushENIToDeleteQueue(&ENIDetails{
ID: *branchInterface.NetworkInterfaceId,
VlanID: vlanId,
deletionTimeStamp: time.Now(),
})
}
log.V(1).Info("successfully initialized trunk with all associated branch interfaces",
"trunk", t.trunkENIId, "branch interfaces", t.uidToBranchENIMap)
return nil
}