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