]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/nl.c
spelling: userns
[mirror_lxc.git] / src / lxc / nl.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE 1
26 #endif
27 #include <errno.h>
28 #include <linux/netlink.h>
29 #include <linux/rtnetlink.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/socket.h>
34 #include <time.h>
35 #include <unistd.h>
36
37 #include "config.h"
38 #include "log.h"
39 #include "nl.h"
40
41 lxc_log_define(nl, lxc);
42
43 extern size_t nlmsg_len(const struct nlmsg *nlmsg)
44 {
45 return nlmsg->nlmsghdr->nlmsg_len - NLMSG_HDRLEN;
46 }
47
48 extern void *nlmsg_data(struct nlmsg *nlmsg)
49 {
50 char *data = ((char *)nlmsg) + NLMSG_HDRLEN;
51 if (!nlmsg_len(nlmsg))
52 return NULL;
53 return data;
54 }
55
56 static int nla_put(struct nlmsg *nlmsg, int attr,
57 const void *data, size_t len)
58 {
59 struct rtattr *rta;
60 size_t rtalen = RTA_LENGTH(len);
61 size_t tlen = NLMSG_ALIGN(nlmsg->nlmsghdr->nlmsg_len) + RTA_ALIGN(rtalen);
62
63 if (tlen > nlmsg->cap)
64 return -ENOMEM;
65
66 rta = NLMSG_TAIL(nlmsg->nlmsghdr);
67 rta->rta_type = attr;
68 rta->rta_len = rtalen;
69 if (data && len)
70 memcpy(RTA_DATA(rta), data, len);
71 nlmsg->nlmsghdr->nlmsg_len = tlen;
72 return 0;
73 }
74
75 extern int nla_put_buffer(struct nlmsg *nlmsg, int attr,
76 const void *data, size_t size)
77 {
78 return nla_put(nlmsg, attr, data, size);
79 }
80
81 extern int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string)
82 {
83 return nla_put(nlmsg, attr, string, strlen(string) + 1);
84 }
85
86 extern int nla_put_u32(struct nlmsg *nlmsg, int attr, int value)
87 {
88 return nla_put(nlmsg, attr, &value, sizeof(value));
89 }
90
91 extern int nla_put_u16(struct nlmsg *nlmsg, int attr, unsigned short value)
92 {
93 return nla_put(nlmsg, attr, &value, 2);
94 }
95
96 extern int nla_put_attr(struct nlmsg *nlmsg, int attr)
97 {
98 return nla_put(nlmsg, attr, NULL, 0);
99 }
100
101 struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr)
102 {
103 struct rtattr *rtattr = NLMSG_TAIL(nlmsg->nlmsghdr);
104
105 if (nla_put_attr(nlmsg, attr))
106 return NULL;
107
108 return rtattr;
109 }
110
111 void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr)
112 {
113 attr->rta_len = (void *)NLMSG_TAIL(nlmsg->nlmsghdr) - (void *)attr;
114 }
115
116 extern struct nlmsg *nlmsg_alloc(size_t size)
117 {
118 struct nlmsg *nlmsg;
119 size_t len = NLMSG_HDRLEN + NLMSG_ALIGN(size);
120
121 nlmsg = (struct nlmsg *)malloc(sizeof(struct nlmsg));
122 if (!nlmsg)
123 return NULL;
124
125 nlmsg->nlmsghdr = (struct nlmsghdr *)malloc(len);
126 if (!nlmsg->nlmsghdr)
127 goto errout;
128
129 memset(nlmsg->nlmsghdr, 0, len);
130 nlmsg->cap = len;
131 nlmsg->nlmsghdr->nlmsg_len = NLMSG_HDRLEN;
132
133 return nlmsg;
134 errout:
135 free(nlmsg);
136 return NULL;
137 }
138
139 extern void *nlmsg_reserve(struct nlmsg *nlmsg, size_t len)
140 {
141 void *buf;
142 size_t nlmsg_len = nlmsg->nlmsghdr->nlmsg_len;
143 size_t tlen = NLMSG_ALIGN(len);
144
145 if (nlmsg_len + tlen > nlmsg->cap)
146 return NULL;
147
148 buf = ((char *)(nlmsg->nlmsghdr)) + nlmsg_len;
149 nlmsg->nlmsghdr->nlmsg_len += tlen;
150
151 if (tlen > len)
152 memset(buf + len, 0, tlen - len);
153
154 return buf;
155 }
156
157 extern struct nlmsg *nlmsg_alloc_reserve(size_t size)
158 {
159 struct nlmsg *nlmsg;
160
161 nlmsg = nlmsg_alloc(size);
162 if (!nlmsg)
163 return NULL;
164
165 /* Just set message length to cap directly. */
166 nlmsg->nlmsghdr->nlmsg_len = nlmsg->cap;
167 return nlmsg;
168 }
169
170 extern void nlmsg_free(struct nlmsg *nlmsg)
171 {
172 if (!nlmsg)
173 return;
174
175 free(nlmsg->nlmsghdr);
176 free(nlmsg);
177 }
178
179 extern int __netlink_recv(struct nl_handler *handler, struct nlmsghdr *nlmsghdr)
180 {
181 int ret;
182 struct sockaddr_nl nladdr;
183 struct iovec iov = {
184 .iov_base = nlmsghdr,
185 .iov_len = nlmsghdr->nlmsg_len,
186 };
187
188 struct msghdr msg = {
189 .msg_name = &nladdr,
190 .msg_namelen = sizeof(nladdr),
191 .msg_iov = &iov,
192 .msg_iovlen = 1,
193 };
194
195 memset(&nladdr, 0, sizeof(nladdr));
196 nladdr.nl_family = AF_NETLINK;
197 nladdr.nl_pid = 0;
198 nladdr.nl_groups = 0;
199
200 again:
201 ret = recvmsg(handler->fd, &msg, 0);
202 if (ret < 0) {
203 if (errno == EINTR)
204 goto again;
205
206 return -1;
207 }
208
209 if (!ret)
210 return 0;
211
212 if (msg.msg_flags & MSG_TRUNC && (ret == nlmsghdr->nlmsg_len)) {
213 errno = EMSGSIZE;
214 ret = -1;
215 }
216
217 return ret;
218 }
219
220 extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer)
221 {
222 return __netlink_recv(handler, answer->nlmsghdr);
223 }
224
225 extern int __netlink_send(struct nl_handler *handler, struct nlmsghdr *nlmsghdr)
226 {
227 int ret;
228 struct sockaddr_nl nladdr;
229 struct iovec iov = {
230 .iov_base = nlmsghdr,
231 .iov_len = nlmsghdr->nlmsg_len,
232 };
233 struct msghdr msg = {
234 .msg_name = &nladdr,
235 .msg_namelen = sizeof(nladdr),
236 .msg_iov = &iov,
237 .msg_iovlen = 1,
238 };
239
240 memset(&nladdr, 0, sizeof(nladdr));
241 nladdr.nl_family = AF_NETLINK;
242 nladdr.nl_pid = 0;
243 nladdr.nl_groups = 0;
244
245 ret = sendmsg(handler->fd, &msg, MSG_NOSIGNAL);
246 if (ret < 0)
247 return -1;
248
249 return ret;
250 }
251
252 extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg)
253 {
254 return __netlink_send(handler, nlmsg->nlmsghdr);
255 }
256
257 extern int __netlink_transaction(struct nl_handler *handler,
258 struct nlmsghdr *request,
259 struct nlmsghdr *answer)
260 {
261 int ret;
262
263 ret = __netlink_send(handler, request);
264 if (ret < 0)
265 return -1;
266
267 ret = __netlink_recv(handler, answer);
268 if (ret < 0)
269 return -1;
270
271 ret = 0;
272 if (answer->nlmsg_type == NLMSG_ERROR) {
273 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(answer);
274 errno = -err->error;
275 if (err->error < 0)
276 ret = -1;
277 }
278
279 return ret;
280 }
281
282 extern int netlink_transaction(struct nl_handler *handler,
283 struct nlmsg *request, struct nlmsg *answer)
284 {
285 return __netlink_transaction(handler, request->nlmsghdr,
286 answer->nlmsghdr);
287 }
288
289 extern int netlink_open(struct nl_handler *handler, int protocol)
290 {
291 socklen_t socklen;
292 int sndbuf = 32768;
293 int rcvbuf = 32768;
294 int err;
295
296 memset(handler, 0, sizeof(*handler));
297
298 handler->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
299 if (handler->fd < 0)
300 return -errno;
301
302 if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF,
303 &sndbuf, sizeof(sndbuf)) < 0)
304 goto err_with_errno;
305
306 if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF,
307 &rcvbuf,sizeof(rcvbuf)) < 0)
308 goto err_with_errno;
309
310 memset(&handler->local, 0, sizeof(handler->local));
311 handler->local.nl_family = AF_NETLINK;
312 handler->local.nl_groups = 0;
313
314 if (bind(handler->fd, (struct sockaddr*)&handler->local,
315 sizeof(handler->local)) < 0)
316 goto err_with_errno;
317
318 socklen = sizeof(handler->local);
319 if (getsockname(handler->fd, (struct sockaddr*)&handler->local,
320 &socklen) < 0)
321 goto err_with_errno;
322
323 if (socklen != sizeof(handler->local)) {
324 err = -EINVAL;
325 goto errclose;
326 }
327
328 if (handler->local.nl_family != AF_NETLINK) {
329 err = -EINVAL;
330 goto errclose;
331 }
332
333 handler->seq = time(NULL);
334
335 return 0;
336 err_with_errno:
337 err = -errno;
338 errclose:
339 close(handler->fd);
340 return err;
341 }
342
343 extern int netlink_close(struct nl_handler *handler)
344 {
345 close(handler->fd);
346 handler->fd = -1;
347 return 0;
348 }
349
350 int addattr(struct nlmsghdr *n, size_t maxlen, int type, const void *data,
351 size_t alen)
352 {
353 int len = RTA_LENGTH(alen);
354 struct rtattr *rta;
355
356 errno = EMSGSIZE;
357 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
358 return -1;
359
360 rta = NLMSG_TAIL(n);
361 rta->rta_type = type;
362 rta->rta_len = len;
363 if (alen)
364 memcpy(RTA_DATA(rta), data, alen);
365 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
366
367 return 0;
368 }