]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_user_nic.c
lxc-user-nic: rename nic inside container to desired name
[mirror_lxc.git] / src / lxc / lxc_user_nic.c
1 /*
2 *
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 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
20 #define _GNU_SOURCE /* See feature_test_macros(7) */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <sys/types.h>
25 #include <pwd.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/file.h>
29 #include <alloca.h>
30 #include <string.h>
31 #include <sched.h>
32 #include <sys/mman.h>
33 #include <sys/socket.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <sys/stat.h>
37 #include <sys/ioctl.h>
38 #include <linux/netlink.h>
39 #include <arpa/inet.h>
40 #include <net/if.h>
41 #include <net/if_arp.h>
42 #include <netinet/in.h>
43 #include <linux/if_bridge.h>
44 #include <linux/netlink.h>
45 #include <linux/rtnetlink.h>
46 #include <linux/sockios.h>
47 #include <sys/param.h>
48 #include <sched.h>
49 #include "config.h"
50 #include "utils.h"
51
52 #ifndef HAVE_GETLINE
53 #ifdef HAVE_FGETLN
54 #include <../include/getline.h>
55 #endif
56 #endif
57
58 /* Define setns() if missing from the C library */
59 #ifndef HAVE_SETNS
60 static inline int setns(int fd, int nstype)
61 {
62 #ifdef __NR_setns
63 return syscall(__NR_setns, fd, nstype);
64 #else
65 errno = ENOSYS;
66 return -1;
67 #endif
68 }
69 #endif
70
71 #if ISTEST
72 #define CONF_FILE "/tmp/lxc-usernet"
73 #define DB_FILE "/tmp/nics"
74 #else
75 #define CONF_FILE LXC_USERNIC_CONF
76 #define DB_FILE LXC_USERNIC_DB
77 #endif
78
79
80 #include "nl.h"
81
82 #ifndef IFLA_LINKMODE
83 # define IFLA_LINKMODE 17
84 #endif
85
86 #ifndef IFLA_LINKINFO
87 # define IFLA_LINKINFO 18
88 #endif
89
90 #ifndef IFLA_NET_NS_PID
91 # define IFLA_NET_NS_PID 19
92 #endif
93
94 #ifndef IFLA_INFO_KIND
95 # define IFLA_INFO_KIND 1
96 #endif
97
98 #ifndef IFLA_VLAN_ID
99 # define IFLA_VLAN_ID 1
100 #endif
101
102 #ifndef IFLA_INFO_DATA
103 # define IFLA_INFO_DATA 2
104 #endif
105
106 #ifndef VETH_INFO_PEER
107 # define VETH_INFO_PEER 1
108 #endif
109
110 #ifndef IFLA_MACVLAN_MODE
111 # define IFLA_MACVLAN_MODE 1
112 #endif
113
114 void usage(char *me, bool fail)
115 {
116 fprintf(stderr, "Usage: %s pid type bridge nicname\n", me);
117 fprintf(stderr, " nicname is the name to use inside the container\n");
118 exit(fail ? 1 : 0);
119 }
120
121 int open_and_lock(char *path)
122 {
123 int fd;
124 struct flock lk;
125
126 fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
127 if (fd < 0) {
128 perror("open");
129 return(fd);
130 }
131
132 lk.l_type = F_WRLCK;
133 lk.l_whence = SEEK_SET;
134 lk.l_start = 0;
135 lk.l_len = 0;
136 if (fcntl(fd, F_SETLKW, &lk) < 0) {
137 perror("fcntl lock");
138 exit(1);
139 }
140
141 return fd;
142 }
143
144
145 char *get_username(char **buf)
146 {
147 struct passwd *pwd = getpwuid(getuid());
148
149 if (pwd == NULL) {
150 perror("getpwuid");
151 return NULL;
152 }
153
154 return pwd->pw_name;
155 }
156
157 /* The configuration file consists of lines of the form:
158 *
159 * user type bridge nic-name count
160 *
161 * We simply count the number of lines in the file, making sure that
162 * every listed nic is still present. Any nics which have disappeared
163 * is removed when we count, in case the container died a harsh death
164 * without being able to clean up after itself.
165 */
166 int get_alloted(char *me, char *intype, char *link)
167 {
168 FILE *fin = fopen(CONF_FILE, "r");
169 char *line = NULL;
170 char user[100], type[100], br[100];
171 size_t len = 0;
172 int n = -1, ret;
173
174 if (!fin)
175 return -1;
176
177 while ((getline(&line, &len, fin)) != -1) {
178 ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", user, type, br, &n);
179
180 if (ret != 4)
181 continue;
182 if (strcmp(user, me) != 0)
183 continue;
184 if (strcmp(type, intype) != 0)
185 continue;
186 if (strcmp(link, br) != 0)
187 continue;
188 free(line);
189 return n;
190 }
191 fclose(fin);
192 if (line)
193 free(line);
194 return -1;
195 }
196
197 char *get_eol(char *s)
198 {
199 while (*s && *s != '\n')
200 s++;
201 return s;
202 }
203
204 char *get_eow(char *s)
205 {
206 while (*s && !isblank(*s) && *s != '\n')
207 s++;
208 return s;
209 }
210
211 char *find_line(char *p, char *e, char *u, char *t, char *l)
212 {
213 char *p1, *p2, *ret;
214
215 while (p < e && (p1 = get_eol(p)) < e) {
216 ret = p;
217 if (*p == '#')
218 goto next;
219 while (isblank(*p)) p++;
220 p2 = get_eow(p);
221 if (!p2 || p2-p != strlen(u) || strncmp(p, u, strlen(u)) != 0)
222 goto next;
223 p = p2+1;
224 while (isblank(*p)) p++;
225 p2 = get_eow(p);
226 if (!p2 || p2-p != strlen(t) || strncmp(p, t, strlen(t)) != 0)
227 goto next;
228 p = p2+1;
229 while (isblank(*p)) p++;
230 p2 = get_eow(p);
231 if (!p2 || p2-p != strlen(l) || strncmp(p, l, strlen(l)) != 0)
232 goto next;
233 return ret;
234 next:
235 p = p1 + 1;
236 }
237
238 return NULL;
239 }
240
241 bool nic_exists(char *nic)
242 {
243 char path[200];
244 int ret;
245 struct stat sb;
246
247 #if ISTEST
248 ret = snprintf(path, 200, "/tmp/lxcnettest/%s", nic);
249 #else
250 ret = snprintf(path, 200, "/sys/class/net/%s", nic);
251 #endif
252 if (ret < 0 || ret >= 200)
253 exit(1);
254 ret = stat(path, &sb);
255 if (ret != 0)
256 return false;
257 return true;
258 }
259
260 struct link_req {
261 struct nlmsg nlmsg;
262 struct ifinfomsg ifinfomsg;
263 };
264
265 #if ! ISTEST
266
267 int lxc_veth_create(const char *name1, const char *name2)
268 {
269 struct nl_handler nlh;
270 struct nlmsg *nlmsg = NULL, *answer = NULL;
271 struct link_req *link_req;
272 struct rtattr *nest1, *nest2, *nest3;
273 int len, err;
274
275 err = netlink_open(&nlh, NETLINK_ROUTE);
276 if (err)
277 return err;
278
279 err = -EINVAL;
280 len = strlen(name1);
281 if (len == 1 || len >= IFNAMSIZ)
282 goto out;
283
284 len = strlen(name2);
285 if (len == 1 || len >= IFNAMSIZ)
286 goto out;
287
288 err = -ENOMEM;
289 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
290 if (!nlmsg)
291 goto out;
292
293 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
294 if (!answer)
295 goto out;
296
297 link_req = (struct link_req *)nlmsg;
298 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
299 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
300 nlmsg->nlmsghdr.nlmsg_flags =
301 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
302 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
303
304 err = -EINVAL;
305 nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
306 if (!nest1)
307 goto out;
308
309 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
310 goto out;
311
312 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
313 if (!nest2)
314 goto out;
315
316 nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
317 if (!nest3)
318 goto out;
319
320 nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg);
321
322 if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
323 goto out;
324
325 nla_end_nested(nlmsg, nest3);
326
327 nla_end_nested(nlmsg, nest2);
328
329 nla_end_nested(nlmsg, nest1);
330
331 if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
332 goto out;
333
334 err = netlink_transaction(&nlh, nlmsg, answer);
335 out:
336 netlink_close(&nlh);
337 nlmsg_free(answer);
338 nlmsg_free(nlmsg);
339 return err;
340 }
341
342 int lxc_netdev_move(char *ifname, pid_t pid)
343 {
344 struct nl_handler nlh;
345 struct nlmsg *nlmsg = NULL;
346 struct link_req *link_req;
347 int err, index;
348
349 index = if_nametoindex(ifname);
350 if (!ifname)
351 return -EINVAL;
352
353 err = netlink_open(&nlh, NETLINK_ROUTE);
354 if (err)
355 return err;
356
357 err = -ENOMEM;
358 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
359 if (!nlmsg)
360 goto out;
361
362 link_req = (struct link_req *)nlmsg;
363 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
364 link_req->ifinfomsg.ifi_index = index;
365 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
366 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
367 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
368
369 if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
370 goto out;
371
372 err = netlink_transaction(&nlh, nlmsg, nlmsg);
373 out:
374 netlink_close(&nlh);
375 nlmsg_free(nlmsg);
376 return err;
377 }
378
379 static int setup_private_host_hw_addr(char *veth1)
380 {
381 struct ifreq ifr;
382 int err;
383 int sockfd;
384
385 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
386 if (sockfd < 0)
387 return -errno;
388
389 snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1);
390 err = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
391 if (err < 0) {
392 close(sockfd);
393 return -errno;
394 }
395
396 ifr.ifr_hwaddr.sa_data[0] = 0xfe;
397 err = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
398 close(sockfd);
399 if (err < 0)
400 return -errno;
401
402 return 0;
403 }
404
405 static int netdev_set_flag(const char *name, int flag)
406 {
407 struct nl_handler nlh;
408 struct nlmsg *nlmsg = NULL, *answer = NULL;
409 struct link_req *link_req;
410 int index, len, err;
411
412 err = netlink_open(&nlh, NETLINK_ROUTE);
413 if (err)
414 return err;
415
416 err = -EINVAL;
417 len = strlen(name);
418 if (len == 1 || len >= IFNAMSIZ)
419 goto out;
420
421 err = -ENOMEM;
422 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
423 if (!nlmsg)
424 goto out;
425
426 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
427 if (!answer)
428 goto out;
429
430 err = -EINVAL;
431 index = if_nametoindex(name);
432 if (!index)
433 goto out;
434
435 link_req = (struct link_req *)nlmsg;
436 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
437 link_req->ifinfomsg.ifi_index = index;
438 link_req->ifinfomsg.ifi_change |= IFF_UP;
439 link_req->ifinfomsg.ifi_flags |= flag;
440 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
441 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
442 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
443
444 err = netlink_transaction(&nlh, nlmsg, answer);
445 out:
446 netlink_close(&nlh);
447 nlmsg_free(nlmsg);
448 nlmsg_free(answer);
449 return err;
450 }
451
452 static int instanciate_veth(char *n1, char **n2)
453 {
454 int err;
455
456 err = snprintf(*n2, IFNAMSIZ, "%sp", n1);
457 if (err < 0 || err >= IFNAMSIZ) {
458 fprintf(stderr, "nic name too long\n");
459 exit(1);
460 }
461
462 err = lxc_veth_create(n1, *n2);
463 if (err) {
464 fprintf(stderr, "failed to create %s-%s : %s\n", n1, *n2,
465 strerror(-err));
466 exit(1);
467 }
468
469 /* changing the high byte of the mac address to 0xfe, the bridge interface
470 * will always keep the host's mac address and not take the mac address
471 * of a container */
472 err = setup_private_host_hw_addr(n1);
473 if (err) {
474 fprintf(stderr, "failed to change mac address of host interface '%s' : %s",
475 n1, strerror(-err));
476 }
477
478 return netdev_set_flag(n1, IFF_UP);
479 }
480
481 int lxc_bridge_attach(const char *bridge, const char *ifname)
482 {
483 int fd, index, err;
484 struct ifreq ifr;
485
486 if (strlen(ifname) >= IFNAMSIZ)
487 return -EINVAL;
488
489 index = if_nametoindex(ifname);
490 if (!index)
491 return -EINVAL;
492
493 fd = socket(AF_INET, SOCK_STREAM, 0);
494 if (fd < 0)
495 return -errno;
496
497 strncpy(ifr.ifr_name, bridge, IFNAMSIZ-1);
498 ifr.ifr_name[IFNAMSIZ-1] = '\0';
499 ifr.ifr_ifindex = index;
500 err = ioctl(fd, SIOCBRADDIF, &ifr);
501 close(fd);
502 if (err)
503 err = -errno;
504
505 return err;
506 }
507
508 int lxc_netdev_delete_by_index(int ifindex)
509 {
510 struct nl_handler nlh;
511 struct nlmsg *nlmsg = NULL, *answer = NULL;
512 struct link_req *link_req;
513 int err;
514
515 err = netlink_open(&nlh, NETLINK_ROUTE);
516 if (err)
517 return err;
518
519 err = -ENOMEM;
520 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
521 if (!nlmsg)
522 goto out;
523
524 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
525 if (!answer)
526 goto out;
527
528 link_req = (struct link_req *)nlmsg;
529 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
530 link_req->ifinfomsg.ifi_index = ifindex;
531 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
532 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
533 nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK;
534
535 err = netlink_transaction(&nlh, nlmsg, answer);
536 out:
537 netlink_close(&nlh);
538 nlmsg_free(answer);
539 nlmsg_free(nlmsg);
540 return err;
541 }
542
543 int lxc_netdev_delete_by_name(const char *name)
544 {
545 int index;
546
547 index = if_nametoindex(name);
548 if (!index)
549 return -EINVAL;
550
551 return lxc_netdev_delete_by_index(index);
552 }
553 #else
554 int lxc_netdev_delete_by_name(const char *name)
555 {
556 char path[200];
557 sprintf(path, "/tmp/lxcnettest/%s", name);
558 return unlink(path);
559 }
560
561 #endif
562
563 bool create_nic(char *nic, char *br, char *pidstr, char **cnic)
564 {
565 #if ISTEST
566 char path[200];
567 sprintf(path, "/tmp/lxcnettest/%s", nic);
568 int fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
569 if (fd < 0)
570 return false;
571 close(fd);
572 return true;
573 #else
574 // not yet implemented
575 char *veth1buf, *veth2buf;
576 veth1buf = alloca(IFNAMSIZ);
577 veth2buf = alloca(IFNAMSIZ);
578 int ret;
579 int pid = atoi(pidstr);
580
581 ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
582 if (ret < 0 || ret >= IFNAMSIZ) {
583 fprintf(stderr, "host nic name too long\n");
584 exit(1);
585 }
586
587 /* create the nics */
588 if (instanciate_veth(veth1buf, &veth2buf) < 0) {
589 fprintf(stderr, "Error creating veth tunnel\n");
590 return false;
591 }
592
593 /* attach veth1 to bridge */
594 if (lxc_bridge_attach(br, veth1buf) < 0) {
595 fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
596 goto out_del;
597 }
598
599 /* pass veth2 to target netns */
600 ret = lxc_netdev_move(veth2buf, pid);
601 if (ret < 0) {
602 fprintf(stderr, "Error moving %s to netns %d\n", veth2buf, pid);
603 goto out_del;
604 }
605 *cnic = strdup(veth2buf);
606 return true;
607
608 out_del:
609 lxc_netdev_delete_by_name(veth1buf);
610 exit(1);
611 #endif
612 }
613
614 /*
615 * Get a new nic.
616 * *dest will container the name (lxcuser-%d) which is attached
617 * on the host to the lxc bridge
618 */
619 void get_new_nicname(char **dest, char *br, char *pid, char **cnic)
620 {
621 int i = 0;
622 // TODO - speed this up. For large installations we won't
623 // want n stats for every nth container startup.
624 while (1) {
625 sprintf(*dest, "lxcuser-%d", i);
626 if (!nic_exists(*dest) && create_nic(*dest, br, pid, cnic))
627 return;
628 i++;
629 }
630 }
631
632 bool get_nic_from_line(char *p, char **nic)
633 {
634 char user[100], type[100], br[100];
635 int ret;
636
637 ret = sscanf(p, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", user, type, br, *nic);
638 if (ret != 4)
639 return false;
640 return true;
641 }
642
643 bool cull_entries(int fd, char *me, char *t, char *br)
644 {
645 struct stat sb;
646 char *buf, *p, *e, *nic;
647 off_t len;
648
649 nic = alloca(100);
650
651 fstat(fd, &sb);
652 len = sb.st_size;
653 if (len == 0)
654 return true;
655 buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
656 if (buf == MAP_FAILED) {
657 fprintf(stderr, "Failed to create mapping: error %d\n", errno);
658 return false;
659 }
660
661 p = buf;
662 e = buf + len;
663 while ((p = find_line(p, e, me, t, br)) != NULL) {
664 if (!get_nic_from_line(p, &nic))
665 continue;
666 if (nic && !nic_exists(nic)) {
667 // copy from eol(p)+1..e to p
668 char *src = get_eol(p) + 1, *dest = p;
669 int diff = src - p;
670 while (src < e)
671 *(dest++) = *(src)++;
672 e -= diff;
673 } else
674 p = get_eol(p) + 1;
675 if (p >= e)
676 break;
677 }
678 munmap(buf, sb.st_size);
679 if (ftruncate(fd, e-buf))
680 fprintf(stderr, "Failed to set new file size\n");
681 return true;
682 }
683
684 int count_entries(char *buf, off_t len, char *me, char *t, char *br)
685 {
686 char *e = &buf[len];
687 int count = 0;
688 while ((buf = find_line(buf, e, me, t, br)) != NULL) {
689 count++;
690 buf = get_eol(buf)+1;
691 if (buf >= e)
692 break;
693 }
694
695 return count;
696 }
697
698 /*
699 * The dbfile has lines of the format:
700 * user type bridge nicname
701 */
702 bool get_nic_if_avail(int fd, char *me, char *pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
703 {
704 off_t len, slen;
705 struct stat sb;
706 char *buf = NULL, *newline;
707 int ret, count = 0;
708
709 cull_entries(fd, me, intype, br);
710
711 fstat(fd, &sb);
712 len = sb.st_size;
713 if (len != 0) {
714 buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
715 if (buf == MAP_FAILED) {
716 fprintf(stderr, "Failed to create mapping\n");
717 return false;
718 }
719
720 count = count_entries(buf, len, me, intype, br);
721 if (count >= allowed)
722 return false;
723 }
724
725
726 get_new_nicname(nicname, br, pid, cnic);
727 /* me ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
728 slen = strlen(me) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
729 newline = alloca(slen);
730 ret = snprintf(newline, slen, "%s %s %s %s\n", me, intype, br, *nicname);
731 if (ret < 0 || ret >= slen) {
732 if (lxc_netdev_delete_by_name(*nicname) != 0)
733 fprintf(stderr, "Error unlinking %s!\n", *nicname);
734 return false;
735 }
736 if (len)
737 munmap(buf, len);
738 if (ftruncate(fd, len + slen))
739 fprintf(stderr, "Failed to set new file size\n");
740 buf = mmap(NULL, len + slen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
741 if (buf == MAP_FAILED) {
742 fprintf(stderr, "Failed to create mapping after extending: error %d\n", errno);
743 if (lxc_netdev_delete_by_name(*nicname) != 0)
744 fprintf(stderr, "Error unlinking %s!\n", *nicname);
745 return false;
746 }
747 strcpy(buf+len, newline);
748 munmap(buf, len+slen);
749 return true;
750 }
751
752 bool create_db_dir(char *fnam)
753 {
754 char *p = alloca(strlen(fnam)+1);
755
756 strcpy(p, fnam);
757 fnam = p;
758 p = p + 1;
759 again:
760 while (*p && *p != '/') p++;
761 if (!*p)
762 return true;
763 *p = '\0';
764 if (mkdir(fnam, 0755) && errno != EEXIST) {
765 fprintf(stderr, "failed to create %s\n", fnam);
766 *p = '/';
767 return false;
768 }
769 *(p++) = '/';
770 goto again;
771 }
772
773 static int lxc_netdev_rename_by_index(int ifindex, const char *newname)
774 {
775 struct nl_handler nlh;
776 struct nlmsg *nlmsg = NULL, *answer = NULL;
777 struct link_req *link_req;
778 int len, err;
779
780 err = netlink_open(&nlh, NETLINK_ROUTE);
781 if (err)
782 return err;
783
784 len = strlen(newname);
785 if (len == 1 || len >= IFNAMSIZ)
786 goto out;
787
788 err = -ENOMEM;
789 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
790 if (!nlmsg)
791 goto out;
792
793 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
794 if (!answer)
795 goto out;
796
797 link_req = (struct link_req *)nlmsg;
798 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
799 link_req->ifinfomsg.ifi_index = ifindex;
800 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
801 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
802 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
803
804 if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
805 goto out;
806
807 err = netlink_transaction(&nlh, nlmsg, answer);
808 out:
809 netlink_close(&nlh);
810 nlmsg_free(answer);
811 nlmsg_free(nlmsg);
812 return err;
813 }
814
815 static int lxc_netdev_rename_by_name(const char *oldname, const char *newname)
816 {
817 int len, index;
818
819 len = strlen(oldname);
820 if (len == 1 || len >= IFNAMSIZ)
821 return -EINVAL;
822
823 index = if_nametoindex(oldname);
824 if (!index) {
825 fprintf(stderr, "Error getting ifindex for %s\n", oldname);
826 return -EINVAL;
827 }
828
829 return lxc_netdev_rename_by_index(index, newname);
830 }
831
832 int rename_in_ns(int pid, char *oldname, char *newname)
833 {
834 char nspath[MAXPATHLEN];
835 int fd = -1, ofd = -1, ret;
836
837 ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", getpid());
838 if (ret < 0 || ret >= MAXPATHLEN)
839 return -1;
840 if ((ofd = open(nspath, O_RDONLY)) < 0) {
841 fprintf(stderr, "Opening %s\n", nspath);
842 return -1;
843 }
844 ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", pid);
845 if (ret < 0 || ret >= MAXPATHLEN)
846 goto out_err;
847
848 if ((fd = open(nspath, O_RDONLY)) < 0) {
849 fprintf(stderr, "Opening %s\n", nspath);
850 goto out_err;
851 }
852 if (setns(fd, 0) < 0) {
853 fprintf(stderr, "setns to container network namespace\n");
854 goto out_err;
855 }
856 close(fd); fd = -1;
857 if ((ret = lxc_netdev_rename_by_name(oldname, newname)) < 0) {
858 fprintf(stderr, "Error %d renaming netdev %s to %s in container\n", ret, oldname, newname);
859 goto out_err;
860 }
861 if (setns(ofd, 0) < 0) {
862 fprintf(stderr, "Error returning to original netns\n");
863 close(ofd);
864 return -1;
865 }
866 close(ofd);
867
868 return 0;
869
870 out_err:
871 if (ofd >= 0)
872 close(ofd);
873 if (setns(ofd, 0) < 0)
874 fprintf(stderr, "Error returning to original network namespace\n");
875 if (fd >= 0)
876 close(fd);
877 return -1;
878 }
879
880 int main(int argc, char *argv[])
881 {
882 int n, fd;
883 bool gotone = false;
884 char *me, *buf = alloca(400);
885 char *nicname = alloca(40);
886 char *cnic; // created nic name in container is returned here.
887 char *vethname;
888 int pid;
889
890 if ((me = get_username(&buf)) == NULL) {
891 fprintf(stderr, "Failed to get username\n");
892 exit(1);
893 }
894
895 if (argc < 4)
896 usage(argv[0], true);
897 if (argc >= 5)
898 vethname = argv[4];
899 else
900 vethname = "eth0";
901
902 if (!create_db_dir(DB_FILE)) {
903 fprintf(stderr, "Failed to create directory for db file\n");
904 exit(1);
905 }
906
907 if ((fd = open_and_lock(DB_FILE)) < 0) {
908 fprintf(stderr, "Failed to lock %s\n", DB_FILE);
909 exit(1);
910 }
911
912 n = get_alloted(me, argv[2], argv[3]);
913 if (n > 0)
914 gotone = get_nic_if_avail(fd, me, argv[1], argv[2], argv[3], n, &nicname, &cnic);
915 close(fd);
916 if (!gotone) {
917 fprintf(stderr, "Quota reached\n");
918 exit(1);
919 }
920
921 pid = atoi(argv[1]);
922 // Now rename the link
923 if (rename_in_ns(pid, cnic, vethname) < 0) {
924 fprintf(stderr, "Failed to rename the link\n");
925 exit(1);
926 }
927
928 exit(0);
929 }