142 lines
4.4 KiB
Go
142 lines
4.4 KiB
Go
|
package netlink
|
||
|
|
||
|
// Network namespace ID functions
|
||
|
//
|
||
|
// The kernel has a weird concept called the network namespace ID.
|
||
|
// This is different from the file reference in proc (and any bind-mounted
|
||
|
// namespaces, etc.)
|
||
|
//
|
||
|
// Instead, namespaces can be assigned a numeric ID at any time. Once set,
|
||
|
// the ID is fixed. The ID can either be set manually by the user, or
|
||
|
// automatically, triggered by certain kernel actions. The most common kernel
|
||
|
// action that triggers namespace ID creation is moving one end of a veth pair
|
||
|
// in to that namespace.
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/vishvananda/netlink/nl"
|
||
|
"golang.org/x/sys/unix"
|
||
|
)
|
||
|
|
||
|
// These can be replaced by the values from sys/unix when it is next released.
|
||
|
const (
|
||
|
_ = iota
|
||
|
NETNSA_NSID
|
||
|
NETNSA_PID
|
||
|
NETNSA_FD
|
||
|
)
|
||
|
|
||
|
// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
|
||
|
// Returns -1 if the namespace does not have an ID set.
|
||
|
func (h *Handle) GetNetNsIdByPid(pid int) (int, error) {
|
||
|
return h.getNetNsId(NETNSA_PID, uint32(pid))
|
||
|
}
|
||
|
|
||
|
// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
|
||
|
// Returns -1 if the namespace does not have an ID set.
|
||
|
func GetNetNsIdByPid(pid int) (int, error) {
|
||
|
return pkgHandle.GetNetNsIdByPid(pid)
|
||
|
}
|
||
|
|
||
|
// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
|
||
|
// The ID can only be set for namespaces without an ID already set.
|
||
|
func (h *Handle) SetNetNsIdByPid(pid, nsid int) error {
|
||
|
return h.setNetNsId(NETNSA_PID, uint32(pid), uint32(nsid))
|
||
|
}
|
||
|
|
||
|
// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
|
||
|
// The ID can only be set for namespaces without an ID already set.
|
||
|
func SetNetNsIdByPid(pid, nsid int) error {
|
||
|
return pkgHandle.SetNetNsIdByPid(pid, nsid)
|
||
|
}
|
||
|
|
||
|
// GetNetNsIdByFd looks up the network namespace ID for a given fd.
|
||
|
// fd must be an open file descriptor to a namespace file.
|
||
|
// Returns -1 if the namespace does not have an ID set.
|
||
|
func (h *Handle) GetNetNsIdByFd(fd int) (int, error) {
|
||
|
return h.getNetNsId(NETNSA_FD, uint32(fd))
|
||
|
}
|
||
|
|
||
|
// GetNetNsIdByFd looks up the network namespace ID for a given fd.
|
||
|
// fd must be an open file descriptor to a namespace file.
|
||
|
// Returns -1 if the namespace does not have an ID set.
|
||
|
func GetNetNsIdByFd(fd int) (int, error) {
|
||
|
return pkgHandle.GetNetNsIdByFd(fd)
|
||
|
}
|
||
|
|
||
|
// SetNetNSIdByFd sets the ID of the network namespace for a given fd.
|
||
|
// fd must be an open file descriptor to a namespace file.
|
||
|
// The ID can only be set for namespaces without an ID already set.
|
||
|
func (h *Handle) SetNetNsIdByFd(fd, nsid int) error {
|
||
|
return h.setNetNsId(NETNSA_FD, uint32(fd), uint32(nsid))
|
||
|
}
|
||
|
|
||
|
// SetNetNSIdByFd sets the ID of the network namespace for a given fd.
|
||
|
// fd must be an open file descriptor to a namespace file.
|
||
|
// The ID can only be set for namespaces without an ID already set.
|
||
|
func SetNetNsIdByFd(fd, nsid int) error {
|
||
|
return pkgHandle.SetNetNsIdByFd(fd, nsid)
|
||
|
}
|
||
|
|
||
|
// getNetNsId requests the netnsid for a given type-val pair
|
||
|
// type should be either NETNSA_PID or NETNSA_FD
|
||
|
func (h *Handle) getNetNsId(attrType int, val uint32) (int, error) {
|
||
|
req := h.newNetlinkRequest(unix.RTM_GETNSID, unix.NLM_F_REQUEST)
|
||
|
|
||
|
rtgen := nl.NewRtGenMsg()
|
||
|
req.AddData(rtgen)
|
||
|
|
||
|
b := make([]byte, 4, 4)
|
||
|
native.PutUint32(b, val)
|
||
|
attr := nl.NewRtAttr(attrType, b)
|
||
|
req.AddData(attr)
|
||
|
|
||
|
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
|
||
|
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
|
||
|
for _, m := range msgs {
|
||
|
msg := nl.DeserializeRtGenMsg(m)
|
||
|
|
||
|
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
|
||
|
for _, attr := range attrs {
|
||
|
switch attr.Attr.Type {
|
||
|
case NETNSA_NSID:
|
||
|
return int(int32(native.Uint32(attr.Value))), nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0, fmt.Errorf("unexpected empty result")
|
||
|
}
|
||
|
|
||
|
// setNetNsId sets the netnsid for a given type-val pair
|
||
|
// type should be either NETNSA_PID or NETNSA_FD
|
||
|
// The ID can only be set for namespaces without an ID already set
|
||
|
func (h *Handle) setNetNsId(attrType int, val uint32, newnsid uint32) error {
|
||
|
req := h.newNetlinkRequest(unix.RTM_NEWNSID, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
|
||
|
|
||
|
rtgen := nl.NewRtGenMsg()
|
||
|
req.AddData(rtgen)
|
||
|
|
||
|
b := make([]byte, 4, 4)
|
||
|
native.PutUint32(b, val)
|
||
|
attr := nl.NewRtAttr(attrType, b)
|
||
|
req.AddData(attr)
|
||
|
|
||
|
b1 := make([]byte, 4, 4)
|
||
|
native.PutUint32(b1, newnsid)
|
||
|
attr1 := nl.NewRtAttr(NETNSA_NSID, b1)
|
||
|
req.AddData(attr1)
|
||
|
|
||
|
_, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
|
||
|
return err
|
||
|
}
|