aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/vishvananda/netlink/netns_linux.go
blob: 77cf6f46901bea178b08ff554d8932e6ea0bd242 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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
}