]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_user_nic.c
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 Canonical Ltd.
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.
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.
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.
33 #include <arpa/inet.h>
34 #include <linux/netlink.h>
35 #include <linux/rtnetlink.h>
36 #include <linux/sockios.h>
38 #include <net/if_arp.h>
39 #include <netinet/in.h>
41 #include <sys/ioctl.h>
43 #include <sys/param.h>
44 #include <sys/socket.h>
46 #include <sys/types.h>
49 #include "namespace.h"
53 #define usernic_debug_stream(stream, format, ...) \
55 fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \
56 __func__, __VA_ARGS__); \
59 #define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__)
61 static void usage(char *me
, bool fail
)
63 fprintf(stderr
, "Usage: %s create {lxcpath} {name} {pid} {type} "
64 "{bridge} {nicname}\n", me
);
65 fprintf(stderr
, "Usage: %s delete {lxcpath} {name} "
66 "{/proc/<pid>/ns/net} {type} {bridge} {nicname}\n", me
);
67 fprintf(stderr
, "{nicname} is the name to use inside the container\n");
75 static int open_and_lock(char *path
)
80 fd
= open(path
, O_RDWR
| O_CREAT
, S_IWUSR
| S_IRUSR
);
82 usernic_error("Failed to open \"%s\": %s\n", path
,
88 lk
.l_whence
= SEEK_SET
;
92 ret
= fcntl(fd
, F_SETLKW
, &lk
);
94 usernic_error("Failed to lock \"%s\": %s\n", path
,
103 static char *get_username(void)
107 pwd
= getpwuid(getuid());
109 usernic_error("Failed to get username: %s\n", strerror(errno
));
116 static void free_groupnames(char **groupnames
)
123 for (i
= 0; groupnames
[i
]; i
++)
129 static char **get_groupnames(void)
137 ngroups
= getgroups(0, NULL
);
139 usernic_error("Failed to get number of groups the user "
140 "belongs to: %s\n", strerror(errno
));
146 group_ids
= malloc(sizeof(gid_t
) * ngroups
);
148 usernic_error("Failed to allocate memory while getting groups "
149 "the user belongs to: %s\n",
154 ret
= getgroups(ngroups
, group_ids
);
157 usernic_error("Failed to get process groups: %s\n",
162 groupnames
= malloc(sizeof(char *) * (ngroups
+ 1));
165 usernic_error("Failed to allocate memory while getting group "
171 memset(groupnames
, 0, sizeof(char *) * (ngroups
+ 1));
173 for (i
= 0; i
< ngroups
; i
++) {
174 gr
= getgrgid(group_ids
[i
]);
176 usernic_error("Failed to get group name: %s\n",
179 free_groupnames(groupnames
);
183 groupnames
[i
] = strdup(gr
->gr_name
);
184 if (!groupnames
[i
]) {
185 usernic_error("Failed to copy group name \"%s\"",
188 free_groupnames(groupnames
);
198 static bool name_is_in_groupnames(char *name
, char **groupnames
)
201 if (!strcmp(name
, *groupnames
))
211 struct alloted_s
*next
;
214 static struct alloted_s
*append_alloted(struct alloted_s
**head
, char *name
,
217 struct alloted_s
*cur
, *al
;
219 if (!head
|| !name
) {
220 /* Sanity check. Parameters should not be null. */
221 usernic_error("%s\n", "Unexpected NULL argument");
225 al
= malloc(sizeof(struct alloted_s
));
227 usernic_error("Failed to allocate memory: %s\n",
232 al
->name
= strdup(name
);
254 static void free_alloted(struct alloted_s
**head
)
256 struct alloted_s
*cur
;
270 /* The configuration file consists of lines of the form:
272 * user type bridge count
274 * @group type bridge count
276 * Return the count entry for the calling user if there is one. Else
279 static int get_alloted(char *me
, char *intype
, char *link
,
280 struct alloted_s
**alloted
)
283 char name
[100], type
[100], br
[100];
291 fin
= fopen(LXC_USERNIC_CONF
, "r");
293 usernic_error("Failed to open \"%s\": %s\n", LXC_USERNIC_CONF
,
298 groups
= get_groupnames();
299 while ((getline(&line
, &len
, fin
)) != -1) {
300 ret
= sscanf(line
, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name
,
305 if (strlen(name
) == 0)
308 if (strcmp(name
, me
)) {
312 if (!name_is_in_groupnames(name
+ 1, groups
))
316 if (strcmp(type
, intype
))
319 if (strcmp(link
, br
))
322 /* Found the user or group with the appropriate settings,
323 * therefore finish the search. What to do if there are more
324 * than one applicable lines? not specified in the docs. Since
325 * getline is implemented with realloc, we don't need to free
326 * line until exiting func.
328 * If append_alloted returns NULL, e.g. due to a malloc error,
329 * we set count to 0 and break the loop, allowing cleanup and
330 * then exiting from main().
332 if (!append_alloted(alloted
, name
, n
)) {
339 free_groupnames(groups
);
343 /* Now return the total number of nics that this user can create. */
347 static char *get_eol(char *s
, char *e
)
349 while ((s
< e
) && *s
&& (*s
!= '\n'))
354 static char *get_eow(char *s
, char *e
)
356 while ((s
< e
) && *s
&& !isblank(*s
) && (*s
!= '\n'))
361 static char *find_line(char *buf_start
, char *buf_end
, char *name
,
362 char *net_type
, char *net_link
, char *net_dev
,
363 bool *owner
, bool *found
, bool *keep
)
365 char *end_of_line
, *end_of_word
, *line
;
367 while (buf_start
< buf_end
) {
369 char netdev_name
[IFNAMSIZ
];
375 end_of_line
= get_eol(buf_start
, buf_end
);
376 if (end_of_line
>= buf_end
)
380 if (*buf_start
== '#')
383 while ((buf_start
< buf_end
) && isblank(*buf_start
))
386 /* Check whether the line contains the caller's name. */
387 end_of_word
= get_eow(buf_start
, buf_end
);
392 if (strncmp(buf_start
, name
, strlen(name
)))
397 buf_start
= end_of_word
+ 1;
398 while ((buf_start
< buf_end
) && isblank(*buf_start
))
401 /* Check whether line is of the right network type. */
402 end_of_word
= get_eow(buf_start
, buf_end
);
407 if (strncmp(buf_start
, net_type
, strlen(net_type
)))
410 buf_start
= end_of_word
+ 1;
411 while ((buf_start
< buf_end
) && isblank(*buf_start
))
414 /* Check whether line is contains the right link. */
415 end_of_word
= get_eow(buf_start
, buf_end
);
420 if (strncmp(buf_start
, net_link
, strlen(net_link
)))
423 buf_start
= end_of_word
+ 1;
424 while ((buf_start
< buf_end
) && isblank(*buf_start
))
427 /* Check whether line contains the right network device. */
428 end_of_word
= get_eow(buf_start
, buf_end
);
433 len
= end_of_word
- buf_start
;
438 memcpy(netdev_name
, buf_start
, len
);
439 netdev_name
[len
] = '\0';
440 *keep
= lxc_nic_exists(netdev_name
);
442 if (net_dev
&& !strcmp(netdev_name
, net_dev
))
448 buf_start
= end_of_line
+ 1;
454 static int instantiate_veth(char *veth1
, char *veth2
)
458 ret
= lxc_veth_create(veth1
, veth2
);
460 usernic_error("Failed to create %s-%s : %s.\n", veth1
, veth2
,
465 /* Changing the high byte of the mac address to 0xfe, the bridge
466 * interface will always keep the host's mac address and not take the
467 * mac address of a container. */
468 ret
= setup_private_host_hw_addr(veth1
);
470 usernic_error("Failed to change mac address of host interface "
471 "%s : %s\n", veth1
, strerror(-ret
));
473 return netdev_set_flag(veth1
, IFF_UP
);
476 static int get_mtu(char *name
)
480 idx
= if_nametoindex(name
);
483 return netdev_get_mtu(idx
);
486 static int create_nic(char *nic
, char *br
, int pid
, char **cnic
)
488 char veth1buf
[IFNAMSIZ
], veth2buf
[IFNAMSIZ
];
491 ret
= snprintf(veth1buf
, IFNAMSIZ
, "%s", nic
);
492 if (ret
< 0 || ret
>= IFNAMSIZ
) {
493 usernic_error("%s", "Could not create nic name\n");
497 ret
= snprintf(veth2buf
, IFNAMSIZ
, "%sp", veth1buf
);
498 if (ret
< 0 || ret
>= IFNAMSIZ
) {
499 usernic_error("%s\n", "Could not create nic name");
502 /* create the nics */
503 ret
= instantiate_veth(veth1buf
, veth2buf
);
505 usernic_error("%s", "Error creating veth tunnel\n");
509 if (strcmp(br
, "none")) {
510 /* copy the bridge's mtu to both ends */
513 ret
= lxc_netdev_set_mtu(veth1buf
, mtu
);
515 usernic_error("Failed to set mtu to %d on %s\n",
520 ret
= lxc_netdev_set_mtu(veth2buf
, mtu
);
522 usernic_error("Failed to set mtu to %d on %s\n",
528 /* attach veth1 to bridge */
529 ret
= lxc_bridge_attach(br
, veth1buf
);
531 usernic_error("Error attaching %s to %s\n", veth1buf
, br
);
536 /* pass veth2 to target netns */
537 ret
= lxc_netdev_move_by_name(veth2buf
, pid
, NULL
);
539 usernic_error("Error moving %s to network namespace of %d\n",
544 *cnic
= strdup(veth2buf
);
546 usernic_error("Failed to copy string \"%s\"\n", veth2buf
);
553 lxc_netdev_delete_by_name(veth1buf
);
563 static bool cull_entries(int fd
, char *name
, char *net_type
, char *net_link
,
564 char *net_dev
, bool *found_nicname
)
567 char *buf
, *buf_end
, *buf_start
;
571 struct entry_line
*entry_lines
= NULL
;
573 ret
= fstat(fd
, &sb
);
575 usernic_error("Failed to fstat: %s\n", strerror(errno
));
582 buf
= lxc_strmmap(NULL
, sb
.st_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
583 if (buf
== MAP_FAILED
) {
584 usernic_error("Failed to establish shared memory mapping: %s\n",
590 buf_end
= buf
+ sb
.st_size
;
591 while ((buf_start
= find_line(buf_start
, buf_end
, name
, net_type
,
592 net_link
, net_dev
, &(bool){true}, &found
,
594 struct entry_line
*newe
;
596 newe
= realloc(entry_lines
, sizeof(*entry_lines
) * (n
+ 1));
599 lxc_strmunmap(buf
, sb
.st_size
);
604 *found_nicname
= true;
607 entry_lines
[n
].start
= buf_start
;
608 entry_lines
[n
].len
= get_eol(buf_start
, buf_end
) - entry_lines
[n
].start
;
609 entry_lines
[n
].keep
= keep
;
612 buf_start
+= entry_lines
[n
- 1].len
+ 1;
613 if (buf_start
>= buf_end
)
618 for (i
= 0; i
< n
; i
++) {
619 if (!entry_lines
[i
].keep
)
622 memcpy(buf_start
, entry_lines
[i
].start
, entry_lines
[i
].len
);
623 buf_start
+= entry_lines
[i
].len
;
629 ret
= ftruncate(fd
, buf_start
- buf
);
630 lxc_strmunmap(buf
, sb
.st_size
);
632 usernic_error("Failed to set new file size: %s\n",
638 static int count_entries(char *buf
, off_t len
, char *name
, char *net_type
, char *net_link
)
645 while ((buf
= find_line(buf
, buf_end
, name
, net_type
, net_link
, NULL
,
646 &owner
, &(bool){true}, &(bool){true}))) {
649 buf
= get_eol(buf
, buf_end
) + 1;
657 /* The dbfile has lines of the format: user type bridge nicname. */
658 static char *get_nic_if_avail(int fd
, struct alloted_s
*names
, int pid
,
659 char *intype
, char *br
, int allowed
, char **cnic
)
663 char *newline
, *owner
;
664 char nicname
[IFNAMSIZ
];
670 for (n
= names
; n
!= NULL
; n
= n
->next
)
671 cull_entries(fd
, n
->name
, intype
, br
, NULL
, NULL
);
678 ret
= fstat(fd
, &sb
);
680 usernic_error("Failed to fstat: %s\n", strerror(errno
));
684 if (sb
.st_size
> 0) {
685 buf
= lxc_strmmap(NULL
, sb
.st_size
, PROT_READ
| PROT_WRITE
,
687 if (buf
== MAP_FAILED
) {
688 usernic_error("Failed to establish shared memory "
689 "mapping: %s\n", strerror(errno
));
694 for (n
= names
; n
!= NULL
; n
= n
->next
) {
695 count
= count_entries(buf
, sb
.st_size
, n
->name
, intype
, br
);
696 if (count
>= n
->allowed
)
703 lxc_strmunmap(buf
, sb
.st_size
);
709 ret
= snprintf(nicname
, sizeof(nicname
), "vethXXXXXX");
710 if (ret
< 0 || (size_t)ret
>= sizeof(nicname
))
713 if (!lxc_mkifname(nicname
))
716 ret
= create_nic(nicname
, br
, pid
, cnic
);
718 usernic_error("%s", "Failed to create new nic\n");
740 slen
= strlen(owner
) + strlen(intype
) + strlen(br
) + strlen(nicname
) + 4;
741 newline
= malloc(slen
+ 1);
744 usernic_error("Failed allocate memory: %s\n", strerror(errno
));
748 ret
= snprintf(newline
, slen
+ 1, "%s %s %s %s\n", owner
, intype
, br
, nicname
);
749 if (ret
< 0 || (size_t)ret
>= (slen
+ 1)) {
750 if (lxc_netdev_delete_by_name(nicname
) != 0)
751 usernic_error("Error unlinking %s\n", nicname
);
756 /* Note that the file needs to be truncated to the size **without** the
757 * \0 byte! Files are not \0-terminated!
759 ret
= ftruncate(fd
, sb
.st_size
+ slen
);
761 usernic_error("Failed to truncate file: %s\n", strerror(errno
));
763 buf
= lxc_strmmap(NULL
, sb
.st_size
+ slen
, PROT_READ
| PROT_WRITE
,
765 if (buf
== MAP_FAILED
) {
766 usernic_error("Failed to establish shared memory mapping: %s\n",
768 if (lxc_netdev_delete_by_name(nicname
) != 0)
769 usernic_error("Error unlinking %s\n", nicname
);
774 /* Note that the memory needs to be moved in the buffer **without** the
775 * \0 byte! Files are not \0-terminated!
777 memmove(buf
+ sb
.st_size
, newline
, slen
);
779 lxc_strmunmap(buf
, sb
.st_size
+ slen
);
781 return strdup(nicname
);
784 static bool create_db_dir(char *fnam
)
789 p
= alloca(strlen(fnam
) + 1);
795 while (*p
&& *p
!= '/')
802 ret
= mkdir(fnam
, 0755);
803 if (ret
< 0 && errno
!= EEXIST
) {
804 usernic_error("Failed to create %s: %s\n", fnam
,
814 static char *lxc_secure_rename_in_ns(int pid
, char *oldname
, char *newname
,
815 int *container_veth_ifidx
)
819 uid_t ruid
, suid
, euid
;
820 char ifname
[IFNAMSIZ
];
821 char *string_ret
= NULL
, *name
= NULL
;
822 int fd
= -1, ifindex
= -1, ofd
= -1;
824 pid_self
= lxc_raw_getpid();
825 ofd
= lxc_preserve_ns(pid_self
, "net");
827 usernic_error("Failed opening network namespace path for %d", pid_self
);
831 fd
= lxc_preserve_ns(pid
, "net");
833 usernic_error("Failed opening network namespace path for %d", pid
);
834 goto do_partial_cleanup
;
837 ret
= getresuid(&ruid
, &euid
, &suid
);
839 usernic_error("Failed to retrieve real, effective, and saved "
842 goto do_partial_cleanup
;
845 ret
= setns(fd
, CLONE_NEWNET
);
849 usernic_error("Failed to setns() to the network namespace of "
850 "the container with PID %d: %s\n",
851 pid
, strerror(errno
));
852 goto do_partial_cleanup
;
855 ret
= setresuid(ruid
, ruid
, 0);
857 usernic_error("Failed to drop privilege by setting effective "
858 "user id and real user id to %d, and saved user "
860 ruid
, strerror(errno
));
861 /* It's ok to jump to do_full_cleanup here since setresuid()
862 * will succeed when trying to set real, effective, and saved to
863 * values they currently have.
865 goto do_full_cleanup
;
868 /* Check if old interface exists. */
869 ifindex
= if_nametoindex(oldname
);
871 usernic_error("Failed to get netdev index: %s\n", strerror(errno
));
872 goto do_full_cleanup
;
875 /* When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
876 * netlink will replace the format specifier with an appropriate index.
877 * So we pass "eth%d".
884 ret
= lxc_netdev_rename_by_name(oldname
, name
);
887 usernic_error("Error %d renaming netdev %s to %s in container\n",
888 ret
, oldname
, newname
? newname
: "eth%d");
889 goto do_full_cleanup
;
892 /* Retrieve new name for interface. */
893 if (!if_indextoname(ifindex
, ifname
)) {
894 usernic_error("Failed to get new netdev name: %s\n", strerror(errno
));
895 goto do_full_cleanup
;
898 /* Allocation failure for strdup() is checked below. */
899 name
= strdup(ifname
);
901 *container_veth_ifidx
= ifindex
;
904 ret
= setresuid(ruid
, euid
, suid
);
906 usernic_error("Failed to restore privilege by setting "
907 "effective user id to %d, real user id to %d, "
908 "and saved user ID to %d: %s\n", ruid
, euid
, suid
,
914 ret
= setns(ofd
, CLONE_NEWNET
);
916 usernic_error("Failed to setns() to original network namespace "
917 "of PID %d: %s\n", ofd
, strerror(errno
));
926 if (!string_ret
&& name
)
934 /* If the caller (real uid, not effective uid) may read the /proc/[pid]/ns/net,
935 * then it is either the caller's netns or one which it created.
937 static bool may_access_netns(int pid
)
941 uid_t ruid
, suid
, euid
;
942 bool may_access
= false;
944 ret
= getresuid(&ruid
, &euid
, &suid
);
946 usernic_error("Failed to retrieve real, effective, and saved "
952 ret
= setresuid(ruid
, ruid
, euid
);
954 usernic_error("Failed to drop privilege by setting effective "
955 "user id and real user id to %d, and saved user "
957 ruid
, euid
, strerror(errno
));
961 ret
= snprintf(s
, 200, "/proc/%d/ns/net", pid
);
962 if (ret
< 0 || ret
>= 200)
965 ret
= access(s
, R_OK
);
969 usernic_error("Uid %d may not access %s: %s\n", (int)ruid
, s
, strerror(errno
));
972 ret
= setresuid(ruid
, euid
, suid
);
974 usernic_error("Failed to restore user id to %d, real user id "
975 "to %d, and saved user ID to %d: %s\n",
976 ruid
, euid
, suid
, strerror(errno
));
983 struct user_nic_args
{
993 #define LXC_USERNIC_CREATE 0
994 #define LXC_USERNIC_DELETE 1
996 static bool is_privileged_over_netns(int netns_fd
)
1000 uid_t euid
, ruid
, suid
;
1004 pid_self
= lxc_raw_getpid();
1005 ofd
= lxc_preserve_ns(pid_self
, "net");
1007 usernic_error("Failed opening network namespace path for %d", pid_self
);
1011 ret
= getresuid(&ruid
, &euid
, &suid
);
1013 usernic_error("Failed to retrieve real, effective, and saved "
1016 goto do_partial_cleanup
;
1019 ret
= setns(netns_fd
, CLONE_NEWNET
);
1021 usernic_error("Failed to setns() to network namespace %s\n",
1023 goto do_partial_cleanup
;
1026 ret
= setresuid(ruid
, ruid
, 0);
1028 usernic_error("Failed to drop privilege by setting effective "
1029 "user id and real user id to %d, and saved user "
1031 ruid
, strerror(errno
));
1032 /* It's ok to jump to do_full_cleanup here since setresuid()
1033 * will succeed when trying to set real, effective, and saved to
1034 * values they currently have.
1036 goto do_full_cleanup
;
1039 /* Test whether we are privileged over the network namespace. To do this
1040 * we try to delete the loopback interface which is not possible. If we
1041 * are privileged over the network namespace we will get ENOTSUP. If we
1042 * are not privileged over the network namespace we will get EPERM.
1044 ret
= lxc_netdev_delete_by_name("lo");
1045 if (ret
== -ENOTSUP
)
1049 ret
= setresuid(ruid
, euid
, suid
);
1051 usernic_error("Failed to restore privilege by setting "
1052 "effective user id to %d, real user id to %d, "
1053 "and saved user ID to %d: %s\n", ruid
, euid
, suid
,
1059 ret
= setns(ofd
, CLONE_NEWNET
);
1061 usernic_error("Failed to setns() to original network namespace "
1062 "of PID %d: %s\n", ofd
, strerror(errno
));
1073 int main(int argc
, char *argv
[])
1075 int fd
, n
, pid
, request
, ret
;
1077 struct user_nic_args args
;
1078 int container_veth_ifidx
= -1, host_veth_ifidx
= -1, netns_fd
= -1;
1079 char *cnic
= NULL
, *nicname
= NULL
;
1080 struct alloted_s
*alloted
= NULL
;
1082 if (argc
< 7 || argc
> 8) {
1083 usage(argv
[0], true);
1087 memset(&args
, 0, sizeof(struct user_nic_args
));
1089 args
.lxc_path
= argv
[2];
1090 args
.lxc_name
= argv
[3];
1092 args
.type
= argv
[5];
1093 args
.link
= argv
[6];
1095 args
.veth_name
= argv
[7];
1097 if (!strcmp(args
.cmd
, "create")) {
1098 request
= LXC_USERNIC_CREATE
;
1099 } else if (!strcmp(args
.cmd
, "delete")) {
1100 request
= LXC_USERNIC_DELETE
;
1102 usage(argv
[0], true);
1106 /* Set a sane env, because we are setuid-root. */
1109 usernic_error("%s", "Failed to clear environment\n");
1113 ret
= setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
1115 usernic_error("%s", "Failed to set PATH, exiting\n");
1119 me
= get_username();
1121 usernic_error("%s", "Failed to get username\n");
1125 if (request
== LXC_USERNIC_CREATE
) {
1126 ret
= lxc_safe_int(args
.pid
, &pid
);
1128 usernic_error("Could not read pid: %s\n", args
.pid
);
1131 } else if (request
== LXC_USERNIC_DELETE
) {
1132 netns_fd
= open(args
.pid
, O_RDONLY
);
1134 usernic_error("Could not open \"%s\": %s\n", args
.pid
,
1140 if (!create_db_dir(LXC_USERNIC_DB
)) {
1141 usernic_error("%s", "Failed to create directory for db file\n");
1147 fd
= open_and_lock(LXC_USERNIC_DB
);
1149 usernic_error("Failed to lock %s\n", LXC_USERNIC_DB
);
1155 if (request
== LXC_USERNIC_CREATE
) {
1156 if (!may_access_netns(pid
)) {
1157 usernic_error("User %s may not modify netns for pid %d\n", me
, pid
);
1160 } else if (request
== LXC_USERNIC_DELETE
) {
1162 has_priv
= is_privileged_over_netns(netns_fd
);
1165 usernic_error("%s", "Process is not privileged over "
1166 "network namespace\n");
1171 n
= get_alloted(me
, args
.type
, args
.link
, &alloted
);
1173 if (request
== LXC_USERNIC_DELETE
) {
1175 struct alloted_s
*it
;
1176 bool found_nicname
= false;
1178 if (!is_ovs_bridge(args
.link
)) {
1179 usernic_error("%s", "Deletion of non ovs type network "
1180 "devices not implemented\n");
1182 free_alloted(&alloted
);
1186 /* Check whether the network device we are supposed to delete
1187 * exists in the db. If it doesn't we will not delete it as we
1188 * need to assume the network device is not under our control.
1189 * As a side effect we also clear any invalid entries from the
1192 for (it
= alloted
; it
; it
= it
->next
)
1193 cull_entries(fd
, it
->name
, args
.type
, args
.link
,
1194 args
.veth_name
, &found_nicname
);
1196 free_alloted(&alloted
);
1198 if (!found_nicname
) {
1199 usernic_error("Caller is not allowed to delete network "
1200 "device \"%s\"\n", args
.veth_name
);
1204 ret
= lxc_ovs_delete_port(args
.link
, args
.veth_name
);
1206 usernic_error("Failed to remove port \"%s\" from "
1207 "openvswitch bridge \"%s\"",
1208 args
.veth_name
, args
.link
);
1215 nicname
= get_nic_if_avail(fd
, alloted
, pid
, args
.type
,
1216 args
.link
, n
, &cnic
);
1219 free_alloted(&alloted
);
1221 usernic_error("%s", "Quota reached\n");
1225 /* Now rename the link. */
1226 newname
= lxc_secure_rename_in_ns(pid
, cnic
, args
.veth_name
,
1227 &container_veth_ifidx
);
1229 usernic_error("%s", "Failed to rename the link\n");
1230 ret
= lxc_netdev_delete_by_name(cnic
);
1232 usernic_error("Failed to delete \"%s\"\n", cnic
);
1237 host_veth_ifidx
= if_nametoindex(nicname
);
1238 if (!host_veth_ifidx
) {
1241 usernic_error("Failed to get netdev index: %s\n", strerror(errno
));
1245 /* Write names of veth pairs and their ifindeces to stout:
1246 * (e.g. eth0:731:veth9MT2L4:730)
1248 fprintf(stdout
, "%s:%d:%s:%d\n", newname
, container_veth_ifidx
, nicname
,