netns_linux.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package netlink
  2. // Network namespace ID functions
  3. //
  4. // The kernel has a weird concept called the network namespace ID.
  5. // This is different from the file reference in proc (and any bind-mounted
  6. // namespaces, etc.)
  7. //
  8. // Instead, namespaces can be assigned a numeric ID at any time. Once set,
  9. // the ID is fixed. The ID can either be set manually by the user, or
  10. // automatically, triggered by certain kernel actions. The most common kernel
  11. // action that triggers namespace ID creation is moving one end of a veth pair
  12. // in to that namespace.
  13. import (
  14. "fmt"
  15. "github.com/vishvananda/netlink/nl"
  16. "golang.org/x/sys/unix"
  17. )
  18. // These can be replaced by the values from sys/unix when it is next released.
  19. const (
  20. _ = iota
  21. NETNSA_NSID
  22. NETNSA_PID
  23. NETNSA_FD
  24. )
  25. // GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
  26. // Returns -1 if the namespace does not have an ID set.
  27. func (h *Handle) GetNetNsIdByPid(pid int) (int, error) {
  28. return h.getNetNsId(NETNSA_PID, uint32(pid))
  29. }
  30. // GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
  31. // Returns -1 if the namespace does not have an ID set.
  32. func GetNetNsIdByPid(pid int) (int, error) {
  33. return pkgHandle.GetNetNsIdByPid(pid)
  34. }
  35. // SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
  36. // The ID can only be set for namespaces without an ID already set.
  37. func (h *Handle) SetNetNsIdByPid(pid, nsid int) error {
  38. return h.setNetNsId(NETNSA_PID, uint32(pid), uint32(nsid))
  39. }
  40. // SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
  41. // The ID can only be set for namespaces without an ID already set.
  42. func SetNetNsIdByPid(pid, nsid int) error {
  43. return pkgHandle.SetNetNsIdByPid(pid, nsid)
  44. }
  45. // GetNetNsIdByPid looks up the network namespace ID for a given fd.
  46. // fd must be an open file descriptor to a namespace file.
  47. // Returns -1 if the namespace does not have an ID set.
  48. func (h *Handle) GetNetNsIdByFd(fd int) (int, error) {
  49. return h.getNetNsId(NETNSA_FD, uint32(fd))
  50. }
  51. // GetNetNsIdByPid looks up the network namespace ID for a given fd.
  52. // fd must be an open file descriptor to a namespace file.
  53. // Returns -1 if the namespace does not have an ID set.
  54. func GetNetNsIdByFd(fd int) (int, error) {
  55. return pkgHandle.GetNetNsIdByFd(fd)
  56. }
  57. // SetNetNSIdByFd sets the ID of the network namespace for a given fd.
  58. // fd must be an open file descriptor to a namespace file.
  59. // The ID can only be set for namespaces without an ID already set.
  60. func (h *Handle) SetNetNsIdByFd(fd, nsid int) error {
  61. return h.setNetNsId(NETNSA_FD, uint32(fd), uint32(nsid))
  62. }
  63. // SetNetNSIdByFd sets the ID of the network namespace for a given fd.
  64. // fd must be an open file descriptor to a namespace file.
  65. // The ID can only be set for namespaces without an ID already set.
  66. func SetNetNsIdByFd(fd, nsid int) error {
  67. return pkgHandle.SetNetNsIdByFd(fd, nsid)
  68. }
  69. // getNetNsId requests the netnsid for a given type-val pair
  70. // type should be either NETNSA_PID or NETNSA_FD
  71. func (h *Handle) getNetNsId(attrType int, val uint32) (int, error) {
  72. req := h.newNetlinkRequest(unix.RTM_GETNSID, unix.NLM_F_REQUEST)
  73. rtgen := nl.NewRtGenMsg()
  74. req.AddData(rtgen)
  75. b := make([]byte, 4, 4)
  76. native.PutUint32(b, val)
  77. attr := nl.NewRtAttr(attrType, b)
  78. req.AddData(attr)
  79. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
  80. if err != nil {
  81. return 0, err
  82. }
  83. for _, m := range msgs {
  84. msg := nl.DeserializeRtGenMsg(m)
  85. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  86. if err != nil {
  87. return 0, err
  88. }
  89. for _, attr := range attrs {
  90. switch attr.Attr.Type {
  91. case NETNSA_NSID:
  92. return int(int32(native.Uint32(attr.Value))), nil
  93. }
  94. }
  95. }
  96. return 0, fmt.Errorf("unexpected empty result")
  97. }
  98. // setNetNsId sets the netnsid for a given type-val pair
  99. // type should be either NETNSA_PID or NETNSA_FD
  100. // The ID can only be set for namespaces without an ID already set
  101. func (h *Handle) setNetNsId(attrType int, val uint32, newnsid uint32) error {
  102. req := h.newNetlinkRequest(unix.RTM_NEWNSID, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
  103. rtgen := nl.NewRtGenMsg()
  104. req.AddData(rtgen)
  105. b := make([]byte, 4, 4)
  106. native.PutUint32(b, val)
  107. attr := nl.NewRtAttr(attrType, b)
  108. req.AddData(attr)
  109. b1 := make([]byte, 4, 4)
  110. native.PutUint32(b1, newnsid)
  111. attr1 := nl.NewRtAttr(NETNSA_NSID, b1)
  112. req.AddData(attr1)
  113. _, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
  114. return err
  115. }