1package 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
15import (
16	"fmt"
17
18	"github.com/vishvananda/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.
23const (
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.
32func (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.
38func 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.
44func (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.
50func 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.
57func (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.
64func 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.
71func (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.
78func 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
84func (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, 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
123func (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, 4)
130	native.PutUint32(b, val)
131	attr := nl.NewRtAttr(attrType, b)
132	req.AddData(attr)
133
134	b1 := make([]byte, 4, 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}
142