-
Notifications
You must be signed in to change notification settings - Fork 19
/
netns.c
238 lines (189 loc) · 6.07 KB
/
netns.c
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#include <stdio.h>
#include <string.h>
#include <linux/rtnetlink.h>
#include <linux/veth.h>
#include <net/if.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include "netns.h"
#include "util.h"
static void addattr_l(
struct nlmsghdr *n, int maxlen, __u16 type,
const void *data, __u16 datalen)
{
__u16 attr_len = RTA_LENGTH(datalen);
__u32 newlen = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(attr_len);
if (newlen > maxlen)
die("cannot add attribute. size (%d) exceeded maxlen (%d)\n",
newlen, maxlen);
struct rtattr *rta;
rta = NLMSG_TAIL(n);
rta->rta_type = type;
rta->rta_len = attr_len;
if (datalen)
memcpy(RTA_DATA(rta), data, datalen);
n->nlmsg_len = newlen;
}
static struct rtattr *addattr_nest(
struct nlmsghdr *n, int maxlen, __u16 type)
{
struct rtattr *nest = NLMSG_TAIL(n);
addattr_l(n, maxlen, type, NULL, 0);
return nest;
}
static void addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
{
nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
}
static ssize_t read_response(
int fd, struct msghdr *msg, char **response)
{
struct iovec *iov = msg->msg_iov;
iov->iov_base = *response;
iov->iov_len = MAX_PAYLOAD;
ssize_t resp_len = recvmsg(fd, msg, 0);
if (resp_len == 0)
die("EOF on netlink\n");
if (resp_len < 0)
die("netlink receive error: %m\n");
return resp_len;
}
static void check_response(int sock_fd)
{
struct iovec iov;
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1
};
char *resp = malloc(MAX_PAYLOAD);
ssize_t resp_len = read_response(sock_fd, &msg, &resp);
struct nlmsghdr *hdr = (struct nlmsghdr *) resp;
int nlmsglen = hdr->nlmsg_len;
int datalen = nlmsglen - sizeof(*hdr);
// Did we read all data?
if (datalen < 0 || nlmsglen > resp_len) {
if (msg.msg_flags & MSG_TRUNC)
die("received truncated message\n");
die("malformed message: nlmsg_len=%d\n", nlmsglen);
}
// Was there an error?
if (hdr->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA(hdr);
if (datalen < sizeof(struct nlmsgerr))
fprintf(stderr, "ERROR truncated!\n");
if(err->error) {
errno = -err->error;
die("RTNETLINK: %m\n");
}
}
free(resp);
}
int create_socket(int domain, int type, int protocol)
{
int sock_fd = socket(domain, type, protocol);
if (sock_fd < 0)
die("cannot open socket: %m\n");
return sock_fd;
}
static void send_nlmsg(int sock_fd, struct nlmsghdr *n)
{
struct iovec iov = {
.iov_base = n,
.iov_len = n->nlmsg_len
};
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1
};
n->nlmsg_seq++;
ssize_t status = sendmsg(sock_fd, &msg, 0);
if (status < 0)
die("cannot talk to rtnetlink: %m\n");
check_response(sock_fd);
}
int get_netns_fd(int pid)
{
char path[256];
sprintf(path, "/proc/%d/ns/net", pid);
int fd = open(path, O_RDONLY);
if (fd < 0)
die("cannot read netns file %s: %m\n", path);
return fd;
}
void if_up(
char *ifname, char *ip, char *netmask)
{
int sock_fd = create_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, ifname, strlen(ifname));
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = 0;
char *p = (char *) &saddr;
saddr.sin_addr.s_addr = inet_addr(ip);
memcpy(((char *)&(ifr.ifr_addr)), p, sizeof(struct sockaddr));
if (ioctl(sock_fd, SIOCSIFADDR, &ifr))
die("cannot set ip addr %s, %s: %m\n", ifname, ip);
saddr.sin_addr.s_addr = inet_addr(netmask);
memcpy(((char *)&(ifr.ifr_addr)), p, sizeof(struct sockaddr));
if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr))
die("cannot set netmask for addr %s, %s: %m\n", ifname, netmask);
ifr.ifr_flags |= IFF_UP | IFF_BROADCAST |
IFF_RUNNING | IFF_MULTICAST;
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr))
die("cannot set flags for addr %s, %s: %m\n", ifname, ip);
close(sock_fd);
}
void create_veth(int sock_fd, char *ifname, char *peername)
{
// ip link add veth0 type veth peer name veth1
__u16 flags =
NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
struct nl_req req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
.n.nlmsg_flags = flags,
.n.nlmsg_type = RTM_NEWLINK,
.i.ifi_family = PF_NETLINK,
};
struct nlmsghdr *n = &req.n;
int maxlen = sizeof(req);
addattr_l(n, maxlen, IFLA_IFNAME, ifname, strlen(ifname) + 1);
struct rtattr *linfo =
addattr_nest(n, maxlen, IFLA_LINKINFO);
addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "veth", 5);
struct rtattr *linfodata =
addattr_nest(n, maxlen, IFLA_INFO_DATA);
struct rtattr *peerinfo =
addattr_nest(n, maxlen, VETH_INFO_PEER);
n->nlmsg_len += sizeof(struct ifinfomsg);
addattr_l(n, maxlen, IFLA_IFNAME, peername, strlen(peername) + 1);
addattr_nest_end(n, peerinfo);
addattr_nest_end(n, linfodata);
addattr_nest_end(n, linfo);
send_nlmsg(sock_fd, n);
}
void move_if_to_pid_netns(int sock_fd, char *ifname, int netns)
{
// ip link set veth1 netns coke
struct nl_req req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
.n.nlmsg_type = RTM_NEWLINK,
.i.ifi_family = PF_NETLINK,
};
addattr_l(&req.n, sizeof(req), IFLA_NET_NS_FD, &netns, 4);
addattr_l(&req.n, sizeof(req), IFLA_IFNAME,
ifname, strlen(ifname) + 1);
send_nlmsg(sock_fd, &req.n);
}