namespace_linux.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package sandbox
  2. import (
  3. "fmt"
  4. "net"
  5. "os"
  6. "runtime"
  7. "sync"
  8. "syscall"
  9. "github.com/vishvananda/netlink"
  10. "github.com/vishvananda/netns"
  11. )
  12. const prefix = "/var/lib/docker/network"
  13. var once sync.Once
  14. // The networkNamespace type is the linux implementation of the Sandbox
  15. // interface. It represents a linux network namespace, and moves an interface
  16. // into it when called on method AddInterface or sets the gateway etc.
  17. type networkNamespace struct {
  18. path string
  19. sinfo *Info
  20. }
  21. func createBasePath() {
  22. err := os.MkdirAll(prefix, 0644)
  23. if err != nil && !os.IsExist(err) {
  24. panic("Could not create net namespace path directory")
  25. }
  26. }
  27. // GenerateKey generates a sandbox key based on the passed
  28. // container id.
  29. func GenerateKey(containerID string) string {
  30. maxLen := 12
  31. if len(containerID) < maxLen {
  32. maxLen = len(containerID)
  33. }
  34. return prefix + "/" + containerID[:maxLen]
  35. }
  36. // NewSandbox provides a new sandbox instance created in an os specific way
  37. // provided a key which uniquely identifies the sandbox
  38. func NewSandbox(key string) (Sandbox, error) {
  39. return createNetworkNamespace(key)
  40. }
  41. func createNetworkNamespace(path string) (Sandbox, error) {
  42. runtime.LockOSThread()
  43. defer runtime.UnlockOSThread()
  44. origns, err := netns.Get()
  45. if err != nil {
  46. return nil, err
  47. }
  48. defer origns.Close()
  49. if err := createNamespaceFile(path); err != nil {
  50. return nil, err
  51. }
  52. defer netns.Set(origns)
  53. newns, err := netns.New()
  54. if err != nil {
  55. return nil, err
  56. }
  57. defer newns.Close()
  58. if err := loopbackUp(); err != nil {
  59. return nil, err
  60. }
  61. procNet := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid())
  62. if err := syscall.Mount(procNet, path, "bind", syscall.MS_BIND, ""); err != nil {
  63. return nil, err
  64. }
  65. interfaces := []*Interface{}
  66. sinfo := &Info{Interfaces: interfaces}
  67. return &networkNamespace{path: path, sinfo: sinfo}, nil
  68. }
  69. func createNamespaceFile(path string) (err error) {
  70. var f *os.File
  71. once.Do(createBasePath)
  72. if f, err = os.Create(path); err == nil {
  73. f.Close()
  74. }
  75. return err
  76. }
  77. func loopbackUp() error {
  78. iface, err := netlink.LinkByName("lo")
  79. if err != nil {
  80. return err
  81. }
  82. return netlink.LinkSetUp(iface)
  83. }
  84. func (n *networkNamespace) AddInterface(i *Interface) error {
  85. runtime.LockOSThread()
  86. defer runtime.UnlockOSThread()
  87. origns, err := netns.Get()
  88. if err != nil {
  89. return err
  90. }
  91. defer origns.Close()
  92. f, err := os.OpenFile(n.path, os.O_RDONLY, 0)
  93. if err != nil {
  94. return fmt.Errorf("failed get network namespace %q: %v", n.path, err)
  95. }
  96. defer f.Close()
  97. // Find the network inteerface identified by the SrcName attribute.
  98. iface, err := netlink.LinkByName(i.SrcName)
  99. if err != nil {
  100. return err
  101. }
  102. // Move the network interface to the destination namespace.
  103. nsFD := f.Fd()
  104. if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil {
  105. return err
  106. }
  107. if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
  108. return err
  109. }
  110. defer netns.Set(origns)
  111. // Down the interface before configuring
  112. if err := netlink.LinkSetDown(iface); err != nil {
  113. return err
  114. }
  115. // Configure the interface now this is moved in the proper namespace.
  116. if err := configureInterface(iface, i); err != nil {
  117. return err
  118. }
  119. // Up the interface.
  120. if err := netlink.LinkSetUp(iface); err != nil {
  121. return err
  122. }
  123. n.sinfo.Interfaces = append(n.sinfo.Interfaces, i)
  124. return nil
  125. }
  126. func (n *networkNamespace) SetGateway(gw net.IP) error {
  127. if len(gw) == 0 {
  128. return nil
  129. }
  130. err := programGateway(n.path, gw)
  131. if err == nil {
  132. n.sinfo.Gateway = gw
  133. }
  134. return err
  135. }
  136. func (n *networkNamespace) SetGatewayIPv6(gw net.IP) error {
  137. if len(gw) == 0 {
  138. return nil
  139. }
  140. err := programGateway(n.path, gw)
  141. if err == nil {
  142. n.sinfo.GatewayIPv6 = gw
  143. }
  144. return err
  145. }
  146. func (n *networkNamespace) Interfaces() []*Interface {
  147. return n.sinfo.Interfaces
  148. }
  149. func (n *networkNamespace) Key() string {
  150. return n.path
  151. }
  152. func (n *networkNamespace) Destroy() error {
  153. // Assuming no running process is executing in this network namespace,
  154. // unmounting is sufficient to destroy it.
  155. if err := syscall.Unmount(n.path, syscall.MNT_DETACH); err != nil {
  156. return err
  157. }
  158. return os.Remove(n.path)
  159. }