@@ -7,18 +7,75 @@ import (
77 "errors"
88 "fmt"
99 "net"
10+ "os"
1011 "runtime"
1112 "strconv"
1213
1314 "github.com/coreos/go-iptables/iptables"
1415 "github.com/vishvananda/netlink"
1516 "github.com/vishvananda/netns"
1617 "go.uber.org/zap"
18+ "golang.org/x/sys/unix"
1719
1820 "github.com/e2b-dev/infra/packages/shared/pkg/logger"
1921)
2022
21- func (s * Slot ) CreateNetwork (ctx context.Context ) error {
23+ type notExistError interface {
24+ IsNotExist () bool
25+ }
26+
27+ type multiUnwrapError interface {
28+ Unwrap () []error
29+ }
30+
31+ func ignoreExpectedAbsent (err error , isExpected func (error ) bool ) bool {
32+ if err == nil {
33+ return true
34+ }
35+
36+ var joined multiUnwrapError
37+ if errors .As (err , & joined ) {
38+ for _ , child := range joined .Unwrap () {
39+ if ! ignoreExpectedAbsent (child , isExpected ) {
40+ return false
41+ }
42+ }
43+
44+ return true
45+ }
46+
47+ return isExpected (err )
48+ }
49+
50+ func isIPTablesNotExist (err error ) bool {
51+ var notExist notExistError
52+
53+ return errors .As (err , & notExist ) && notExist .IsNotExist ()
54+ }
55+
56+ func isRouteNotExist (err error ) bool {
57+ return errors .Is (err , unix .ESRCH ) || errors .Is (err , unix .ENOENT )
58+ }
59+
60+ func isLinkNotExist (err error ) bool {
61+ var linkNotFound netlink.LinkNotFoundError
62+
63+ return errors .As (err , & linkNotFound ) || errors .Is (err , unix .ENODEV ) || errors .Is (err , unix .ENOENT )
64+ }
65+
66+ func isNamespaceNotExist (err error ) bool {
67+ return os .IsNotExist (err ) || errors .Is (err , unix .ENOENT )
68+ }
69+
70+ func appendUnlessExpectedAbsentf (errs * []error , err error , isExpected func (error ) bool , format string ) {
71+ if ignoreExpectedAbsent (err , isExpected ) {
72+ return
73+ }
74+
75+ * errs = append (* errs , fmt .Errorf (format , err ))
76+ }
77+
78+ func (s * Slot ) CreateNetwork (ctx context.Context ) (retErr error ) {
2279 // Prevent thread changes so we can safely manipulate with namespaces
2380 runtime .LockOSThread ()
2481 defer runtime .UnlockOSThread ()
@@ -29,10 +86,19 @@ func (s *Slot) CreateNetwork(ctx context.Context) error {
2986 return fmt .Errorf ("cannot get current (host) namespace: %w" , err )
3087 }
3188
89+ cleanupNeeded := false
3290 defer func () {
33- err = netns .Set (hostNS )
34- if err != nil {
35- logger .L ().Error (ctx , "error resetting network namespace back to the host namespace" , zap .Error (err ))
91+ restoreErr := netns .Set (hostNS )
92+ if restoreErr != nil {
93+ logger .L ().Error (ctx , "error resetting network namespace back to the host namespace" , zap .Error (restoreErr ))
94+ }
95+
96+ if retErr != nil && cleanupNeeded {
97+ if restoreErr != nil {
98+ retErr = errors .Join (retErr , fmt .Errorf ("error resetting network namespace back to the host namespace before cleanup: %w" , restoreErr ))
99+ } else if cleanupErr := s .RemoveNetwork (); cleanupErr != nil {
100+ retErr = errors .Join (retErr , fmt .Errorf ("error cleaning up partially created network: %w" , cleanupErr ))
101+ }
36102 }
37103
38104 err = hostNS .Close ()
@@ -46,6 +112,7 @@ func (s *Slot) CreateNetwork(ctx context.Context) error {
46112 if err != nil {
47113 return fmt .Errorf ("cannot create new namespace: %w" , err )
48114 }
115+ cleanupNeeded = true
49116
50117 defer ns .Close ()
51118
@@ -273,85 +340,67 @@ func (s *Slot) RemoveNetwork() error {
273340 } else {
274341 // Delete host forwarding rules
275342 err = tables .Delete ("filter" , "FORWARD" , "-i" , s .VethName (), "-o" , defaultGateway , "-j" , "ACCEPT" )
276- if err != nil {
277- errs = append (errs , fmt .Errorf ("error deleting host forwarding rule to default gateway: %w" , err ))
278- }
343+ appendUnlessExpectedAbsentf (& errs , err , isIPTablesNotExist , "error deleting host forwarding rule to default gateway: %w" )
279344
280345 err = tables .Delete ("filter" , "FORWARD" , "-i" , defaultGateway , "-o" , s .VethName (), "-j" , "ACCEPT" )
281- if err != nil {
282- errs = append (errs , fmt .Errorf ("error deleting host forwarding rule from default gateway: %w" , err ))
283- }
346+ appendUnlessExpectedAbsentf (& errs , err , isIPTablesNotExist , "error deleting host forwarding rule from default gateway: %w" )
284347
285348 // Delete host postrouting rules
286349 err = tables .Delete ("nat" , "POSTROUTING" , "-s" , s .HostCIDR (), "-o" , defaultGateway , "-j" , "MASQUERADE" )
287- if err != nil {
288- errs = append (errs , fmt .Errorf ("error deleting host postrouting rule: %w" , err ))
289- }
350+ appendUnlessExpectedAbsentf (& errs , err , isIPTablesNotExist , "error deleting host postrouting rule: %w" )
290351
291352 // Delete hyperloop proxy redirect rule
292353 err = tables .Delete (
293354 "nat" , "PREROUTING" , "-i" , s .VethName (),
294355 "-p" , "tcp" , "-d" , s .config .OrchestratorInSandboxIPAddress , "--dport" , "80" ,
295356 "-j" , "REDIRECT" , "--to-port" , s .hyperloopPort ,
296357 )
297- if err != nil {
298- errs = append (errs , fmt .Errorf ("error deleting sandbox hyperloop proxy redirect rule: %w" , err ))
299- }
358+ appendUnlessExpectedAbsentf (& errs , err , isIPTablesNotExist , "error deleting sandbox hyperloop proxy redirect rule: %w" )
300359
301360 // Delete changes made by egress proxy
302361 err = s .egressProxy .OnSlotDelete (s , tables )
303- if err != nil {
304- errs = append (errs , err )
305- }
362+ appendUnlessExpectedAbsentf (& errs , err , isIPTablesNotExist , "%w" )
306363 }
307364
308365 // Delete routing from host to FC namespace
309366 err = netlink .RouteDel (& netlink.Route {
310367 Gw : s .VpeerIP (),
311368 Dst : s .HostNet (),
312369 })
313- if err != nil {
314- errs = append (errs , fmt .Errorf ("error deleting route from host to FC: %w" , err ))
315- }
370+ appendUnlessExpectedAbsentf (& errs , err , isRouteNotExist , "error deleting route from host to FC: %w" )
316371
317372 // Delete veth device
318373 // We explicitly delete the veth device from the host namespace because even though deleting
319374 // is deleting the device there may be a race condition when creating a new veth device with
320375 // the same name immediately after deleting the namespace.
321376 veth , err := netlink .LinkByName (s .VethName ())
322377 if err != nil {
323- errs = append ( errs , fmt . Errorf ( "error finding veth: %w" , err ) )
378+ appendUnlessExpectedAbsentf ( & errs , err , isLinkNotExist , "error finding veth: %w" )
324379 } else {
325380 err = netlink .LinkDel (veth )
326- if err != nil {
327- errs = append (errs , fmt .Errorf ("error deleting veth device: %w" , err ))
328- }
381+ appendUnlessExpectedAbsentf (& errs , err , isLinkNotExist , "error deleting veth device: %w" )
329382 }
330383
331- // Delete NFS proxy redirect rule
332- err = tables .Delete ("nat" , "PREROUTING" ,
333- "--in-interface" , s .VethName (), "--protocol" , "tcp" ,
334- "--destination" , s .config .OrchestratorInSandboxIPAddress , "--dport" , "2049" ,
335- "--jump" , "REDIRECT" , "--to-port" , strconv .Itoa (int (s .config .NFSProxyPort )),
336- )
337- if err != nil {
338- errs = append (errs , fmt .Errorf ("error deleting sandbox NFS proxy redirect rule: %w" , err ))
339- }
384+ if tables != nil {
385+ // Delete NFS proxy redirect rule
386+ err = tables .Delete ("nat" , "PREROUTING" ,
387+ "--in-interface" , s .VethName (), "--protocol" , "tcp" ,
388+ "--destination" , s .config .OrchestratorInSandboxIPAddress , "--dport" , "2049" ,
389+ "--jump" , "REDIRECT" , "--to-port" , strconv .Itoa (int (s .config .NFSProxyPort )),
390+ )
391+ appendUnlessExpectedAbsentf (& errs , err , isIPTablesNotExist , "error deleting sandbox NFS proxy redirect rule: %w" )
340392
341- // Delete portmapper redirect rule
342- err = tables .Delete ("nat" , "PREROUTING" ,
343- "--in-interface" , s .VethName (), "--protocol" , "tcp" ,
344- "--destination" , s .config .OrchestratorInSandboxIPAddress , "--dport" , "111" ,
345- "--jump" , "REDIRECT" , "--to-port" , strconv .Itoa (int (s .config .PortmapperPort )),
346- )
347- if err != nil {
348- errs = append (errs , fmt .Errorf ("error deleting sandbox portmapper redirect rule: %w" , err ))
393+ // Delete portmapper redirect rule
394+ err = tables .Delete ("nat" , "PREROUTING" ,
395+ "--in-interface" , s .VethName (), "--protocol" , "tcp" ,
396+ "--destination" , s .config .OrchestratorInSandboxIPAddress , "--dport" , "111" ,
397+ "--jump" , "REDIRECT" , "--to-port" , strconv .Itoa (int (s .config .PortmapperPort )),
398+ )
399+ appendUnlessExpectedAbsentf (& errs , err , isIPTablesNotExist , "error deleting sandbox portmapper redirect rule: %w" )
349400 }
350401
351402 err = netns .DeleteNamed (s .NamespaceID ())
352- if err != nil {
353- errs = append (errs , fmt .Errorf ("error deleting namespace: %w" , err ))
354- }
403+ appendUnlessExpectedAbsentf (& errs , err , isNamespaceNotExist , "error deleting namespace: %w" )
355404
356405 return errors .Join (errs ... )
357406}
0 commit comments