Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
d3e7b8ad
Commit
d3e7b8ad
authored
Aug 29, 2017
by
Stéphane Graber
Committed by
GitHub
Aug 29, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1768 from brauner/2017-08-29/stable_2.0_cherry_picks
stable 2.0: cherry picks
parents
d99d8dbc
4d26f247
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1826 additions
and
1509 deletions
+1826
-1509
attach.c
src/lxc/attach.c
+104
-82
attach.h
src/lxc/attach.h
+5
-3
cgfsng.c
src/lxc/cgroups/cgfsng.c
+17
-8
conf.c
src/lxc/conf.c
+2
-1053
conf.h
src/lxc/conf.h
+20
-122
confile_utils.c
src/lxc/confile_utils.c
+4
-1
lxc_user_nic.c
src/lxc/lxc_user_nic.c
+293
-175
network.c
src/lxc/network.c
+1240
-50
network.h
src/lxc/network.h
+131
-6
start.c
src/lxc/start.c
+3
-2
lxc-test-usernic.in
src/tests/lxc-test-usernic.in
+7
-7
No files found.
src/lxc/attach.c
View file @
d3e7b8ad
...
@@ -39,7 +39,9 @@
...
@@ -39,7 +39,9 @@
#include <sys/syscall.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/wait.h>
#if !HAVE_DECL_PR_CAPBSET_DROP
#include <lxc/lxccontainer.h>
#ifndef HAVE_DECL_PR_CAPBSET_DROP
#define PR_CAPBSET_DROP 24
#define PR_CAPBSET_DROP 24
#endif
#endif
...
@@ -58,14 +60,12 @@
...
@@ -58,14 +60,12 @@
#include "namespace.h"
#include "namespace.h"
#include "utils.h"
#include "utils.h"
#include <lxc/lxccontainer.h>
#if HAVE_SYS_PERSONALITY_H
#if HAVE_SYS_PERSONALITY_H
#include <sys/personality.h>
#include <sys/personality.h>
#endif
#endif
#ifndef SOCK_CLOEXEC
#ifndef SOCK_CLOEXEC
#
define SOCK_CLOEXEC
02000000
#
define SOCK_CLOEXEC
02000000
#endif
#endif
#ifndef MS_REC
#ifndef MS_REC
...
@@ -73,7 +73,7 @@
...
@@ -73,7 +73,7 @@
#endif
#endif
#ifndef MS_SLAVE
#ifndef MS_SLAVE
#define MS_SLAVE (1
<<
19)
#define MS_SLAVE (1
<<
19)
#endif
#endif
lxc_log_define
(
lxc_attach
,
lxc
);
lxc_log_define
(
lxc_attach
,
lxc
);
...
@@ -118,7 +118,7 @@ static int lsm_openat(int procfd, pid_t pid, int on_exec)
...
@@ -118,7 +118,7 @@ static int lsm_openat(int procfd, pid_t pid, int on_exec)
static
int
lsm_set_label_at
(
int
lsm_labelfd
,
int
on_exec
,
char
*
lsm_label
)
static
int
lsm_set_label_at
(
int
lsm_labelfd
,
int
on_exec
,
char
*
lsm_label
)
{
{
int
fret
=
-
1
;
int
fret
=
-
1
;
const
char
*
name
;
const
char
*
name
;
char
*
command
=
NULL
;
char
*
command
=
NULL
;
name
=
lsm_name
();
name
=
lsm_name
();
...
@@ -136,7 +136,8 @@ static int lsm_set_label_at(int lsm_labelfd, int on_exec, char *lsm_label)
...
@@ -136,7 +136,8 @@ static int lsm_set_label_at(int lsm_labelfd, int on_exec, char *lsm_label)
if
(
strcmp
(
name
,
"AppArmor"
)
==
0
)
{
if
(
strcmp
(
name
,
"AppArmor"
)
==
0
)
{
int
size
;
int
size
;
command
=
malloc
(
strlen
(
lsm_label
)
+
strlen
(
"changeprofile "
)
+
1
);
command
=
malloc
(
strlen
(
lsm_label
)
+
strlen
(
"changeprofile "
)
+
1
);
if
(
!
command
)
{
if
(
!
command
)
{
SYSERROR
(
"Failed to write apparmor profile."
);
SYSERROR
(
"Failed to write apparmor profile."
);
goto
out
;
goto
out
;
...
@@ -175,15 +176,15 @@ out:
...
@@ -175,15 +176,15 @@ out:
}
}
/* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */
/* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */
#define __PROC_STATUS_LEN (5 +
21
+ 7 + 1)
#define __PROC_STATUS_LEN (5 +
(LXC_NUMSTRLEN64)
+ 7 + 1)
static
struct
lxc_proc_context_info
*
lxc_proc_get_context_info
(
pid_t
pid
)
static
struct
lxc_proc_context_info
*
lxc_proc_get_context_info
(
pid_t
pid
)
{
{
int
ret
;
bool
found
;
FILE
*
proc_file
;
FILE
*
proc_file
;
char
proc_fn
[
__PROC_STATUS_LEN
];
char
proc_fn
[
__PROC_STATUS_LEN
];
bool
found
;
int
ret
;
char
*
line
=
NULL
;
size_t
line_bufsz
=
0
;
size_t
line_bufsz
=
0
;
char
*
line
=
NULL
;
struct
lxc_proc_context_info
*
info
=
NULL
;
struct
lxc_proc_context_info
*
info
=
NULL
;
/* Read capabilities. */
/* Read capabilities. */
...
@@ -217,7 +218,8 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
...
@@ -217,7 +218,8 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
fclose
(
proc_file
);
fclose
(
proc_file
);
if
(
!
found
)
{
if
(
!
found
)
{
SYSERROR
(
"Could not read capability bounding set from %s."
,
proc_fn
);
SYSERROR
(
"Could not read capability bounding set from %s."
,
proc_fn
);
errno
=
ENOENT
;
errno
=
ENOENT
;
goto
on_error
;
goto
on_error
;
}
}
...
@@ -244,7 +246,6 @@ static int lxc_attach_to_ns(pid_t pid, int which)
...
@@ -244,7 +246,6 @@ static int lxc_attach_to_ns(pid_t pid, int which)
int
fd
[
LXC_NS_MAX
];
int
fd
[
LXC_NS_MAX
];
int
i
,
j
,
saved_errno
;
int
i
,
j
,
saved_errno
;
if
(
access
(
"/proc/self/ns"
,
X_OK
))
{
if
(
access
(
"/proc/self/ns"
,
X_OK
))
{
ERROR
(
"Does this kernel version support namespaces?"
);
ERROR
(
"Does this kernel version support namespaces?"
);
return
-
1
;
return
-
1
;
...
@@ -268,7 +269,8 @@ static int lxc_attach_to_ns(pid_t pid, int which)
...
@@ -268,7 +269,8 @@ static int lxc_attach_to_ns(pid_t pid, int which)
close
(
fd
[
j
]);
close
(
fd
[
j
]);
errno
=
saved_errno
;
errno
=
saved_errno
;
SYSERROR
(
"Failed to open namespace:
\"
%s
\"
."
,
ns_info
[
i
].
proc_name
);
SYSERROR
(
"Failed to open namespace:
\"
%s
\"
."
,
ns_info
[
i
].
proc_name
);
return
-
1
;
return
-
1
;
}
}
}
}
...
@@ -284,7 +286,8 @@ static int lxc_attach_to_ns(pid_t pid, int which)
...
@@ -284,7 +286,8 @@ static int lxc_attach_to_ns(pid_t pid, int which)
close
(
fd
[
j
]);
close
(
fd
[
j
]);
errno
=
saved_errno
;
errno
=
saved_errno
;
SYSERROR
(
"Failed to attach to namespace
\"
%s
\"
."
,
ns_info
[
i
].
proc_name
);
SYSERROR
(
"Failed to attach to namespace
\"
%s
\"
."
,
ns_info
[
i
].
proc_name
);
return
-
1
;
return
-
1
;
}
}
...
@@ -307,7 +310,7 @@ static int lxc_attach_remount_sys_proc(void)
...
@@ -307,7 +310,7 @@ static int lxc_attach_remount_sys_proc(void)
}
}
if
(
detect_shared_rootfs
())
{
if
(
detect_shared_rootfs
())
{
if
(
mount
(
NULL
,
"/"
,
NULL
,
MS_SLAVE
|
MS_REC
,
NULL
))
{
if
(
mount
(
NULL
,
"/"
,
NULL
,
MS_SLAVE
|
MS_REC
,
NULL
))
{
SYSERROR
(
"Failed to make / rslave."
);
SYSERROR
(
"Failed to make / rslave."
);
ERROR
(
"Continuing..."
);
ERROR
(
"Continuing..."
);
}
}
...
@@ -347,9 +350,9 @@ static int lxc_attach_remount_sys_proc(void)
...
@@ -347,9 +350,9 @@ static int lxc_attach_remount_sys_proc(void)
static
int
lxc_attach_drop_privs
(
struct
lxc_proc_context_info
*
ctx
)
static
int
lxc_attach_drop_privs
(
struct
lxc_proc_context_info
*
ctx
)
{
{
int
last_cap
=
lxc_caps_last_cap
();
int
cap
,
last_cap
;
int
cap
;
last_cap
=
lxc_caps_last_cap
();
for
(
cap
=
0
;
cap
<=
last_cap
;
cap
++
)
{
for
(
cap
=
0
;
cap
<=
last_cap
;
cap
++
)
{
if
(
ctx
->
capability_mask
&
(
1LL
<<
cap
))
if
(
ctx
->
capability_mask
&
(
1LL
<<
cap
))
continue
;
continue
;
...
@@ -363,11 +366,12 @@ static int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
...
@@ -363,11 +366,12 @@ static int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
return
0
;
return
0
;
}
}
static
int
lxc_attach_set_environment
(
enum
lxc_attach_env_policy_t
policy
,
char
**
extra_env
,
char
**
extra_keep
)
static
int
lxc_attach_set_environment
(
enum
lxc_attach_env_policy_t
policy
,
char
**
extra_env
,
char
**
extra_keep
)
{
{
if
(
policy
==
LXC_ATTACH_CLEAR_ENV
)
{
if
(
policy
==
LXC_ATTACH_CLEAR_ENV
)
{
char
**
extra_keep_store
=
NULL
;
int
path_kept
=
0
;
int
path_kept
=
0
;
char
**
extra_keep_store
=
NULL
;
if
(
extra_keep
)
{
if
(
extra_keep
)
{
size_t
count
,
i
;
size_t
count
,
i
;
...
@@ -403,6 +407,7 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
...
@@ -403,6 +407,7 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
if
(
clearenv
())
{
if
(
clearenv
())
{
char
**
p
;
char
**
p
;
SYSERROR
(
"Failed to clear environment."
);
SYSERROR
(
"Failed to clear environment."
);
if
(
extra_keep_store
)
{
if
(
extra_keep_store
)
{
for
(
p
=
extra_keep_store
;
*
p
;
p
++
)
for
(
p
=
extra_keep_store
;
*
p
;
p
++
)
...
@@ -414,6 +419,7 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
...
@@ -414,6 +419,7 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
if
(
extra_keep_store
)
{
if
(
extra_keep_store
)
{
size_t
i
;
size_t
i
;
for
(
i
=
0
;
extra_keep
[
i
];
i
++
)
{
for
(
i
=
0
;
extra_keep
[
i
];
i
++
)
{
if
(
extra_keep_store
[
i
])
{
if
(
extra_keep_store
[
i
])
{
if
(
setenv
(
extra_keep
[
i
],
extra_keep_store
[
i
],
1
)
<
0
)
if
(
setenv
(
extra_keep
[
i
],
extra_keep_store
[
i
],
1
)
<
0
)
...
@@ -462,10 +468,9 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
...
@@ -462,10 +468,9 @@ static int lxc_attach_set_environment(enum lxc_attach_env_policy_t policy, char*
static
char
*
lxc_attach_getpwshell
(
uid_t
uid
)
static
char
*
lxc_attach_getpwshell
(
uid_t
uid
)
{
{
int
fd
,
ret
;
pid_t
pid
;
pid_t
pid
;
int
pipes
[
2
];
int
pipes
[
2
];
int
ret
;
int
fd
;
char
*
result
=
NULL
;
char
*
result
=
NULL
;
/* We need to fork off a process that runs the getent program, and we
/* We need to fork off a process that runs the getent program, and we
...
@@ -483,21 +488,20 @@ static char *lxc_attach_getpwshell(uid_t uid)
...
@@ -483,21 +488,20 @@ static char *lxc_attach_getpwshell(uid_t uid)
}
}
if
(
pid
)
{
if
(
pid
)
{
int
status
;
FILE
*
pipe_f
;
FILE
*
pipe_f
;
char
*
line
=
NULL
;
size_t
line_bufsz
=
0
;
int
found
=
0
;
int
found
=
0
;
int
status
;
size_t
line_bufsz
=
0
;
char
*
line
=
NULL
;
close
(
pipes
[
1
]);
close
(
pipes
[
1
]);
pipe_f
=
fdopen
(
pipes
[
0
],
"r"
);
pipe_f
=
fdopen
(
pipes
[
0
],
"r"
);
while
(
getline
(
&
line
,
&
line_bufsz
,
pipe_f
)
!=
-
1
)
{
while
(
getline
(
&
line
,
&
line_bufsz
,
pipe_f
)
!=
-
1
)
{
char
*
token
;
char
*
saveptr
=
NULL
;
long
value
;
char
*
endptr
=
NULL
;
int
i
;
int
i
;
long
value
;
char
*
token
;
char
*
endptr
=
NULL
,
*
saveptr
=
NULL
;
/* If we already found something, just continue to read
/* If we already found something, just continue to read
* until the pipe doesn't deliver any more data, but
* until the pipe doesn't deliver any more data, but
...
@@ -608,7 +612,7 @@ static char *lxc_attach_getpwshell(uid_t uid)
...
@@ -608,7 +612,7 @@ static char *lxc_attach_getpwshell(uid_t uid)
}
}
}
}
static
void
lxc_attach_get_init_uidgid
(
uid_t
*
init_uid
,
gid_t
*
init_gid
)
static
void
lxc_attach_get_init_uidgid
(
uid_t
*
init_uid
,
gid_t
*
init_gid
)
{
{
FILE
*
proc_file
;
FILE
*
proc_file
;
char
proc_fn
[
__PROC_STATUS_LEN
];
char
proc_fn
[
__PROC_STATUS_LEN
];
...
@@ -632,11 +636,11 @@ static void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
...
@@ -632,11 +636,11 @@ static void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
*/
*/
ret
=
sscanf
(
line
,
"Uid: %ld"
,
&
value
);
ret
=
sscanf
(
line
,
"Uid: %ld"
,
&
value
);
if
(
ret
!=
EOF
&&
ret
==
1
)
{
if
(
ret
!=
EOF
&&
ret
==
1
)
{
uid
=
(
uid_t
)
value
;
uid
=
(
uid_t
)
value
;
}
else
{
}
else
{
ret
=
sscanf
(
line
,
"Gid: %ld"
,
&
value
);
ret
=
sscanf
(
line
,
"Gid: %ld"
,
&
value
);
if
(
ret
!=
EOF
&&
ret
==
1
)
if
(
ret
!=
EOF
&&
ret
==
1
)
gid
=
(
gid_t
)
value
;
gid
=
(
gid_t
)
value
;
}
}
if
(
uid
!=
(
uid_t
)
-
1
&&
gid
!=
(
gid_t
)
-
1
)
if
(
uid
!=
(
uid_t
)
-
1
&&
gid
!=
(
gid_t
)
-
1
)
break
;
break
;
...
@@ -658,42 +662,45 @@ static void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
...
@@ -658,42 +662,45 @@ static void lxc_attach_get_init_uidgid(uid_t* init_uid, gid_t* init_gid)
struct
attach_clone_payload
{
struct
attach_clone_payload
{
int
ipc_socket
;
int
ipc_socket
;
lxc_attach_options_t
*
options
;
lxc_attach_options_t
*
options
;
struct
lxc_proc_context_info
*
init_ctx
;
struct
lxc_proc_context_info
*
init_ctx
;
lxc_attach_exec_t
exec_function
;
lxc_attach_exec_t
exec_function
;
void
*
exec_payload
;
void
*
exec_payload
;
};
};
static
int
attach_child_main
(
void
*
data
);
static
int
attach_child_main
(
void
*
data
);
/* Help the optimizer along if it doesn't know that exit always exits. */
/* Help the optimizer along if it doesn't know that exit always exits. */
#define rexit(c) do { int __c = (c); _exit(__c); return __c; } while(0)
#define rexit(c) \
do { \
int __c = (c); \
_exit(__c); \
return __c; \
} while (0)
/* Define default options if no options are supplied by the user. */
/* Define default options if no options are supplied by the user. */
static
lxc_attach_options_t
attach_static_default_options
=
LXC_ATTACH_OPTIONS_DEFAULT
;
static
lxc_attach_options_t
attach_static_default_options
=
LXC_ATTACH_OPTIONS_DEFAULT
;
static
bool
fetch_seccomp
(
const
char
*
name
,
const
char
*
lxcpath
,
static
bool
fetch_seccomp
(
struct
lxc_container
*
c
,
struct
lxc_proc_context_info
*
i
,
lxc_attach_options_t
*
options
)
lxc_attach_options_t
*
options
)
{
{
struct
lxc_container
*
c
;
char
*
path
;
char
*
path
;
if
(
!
(
options
->
namespaces
&
CLONE_NEWNS
)
||
!
(
options
->
attach_flags
&
LXC_ATTACH_LSM
))
if
(
!
(
options
->
namespaces
&
CLONE_NEWNS
)
||
!
(
options
->
attach_flags
&
LXC_ATTACH_LSM
))
{
free
(
c
->
lxc_conf
->
seccomp
);
c
->
lxc_conf
->
seccomp
=
NULL
;
return
true
;
return
true
;
}
c
=
lxc_container_new
(
name
,
lxcpath
);
/* Remove current setting. */
if
(
!
c
)
if
(
!
c
->
set_config_item
(
c
,
"lxc.seccomp"
,
""
))
return
false
;
i
->
container
=
c
;
/* Initialize an empty lxc_conf */
if
(
!
c
->
set_config_item
(
c
,
"lxc.seccomp"
,
""
))
{
return
false
;
return
false
;
}
/* Fetch the current profile path over the cmd interface. */
/* Fetch the current profile path over the cmd interface. */
path
=
c
->
get_running_config_item
(
c
,
"lxc.seccomp"
);
path
=
c
->
get_running_config_item
(
c
,
"lxc.seccomp"
);
if
(
!
path
)
{
if
(
!
path
)
{
INFO
(
"Failed to get running config item for lxc.seccomp"
);
return
true
;
return
true
;
}
}
...
@@ -710,30 +717,35 @@ static bool fetch_seccomp(const char *name, const char *lxcpath,
...
@@ -710,30 +717,35 @@ static bool fetch_seccomp(const char *name, const char *lxcpath,
return
false
;
return
false
;
}
}
INFO
(
"Retrieved seccomp policy."
);
return
true
;
return
true
;
}
}
static
signed
long
get_personality
(
const
char
*
name
,
const
char
*
lxcpath
)
static
signed
long
get_personality
(
const
char
*
name
,
const
char
*
lxcpath
)
{
{
char
*
p
=
lxc_cmd_get_config_item
(
name
,
"lxc.arch"
,
lxcpath
)
;
char
*
p
;
signed
long
ret
;
signed
long
ret
;
p
=
lxc_cmd_get_config_item
(
name
,
"lxc.arch"
,
lxcpath
);
if
(
!
p
)
if
(
!
p
)
return
-
1
;
return
-
1
;
ret
=
lxc_config_parse_arch
(
p
);
ret
=
lxc_config_parse_arch
(
p
);
free
(
p
);
free
(
p
);
return
ret
;
return
ret
;
}
}
int
lxc_attach
(
const
char
*
name
,
const
char
*
lxcpath
,
lxc_attach_exec_t
exec_function
,
void
*
exec_payload
,
lxc_attach_options_t
*
options
,
pid_t
*
attached_process
)
int
lxc_attach
(
const
char
*
name
,
const
char
*
lxcpath
,
lxc_attach_exec_t
exec_function
,
void
*
exec_payload
,
lxc_attach_options_t
*
options
,
pid_t
*
attached_process
)
{
{
int
ret
,
status
;
int
ret
,
status
;
pid_t
init_pid
,
pid
,
attached_pid
,
expected
;
struct
lxc_proc_context_info
*
init_ctx
;
char
*
cwd
;
char
*
new_cwd
;
int
ipc_sockets
[
2
];
int
ipc_sockets
[
2
];
char
*
cwd
,
*
new_cwd
;
signed
long
personality
;
signed
long
personality
;
pid_t
attached_pid
,
expected
,
init_pid
,
pid
;
struct
lxc_proc_context_info
*
init_ctx
;
if
(
!
options
)
if
(
!
options
)
options
=
&
attach_static_default_options
;
options
=
&
attach_static_default_options
;
...
@@ -746,20 +758,23 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -746,20 +758,23 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
init_ctx
=
lxc_proc_get_context_info
(
init_pid
);
init_ctx
=
lxc_proc_get_context_info
(
init_pid
);
if
(
!
init_ctx
)
{
if
(
!
init_ctx
)
{
ERROR
(
"Failed to get context of init process: %ld."
,
ERROR
(
"Failed to get context of init process: %ld"
,
(
long
)
init_pid
);
(
long
)
init_pid
);
return
-
1
;
return
-
1
;
}
}
personality
=
get_personality
(
name
,
lxcpath
);
personality
=
get_personality
(
name
,
lxcpath
);
if
(
init_ctx
->
personality
<
0
)
{
if
(
init_ctx
->
personality
<
0
)
{
ERROR
(
"Failed to get personality of the container
.
"
);
ERROR
(
"Failed to get personality of the container"
);
lxc_proc_put_context_info
(
init_ctx
);
lxc_proc_put_context_info
(
init_ctx
);
return
-
1
;
return
-
1
;
}
}
init_ctx
->
personality
=
personality
;
init_ctx
->
personality
=
personality
;
if
(
!
fetch_seccomp
(
name
,
lxcpath
,
init_ctx
,
options
))
init_ctx
->
container
=
lxc_container_new
(
name
,
lxcpath
);
if
(
!
init_ctx
->
container
)
return
-
1
;
if
(
!
fetch_seccomp
(
init_ctx
->
container
,
options
))
WARN
(
"Failed to get seccomp policy."
);
WARN
(
"Failed to get seccomp policy."
);
cwd
=
getcwd
(
NULL
,
0
);
cwd
=
getcwd
(
NULL
,
0
);
...
@@ -831,7 +846,6 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -831,7 +846,6 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
* setns() (otherwise, user namespaces will hate us).
* setns() (otherwise, user namespaces will hate us).
*/
*/
pid
=
fork
();
pid
=
fork
();
if
(
pid
<
0
)
{
if
(
pid
<
0
)
{
SYSERROR
(
"Failed to create first subprocess."
);
SYSERROR
(
"Failed to create first subprocess."
);
free
(
cwd
);
free
(
cwd
);
...
@@ -874,7 +888,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -874,7 +888,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
}
}
/* Get pid of attached process from intermediate process. */
/* Get pid of attached process from intermediate process. */
ret
=
lxc_read_nointr_expect
(
ipc_sockets
[
0
],
&
attached_pid
,
sizeof
(
attached_pid
),
NULL
);
ret
=
lxc_read_nointr_expect
(
ipc_sockets
[
0
],
&
attached_pid
,
sizeof
(
attached_pid
),
NULL
);
if
(
ret
<=
0
)
{
if
(
ret
<=
0
)
{
if
(
ret
!=
0
)
if
(
ret
!=
0
)
ERROR
(
"Expected to receive pid: %s."
,
strerror
(
errno
));
ERROR
(
"Expected to receive pid: %s."
,
strerror
(
errno
));
...
@@ -905,7 +920,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -905,7 +920,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
/* Wait for the attached process to finish initializing. */
/* Wait for the attached process to finish initializing. */
expected
=
1
;
expected
=
1
;
ret
=
lxc_read_nointr_expect
(
ipc_sockets
[
0
],
&
status
,
sizeof
(
status
),
&
expected
);
ret
=
lxc_read_nointr_expect
(
ipc_sockets
[
0
],
&
status
,
sizeof
(
status
),
&
expected
);
if
(
ret
<=
0
)
{
if
(
ret
<=
0
)
{
if
(
ret
!=
0
)
if
(
ret
!=
0
)
ERROR
(
"Expected to receive sequence number 1: %s."
,
strerror
(
errno
));
ERROR
(
"Expected to receive sequence number 1: %s."
,
strerror
(
errno
));
...
@@ -924,7 +940,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -924,7 +940,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
* up its LSM labels.
* up its LSM labels.
*/
*/
expected
=
3
;
expected
=
3
;
ret
=
lxc_read_nointr_expect
(
ipc_sockets
[
0
],
&
status
,
sizeof
(
status
),
&
expected
);
ret
=
lxc_read_nointr_expect
(
ipc_sockets
[
0
],
&
status
,
sizeof
(
status
),
&
expected
);
if
(
ret
<=
0
)
{
if
(
ret
<=
0
)
{
ERROR
(
"Expected to receive sequence number 3: %s."
,
ERROR
(
"Expected to receive sequence number 3: %s."
,
strerror
(
errno
));
strerror
(
errno
));
...
@@ -932,9 +949,12 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -932,9 +949,12 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
}
}
/* Open LSM fd and send it to child. */
/* Open LSM fd and send it to child. */
if
((
options
->
namespaces
&
CLONE_NEWNS
)
&&
(
options
->
attach_flags
&
LXC_ATTACH_LSM
)
&&
init_ctx
->
lsm_label
)
{
if
((
options
->
namespaces
&
CLONE_NEWNS
)
&&
(
options
->
attach_flags
&
LXC_ATTACH_LSM
)
&&
init_ctx
->
lsm_label
)
{
int
on_exec
,
saved_errno
;
int
on_exec
,
saved_errno
;
int
labelfd
=
-
1
;
int
labelfd
=
-
1
;
on_exec
=
options
->
attach_flags
&
LXC_ATTACH_LSM_EXEC
?
1
:
0
;
on_exec
=
options
->
attach_flags
&
LXC_ATTACH_LSM_EXEC
?
1
:
0
;
/* Open fd for the LSM security module. */
/* Open fd for the LSM security module. */
labelfd
=
lsm_openat
(
procfd
,
attached_pid
,
on_exec
);
labelfd
=
lsm_openat
(
procfd
,
attached_pid
,
on_exec
);
...
@@ -975,7 +995,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -975,7 +995,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
shutdown
(
ipc_sockets
[
0
],
SHUT_RDWR
);
shutdown
(
ipc_sockets
[
0
],
SHUT_RDWR
);
close
(
ipc_sockets
[
0
]);
close
(
ipc_sockets
[
0
]);
if
(
to_cleanup_pid
)
if
(
to_cleanup_pid
)
(
void
)
wait_for_pid
(
to_cleanup_pid
);
(
void
)
wait_for_pid
(
to_cleanup_pid
);
lxc_proc_put_context_info
(
init_ctx
);
lxc_proc_put_context_info
(
init_ctx
);
return
-
1
;
return
-
1
;
}
}
...
@@ -988,7 +1008,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -988,7 +1008,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
/* Wait for the parent to have setup cgroups. */
/* Wait for the parent to have setup cgroups. */
expected
=
0
;
expected
=
0
;
status
=
-
1
;
status
=
-
1
;
ret
=
lxc_read_nointr_expect
(
ipc_sockets
[
1
],
&
status
,
sizeof
(
status
),
&
expected
);
ret
=
lxc_read_nointr_expect
(
ipc_sockets
[
1
],
&
status
,
sizeof
(
status
),
&
expected
);
if
(
ret
<=
0
)
{
if
(
ret
<=
0
)
{
ERROR
(
"Expected to receive sequence number 0: %s."
,
strerror
(
errno
));
ERROR
(
"Expected to receive sequence number 0: %s."
,
strerror
(
errno
));
shutdown
(
ipc_sockets
[
1
],
SHUT_RDWR
);
shutdown
(
ipc_sockets
[
1
],
SHUT_RDWR
);
...
@@ -1025,7 +1046,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -1025,7 +1046,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
.
options
=
options
,
.
options
=
options
,
.
init_ctx
=
init_ctx
,
.
init_ctx
=
init_ctx
,
.
exec_function
=
exec_function
,
.
exec_function
=
exec_function
,
.
exec_payload
=
exec_payload
.
exec_payload
=
exec_payload
,
};
};
/* We use clone_parent here to make this subprocess a direct
/* We use clone_parent here to make this subprocess a direct
* child of the initial process. Then this intermediate process
* child of the initial process. Then this intermediate process
...
@@ -1062,21 +1083,17 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
...
@@ -1062,21 +1083,17 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
static
int
attach_child_main
(
void
*
data
)
static
int
attach_child_main
(
void
*
data
)
{
{
struct
attach_clone_payload
*
payload
=
(
struct
attach_clone_payload
*
)
data
;
int
expected
,
fd
,
lsm_labelfd
,
ret
,
status
;
int
ipc_socket
=
payload
->
ipc_socket
;
long
flags
;
lxc_attach_options_t
*
options
=
payload
->
options
;
struct
lxc_proc_context_info
*
init_ctx
=
payload
->
init_ctx
;
#if HAVE_SYS_PERSONALITY_H
#if HAVE_SYS_PERSONALITY_H
long
new_personality
;
long
new_personality
;
#endif
#endif
int
ret
;
int
status
;
int
expected
;
long
flags
;
int
fd
;
int
lsm_labelfd
;
uid_t
new_uid
;
uid_t
new_uid
;
gid_t
new_gid
;
gid_t
new_gid
;
struct
attach_clone_payload
*
payload
=
(
struct
attach_clone_payload
*
)
data
;
int
ipc_socket
=
payload
->
ipc_socket
;
lxc_attach_options_t
*
options
=
payload
->
options
;
struct
lxc_proc_context_info
*
init_ctx
=
payload
->
init_ctx
;
/* Wait for the initial thread to signal us that it's ready for us to
/* Wait for the initial thread to signal us that it's ready for us to
* start initializing.
* start initializing.
...
@@ -1095,7 +1112,8 @@ static int attach_child_main(void* data)
...
@@ -1095,7 +1112,8 @@ static int attach_child_main(void* data)
* parent process, otherwise /proc may not properly reflect the new pid
* parent process, otherwise /proc may not properly reflect the new pid
* namespace.
* namespace.
*/
*/
if
(
!
(
options
->
namespaces
&
CLONE_NEWNS
)
&&
(
options
->
attach_flags
&
LXC_ATTACH_REMOUNT_PROC_SYS
))
{
if
(
!
(
options
->
namespaces
&
CLONE_NEWNS
)
&&
(
options
->
attach_flags
&
LXC_ATTACH_REMOUNT_PROC_SYS
))
{
ret
=
lxc_attach_remount_sys_proc
();
ret
=
lxc_attach_remount_sys_proc
();
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
shutdown
(
ipc_socket
,
SHUT_RDWR
);
shutdown
(
ipc_socket
,
SHUT_RDWR
);
...
@@ -1132,7 +1150,9 @@ static int attach_child_main(void* data)
...
@@ -1132,7 +1150,9 @@ static int attach_child_main(void* data)
/* Always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL)
/* Always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL)
* if you want this to be a no-op).
* if you want this to be a no-op).
*/
*/
ret
=
lxc_attach_set_environment
(
options
->
env_policy
,
options
->
extra_env_vars
,
options
->
extra_keep_env
);
ret
=
lxc_attach_set_environment
(
options
->
env_policy
,
options
->
extra_env_vars
,
options
->
extra_keep_env
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Could not set initial environment for attached process."
);
ERROR
(
"Could not set initial environment for attached process."
);
shutdown
(
ipc_socket
,
SHUT_RDWR
);
shutdown
(
ipc_socket
,
SHUT_RDWR
);
...
@@ -1176,7 +1196,8 @@ static int attach_child_main(void* data)
...
@@ -1176,7 +1196,8 @@ static int attach_child_main(void* data)
rexit
(
-
1
);
rexit
(
-
1
);
}
}
}
}
if
((
new_uid
!=
0
||
options
->
namespaces
&
CLONE_NEWUSER
)
&&
setuid
(
new_uid
))
{
if
((
new_uid
!=
0
||
options
->
namespaces
&
CLONE_NEWUSER
)
&&
setuid
(
new_uid
))
{
SYSERROR
(
"Switching to container uid."
);
SYSERROR
(
"Switching to container uid."
);
shutdown
(
ipc_socket
,
SHUT_RDWR
);
shutdown
(
ipc_socket
,
SHUT_RDWR
);
rexit
(
-
1
);
rexit
(
-
1
);
...
@@ -1203,7 +1224,6 @@ static int attach_child_main(void* data)
...
@@ -1203,7 +1224,6 @@ static int attach_child_main(void* data)
rexit
(
-
1
);
rexit
(
-
1
);
}
}
/* Tell the (grand)parent to send us LSM label fd. */
/* Tell the (grand)parent to send us LSM label fd. */
status
=
3
;
status
=
3
;
ret
=
lxc_write_nointr
(
ipc_socket
,
&
status
,
sizeof
(
status
));
ret
=
lxc_write_nointr
(
ipc_socket
,
&
status
,
sizeof
(
status
));
...
@@ -1213,7 +1233,8 @@ static int attach_child_main(void* data)
...
@@ -1213,7 +1233,8 @@ static int attach_child_main(void* data)
rexit
(
-
1
);
rexit
(
-
1
);
}
}
if
((
options
->
namespaces
&
CLONE_NEWNS
)
&&
(
options
->
attach_flags
&
LXC_ATTACH_LSM
)
&&
init_ctx
->
lsm_label
)
{
if
((
options
->
namespaces
&
CLONE_NEWNS
)
&&
(
options
->
attach_flags
&
LXC_ATTACH_LSM
)
&&
init_ctx
->
lsm_label
)
{
int
on_exec
;
int
on_exec
;
/* Receive fd for LSM security module. */
/* Receive fd for LSM security module. */
ret
=
lxc_abstract_unix_recv_fds
(
ipc_socket
,
&
lsm_labelfd
,
1
,
NULL
,
0
);
ret
=
lxc_abstract_unix_recv_fds
(
ipc_socket
,
&
lsm_labelfd
,
1
,
NULL
,
0
);
...
@@ -1235,7 +1256,8 @@ static int attach_child_main(void* data)
...
@@ -1235,7 +1256,8 @@ static int attach_child_main(void* data)
}
}
if
(
init_ctx
->
container
&&
init_ctx
->
container
->
lxc_conf
&&
if
(
init_ctx
->
container
&&
init_ctx
->
container
->
lxc_conf
&&
lxc_seccomp_load
(
init_ctx
->
container
->
lxc_conf
)
!=
0
)
{
init_ctx
->
container
->
lxc_conf
->
seccomp
&&
(
lxc_seccomp_load
(
init_ctx
->
container
->
lxc_conf
)
!=
0
))
{
ERROR
(
"Failed to load seccomp policy."
);
ERROR
(
"Failed to load seccomp policy."
);
shutdown
(
ipc_socket
,
SHUT_RDWR
);
shutdown
(
ipc_socket
,
SHUT_RDWR
);
rexit
(
-
1
);
rexit
(
-
1
);
...
...
src/lxc/attach.h
View file @
d3e7b8ad
...
@@ -24,8 +24,8 @@
...
@@ -24,8 +24,8 @@
#ifndef __LXC_ATTACH_H
#ifndef __LXC_ATTACH_H
#define __LXC_ATTACH_H
#define __LXC_ATTACH_H
#include <sys/types.h>
#include <lxc/attach_options.h>
#include <lxc/attach_options.h>
#include <sys/types.h>
struct
lxc_conf
;
struct
lxc_conf
;
...
@@ -36,6 +36,8 @@ struct lxc_proc_context_info {
...
@@ -36,6 +36,8 @@ struct lxc_proc_context_info {
unsigned
long
long
capability_mask
;
unsigned
long
long
capability_mask
;
};
};
extern
int
lxc_attach
(
const
char
*
name
,
const
char
*
lxcpath
,
lxc_attach_exec_t
exec_function
,
void
*
exec_payload
,
lxc_attach_options_t
*
options
,
pid_t
*
attached_process
);
extern
int
lxc_attach
(
const
char
*
name
,
const
char
*
lxcpath
,
lxc_attach_exec_t
exec_function
,
void
*
exec_payload
,
lxc_attach_options_t
*
options
,
pid_t
*
attached_process
);
#endif
#endif
/* __LXC_ATTACH_H */
src/lxc/cgroups/cgfsng.c
View file @
d3e7b8ad
...
@@ -1176,6 +1176,7 @@ out_free:
...
@@ -1176,6 +1176,7 @@ out_free:
static
int
cgroup_rmdir
(
char
*
dirname
)
static
int
cgroup_rmdir
(
char
*
dirname
)
{
{
int
ret
;
struct
dirent
*
direntp
;
struct
dirent
*
direntp
;
DIR
*
dir
;
DIR
*
dir
;
int
r
=
0
;
int
r
=
0
;
...
@@ -1185,8 +1186,8 @@ static int cgroup_rmdir(char *dirname)
...
@@ -1185,8 +1186,8 @@ static int cgroup_rmdir(char *dirname)
return
-
1
;
return
-
1
;
while
((
direntp
=
readdir
(
dir
)))
{
while
((
direntp
=
readdir
(
dir
)))
{
struct
stat
mystat
;
char
*
pathname
;
char
*
pathname
;
struct
stat
mystat
;
if
(
!
direntp
)
if
(
!
direntp
)
break
;
break
;
...
@@ -1197,32 +1198,40 @@ static int cgroup_rmdir(char *dirname)
...
@@ -1197,32 +1198,40 @@ static int cgroup_rmdir(char *dirname)
pathname
=
must_make_path
(
dirname
,
direntp
->
d_name
,
NULL
);
pathname
=
must_make_path
(
dirname
,
direntp
->
d_name
,
NULL
);
if
(
lstat
(
pathname
,
&
mystat
))
{
ret
=
lstat
(
pathname
,
&
mystat
);
if
(
ret
<
0
)
{
if
(
!
r
)
if
(
!
r
)
WARN
(
"
f
ailed to stat %s"
,
pathname
);
WARN
(
"
F
ailed to stat %s"
,
pathname
);
r
=
-
1
;
r
=
-
1
;
goto
next
;
goto
next
;
}
}
if
(
!
S_ISDIR
(
mystat
.
st_mode
))
if
(
!
S_ISDIR
(
mystat
.
st_mode
))
goto
next
;
goto
next
;
if
(
cgroup_rmdir
(
pathname
)
<
0
)
ret
=
cgroup_rmdir
(
pathname
);
if
(
ret
<
0
)
r
=
-
1
;
r
=
-
1
;
next:
next:
free
(
pathname
);
free
(
pathname
);
}
}
if
(
rmdir
(
dirname
)
<
0
)
{
ret
=
rmdir
(
dirname
);
if
(
ret
<
0
)
{
if
(
!
r
)
if
(
!
r
)
WARN
(
"failed to delete %s: %s"
,
dirname
,
strerror
(
errno
));
WARN
(
"Failed to delete
\"
%s
\"
: %s"
,
dirname
,
strerror
(
errno
));
r
=
-
1
;
r
=
-
1
;
}
}
if
(
closedir
(
dir
)
<
0
)
{
ret
=
closedir
(
dir
);
if
(
ret
<
0
)
{
if
(
!
r
)
if
(
!
r
)
WARN
(
"failed to delete %s: %s"
,
dirname
,
strerror
(
errno
));
WARN
(
"Failed to delete
\"
%s
\"
: %s"
,
dirname
,
strerror
(
errno
));
r
=
-
1
;
r
=
-
1
;
}
}
return
r
;
return
r
;
}
}
...
...
src/lxc/conf.c
View file @
d3e7b8ad
...
@@ -235,8 +235,6 @@ char *lxchook_names[NUM_LXC_HOOKS] = {"pre-start", "pre-mount", "mount",
...
@@ -235,8 +235,6 @@ char *lxchook_names[NUM_LXC_HOOKS] = {"pre-start", "pre-mount", "mount",
"autodev"
,
"start"
,
"stop"
,
"autodev"
,
"start"
,
"stop"
,
"post-stop"
,
"clone"
,
"destroy"
};
"post-stop"
,
"clone"
,
"destroy"
};
typedef
int
(
*
instantiate_cb
)(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
struct
mount_opt
{
struct
mount_opt
{
char
*
name
;
char
*
name
;
int
clear
;
int
clear
;
...
@@ -262,38 +260,6 @@ struct lxc_conf *current_config;
...
@@ -262,38 +260,6 @@ struct lxc_conf *current_config;
/* Declare this here, since we don't want to reshuffle the whole file. */
/* Declare this here, since we don't want to reshuffle the whole file. */
static
int
in_caplist
(
int
cap
,
struct
lxc_list
*
caps
);
static
int
in_caplist
(
int
cap
,
struct
lxc_list
*
caps
);
static
int
instantiate_veth
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
instantiate_macvlan
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
instantiate_vlan
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
instantiate_phys
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
instantiate_empty
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
instantiate_none
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
instantiate_cb
netdev_conf
[
LXC_NET_MAXCONFTYPE
+
1
]
=
{
[
LXC_NET_VETH
]
=
instantiate_veth
,
[
LXC_NET_MACVLAN
]
=
instantiate_macvlan
,
[
LXC_NET_VLAN
]
=
instantiate_vlan
,
[
LXC_NET_PHYS
]
=
instantiate_phys
,
[
LXC_NET_EMPTY
]
=
instantiate_empty
,
[
LXC_NET_NONE
]
=
instantiate_none
,
};
static
int
shutdown_veth
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
shutdown_macvlan
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
shutdown_vlan
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
shutdown_phys
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
shutdown_empty
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
shutdown_none
(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
instantiate_cb
netdev_deconf
[
LXC_NET_MAXCONFTYPE
+
1
]
=
{
[
LXC_NET_VETH
]
=
shutdown_veth
,
[
LXC_NET_MACVLAN
]
=
shutdown_macvlan
,
[
LXC_NET_VLAN
]
=
shutdown_vlan
,
[
LXC_NET_PHYS
]
=
shutdown_phys
,
[
LXC_NET_EMPTY
]
=
shutdown_empty
,
[
LXC_NET_NONE
]
=
shutdown_none
,
};
static
struct
mount_opt
mount_opt
[]
=
{
static
struct
mount_opt
mount_opt
[]
=
{
{
"async"
,
1
,
MS_SYNCHRONOUS
},
{
"async"
,
1
,
MS_SYNCHRONOUS
},
{
"atime"
,
1
,
MS_NOATIME
},
{
"atime"
,
1
,
MS_NOATIME
},
...
@@ -471,8 +437,7 @@ static int run_script_argv(const char *name, const char *section,
...
@@ -471,8 +437,7 @@ static int run_script_argv(const char *name, const char *section,
return
run_buffer
(
buffer
);
return
run_buffer
(
buffer
);
}
}
static
int
run_script
(
const
char
*
name
,
const
char
*
section
,
const
char
*
script
,
int
run_script
(
const
char
*
name
,
const
char
*
section
,
const
char
*
script
,
...)
...)
{
{
int
ret
;
int
ret
;
char
*
buffer
,
*
p
;
char
*
buffer
,
*
p
;
...
@@ -2286,328 +2251,6 @@ static int dropcaps_except(struct lxc_list *caps)
...
@@ -2286,328 +2251,6 @@ static int dropcaps_except(struct lxc_list *caps)
return
0
;
return
0
;
}
}
static
int
setup_hw_addr
(
char
*
hwaddr
,
const
char
*
ifname
)
{
struct
sockaddr
sockaddr
;
struct
ifreq
ifr
;
int
ret
,
fd
,
saved_errno
;
ret
=
lxc_convert_mac
(
hwaddr
,
&
sockaddr
);
if
(
ret
)
{
ERROR
(
"mac address '%s' conversion failed : %s"
,
hwaddr
,
strerror
(
-
ret
));
return
-
1
;
}
memcpy
(
ifr
.
ifr_name
,
ifname
,
IFNAMSIZ
);
ifr
.
ifr_name
[
IFNAMSIZ
-
1
]
=
'\0'
;
memcpy
((
char
*
)
&
ifr
.
ifr_hwaddr
,
(
char
*
)
&
sockaddr
,
sizeof
(
sockaddr
));
fd
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
if
(
fd
<
0
)
{
ERROR
(
"socket failure : %s"
,
strerror
(
errno
));
return
-
1
;
}
ret
=
ioctl
(
fd
,
SIOCSIFHWADDR
,
&
ifr
);
saved_errno
=
errno
;
close
(
fd
);
if
(
ret
)
ERROR
(
"ioctl failure : %s"
,
strerror
(
saved_errno
));
DEBUG
(
"mac address '%s' on '%s' has been setup"
,
hwaddr
,
ifr
.
ifr_name
);
return
ret
;
}
static
int
setup_ipv4_addr
(
struct
lxc_list
*
ip
,
int
ifindex
)
{
struct
lxc_list
*
iterator
;
struct
lxc_inetdev
*
inetdev
;
int
err
;
lxc_list_for_each
(
iterator
,
ip
)
{
inetdev
=
iterator
->
elem
;
err
=
lxc_ipv4_addr_add
(
ifindex
,
&
inetdev
->
addr
,
&
inetdev
->
bcast
,
inetdev
->
prefix
);
if
(
err
)
{
ERROR
(
"failed to setup_ipv4_addr ifindex %d : %s"
,
ifindex
,
strerror
(
-
err
));
return
-
1
;
}
}
return
0
;
}
static
int
setup_ipv6_addr
(
struct
lxc_list
*
ip
,
int
ifindex
)
{
struct
lxc_list
*
iterator
;
struct
lxc_inet6dev
*
inet6dev
;
int
err
;
lxc_list_for_each
(
iterator
,
ip
)
{
inet6dev
=
iterator
->
elem
;
err
=
lxc_ipv6_addr_add
(
ifindex
,
&
inet6dev
->
addr
,
&
inet6dev
->
mcast
,
&
inet6dev
->
acast
,
inet6dev
->
prefix
);
if
(
err
)
{
ERROR
(
"failed to setup_ipv6_addr ifindex %d : %s"
,
ifindex
,
strerror
(
-
err
));
return
-
1
;
}
}
return
0
;
}
static
int
setup_netdev
(
struct
lxc_netdev
*
netdev
)
{
char
ifname
[
IFNAMSIZ
];
char
*
current_ifname
=
ifname
;
int
err
;
/* empty network namespace */
if
(
!
netdev
->
ifindex
)
{
if
(
netdev
->
flags
&
IFF_UP
)
{
err
=
lxc_netdev_up
(
"lo"
);
if
(
err
)
{
ERROR
(
"failed to set the loopback up : %s"
,
strerror
(
-
err
));
return
-
1
;
}
}
if
(
netdev
->
type
!=
LXC_NET_VETH
)
return
0
;
netdev
->
ifindex
=
if_nametoindex
(
netdev
->
name
);
}
/* get the new ifindex in case of physical netdev */
if
(
netdev
->
type
==
LXC_NET_PHYS
)
{
if
(
!
(
netdev
->
ifindex
=
if_nametoindex
(
netdev
->
link
)))
{
ERROR
(
"failed to get ifindex for %s"
,
netdev
->
link
);
return
-
1
;
}
}
/* retrieve the name of the interface */
if
(
!
if_indextoname
(
netdev
->
ifindex
,
current_ifname
))
{
ERROR
(
"no interface corresponding to index '%d'"
,
netdev
->
ifindex
);
return
-
1
;
}
/* default: let the system to choose one interface name */
if
(
!
netdev
->
name
)
netdev
->
name
=
netdev
->
type
==
LXC_NET_PHYS
?
netdev
->
link
:
"eth%d"
;
/* rename the interface name */
if
(
strcmp
(
ifname
,
netdev
->
name
)
!=
0
)
{
err
=
lxc_netdev_rename_by_name
(
ifname
,
netdev
->
name
);
if
(
err
)
{
ERROR
(
"failed to rename %s->%s : %s"
,
ifname
,
netdev
->
name
,
strerror
(
-
err
));
return
-
1
;
}
}
/* Re-read the name of the interface because its name has changed
* and would be automatically allocated by the system
*/
if
(
!
if_indextoname
(
netdev
->
ifindex
,
current_ifname
))
{
ERROR
(
"no interface corresponding to index '%d'"
,
netdev
->
ifindex
);
return
-
1
;
}
/* set a mac address */
if
(
netdev
->
hwaddr
)
{
if
(
setup_hw_addr
(
netdev
->
hwaddr
,
current_ifname
))
{
ERROR
(
"failed to setup hw address for '%s'"
,
current_ifname
);
return
-
1
;
}
}
/* setup ipv4 addresses on the interface */
if
(
setup_ipv4_addr
(
&
netdev
->
ipv4
,
netdev
->
ifindex
))
{
ERROR
(
"failed to setup ip addresses for '%s'"
,
ifname
);
return
-
1
;
}
/* setup ipv6 addresses on the interface */
if
(
setup_ipv6_addr
(
&
netdev
->
ipv6
,
netdev
->
ifindex
))
{
ERROR
(
"failed to setup ipv6 addresses for '%s'"
,
ifname
);
return
-
1
;
}
/* set the network device up */
if
(
netdev
->
flags
&
IFF_UP
)
{
int
err
;
err
=
lxc_netdev_up
(
current_ifname
);
if
(
err
)
{
ERROR
(
"failed to set '%s' up : %s"
,
current_ifname
,
strerror
(
-
err
));
return
-
1
;
}
/* the network is up, make the loopback up too */
err
=
lxc_netdev_up
(
"lo"
);
if
(
err
)
{
ERROR
(
"failed to set the loopback up : %s"
,
strerror
(
-
err
));
return
-
1
;
}
}
/* We can only set up the default routes after bringing
* up the interface, sine bringing up the interface adds
* the link-local routes and we can't add a default
* route if the gateway is not reachable. */
/* setup ipv4 gateway on the interface */
if
(
netdev
->
ipv4_gateway
)
{
if
(
!
(
netdev
->
flags
&
IFF_UP
))
{
ERROR
(
"Cannot add ipv4 gateway for %s when not bringing up the interface"
,
ifname
);
return
-
1
;
}
if
(
lxc_list_empty
(
&
netdev
->
ipv4
))
{
ERROR
(
"Cannot add ipv4 gateway for %s when not assigning an address"
,
ifname
);
return
-
1
;
}
err
=
lxc_ipv4_gateway_add
(
netdev
->
ifindex
,
netdev
->
ipv4_gateway
);
if
(
err
)
{
err
=
lxc_ipv4_dest_add
(
netdev
->
ifindex
,
netdev
->
ipv4_gateway
);
if
(
err
)
{
ERROR
(
"failed to add ipv4 dest for '%s': %s"
,
ifname
,
strerror
(
-
err
));
}
err
=
lxc_ipv4_gateway_add
(
netdev
->
ifindex
,
netdev
->
ipv4_gateway
);
if
(
err
)
{
ERROR
(
"failed to setup ipv4 gateway for '%s': %s"
,
ifname
,
strerror
(
-
err
));
if
(
netdev
->
ipv4_gateway_auto
)
{
char
buf
[
INET_ADDRSTRLEN
];
inet_ntop
(
AF_INET
,
netdev
->
ipv4_gateway
,
buf
,
sizeof
(
buf
));
ERROR
(
"tried to set autodetected ipv4 gateway '%s'"
,
buf
);
}
return
-
1
;
}
}
}
/* setup ipv6 gateway on the interface */
if
(
netdev
->
ipv6_gateway
)
{
if
(
!
(
netdev
->
flags
&
IFF_UP
))
{
ERROR
(
"Cannot add ipv6 gateway for %s when not bringing up the interface"
,
ifname
);
return
-
1
;
}
if
(
lxc_list_empty
(
&
netdev
->
ipv6
)
&&
!
IN6_IS_ADDR_LINKLOCAL
(
netdev
->
ipv6_gateway
))
{
ERROR
(
"Cannot add ipv6 gateway for %s when not assigning an address"
,
ifname
);
return
-
1
;
}
err
=
lxc_ipv6_gateway_add
(
netdev
->
ifindex
,
netdev
->
ipv6_gateway
);
if
(
err
)
{
err
=
lxc_ipv6_dest_add
(
netdev
->
ifindex
,
netdev
->
ipv6_gateway
);
if
(
err
)
{
ERROR
(
"failed to add ipv6 dest for '%s': %s"
,
ifname
,
strerror
(
-
err
));
}
err
=
lxc_ipv6_gateway_add
(
netdev
->
ifindex
,
netdev
->
ipv6_gateway
);
if
(
err
)
{
ERROR
(
"failed to setup ipv6 gateway for '%s': %s"
,
ifname
,
strerror
(
-
err
));
if
(
netdev
->
ipv6_gateway_auto
)
{
char
buf
[
INET6_ADDRSTRLEN
];
inet_ntop
(
AF_INET6
,
netdev
->
ipv6_gateway
,
buf
,
sizeof
(
buf
));
ERROR
(
"tried to set autodetected ipv6 gateway '%s'"
,
buf
);
}
return
-
1
;
}
}
}
DEBUG
(
"'%s' has been setup"
,
current_ifname
);
return
0
;
}
static
int
setup_network
(
struct
lxc_list
*
network
)
{
struct
lxc_list
*
iterator
;
struct
lxc_netdev
*
netdev
;
lxc_list_for_each
(
iterator
,
network
)
{
netdev
=
iterator
->
elem
;
if
(
setup_netdev
(
netdev
))
{
ERROR
(
"failed to setup netdev"
);
return
-
1
;
}
}
if
(
!
lxc_list_empty
(
network
))
INFO
(
"network has been setup"
);
return
0
;
}
/* try to move physical nics to the init netns */
void
lxc_restore_phys_nics_to_netns
(
int
netnsfd
,
struct
lxc_conf
*
conf
)
{
int
i
,
oldfd
;
char
ifname
[
IFNAMSIZ
];
if
(
netnsfd
<
0
||
conf
->
num_savednics
==
0
)
return
;
INFO
(
"Running to reset %d nic names."
,
conf
->
num_savednics
);
oldfd
=
lxc_preserve_ns
(
getpid
(),
"net"
);
if
(
oldfd
<
0
)
{
SYSERROR
(
"Failed to open monitor netns fd."
);
return
;
}
if
(
setns
(
netnsfd
,
0
)
!=
0
)
{
SYSERROR
(
"Failed to enter container netns to reset nics"
);
close
(
oldfd
);
return
;
}
for
(
i
=
0
;
i
<
conf
->
num_savednics
;
i
++
)
{
struct
saved_nic
*
s
=
&
conf
->
saved_nics
[
i
];
/* retrieve the name of the interface */
if
(
!
if_indextoname
(
s
->
ifindex
,
ifname
))
{
WARN
(
"no interface corresponding to index '%d'"
,
s
->
ifindex
);
continue
;
}
if
(
lxc_netdev_move_by_name
(
ifname
,
1
,
s
->
orig_name
))
WARN
(
"Error moving nic name:%s back to host netns"
,
ifname
);
free
(
s
->
orig_name
);
}
conf
->
num_savednics
=
0
;
if
(
setns
(
oldfd
,
0
)
!=
0
)
SYSERROR
(
"Failed to re-enter monitor's netns"
);
close
(
oldfd
);
}
static
char
*
default_rootfs_mount
=
LXCROOTFSMOUNT
;
static
char
*
default_rootfs_mount
=
LXCROOTFSMOUNT
;
struct
lxc_conf
*
lxc_conf_init
(
void
)
struct
lxc_conf
*
lxc_conf_init
(
void
)
...
@@ -2672,651 +2315,6 @@ struct lxc_conf *lxc_conf_init(void)
...
@@ -2672,651 +2315,6 @@ struct lxc_conf *lxc_conf_init(void)
return
new
;
return
new
;
}
}
static
int
instantiate_veth
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
char
*
veth1
,
*
veth2
;
char
veth1buf
[
IFNAMSIZ
],
veth2buf
[
IFNAMSIZ
];
int
bridge_index
,
err
;
unsigned
int
mtu
=
0
;
if
(
netdev
->
priv
.
veth_attr
.
pair
)
{
veth1
=
netdev
->
priv
.
veth_attr
.
pair
;
if
(
handler
->
conf
->
reboot
)
lxc_netdev_delete_by_name
(
veth1
);
}
else
{
err
=
snprintf
(
veth1buf
,
sizeof
(
veth1buf
),
"vethXXXXXX"
);
if
(
err
>=
sizeof
(
veth1buf
))
{
/* can't *really* happen, but... */
ERROR
(
"veth1 name too long"
);
return
-
1
;
}
veth1
=
lxc_mkifname
(
veth1buf
);
if
(
!
veth1
)
{
ERROR
(
"failed to allocate a temporary name"
);
return
-
1
;
}
/* store away for deconf */
memcpy
(
netdev
->
priv
.
veth_attr
.
veth1
,
veth1
,
IFNAMSIZ
);
}
snprintf
(
veth2buf
,
sizeof
(
veth2buf
),
"vethXXXXXX"
);
veth2
=
lxc_mkifname
(
veth2buf
);
if
(
!
veth2
)
{
ERROR
(
"failed to allocate a temporary name"
);
goto
out_delete
;
}
err
=
lxc_veth_create
(
veth1
,
veth2
);
if
(
err
)
{
ERROR
(
"failed to create veth pair
\"
%s
\"
and
\"
%s
\"
: %s"
,
veth1
,
veth2
,
strerror
(
-
err
));
goto
out_delete
;
}
/* changing the high byte of the mac address to 0xfe, the bridge interface
* will always keep the host's mac address and not take the mac address
* of a container */
err
=
setup_private_host_hw_addr
(
veth1
);
if
(
err
)
{
ERROR
(
"failed to change mac address of host interface
\"
%s
\"
: %s"
,
veth1
,
strerror
(
-
err
));
goto
out_delete
;
}
netdev
->
ifindex
=
if_nametoindex
(
veth2
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"failed to retrieve the index for
\"
%s
\"
"
,
veth2
);
goto
out_delete
;
}
if
(
netdev
->
mtu
)
{
if
(
lxc_safe_uint
(
netdev
->
mtu
,
&
mtu
)
<
0
)
WARN
(
"failed to parse mtu from"
);
else
INFO
(
"retrieved mtu %d"
,
mtu
);
}
else
if
(
netdev
->
link
)
{
bridge_index
=
if_nametoindex
(
netdev
->
link
);
if
(
bridge_index
)
{
mtu
=
netdev_get_mtu
(
bridge_index
);
INFO
(
"retrieved mtu %d from %s"
,
mtu
,
netdev
->
link
);
}
else
{
mtu
=
netdev_get_mtu
(
netdev
->
ifindex
);
INFO
(
"retrieved mtu %d from %s"
,
mtu
,
veth2
);
}
}
if
(
mtu
)
{
err
=
lxc_netdev_set_mtu
(
veth1
,
mtu
);
if
(
!
err
)
err
=
lxc_netdev_set_mtu
(
veth2
,
mtu
);
if
(
err
)
{
ERROR
(
"failed to set mtu
\"
%d
\"
for veth pair
\"
%s
\"
"
"and
\"
%s
\"
: %s"
,
mtu
,
veth1
,
veth2
,
strerror
(
-
err
));
goto
out_delete
;
}
}
if
(
netdev
->
link
)
{
err
=
lxc_bridge_attach
(
handler
->
lxcpath
,
handler
->
name
,
netdev
->
link
,
veth1
);
if
(
err
)
{
ERROR
(
"failed to attach
\"
%s
\"
to bridge
\"
%s
\"
: %s"
,
veth1
,
netdev
->
link
,
strerror
(
-
err
));
goto
out_delete
;
}
INFO
(
"attached
\"
%s
\"
to bridge
\"
%s
\"
"
,
veth1
,
netdev
->
link
);
}
err
=
lxc_netdev_up
(
veth1
);
if
(
err
)
{
ERROR
(
"failed to set
\"
%s
\"
up: %s"
,
veth1
,
strerror
(
-
err
));
goto
out_delete
;
}
if
(
netdev
->
upscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
upscript
,
"up"
,
"veth"
,
veth1
,
(
char
*
)
NULL
);
if
(
err
)
goto
out_delete
;
}
DEBUG
(
"instantiated veth
\"
%s/%s
\"
, index is
\"
%d
\"
"
,
veth1
,
veth2
,
netdev
->
ifindex
);
return
0
;
out_delete:
if
(
netdev
->
ifindex
!=
0
)
lxc_netdev_delete_by_name
(
veth1
);
if
(
!
netdev
->
priv
.
veth_attr
.
pair
)
free
(
veth1
);
free
(
veth2
);
return
-
1
;
}
static
int
shutdown_veth
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
char
*
veth1
;
int
err
;
if
(
netdev
->
priv
.
veth_attr
.
pair
)
veth1
=
netdev
->
priv
.
veth_attr
.
pair
;
else
veth1
=
netdev
->
priv
.
veth_attr
.
veth1
;
if
(
netdev
->
downscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
downscript
,
"down"
,
"veth"
,
veth1
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
instantiate_macvlan
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
char
peerbuf
[
IFNAMSIZ
],
*
peer
;
int
err
;
if
(
!
netdev
->
link
)
{
ERROR
(
"no link specified for macvlan netdev"
);
return
-
1
;
}
err
=
snprintf
(
peerbuf
,
sizeof
(
peerbuf
),
"mcXXXXXX"
);
if
(
err
>=
sizeof
(
peerbuf
))
return
-
1
;
peer
=
lxc_mkifname
(
peerbuf
);
if
(
!
peer
)
{
ERROR
(
"failed to make a temporary name"
);
return
-
1
;
}
err
=
lxc_macvlan_create
(
netdev
->
link
,
peer
,
netdev
->
priv
.
macvlan_attr
.
mode
);
if
(
err
)
{
ERROR
(
"failed to create macvlan interface '%s' on '%s' : %s"
,
peer
,
netdev
->
link
,
strerror
(
-
err
));
goto
out
;
}
netdev
->
ifindex
=
if_nametoindex
(
peer
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"failed to retrieve the index for %s"
,
peer
);
goto
out
;
}
if
(
netdev
->
upscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
upscript
,
"up"
,
"macvlan"
,
netdev
->
link
,
(
char
*
)
NULL
);
if
(
err
)
goto
out
;
}
DEBUG
(
"instantiated macvlan '%s', index is '%d' and mode '%d'"
,
peer
,
netdev
->
ifindex
,
netdev
->
priv
.
macvlan_attr
.
mode
);
return
0
;
out:
lxc_netdev_delete_by_name
(
peer
);
free
(
peer
);
return
-
1
;
}
static
int
shutdown_macvlan
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
int
err
;
if
(
netdev
->
downscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
downscript
,
"down"
,
"macvlan"
,
netdev
->
link
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
/* XXX: merge with instantiate_macvlan */
static
int
instantiate_vlan
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
char
peer
[
IFNAMSIZ
];
int
err
;
static
uint16_t
vlan_cntr
=
0
;
unsigned
int
mtu
=
0
;
if
(
!
netdev
->
link
)
{
ERROR
(
"no link specified for vlan netdev"
);
return
-
1
;
}
err
=
snprintf
(
peer
,
sizeof
(
peer
),
"vlan%d-%d"
,
netdev
->
priv
.
vlan_attr
.
vid
,
vlan_cntr
++
);
if
(
err
>=
sizeof
(
peer
))
{
ERROR
(
"peer name too long"
);
return
-
1
;
}
err
=
lxc_vlan_create
(
netdev
->
link
,
peer
,
netdev
->
priv
.
vlan_attr
.
vid
);
if
(
err
)
{
ERROR
(
"failed to create vlan interface '%s' on '%s' : %s"
,
peer
,
netdev
->
link
,
strerror
(
-
err
));
return
-
1
;
}
netdev
->
ifindex
=
if_nametoindex
(
peer
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"failed to retrieve the ifindex for %s"
,
peer
);
lxc_netdev_delete_by_name
(
peer
);
return
-
1
;
}
DEBUG
(
"instantiated vlan '%s', ifindex is '%d'"
,
" vlan1000"
,
netdev
->
ifindex
);
if
(
netdev
->
mtu
)
{
if
(
lxc_safe_uint
(
netdev
->
mtu
,
&
mtu
)
<
0
)
{
ERROR
(
"Failed to retrieve mtu from: '%d'/'%s'."
,
netdev
->
ifindex
,
netdev
->
name
);
return
-
1
;
}
err
=
lxc_netdev_set_mtu
(
peer
,
mtu
);
if
(
err
)
{
ERROR
(
"failed to set mtu '%s' for %s : %s"
,
netdev
->
mtu
,
peer
,
strerror
(
-
err
));
lxc_netdev_delete_by_name
(
peer
);
return
-
1
;
}
}
return
0
;
}
static
int
shutdown_vlan
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
return
0
;
}
static
int
instantiate_phys
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
if
(
!
netdev
->
link
)
{
ERROR
(
"no link specified for the physical interface"
);
return
-
1
;
}
netdev
->
ifindex
=
if_nametoindex
(
netdev
->
link
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"failed to retrieve the index for %s"
,
netdev
->
link
);
return
-
1
;
}
if
(
netdev
->
upscript
)
{
int
err
;
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
upscript
,
"up"
,
"phys"
,
netdev
->
link
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
shutdown_phys
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
int
err
;
if
(
netdev
->
downscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
downscript
,
"down"
,
"phys"
,
netdev
->
link
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
instantiate_none
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
netdev
->
ifindex
=
0
;
return
0
;
}
static
int
instantiate_empty
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
netdev
->
ifindex
=
0
;
if
(
netdev
->
upscript
)
{
int
err
;
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
upscript
,
"up"
,
"empty"
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
shutdown_empty
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
int
err
;
if
(
netdev
->
downscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
downscript
,
"down"
,
"empty"
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
shutdown_none
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
return
0
;
}
int
lxc_requests_empty_network
(
struct
lxc_handler
*
handler
)
{
struct
lxc_list
*
network
=
&
handler
->
conf
->
network
;
struct
lxc_list
*
iterator
;
struct
lxc_netdev
*
netdev
;
bool
found_none
=
false
,
found_nic
=
false
;
if
(
lxc_list_empty
(
network
))
return
0
;
lxc_list_for_each
(
iterator
,
network
)
{
netdev
=
iterator
->
elem
;
if
(
netdev
->
type
==
LXC_NET_NONE
)
found_none
=
true
;
else
found_nic
=
true
;
}
if
(
found_none
&&
!
found_nic
)
return
1
;
return
0
;
}
int
lxc_create_network
(
struct
lxc_handler
*
handler
)
{
struct
lxc_list
*
network
=
&
handler
->
conf
->
network
;
struct
lxc_list
*
iterator
;
struct
lxc_netdev
*
netdev
;
int
am_root
=
(
getuid
()
==
0
);
if
(
!
am_root
)
return
0
;
lxc_log_configured_netdevs
(
handler
->
conf
);
lxc_list_for_each
(
iterator
,
network
)
{
netdev
=
iterator
->
elem
;
if
(
netdev
->
type
!=
LXC_NET_MACVLAN
&&
netdev
->
priv
.
macvlan_attr
.
mode
)
{
ERROR
(
"Invalid macvlan.mode for a non-macvlan netdev"
);
return
-
1
;
}
if
(
netdev
->
type
!=
LXC_NET_VETH
&&
netdev
->
priv
.
veth_attr
.
pair
)
{
ERROR
(
"Invalid veth pair for a non-veth netdev"
);
return
-
1
;
}
if
(
netdev
->
type
!=
LXC_NET_VLAN
&&
netdev
->
priv
.
vlan_attr
.
vid
>
0
)
{
ERROR
(
"Invalid vlan.id for a non-macvlan netdev"
);
return
-
1
;
}
if
(
netdev
->
type
<
0
||
netdev
->
type
>
LXC_NET_MAXCONFTYPE
)
{
ERROR
(
"invalid network configuration type '%d'"
,
netdev
->
type
);
return
-
1
;
}
if
(
netdev_conf
[
netdev
->
type
](
handler
,
netdev
))
{
ERROR
(
"failed to create netdev"
);
return
-
1
;
}
}
return
0
;
}
bool
lxc_delete_network
(
struct
lxc_handler
*
handler
)
{
int
ret
;
struct
lxc_list
*
network
=
&
handler
->
conf
->
network
;
struct
lxc_list
*
iterator
;
struct
lxc_netdev
*
netdev
;
bool
deleted_all
=
true
;
lxc_list_for_each
(
iterator
,
network
)
{
netdev
=
iterator
->
elem
;
if
(
netdev
->
ifindex
!=
0
&&
netdev
->
type
==
LXC_NET_PHYS
)
{
if
(
lxc_netdev_rename_by_index
(
netdev
->
ifindex
,
netdev
->
link
))
WARN
(
"Failed to rename interface with index %d "
"to its initial name
\"
%s
\"
."
,
netdev
->
ifindex
,
netdev
->
link
);
continue
;
}
if
(
netdev_deconf
[
netdev
->
type
](
handler
,
netdev
))
{
WARN
(
"Failed to destroy netdev"
);
}
/* Recent kernel remove the virtual interfaces when the network
* namespace is destroyed but in case we did not move the
* interface to the network namespace, we have to destroy it
*/
if
(
netdev
->
ifindex
!=
0
)
{
ret
=
lxc_netdev_delete_by_index
(
netdev
->
ifindex
);
if
(
-
ret
==
ENODEV
)
{
INFO
(
"Interface
\"
%s
\"
with index %d already "
"deleted or existing in different network "
"namespace."
,
netdev
->
name
?
netdev
->
name
:
"(null)"
,
netdev
->
ifindex
);
}
else
if
(
ret
<
0
)
{
deleted_all
=
false
;
WARN
(
"Failed to remove interface
\"
%s
\"
with "
"index %d: %s."
,
netdev
->
name
?
netdev
->
name
:
"(null)"
,
netdev
->
ifindex
,
strerror
(
-
ret
));
}
else
{
INFO
(
"Removed interface
\"
%s
\"
with index %d."
,
netdev
->
name
?
netdev
->
name
:
"(null)"
,
netdev
->
ifindex
);
}
}
/* Explicitly delete host veth device to prevent lingering
* devices. We had issues in LXD around this.
*/
if
(
netdev
->
ifindex
!=
0
&&
netdev
->
type
==
LXC_NET_VETH
&&
!
am_unpriv
())
{
char
*
hostveth
;
if
(
netdev
->
priv
.
veth_attr
.
pair
)
{
hostveth
=
netdev
->
priv
.
veth_attr
.
pair
;
ret
=
lxc_netdev_delete_by_name
(
hostveth
);
if
(
ret
<
0
)
WARN
(
"Failed to remove interface
\"
%s
\"
from host: %s."
,
hostveth
,
strerror
(
-
ret
));
else
INFO
(
"Removed interface
\"
%s
\"
from host."
,
hostveth
);
}
else
if
(
strlen
(
netdev
->
priv
.
veth_attr
.
veth1
)
>
0
)
{
hostveth
=
netdev
->
priv
.
veth_attr
.
veth1
;
ret
=
lxc_netdev_delete_by_name
(
hostveth
);
if
(
ret
<
0
)
{
WARN
(
"Failed to remove
\"
%s
\"
from host: %s."
,
hostveth
,
strerror
(
-
ret
));
}
else
{
INFO
(
"Removed interface
\"
%s
\"
from host."
,
hostveth
);
memset
((
void
*
)
&
netdev
->
priv
.
veth_attr
.
veth1
,
0
,
sizeof
(
netdev
->
priv
.
veth_attr
.
veth1
));
}
}
}
}
return
deleted_all
;
}
#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
/* lxc-user-nic returns "interface_name:interface_name\n" */
#define MAX_BUFFER_SIZE IFNAMSIZ * 2 + 2
static
int
unpriv_assign_nic
(
const
char
*
lxcpath
,
char
*
lxcname
,
struct
lxc_netdev
*
netdev
,
pid_t
pid
)
{
pid_t
child
;
int
bytes
,
pipefd
[
2
];
char
*
token
,
*
saveptr
=
NULL
;
char
buffer
[
MAX_BUFFER_SIZE
];
char
netdev_link
[
IFNAMSIZ
+
1
];
if
(
netdev
->
type
!=
LXC_NET_VETH
)
{
ERROR
(
"nic type %d not support for unprivileged use"
,
netdev
->
type
);
return
-
1
;
}
if
(
pipe
(
pipefd
)
<
0
)
{
SYSERROR
(
"pipe failed"
);
return
-
1
;
}
child
=
fork
();
if
(
child
<
0
)
{
SYSERROR
(
"fork"
);
close
(
pipefd
[
0
]);
close
(
pipefd
[
1
]);
return
-
1
;
}
if
(
child
==
0
)
{
// child
/* Call lxc-user-nic pid type bridge. */
int
ret
;
char
pidstr
[
LXC_NUMSTRLEN64
];
close
(
pipefd
[
0
]);
/* Close the read-end of the pipe. */
/* Redirect stdout to write-end of the pipe. */
ret
=
dup2
(
pipefd
[
1
],
STDOUT_FILENO
);
close
(
pipefd
[
1
]);
/* Close the write-end of the pipe. */
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to dup2() to redirect stdout to pipe file descriptor."
);
exit
(
EXIT_FAILURE
);
}
if
(
netdev
->
link
)
strncpy
(
netdev_link
,
netdev
->
link
,
IFNAMSIZ
);
else
strncpy
(
netdev_link
,
"none"
,
IFNAMSIZ
);
ret
=
snprintf
(
pidstr
,
LXC_NUMSTRLEN64
,
"%d"
,
pid
);
if
(
ret
<
0
||
ret
>=
LXC_NUMSTRLEN64
)
exit
(
EXIT_FAILURE
);
pidstr
[
LXC_NUMSTRLEN64
-
1
]
=
'\0'
;
INFO
(
"Execing lxc-user-nic %s %s %s veth %s %s"
,
lxcpath
,
lxcname
,
pidstr
,
netdev_link
,
netdev
->
name
);
execlp
(
LXC_USERNIC_PATH
,
LXC_USERNIC_PATH
,
lxcpath
,
lxcname
,
pidstr
,
"veth"
,
netdev_link
,
netdev
->
name
,
NULL
);
SYSERROR
(
"Failed to exec lxc-user-nic."
);
exit
(
EXIT_FAILURE
);
}
/* close the write-end of the pipe */
close
(
pipefd
[
1
]);
bytes
=
read
(
pipefd
[
0
],
&
buffer
,
MAX_BUFFER_SIZE
);
if
(
bytes
<
0
)
{
SYSERROR
(
"Failed to read from pipe file descriptor."
);
close
(
pipefd
[
0
]);
return
-
1
;
}
buffer
[
bytes
-
1
]
=
'\0'
;
if
(
wait_for_pid
(
child
)
!=
0
)
{
TRACE
(
"lxc-user-nic failed to configure requested network"
);
close
(
pipefd
[
0
]);
return
-
1
;
}
TRACE
(
"Received output
\"
%s
\"
from lxc-user-nic"
,
buffer
);
/* close the read-end of the pipe */
close
(
pipefd
[
0
]);
/* fill netdev->name field */
token
=
strtok_r
(
buffer
,
":"
,
&
saveptr
);
if
(
!
token
)
return
-
1
;
netdev
->
name
=
malloc
(
IFNAMSIZ
+
1
);
if
(
!
netdev
->
name
)
{
SYSERROR
(
"Failed to allocate memory."
);
return
-
1
;
}
memset
(
netdev
->
name
,
0
,
IFNAMSIZ
+
1
);
strncpy
(
netdev
->
name
,
token
,
IFNAMSIZ
);
/* fill netdev->veth_attr.pair field */
token
=
strtok_r
(
NULL
,
":"
,
&
saveptr
);
if
(
!
token
)
return
-
1
;
netdev
->
priv
.
veth_attr
.
pair
=
strdup
(
token
);
if
(
!
netdev
->
priv
.
veth_attr
.
pair
)
{
ERROR
(
"Failed to allocate memory."
);
return
-
1
;
}
return
0
;
}
int
lxc_assign_network
(
const
char
*
lxcpath
,
char
*
lxcname
,
struct
lxc_list
*
network
,
pid_t
pid
)
{
struct
lxc_list
*
iterator
;
struct
lxc_netdev
*
netdev
;
char
ifname
[
IFNAMSIZ
];
int
am_root
=
(
getuid
()
==
0
);
int
err
;
lxc_list_for_each
(
iterator
,
network
)
{
netdev
=
iterator
->
elem
;
if
(
netdev
->
type
==
LXC_NET_VETH
&&
!
am_root
)
{
if
(
netdev
->
mtu
)
INFO
(
"mtu ignored due to insufficient privilege"
);
if
(
unpriv_assign_nic
(
lxcpath
,
lxcname
,
netdev
,
pid
))
return
-
1
;
// lxc-user-nic has moved the nic to the new ns.
// unpriv_assign_nic() fills in netdev->name.
// netdev->ifindex will be filed in at setup_netdev.
continue
;
}
/* empty network namespace, nothing to move */
if
(
!
netdev
->
ifindex
)
continue
;
/* retrieve the name of the interface */
if
(
!
if_indextoname
(
netdev
->
ifindex
,
ifname
))
{
ERROR
(
"no interface corresponding to index '%d'"
,
netdev
->
ifindex
);
return
-
1
;
}
err
=
lxc_netdev_move_by_name
(
ifname
,
pid
,
NULL
);
if
(
err
)
{
ERROR
(
"failed to move '%s' to the container : %s"
,
netdev
->
link
,
strerror
(
-
err
));
return
-
1
;
}
DEBUG
(
"move '%s'/'%s' to '%d': ."
,
ifname
,
netdev
->
name
,
pid
);
}
return
0
;
}
static
int
write_id_mapping
(
enum
idtype
idtype
,
pid_t
pid
,
const
char
*
buf
,
static
int
write_id_mapping
(
enum
idtype
idtype
,
pid_t
pid
,
const
char
*
buf
,
size_t
buf_size
)
size_t
buf_size
)
{
{
...
@@ -3588,54 +2586,6 @@ again:
...
@@ -3588,54 +2586,6 @@ again:
return
freeid
;
return
freeid
;
}
}
int
lxc_find_gateway_addresses
(
struct
lxc_handler
*
handler
)
{
struct
lxc_list
*
network
=
&
handler
->
conf
->
network
;
struct
lxc_list
*
iterator
;
struct
lxc_netdev
*
netdev
;
int
link_index
;
lxc_list_for_each
(
iterator
,
network
)
{
netdev
=
iterator
->
elem
;
if
(
!
netdev
->
ipv4_gateway_auto
&&
!
netdev
->
ipv6_gateway_auto
)
continue
;
if
(
netdev
->
type
!=
LXC_NET_VETH
&&
netdev
->
type
!=
LXC_NET_MACVLAN
)
{
ERROR
(
"gateway = auto only supported for "
"veth and macvlan"
);
return
-
1
;
}
if
(
!
netdev
->
link
)
{
ERROR
(
"gateway = auto needs a link interface"
);
return
-
1
;
}
link_index
=
if_nametoindex
(
netdev
->
link
);
if
(
!
link_index
)
return
-
EINVAL
;
if
(
netdev
->
ipv4_gateway_auto
)
{
if
(
lxc_ipv4_addr_get
(
link_index
,
&
netdev
->
ipv4_gateway
))
{
ERROR
(
"failed to automatically find ipv4 gateway "
"address from link interface '%s'"
,
netdev
->
link
);
return
-
1
;
}
}
if
(
netdev
->
ipv6_gateway_auto
)
{
if
(
lxc_ipv6_addr_get
(
link_index
,
&
netdev
->
ipv6_gateway
))
{
ERROR
(
"failed to automatically find ipv6 gateway "
"address from link interface '%s'"
,
netdev
->
link
);
return
-
1
;
}
}
}
return
0
;
}
int
lxc_create_tty
(
const
char
*
name
,
struct
lxc_conf
*
conf
)
int
lxc_create_tty
(
const
char
*
name
,
struct
lxc_conf
*
conf
)
{
{
struct
lxc_tty_info
*
tty_info
=
&
conf
->
tty_info
;
struct
lxc_tty_info
*
tty_info
=
&
conf
->
tty_info
;
...
@@ -4113,7 +3063,7 @@ int lxc_setup(struct lxc_handler *handler)
...
@@ -4113,7 +3063,7 @@ int lxc_setup(struct lxc_handler *handler)
}
}
}
}
if
(
setup_network
(
&
lxc_conf
->
network
))
{
if
(
lxc_setup_network_in_child_namespaces
(
lxc_conf
,
&
lxc_conf
->
network
))
{
ERROR
(
"failed to setup the network for '%s'"
,
name
);
ERROR
(
"failed to setup the network for '%s'"
,
name
);
return
-
1
;
return
-
1
;
}
}
...
@@ -4469,7 +3419,6 @@ int lxc_clear_environment(struct lxc_conf *c)
...
@@ -4469,7 +3419,6 @@ int lxc_clear_environment(struct lxc_conf *c)
return
0
;
return
0
;
}
}
int
lxc_clear_mount_entries
(
struct
lxc_conf
*
c
)
int
lxc_clear_mount_entries
(
struct
lxc_conf
*
c
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
...
...
src/lxc/conf.h
View file @
d3e7b8ad
...
@@ -43,103 +43,6 @@ typedef void * scmp_filter_ctx;
...
@@ -43,103 +43,6 @@ typedef void * scmp_filter_ctx;
#define subuidfile "/etc/subuid"
#define subuidfile "/etc/subuid"
#define subgidfile "/etc/subgid"
#define subgidfile "/etc/subgid"
enum
{
LXC_NET_EMPTY
,
LXC_NET_VETH
,
LXC_NET_MACVLAN
,
LXC_NET_PHYS
,
LXC_NET_VLAN
,
LXC_NET_NONE
,
LXC_NET_MAXCONFTYPE
,
};
/*
* Defines the structure to configure an ipv4 address
* @address : ipv4 address
* @broadcast : ipv4 broadcast address
* @mask : network mask
*/
struct
lxc_inetdev
{
struct
in_addr
addr
;
struct
in_addr
bcast
;
unsigned
int
prefix
;
};
struct
lxc_route
{
struct
in_addr
addr
;
};
/*
* Defines the structure to configure an ipv6 address
* @flags : set the address up
* @address : ipv6 address
* @broadcast : ipv6 broadcast address
* @mask : network mask
*/
struct
lxc_inet6dev
{
struct
in6_addr
addr
;
struct
in6_addr
mcast
;
struct
in6_addr
acast
;
unsigned
int
prefix
;
};
struct
lxc_route6
{
struct
in6_addr
addr
;
};
struct
ifla_veth
{
char
*
pair
;
/* pair name */
char
veth1
[
IFNAMSIZ
];
/* needed for deconf */
};
struct
ifla_vlan
{
unsigned
int
flags
;
unsigned
int
fmask
;
unsigned
short
vid
;
unsigned
short
pad
;
};
struct
ifla_macvlan
{
int
mode
;
/* private, vepa, bridge, passthru */
};
union
netdev_p
{
struct
ifla_veth
veth_attr
;
struct
ifla_vlan
vlan_attr
;
struct
ifla_macvlan
macvlan_attr
;
};
/*
* Defines a structure to configure a network device
* @link : lxc.network.link, name of bridge or host iface to attach if any
* @name : lxc.network.name, name of iface on the container side
* @flags : flag of the network device (IFF_UP, ... )
* @ipv4 : a list of ipv4 addresses to be set on the network device
* @ipv6 : a list of ipv6 addresses to be set on the network device
* @upscript : a script filename to be executed during interface configuration
* @downscript : a script filename to be executed during interface destruction
* @idx : network counter
*/
struct
lxc_netdev
{
unsigned
int
idx
;
int
type
;
int
flags
;
int
ifindex
;
char
*
link
;
char
*
name
;
char
*
hwaddr
;
char
*
mtu
;
union
netdev_p
priv
;
struct
lxc_list
ipv4
;
struct
lxc_list
ipv6
;
struct
in_addr
*
ipv4_gateway
;
bool
ipv4_gateway_auto
;
struct
in6_addr
*
ipv6_gateway
;
bool
ipv6_gateway_auto
;
char
*
upscript
;
char
*
downscript
;
};
/*
/*
* Defines a generic struct to configure the control group.
* Defines a generic struct to configure the control group.
* It is up to the programmer to specify the right subsystem.
* It is up to the programmer to specify the right subsystem.
...
@@ -282,16 +185,20 @@ enum {
...
@@ -282,16 +185,20 @@ enum {
* @lsm_se_context : selinux type to switch to or NULL
* @lsm_se_context : selinux type to switch to or NULL
*/
*/
enum
lxchooks
{
enum
lxchooks
{
LXCHOOK_PRESTART
,
LXCHOOK_PREMOUNT
,
LXCHOOK_MOUNT
,
LXCHOOK_AUTODEV
,
LXCHOOK_PRESTART
,
LXCHOOK_START
,
LXCHOOK_STOP
,
LXCHOOK_POSTSTOP
,
LXCHOOK_CLONE
,
LXCHOOK_DESTROY
,
LXCHOOK_PREMOUNT
,
NUM_LXC_HOOKS
};
LXCHOOK_MOUNT
,
extern
char
*
lxchook_names
[
NUM_LXC_HOOKS
];
LXCHOOK_AUTODEV
,
LXCHOOK_START
,
struct
saved_nic
{
LXCHOOK_STOP
,
int
ifindex
;
LXCHOOK_POSTSTOP
,
char
*
orig_name
;
LXCHOOK_CLONE
,
LXCHOOK_DESTROY
,
NUM_LXC_HOOKS
};
};
extern
char
*
lxchook_names
[
NUM_LXC_HOOKS
];
struct
lxc_conf
{
struct
lxc_conf
{
int
is_execute
;
int
is_execute
;
char
*
fstab
;
char
*
fstab
;
...
@@ -400,15 +307,7 @@ extern struct lxc_conf *lxc_conf_init(void);
...
@@ -400,15 +307,7 @@ extern struct lxc_conf *lxc_conf_init(void);
extern
void
lxc_conf_free
(
struct
lxc_conf
*
conf
);
extern
void
lxc_conf_free
(
struct
lxc_conf
*
conf
);
extern
int
pin_rootfs
(
const
char
*
rootfs
);
extern
int
pin_rootfs
(
const
char
*
rootfs
);
extern
int
lxc_requests_empty_network
(
struct
lxc_handler
*
handler
);
extern
int
lxc_create_network
(
struct
lxc_handler
*
handler
);
extern
bool
lxc_delete_network
(
struct
lxc_handler
*
handler
);
extern
int
lxc_assign_network
(
const
char
*
lxcpath
,
char
*
lxcname
,
struct
lxc_list
*
networks
,
pid_t
pid
);
extern
int
lxc_map_ids
(
struct
lxc_list
*
idmap
,
pid_t
pid
);
extern
int
lxc_map_ids
(
struct
lxc_list
*
idmap
,
pid_t
pid
);
extern
int
lxc_find_gateway_addresses
(
struct
lxc_handler
*
handler
);
extern
int
lxc_create_tty
(
const
char
*
name
,
struct
lxc_conf
*
conf
);
extern
int
lxc_create_tty
(
const
char
*
name
,
struct
lxc_conf
*
conf
);
extern
void
lxc_delete_tty
(
struct
lxc_tty_info
*
tty_info
);
extern
void
lxc_delete_tty
(
struct
lxc_tty_info
*
tty_info
);
...
@@ -435,9 +334,6 @@ extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
...
@@ -435,9 +334,6 @@ extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
struct
cgroup_process_info
;
struct
cgroup_process_info
;
extern
int
lxc_setup
(
struct
lxc_handler
*
handler
);
extern
int
lxc_setup
(
struct
lxc_handler
*
handler
);
extern
void
lxc_restore_phys_nics_to_netns
(
int
netnsfd
,
struct
lxc_conf
*
conf
);
extern
int
find_unmapped_nsid
(
struct
lxc_conf
*
conf
,
enum
idtype
idtype
);
extern
int
find_unmapped_nsid
(
struct
lxc_conf
*
conf
,
enum
idtype
idtype
);
extern
int
mapped_hostid
(
unsigned
id
,
struct
lxc_conf
*
conf
,
enum
idtype
idtype
);
extern
int
mapped_hostid
(
unsigned
id
,
struct
lxc_conf
*
conf
,
enum
idtype
idtype
);
extern
int
chown_mapped_root
(
char
*
path
,
struct
lxc_conf
*
conf
);
extern
int
chown_mapped_root
(
char
*
path
,
struct
lxc_conf
*
conf
);
...
@@ -449,9 +345,11 @@ extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
...
@@ -449,9 +345,11 @@ extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
extern
void
tmp_proc_unmount
(
struct
lxc_conf
*
lxc_conf
);
extern
void
tmp_proc_unmount
(
struct
lxc_conf
*
lxc_conf
);
void
remount_all_slave
(
void
);
void
remount_all_slave
(
void
);
extern
void
suggest_default_idmap
(
void
);
extern
void
suggest_default_idmap
(
void
);
FILE
*
make_anonymous_mount_file
(
struct
lxc_list
*
mount
);
extern
FILE
*
make_anonymous_mount_file
(
struct
lxc_list
*
mount
);
struct
lxc_list
*
sort_cgroup_settings
(
struct
lxc_list
*
cgroup_settings
);
extern
struct
lxc_list
*
sort_cgroup_settings
(
struct
lxc_list
*
cgroup_settings
);
unsigned
long
add_required_remount_flags
(
const
char
*
s
,
const
char
*
d
,
extern
unsigned
long
add_required_remount_flags
(
const
char
*
s
,
const
char
*
d
,
unsigned
long
flags
);
unsigned
long
flags
);
extern
int
run_script
(
const
char
*
name
,
const
char
*
section
,
const
char
*
script
,
#endif
...);
#endif
/* __LXC_CONF_H */
src/lxc/confile_utils.c
View file @
d3e7b8ad
...
@@ -29,6 +29,8 @@
...
@@ -29,6 +29,8 @@
#include "error.h"
#include "error.h"
#include "log.h"
#include "log.h"
#include "list.h"
#include "list.h"
#include "network.h"
#include "parse.h"
#include "utils.h"
#include "utils.h"
lxc_log_define
(
lxc_confile_utils
,
lxc
);
lxc_log_define
(
lxc_confile_utils
,
lxc
);
...
@@ -253,7 +255,8 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
...
@@ -253,7 +255,8 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
lxc_list_for_each
(
it
,
&
conf
->
network
)
{
lxc_list_for_each
(
it
,
&
conf
->
network
)
{
netdev
=
it
->
elem
;
netdev
=
it
->
elem
;
TRACE
(
"index: %d"
,
netdev
->
idx
);
TRACE
(
"index: %zd"
,
netdev
->
idx
);
TRACE
(
"ifindex: %d"
,
netdev
->
ifindex
);
switch
(
netdev
->
type
)
{
switch
(
netdev
->
type
)
{
case
LXC_NET_VETH
:
case
LXC_NET_VETH
:
TRACE
(
"type: veth"
);
TRACE
(
"type: veth"
);
...
...
src/lxc/lxc_user_nic.c
View file @
d3e7b8ad
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
*/
#define _GNU_SOURCE
/* See feature_test_macros(7) */
#define _GNU_SOURCE
#include <alloca.h>
#include <alloca.h>
#include <ctype.h>
#include <ctype.h>
#include <errno.h>
#include <errno.h>
...
@@ -59,21 +59,27 @@
...
@@ -59,21 +59,27 @@
static
void
usage
(
char
*
me
,
bool
fail
)
static
void
usage
(
char
*
me
,
bool
fail
)
{
{
fprintf
(
stderr
,
"Usage: %s lxcpath name pid type bridge nicname
\n
"
,
me
);
fprintf
(
stderr
,
"Usage: %s create {lxcpath} {name} {pid} {type} "
fprintf
(
stderr
,
" nicname is the name to use inside the container
\n
"
);
"{bridge} {nicname}
\n
"
,
me
);
exit
(
fail
?
1
:
0
);
fprintf
(
stderr
,
"Usage: %s delete {lxcpath} {name} {pid} {type} "
}
"{bridge} {nicname}
\n
"
,
me
);
fprintf
(
stderr
,
"{nicname} is the name to use inside the container
\n
"
);
static
char
*
lxcpath
,
*
lxcname
;
if
(
fail
)
exit
(
EXIT_FAILURE
);
exit
(
EXIT_SUCCESS
);
}
static
int
open_and_lock
(
char
*
path
)
static
int
open_and_lock
(
char
*
path
)
{
{
int
fd
;
int
fd
,
ret
;
struct
flock
lk
;
struct
flock
lk
;
fd
=
open
(
path
,
O_RDWR
|
O_CREAT
,
S_IWUSR
|
S_IRUSR
);
fd
=
open
(
path
,
O_RDWR
|
O_CREAT
,
S_IWUSR
|
S_IRUSR
);
if
(
fd
<
0
)
{
if
(
fd
<
0
)
{
usernic_error
(
"Failed to open %s: %s.
\n
"
,
path
,
strerror
(
errno
));
usernic_error
(
"Failed to open %s: %s.
\n
"
,
path
,
strerror
(
errno
));
return
-
1
;
return
-
1
;
}
}
...
@@ -81,8 +87,11 @@ static int open_and_lock(char *path)
...
@@ -81,8 +87,11 @@ static int open_and_lock(char *path)
lk
.
l_whence
=
SEEK_SET
;
lk
.
l_whence
=
SEEK_SET
;
lk
.
l_start
=
0
;
lk
.
l_start
=
0
;
lk
.
l_len
=
0
;
lk
.
l_len
=
0
;
if
(
fcntl
(
fd
,
F_SETLKW
,
&
lk
)
<
0
)
{
usernic_error
(
"Failed to lock %s: %s.
\n
"
,
path
,
strerror
(
errno
));
ret
=
fcntl
(
fd
,
F_SETLKW
,
&
lk
);
if
(
ret
<
0
)
{
usernic_error
(
"Failed to lock
\"
%s
\"
: %s
\n
"
,
path
,
strerror
(
errno
));
close
(
fd
);
close
(
fd
);
return
-
1
;
return
-
1
;
}
}
...
@@ -90,14 +99,13 @@ static int open_and_lock(char *path)
...
@@ -90,14 +99,13 @@ static int open_and_lock(char *path)
return
fd
;
return
fd
;
}
}
static
char
*
get_username
(
void
)
static
char
*
get_username
(
void
)
{
{
struct
passwd
*
pwd
;
struct
passwd
*
pwd
;
pwd
=
getpwuid
(
getuid
());
pwd
=
getpwuid
(
getuid
());
if
(
!
pwd
)
{
if
(
!
pwd
)
{
usernic_error
(
"Failed to
call get username: %s.
\n
"
,
strerror
(
errno
));
usernic_error
(
"Failed to
get username: %s
\n
"
,
strerror
(
errno
));
return
NULL
;
return
NULL
;
}
}
...
@@ -127,9 +135,8 @@ static char **get_groupnames(void)
...
@@ -127,9 +135,8 @@ static char **get_groupnames(void)
ngroups
=
getgroups
(
0
,
NULL
);
ngroups
=
getgroups
(
0
,
NULL
);
if
(
ngroups
<
0
)
{
if
(
ngroups
<
0
)
{
usernic_error
(
usernic_error
(
"Failed to get number of groups the user "
"Failed to get number of groups the user belongs to: %s.
\n
"
,
"belongs to: %s
\n
"
,
strerror
(
errno
));
strerror
(
errno
));
return
NULL
;
return
NULL
;
}
}
if
(
ngroups
==
0
)
if
(
ngroups
==
0
)
...
@@ -203,19 +210,21 @@ struct alloted_s {
...
@@ -203,19 +210,21 @@ struct alloted_s {
struct
alloted_s
*
next
;
struct
alloted_s
*
next
;
};
};
static
struct
alloted_s
*
append_alloted
(
struct
alloted_s
**
head
,
char
*
name
,
int
n
)
static
struct
alloted_s
*
append_alloted
(
struct
alloted_s
**
head
,
char
*
name
,
int
n
)
{
{
struct
alloted_s
*
cur
,
*
al
;
struct
alloted_s
*
cur
,
*
al
;
if
(
!
head
||
!
name
)
{
if
(
!
head
||
!
name
)
{
/
/ sanity check. parameters should not be null
/
* Sanity check. Parameters should not be null. */
usernic_error
(
"%s
\n
"
,
"Unexpected NULL argument
.
"
);
usernic_error
(
"%s
\n
"
,
"Unexpected NULL argument"
);
return
NULL
;
return
NULL
;
}
}
al
=
malloc
(
sizeof
(
struct
alloted_s
));
al
=
malloc
(
sizeof
(
struct
alloted_s
));
if
(
!
al
)
{
if
(
!
al
)
{
usernic_error
(
"Failed to allocate memory: %s.
\n
"
,
strerror
(
errno
));
usernic_error
(
"Failed to allocate memory: %s
\n
"
,
strerror
(
errno
));
return
NULL
;
return
NULL
;
}
}
...
@@ -266,7 +275,8 @@ static void free_alloted(struct alloted_s **head)
...
@@ -266,7 +275,8 @@ static void free_alloted(struct alloted_s **head)
* Return the count entry for the calling user if there is one. Else
* Return the count entry for the calling user if there is one. Else
* return -1.
* return -1.
*/
*/
static
int
get_alloted
(
char
*
me
,
char
*
intype
,
char
*
link
,
struct
alloted_s
**
alloted
)
static
int
get_alloted
(
char
*
me
,
char
*
intype
,
char
*
link
,
struct
alloted_s
**
alloted
)
{
{
int
n
,
ret
;
int
n
,
ret
;
char
name
[
100
],
type
[
100
],
br
[
100
];
char
name
[
100
],
type
[
100
],
br
[
100
];
...
@@ -279,13 +289,15 @@ static int get_alloted(char *me, char *intype, char *link, struct alloted_s **al
...
@@ -279,13 +289,15 @@ static int get_alloted(char *me, char *intype, char *link, struct alloted_s **al
fin
=
fopen
(
LXC_USERNIC_CONF
,
"r"
);
fin
=
fopen
(
LXC_USERNIC_CONF
,
"r"
);
if
(
!
fin
)
{
if
(
!
fin
)
{
usernic_error
(
"Failed to open
\"
%s
\"
: %s.
\n
"
,
LXC_USERNIC_CONF
,
strerror
(
errno
));
usernic_error
(
"Failed to open
\"
%s
\"
: %s
\n
"
,
LXC_USERNIC_CONF
,
strerror
(
errno
));
return
-
1
;
return
-
1
;
}
}
groups
=
get_groupnames
();
groups
=
get_groupnames
();
while
((
getline
(
&
line
,
&
len
,
fin
))
!=
-
1
)
{
while
((
getline
(
&
line
,
&
len
,
fin
))
!=
-
1
)
{
ret
=
sscanf
(
line
,
"%99[^
\t
] %99[^
\t
] %99[^
\t
] %d"
,
name
,
type
,
br
,
&
n
);
ret
=
sscanf
(
line
,
"%99[^
\t
] %99[^
\t
] %99[^
\t
] %d"
,
name
,
type
,
br
,
&
n
);
if
(
ret
!=
4
)
if
(
ret
!=
4
)
continue
;
continue
;
...
@@ -358,7 +370,8 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
...
@@ -358,7 +370,8 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
p
++
;
p
++
;
p2
=
get_eow
(
p
,
e
);
p2
=
get_eow
(
p
,
e
);
if
(
!
p2
||
((
size_t
)(
p2
-
p
))
!=
strlen
(
u
)
||
strncmp
(
p
,
u
,
strlen
(
u
)))
if
(
!
p2
||
((
size_t
)(
p2
-
p
))
!=
strlen
(
u
)
||
strncmp
(
p
,
u
,
strlen
(
u
)))
goto
next
;
goto
next
;
p
=
p2
+
1
;
p
=
p2
+
1
;
...
@@ -366,7 +379,8 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
...
@@ -366,7 +379,8 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
p
++
;
p
++
;
p2
=
get_eow
(
p
,
e
);
p2
=
get_eow
(
p
,
e
);
if
(
!
p2
||
((
size_t
)(
p2
-
p
))
!=
strlen
(
t
)
||
strncmp
(
p
,
t
,
strlen
(
t
)))
if
(
!
p2
||
((
size_t
)(
p2
-
p
))
!=
strlen
(
t
)
||
strncmp
(
p
,
t
,
strlen
(
t
)))
goto
next
;
goto
next
;
p
=
p2
+
1
;
p
=
p2
+
1
;
...
@@ -374,11 +388,12 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
...
@@ -374,11 +388,12 @@ static char *find_line(char *p, char *e, char *u, char *t, char *l)
p
++
;
p
++
;
p2
=
get_eow
(
p
,
e
);
p2
=
get_eow
(
p
,
e
);
if
(
!
p2
||
((
size_t
)(
p2
-
p
))
!=
strlen
(
l
)
||
strncmp
(
p
,
l
,
strlen
(
l
)))
if
(
!
p2
||
((
size_t
)(
p2
-
p
))
!=
strlen
(
l
)
||
strncmp
(
p
,
l
,
strlen
(
l
)))
goto
next
;
goto
next
;
return
ret
;
return
ret
;
next:
next:
p
=
p1
+
1
;
p
=
p1
+
1
;
}
}
...
@@ -417,7 +432,8 @@ static int instantiate_veth(char *n1, char **n2)
...
@@ -417,7 +432,8 @@ static int instantiate_veth(char *n1, char **n2)
err
=
lxc_veth_create
(
n1
,
*
n2
);
err
=
lxc_veth_create
(
n1
,
*
n2
);
if
(
err
)
{
if
(
err
)
{
usernic_error
(
"Failed to create %s-%s : %s.
\n
"
,
n1
,
*
n2
,
strerror
(
-
err
));
usernic_error
(
"Failed to create %s-%s : %s.
\n
"
,
n1
,
*
n2
,
strerror
(
-
err
));
return
-
1
;
return
-
1
;
}
}
...
@@ -427,8 +443,7 @@ static int instantiate_veth(char *n1, char **n2)
...
@@ -427,8 +443,7 @@ static int instantiate_veth(char *n1, char **n2)
err
=
setup_private_host_hw_addr
(
n1
);
err
=
setup_private_host_hw_addr
(
n1
);
if
(
err
)
if
(
err
)
usernic_error
(
"Failed to change mac address of host interface "
usernic_error
(
"Failed to change mac address of host interface "
"%s : %s.
\n
"
,
"%s : %s
\n
"
,
n1
,
strerror
(
-
err
));
n1
,
strerror
(
-
err
));
return
netdev_set_flag
(
n1
,
IFF_UP
);
return
netdev_set_flag
(
n1
,
IFF_UP
);
}
}
...
@@ -471,19 +486,21 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
...
@@ -471,19 +486,21 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
if
(
mtu
>
0
)
{
if
(
mtu
>
0
)
{
ret
=
lxc_netdev_set_mtu
(
veth1buf
,
mtu
);
ret
=
lxc_netdev_set_mtu
(
veth1buf
,
mtu
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
usernic_error
(
"Failed to set mtu to %d on %s.
\n
"
,
mtu
,
veth1buf
);
usernic_error
(
"Failed to set mtu to %d on %s
\n
"
,
mtu
,
veth1buf
);
goto
out_del
;
goto
out_del
;
}
}
ret
=
lxc_netdev_set_mtu
(
veth2buf
,
mtu
);
ret
=
lxc_netdev_set_mtu
(
veth2buf
,
mtu
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
usernic_error
(
"Failed to set mtu to %d on %s.
\n
"
,
mtu
,
veth2buf
);
usernic_error
(
"Failed to set mtu to %d on %s
\n
"
,
mtu
,
veth2buf
);
goto
out_del
;
goto
out_del
;
}
}
}
}
/* attach veth1 to bridge */
/* attach veth1 to bridge */
ret
=
lxc_bridge_attach
(
lxcpath
,
lxcname
,
br
,
veth1buf
);
ret
=
lxc_bridge_attach
(
br
,
veth1buf
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
usernic_error
(
"Error attaching %s to %s.
\n
"
,
veth1buf
,
br
);
usernic_error
(
"Error attaching %s to %s.
\n
"
,
veth1buf
,
br
);
goto
out_del
;
goto
out_del
;
...
@@ -493,7 +510,8 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
...
@@ -493,7 +510,8 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
/* pass veth2 to target netns */
/* pass veth2 to target netns */
ret
=
lxc_netdev_move_by_name
(
veth2buf
,
pid
,
NULL
);
ret
=
lxc_netdev_move_by_name
(
veth2buf
,
pid
,
NULL
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
usernic_error
(
"Error moving %s to network namespace of %d.
\n
"
,
veth2buf
,
pid
);
usernic_error
(
"Error moving %s to network namespace of %d
\n
"
,
veth2buf
,
pid
);
goto
out_del
;
goto
out_del
;
}
}
...
@@ -510,25 +528,29 @@ out_del:
...
@@ -510,25 +528,29 @@ out_del:
return
false
;
return
false
;
}
}
/*
/* get_new_nicname() will return the name (vethXXXXXX) which is attached on the
* Get a new nic.
* host to the lxc bridge. The returned string must be freed by caller.
* *dest will contain the name (vethXXXXXX) which is attached
* on the host to the lxc bridge
*/
*/
static
bool
get_new_nicname
(
char
**
dest
,
char
*
br
,
int
pid
,
char
**
cnic
)
static
char
*
get_new_nicname
(
char
*
br
,
int
pid
,
char
**
cnic
)
{
{
int
ret
;
int
ret
;
char
*
nicname
;
char
template
[
IFNAMSIZ
];
char
template
[
IFNAMSIZ
];
ret
=
snprintf
(
template
,
sizeof
(
template
),
"vethXXXXXX"
);
ret
=
snprintf
(
template
,
sizeof
(
template
),
"vethXXXXXX"
);
if
(
ret
<
0
||
(
size_t
)
ret
>=
sizeof
(
template
))
if
(
ret
<
0
||
(
size_t
)
ret
>=
sizeof
(
template
))
return
false
;
return
NULL
;
*
dest
=
lxc_mkifname
(
template
);
nicname
=
lxc_mkifname
(
template
);
if
(
!
create_nic
(
*
dest
,
br
,
pid
,
cnic
)
)
if
(
!
nicname
)
return
false
;
return
NULL
;
return
true
;
if
(
!
create_nic
(
nicname
,
br
,
pid
,
cnic
))
{
free
(
nicname
);
return
NULL
;
}
return
nicname
;
}
}
static
bool
get_nic_from_line
(
char
*
p
,
char
**
nic
)
static
bool
get_nic_from_line
(
char
*
p
,
char
**
nic
)
...
@@ -536,7 +558,8 @@ static bool get_nic_from_line(char *p, char **nic)
...
@@ -536,7 +558,8 @@ static bool get_nic_from_line(char *p, char **nic)
int
ret
;
int
ret
;
char
user
[
100
],
type
[
100
],
br
[
100
];
char
user
[
100
],
type
[
100
],
br
[
100
];
ret
=
sscanf
(
p
,
"%99[^
\t\n
] %99[^
\t\n
] %99[^
\t\n
] %99[^
\t\n
]"
,
user
,
type
,
br
,
*
nic
);
ret
=
sscanf
(
p
,
"%99[^
\t\n
] %99[^
\t\n
] %99[^
\t\n
] %99[^
\t\n
]"
,
user
,
type
,
br
,
*
nic
);
if
(
ret
!=
4
)
if
(
ret
!=
4
)
return
false
;
return
false
;
...
@@ -549,20 +572,23 @@ struct entry_line {
...
@@ -549,20 +572,23 @@ struct entry_line {
bool
keep
;
bool
keep
;
};
};
static
bool
cull_entries
(
int
fd
,
char
*
me
,
char
*
t
,
char
*
br
)
static
bool
cull_entries
(
int
fd
,
char
*
me
,
char
*
t
,
char
*
br
,
char
*
nicname
,
bool
*
found_nicname
)
{
{
int
i
,
n
=
0
;
int
i
,
ret
;
off_t
len
;
off_t
len
;
char
*
buf
,
*
p
,
*
e
,
*
nic
;
char
*
buf
,
*
e
,
*
nic
,
*
p
;
struct
stat
sb
;
struct
stat
sb
;
int
n
=
0
;
struct
entry_line
*
entry_lines
=
NULL
;
struct
entry_line
*
entry_lines
=
NULL
;
nic
=
alloca
(
100
);
nic
=
alloca
(
100
);
if
(
!
nic
)
if
(
!
nic
)
return
false
;
return
false
;
if
(
fstat
(
fd
,
&
sb
)
<
0
)
{
ret
=
fstat
(
fd
,
&
sb
);
usernic_error
(
"Failed to fstat: %s.
\n
"
,
strerror
(
errno
));
if
(
ret
<
0
)
{
usernic_error
(
"Failed to fstat: %s
\n
"
,
strerror
(
errno
));
return
false
;
return
false
;
}
}
...
@@ -570,9 +596,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
...
@@ -570,9 +596,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
if
(
len
==
0
)
if
(
len
==
0
)
return
true
;
return
true
;
buf
=
mmap
(
NULL
,
len
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
buf
=
lxc_strmmap
(
NULL
,
sb
.
st_size
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
if
(
buf
==
MAP_FAILED
)
{
if
(
buf
==
MAP_FAILED
)
{
usernic_error
(
"Failed to establish shared memory mapping: %s.
\n
"
,
strerror
(
errno
));
usernic_error
(
"Failed to establish shared memory mapping: %s
\n
"
,
strerror
(
errno
));
return
false
;
return
false
;
}
}
...
@@ -598,6 +625,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
...
@@ -598,6 +625,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
if
(
nic
&&
!
nic_exists
(
nic
))
if
(
nic
&&
!
nic_exists
(
nic
))
entry_lines
[
n
-
1
].
keep
=
false
;
entry_lines
[
n
-
1
].
keep
=
false
;
if
(
nicname
)
if
(
!
strcmp
(
nic
,
nicname
))
*
found_nicname
=
true
;
p
+=
entry_lines
[
n
-
1
].
len
+
1
;
p
+=
entry_lines
[
n
-
1
].
len
+
1
;
if
(
p
>=
e
)
if
(
p
>=
e
)
break
;
break
;
...
@@ -615,9 +646,11 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
...
@@ -615,9 +646,11 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
}
}
free
(
entry_lines
);
free
(
entry_lines
);
munmap
(
buf
,
sb
.
st_size
);
lxc_strmunmap
(
buf
,
sb
.
st_size
);
if
(
ftruncate
(
fd
,
p
-
buf
))
ret
=
ftruncate
(
fd
,
p
-
buf
);
usernic_error
(
"Failed to set new file size: %s.
\n
"
,
strerror
(
errno
));
if
(
ret
<
0
)
usernic_error
(
"Failed to set new file size: %s
\n
"
,
strerror
(
errno
));
return
true
;
return
true
;
}
}
...
@@ -638,41 +671,39 @@ static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
...
@@ -638,41 +671,39 @@ static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
return
count
;
return
count
;
}
}
/*
/* The dbfile has lines of the format: user type bridge nicname. */
* The dbfile has lines of the format:
static
char
*
get_nic_if_avail
(
int
fd
,
struct
alloted_s
*
names
,
int
pid
,
* user type bridge nicname
char
*
intype
,
char
*
br
,
int
allowed
,
char
**
cnic
)
*/
static
bool
get_nic_if_avail
(
int
fd
,
struct
alloted_s
*
names
,
int
pid
,
char
*
intype
,
char
*
br
,
int
allowed
,
char
**
nicname
,
char
**
cnic
)
{
{
int
ret
;
int
ret
;
off_t
len
,
slen
;
off_t
len
,
slen
;
char
*
newline
,
*
owner
;
char
*
newline
,
*
nicname
,
*
owner
;
struct
stat
sb
;
struct
stat
sb
;
struct
alloted_s
*
n
;
struct
alloted_s
*
n
;
int
count
=
0
;
int
count
=
0
;
char
*
buf
=
NULL
;
char
*
buf
=
NULL
;
for
(
n
=
names
;
n
!=
NULL
;
n
=
n
->
next
)
for
(
n
=
names
;
n
!=
NULL
;
n
=
n
->
next
)
cull_entries
(
fd
,
n
->
name
,
intype
,
br
);
cull_entries
(
fd
,
n
->
name
,
intype
,
br
,
NULL
,
NULL
);
if
(
allowed
==
0
)
if
(
allowed
==
0
)
return
false
;
return
NULL
;
owner
=
names
->
name
;
owner
=
names
->
name
;
if
(
fstat
(
fd
,
&
sb
)
<
0
)
{
if
(
fstat
(
fd
,
&
sb
)
<
0
)
{
usernic_error
(
"Failed to fstat: %s
.
\n
"
,
strerror
(
errno
));
usernic_error
(
"Failed to fstat: %s
\n
"
,
strerror
(
errno
));
return
false
;
return
NULL
;
}
}
len
=
sb
.
st_size
;
len
=
sb
.
st_size
;
if
(
len
>
0
)
{
if
(
len
>
0
)
{
buf
=
mmap
(
NULL
,
len
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
buf
=
mmap
(
NULL
,
len
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
if
(
buf
==
MAP_FAILED
)
{
if
(
buf
==
MAP_FAILED
)
{
usernic_error
(
"Failed to establish shared memory mapping: %s.
\n
"
,
strerror
(
errno
));
usernic_error
(
"Failed to establish shared memory mapping: %s
\n
"
,
return
false
;
strerror
(
errno
));
return
NULL
;
}
}
owner
=
NULL
;
owner
=
NULL
;
...
@@ -688,47 +719,56 @@ static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid,
...
@@ -688,47 +719,56 @@ static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid,
}
}
if
(
owner
==
NULL
)
if
(
owner
==
NULL
)
return
false
;
return
NULL
;
if
(
!
get_new_nicname
(
nicname
,
br
,
pid
,
cnic
))
nicname
=
get_new_nicname
(
br
,
pid
,
cnic
);
return
false
;
if
(
!
nicname
)
{
usernic_error
(
"%s"
,
"Failed to get new nic name
\n
"
);
return
NULL
;
}
/* owner ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
/* owner ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
slen
=
strlen
(
owner
)
+
strlen
(
intype
)
+
strlen
(
br
)
+
strlen
(
*
nicname
)
+
5
;
slen
=
strlen
(
owner
)
+
strlen
(
intype
)
+
strlen
(
br
)
+
strlen
(
nicname
)
+
5
;
newline
=
alloca
(
slen
);
newline
=
alloca
(
slen
);
if
(
!
newline
)
{
if
(
!
newline
)
{
usernic_error
(
"Failed allocate memory: %s.
\n
"
,
strerror
(
errno
));
free
(
nicname
);
return
false
;
usernic_error
(
"Failed allocate memory: %s
\n
"
,
strerror
(
errno
));
return
NULL
;
}
}
ret
=
snprintf
(
newline
,
slen
,
"%s %s %s %s
\n
"
,
owner
,
intype
,
br
,
*
nicname
);
ret
=
snprintf
(
newline
,
slen
,
"%s %s %s %s
\n
"
,
owner
,
intype
,
br
,
nicname
);
if
(
ret
<
0
||
ret
>=
slen
)
{
if
(
ret
<
0
||
ret
>=
slen
)
{
if
(
lxc_netdev_delete_by_name
(
*
nicname
)
!=
0
)
if
(
lxc_netdev_delete_by_name
(
nicname
)
!=
0
)
usernic_error
(
"Error unlinking %s.
\n
"
,
*
nicname
);
usernic_error
(
"Error unlinking %s
\n
"
,
nicname
);
return
false
;
free
(
nicname
);
return
NULL
;
}
}
if
(
len
)
if
(
len
)
munmap
(
buf
,
len
);
munmap
(
buf
,
len
);
if
(
ftruncate
(
fd
,
len
+
slen
))
if
(
ftruncate
(
fd
,
len
+
slen
))
usernic_error
(
"Failed to set new file size: %s.
\n
"
,
strerror
(
errno
));
usernic_error
(
"Failed to set new file size: %s
\n
"
,
strerror
(
errno
));
buf
=
mmap
(
NULL
,
len
+
slen
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
buf
=
mmap
(
NULL
,
len
+
slen
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0
);
if
(
buf
==
MAP_FAILED
)
{
if
(
buf
==
MAP_FAILED
)
{
usernic_error
(
"Failed to establish shared memory mapping: %s.
\n
"
,
strerror
(
errno
));
usernic_error
(
"Failed to establish shared memory mapping: %s
\n
"
,
if
(
lxc_netdev_delete_by_name
(
*
nicname
)
!=
0
)
strerror
(
errno
));
usernic_error
(
"Error unlinking %s.
\n
"
,
*
nicname
);
if
(
lxc_netdev_delete_by_name
(
nicname
)
!=
0
)
return
false
;
usernic_error
(
"Error unlinking %s
\n
"
,
nicname
);
free
(
nicname
);
return
NULL
;
}
}
strcpy
(
buf
+
len
,
newline
);
strcpy
(
buf
+
len
,
newline
);
munmap
(
buf
,
len
+
slen
);
munmap
(
buf
,
len
+
slen
);
return
tru
e
;
return
nicnam
e
;
}
}
static
bool
create_db_dir
(
char
*
fnam
)
static
bool
create_db_dir
(
char
*
fnam
)
{
{
int
ret
;
char
*
p
;
char
*
p
;
p
=
alloca
(
strlen
(
fnam
)
+
1
);
p
=
alloca
(
strlen
(
fnam
)
+
1
);
...
@@ -743,8 +783,11 @@ again:
...
@@ -743,8 +783,11 @@ again:
return
true
;
return
true
;
*
p
=
'\0'
;
*
p
=
'\0'
;
if
(
mkdir
(
fnam
,
0755
)
&&
errno
!=
EEXIST
)
{
usernic_error
(
"Failed to create %s: %s.
\n
"
,
fnam
,
strerror
(
errno
));
ret
=
mkdir
(
fnam
,
0755
);
if
(
ret
<
0
&&
errno
!=
EEXIST
)
{
usernic_error
(
"Failed to create %s: %s
\n
"
,
fnam
,
strerror
(
errno
));
*
p
=
'/'
;
*
p
=
'/'
;
return
false
;
return
false
;
}
}
...
@@ -753,18 +796,19 @@ again:
...
@@ -753,18 +796,19 @@ again:
goto
again
;
goto
again
;
}
}
#define VETH_DEF_NAME "eth%d"
static
char
*
lxc_secure_rename_in_ns
(
int
pid
,
char
*
oldname
,
char
*
newname
,
static
int
rename_in_ns
(
int
pid
,
char
*
oldname
,
char
**
newnamep
)
int
*
ifidx
)
{
{
int
ret
;
uid_t
ruid
,
suid
,
euid
;
uid_t
ruid
,
suid
,
euid
;
int
fret
=
-
1
;
char
ifname
[
IFNAMSIZ
]
;
int
fd
=
-
1
,
ifindex
=
-
1
,
ofd
=
-
1
,
ret
;
char
*
string_ret
=
NULL
,
*
name
=
NULL
;
bool
grab_newname
=
false
;
int
fd
=
-
1
,
ifindex
=
-
1
,
ofd
=
-
1
;
ofd
=
lxc_preserve_ns
(
getpid
(),
"net"
);
ofd
=
lxc_preserve_ns
(
getpid
(),
"net"
);
if
(
ofd
<
0
)
{
if
(
ofd
<
0
)
{
usernic_error
(
"Failed opening network namespace path for
'%d'.
"
,
getpid
());
usernic_error
(
"Failed opening network namespace path for
%d
"
,
getpid
());
return
fret
;
return
NULL
;
}
}
fd
=
lxc_preserve_ns
(
pid
,
"net"
);
fd
=
lxc_preserve_ns
(
pid
,
"net"
);
...
@@ -803,66 +847,70 @@ static int rename_in_ns(int pid, char *oldname, char **newnamep)
...
@@ -803,66 +847,70 @@ static int rename_in_ns(int pid, char *oldname, char **newnamep)
goto
do_full_cleanup
;
goto
do_full_cleanup
;
}
}
if
(
!*
newnamep
)
{
/* Check if old interface exists. */
grab_newname
=
true
;
ifindex
=
if_nametoindex
(
oldname
);
*
newnamep
=
VETH_DEF_NAME
;
if
(
!
ifindex
)
{
usernic_error
(
"Failed to get netdev index: %s
\n
"
,
strerror
(
errno
));
ifindex
=
if_nametoindex
(
oldname
);
goto
do_full_cleanup
;
if
(
!
ifindex
)
{
usernic_error
(
"Failed to get netdev index: %s.
\n
"
,
strerror
(
errno
));
goto
do_full_cleanup
;
}
}
}
ret
=
lxc_netdev_rename_by_name
(
oldname
,
*
newnamep
);
/* When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
* netlink will replace the format specifier with an appropriate index.
* So we pass "eth%d".
*/
if
(
newname
)
name
=
newname
;
else
name
=
"eth%d"
;
ret
=
lxc_netdev_rename_by_name
(
oldname
,
name
);
name
=
NULL
;
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
usernic_error
(
"Error %d renaming netdev %s to %s in container.
\n
"
,
ret
,
oldname
,
*
newnamep
);
usernic_error
(
"Error %d renaming netdev %s to %s in container
\n
"
,
ret
,
oldname
,
newname
?
newname
:
"eth%d"
);
goto
do_full_cleanup
;
goto
do_full_cleanup
;
}
}
if
(
grab_newname
)
{
/* Retrieve new name for interface. */
char
ifname
[
IFNAMSIZ
];
if
(
!
if_indextoname
(
ifindex
,
ifname
))
{
char
*
namep
=
ifname
;
usernic_error
(
"Failed to get new netdev name: %s
\n
"
,
strerror
(
errno
));
goto
do_full_cleanup
;
if
(
!
if_indextoname
(
ifindex
,
namep
))
{
usernic_error
(
"Failed to get new netdev name: %s.
\n
"
,
strerror
(
errno
));
goto
do_full_cleanup
;
}
*
newnamep
=
strdup
(
namep
);
if
(
!*
newnamep
)
goto
do_full_cleanup
;
}
}
fret
=
0
;
/* Allocation failure for strdup() is checked below. */
name
=
strdup
(
ifname
);
string_ret
=
name
;
*
ifidx
=
ifindex
;
do_full_cleanup:
do_full_cleanup:
ret
=
setresuid
(
ruid
,
euid
,
suid
);
ret
=
setresuid
(
ruid
,
euid
,
suid
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
usernic_error
(
"Failed to restore privilege by setting effective "
usernic_error
(
"Failed to restore privilege by setting "
"user id to %d, real user id to %d, and saved user "
"effective user id to %d, real user id to %d, "
"ID to %d: %s.
\n
"
,
"and saved user ID to %d: %s
\n
"
,
ruid
,
euid
,
suid
,
ruid
,
euid
,
suid
,
strerror
(
errno
));
strerror
(
errno
));
fret
=
-
1
;
// COMMENT(brauner): setns() should fail if setresuid() doesn't
string_ret
=
NULL
;
// succeed but there's no harm in falling through; keeps the
// code cleaner.
}
}
ret
=
setns
(
ofd
,
CLONE_NEWNET
);
ret
=
setns
(
ofd
,
CLONE_NEWNET
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
usernic_error
(
"Failed to setns() to original network namespace "
usernic_error
(
"Failed to setns() to original network namespace "
"of PID %d: %s
.
\n
"
,
"of PID %d: %s
\n
"
,
ofd
,
strerror
(
errno
));
ofd
,
strerror
(
errno
));
fret
=
-
1
;
string_ret
=
NULL
;
}
}
do_partial_cleanup:
do_partial_cleanup:
if
(
fd
>=
0
)
if
(
fd
>=
0
)
close
(
fd
);
close
(
fd
);
if
(
!
string_ret
&&
name
)
free
(
name
);
close
(
ofd
);
close
(
ofd
);
return
f
ret
;
return
string_
ret
;
}
}
/*
/*
...
@@ -916,50 +964,73 @@ static bool may_access_netns(int pid)
...
@@ -916,50 +964,73 @@ static bool may_access_netns(int pid)
return
may_access
;
return
may_access
;
}
}
struct
user_nic_args
{
char
*
cmd
;
char
*
lxc_path
;
char
*
lxc_name
;
char
*
pid
;
char
*
type
;
char
*
link
;
char
*
veth_name
;
};
#define LXC_USERNIC_CREATE 0
#define LXC_USERNIC_DELETE 1
int
main
(
int
argc
,
char
*
argv
[])
int
main
(
int
argc
,
char
*
argv
[])
{
{
int
n
,
fd
;
int
fd
,
ifindex
,
n
,
pid
,
request
,
ret
;
char
*
me
;
char
*
me
,
*
newname
;
char
*
nicname
;
char
*
cnic
=
NULL
,
*
nicname
=
NULL
;
int
pid
;
char
*
cnic
=
NULL
;
/* Created nic name in container is returned here. */
char
*
vethname
=
NULL
;
bool
gotone
=
false
;
struct
alloted_s
*
alloted
=
NULL
;
struct
alloted_s
*
alloted
=
NULL
;
struct
user_nic_args
args
;
nicname
=
alloca
(
40
);
if
(
argc
<
7
||
argc
>
8
)
{
if
(
!
nicname
)
{
usage
(
argv
[
0
],
true
);
usernic_error
(
"Failed allocate memory: %s.
\n
"
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
/* set a sane env, because we are setuid-root */
memset
(
&
args
,
0
,
sizeof
(
struct
user_nic_args
));
if
(
clearenv
()
<
0
)
{
args
.
cmd
=
argv
[
1
];
usernic_error
(
"%s"
,
"Failed to clear environment.
\n
"
);
args
.
lxc_path
=
argv
[
2
];
args
.
lxc_name
=
argv
[
3
];
args
.
pid
=
argv
[
4
];
args
.
type
=
argv
[
5
];
args
.
link
=
argv
[
6
];
if
(
argc
>=
8
)
args
.
veth_name
=
argv
[
7
];
if
(
!
strcmp
(
args
.
cmd
,
"create"
))
{
request
=
LXC_USERNIC_CREATE
;
}
else
if
(
!
strcmp
(
args
.
cmd
,
"delete"
))
{
request
=
LXC_USERNIC_DELETE
;
}
else
{
usage
(
argv
[
0
],
true
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
if
(
setenv
(
"PATH"
,
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
,
1
)
<
0
)
{
usernic_error
(
"%s"
,
"Failed to set PATH, exiting.
\n
"
);
/* Set a sane env, because we are setuid-root. */
ret
=
clearenv
();
if
(
ret
)
{
usernic_error
(
"%s"
,
"Failed to clear environment
\n
"
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
if
((
me
=
get_username
())
==
NULL
)
{
usernic_error
(
"%s"
,
"Failed to get username.
\n
"
);
ret
=
setenv
(
"PATH"
,
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
,
1
);
if
(
ret
<
0
)
{
usernic_error
(
"%s"
,
"Failed to set PATH, exiting
\n
"
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
if
(
argc
<
6
)
me
=
get_username
();
usage
(
argv
[
0
],
true
);
if
(
!
me
)
{
usernic_error
(
"%s"
,
"Failed to get username
\n
"
);
if
(
argc
>=
7
)
exit
(
EXIT_FAILURE
);
vethname
=
argv
[
6
];
}
lxcpath
=
argv
[
1
];
lxcname
=
argv
[
2
];
errno
=
0
;
ret
=
lxc_safe_int
(
args
.
pid
,
&
pid
);
pid
=
strtol
(
argv
[
3
],
NULL
,
10
);
if
(
ret
<
0
)
{
if
(
errno
)
{
usernic_error
(
"Could not read pid: %s
\n
"
,
args
.
pid
);
usernic_error
(
"Could not read pid: %s.
\n
"
,
argv
[
1
]);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
...
@@ -968,8 +1039,9 @@ int main(int argc, char *argv[])
...
@@ -968,8 +1039,9 @@ int main(int argc, char *argv[])
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
if
((
fd
=
open_and_lock
(
LXC_USERNIC_DB
))
<
0
)
{
fd
=
open_and_lock
(
LXC_USERNIC_DB
);
usernic_error
(
"Failed to lock %s.
\n
"
,
LXC_USERNIC_DB
);
if
(
fd
<
0
)
{
usernic_error
(
"Failed to lock %s
\n
"
,
LXC_USERNIC_DB
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
...
@@ -978,28 +1050,74 @@ int main(int argc, char *argv[])
...
@@ -978,28 +1050,74 @@ int main(int argc, char *argv[])
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
n
=
get_alloted
(
me
,
argv
[
4
],
argv
[
5
],
&
alloted
);
n
=
get_alloted
(
me
,
args
.
type
,
args
.
link
,
&
alloted
);
if
(
request
==
LXC_USERNIC_DELETE
)
{
int
ret
;
struct
alloted_s
*
it
;
bool
found_nicname
=
false
;
if
(
!
is_ovs_bridge
(
args
.
link
))
{
usernic_error
(
"%s"
,
"Deletion of non ovs type network "
"devices not implemented
\n
"
);
close
(
fd
);
free_alloted
(
&
alloted
);
exit
(
EXIT_FAILURE
);
}
/* Check whether the network device we are supposed to delete
* exists in the db. If it doesn't we will not delete it as we
* need to assume the network device is not under our control.
* As a side effect we also clear any invalid entries from the
* database.
*/
for
(
it
=
alloted
;
it
;
it
=
it
->
next
)
cull_entries
(
fd
,
it
->
name
,
args
.
type
,
args
.
link
,
args
.
veth_name
,
&
found_nicname
);
close
(
fd
);
free_alloted
(
&
alloted
);
if
(
!
found_nicname
)
{
usernic_error
(
"%s"
,
"Caller is not allowed to delete "
"network device
\n
"
);
exit
(
EXIT_FAILURE
);
}
ret
=
lxc_ovs_delete_port
(
args
.
link
,
args
.
veth_name
);
if
(
ret
<
0
)
{
usernic_error
(
"Failed to remove port
\"
%s
\"
from "
"openvswitch bridge
\"
%s
\"
"
,
args
.
veth_name
,
args
.
link
);
exit
(
EXIT_FAILURE
);
}
exit
(
EXIT_SUCCESS
);
}
if
(
n
>
0
)
if
(
n
>
0
)
gotone
=
get_nic_if_avail
(
fd
,
alloted
,
pid
,
argv
[
4
],
argv
[
5
],
n
,
&
nicname
,
&
cnic
);
nicname
=
get_nic_if_avail
(
fd
,
alloted
,
pid
,
args
.
type
,
args
.
link
,
n
,
&
cnic
);
close
(
fd
);
close
(
fd
);
free_alloted
(
&
alloted
);
free_alloted
(
&
alloted
);
if
(
!
goton
e
)
{
if
(
!
nicnam
e
)
{
usernic_error
(
"%s"
,
"Quota reached
.
\n
"
);
usernic_error
(
"%s"
,
"Quota reached
\n
"
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
/* Now rename the link. */
/* Now rename the link. */
if
(
rename_in_ns
(
pid
,
cnic
,
&
vethname
)
<
0
)
{
newname
=
lxc_secure_rename_in_ns
(
pid
,
cnic
,
args
.
veth_name
,
&
ifindex
);
usernic_error
(
"%s"
,
"Failed to rename the link.
\n
"
);
if
(
!
newname
)
{
if
(
lxc_netdev_delete_by_name
(
cnic
)
<
0
)
usernic_error
(
"%s"
,
"Failed to rename the link
\n
"
);
usernic_error
(
"Failed to delete link
\"
%s
\"
the link. Manual cleanup needed.
\n
"
,
cnic
);
ret
=
lxc_netdev_delete_by_name
(
cnic
);
if
(
ret
<
0
)
usernic_error
(
"Failed to delete
\"
%s
\"\n
"
,
cnic
);
free
(
nicname
);
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
}
}
/* Write the name of the interface pair to the stdout
- like
/* Write the name of the interface pair to the stdout
: eth0:veth9MT2L4 */
* eth0:veth9MT2L4.
fprintf
(
stdout
,
"%s:%s:%d
\n
"
,
newname
,
nicname
,
ifindex
);
*/
free
(
newname
);
f
printf
(
stdout
,
"%s:%s
\n
"
,
vethname
,
nicname
);
f
ree
(
nicname
);
exit
(
EXIT_SUCCESS
);
exit
(
EXIT_SUCCESS
);
}
}
src/lxc/network.c
View file @
d3e7b8ad
...
@@ -21,8 +21,7 @@
...
@@ -21,8 +21,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
*/
#include "config.h"
#define _GNU_SOURCE
#include <ctype.h>
#include <ctype.h>
#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <fcntl.h>
...
@@ -47,6 +46,8 @@
...
@@ -47,6 +46,8 @@
#include <sys/types.h>
#include <sys/types.h>
#include "conf.h"
#include "conf.h"
#include "config.h"
#include "confile_utils.h"
#include "log.h"
#include "log.h"
#include "network.h"
#include "network.h"
#include "nl.h"
#include "nl.h"
...
@@ -92,7 +93,356 @@
...
@@ -92,7 +93,356 @@
lxc_log_define
(
lxc_network
,
lxc
);
lxc_log_define
(
lxc_network
,
lxc
);
int
lxc_netdev_move_by_index
(
int
ifindex
,
pid_t
pid
,
const
char
*
ifname
)
typedef
int
(
*
instantiate_cb
)(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
static
int
instantiate_veth
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
int
bridge_index
,
err
;
char
*
veth1
,
*
veth2
;
char
veth1buf
[
IFNAMSIZ
],
veth2buf
[
IFNAMSIZ
];
unsigned
int
mtu
=
0
;
if
(
netdev
->
priv
.
veth_attr
.
pair
)
{
veth1
=
netdev
->
priv
.
veth_attr
.
pair
;
if
(
handler
->
conf
->
reboot
)
lxc_netdev_delete_by_name
(
veth1
);
}
else
{
err
=
snprintf
(
veth1buf
,
sizeof
(
veth1buf
),
"vethXXXXXX"
);
if
(
err
<
0
||
(
size_t
)
err
>=
sizeof
(
veth1buf
))
return
-
1
;
veth1
=
lxc_mkifname
(
veth1buf
);
if
(
!
veth1
)
return
-
1
;
/* store away for deconf */
memcpy
(
netdev
->
priv
.
veth_attr
.
veth1
,
veth1
,
IFNAMSIZ
);
}
snprintf
(
veth2buf
,
sizeof
(
veth2buf
),
"vethXXXXXX"
);
veth2
=
lxc_mkifname
(
veth2buf
);
if
(
!
veth2
)
goto
out_delete
;
err
=
lxc_veth_create
(
veth1
,
veth2
);
if
(
err
)
{
ERROR
(
"Failed to create veth pair
\"
%s
\"
and
\"
%s
\"
: %s"
,
veth1
,
veth2
,
strerror
(
-
err
));
goto
out_delete
;
}
/* changing the high byte of the mac address to 0xfe, the bridge interface
* will always keep the host's mac address and not take the mac address
* of a container */
err
=
setup_private_host_hw_addr
(
veth1
);
if
(
err
)
{
ERROR
(
"Failed to change mac address of host interface
\"
%s
\"
: %s"
,
veth1
,
strerror
(
-
err
));
goto
out_delete
;
}
netdev
->
ifindex
=
if_nametoindex
(
veth2
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"Failed to retrieve ifindex for
\"
%s
\"
"
,
veth2
);
goto
out_delete
;
}
if
(
netdev
->
mtu
)
{
if
(
lxc_safe_uint
(
netdev
->
mtu
,
&
mtu
)
<
0
)
WARN
(
"Failed to parse mtu"
);
else
INFO
(
"Retrieved mtu %d"
,
mtu
);
}
else
if
(
netdev
->
link
)
{
bridge_index
=
if_nametoindex
(
netdev
->
link
);
if
(
bridge_index
)
{
mtu
=
netdev_get_mtu
(
bridge_index
);
INFO
(
"Retrieved mtu %d from %s"
,
mtu
,
netdev
->
link
);
}
else
{
mtu
=
netdev_get_mtu
(
netdev
->
ifindex
);
INFO
(
"Retrieved mtu %d from %s"
,
mtu
,
veth2
);
}
}
if
(
mtu
)
{
err
=
lxc_netdev_set_mtu
(
veth1
,
mtu
);
if
(
!
err
)
err
=
lxc_netdev_set_mtu
(
veth2
,
mtu
);
if
(
err
)
{
ERROR
(
"Failed to set mtu
\"
%d
\"
for veth pair
\"
%s
\"
"
"and
\"
%s
\"
: %s"
,
mtu
,
veth1
,
veth2
,
strerror
(
-
err
));
goto
out_delete
;
}
}
if
(
netdev
->
link
)
{
err
=
lxc_bridge_attach
(
netdev
->
link
,
veth1
);
if
(
err
)
{
ERROR
(
"Failed to attach
\"
%s
\"
to bridge
\"
%s
\"
: %s"
,
veth1
,
netdev
->
link
,
strerror
(
-
err
));
goto
out_delete
;
}
INFO
(
"Attached
\"
%s
\"
to bridge
\"
%s
\"
"
,
veth1
,
netdev
->
link
);
}
err
=
lxc_netdev_up
(
veth1
);
if
(
err
)
{
ERROR
(
"Failed to set
\"
%s
\"
up: %s"
,
veth1
,
strerror
(
-
err
));
goto
out_delete
;
}
if
(
netdev
->
upscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
upscript
,
"up"
,
"veth"
,
veth1
,
(
char
*
)
NULL
);
if
(
err
)
goto
out_delete
;
}
DEBUG
(
"Instantiated veth
\"
%s/%s
\"
, index is
\"
%d
\"
"
,
veth1
,
veth2
,
netdev
->
ifindex
);
return
0
;
out_delete:
if
(
netdev
->
ifindex
!=
0
)
lxc_netdev_delete_by_name
(
veth1
);
if
(
!
netdev
->
priv
.
veth_attr
.
pair
)
free
(
veth1
);
free
(
veth2
);
return
-
1
;
}
static
int
instantiate_macvlan
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
char
peerbuf
[
IFNAMSIZ
],
*
peer
;
int
err
;
if
(
!
netdev
->
link
)
{
ERROR
(
"No link for macvlan network device specified"
);
return
-
1
;
}
err
=
snprintf
(
peerbuf
,
sizeof
(
peerbuf
),
"mcXXXXXX"
);
if
(
err
<
0
||
(
size_t
)
err
>=
sizeof
(
peerbuf
))
return
-
1
;
peer
=
lxc_mkifname
(
peerbuf
);
if
(
!
peer
)
return
-
1
;
err
=
lxc_macvlan_create
(
netdev
->
link
,
peer
,
netdev
->
priv
.
macvlan_attr
.
mode
);
if
(
err
)
{
ERROR
(
"Failed to create macvlan interface
\"
%s
\"
on
\"
%s
\"
: %s"
,
peer
,
netdev
->
link
,
strerror
(
-
err
));
goto
out
;
}
netdev
->
ifindex
=
if_nametoindex
(
peer
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"Failed to retrieve ifindex for
\"
%s
\"
"
,
peer
);
goto
out
;
}
if
(
netdev
->
upscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
upscript
,
"up"
,
"macvlan"
,
netdev
->
link
,
(
char
*
)
NULL
);
if
(
err
)
goto
out
;
}
DEBUG
(
"Instantiated macvlan
\"
%s
\"
with ifindex is %d and mode %d"
,
peer
,
netdev
->
ifindex
,
netdev
->
priv
.
macvlan_attr
.
mode
);
return
0
;
out:
lxc_netdev_delete_by_name
(
peer
);
free
(
peer
);
return
-
1
;
}
static
int
instantiate_vlan
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
char
peer
[
IFNAMSIZ
];
int
err
;
static
uint16_t
vlan_cntr
=
0
;
unsigned
int
mtu
=
0
;
if
(
!
netdev
->
link
)
{
ERROR
(
"No link for vlan network device specified"
);
return
-
1
;
}
err
=
snprintf
(
peer
,
sizeof
(
peer
),
"vlan%d-%d"
,
netdev
->
priv
.
vlan_attr
.
vid
,
vlan_cntr
++
);
if
(
err
<
0
||
(
size_t
)
err
>=
sizeof
(
peer
))
return
-
1
;
err
=
lxc_vlan_create
(
netdev
->
link
,
peer
,
netdev
->
priv
.
vlan_attr
.
vid
);
if
(
err
)
{
ERROR
(
"Failed to create vlan interface
\"
%s
\"
on
\"
%s
\"
: %s"
,
peer
,
netdev
->
link
,
strerror
(
-
err
));
return
-
1
;
}
netdev
->
ifindex
=
if_nametoindex
(
peer
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"Failed to retrieve ifindex for
\"
%s
\"
"
,
peer
);
lxc_netdev_delete_by_name
(
peer
);
return
-
1
;
}
DEBUG
(
"Instantiated vlan
\"
%s
\"
with ifindex is
\"
%d
\"
(vlan1000)"
,
peer
,
netdev
->
ifindex
);
if
(
netdev
->
mtu
)
{
if
(
lxc_safe_uint
(
netdev
->
mtu
,
&
mtu
)
<
0
)
{
ERROR
(
"Failed to retrieve mtu from
\"
%d
\"
/
\"
%s
\"
."
,
netdev
->
ifindex
,
netdev
->
name
?
netdev
->
name
:
"(null)"
);
return
-
1
;
}
err
=
lxc_netdev_set_mtu
(
peer
,
mtu
);
if
(
err
)
{
ERROR
(
"Failed to set mtu
\"
%s
\"
for
\"
%s
\"
: %s"
,
netdev
->
mtu
,
peer
,
strerror
(
-
err
));
lxc_netdev_delete_by_name
(
peer
);
return
-
1
;
}
}
return
0
;
}
static
int
instantiate_phys
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
if
(
!
netdev
->
link
)
{
ERROR
(
"No link for physical interface specified"
);
return
-
1
;
}
netdev
->
ifindex
=
if_nametoindex
(
netdev
->
link
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"Failed to retrieve ifindex for
\"
%s
\"
"
,
netdev
->
link
);
return
-
1
;
}
if
(
netdev
->
upscript
)
{
int
err
;
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
upscript
,
"up"
,
"phys"
,
netdev
->
link
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
instantiate_empty
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
netdev
->
ifindex
=
0
;
if
(
netdev
->
upscript
)
{
int
err
;
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
upscript
,
"up"
,
"empty"
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
instantiate_none
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
netdev
->
ifindex
=
0
;
return
0
;
}
static
instantiate_cb
netdev_conf
[
LXC_NET_MAXCONFTYPE
+
1
]
=
{
[
LXC_NET_VETH
]
=
instantiate_veth
,
[
LXC_NET_MACVLAN
]
=
instantiate_macvlan
,
[
LXC_NET_VLAN
]
=
instantiate_vlan
,
[
LXC_NET_PHYS
]
=
instantiate_phys
,
[
LXC_NET_EMPTY
]
=
instantiate_empty
,
[
LXC_NET_NONE
]
=
instantiate_none
,
};
static
int
shutdown_veth
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
char
*
veth1
;
int
err
;
if
(
netdev
->
priv
.
veth_attr
.
pair
)
veth1
=
netdev
->
priv
.
veth_attr
.
pair
;
else
veth1
=
netdev
->
priv
.
veth_attr
.
veth1
;
if
(
netdev
->
downscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
downscript
,
"down"
,
"veth"
,
veth1
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
shutdown_macvlan
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
int
err
;
if
(
netdev
->
downscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
downscript
,
"down"
,
"macvlan"
,
netdev
->
link
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
shutdown_vlan
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
return
0
;
}
static
int
shutdown_phys
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
int
err
;
if
(
netdev
->
downscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
downscript
,
"down"
,
"phys"
,
netdev
->
link
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
shutdown_empty
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
int
err
;
if
(
netdev
->
downscript
)
{
err
=
run_script
(
handler
->
name
,
"net"
,
netdev
->
downscript
,
"down"
,
"empty"
,
(
char
*
)
NULL
);
if
(
err
)
return
-
1
;
}
return
0
;
}
static
int
shutdown_none
(
struct
lxc_handler
*
handler
,
struct
lxc_netdev
*
netdev
)
{
return
0
;
}
static
instantiate_cb
netdev_deconf
[
LXC_NET_MAXCONFTYPE
+
1
]
=
{
[
LXC_NET_VETH
]
=
shutdown_veth
,
[
LXC_NET_MACVLAN
]
=
shutdown_macvlan
,
[
LXC_NET_VLAN
]
=
shutdown_vlan
,
[
LXC_NET_PHYS
]
=
shutdown_phys
,
[
LXC_NET_EMPTY
]
=
shutdown_empty
,
[
LXC_NET_NONE
]
=
shutdown_none
,
};
int
lxc_netdev_move_by_index
(
int
ifindex
,
pid_t
pid
,
const
char
*
ifname
)
{
{
struct
nl_handler
nlh
;
struct
nl_handler
nlh
;
struct
nlmsg
*
nlmsg
=
NULL
;
struct
nlmsg
*
nlmsg
=
NULL
;
...
@@ -1395,7 +1745,7 @@ int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest)
...
@@ -1395,7 +1745,7 @@ int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest)
return
ip_route_dest_add
(
AF_INET6
,
ifindex
,
dest
);
return
ip_route_dest_add
(
AF_INET6
,
ifindex
,
dest
);
}
}
static
bool
is_ovs_bridge
(
const
char
*
bridge
)
bool
is_ovs_bridge
(
const
char
*
bridge
)
{
{
char
brdirname
[
22
+
IFNAMSIZ
+
1
]
=
{
0
};
char
brdirname
[
22
+
IFNAMSIZ
+
1
]
=
{
0
};
struct
stat
sb
;
struct
stat
sb
;
...
@@ -1406,70 +1756,71 @@ static bool is_ovs_bridge(const char *bridge)
...
@@ -1406,70 +1756,71 @@ static bool is_ovs_bridge(const char *bridge)
return
false
;
return
false
;
}
}
struct
ovs_veth_args
{
const
char
*
bridge
;
const
char
*
nic
;
};
/* Called from a background thread - when nic goes away, remove it from the
/* Called from a background thread - when nic goes away, remove it from the
* bridge.
* bridge.
*/
*/
static
void
ovs_cleanup_nic
(
const
char
*
lxcpath
,
const
char
*
name
,
static
int
lxc_ovs_delete_port_exec
(
void
*
data
)
const
char
*
bridge
,
const
char
*
nic
)
{
{
int
ret
;
struct
ovs_veth_args
*
args
=
data
;
ret
=
lxc_check_inherited
(
NULL
,
true
,
&
(
int
){
-
1
},
1
);
execlp
(
"ovs-vsctl"
,
"ovs-vsctl"
,
"del-port"
,
args
->
bridge
,
args
->
nic
,
if
(
ret
<
0
)
(
char
*
)
NULL
);
return
;
return
-
1
;
}
TRACE
(
"Registering cleanup thread to remove nic
\"
%s
\"
from "
int
lxc_ovs_delete_port
(
const
char
*
bridge
,
const
char
*
nic
)
"openvswitch bridge
\"
%s
\"
"
,
nic
,
bridge
);
{
int
ret
;
char
cmd_output
[
MAXPATHLEN
];
struct
ovs_veth_args
args
;
ret
=
lxc_wait
(
name
,
"STOPPED"
,
-
1
,
lxcpath
);
args
.
bridge
=
bridge
;
args
.
nic
=
nic
;
ret
=
run_command
(
cmd_output
,
sizeof
(
cmd_output
),
lxc_ovs_delete_port_exec
,
(
void
*
)
&
args
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Failed to
register cleanup thread to remove nic
\"
%s
\"
"
ERROR
(
"Failed to
delete
\"
%s
\"
from openvswitch bridge
\"
%s
\"
:
"
"
from openvswitch bridge
\"
%s
\"
"
,
nic
,
bridge
);
"
%s"
,
bridge
,
nic
,
cmd_output
);
return
;
return
-
1
;
}
}
execlp
(
"ovs-vsctl"
,
"ovs-vsctl"
,
"del-port"
,
bridge
,
nic
,
(
char
*
)
NULL
);
return
0
;
exit
(
EXIT_FAILURE
);
}
}
static
int
attach_to_ovs_bridge
(
const
char
*
lxcpath
,
const
char
*
name
,
const
char
*
bridge
,
const
char
*
nic
)
static
int
lxc_ovs_attach_bridge_exec
(
void
*
data
)
{
{
pid_t
pid
;
struct
ovs_veth_args
*
args
=
data
;
char
*
cmd
;
int
ret
;
cmd
=
on_path
(
"ovs-vsctl"
,
NULL
);
execlp
(
"ovs-vsctl"
,
"ovs-vsctl"
,
"add-port"
,
args
->
bridge
,
args
->
nic
,
if
(
!
cmd
)
(
char
*
)
NULL
);
return
-
1
;
return
-
1
;
free
(
cmd
);
}
pid
=
fork
();
static
int
lxc_ovs_attach_bridge
(
const
char
*
bridge
,
const
char
*
nic
)
if
(
pid
<
0
)
{
int
ret
;
char
cmd_output
[
MAXPATHLEN
];
struct
ovs_veth_args
args
;
args
.
bridge
=
bridge
;
args
.
nic
=
nic
;
ret
=
run_command
(
cmd_output
,
sizeof
(
cmd_output
),
lxc_ovs_attach_bridge_exec
,
(
void
*
)
&
args
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to attach
\"
%s
\"
to openvswitch bridge
\"
%s
\"
: %s"
,
bridge
,
nic
,
cmd_output
);
return
-
1
;
return
-
1
;
if
(
pid
>
0
)
{
ret
=
wait_for_pid
(
pid
);
if
(
ret
<
0
)
return
ret
;
pid
=
fork
();
if
(
pid
<
0
)
return
-
1
;
// how to properly recover?
if
(
pid
>
0
)
return
0
;
ovs_cleanup_nic
(
lxcpath
,
name
,
bridge
,
nic
);
exit
(
0
);
}
}
if
(
execlp
(
"ovs-vsctl"
,
"ovs-vsctl"
,
"add-port"
,
bridge
,
nic
,
(
char
*
)
NULL
))
return
0
;
exit
(
1
);
// not reached
exit
(
1
);
}
}
/*
int
lxc_bridge_attach
(
const
char
*
bridge
,
const
char
*
ifname
)
* There is a lxc_bridge_attach, but no need of a bridge detach
* as automatically done by kernel when a netdev is deleted.
*/
int
lxc_bridge_attach
(
const
char
*
lxcpath
,
const
char
*
name
,
const
char
*
bridge
,
const
char
*
ifname
)
{
{
int
fd
,
index
,
err
;
int
fd
,
index
,
err
;
struct
ifreq
ifr
;
struct
ifreq
ifr
;
...
@@ -1482,7 +1833,7 @@ int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge,
...
@@ -1482,7 +1833,7 @@ int lxc_bridge_attach(const char *lxcpath, const char *name, const char *bridge,
return
-
EINVAL
;
return
-
EINVAL
;
if
(
is_ovs_bridge
(
bridge
))
if
(
is_ovs_bridge
(
bridge
))
return
attach_to_ovs_bridge
(
lxcpath
,
name
,
bridge
,
ifname
);
return
lxc_ovs_attach_bridge
(
bridge
,
ifname
);
fd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
fd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
fd
<
0
)
if
(
fd
<
0
)
...
@@ -1518,7 +1869,7 @@ const char *lxc_net_type_to_str(int type)
...
@@ -1518,7 +1869,7 @@ const char *lxc_net_type_to_str(int type)
static
const
char
padchar
[]
=
static
const
char
padchar
[]
=
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
;
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
;
char
*
lxc_mkifname
(
char
*
template
)
char
*
lxc_mkifname
(
c
onst
c
har
*
template
)
{
{
char
*
name
=
NULL
;
char
*
name
=
NULL
;
size_t
i
=
0
;
size_t
i
=
0
;
...
@@ -1604,3 +1955,842 @@ int setup_private_host_hw_addr(char *veth1)
...
@@ -1604,3 +1955,842 @@ int setup_private_host_hw_addr(char *veth1)
return
0
;
return
0
;
}
}
int
lxc_find_gateway_addresses
(
struct
lxc_handler
*
handler
)
{
struct
lxc_list
*
network
=
&
handler
->
conf
->
network
;
struct
lxc_list
*
iterator
;
struct
lxc_netdev
*
netdev
;
int
link_index
;
lxc_list_for_each
(
iterator
,
network
)
{
netdev
=
iterator
->
elem
;
if
(
!
netdev
->
ipv4_gateway_auto
&&
!
netdev
->
ipv6_gateway_auto
)
continue
;
if
(
netdev
->
type
!=
LXC_NET_VETH
&&
netdev
->
type
!=
LXC_NET_MACVLAN
)
{
ERROR
(
"Automatic gateway detection is only supported "
"for veth and macvlan"
);
return
-
1
;
}
if
(
!
netdev
->
link
)
{
ERROR
(
"Automatic gateway detection needs a link interface"
);
return
-
1
;
}
link_index
=
if_nametoindex
(
netdev
->
link
);
if
(
!
link_index
)
return
-
EINVAL
;
if
(
netdev
->
ipv4_gateway_auto
)
{
if
(
lxc_ipv4_addr_get
(
link_index
,
&
netdev
->
ipv4_gateway
))
{
ERROR
(
"Failed to automatically find ipv4 gateway "
"address from link interface
\"
%s
\"
"
,
netdev
->
link
);
return
-
1
;
}
}
if
(
netdev
->
ipv6_gateway_auto
)
{
if
(
lxc_ipv6_addr_get
(
link_index
,
&
netdev
->
ipv6_gateway
))
{
ERROR
(
"Failed to automatically find ipv6 gateway "
"address from link interface
\"
%s
\"
"
,
netdev
->
link
);
return
-
1
;
}
}
}
return
0
;
}
#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
static
int
lxc_create_network_unpriv
(
const
char
*
lxcpath
,
char
*
lxcname
,
struct
lxc_netdev
*
netdev
,
pid_t
pid
)
{
int
ret
;
pid_t
child
;
int
bytes
,
pipefd
[
2
];
char
*
token
,
*
saveptr
=
NULL
;
char
netdev_link
[
IFNAMSIZ
+
1
];
char
buffer
[
MAXPATHLEN
]
=
{
0
};
if
(
netdev
->
type
!=
LXC_NET_VETH
)
{
ERROR
(
"Network type %d not support for unprivileged use"
,
netdev
->
type
);
return
-
1
;
}
ret
=
pipe
(
pipefd
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to create pipe"
);
return
-
1
;
}
child
=
fork
();
if
(
child
<
0
)
{
SYSERROR
(
"Failed to create new process"
);
close
(
pipefd
[
0
]);
close
(
pipefd
[
1
]);
return
-
1
;
}
if
(
child
==
0
)
{
int
ret
;
char
pidstr
[
LXC_NUMSTRLEN64
];
close
(
pipefd
[
0
]);
ret
=
dup2
(
pipefd
[
1
],
STDOUT_FILENO
);
if
(
ret
>=
0
)
ret
=
dup2
(
pipefd
[
1
],
STDERR_FILENO
);
close
(
pipefd
[
1
]);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to duplicate std{err,out} file descriptor"
);
exit
(
EXIT_FAILURE
);
}
if
(
netdev
->
link
)
strncpy
(
netdev_link
,
netdev
->
link
,
IFNAMSIZ
);
else
strncpy
(
netdev_link
,
"none"
,
IFNAMSIZ
);
ret
=
snprintf
(
pidstr
,
LXC_NUMSTRLEN64
,
"%d"
,
pid
);
if
(
ret
<
0
||
ret
>=
LXC_NUMSTRLEN64
)
exit
(
EXIT_FAILURE
);
pidstr
[
LXC_NUMSTRLEN64
-
1
]
=
'\0'
;
INFO
(
"Execing lxc-user-nic create %s %s %s veth %s %s"
,
lxcpath
,
lxcname
,
pidstr
,
netdev_link
,
netdev
->
name
?
netdev
->
name
:
"(null)"
);
if
(
netdev
->
name
)
execlp
(
LXC_USERNIC_PATH
,
LXC_USERNIC_PATH
,
"create"
,
lxcpath
,
lxcname
,
pidstr
,
"veth"
,
netdev_link
,
netdev
->
name
,
(
char
*
)
NULL
);
else
execlp
(
LXC_USERNIC_PATH
,
LXC_USERNIC_PATH
,
"create"
,
lxcpath
,
lxcname
,
pidstr
,
"veth"
,
netdev_link
,
(
char
*
)
NULL
);
SYSERROR
(
"Failed to execute lxc-user-nic"
);
exit
(
EXIT_FAILURE
);
}
/* close the write-end of the pipe */
close
(
pipefd
[
1
]);
bytes
=
read
(
pipefd
[
0
],
&
buffer
,
MAXPATHLEN
);
if
(
bytes
<
0
)
{
SYSERROR
(
"Failed to read from pipe file descriptor."
);
close
(
pipefd
[
0
]);
return
-
1
;
}
buffer
[
bytes
-
1
]
=
'\0'
;
ret
=
wait_for_pid
(
child
);
close
(
pipefd
[
0
]);
if
(
ret
!=
0
)
{
ERROR
(
"lxc-user-nic failed to configure requested network: %s"
,
buffer
[
0
]
!=
'\0'
?
buffer
:
"(null)"
);
return
-
1
;
}
TRACE
(
"Received output
\"
%s
\"
from lxc-user-nic"
,
buffer
);
/* netdev->name */
token
=
strtok_r
(
buffer
,
":"
,
&
saveptr
);
if
(
!
token
)
return
-
1
;
netdev
->
name
=
malloc
(
IFNAMSIZ
+
1
);
if
(
!
netdev
->
name
)
{
SYSERROR
(
"Failed to allocate memory."
);
return
-
1
;
}
memset
(
netdev
->
name
,
0
,
IFNAMSIZ
+
1
);
strncpy
(
netdev
->
name
,
token
,
IFNAMSIZ
);
/* netdev->priv.veth_attr.pair */
token
=
strtok_r
(
NULL
,
":"
,
&
saveptr
);
if
(
!
token
)
return
-
1
;
netdev
->
priv
.
veth_attr
.
pair
=
strdup
(
token
);
if
(
!
netdev
->
priv
.
veth_attr
.
pair
)
{
ERROR
(
"Failed to allocate memory."
);
return
-
1
;
}
/* netdev->ifindex */
token
=
strtok_r
(
NULL
,
":"
,
&
saveptr
);
if
(
!
token
)
return
-
1
;
ret
=
lxc_safe_int
(
token
,
&
netdev
->
ifindex
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to parse ifindex for network device
\"
%s
\"
"
,
netdev
->
name
);
return
-
1
;
}
return
0
;
}
static
int
lxc_delete_network_unpriv
(
const
char
*
lxcpath
,
char
*
lxcname
,
struct
lxc_netdev
*
netdev
,
pid_t
pid
)
{
int
bytes
,
ret
;
pid_t
child
;
int
pipefd
[
2
];
char
buffer
[
MAXPATHLEN
]
=
{
0
};
if
(
netdev
->
type
!=
LXC_NET_VETH
)
{
ERROR
(
"Network type %d not support for unprivileged use"
,
netdev
->
type
);
return
-
1
;
}
ret
=
pipe
(
pipefd
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to create pipe"
);
return
-
1
;
}
child
=
fork
();
if
(
child
<
0
)
{
SYSERROR
(
"Failed to create new process"
);
close
(
pipefd
[
0
]);
close
(
pipefd
[
1
]);
return
-
1
;
}
if
(
child
==
0
)
{
int
ret
;
char
pidstr
[
LXC_NUMSTRLEN64
];
close
(
pipefd
[
0
]);
ret
=
dup2
(
pipefd
[
1
],
STDOUT_FILENO
);
if
(
ret
>=
0
)
ret
=
dup2
(
pipefd
[
1
],
STDERR_FILENO
);
close
(
pipefd
[
1
]);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to duplicate std{err,out} file descriptor"
);
exit
(
EXIT_FAILURE
);
}
if
(
!
netdev
->
link
)
SYSERROR
(
"Network link for network device
\"
%s
\"
is "
"missing"
,
netdev
->
priv
.
veth_attr
.
pair
);
ret
=
snprintf
(
pidstr
,
LXC_NUMSTRLEN64
,
"%d"
,
pid
);
if
(
ret
<
0
||
ret
>=
LXC_NUMSTRLEN64
)
exit
(
EXIT_FAILURE
);
pidstr
[
LXC_NUMSTRLEN64
-
1
]
=
'\0'
;
INFO
(
"Execing lxc-user-nic delete %s %s %s veth %s %s"
,
lxcpath
,
lxcname
,
pidstr
,
netdev
->
link
,
netdev
->
priv
.
veth_attr
.
pair
);
execlp
(
LXC_USERNIC_PATH
,
LXC_USERNIC_PATH
,
"delete"
,
lxcpath
,
lxcname
,
pidstr
,
"veth"
,
netdev
->
link
,
netdev
->
priv
.
veth_attr
.
pair
,
(
char
*
)
NULL
);
SYSERROR
(
"Failed to exec lxc-user-nic."
);
exit
(
EXIT_FAILURE
);
}
close
(
pipefd
[
1
]);
bytes
=
read
(
pipefd
[
0
],
&
buffer
,
MAXPATHLEN
);
if
(
bytes
<
0
)
{
SYSERROR
(
"Failed to read from pipe file descriptor."
);
close
(
pipefd
[
0
]);
return
-
1
;
}
buffer
[
bytes
-
1
]
=
'\0'
;
if
(
wait_for_pid
(
child
)
!=
0
)
{
ERROR
(
"lxc-user-nic failed to delete requested network: %s"
,
buffer
[
0
]
!=
'\0'
?
buffer
:
"(null)"
);
close
(
pipefd
[
0
]);
return
-
1
;
}
close
(
pipefd
[
0
]);
return
0
;
}
int
lxc_create_network_priv
(
struct
lxc_handler
*
handler
)
{
bool
am_root
;
struct
lxc_list
*
iterator
;
struct
lxc_list
*
network
=
&
handler
->
conf
->
network
;
/* We need to be root. */
am_root
=
(
getuid
()
==
0
);
if
(
!
am_root
)
return
0
;
lxc_list_for_each
(
iterator
,
network
)
{
struct
lxc_netdev
*
netdev
=
iterator
->
elem
;
if
(
netdev
->
type
<
0
||
netdev
->
type
>
LXC_NET_MAXCONFTYPE
)
{
ERROR
(
"Invalid network configuration type %d"
,
netdev
->
type
);
return
-
1
;
}
if
(
netdev_conf
[
netdev
->
type
](
handler
,
netdev
))
{
ERROR
(
"Failed to create network device"
);
return
-
1
;
}
}
return
0
;
}
int
lxc_create_network
(
const
char
*
lxcpath
,
char
*
lxcname
,
struct
lxc_list
*
network
,
pid_t
pid
)
{
int
err
;
bool
am_root
;
char
ifname
[
IFNAMSIZ
];
struct
lxc_list
*
iterator
;
am_root
=
(
getuid
()
==
0
);
lxc_list_for_each
(
iterator
,
network
)
{
struct
lxc_netdev
*
netdev
=
iterator
->
elem
;
if
(
netdev
->
type
==
LXC_NET_VETH
&&
!
am_root
)
{
if
(
netdev
->
mtu
)
INFO
(
"mtu ignored due to insufficient privilege"
);
if
(
lxc_create_network_unpriv
(
lxcpath
,
lxcname
,
netdev
,
pid
))
return
-
1
;
/* lxc-user-nic has moved the nic to the new ns.
* unpriv_assign_nic() fills in netdev->name.
* netdev->ifindex will be filled in at
* lxc_setup_netdev_in_child_namespaces().
*/
continue
;
}
/* empty network namespace, nothing to move */
if
(
!
netdev
->
ifindex
)
continue
;
/* retrieve the name of the interface */
if
(
!
if_indextoname
(
netdev
->
ifindex
,
ifname
))
{
ERROR
(
"No interface corresponding to ifindex
\"
%d
\"
"
,
netdev
->
ifindex
);
return
-
1
;
}
err
=
lxc_netdev_move_by_name
(
ifname
,
pid
,
NULL
);
if
(
err
)
{
ERROR
(
"Failed to move network device
\"
%s
\"
to "
"network namespace %d: %s"
,
ifname
,
pid
,
strerror
(
-
err
));
return
-
1
;
}
DEBUG
(
"Moved network device
\"
%s
\"
/
\"
%s
\"
to network namespace "
"of %d:"
,
ifname
,
netdev
->
name
?
netdev
->
name
:
"(null)"
,
pid
);
}
return
0
;
}
bool
lxc_delete_network
(
struct
lxc_handler
*
handler
)
{
int
ret
;
struct
lxc_list
*
iterator
;
struct
lxc_list
*
network
=
&
handler
->
conf
->
network
;
bool
deleted_all
=
true
;
lxc_list_for_each
(
iterator
,
network
)
{
char
*
hostveth
=
NULL
;
struct
lxc_netdev
*
netdev
=
iterator
->
elem
;
/* We can only delete devices whose ifindex we have. If we don't
* have the index it means that we didn't create it.
*/
if
(
!
netdev
->
ifindex
)
continue
;
if
(
netdev
->
type
==
LXC_NET_PHYS
)
{
ret
=
lxc_netdev_rename_by_index
(
netdev
->
ifindex
,
netdev
->
link
);
if
(
ret
<
0
)
WARN
(
"Failed to rename interface with index %d "
"to its initial name
\"
%s
\"
"
,
netdev
->
ifindex
,
netdev
->
link
);
else
TRACE
(
"Renamed interface with index %d to its "
"initial name
\"
%s
\"
"
,
netdev
->
ifindex
,
netdev
->
link
);
continue
;
}
ret
=
netdev_deconf
[
netdev
->
type
](
handler
,
netdev
);
if
(
ret
<
0
)
WARN
(
"Failed to deconfigure network device"
);
/* Recent kernels remove the virtual interfaces when the network
* namespace is destroyed but in case we did not move the
* interface to the network namespace, we have to destroy it.
*/
if
(
!
am_unpriv
())
{
ret
=
lxc_netdev_delete_by_index
(
netdev
->
ifindex
);
if
(
-
ret
==
ENODEV
)
{
INFO
(
"Interface
\"
%s
\"
with index %d already "
"deleted or existing in different network "
"namespace"
,
netdev
->
name
?
netdev
->
name
:
"(null)"
,
netdev
->
ifindex
);
}
else
if
(
ret
<
0
)
{
deleted_all
=
false
;
WARN
(
"Failed to remove interface
\"
%s
\"
with "
"index %d: %s"
,
netdev
->
name
?
netdev
->
name
:
"(null)"
,
netdev
->
ifindex
,
strerror
(
-
ret
));
continue
;
}
INFO
(
"Removed interface
\"
%s
\"
with index %d"
,
netdev
->
name
?
netdev
->
name
:
"(null)"
,
netdev
->
ifindex
);
}
if
(
netdev
->
type
!=
LXC_NET_VETH
)
continue
;
if
(
am_unpriv
())
{
if
(
is_ovs_bridge
(
netdev
->
link
))
{
ret
=
lxc_delete_network_unpriv
(
handler
->
lxcpath
,
handler
->
name
,
netdev
,
getpid
());
if
(
ret
<
0
)
WARN
(
"Failed to remove port
\"
%s
\"
"
"from openvswitch bridge
\"
%s
\"
"
,
netdev
->
priv
.
veth_attr
.
pair
,
netdev
->
link
);
}
continue
;
}
/* Explicitly delete host veth device to prevent lingering
* devices. We had issues in LXD around this.
*/
if
(
netdev
->
priv
.
veth_attr
.
pair
)
hostveth
=
netdev
->
priv
.
veth_attr
.
pair
;
else
hostveth
=
netdev
->
priv
.
veth_attr
.
veth1
;
if
(
*
hostveth
==
'\0'
)
continue
;
ret
=
lxc_netdev_delete_by_name
(
hostveth
);
if
(
ret
<
0
)
{
deleted_all
=
false
;
WARN
(
"Failed to remove interface
\"
%s
\"
from
\"
%s
\"
: %s"
,
hostveth
,
netdev
->
link
,
strerror
(
-
ret
));
continue
;
}
INFO
(
"Removed interface
\"
%s
\"
from
\"
%s
\"
"
,
hostveth
,
netdev
->
link
);
if
(
!
is_ovs_bridge
(
netdev
->
link
))
{
netdev
->
priv
.
veth_attr
.
veth1
[
0
]
=
'\0'
;
continue
;
}
/* Delete the openvswitch port. */
ret
=
lxc_ovs_delete_port
(
netdev
->
link
,
hostveth
);
if
(
ret
<
0
)
WARN
(
"Failed to remove port
\"
%s
\"
from openvswitch "
"bridge
\"
%s
\"
"
,
hostveth
,
netdev
->
link
);
else
INFO
(
"Removed port
\"
%s
\"
from openvswitch bridge
\"
%s
\"
"
,
hostveth
,
netdev
->
link
);
netdev
->
priv
.
veth_attr
.
veth1
[
0
]
=
'\0'
;
}
return
deleted_all
;
}
int
lxc_requests_empty_network
(
struct
lxc_handler
*
handler
)
{
struct
lxc_list
*
network
=
&
handler
->
conf
->
network
;
struct
lxc_list
*
iterator
;
bool
found_none
=
false
,
found_nic
=
false
;
if
(
lxc_list_empty
(
network
))
return
0
;
lxc_list_for_each
(
iterator
,
network
)
{
struct
lxc_netdev
*
netdev
=
iterator
->
elem
;
if
(
netdev
->
type
==
LXC_NET_NONE
)
found_none
=
true
;
else
found_nic
=
true
;
}
if
(
found_none
&&
!
found_nic
)
return
1
;
return
0
;
}
/* try to move physical nics to the init netns */
void
lxc_restore_phys_nics_to_netns
(
int
netnsfd
,
struct
lxc_conf
*
conf
)
{
int
ret
;
int
i
,
oldfd
;
char
ifname
[
IFNAMSIZ
];
if
(
netnsfd
<
0
||
conf
->
num_savednics
==
0
)
return
;
INFO
(
"Trying to restore network device names in original namespace for "
"%d network devices"
,
conf
->
num_savednics
);
oldfd
=
lxc_preserve_ns
(
getpid
(),
"net"
);
if
(
oldfd
<
0
)
{
SYSERROR
(
"Failed to preserve network namespace"
);
return
;
}
ret
=
setns
(
netnsfd
,
0
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to enter network namespace"
);
close
(
oldfd
);
return
;
}
for
(
i
=
0
;
i
<
conf
->
num_savednics
;
i
++
)
{
struct
saved_nic
*
s
=
&
conf
->
saved_nics
[
i
];
/* retrieve the name of the interface */
if
(
!
if_indextoname
(
s
->
ifindex
,
ifname
))
{
WARN
(
"No interface corresponding to ifindex %d"
,
s
->
ifindex
);
continue
;
}
if
(
lxc_netdev_move_by_name
(
ifname
,
1
,
s
->
orig_name
))
WARN
(
"Error moving network device
\"
%s
\"
back to "
"network namespace"
,
ifname
);
free
(
s
->
orig_name
);
}
conf
->
num_savednics
=
0
;
ret
=
setns
(
oldfd
,
0
);
if
(
ret
<
0
)
SYSERROR
(
"Failed to enter network namespace"
);
close
(
oldfd
);
}
static
int
setup_hw_addr
(
char
*
hwaddr
,
const
char
*
ifname
)
{
struct
sockaddr
sockaddr
;
struct
ifreq
ifr
;
int
ret
,
fd
,
saved_errno
;
ret
=
lxc_convert_mac
(
hwaddr
,
&
sockaddr
);
if
(
ret
)
{
ERROR
(
"Mac address
\"
%s
\"
conversion failed: %s"
,
hwaddr
,
strerror
(
-
ret
));
return
-
1
;
}
memcpy
(
ifr
.
ifr_name
,
ifname
,
IFNAMSIZ
);
ifr
.
ifr_name
[
IFNAMSIZ
-
1
]
=
'\0'
;
memcpy
((
char
*
)
&
ifr
.
ifr_hwaddr
,
(
char
*
)
&
sockaddr
,
sizeof
(
sockaddr
));
fd
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
if
(
fd
<
0
)
return
-
1
;
ret
=
ioctl
(
fd
,
SIOCSIFHWADDR
,
&
ifr
);
saved_errno
=
errno
;
close
(
fd
);
if
(
ret
)
ERROR
(
"Failed to perform ioctl: %s"
,
strerror
(
saved_errno
));
DEBUG
(
"Mac address
\"
%s
\"
on
\"
%s
\"
has been setup"
,
hwaddr
,
ifr
.
ifr_name
);
return
ret
;
}
static
int
setup_ipv4_addr
(
struct
lxc_list
*
ip
,
int
ifindex
)
{
struct
lxc_list
*
iterator
;
int
err
;
lxc_list_for_each
(
iterator
,
ip
)
{
struct
lxc_inetdev
*
inetdev
=
iterator
->
elem
;
err
=
lxc_ipv4_addr_add
(
ifindex
,
&
inetdev
->
addr
,
&
inetdev
->
bcast
,
inetdev
->
prefix
);
if
(
err
)
{
ERROR
(
"Failed to setup ipv4 address for network device "
"with eifindex %d: %s"
,
ifindex
,
strerror
(
-
err
));
return
-
1
;
}
}
return
0
;
}
static
int
setup_ipv6_addr
(
struct
lxc_list
*
ip
,
int
ifindex
)
{
struct
lxc_list
*
iterator
;
int
err
;
lxc_list_for_each
(
iterator
,
ip
)
{
struct
lxc_inet6dev
*
inet6dev
=
iterator
->
elem
;
err
=
lxc_ipv6_addr_add
(
ifindex
,
&
inet6dev
->
addr
,
&
inet6dev
->
mcast
,
&
inet6dev
->
acast
,
inet6dev
->
prefix
);
if
(
err
)
{
ERROR
(
"Failed to setup ipv6 address for network device "
"with eifindex %d: %s"
,
ifindex
,
strerror
(
-
err
));
return
-
1
;
}
}
return
0
;
}
static
int
lxc_setup_netdev_in_child_namespaces
(
struct
lxc_netdev
*
netdev
)
{
char
ifname
[
IFNAMSIZ
];
int
err
;
const
char
*
net_type_name
;
char
*
current_ifname
=
ifname
;
/* empty network namespace */
if
(
!
netdev
->
ifindex
)
{
if
(
netdev
->
flags
&
IFF_UP
)
{
err
=
lxc_netdev_up
(
"lo"
);
if
(
err
)
{
ERROR
(
"Failed to set the loopback network "
"device up: %s"
,
strerror
(
-
err
));
return
-
1
;
}
}
if
(
netdev
->
type
==
LXC_NET_EMPTY
)
return
0
;
if
(
netdev
->
type
==
LXC_NET_NONE
)
return
0
;
if
(
netdev
->
type
!=
LXC_NET_VETH
)
{
net_type_name
=
lxc_net_type_to_str
(
netdev
->
type
);
ERROR
(
"%s networks are not supported for containers "
"not setup up by privileged users"
,
net_type_name
);
return
-
1
;
}
netdev
->
ifindex
=
if_nametoindex
(
netdev
->
name
);
}
/* get the new ifindex in case of physical netdev */
if
(
netdev
->
type
==
LXC_NET_PHYS
)
{
netdev
->
ifindex
=
if_nametoindex
(
netdev
->
link
);
if
(
!
netdev
->
ifindex
)
{
ERROR
(
"Failed to get ifindex for network device
\"
%s
\"
"
,
netdev
->
link
);
return
-
1
;
}
}
/* retrieve the name of the interface */
if
(
!
if_indextoname
(
netdev
->
ifindex
,
current_ifname
))
{
ERROR
(
"Failed get name for network device with ifindex %d"
,
netdev
->
ifindex
);
return
-
1
;
}
/* Default: let the system to choose one interface name.
* When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
* netlink will replace the format specifier with an appropriate index.
*/
if
(
!
netdev
->
name
)
netdev
->
name
=
netdev
->
type
==
LXC_NET_PHYS
?
netdev
->
link
:
"eth%d"
;
/* rename the interface name */
if
(
strcmp
(
ifname
,
netdev
->
name
)
!=
0
)
{
err
=
lxc_netdev_rename_by_name
(
ifname
,
netdev
->
name
);
if
(
err
)
{
ERROR
(
"Failed to rename network device
\"
%s
\"
to "
"
\"
%s
\"
: %s"
,
ifname
,
netdev
->
name
,
strerror
(
-
err
));
return
-
1
;
}
}
/* Re-read the name of the interface because its name has changed
* and would be automatically allocated by the system
*/
if
(
!
if_indextoname
(
netdev
->
ifindex
,
current_ifname
))
{
ERROR
(
"Failed get name for network device with ifindex %d"
,
netdev
->
ifindex
);
return
-
1
;
}
/* set a mac address */
if
(
netdev
->
hwaddr
)
{
if
(
setup_hw_addr
(
netdev
->
hwaddr
,
current_ifname
))
{
ERROR
(
"Failed to setup hw address for network device
\"
%s
\"
"
,
current_ifname
);
return
-
1
;
}
}
/* setup ipv4 addresses on the interface */
if
(
setup_ipv4_addr
(
&
netdev
->
ipv4
,
netdev
->
ifindex
))
{
ERROR
(
"Failed to setup ip addresses for network device
\"
%s
\"
"
,
ifname
);
return
-
1
;
}
/* setup ipv6 addresses on the interface */
if
(
setup_ipv6_addr
(
&
netdev
->
ipv6
,
netdev
->
ifindex
))
{
ERROR
(
"Failed to setup ipv6 addresses for network device
\"
%s
\"
"
,
ifname
);
return
-
1
;
}
/* set the network device up */
if
(
netdev
->
flags
&
IFF_UP
)
{
int
err
;
err
=
lxc_netdev_up
(
current_ifname
);
if
(
err
)
{
ERROR
(
"Failed to set network device
\"
%s
\"
up: %s"
,
current_ifname
,
strerror
(
-
err
));
return
-
1
;
}
/* the network is up, make the loopback up too */
err
=
lxc_netdev_up
(
"lo"
);
if
(
err
)
{
ERROR
(
"Failed to set the loopback network device up: %s"
,
strerror
(
-
err
));
return
-
1
;
}
}
/* We can only set up the default routes after bringing
* up the interface, sine bringing up the interface adds
* the link-local routes and we can't add a default
* route if the gateway is not reachable. */
/* setup ipv4 gateway on the interface */
if
(
netdev
->
ipv4_gateway
)
{
if
(
!
(
netdev
->
flags
&
IFF_UP
))
{
ERROR
(
"Cannot add ipv4 gateway for network device "
"
\"
%s
\"
when not bringing up the interface"
,
ifname
);
return
-
1
;
}
if
(
lxc_list_empty
(
&
netdev
->
ipv4
))
{
ERROR
(
"Cannot add ipv4 gateway for network device "
"
\"
%s
\"
when not assigning an address"
,
ifname
);
return
-
1
;
}
err
=
lxc_ipv4_gateway_add
(
netdev
->
ifindex
,
netdev
->
ipv4_gateway
);
if
(
err
)
{
err
=
lxc_ipv4_dest_add
(
netdev
->
ifindex
,
netdev
->
ipv4_gateway
);
if
(
err
)
{
ERROR
(
"Failed to add ipv4 dest for network "
"device
\"
%s
\"
: %s"
,
ifname
,
strerror
(
-
err
));
}
err
=
lxc_ipv4_gateway_add
(
netdev
->
ifindex
,
netdev
->
ipv4_gateway
);
if
(
err
)
{
ERROR
(
"Failed to setup ipv4 gateway for "
"network device
\"
%s
\"
: %s"
,
ifname
,
strerror
(
-
err
));
if
(
netdev
->
ipv4_gateway_auto
)
{
char
buf
[
INET_ADDRSTRLEN
];
inet_ntop
(
AF_INET
,
netdev
->
ipv4_gateway
,
buf
,
sizeof
(
buf
));
ERROR
(
"Fried to set autodetected ipv4 gateway
\"
%s
\"
"
,
buf
);
}
return
-
1
;
}
}
}
/* setup ipv6 gateway on the interface */
if
(
netdev
->
ipv6_gateway
)
{
if
(
!
(
netdev
->
flags
&
IFF_UP
))
{
ERROR
(
"Cannot add ipv6 gateway for network device "
"
\"
%s
\"
when not bringing up the interface"
,
ifname
);
return
-
1
;
}
if
(
lxc_list_empty
(
&
netdev
->
ipv6
)
&&
!
IN6_IS_ADDR_LINKLOCAL
(
netdev
->
ipv6_gateway
))
{
ERROR
(
"Cannot add ipv6 gateway for network device "
"
\"
%s
\"
when not assigning an address"
,
ifname
);
return
-
1
;
}
err
=
lxc_ipv6_gateway_add
(
netdev
->
ifindex
,
netdev
->
ipv6_gateway
);
if
(
err
)
{
err
=
lxc_ipv6_dest_add
(
netdev
->
ifindex
,
netdev
->
ipv6_gateway
);
if
(
err
)
{
ERROR
(
"Failed to add ipv6 dest for network "
"device
\"
%s
\"
: %s"
,
ifname
,
strerror
(
-
err
));
}
err
=
lxc_ipv6_gateway_add
(
netdev
->
ifindex
,
netdev
->
ipv6_gateway
);
if
(
err
)
{
ERROR
(
"Failed to setup ipv6 gateway for "
"network device
\"
%s
\"
: %s"
,
ifname
,
strerror
(
-
err
));
if
(
netdev
->
ipv6_gateway_auto
)
{
char
buf
[
INET6_ADDRSTRLEN
];
inet_ntop
(
AF_INET6
,
netdev
->
ipv6_gateway
,
buf
,
sizeof
(
buf
));
ERROR
(
"Tried to set autodetected ipv6 "
"gateway for network device "
"
\"
%s
\"
"
,
buf
);
}
return
-
1
;
}
}
}
DEBUG
(
"Network devie
\"
%s
\"
has been setup"
,
current_ifname
);
return
0
;
}
int
lxc_setup_network_in_child_namespaces
(
const
struct
lxc_conf
*
conf
,
struct
lxc_list
*
network
)
{
struct
lxc_list
*
iterator
;
struct
lxc_netdev
*
netdev
;
lxc_log_configured_netdevs
(
conf
);
lxc_list_for_each
(
iterator
,
network
)
{
netdev
=
iterator
->
elem
;
/* REMOVE in LXC 3.0 */
if
(
netdev
->
idx
<
0
)
{
ERROR
(
"WARNING: using
\"
lxc.network.*
\"
keys to define "
"networks is DEPRECATED, please switch to using "
"
\"
lxc.net.[i].* keys
\"
"
);
}
if
(
lxc_setup_netdev_in_child_namespaces
(
netdev
))
{
ERROR
(
"failed to setup netdev"
);
return
-
1
;
}
}
if
(
!
lxc_list_empty
(
network
))
INFO
(
"network has been setup"
);
return
0
;
}
src/lxc/network.h
View file @
d3e7b8ad
...
@@ -23,9 +23,121 @@
...
@@ -23,9 +23,121 @@
#ifndef __LXC_NETWORK_H
#ifndef __LXC_NETWORK_H
#define __LXC_NETWORK_H
#define __LXC_NETWORK_H
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "list.h"
struct
lxc_conf
;
struct
lxc_handler
;
struct
lxc_netdev
;
enum
{
LXC_NET_EMPTY
,
LXC_NET_VETH
,
LXC_NET_MACVLAN
,
LXC_NET_PHYS
,
LXC_NET_VLAN
,
LXC_NET_NONE
,
LXC_NET_MAXCONFTYPE
,
};
/*
/*
* Convert a string mac address to a socket structure
* Defines the structure to configure an ipv4 address
* @address : ipv4 address
* @broadcast : ipv4 broadcast address
* @mask : network mask
*/
*/
struct
lxc_inetdev
{
struct
in_addr
addr
;
struct
in_addr
bcast
;
unsigned
int
prefix
;
};
struct
lxc_route
{
struct
in_addr
addr
;
};
/*
* Defines the structure to configure an ipv6 address
* @flags : set the address up
* @address : ipv6 address
* @broadcast : ipv6 broadcast address
* @mask : network mask
*/
struct
lxc_inet6dev
{
struct
in6_addr
addr
;
struct
in6_addr
mcast
;
struct
in6_addr
acast
;
unsigned
int
prefix
;
};
struct
lxc_route6
{
struct
in6_addr
addr
;
};
struct
ifla_veth
{
char
*
pair
;
/* pair name */
char
veth1
[
IFNAMSIZ
];
/* needed for deconf */
};
struct
ifla_vlan
{
unsigned
int
flags
;
unsigned
int
fmask
;
unsigned
short
vid
;
unsigned
short
pad
;
};
struct
ifla_macvlan
{
int
mode
;
/* private, vepa, bridge, passthru */
};
union
netdev_p
{
struct
ifla_veth
veth_attr
;
struct
ifla_vlan
vlan_attr
;
struct
ifla_macvlan
macvlan_attr
;
};
/*
* Defines a structure to configure a network device
* @link : lxc.net.[i].link, name of bridge or host iface to attach if any
* @name : lxc.net.[i].name, name of iface on the container side
* @flags : flag of the network device (IFF_UP, ... )
* @ipv4 : a list of ipv4 addresses to be set on the network device
* @ipv6 : a list of ipv6 addresses to be set on the network device
* @upscript : a script filename to be executed during interface configuration
* @downscript : a script filename to be executed during interface destruction
* @idx : network counter
*/
struct
lxc_netdev
{
ssize_t
idx
;
int
type
;
int
flags
;
int
ifindex
;
char
*
link
;
char
*
name
;
char
*
hwaddr
;
char
*
mtu
;
union
netdev_p
priv
;
struct
lxc_list
ipv4
;
struct
lxc_list
ipv6
;
struct
in_addr
*
ipv4_gateway
;
bool
ipv4_gateway_auto
;
struct
in6_addr
*
ipv6_gateway
;
bool
ipv6_gateway_auto
;
char
*
upscript
;
char
*
downscript
;
};
struct
saved_nic
{
int
ifindex
;
char
*
orig_name
;
};
/* Convert a string mac address to a socket structure. */
extern
int
lxc_convert_mac
(
char
*
macaddr
,
struct
sockaddr
*
sockaddr
);
extern
int
lxc_convert_mac
(
char
*
macaddr
,
struct
sockaddr
*
sockaddr
);
/*
/*
...
@@ -109,7 +221,10 @@ extern int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw);
...
@@ -109,7 +221,10 @@ extern int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw);
/*
/*
* Attach an interface to the bridge
* Attach an interface to the bridge
*/
*/
extern
int
lxc_bridge_attach
(
const
char
*
lxcpath
,
const
char
*
name
,
const
char
*
bridge
,
const
char
*
ifname
);
extern
int
lxc_bridge_attach
(
const
char
*
bridge
,
const
char
*
ifname
);
extern
int
lxc_ovs_delete_port
(
const
char
*
bridge
,
const
char
*
nic
);
extern
bool
is_ovs_bridge
(
const
char
*
bridge
);
/*
/*
* Create default gateway
* Create default gateway
...
@@ -133,12 +248,22 @@ extern int lxc_neigh_proxy_on(const char *name, int family);
...
@@ -133,12 +248,22 @@ extern int lxc_neigh_proxy_on(const char *name, int family);
*/
*/
extern
int
lxc_neigh_proxy_off
(
const
char
*
name
,
int
family
);
extern
int
lxc_neigh_proxy_off
(
const
char
*
name
,
int
family
);
/*
/*
Generate a new unique network interface name.
*
Generate a new unique network interface name
*
Allocated memory must be freed by caller.
*/
*/
extern
char
*
lxc_mkifname
(
char
*
template
);
extern
char
*
lxc_mkifname
(
c
onst
c
har
*
template
);
extern
const
char
*
lxc_net_type_to_str
(
int
type
);
extern
const
char
*
lxc_net_type_to_str
(
int
type
);
extern
int
setup_private_host_hw_addr
(
char
*
veth1
);
extern
int
setup_private_host_hw_addr
(
char
*
veth1
);
extern
int
netdev_get_mtu
(
int
ifindex
);
extern
int
netdev_get_mtu
(
int
ifindex
);
#endif
extern
int
lxc_create_network_priv
(
struct
lxc_handler
*
handler
);
extern
bool
lxc_delete_network
(
struct
lxc_handler
*
handler
);
extern
int
lxc_find_gateway_addresses
(
struct
lxc_handler
*
handler
);
extern
int
lxc_create_network
(
const
char
*
lxcpath
,
char
*
lxcname
,
struct
lxc_list
*
network
,
pid_t
pid
);
extern
int
lxc_requests_empty_network
(
struct
lxc_handler
*
handler
);
extern
void
lxc_restore_phys_nics_to_netns
(
int
netnsfd
,
struct
lxc_conf
*
conf
);
extern
int
lxc_setup_network_in_child_namespaces
(
const
struct
lxc_conf
*
conf
,
struct
lxc_list
*
network
);
#endif
/* __LXC_NETWORK_H */
src/lxc/start.c
View file @
d3e7b8ad
...
@@ -70,6 +70,7 @@
...
@@ -70,6 +70,7 @@
#include "mainloop.h"
#include "mainloop.h"
#include "monitor.h"
#include "monitor.h"
#include "namespace.h"
#include "namespace.h"
#include "network.h"
#include "start.h"
#include "start.h"
#include "storage.h"
#include "storage.h"
#include "storage_utils.h"
#include "storage_utils.h"
...
@@ -1311,7 +1312,7 @@ static int lxc_spawn(struct lxc_handler *handler)
...
@@ -1311,7 +1312,7 @@ static int lxc_spawn(struct lxc_handler *handler)
/* That should be done before the clone because we will
/* That should be done before the clone because we will
* fill the netdev index and use them in the child.
* fill the netdev index and use them in the child.
*/
*/
if
(
lxc_create_network
(
handler
))
{
if
(
lxc_create_network
_priv
(
handler
))
{
ERROR
(
"Failed to create the network."
);
ERROR
(
"Failed to create the network."
);
lxc_sync_fini
(
handler
);
lxc_sync_fini
(
handler
);
return
-
1
;
return
-
1
;
...
@@ -1429,7 +1430,7 @@ static int lxc_spawn(struct lxc_handler *handler)
...
@@ -1429,7 +1430,7 @@ static int lxc_spawn(struct lxc_handler *handler)
/* Create the network configuration. */
/* Create the network configuration. */
if
(
handler
->
clone_flags
&
CLONE_NEWNET
)
{
if
(
handler
->
clone_flags
&
CLONE_NEWNET
)
{
if
(
lxc_
assign
_network
(
handler
->
lxcpath
,
handler
->
name
,
if
(
lxc_
create
_network
(
handler
->
lxcpath
,
handler
->
name
,
&
handler
->
conf
->
network
,
handler
->
pid
))
{
&
handler
->
conf
->
network
,
handler
->
pid
))
{
ERROR
(
"Failed to create the configured network."
);
ERROR
(
"Failed to create the configured network."
);
goto
out_delete_net
;
goto
out_delete_net
;
...
...
src/tests/lxc-test-usernic.in
View file @
d3e7b8ad
...
@@ -153,7 +153,7 @@ lxcpath=/home/usernic-user/.local/share/lxc
...
@@ -153,7 +153,7 @@ lxcpath=/home/usernic-user/.local/share/lxc
lxcname
=
b1
lxcname
=
b1
# Assign one veth, should fail as no allowed entries yet
# Assign one veth, should fail as no allowed entries yet
if
run_cmd
"
$LXC_USER_NIC
$lxcpath
$lxcname
$p1
veth usernic-br0 xx1"
;
then
if
run_cmd
"
$LXC_USER_NIC
create
$lxcpath
$lxcname
$p1
veth usernic-br0 xx1"
;
then
echo
"FAIL: able to create nic with no entries"
echo
"FAIL: able to create nic with no entries"
exit
1
exit
1
fi
fi
...
@@ -164,24 +164,24 @@ sed -i '/^usernic-user/d' /etc/lxc/lxc-usernet
...
@@ -164,24 +164,24 @@ sed -i '/^usernic-user/d' /etc/lxc/lxc-usernet
echo
"usernic-user veth usernic-br0 2"
>>
/etc/lxc/lxc-usernet
echo
"usernic-user veth usernic-br0 2"
>>
/etc/lxc/lxc-usernet
# Assign one veth to second bridge, should fail
# Assign one veth to second bridge, should fail
if
run_cmd
"
$LXC_USER_NIC
$lxcpath
$lxcname
$p1
veth usernic-br1 xx1"
;
then
if
run_cmd
"
$LXC_USER_NIC
create
$lxcpath
$lxcname
$p1
veth usernic-br1 xx1"
;
then
echo
"FAIL: able to create nic with no entries"
echo
"FAIL: able to create nic with no entries"
exit
1
exit
1
fi
fi
# Assign two veths, should succeed
# Assign two veths, should succeed
if
!
run_cmd
"
$LXC_USER_NIC
$lxcpath
$lxcname
$p1
veth usernic-br0 xx2"
;
then
if
!
run_cmd
"
$LXC_USER_NIC
create
$lxcpath
$lxcname
$p1
veth usernic-br0 xx2"
;
then
echo
"FAIL: unable to create first nic"
echo
"FAIL: unable to create first nic"
exit
1
exit
1
fi
fi
if
!
run_cmd
"
$LXC_USER_NIC
$lxcpath
$lxcname
$p1
veth usernic-br0 xx3"
;
then
if
!
run_cmd
"
$LXC_USER_NIC
create
$lxcpath
$lxcname
$p1
veth usernic-br0 xx3"
;
then
echo
"FAIL: unable to create second nic"
echo
"FAIL: unable to create second nic"
exit
1
exit
1
fi
fi
# Assign one more veth, should fail.
# Assign one more veth, should fail.
if
run_cmd
"
$LXC_USER_NIC
$lxcpath
$lxcname
$p1
veth usernic-br0 xx4"
;
then
if
run_cmd
"
$LXC_USER_NIC
create
$lxcpath
$lxcname
$p1
veth usernic-br0 xx4"
;
then
echo
"FAIL: able to create third nic"
echo
"FAIL: able to create third nic"
exit
1
exit
1
fi
fi
...
@@ -191,7 +191,7 @@ run_cmd "lxc-stop -n b1 -k"
...
@@ -191,7 +191,7 @@ run_cmd "lxc-stop -n b1 -k"
run_cmd
"lxc-start -n b1 -d"
run_cmd
"lxc-start -n b1 -d"
p1
=
$(
run_cmd
"lxc-info -n b1 -p -H"
)
p1
=
$(
run_cmd
"lxc-info -n b1 -p -H"
)
if
!
run_cmd
"
$LXC_USER_NIC
$lxcpath
$lxcname
$p1
veth usernic-br0 xx5"
;
then
if
!
run_cmd
"
$LXC_USER_NIC
create
$lxcpath
$lxcname
$p1
veth usernic-br0 xx5"
;
then
echo
"FAIL: unable to create nic after destroying the old"
echo
"FAIL: unable to create nic after destroying the old"
cleanup 1
cleanup 1
fi
fi
...
@@ -204,7 +204,7 @@ lxc-start -n usernic-c1 -d
...
@@ -204,7 +204,7 @@ lxc-start -n usernic-c1 -d
p2
=
$(
lxc-info
-n
usernic-c1
-p
-H
)
p2
=
$(
lxc-info
-n
usernic-c1
-p
-H
)
# assign veth to it - should fail
# assign veth to it - should fail
if
run_cmd
"
$LXC_USER_NIC
$lxcpath
$lxcname
$p2
veth usernic-br0 xx6"
;
then
if
run_cmd
"
$LXC_USER_NIC
create
$lxcpath
$lxcname
$p2
veth usernic-br0 xx6"
;
then
echo
"FAIL: able to attach nic to root-owned container"
echo
"FAIL: able to attach nic to root-owned container"
cleanup 1
cleanup 1
fi
fi
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment