@@ -2,6 +2,7 @@ package sriov
22
33import (
44 "fmt"
5+ "net"
56
67 "github.com/containernetworking/plugins/pkg/ns"
78 "github.com/vishvananda/netlink"
@@ -67,81 +68,96 @@ func NewSriovManager() Manager {
6768func (s * sriovManager ) SetupVF (conf * sriovtypes.NetConf , podifName string , netns ns.NetNS ) error {
6869 linkName := conf .OrigVfState .HostIFName
6970
70- linkObj , err := s .nLink .LinkByName (linkName )
71+ // Save the original NS in case we need to restore it
72+ // after an error occurs
73+ initns , _ := ns .GetCurrentNS ()
74+
75+ tempNS , err := ns .TempNetNS ()
7176 if err != nil {
72- return fmt .Errorf ("error getting VF netdevice with name %s " , linkName )
77+ return fmt .Errorf ("failed to create tempNS: %v " , err )
7378 }
79+ defer tempNS .Close ()
7480
81+ linkObj , err := s .nLink .LinkByName (linkName )
82+ if err != nil {
83+ return fmt .Errorf ("error: %v. Failed to get VF netdevice with name %s" , err , linkName )
84+ }
85+ if linkObj .Attrs ().Flags & net .FlagUp == net .FlagUp {
86+ defer func () {
87+ if err != nil {
88+ logging .Debug ("Setting link up in defer because of " , "error" , err )
89+ if linkObj , err := s .nLink .LinkByName (linkName ); err == nil {
90+ _ = s .nLink .LinkSetUp (linkObj )
91+ }
92+ }
93+ }()
94+ }
7595 // Save the original effective MAC address before overriding it
7696 conf .OrigVfState .EffectiveMAC = linkObj .Attrs ().HardwareAddr .String ()
7797
78- // tempName used as intermediary name to avoid name conflicts
79- tempName := fmt .Sprintf ("%s%d" , "temp_" , linkObj .Attrs ().Index )
80-
81- // 1. Set link down
82- logging .Debug ("1. Set link down" ,
98+ // 1.Move interface to tempNS
99+ logging .Debug ("1. Move the interface to tempNS" ,
83100 "func" , "SetupVF" ,
84101 "linkObj" , linkObj )
85- if err := s .nLink .LinkSetDown (linkObj ); err != nil {
86- return fmt .Errorf ("failed to down vf device %q: %v" , linkName , err )
87- }
88-
89- // 2. Set temp name
90- logging .Debug ("2. Set temp name" ,
91- "func" , "SetupVF" ,
92- "linkObj" , linkObj ,
93- "tempName" , tempName )
94- if err := s .nLink .LinkSetName (linkObj , tempName ); err != nil {
95- return fmt .Errorf ("error setting temp IF name %s for %s" , tempName , linkName )
102+ if err = s .nLink .LinkSetNsFd (linkObj , int (tempNS .Fd ())); err != nil {
103+ return fmt .Errorf ("failed to move %q to tempNS: %v" , linkName , err )
96104 }
105+ err = tempNS .Do (func (linkNS ns.NetNS ) error {
106+ // lookup the device in tempNS (index might have changed)
107+ tempNSLinkObj , err := s .nLink .LinkByName (linkName )
108+ if err != nil {
109+ return fmt .Errorf ("failed to find %q in tempNS: %v" , linkName , err )
110+ }
111+ // Rename the interface to pod interface name
112+ if err = s .nLink .LinkSetName (tempNSLinkObj , podifName ); err != nil {
113+ return fmt .Errorf ("failed to rename host device %q to %q: %v" , linkName , podifName , err )
114+ }
97115
98- // 3. Remove alt name from the nic
99- logging .Debug ("3. Remove interface original name from alt names" ,
100- "func" , "SetupVF" ,
101- "linkObj" , linkObj ,
102- "OriginalLinkName" , linkName ,
103- "tempName" , tempName )
104- linkObj , err = s .nLink .LinkByName (tempName )
105- if err != nil {
106- return fmt .Errorf ("error getting VF netdevice with name %s: %v" , tempName , err )
107- }
108- for _ , altName := range linkObj .Attrs ().AltNames {
109- if altName == linkName {
110- if err := s .nLink .LinkDelAltName (linkObj , linkName ); err != nil {
111- return fmt .Errorf ("error removing VF altname %s: %v" , linkName , err )
116+ // 3. Remove alt name from the nic
117+ logging .Debug ("3. Remove interface original name from alt names" ,
118+ "func" , "SetupVF" ,
119+ "tempNSObj" , tempNSLinkObj ,
120+ "OriginalLinkName" , linkName )
121+ for _ , altName := range tempNSLinkObj .Attrs ().AltNames {
122+ if altName == linkName {
123+ if err = s .nLink .LinkDelAltName (tempNSLinkObj , linkName ); err != nil {
124+ return fmt .Errorf ("error removing VF altname %s: %v" , linkName , err )
125+ }
112126 }
113127 }
114- }
115128
116- // 4. Change netns
117- logging .Debug ("4. Change netns" ,
118- "func" , "SetupVF" ,
119- "linkObj" , linkObj ,
120- "netns.Fd()" , int (netns .Fd ()))
121- if err := s .nLink .LinkSetNsFd (linkObj , int (netns .Fd ())); err != nil {
122- return fmt .Errorf ("failed to move IF %s to netns: %q" , tempName , err )
129+ // 4. Change netns
130+ logging .Debug ("4. Change netns" ,
131+ "func" , "SetupVF" ,
132+ "tempNSObj" , tempNSLinkObj ,
133+ "netns.Fd()" , int (netns .Fd ()))
134+ if err = s .nLink .LinkSetNsFd (tempNSLinkObj , int (netns .Fd ())); err != nil {
135+ return fmt .Errorf ("failed to move IF %s to netns: %q" , podifName , err )
136+ }
137+ return nil
138+ })
139+ if err != nil {
140+ logging .Debug ("Move the interface back to initNS because of " , "error" , err )
141+ s .cleanupLinkInTempNS (tempNS , podifName , linkName , initns )
142+ return err
123143 }
124144
125- if err := netns .Do (func (_ ns.NetNS ) error {
126- // 5. Set Pod IF name
127- logging .Debug ("5. Set Pod IF name" ,
128- "func" , "SetupVF" ,
129- "linkObj" , linkObj ,
130- "podifName" , podifName )
131- if err := s .nLink .LinkSetName (linkObj , podifName ); err != nil {
132- return fmt .Errorf ("error setting container interface name %s for %s" , linkName , tempName )
145+ err = netns .Do (func (_ ns.NetNS ) error {
146+ netNSLinkObj , err := s .nLink .LinkByName (podifName )
147+ if err != nil {
148+ return fmt .Errorf ("error: %v. Failed to get VF netdevice with name %s" , err , podifName )
133149 }
134150
135- // 6 . Enable IPv4 ARP notify and IPv6 Network Discovery notify
151+ // 5 . Enable IPv4 ARP notify and IPv6 Network Discovery notify
136152 // Error is ignored here because enabling this feature is only a performance enhancement.
137- logging .Debug ("6 . Enable IPv4 ARP notify and IPv6 Network Discovery notify" ,
153+ logging .Debug ("5 . Enable IPv4 ARP notify and IPv6 Network Discovery notify" ,
138154 "func" , "SetupVF" ,
139155 "podifName" , podifName )
140156 _ = s .utils .EnableArpAndNdiscNotify (podifName )
141157
142- // 7 . Set MAC address
158+ // 6 . Set MAC address
143159 if conf .MAC != "" {
144- logging .Debug ("7 . Set MAC address" ,
160+ logging .Debug ("6 . Set MAC address" ,
145161 "func" , "SetupVF" ,
146162 "s.nLink" , s .nLink ,
147163 "podifName" , podifName ,
@@ -152,37 +168,77 @@ func (s *sriovManager) SetupVF(conf *sriovtypes.NetConf, podifName string, netns
152168 }
153169 }
154170
155- logging .Debug ("8 . Enable Optimistic DAD for IPv6 addresses" , "func" , "SetupVF" ,
156- "linkObj" , linkObj )
171+ logging .Debug ("7 . Enable Optimistic DAD for IPv6 addresses" , "func" , "SetupVF" ,
172+ "linkObj" , netNSLinkObj )
157173 _ = s .utils .EnableOptimisticDad (podifName )
158174
159- // 9 . Bring IF up in Pod netns
160- logging .Debug ("9 . Bring IF up in Pod netns" ,
175+ // 8 . Bring IF up in Pod netns
176+ logging .Debug ("8 . Bring IF up in Pod netns" ,
161177 "func" , "SetupVF" ,
162- "linkObj" , linkObj )
163- if err : = s .nLink .LinkSetUp (linkObj ); err != nil {
178+ "linkObj" , netNSLinkObj )
179+ if err = s .nLink .LinkSetUp (netNSLinkObj ); err != nil {
164180 return fmt .Errorf ("error bringing interface up in container ns: %q" , err )
165181 }
166182
167183 return nil
168- }); err != nil {
169- return fmt .Errorf ("error setting up interface in container namespace: %q" , err )
184+ })
185+ if err != nil {
186+ // Cleanup: try to move interface back to tempNS
187+ logging .Debug ("Move the interface back to tempNS because of " , "error" , err )
188+ _ = netns .Do (func (_ ns.NetNS ) error {
189+ if netNSLinkObj , e := s .nLink .LinkByName (podifName ); e == nil {
190+ linkSetNsFdError := s .nLink .LinkSetNsFd (netNSLinkObj , int (tempNS .Fd ()))
191+ if linkSetNsFdError != nil {
192+ logging .Debug ("LinkSetNsFd failed when trying to move back to tempNS" , "error" , linkSetNsFdError )
193+ }
194+ }
195+ return nil
196+ })
197+ // Restore the original link name in case of error in renaming
198+ s .cleanupLinkInTempNS (tempNS , podifName , linkName , initns )
199+ return err
170200 }
171201
172202 // Copy the MTU value to a new variable
173203 // and use it as a pointer
174204 vfMTU := linkObj .Attrs ().MTU
175205 conf .MTU = & vfMTU
176-
177206 return nil
178207}
179208
209+ // cleanupLinkInTempNS restores the original link name and moves it back to initns
210+ func (s * sriovManager ) cleanupLinkInTempNS (tempNS ns.NetNS , podifName , linkName string , initns ns.NetNS ) {
211+ _ = tempNS .Do (func (_ ns.NetNS ) error {
212+ // Restore the original link name in case of error in renaming
213+ if tempNSLinkObj , err := s .nLink .LinkByName (podifName ); err == nil {
214+ linkSetNameError := s .nLink .LinkSetName (tempNSLinkObj , linkName )
215+ if linkSetNameError != nil {
216+ logging .Debug ("LinkSetName failed when trying to restore original name" , "error" , linkSetNameError )
217+ }
218+ }
219+
220+ // Try to move interface back to initns
221+ if tempNSLinkObj , e := s .nLink .LinkByName (linkName ); e == nil {
222+ linkSetNsFdError := s .nLink .LinkSetNsFd (tempNSLinkObj , int (initns .Fd ()))
223+ if linkSetNsFdError != nil {
224+ logging .Debug ("LinkSetNsFd failed when trying to move back to initns in case of an error" , "error" , linkSetNsFdError )
225+ }
226+ }
227+ return nil
228+ })
229+ }
230+
180231// ReleaseVF reset a VF from Pod netns and return it to init netns
181232func (s * sriovManager ) ReleaseVF (conf * sriovtypes.NetConf , podifName string , netns ns.NetNS ) error {
182233 initns , err := ns .GetCurrentNS ()
183234 if err != nil {
184235 return fmt .Errorf ("failed to get init netns: %v" , err )
185236 }
237+ tempNS , err := ns .TempNetNS ()
238+ if err != nil {
239+ return fmt .Errorf ("failed to create tempNS: %v" , err )
240+ }
241+ defer tempNS .Close ()
186242
187243 return netns .Do (func (_ ns.NetNS ) error {
188244 // get VF device
@@ -202,51 +258,82 @@ func (s *sriovManager) ReleaseVF(conf *sriovtypes.NetConf, podifName string, net
202258 return fmt .Errorf ("failed to set link %s down: %q" , podifName , err )
203259 }
204260
205- // rename VF device
206- logging .Debug ("Rename VF device" ,
261+ logging .Debug ("Move VF device to temp netns" ,
207262 "func" , "ReleaseVF" ,
208263 "linkObj" , linkObj ,
209- "conf.OrigVfState.HostIFName" , conf .OrigVfState .HostIFName )
210- err = s .nLink .LinkSetName (linkObj , conf .OrigVfState .HostIFName )
211- if err != nil {
212- return fmt .Errorf ("failed to rename link %s to host name %s: %q" , podifName , conf .OrigVfState .HostIFName , err )
264+ "tempNS.Fd()" , int (tempNS .Fd ()))
265+ if err = s .nLink .LinkSetNsFd (linkObj , int (tempNS .Fd ())); err != nil {
266+ return fmt .Errorf ("failed to move interface %s to temp netns: %v" , podifName , err )
213267 }
214268
215- if conf .MAC != "" {
216- // reset effective MAC address
217- logging .Debug ("Reset effective MAC address" ,
218- "func" , "ReleaseVF" ,
219- "s.nLink" , s .nLink ,
220- "conf.OrigVfState.HostIFName" , conf .OrigVfState .HostIFName ,
221- "conf.OrigVfState.EffectiveMAC" , conf .OrigVfState .EffectiveMAC )
222- err = utils .SetVFEffectiveMAC (s .nLink , conf .OrigVfState .HostIFName , conf .OrigVfState .EffectiveMAC )
269+ err = tempNS .Do (func (hostNS ns.NetNS ) error {
270+ tempNSLinkObj , err := s .nLink .LinkByName (podifName )
223271 if err != nil {
224- return fmt .Errorf ("failed to restore original effective netlink MAC address %s : %v" , conf . OrigVfState . EffectiveMAC , err )
272+ return fmt .Errorf ("failed to find %q in tempNS : %v" , podifName , err )
225273 }
226- }
227274
228- // reset MTU for VF device until if the MTU was captured in the cache
229- if conf .OrigVfState .MTU != 0 {
230- logging .Debug ("Reset VF device MTU" ,
231- "func" , "ReleaseVF" ,
232- "linkObj" , linkObj ,
233- "conf.OrigVfState.HostIFName" , conf .OrigVfState .HostIFName ,
234- "conf.OrigVfState.MTU" , conf .OrigVfState .MTU )
235- err = s .nLink .LinkSetMTU (linkObj , conf .OrigVfState .MTU )
236- if err != nil {
237- return fmt .Errorf ("failed to reset MTU for link link %s: %q" , conf .OrigVfState .HostIFName , err )
275+ // Move the interface back to netns on error
276+ defer func () {
277+ if err != nil {
278+ logging .Debug ("Moving the interface back to netns because of " , "error" , err )
279+ linkSetNsFdError := s .nLink .LinkSetNsFd (tempNSLinkObj , int (netns .Fd ()))
280+ if linkSetNsFdError != nil {
281+ logging .Debug ("LinkSetNsFd failed in defer" , "error" , linkSetNsFdError )
282+ }
283+ }
284+ }()
285+
286+ // Rename interface to linkName
287+ if err = s .nLink .LinkSetName (tempNSLinkObj , conf .OrigVfState .HostIFName ); err != nil {
288+ return fmt .Errorf ("failed to rename device %q to %q: %v" , podifName , conf .OrigVfState .HostIFName , err )
238289 }
239- }
240290
241- // move VF device to init netns
242- logging .Debug ("Move VF device to init netns" ,
243- "func" , "ReleaseVF" ,
244- "linkObj" , linkObj ,
245- "initns.Fd()" , int (initns .Fd ()))
246- if err = s .nLink .LinkSetNsFd (linkObj , int (initns .Fd ())); err != nil {
247- return fmt .Errorf ("failed to move interface %s to init netns: %v" , conf .OrigVfState .HostIFName , err )
248- }
291+ // Rename the interface back to podIfName on error
292+ defer func () {
293+ if err != nil {
294+ logging .Debug ("Renaming the interface back to podIfName because of " , "error" , err )
295+ LinkSetNameError := s .nLink .LinkSetName (tempNSLinkObj , podifName )
296+ if LinkSetNameError != nil {
297+ logging .Debug ("LinkSetName failed in defer" , "error" , LinkSetNameError )
298+ }
299+ }
300+ }()
301+
302+ if conf .MAC != "" {
303+ // reset effective MAC address
304+ logging .Debug ("Reset effective MAC address" ,
305+ "func" , "ReleaseVF" ,
306+ "s.nLink" , s .nLink ,
307+ "conf.OrigVfState.HostIFName" , conf .OrigVfState .HostIFName ,
308+ "conf.OrigVfState.EffectiveMAC" , conf .OrigVfState .EffectiveMAC )
309+ err = utils .SetVFEffectiveMAC (s .nLink , conf .OrigVfState .HostIFName , conf .OrigVfState .EffectiveMAC )
310+ if err != nil {
311+ return fmt .Errorf ("failed to restore original effective netlink MAC address %s: %v" , conf .OrigVfState .EffectiveMAC , err )
312+ }
313+ }
314+
315+ // reset MTU for VF device until if the MTU was captured in the cache
316+ if conf .OrigVfState .MTU != 0 {
317+ logging .Debug ("Reset VF device MTU" ,
318+ "func" , "ReleaseVF" ,
319+ "linkObj" , linkObj ,
320+ "conf.OrigVfState.HostIFName" , conf .OrigVfState .HostIFName ,
321+ "conf.OrigVfState.MTU" , conf .OrigVfState .MTU )
322+ err = s .nLink .LinkSetMTU (tempNSLinkObj , conf .OrigVfState .MTU )
323+ if err != nil {
324+ return fmt .Errorf ("failed to reset MTU for link link %s: %q" , conf .OrigVfState .HostIFName , err )
325+ }
326+ }
249327
328+ // Finally move the interface to the initns
329+ if err = s .nLink .LinkSetNsFd (tempNSLinkObj , int (initns .Fd ())); err != nil {
330+ return fmt .Errorf ("failed to move %q to initns: %v" , conf .OrigVfState .HostIFName , err )
331+ }
332+ return nil
333+ })
334+ if err != nil {
335+ return fmt .Errorf ("error setting up interface in temp namespace: %q" , err )
336+ }
250337 return nil
251338 })
252339}
@@ -273,7 +360,6 @@ func (s *sriovManager) ApplyVFConfig(conf *sriovtypes.NetConf) error {
273360 return fmt .Errorf ("failed to set vf %d vlan configuration - id %d, qos %d and proto %s: %v" , conf .VFID , * conf .Vlan , * conf .VlanQoS , * conf .VlanProto , err )
274361 }
275362 }
276-
277363 // 2. Set mac address
278364 if conf .MAC != "" {
279365 // when we restore the original hardware mac address we may get a device or resource busy. so we introduce retry
0 commit comments