]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/cmd/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"
55 #include "include/strlcpy.h"
58 #define usernic_debug_stream(stream, format, ...) \
60 fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \
61 __func__, __VA_ARGS__); \
64 #define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__)
66 static void usage(char *me
, bool fail
)
68 fprintf(stderr
, "Usage: %s create {lxcpath} {name} {pid} {type} "
69 "{bridge} {nicname}\n", me
);
70 fprintf(stderr
, "Usage: %s delete {lxcpath} {name} "
71 "{/proc/<pid>/ns/net} {type} {bridge} {nicname}\n", me
);
72 fprintf(stderr
, "{nicname} is the name to use inside the container\n");
80 static int open_and_lock(char *path
)
85 fd
= open(path
, O_RDWR
| O_CREAT
, S_IWUSR
| S_IRUSR
);
87 usernic_error("Failed to open \"%s\": %s\n", path
,
93 lk
.l_whence
= SEEK_SET
;
97 ret
= fcntl(fd
, F_SETLKW
, &lk
);
99 usernic_error("Failed to lock \"%s\": %s\n", path
,
108 static char *get_username(void)
111 struct passwd
*pwentp
= NULL
;
117 bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
);
121 buf
= malloc(bufsize
);
125 ret
= getpwuid_r(getuid(), &pwent
, buf
, bufsize
, &pwentp
);
128 usernic_error("%s", "Could not find matched password record\n");
130 usernic_error("Failed to get username: %s(%u)\n", strerror(errno
), getuid());
135 username
= strdup(pwent
.pw_name
);
141 static void free_groupnames(char **groupnames
)
148 for (i
= 0; groupnames
[i
]; i
++)
154 static char **get_groupnames(void)
161 struct group
*grentp
= NULL
;
165 ngroups
= getgroups(0, NULL
);
167 usernic_error("Failed to get number of groups the user "
168 "belongs to: %s\n", strerror(errno
));
174 group_ids
= malloc(sizeof(gid_t
) * ngroups
);
176 usernic_error("Failed to allocate memory while getting groups "
177 "the user belongs to: %s\n",
182 ret
= getgroups(ngroups
, group_ids
);
185 usernic_error("Failed to get process groups: %s\n",
190 groupnames
= malloc(sizeof(char *) * (ngroups
+ 1));
193 usernic_error("Failed to allocate memory while getting group "
199 memset(groupnames
, 0, sizeof(char *) * (ngroups
+ 1));
201 bufsize
= sysconf(_SC_GETGR_R_SIZE_MAX
);
205 buf
= malloc(bufsize
);
208 free_groupnames(groupnames
);
209 usernic_error("Failed to allocate memory while getting group "
215 for (i
= 0; i
< ngroups
; i
++) {
216 ret
= getgrgid_r(group_ids
[i
], &grent
, buf
, bufsize
, &grentp
);
219 usernic_error("%s", "Could not find matched group record\n");
221 usernic_error("Failed to get group name: %s(%u)\n",
222 strerror(errno
), group_ids
[i
]);
225 free_groupnames(groupnames
);
229 groupnames
[i
] = strdup(grent
.gr_name
);
230 if (!groupnames
[i
]) {
231 usernic_error("Failed to copy group name \"%s\"",
235 free_groupnames(groupnames
);
246 static bool name_is_in_groupnames(char *name
, char **groupnames
)
249 if (!strcmp(name
, *groupnames
))
259 struct alloted_s
*next
;
262 static struct alloted_s
*append_alloted(struct alloted_s
**head
, char *name
,
265 struct alloted_s
*cur
, *al
;
267 if (!head
|| !name
) {
268 /* Sanity check. Parameters should not be null. */
269 usernic_error("%s\n", "Unexpected NULL argument");
273 al
= malloc(sizeof(struct alloted_s
));
275 usernic_error("Failed to allocate memory: %s\n",
280 al
->name
= strdup(name
);
302 static void free_alloted(struct alloted_s
**head
)
304 struct alloted_s
*cur
;
318 /* The configuration file consists of lines of the form:
320 * user type bridge count
322 * @group type bridge count
324 * Return the count entry for the calling user if there is one. Else
327 static int get_alloted(char *me
, char *intype
, char *link
,
328 struct alloted_s
**alloted
)
331 char name
[100], type
[100], br
[100];
339 fin
= fopen(LXC_USERNIC_CONF
, "r");
341 usernic_error("Failed to open \"%s\": %s\n", LXC_USERNIC_CONF
,
346 groups
= get_groupnames();
347 while ((getline(&line
, &len
, fin
)) != -1) {
348 ret
= sscanf(line
, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name
,
353 if (strlen(name
) == 0)
356 if (strcmp(name
, me
)) {
360 if (!name_is_in_groupnames(name
+ 1, groups
))
364 if (strcmp(type
, intype
))
367 if (strcmp(link
, br
))
370 /* Found the user or group with the appropriate settings,
371 * therefore finish the search. What to do if there are more
372 * than one applicable lines? not specified in the docs. Since
373 * getline is implemented with realloc, we don't need to free
374 * line until exiting func.
376 * If append_alloted returns NULL, e.g. due to a malloc error,
377 * we set count to 0 and break the loop, allowing cleanup and
378 * then exiting from main().
380 if (!append_alloted(alloted
, name
, n
)) {
387 free_groupnames(groups
);
391 /* Now return the total number of nics that this user can create. */
395 static char *get_eol(char *s
, char *e
)
397 while ((s
< e
) && *s
&& (*s
!= '\n'))
402 static char *get_eow(char *s
, char *e
)
404 while ((s
< e
) && *s
&& !isblank(*s
) && (*s
!= '\n'))
409 static char *find_line(char *buf_start
, char *buf_end
, char *name
,
410 char *net_type
, char *net_link
, char *net_dev
,
411 bool *owner
, bool *found
, bool *keep
)
413 char *end_of_line
, *end_of_word
, *line
;
415 while (buf_start
< buf_end
) {
417 char netdev_name
[IFNAMSIZ
];
423 end_of_line
= get_eol(buf_start
, buf_end
);
424 if (end_of_line
>= buf_end
)
428 if (*buf_start
== '#')
431 while ((buf_start
< buf_end
) && isblank(*buf_start
))
434 /* Check whether the line contains the caller's name. */
435 end_of_word
= get_eow(buf_start
, buf_end
);
440 if (strncmp(buf_start
, name
, strlen(name
)))
445 buf_start
= end_of_word
+ 1;
446 while ((buf_start
< buf_end
) && isblank(*buf_start
))
449 /* Check whether line is of the right network type. */
450 end_of_word
= get_eow(buf_start
, buf_end
);
455 if (strncmp(buf_start
, net_type
, strlen(net_type
)))
458 buf_start
= end_of_word
+ 1;
459 while ((buf_start
< buf_end
) && isblank(*buf_start
))
462 /* Check whether line is contains the right link. */
463 end_of_word
= get_eow(buf_start
, buf_end
);
468 if (strncmp(buf_start
, net_link
, strlen(net_link
)))
471 buf_start
= end_of_word
+ 1;
472 while ((buf_start
< buf_end
) && isblank(*buf_start
))
475 /* Check whether line contains the right network device. */
476 end_of_word
= get_eow(buf_start
, buf_end
);
481 len
= end_of_word
- buf_start
;
486 memcpy(netdev_name
, buf_start
, len
);
487 netdev_name
[len
] = '\0';
488 *keep
= lxc_nic_exists(netdev_name
);
490 if (net_dev
&& !strcmp(netdev_name
, net_dev
))
496 buf_start
= end_of_line
+ 1;
502 static int instantiate_veth(char *veth1
, char *veth2
)
506 ret
= lxc_veth_create(veth1
, veth2
);
508 usernic_error("Failed to create %s-%s : %s.\n", veth1
, veth2
,
513 /* Changing the high byte of the mac address to 0xfe, the bridge
514 * interface will always keep the host's mac address and not take the
515 * mac address of a container. */
516 ret
= setup_private_host_hw_addr(veth1
);
518 usernic_error("Failed to change mac address of host interface "
519 "%s : %s\n", veth1
, strerror(-ret
));
521 return netdev_set_flag(veth1
, IFF_UP
);
524 static int get_mtu(char *name
)
528 idx
= if_nametoindex(name
);
531 return netdev_get_mtu(idx
);
534 static int create_nic(char *nic
, char *br
, int pid
, char **cnic
)
536 char veth1buf
[IFNAMSIZ
], veth2buf
[IFNAMSIZ
];
539 ret
= snprintf(veth1buf
, IFNAMSIZ
, "%s", nic
);
540 if (ret
< 0 || ret
>= IFNAMSIZ
) {
541 usernic_error("%s", "Could not create nic name\n");
545 ret
= snprintf(veth2buf
, IFNAMSIZ
, "%sp", veth1buf
);
546 if (ret
< 0 || ret
>= IFNAMSIZ
) {
547 usernic_error("%s\n", "Could not create nic name");
550 /* create the nics */
551 ret
= instantiate_veth(veth1buf
, veth2buf
);
553 usernic_error("%s", "Error creating veth tunnel\n");
557 if (strcmp(br
, "none")) {
558 /* copy the bridge's mtu to both ends */
561 ret
= lxc_netdev_set_mtu(veth1buf
, mtu
);
563 usernic_error("Failed to set mtu to %d on %s\n",
568 ret
= lxc_netdev_set_mtu(veth2buf
, mtu
);
570 usernic_error("Failed to set mtu to %d on %s\n",
576 /* attach veth1 to bridge */
577 ret
= lxc_bridge_attach(br
, veth1buf
);
579 usernic_error("Error attaching %s to %s\n", veth1buf
, br
);
584 /* pass veth2 to target netns */
585 ret
= lxc_netdev_move_by_name(veth2buf
, pid
, NULL
);
587 usernic_error("Error moving %s to network namespace of %d\n",
592 *cnic
= strdup(veth2buf
);
594 usernic_error("Failed to copy string \"%s\"\n", veth2buf
);
601 lxc_netdev_delete_by_name(veth1buf
);
611 static bool cull_entries(int fd
, char *name
, char *net_type
, char *net_link
,
612 char *net_dev
, bool *found_nicname
)
615 char *buf
, *buf_end
, *buf_start
;
619 struct entry_line
*entry_lines
= NULL
;
621 ret
= fstat(fd
, &sb
);
623 usernic_error("Failed to fstat: %s\n", strerror(errno
));
630 buf
= lxc_strmmap(NULL
, sb
.st_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
631 if (buf
== MAP_FAILED
) {
632 usernic_error("Failed to establish shared memory mapping: %s\n",
638 buf_end
= buf
+ sb
.st_size
;
639 while ((buf_start
= find_line(buf_start
, buf_end
, name
, net_type
,
640 net_link
, net_dev
, &(bool){true}, &found
,
642 struct entry_line
*newe
;
644 newe
= realloc(entry_lines
, sizeof(*entry_lines
) * (n
+ 1));
647 lxc_strmunmap(buf
, sb
.st_size
);
652 *found_nicname
= true;
655 entry_lines
[n
].start
= buf_start
;
656 entry_lines
[n
].len
= get_eol(buf_start
, buf_end
) - entry_lines
[n
].start
;
657 entry_lines
[n
].keep
= keep
;
660 buf_start
+= entry_lines
[n
- 1].len
+ 1;
661 if (buf_start
>= buf_end
)
666 for (i
= 0; i
< n
; i
++) {
667 if (!entry_lines
[i
].keep
)
670 memcpy(buf_start
, entry_lines
[i
].start
, entry_lines
[i
].len
);
671 buf_start
+= entry_lines
[i
].len
;
677 ret
= ftruncate(fd
, buf_start
- buf
);
678 lxc_strmunmap(buf
, sb
.st_size
);
680 usernic_error("Failed to set new file size: %s\n",
686 static int count_entries(char *buf
, off_t len
, char *name
, char *net_type
, char *net_link
)
693 while ((buf
= find_line(buf
, buf_end
, name
, net_type
, net_link
, NULL
,
694 &owner
, &(bool){true}, &(bool){true}))) {
697 buf
= get_eol(buf
, buf_end
) + 1;
705 /* The dbfile has lines of the format: user type bridge nicname. */
706 static char *get_nic_if_avail(int fd
, struct alloted_s
*names
, int pid
,
707 char *intype
, char *br
, int allowed
, char **cnic
)
711 char *newline
, *owner
;
712 char nicname
[IFNAMSIZ
];
718 for (n
= names
; n
!= NULL
; n
= n
->next
)
719 cull_entries(fd
, n
->name
, intype
, br
, NULL
, NULL
);
726 ret
= fstat(fd
, &sb
);
728 usernic_error("Failed to fstat: %s\n", strerror(errno
));
732 if (sb
.st_size
> 0) {
733 buf
= lxc_strmmap(NULL
, sb
.st_size
, PROT_READ
| PROT_WRITE
,
735 if (buf
== MAP_FAILED
) {
736 usernic_error("Failed to establish shared memory "
737 "mapping: %s\n", strerror(errno
));
742 for (n
= names
; n
!= NULL
; n
= n
->next
) {
743 count
= count_entries(buf
, sb
.st_size
, n
->name
, intype
, br
);
744 if (count
>= n
->allowed
)
751 lxc_strmunmap(buf
, sb
.st_size
);
757 ret
= snprintf(nicname
, sizeof(nicname
), "vethXXXXXX");
758 if (ret
< 0 || (size_t)ret
>= sizeof(nicname
))
761 if (!lxc_mkifname(nicname
))
764 ret
= create_nic(nicname
, br
, pid
, cnic
);
766 usernic_error("%s", "Failed to create new nic\n");
788 slen
= strlen(owner
) + strlen(intype
) + strlen(br
) + strlen(nicname
) + 4;
789 newline
= malloc(slen
+ 1);
792 usernic_error("Failed allocate memory: %s\n", strerror(errno
));
796 ret
= snprintf(newline
, slen
+ 1, "%s %s %s %s\n", owner
, intype
, br
, nicname
);
797 if (ret
< 0 || (size_t)ret
>= (slen
+ 1)) {
798 if (lxc_netdev_delete_by_name(nicname
) != 0)
799 usernic_error("Error unlinking %s\n", nicname
);
804 /* Note that the file needs to be truncated to the size **without** the
805 * \0 byte! Files are not \0-terminated!
807 ret
= ftruncate(fd
, sb
.st_size
+ slen
);
809 usernic_error("Failed to truncate file: %s\n", strerror(errno
));
811 buf
= lxc_strmmap(NULL
, sb
.st_size
+ slen
, PROT_READ
| PROT_WRITE
,
813 if (buf
== MAP_FAILED
) {
814 usernic_error("Failed to establish shared memory mapping: %s\n",
816 if (lxc_netdev_delete_by_name(nicname
) != 0)
817 usernic_error("Error unlinking %s\n", nicname
);
822 /* Note that the memory needs to be moved in the buffer **without** the
823 * \0 byte! Files are not \0-terminated!
825 memmove(buf
+ sb
.st_size
, newline
, slen
);
827 lxc_strmunmap(buf
, sb
.st_size
+ slen
);
829 return strdup(nicname
);
832 static bool create_db_dir(char *fnam
)
840 (void)strlcpy(p
, fnam
, len
+ 1);
845 while (*p
&& *p
!= '/')
852 ret
= mkdir(fnam
, 0755);
853 if (ret
< 0 && errno
!= EEXIST
) {
854 usernic_error("Failed to create %s: %s\n", fnam
,
864 static char *lxc_secure_rename_in_ns(int pid
, char *oldname
, char *newname
,
865 int *container_veth_ifidx
)
869 uid_t ruid
, suid
, euid
;
870 char ifname
[IFNAMSIZ
];
871 char *string_ret
= NULL
, *name
= NULL
;
872 int fd
= -1, ifindex
= -1, ofd
= -1;
874 pid_self
= lxc_raw_getpid();
875 ofd
= lxc_preserve_ns(pid_self
, "net");
877 usernic_error("Failed opening network namespace path for %d", pid_self
);
881 fd
= lxc_preserve_ns(pid
, "net");
883 usernic_error("Failed opening network namespace path for %d", pid
);
884 goto do_partial_cleanup
;
887 ret
= getresuid(&ruid
, &euid
, &suid
);
889 usernic_error("Failed to retrieve real, effective, and saved "
892 goto do_partial_cleanup
;
895 ret
= setns(fd
, CLONE_NEWNET
);
899 usernic_error("Failed to setns() to the network namespace of "
900 "the container with PID %d: %s\n",
901 pid
, strerror(errno
));
902 goto do_partial_cleanup
;
905 ret
= setresuid(ruid
, ruid
, 0);
907 usernic_error("Failed to drop privilege by setting effective "
908 "user id and real user id to %d, and saved user "
910 ruid
, strerror(errno
));
911 /* It's ok to jump to do_full_cleanup here since setresuid()
912 * will succeed when trying to set real, effective, and saved to
913 * values they currently have.
915 goto do_full_cleanup
;
918 /* Check if old interface exists. */
919 ifindex
= if_nametoindex(oldname
);
921 usernic_error("Failed to get netdev index: %s\n", strerror(errno
));
922 goto do_full_cleanup
;
925 /* When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
926 * netlink will replace the format specifier with an appropriate index.
927 * So we pass "eth%d".
934 ret
= lxc_netdev_rename_by_name(oldname
, name
);
937 usernic_error("Error %d renaming netdev %s to %s in container\n",
938 ret
, oldname
, newname
? newname
: "eth%d");
939 goto do_full_cleanup
;
942 /* Retrieve new name for interface. */
943 if (!if_indextoname(ifindex
, ifname
)) {
944 usernic_error("Failed to get new netdev name: %s\n", strerror(errno
));
945 goto do_full_cleanup
;
948 /* Allocation failure for strdup() is checked below. */
949 name
= strdup(ifname
);
951 *container_veth_ifidx
= ifindex
;
954 ret
= setresuid(ruid
, euid
, suid
);
956 usernic_error("Failed to restore privilege by setting "
957 "effective user id to %d, real user id to %d, "
958 "and saved user ID to %d: %s\n", ruid
, euid
, suid
,
964 ret
= setns(ofd
, CLONE_NEWNET
);
966 usernic_error("Failed to setns() to original network namespace "
967 "of PID %d: %s\n", ofd
, strerror(errno
));
976 if (!string_ret
&& name
)
984 /* If the caller (real uid, not effective uid) may read the /proc/[pid]/ns/net,
985 * then it is either the caller's netns or one which it created.
987 static bool may_access_netns(int pid
)
991 uid_t ruid
, suid
, euid
;
992 bool may_access
= false;
994 ret
= getresuid(&ruid
, &euid
, &suid
);
996 usernic_error("Failed to retrieve real, effective, and saved "
1002 ret
= setresuid(ruid
, ruid
, euid
);
1004 usernic_error("Failed to drop privilege by setting effective "
1005 "user id and real user id to %d, and saved user "
1007 ruid
, euid
, strerror(errno
));
1011 ret
= snprintf(s
, 200, "/proc/%d/ns/net", pid
);
1012 if (ret
< 0 || ret
>= 200)
1015 ret
= access(s
, R_OK
);
1019 usernic_error("Uid %d may not access %s: %s\n", (int)ruid
, s
, strerror(errno
));
1022 ret
= setresuid(ruid
, euid
, suid
);
1024 usernic_error("Failed to restore user id to %d, real user id "
1025 "to %d, and saved user ID to %d: %s\n",
1026 ruid
, euid
, suid
, strerror(errno
));
1033 struct user_nic_args
{
1043 #define LXC_USERNIC_CREATE 0
1044 #define LXC_USERNIC_DELETE 1
1046 static bool is_privileged_over_netns(int netns_fd
)
1050 uid_t euid
, ruid
, suid
;
1054 pid_self
= lxc_raw_getpid();
1055 ofd
= lxc_preserve_ns(pid_self
, "net");
1057 usernic_error("Failed opening network namespace path for %d", pid_self
);
1061 ret
= getresuid(&ruid
, &euid
, &suid
);
1063 usernic_error("Failed to retrieve real, effective, and saved "
1066 goto do_partial_cleanup
;
1069 ret
= setns(netns_fd
, CLONE_NEWNET
);
1071 usernic_error("Failed to setns() to network namespace %s\n",
1073 goto do_partial_cleanup
;
1076 ret
= setresuid(ruid
, ruid
, 0);
1078 usernic_error("Failed to drop privilege by setting effective "
1079 "user id and real user id to %d, and saved user "
1081 ruid
, strerror(errno
));
1082 /* It's ok to jump to do_full_cleanup here since setresuid()
1083 * will succeed when trying to set real, effective, and saved to
1084 * values they currently have.
1086 goto do_full_cleanup
;
1089 /* Test whether we are privileged over the network namespace. To do this
1090 * we try to delete the loopback interface which is not possible. If we
1091 * are privileged over the network namespace we will get ENOTSUP. If we
1092 * are not privileged over the network namespace we will get EPERM.
1094 ret
= lxc_netdev_delete_by_name("lo");
1095 if (ret
== -ENOTSUP
)
1099 ret
= setresuid(ruid
, euid
, suid
);
1101 usernic_error("Failed to restore privilege by setting "
1102 "effective user id to %d, real user id to %d, "
1103 "and saved user ID to %d: %s\n", ruid
, euid
, suid
,
1109 ret
= setns(ofd
, CLONE_NEWNET
);
1111 usernic_error("Failed to setns() to original network namespace "
1112 "of PID %d: %s\n", ofd
, strerror(errno
));
1123 int main(int argc
, char *argv
[])
1125 int fd
, n
, pid
, request
, ret
;
1127 struct user_nic_args args
;
1128 int container_veth_ifidx
= -1, host_veth_ifidx
= -1, netns_fd
= -1;
1129 char *cnic
= NULL
, *nicname
= NULL
;
1130 struct alloted_s
*alloted
= NULL
;
1132 if (argc
< 7 || argc
> 8) {
1133 usage(argv
[0], true);
1137 memset(&args
, 0, sizeof(struct user_nic_args
));
1139 args
.lxc_path
= argv
[2];
1140 args
.lxc_name
= argv
[3];
1142 args
.type
= argv
[5];
1143 args
.link
= argv
[6];
1145 args
.veth_name
= argv
[7];
1147 if (!strcmp(args
.cmd
, "create")) {
1148 request
= LXC_USERNIC_CREATE
;
1149 } else if (!strcmp(args
.cmd
, "delete")) {
1150 request
= LXC_USERNIC_DELETE
;
1152 usage(argv
[0], true);
1156 /* Set a sane env, because we are setuid-root. */
1159 usernic_error("%s", "Failed to clear environment\n");
1163 ret
= setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
1165 usernic_error("%s", "Failed to set PATH, exiting\n");
1169 me
= get_username();
1171 usernic_error("%s", "Failed to get username\n");
1175 if (request
== LXC_USERNIC_CREATE
) {
1176 ret
= lxc_safe_int(args
.pid
, &pid
);
1178 usernic_error("Could not read pid: %s\n", args
.pid
);
1181 } else if (request
== LXC_USERNIC_DELETE
) {
1182 netns_fd
= open(args
.pid
, O_RDONLY
);
1184 usernic_error("Could not open \"%s\": %s\n", args
.pid
,
1190 if (!create_db_dir(LXC_USERNIC_DB
)) {
1191 usernic_error("%s", "Failed to create directory for db file\n");
1197 fd
= open_and_lock(LXC_USERNIC_DB
);
1199 usernic_error("Failed to lock %s\n", LXC_USERNIC_DB
);
1205 if (request
== LXC_USERNIC_CREATE
) {
1206 if (!may_access_netns(pid
)) {
1207 usernic_error("User %s may not modify netns for pid %d\n", me
, pid
);
1210 } else if (request
== LXC_USERNIC_DELETE
) {
1212 has_priv
= is_privileged_over_netns(netns_fd
);
1215 usernic_error("%s", "Process is not privileged over "
1216 "network namespace\n");
1221 n
= get_alloted(me
, args
.type
, args
.link
, &alloted
);
1224 if (request
== LXC_USERNIC_DELETE
) {
1226 struct alloted_s
*it
;
1227 bool found_nicname
= false;
1229 if (!is_ovs_bridge(args
.link
)) {
1230 usernic_error("%s", "Deletion of non ovs type network "
1231 "devices not implemented\n");
1233 free_alloted(&alloted
);
1237 /* Check whether the network device we are supposed to delete
1238 * exists in the db. If it doesn't we will not delete it as we
1239 * need to assume the network device is not under our control.
1240 * As a side effect we also clear any invalid entries from the
1243 for (it
= alloted
; it
; it
= it
->next
)
1244 cull_entries(fd
, it
->name
, args
.type
, args
.link
,
1245 args
.veth_name
, &found_nicname
);
1247 free_alloted(&alloted
);
1249 if (!found_nicname
) {
1250 usernic_error("Caller is not allowed to delete network "
1251 "device \"%s\"\n", args
.veth_name
);
1255 ret
= lxc_ovs_delete_port(args
.link
, args
.veth_name
);
1257 usernic_error("Failed to remove port \"%s\" from "
1258 "openvswitch bridge \"%s\"",
1259 args
.veth_name
, args
.link
);
1266 nicname
= get_nic_if_avail(fd
, alloted
, pid
, args
.type
,
1267 args
.link
, n
, &cnic
);
1270 free_alloted(&alloted
);
1272 usernic_error("%s", "Quota reached\n");
1276 /* Now rename the link. */
1277 newname
= lxc_secure_rename_in_ns(pid
, cnic
, args
.veth_name
,
1278 &container_veth_ifidx
);
1280 usernic_error("%s", "Failed to rename the link\n");
1281 ret
= lxc_netdev_delete_by_name(cnic
);
1283 usernic_error("Failed to delete \"%s\"\n", cnic
);
1288 host_veth_ifidx
= if_nametoindex(nicname
);
1289 if (!host_veth_ifidx
) {
1292 usernic_error("Failed to get netdev index: %s\n", strerror(errno
));
1296 /* Write names of veth pairs and their ifindeces to stout:
1297 * (e.g. eth0:731:veth9MT2L4:730)
1299 fprintf(stdout
, "%s:%d:%s:%d\n", newname
, container_veth_ifidx
, nicname
,