]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile_utils.c
Merge pull request #1630 from brauner/2017-06-20/fix_siblk_detection
[mirror_lxc.git] / src / lxc / confile_utils.c
CommitLineData
0b843d35
CB
1/* liblxcapi
2 *
3 * Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2017 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
ce2f5ae8
CB
20#include "config.h"
21
0b843d35 22#include <stdio.h>
ce2f5ae8 23#include <stdlib.h>
0b843d35 24#include <string.h>
9b0df30f 25#include <arpa/inet.h>
0b843d35 26
663e9916 27#include "conf.h"
ce2f5ae8
CB
28#include "confile.h"
29#include "confile_utils.h"
30#include "error.h"
663e9916 31#include "log.h"
ce2f5ae8 32#include "list.h"
0b843d35
CB
33#include "utils.h"
34
ce2f5ae8
CB
35lxc_log_define(lxc_confile_utils, lxc);
36
0b843d35
CB
37int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
38 unsigned long *hostid, unsigned long *range)
39{
40 int ret = -1;
41 unsigned long tmp_hostid, tmp_nsid, tmp_range;
42 char tmp_type;
43 char *window, *slide;
44 char *dup = NULL;
45
46 /* Duplicate string. */
47 dup = strdup(idmap);
48 if (!dup)
49 goto on_error;
50
51 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
52
53 /* align */
54 slide = window = dup;
55 /* skip whitespace */
56 slide += strspn(slide, " \t\r");
57 if (slide != window && *slide == '\0')
58 goto on_error;
59
60 /* Validate type. */
61 if (*slide != 'u' && *slide != 'g')
62 goto on_error;
63 /* Assign type. */
64 tmp_type = *slide;
65
66 /* move beyond type */
67 slide++;
68 /* align */
69 window = slide;
70 /* Validate that only whitespace follows. */
71 slide += strspn(slide, " \t\r");
72 /* There must be whitespace. */
73 if (slide == window)
74 goto on_error;
75
76 /* Mark beginning of nsuid. */
77 window = slide;
78 /* Validate that non-whitespace follows. */
79 slide += strcspn(slide, " \t\r");
80 /* There must be non-whitespace. */
81 if (slide == window || *slide == '\0')
82 goto on_error;
83 /* Mark end of nsuid. */
84 *slide = '\0';
85
86 /* Parse nsuid. */
87 if (lxc_safe_ulong(window, &tmp_nsid) < 0)
88 goto on_error;
89
90 /* Move beyond \0. */
91 slide++;
92 /* align */
93 window = slide;
94 /* Validate that only whitespace follows. */
95 slide += strspn(slide, " \t\r");
96 /* If there was only one whitespace then we whiped it with our \0 above.
97 * So only ensure that we're not at the end of the string.
98 */
99 if (*slide == '\0')
100 goto on_error;
101
102 /* Mark beginning of hostid. */
103 window = slide;
104 /* Validate that non-whitespace follows. */
105 slide += strcspn(slide, " \t\r");
106 /* There must be non-whitespace. */
107 if (slide == window || *slide == '\0')
108 goto on_error;
109 /* Mark end of nsuid. */
110 *slide = '\0';
111
112 /* Parse hostid. */
113 if (lxc_safe_ulong(window, &tmp_hostid) < 0)
114 goto on_error;
115
116 /* Move beyond \0. */
117 slide++;
118 /* align */
119 window = slide;
120 /* Validate that only whitespace follows. */
121 slide += strspn(slide, " \t\r");
122 /* If there was only one whitespace then we whiped it with our \0 above.
123 * So only ensure that we're not at the end of the string.
124 */
125 if (*slide == '\0')
126 goto on_error;
127
128 /* Mark beginning of range. */
129 window = slide;
130 /* Validate that non-whitespace follows. */
131 slide += strcspn(slide, " \t\r");
132 /* There must be non-whitespace. */
133 if (slide == window)
134 goto on_error;
135
136 /* The range is the last valid entry we expect. So make sure that there
137 * is not trailing garbage and if there is, error out.
138 */
139 if (*(slide + strspn(slide, " \t\r\n")) != '\0')
140 goto on_error;
141 /* Mark end of range. */
142 *slide = '\0';
143
144 /* Parse range. */
145 if (lxc_safe_ulong(window, &tmp_range) < 0)
146 goto on_error;
147
148 *type = tmp_type;
149 *nsid = tmp_nsid;
150 *hostid = tmp_hostid;
151 *range = tmp_range;
152
153 /* Yay, we survived. */
154 ret = 0;
155
156on_error:
157 free(dup);
158
159 return ret;
160}
663e9916
CB
161
162bool lxc_config_value_empty(const char *value)
163{
164 if (value && strlen(value) > 0)
165 return false;
166
167 return true;
168}
ce2f5ae8 169
c302b476 170struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
ce2f5ae8
CB
171{
172 struct lxc_list *newlist;
173 struct lxc_netdev *netdev = NULL;
ce2f5ae8
CB
174
175 /* network does not exist */
176 netdev = malloc(sizeof(*netdev));
177 if (!netdev)
178 return NULL;
179
180 memset(netdev, 0, sizeof(*netdev));
181 lxc_list_init(&netdev->ipv4);
182 lxc_list_init(&netdev->ipv6);
183
184 /* give network a unique index */
185 netdev->idx = idx;
186
187 /* prepare new list */
188 newlist = malloc(sizeof(*newlist));
189 if (!newlist) {
190 free(netdev);
191 return NULL;
192 }
193
194 lxc_list_init(newlist);
195 newlist->elem = netdev;
196
c302b476
CB
197 if (tail)
198 lxc_list_add_tail(networks, newlist);
199 else
200 lxc_list_add(networks, newlist);
ce2f5ae8
CB
201 return netdev;
202}
1ed6ba91 203
c302b476
CB
204/* Takes care of finding the correct netdev struct in the networks list or
205 * allocates a new one if it couldn't be found.
206 */
207struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf,
208 unsigned int idx, bool allocate)
209{
210 struct lxc_netdev *netdev = NULL;
211 struct lxc_list *networks = &conf->network;
212 struct lxc_list *insert = networks;
213
214 /* lookup network */
215 if (!lxc_list_empty(networks)) {
216 lxc_list_for_each(insert, networks) {
217 netdev = insert->elem;
218 if (netdev->idx == idx)
219 return netdev;
220 else if (netdev->idx > idx)
221 break;
222 }
223 }
224
225 if (!allocate)
226 return NULL;
227
228 return lxc_network_add(insert, idx, true);
229}
230
1ed6ba91
CB
231void lxc_log_configured_netdevs(const struct lxc_conf *conf)
232{
233 struct lxc_netdev *netdev;
234 struct lxc_list *it = (struct lxc_list *)&conf->network;;
235
236 if ((conf->loglevel != LXC_LOG_LEVEL_TRACE) &&
237 (lxc_log_get_level() != LXC_LOG_LEVEL_TRACE))
238 return;
239
240 if (lxc_list_empty(it)) {
241 TRACE("container has no networks configured");
242 return;
243 }
244
245 lxc_list_for_each(it, &conf->network) {
9b0df30f
CB
246 struct lxc_list *cur, *next;
247 struct lxc_inetdev *inet4dev;
248 struct lxc_inet6dev *inet6dev;
249 char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
250
1ed6ba91
CB
251 netdev = it->elem;
252
c302b476 253 TRACE("index: %zd", netdev->idx);
1ed6ba91
CB
254 switch (netdev->type) {
255 case LXC_NET_VETH:
256 TRACE("type: veth");
9b0df30f
CB
257 if (netdev->priv.veth_attr.pair)
258 TRACE("veth pair: %s",
259 netdev->priv.veth_attr.pair);
1ed6ba91
CB
260 break;
261 case LXC_NET_MACVLAN:
262 TRACE("type: macvlan");
9b0df30f
CB
263 if (netdev->priv.macvlan_attr.mode > 0) {
264 char *macvlan_mode;
265 macvlan_mode = lxc_macvlan_flag_to_mode(
266 netdev->priv.macvlan_attr.mode);
267 TRACE("macvlan mode: %s",
268 macvlan_mode ? macvlan_mode
269 : "(invalid mode)");
270 }
1ed6ba91
CB
271 break;
272 case LXC_NET_VLAN:
273 TRACE("type: vlan");
9b0df30f 274 TRACE("vlan id: %d", netdev->priv.vlan_attr.vid);
1ed6ba91
CB
275 break;
276 case LXC_NET_PHYS:
277 TRACE("type: phys");
278 break;
279 case LXC_NET_EMPTY:
280 TRACE("type: empty");
281 break;
282 case LXC_NET_NONE:
283 TRACE("type: none");
284 break;
285 default:
286 ERROR("invalid network type %d", netdev->type);
287 return;
288 }
289
9b0df30f
CB
290 if (netdev->type != LXC_NET_EMPTY) {
291 TRACE("flags: %s",
292 netdev->flags == IFF_UP ? "up" : "none");
293 if (netdev->link)
294 TRACE("link: %s", netdev->link);
295 if (netdev->name)
296 TRACE("name: %s", netdev->name);
297 if (netdev->hwaddr)
298 TRACE("hwaddr: %s", netdev->hwaddr);
299 if (netdev->mtu)
300 TRACE("mtu: %s", netdev->mtu);
301 if (netdev->upscript)
302 TRACE("upscript: %s", netdev->upscript);
303 if (netdev->downscript)
304 TRACE("downscript: %s", netdev->downscript);
305
306 TRACE("ipv4 gateway auto: %s",
307 netdev->ipv4_gateway_auto ? "true" : "false");
308
309 if (netdev->ipv4_gateway) {
310 inet_ntop(AF_INET, netdev->ipv4_gateway,
311 bufinet4, sizeof(bufinet4));
312 TRACE("ipv4 gateway: %s", bufinet4);
313 }
314
315 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
316 inet4dev = cur->elem;
317 inet_ntop(AF_INET, &inet4dev->addr, bufinet4,
318 sizeof(bufinet4));
319 TRACE("ipv4 addr: %s", bufinet4);
320 }
321
322 TRACE("ipv6 gateway auto: %s",
323 netdev->ipv6_gateway_auto ? "true" : "false");
324 if (netdev->ipv6_gateway) {
325 inet_ntop(AF_INET6, netdev->ipv6_gateway,
326 bufinet6, sizeof(bufinet6));
327 TRACE("ipv6 gateway: %s", bufinet6);
328 }
329 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
330 inet6dev = cur->elem;
331 inet_ntop(AF_INET6, &inet6dev->addr, bufinet6,
332 sizeof(bufinet6));
333 TRACE("ipv6 addr: %s", bufinet6);
334 }
335 }
1ed6ba91
CB
336 }
337}
519df1c1 338
e5d2fd7c
CB
339static void lxc_free_netdev(struct lxc_netdev *netdev)
340{
341 struct lxc_list *cur, *next;
342
343 free(netdev->link);
344 free(netdev->name);
345 if (netdev->type == LXC_NET_VETH)
346 free(netdev->priv.veth_attr.pair);
347 free(netdev->upscript);
348 free(netdev->downscript);
349 free(netdev->hwaddr);
350 free(netdev->mtu);
351
352 free(netdev->ipv4_gateway);
353 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
354 lxc_list_del(cur);
355 free(cur->elem);
356 free(cur);
357 }
358
359 free(netdev->ipv6_gateway);
360 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
361 lxc_list_del(cur);
362 free(cur->elem);
363 free(cur);
364 }
365
366 free(netdev);
367}
368
519df1c1
CB
369bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
370{
e5d2fd7c 371 struct lxc_list *cur, *next;
519df1c1
CB
372 struct lxc_netdev *netdev;
373 bool found = false;
374
375 lxc_list_for_each_safe(cur, &conf->network, next) {
376 netdev = cur->elem;
377 if (netdev->idx != idx)
378 continue;
379
380 lxc_list_del(cur);
381 found = true;
382 break;
383 }
384
385 if (!found)
386 return false;
387
e5d2fd7c 388 lxc_free_netdev(netdev);
519df1c1
CB
389 free(cur);
390
391 return true;
392}
e5d2fd7c 393
c302b476 394void lxc_free_networks(struct lxc_list *networks)
e5d2fd7c
CB
395{
396 struct lxc_list *cur, *next;
397 struct lxc_netdev *netdev;
398
c302b476 399 lxc_list_for_each_safe(cur, networks, next) {
e5d2fd7c
CB
400 netdev = cur->elem;
401 lxc_free_netdev(netdev);
402 free(cur);
403 }
404
405 /* prevent segfaults */
c302b476 406 lxc_list_init(networks);
e5d2fd7c 407}
9b0df30f
CB
408
409static struct macvlan_mode {
410 char *name;
411 int mode;
412} macvlan_mode[] = {
413 { "private", MACVLAN_MODE_PRIVATE },
414 { "vepa", MACVLAN_MODE_VEPA },
415 { "bridge", MACVLAN_MODE_BRIDGE },
416 { "passthru", MACVLAN_MODE_PASSTHRU },
417};
418
419int lxc_macvlan_mode_to_flag(int *mode, const char *value)
420{
421 size_t i;
422
423 for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
424 if (strcmp(macvlan_mode[i].name, value))
425 continue;
426
427 *mode = macvlan_mode[i].mode;
428 return 0;
429 }
430
431 return -1;
432}
433
434char *lxc_macvlan_flag_to_mode(int mode)
435{
436 size_t i;
437
438 for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
439 if (macvlan_mode[i].mode == mode)
440 continue;
441
442 return macvlan_mode[i].name;
443 }
444
445 return NULL;
446}