netns_110.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. // Copyright (c) 2016 Arista Networks, Inc.
  2. // Use of this source code is governed by the Apache License 2.0
  3. // that can be found in the COPYING file.
  4. // +build go1.10
  5. package netns
  6. import (
  7. "fmt"
  8. "os"
  9. "runtime"
  10. )
  11. // Do takes a function which it will call in the network namespace specified by nsName.
  12. // The goroutine that calls this will lock itself to its current OS thread, hop
  13. // namespaces, call the given function, hop back to its original namespace, and then
  14. // unlock itself from its current OS thread.
  15. // Do returns an error if an error occurs at any point besides in the invocation of
  16. // the given function, or if the given function itself returns an error.
  17. //
  18. // The callback function is expected to do something simple such as just
  19. // creating a socket / opening a connection, as it's not desirable to start
  20. // complex logic in a goroutine that is pinned to the current OS thread.
  21. // Also any goroutine started from the callback function may or may not
  22. // execute in the desired namespace.
  23. func Do(nsName string, cb Callback) error {
  24. // If destNS is empty, the function is called in the caller's namespace
  25. if nsName == "" {
  26. return cb()
  27. }
  28. // Get the file descriptor to the current namespace
  29. currNsFd, err := getNs(selfNsFile)
  30. if os.IsNotExist(err) {
  31. return fmt.Errorf("File descriptor to current namespace does not exist: %s", err)
  32. } else if err != nil {
  33. return fmt.Errorf("Failed to open %s: %s", selfNsFile, err)
  34. }
  35. defer currNsFd.close()
  36. runtime.LockOSThread()
  37. defer runtime.UnlockOSThread()
  38. // Jump to the new network namespace
  39. if err := setNsByName(nsName); err != nil {
  40. return fmt.Errorf("Failed to set the namespace to %s: %s", nsName, err)
  41. }
  42. // Call the given function
  43. cbErr := cb()
  44. // Come back to the original namespace
  45. if err = setNs(currNsFd); err != nil {
  46. return fmt.Errorf("Failed to return to the original namespace: %s (callback returned %v)",
  47. err, cbErr)
  48. }
  49. return cbErr
  50. }