Skip to content

Commit 7e5b255

Browse files
committed
backporting functions outside of overlay expansion
1 parent 83d6787 commit 7e5b255

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed

cns/restserver/internalapi.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,136 @@ func (service *HTTPRestService) CreateOrUpdateNetworkContainerInternal(req *cns.
586586
return returnCode
587587
}
588588

589+
func (service *HTTPRestService) ReconcileIPAssignment(podInfoByIP map[string]cns.PodInfo, ncReqs []*cns.CreateNetworkContainerRequest) types.ResponseCode {
590+
// index all the secondary IP configs for all the nc reqs, for easier lookup later on.
591+
allSecIPsIdx := make(map[string]*cns.CreateNetworkContainerRequest)
592+
for i := range ncReqs {
593+
for _, secIPConfig := range ncReqs[i].SecondaryIPConfigs {
594+
allSecIPsIdx[secIPConfig.IPAddress] = ncReqs[i]
595+
}
596+
}
597+
598+
// we now need to reconcile IP assignment.
599+
// considering that a single pod may have multiple ips (such as in dual stack scenarios)
600+
// and that IP assignment in CNS (as done by requestIPConfigsHelper) does not allow
601+
// updates (it returns the existing state if one already exists for the pod's interface),
602+
// we need to assign all IPs for a pod interface or name+namespace at the same time.
603+
//
604+
// iterating over single IPs is not appropriate then, since assignment for the first IP for
605+
// a pod will prevent the second IP from being added. the following function call transforms
606+
// pod info indexed by ip address:
607+
//
608+
// {
609+
// "10.0.0.1": podInfo{interface: "aaa-eth0"},
610+
// "fe80::1": podInfo{interface: "aaa-eth0"},
611+
// }
612+
//
613+
// to pod IPs indexed by pod key (interface or name+namespace, depending on scenario):
614+
//
615+
// {
616+
// "aaa-eth0": podIPs{v4IP: 10.0.0.1, v6IP: fe80::1}
617+
// }
618+
//
619+
// such that we can iterate over pod interfaces, and assign all IPs for it at once.
620+
621+
podKeyToPodIPs, err := newPodKeyToPodIPsMap(podInfoByIP)
622+
if err != nil {
623+
logger.Errorf("could not transform pods indexed by IP address to pod IPs indexed by interface: %v", err)
624+
return types.UnexpectedError
625+
}
626+
627+
for podKey, podIPs := range podKeyToPodIPs {
628+
var (
629+
desiredIPs []string
630+
ncIDs []string
631+
)
632+
633+
var ips []net.IP
634+
if podIPs.v4IP != nil {
635+
ips = append(ips, podIPs.v4IP)
636+
}
637+
638+
if podIPs.v6IP != nil {
639+
ips = append(ips, podIPs.v6IP)
640+
}
641+
642+
for _, ip := range ips {
643+
if ncReq, ok := allSecIPsIdx[ip.String()]; ok {
644+
desiredIPs = append(desiredIPs, ip.String())
645+
ncIDs = append(ncIDs, ncReq.NetworkContainerid)
646+
} else {
647+
// it might still be possible to see host networking pods here (where ips are not from ncs) if we are restoring using the kube podinfo provider
648+
// todo: once kube podinfo provider reconcile flow is removed, this line will not be necessary/should be removed.
649+
logger.Errorf("ip %s assigned to pod %+v but not found in any nc", ip, podIPs)
650+
}
651+
}
652+
653+
if len(desiredIPs) == 0 {
654+
// this may happen for pods in the host network
655+
continue
656+
}
657+
658+
jsonContext, err := podIPs.OrchestratorContext()
659+
if err != nil {
660+
logger.Errorf("Failed to marshal KubernetesPodInfo, error: %v", err)
661+
return types.UnexpectedError
662+
}
663+
664+
ipconfigsRequest := cns.IPConfigsRequest{
665+
DesiredIPAddresses: desiredIPs,
666+
OrchestratorContext: jsonContext,
667+
InfraContainerID: podIPs.InfraContainerID(),
668+
PodInterfaceID: podIPs.InterfaceID(),
669+
}
670+
671+
if _, err := requestIPConfigsHelper(service, ipconfigsRequest); err != nil {
672+
//nolint:staticcheck // SA1019: suppress deprecated logger.Printf usage. Todo: legacy logger usage is consistent in cns repo. Migrates when all logger usage is migrated
673+
logger.Errorf("requestIPConfigsHelper failed for pod key %s, podInfo %+v, ncIDs %v, error: %v", podKey, podIPs, ncIDs, err)
674+
return types.FailedToAllocateIPConfig
675+
}
676+
}
677+
678+
return types.Success
679+
}
680+
681+
func (service *HTTPRestService) CreateNCs(ncReqs []*cns.CreateNetworkContainerRequest) types.ResponseCode {
682+
for _, ncReq := range ncReqs {
683+
returnCode := service.CreateOrUpdateNetworkContainerInternal(ncReq)
684+
if returnCode != types.Success {
685+
return returnCode
686+
}
687+
}
688+
689+
return types.Success
690+
}
691+
692+
func (service *HTTPRestService) ReconcileIPAMStateForSwift(ncReqs []*cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.PodInfo, nnc *v1alpha.NodeNetworkConfig) types.ResponseCode {
693+
logger.Printf("Reconciling CNS IPAM state with nc requests: [%+v], PodInfo [%+v], NNC: [%+v]", ncReqs, podInfoByIP, nnc)
694+
// if no nc reqs, there is no CRD state yet
695+
if len(ncReqs) == 0 {
696+
logger.Printf("CNS starting with no NC state, podInfoMap count %d", len(podInfoByIP))
697+
return types.Success
698+
}
699+
700+
// first step in reconciliation is to create all the NCs in CNS, no IP assignment yet.
701+
if returnCode := service.CreateNCs(ncReqs); returnCode != types.Success {
702+
return returnCode
703+
}
704+
705+
logger.Debugf("ncReqs created successfully, now save IPs")
706+
// now reconcile IPAM state.
707+
if returnCode := service.ReconcileIPAssignment(podInfoByIP, ncReqs); returnCode != types.Success {
708+
return returnCode
709+
}
710+
711+
if err := service.MarkExistingIPsAsPendingRelease(nnc.Spec.IPsNotInUse); err != nil {
712+
logger.Errorf("[Azure CNS] Error. Failed to mark IPs as pending %v", nnc.Spec.IPsNotInUse)
713+
return types.UnexpectedError
714+
}
715+
716+
return types.Success
717+
}
718+
589719
// IsCIDRSuperset returns true if newCIDR is a superset of oldCIDR (i.e., all IPs in oldCIDR are contained in newCIDR).
590720
func validateCIDRSuperset(newCIDR, oldCIDR string) bool {
591721
// Parse newCIDR and oldCIDR into netip.Prefix

0 commit comments

Comments
 (0)