in cni/network/invoker_cns.go [88:223]
func (invoker *CNSIPAMInvoker) Add(addConfig IPAMAddConfig) (IPAMAddResult, error) {
// Parse Pod arguments.
podInfo := cns.KubernetesPodInfo{
PodName: invoker.podName,
PodNamespace: invoker.podNamespace,
}
orchestratorContext, err := json.Marshal(podInfo)
if err != nil {
logger.Info(podInfo.PodName)
return IPAMAddResult{}, errors.Wrap(err, "Failed to unmarshal orchestrator context during add: %w")
}
if addConfig.args == nil {
return IPAMAddResult{}, errEmptyCNIArgs
}
ipconfigs := cns.IPConfigsRequest{
OrchestratorContext: orchestratorContext,
PodInterfaceID: GetEndpointID(addConfig.args),
InfraContainerID: addConfig.args.ContainerID,
}
logger.Info("Requesting IP for pod using ipconfig",
zap.Any("pod", podInfo),
zap.Any("ipconfig", ipconfigs))
response, err := invoker.cnsClient.RequestIPs(context.TODO(), ipconfigs)
if err != nil {
if cnscli.IsUnsupportedAPI(err) {
// If RequestIPs is not supported by CNS, use RequestIPAddress API
logger.Error("RequestIPs not supported by CNS. Invoking RequestIPAddress API",
zap.Any("infracontainerid", ipconfigs.InfraContainerID))
ipconfig := cns.IPConfigRequest{
OrchestratorContext: orchestratorContext,
PodInterfaceID: GetEndpointID(addConfig.args),
InfraContainerID: addConfig.args.ContainerID,
}
res, errRequestIP := invoker.cnsClient.RequestIPAddress(context.TODO(), ipconfig)
if errRequestIP != nil {
// if the old API fails as well then we just return the error
logger.Error("Failed to request IP address from CNS using RequestIPAddress",
zap.Any("infracontainerid", ipconfig.InfraContainerID),
zap.Error(errRequestIP))
return IPAMAddResult{}, errors.Wrap(errRequestIP, "Failed to get IP address from CNS")
}
response = &cns.IPConfigsResponse{
Response: res.Response,
PodIPInfo: []cns.PodIpInfo{
res.PodIpInfo,
},
}
} else {
logger.Info("Failed to get IP address from CNS",
zap.Any("response", response))
return IPAMAddResult{}, errors.Wrap(err, "Failed to get IP address from CNS")
}
}
addResult := IPAMAddResult{interfaceInfo: make(map[string]network.InterfaceInfo)}
numInterfacesWithDefaultRoutes := 0
for i := 0; i < len(response.PodIPInfo); i++ {
info := IPResultInfo{
podIPAddress: response.PodIPInfo[i].PodIPConfig.IPAddress,
ncSubnetPrefix: response.PodIPInfo[i].NetworkContainerPrimaryIPConfig.IPSubnet.PrefixLength,
ncPrimaryIP: response.PodIPInfo[i].NetworkContainerPrimaryIPConfig.IPSubnet.IPAddress,
ncGatewayIPAddress: response.PodIPInfo[i].NetworkContainerPrimaryIPConfig.GatewayIPAddress,
hostSubnet: response.PodIPInfo[i].HostPrimaryIPInfo.Subnet,
hostPrimaryIP: response.PodIPInfo[i].HostPrimaryIPInfo.PrimaryIP,
hostGateway: response.PodIPInfo[i].HostPrimaryIPInfo.Gateway,
nicType: response.PodIPInfo[i].NICType,
macAddress: response.PodIPInfo[i].MacAddress,
skipDefaultRoutes: response.PodIPInfo[i].SkipDefaultRoutes,
routes: response.PodIPInfo[i].Routes,
pnpID: response.PodIPInfo[i].PnPID,
endpointPolicies: response.PodIPInfo[i].EndpointPolicies,
}
logger.Info("Received info for pod",
zap.Any("ipInfo", info),
zap.Any("podInfo", podInfo))
//nolint:exhaustive // ignore exhaustive types check
// Do we want to leverage this lint skip in other places of our code?
key := invoker.getInterfaceInfoKey(info.nicType, info.macAddress)
switch info.nicType {
case cns.NodeNetworkInterfaceFrontendNIC:
// only handling single v4 PodIPInfo for NodeNetworkInterfaceFrontendNIC and AccelnetNIC at the moment, will have to update once v6 gets added
if !info.skipDefaultRoutes {
numInterfacesWithDefaultRoutes++
}
// Add secondary interface info from podIPInfo to ipamAddResult
info.hostSubnet = response.PodIPInfo[i].HostPrimaryIPInfo.Subnet
info.hostPrimaryIP = response.PodIPInfo[i].HostPrimaryIPInfo.PrimaryIP
info.hostGateway = response.PodIPInfo[i].HostPrimaryIPInfo.Gateway
if err := configureSecondaryAddResult(&info, &addResult, &response.PodIPInfo[i].PodIPConfig, key); err != nil {
return IPAMAddResult{}, err
}
case cns.BackendNIC:
// TODO: check whether setting default route on IB interface
// handle ipv4 PodIPInfo for BackendNIC
if err := addBackendNICToResult(&info, &addResult, key); err != nil {
return IPAMAddResult{}, err
}
case cns.InfraNIC, "":
// if we change from legacy cns, the nicType will be empty, so we assume it is infra nic
info.nicType = cns.InfraNIC
// only count dualstack interface once
_, exist := addResult.interfaceInfo[key]
if !exist {
addResult.interfaceInfo[key] = network.InterfaceInfo{}
if !info.skipDefaultRoutes {
numInterfacesWithDefaultRoutes++
}
}
overlayMode := (invoker.ipamMode == util.V4Overlay) || (invoker.ipamMode == util.DualStackOverlay) || (invoker.ipamMode == util.Overlay)
if err := configureDefaultAddResult(&info, &addConfig, &addResult, overlayMode, key); err != nil {
return IPAMAddResult{}, err
}
default:
logger.Warn("Unknown NIC type received from cns pod ip info", zap.String("nicType", string(info.nicType)))
}
}
// Make sure default routes exist for 1 interface
if numInterfacesWithDefaultRoutes != expectedNumInterfacesWithDefaultRoutes {
return IPAMAddResult{}, errInvalidDefaultRouting
}
return addResult, nil
}