@@ -3,6 +3,8 @@ package middlewares
33import (
44 "context"
55 "fmt"
6+ "net/netip"
7+
68 "github.com/Azure/azure-container-networking/cns"
79 "github.com/Azure/azure-container-networking/cns/configuration"
810 "github.com/Azure/azure-container-networking/cns/logger"
@@ -37,17 +39,17 @@ var _ cns.IPConfigsHandlerMiddleware = (*K8sSWIFTv2Middleware)(nil)
3739
3840// IPConfigsRequestHandlerWrapper is the middleware function for handling SWIFT v2 IP configs requests for AKS-SWIFT. This function wrapped the default SWIFT request
3941// and release IP configs handlers.
40- func (k * K8sSWIFTv2Middleware ) IPConfigsRequestHandlerWrapper (defaultHandler , failureHandler cns.IPConfigsHandlerFunc ) cns.IPConfigsHandlerFunc {
42+ func (m * K8sSWIFTv2Middleware ) IPConfigsRequestHandlerWrapper (defaultHandler , failureHandler cns.IPConfigsHandlerFunc ) cns.IPConfigsHandlerFunc {
4143 return func (ctx context.Context , req cns.IPConfigsRequest ) (* cns.IPConfigsResponse , error ) {
42- podInfo , respCode , message := k .validateIPConfigsRequest (ctx , & req )
44+ podInfo , respCode , message := m .validateIPConfigsRequest (ctx , & req )
4345
4446 if respCode != types .Success {
4547 return & cns.IPConfigsResponse {
4648 Response : cns.Response {
4749 ReturnCode : respCode ,
4850 Message : message ,
4951 },
50- }, errors .New ("failed to validate IP configs request" )
52+ }, errors .New ("failed to validate ip configs request" )
5153 }
5254 ipConfigsResp , err := defaultHandler (ctx , req )
5355 // If the pod is not v2, return the response from the handler
@@ -67,7 +69,7 @@ func (k *K8sSWIFTv2Middleware) IPConfigsRequestHandlerWrapper(defaultHandler, fa
6769 if err != nil {
6870 return ipConfigsResp , err
6971 }
70- SWIFTv2PodIPInfos , err := k .getIPConfig (ctx , podInfo )
72+ SWIFTv2PodIPInfo , err := m .getIPConfig (ctx , podInfo )
7173 if err != nil {
7274 return & cns.IPConfigsResponse {
7375 Response : cns.Response {
@@ -77,11 +79,11 @@ func (k *K8sSWIFTv2Middleware) IPConfigsRequestHandlerWrapper(defaultHandler, fa
7779 PodIPInfo : []cns.PodIpInfo {},
7880 }, errors .Wrapf (err , "failed to get SWIFTv2 IP config : %v" , req )
7981 }
80- ipConfigsResp .PodIPInfo = append (ipConfigsResp .PodIPInfo , SWIFTv2PodIPInfos ... )
82+ ipConfigsResp .PodIPInfo = append (ipConfigsResp .PodIPInfo , SWIFTv2PodIPInfo )
8183 // Set routes for the pod
8284 for i := range ipConfigsResp .PodIPInfo {
8385 ipInfo := & ipConfigsResp .PodIPInfo [i ]
84- err = k .setRoutes (ipInfo )
86+ err = m .setRoutes (ipInfo )
8587 if err != nil {
8688 return & cns.IPConfigsResponse {
8789 Response : cns.Response {
@@ -98,7 +100,7 @@ func (k *K8sSWIFTv2Middleware) IPConfigsRequestHandlerWrapper(defaultHandler, fa
98100
99101// validateIPConfigsRequest validates if pod is multitenant by checking the pod labels, used in SWIFT V2 AKS scenario.
100102// nolint
101- func (k * K8sSWIFTv2Middleware ) validateIPConfigsRequest (ctx context.Context , req * cns.IPConfigsRequest ) (podInfo cns.PodInfo , respCode types.ResponseCode , message string ) {
103+ func (m * K8sSWIFTv2Middleware ) validateIPConfigsRequest (ctx context.Context , req * cns.IPConfigsRequest ) (podInfo cns.PodInfo , respCode types.ResponseCode , message string ) {
102104 // Retrieve the pod from the cluster
103105 podInfo , err := cns .UnmarshalPodInfo (req .OrchestratorContext )
104106 if err != nil {
@@ -108,7 +110,7 @@ func (k *K8sSWIFTv2Middleware) validateIPConfigsRequest(ctx context.Context, req
108110 logger .Printf ("[SWIFTv2Middleware] validate ipconfigs request for pod %s" , podInfo .Name ())
109111 podNamespacedName := k8stypes.NamespacedName {Namespace : podInfo .Namespace (), Name : podInfo .Name ()}
110112 pod := v1.Pod {}
111- if err := k .Cli .Get (ctx , podNamespacedName , & pod ); err != nil {
113+ if err := m .Cli .Get (ctx , podNamespacedName , & pod ); err != nil {
112114 errBuf := errors .Wrapf (err , "failed to get pod %+v" , podNamespacedName )
113115 return nil , types .UnexpectedError , errBuf .Error ()
114116 }
@@ -119,11 +121,11 @@ func (k *K8sSWIFTv2Middleware) validateIPConfigsRequest(ctx context.Context, req
119121 // Check if the MTPNC CRD exists for the pod, if not, return error
120122 mtpnc := v1alpha1.MultitenantPodNetworkConfig {}
121123 mtpncNamespacedName := k8stypes.NamespacedName {Namespace : podInfo .Namespace (), Name : podInfo .Name ()}
122- if err := k .Cli .Get (ctx , mtpncNamespacedName , & mtpnc ); err != nil {
124+ if err := m .Cli .Get (ctx , mtpncNamespacedName , & mtpnc ); err != nil {
123125 return nil , types .UnexpectedError , fmt .Errorf ("failed to get pod's mtpnc from cache : %w" , err ).Error ()
124126 }
125127 // Check if the MTPNC CRD is ready. If one of the fields is empty, return error
126- if ! mtpnc .IsReady () {
128+ if mtpnc .Status . PrimaryIP == "" || mtpnc . Status . MacAddress == "" || mtpnc . Status . NCID == "" || mtpnc . Status . GatewayIP == "" {
127129 return nil , types .UnexpectedError , errMTPNCNotReady .Error ()
128130 }
129131 }
@@ -133,78 +135,150 @@ func (k *K8sSWIFTv2Middleware) validateIPConfigsRequest(ctx context.Context, req
133135}
134136
135137// getIPConfig returns the pod's SWIFT V2 IP configuration.
136- func (k * K8sSWIFTv2Middleware ) getIPConfig (ctx context.Context , podInfo cns.PodInfo ) ([] cns.PodIpInfo , error ) {
138+ func (m * K8sSWIFTv2Middleware ) getIPConfig (ctx context.Context , podInfo cns.PodInfo ) (cns.PodIpInfo , error ) {
137139 // Check if the MTPNC CRD exists for the pod, if not, return error
138140 mtpnc := v1alpha1.MultitenantPodNetworkConfig {}
139141 mtpncNamespacedName := k8stypes.NamespacedName {Namespace : podInfo .Namespace (), Name : podInfo .Name ()}
140- if err := k .Cli .Get (ctx , mtpncNamespacedName , & mtpnc ); err != nil {
141- return nil , errors .Wrapf (err , "failed to get pod's mtpnc from cache" )
142+ if err := m .Cli .Get (ctx , mtpncNamespacedName , & mtpnc ); err != nil {
143+ return cns. PodIpInfo {} , errors .Wrapf (err , "failed to get pod's mtpnc from cache" )
142144 }
143145
144146 // Check if the MTPNC CRD is ready. If one of the fields is empty, return error
145- if ! mtpnc .IsReady () {
146- return nil , errMTPNCNotReady
147+ if mtpnc .Status . PrimaryIP == "" || mtpnc . Status . MacAddress == "" || mtpnc . Status . NCID == "" || mtpnc . Status . GatewayIP == "" {
148+ return cns. PodIpInfo {} , errMTPNCNotReady
147149 }
148150 logger .Printf ("[SWIFTv2Middleware] mtpnc for pod %s is : %+v" , podInfo .Name (), mtpnc )
149151
150- var podIPInfos []cns.PodIpInfo
152+ // Parse MTPNC primaryIP to get the IP address and prefix length
153+ p , err := netip .ParsePrefix (mtpnc .Status .PrimaryIP )
154+ if err != nil {
155+ return cns.PodIpInfo {}, errors .Wrapf (err , "failed to parse mtpnc primaryIP %s" , mtpnc .Status .PrimaryIP )
156+ }
157+ // Get the IP address and prefix length
158+ ip := p .Addr ()
159+ prefixSize := p .Bits ()
160+ if prefixSize != prefixLength {
161+ return cns.PodIpInfo {}, errors .Wrapf (errInvalidMTPNCPrefixLength , "mtpnc primaryIP prefix length is %d" , prefixSize )
162+ }
163+ podIPInfo := cns.PodIpInfo {
164+ PodIPConfig : cns.IPSubnet {
165+ IPAddress : ip .String (),
166+ PrefixLength : uint8 (prefixSize ),
167+ },
168+ MacAddress : mtpnc .Status .MacAddress ,
169+ NICType : cns .DelegatedVMNIC ,
170+ SkipDefaultRoutes : false ,
171+ // InterfaceName is empty for DelegatedVMNIC
172+ }
173+
174+ return podIPInfo , nil
175+ }
151176
152- if len (mtpnc .Status .InterfaceInfos ) == 0 {
153- // Use fields from mtpnc.Status if InterfaceInfos is empty
154- ip , prefixSize , err := utils .ParseIPAndPrefix (mtpnc .Status .PrimaryIP )
177+ // setRoutes sets the routes for podIPInfo used in SWIFT V2 scenario.
178+ func (m * K8sSWIFTv2Middleware ) setRoutes (podIPInfo * cns.PodIpInfo ) error {
179+ logger .Printf ("[SWIFTv2Middleware] set routes for pod with nic type : %s" , podIPInfo .NICType )
180+ podIPInfo .Routes = []cns.Route {}
181+ switch podIPInfo .NICType {
182+ case cns .DelegatedVMNIC :
183+ virtualGWRoute := cns.Route {
184+ IPAddress : fmt .Sprintf ("%s/%d" , virtualGW , prefixLength ),
185+ }
186+ // default route via SWIFT v2 interface
187+ route := cns.Route {
188+ IPAddress : "0.0.0.0/0" ,
189+ GatewayIPAddress : virtualGW ,
190+ }
191+ podIPInfo .Routes = []cns.Route {virtualGWRoute , route }
192+ case cns .InfraNIC :
193+ // Get and parse infraVNETCIDRs from env
194+ infraVNETCIDRs , err := configuration .InfraVNETCIDRs ()
155195 if err != nil {
156- return nil , errors .Wrap (err , "failed to parse mtpnc primary IP and prefix" )
157- }
158- if prefixSize != prefixLength {
159- return nil , errors .Wrapf (errInvalidMTPNCPrefixLength , "mtpnc primaryIP prefix length is %d" , prefixSize )
160- }
161-
162- podIPInfos = append (podIPInfos , cns.PodIpInfo {
163- PodIPConfig : cns.IPSubnet {
164- IPAddress : ip ,
165- PrefixLength : uint8 (prefixSize ),
166- },
167- MacAddress : mtpnc .Status .MacAddress ,
168- NICType : cns .DelegatedVMNIC ,
169- SkipDefaultRoutes : false ,
170- // InterfaceName is empty for DelegatedVMNIC
171- })
172- } else {
173- // Use InterfaceInfos if not empty
174- podIPInfos = make ([]cns.PodIpInfo , len (mtpnc .Status .InterfaceInfos ))
175- for i , interfaceInfo := range mtpnc .Status .InterfaceInfos {
176- // Parse MTPNC primaryIP to get the IP address and prefix length
177- ip , prefixSize , err := utils .ParseIPAndPrefix (interfaceInfo .PrimaryIP )
178- if err != nil {
179- return nil , errors .Wrap (err , "failed to parse mtpnc primary IP and prefix" )
196+ return errors .Wrapf (err , "failed to get infraVNETCIDRs from env" )
197+ }
198+ infraVNETCIDRsv4 , infraVNETCIDRsv6 , err := utils .ParseCIDRs (infraVNETCIDRs )
199+ if err != nil {
200+ return errors .Wrapf (err , "failed to parse infraVNETCIDRs" )
201+ }
202+
203+ // Get and parse podCIDRs from env
204+ podCIDRs , err := configuration .PodCIDRs ()
205+ if err != nil {
206+ return errors .Wrapf (err , "failed to get podCIDRs from env" )
207+ }
208+ podCIDRsV4 , podCIDRv6 , err := utils .ParseCIDRs (podCIDRs )
209+ if err != nil {
210+ return errors .Wrapf (err , "failed to parse podCIDRs" )
211+ }
212+
213+ // Get and parse serviceCIDRs from env
214+ serviceCIDRs , err := configuration .ServiceCIDRs ()
215+ if err != nil {
216+ return errors .Wrapf (err , "failed to get serviceCIDRs from env" )
217+ }
218+ serviceCIDRsV4 , serviceCIDRsV6 , err := utils .ParseCIDRs (serviceCIDRs )
219+ if err != nil {
220+ return errors .Wrapf (err , "failed to parse serviceCIDRs" )
221+ }
222+ // Check if the podIPInfo is IPv4 or IPv6
223+ ip , err := netip .ParseAddr (podIPInfo .PodIPConfig .IPAddress )
224+ if err != nil {
225+ return errors .Wrapf (err , "failed to parse podIPConfig IP address %s" , podIPInfo .PodIPConfig .IPAddress )
226+ }
227+ if ip .Is4 () {
228+ // routes for IPv4 podCIDR traffic
229+ for _ , podCIDRv4 := range podCIDRsV4 {
230+ podCIDRv4Route := cns.Route {
231+ IPAddress : podCIDRv4 ,
232+ GatewayIPAddress : overlayGatewayv4 ,
233+ }
234+ podIPInfo .Routes = append (podIPInfo .Routes , podCIDRv4Route )
180235 }
181- if prefixSize != prefixLength {
182- return nil , errors .Wrapf (errInvalidMTPNCPrefixLength , "mtpnc primaryIP prefix length is %d" , prefixSize )
236+ // route for IPv4 serviceCIDR traffic
237+ for _ , serviceCIDRv4 := range serviceCIDRsV4 {
238+ serviceCIDRv4Route := cns.Route {
239+ IPAddress : serviceCIDRv4 ,
240+ GatewayIPAddress : overlayGatewayv4 ,
241+ }
242+ podIPInfo .Routes = append (podIPInfo .Routes , serviceCIDRv4Route )
183243 }
184-
185- var nicType cns.NICType
186- switch {
187- case interfaceInfo .DeviceType == v1alpha1 .DeviceTypeVnetNIC && ! interfaceInfo .AccelnetEnabled :
188- nicType = cns .DelegatedVMNIC
189- case interfaceInfo .DeviceType == v1alpha1 .DeviceTypeVnetNIC && interfaceInfo .AccelnetEnabled :
190- nicType = cns .NodeNetworkInterfaceAccelnetFrontendNIC
191- case interfaceInfo .DeviceType == v1alpha1 .DeviceTypeInfiniBandNIC :
192- nicType = cns .NodeNetworkInterfaceBackendNIC
193- default :
194- nicType = cns .DelegatedVMNIC
244+ // route for IPv4 infraVNETCIDR traffic
245+ for _ , infraVNETCIDRv4 := range infraVNETCIDRsv4 {
246+ infraVNETCIDRv4Route := cns.Route {
247+ IPAddress : infraVNETCIDRv4 ,
248+ GatewayIPAddress : overlayGatewayv4 ,
249+ }
250+ podIPInfo .Routes = append (podIPInfo .Routes , infraVNETCIDRv4Route )
195251 }
196-
197- podIPInfos [i ] = cns.PodIpInfo {
198- PodIPConfig : cns.IPSubnet {
199- IPAddress : ip ,
200- PrefixLength : uint8 (prefixSize ),
201- },
202- MacAddress : interfaceInfo .MacAddress ,
203- NICType : nicType ,
204- SkipDefaultRoutes : false ,
252+ } else {
253+ // routes for IPv6 podCIDR traffic
254+ for _ , podCIDRv6 := range podCIDRv6 {
255+ podCIDRv6Route := cns.Route {
256+ IPAddress : podCIDRv6 ,
257+ GatewayIPAddress : overlayGatewayV6 ,
258+ }
259+ podIPInfo .Routes = append (podIPInfo .Routes , podCIDRv6Route )
260+ }
261+ // route for IPv6 serviceCIDR traffic
262+ for _ , serviceCIDRv6 := range serviceCIDRsV6 {
263+ serviceCIDRv6Route := cns.Route {
264+ IPAddress : serviceCIDRv6 ,
265+ GatewayIPAddress : overlayGatewayV6 ,
266+ }
267+ podIPInfo .Routes = append (podIPInfo .Routes , serviceCIDRv6Route )
268+ }
269+ // route for IPv6 infraVNETCIDR traffic
270+ for _ , infraVNETCIDRv6 := range infraVNETCIDRsv6 {
271+ infraVNETCIDRv6Route := cns.Route {
272+ IPAddress : infraVNETCIDRv6 ,
273+ GatewayIPAddress : overlayGatewayV6 ,
274+ }
275+ podIPInfo .Routes = append (podIPInfo .Routes , infraVNETCIDRv6Route )
205276 }
206277 }
278+ podIPInfo .SkipDefaultRoutes = true
279+ case cns .BackendNIC :
280+ default :
281+ return errInvalidSWIFTv2NICType
207282 }
208-
209- return podIPInfos , nil
283+ return nil
210284}
0 commit comments