]> git.proxmox.com Git - mirror_lxc.git/blob - src/tests/share_ns.c
Replace 'which' with 'command -v' in tests too
[mirror_lxc.git] / src / tests / share_ns.c
1 /* liblxcapi
2 *
3 * Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _GNU_SOURCE
20 #include <alloca.h>
21 #include <errno.h>
22 #include <pthread.h>
23 #include <sched.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/reboot.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31
32 #include "lxc/lxccontainer.h"
33 #include "lxctest.h"
34 #include "../lxc/compiler.h"
35
36 #define TEST_DEFAULT_BUF_SIZE 256
37
38 struct thread_args {
39 int thread_id;
40 bool success;
41 pid_t init_pid;
42 char inherited_ipc_ns[TEST_DEFAULT_BUF_SIZE];
43 char inherited_net_ns[TEST_DEFAULT_BUF_SIZE];
44 };
45
46 __noreturn static void *ns_sharing_wrapper(void *data)
47 {
48 int init_pid;
49 ssize_t ret;
50 char name[100];
51 char owning_ns_init_pid[100];
52 char proc_ns_path[TEST_DEFAULT_BUF_SIZE];
53 char ns_buf[TEST_DEFAULT_BUF_SIZE];
54 struct lxc_container *c;
55 struct thread_args *args = data;
56
57 lxc_debug("Starting namespace sharing thread %d\n", args->thread_id);
58
59 sprintf(name, "share-ns-%d", args->thread_id);
60 c = lxc_container_new(name, NULL);
61 if (!c) {
62 lxc_error("Failed to create container \"%s\"\n", name);
63 goto out_pthread_exit;
64 }
65
66 if (c->is_defined(c)) {
67 lxc_error("Container \"%s\" is defined\n", name);
68 goto out;
69 }
70
71 if (!c->createl(c, "busybox", NULL, NULL, 0, NULL)) {
72 lxc_error("Failed to create busybox container \"%s\"\n", name);
73 goto out;
74 }
75
76 if (!c->is_defined(c)) {
77 lxc_error("Container \"%s\" is not defined\n", name);
78 goto out;
79 }
80
81 c->clear_config(c);
82
83 if (!c->load_config(c, NULL)) {
84 lxc_error("Failed to load config for container \"%s\"\n", name);
85 goto out;
86 }
87
88 /* share ipc namespace by container name */
89 if (!c->set_config_item(c, "lxc.namespace.share.ipc", "owning-ns")) {
90 lxc_error("Failed to set \"lxc.namespace.share.ipc=owning-ns\" for container \"%s\"\n", name);
91 goto out;
92 }
93
94 /* clear all network configuration */
95 if (!c->set_config_item(c, "lxc.net", "")) {
96 lxc_error("Failed to set \"lxc.namespace.share.ipc=owning-ns\" for container \"%s\"\n", name);
97 goto out;
98 }
99
100 if (!c->set_config_item(c, "lxc.net.0.type", "empty")) {
101 lxc_error("Failed to set \"lxc.net.0.type=empty\" for container \"%s\"\n", name);
102 goto out;
103 }
104
105 sprintf(owning_ns_init_pid, "%d", args->init_pid);
106 /* share net namespace by pid */
107 if (!c->set_config_item(c, "lxc.namespace.share.net", owning_ns_init_pid)) {
108 lxc_error("Failed to set \"lxc.namespace.share.net=%s\" for container \"%s\"\n", owning_ns_init_pid, name);
109 goto out;
110 }
111
112 if (!c->want_daemonize(c, true)) {
113 lxc_error("Failed to mark container \"%s\" daemonized\n", name);
114 goto out;
115 }
116
117 if (!c->startl(c, 0, NULL)) {
118 lxc_error("Failed to start container \"%s\" daemonized\n", name);
119 goto out;
120 }
121
122 init_pid = c->init_pid(c);
123 if (init_pid < 0) {
124 lxc_error("Failed to retrieve init pid of container \"%s\"\n", name);
125 goto out;
126 }
127
128 /* Check whether we correctly inherited the ipc namespace. */
129 ret = snprintf(proc_ns_path, sizeof(proc_ns_path), "/proc/%d/ns/ipc", init_pid);
130 if (ret < 0 || (size_t)ret >= sizeof(proc_ns_path)) {
131 lxc_error("Failed to create string for container \"%s\"\n", name);
132 goto out;
133 }
134
135 ret = readlink(proc_ns_path, ns_buf, sizeof(ns_buf));
136 if (ret < 0 || (size_t)ret >= sizeof(ns_buf)) {
137 lxc_error("Failed to retrieve ipc namespace for container \"%s\"\n", name);
138 goto out;
139 }
140 ns_buf[ret] = '\0';
141
142 if (strcmp(args->inherited_ipc_ns, ns_buf) != 0) {
143 lxc_error("Failed to inherit ipc namespace from container \"owning-ns\": %s != %s\n", args->inherited_ipc_ns, ns_buf);
144 goto out;
145 }
146 lxc_debug("Inherited ipc namespace from container \"owning-ns\": %s == %s\n", args->inherited_ipc_ns, ns_buf);
147
148 /* Check whether we correctly inherited the net namespace. */
149 ret = snprintf(proc_ns_path, sizeof(proc_ns_path), "/proc/%d/ns/net", init_pid);
150 if (ret < 0 || (size_t)ret >= sizeof(proc_ns_path)) {
151 lxc_error("Failed to create string for container \"%s\"\n", name);
152 goto out;
153 }
154
155 ret = readlink(proc_ns_path, ns_buf, sizeof(ns_buf));
156 if (ret < 0 || (size_t)ret >= sizeof(ns_buf)) {
157 lxc_error("Failed to retrieve ipc namespace for container \"%s\"\n", name);
158 goto out;
159 }
160 ns_buf[ret] = '\0';
161
162 if (strcmp(args->inherited_net_ns, ns_buf) != 0) {
163 lxc_error("Failed to inherit net namespace from container \"owning-ns\": %s != %s\n", args->inherited_net_ns, ns_buf);
164 goto out;
165 }
166 lxc_debug("Inherited net namespace from container \"owning-ns\": %s == %s\n", args->inherited_net_ns, ns_buf);
167
168 args->success = true;
169
170 out:
171 if (c->is_running(c) && !c->stop(c))
172 lxc_error("Failed to stop container \"%s\"\n", name);
173
174 if (!c->destroy(c))
175 lxc_error("Failed to destroy container \"%s\"\n", name);
176
177 lxc_container_put(c);
178
179 out_pthread_exit:
180 pthread_exit(NULL);
181 }
182
183 int main(int argc, char *argv[])
184 {
185 struct thread_args *args = NULL;
186 pthread_t *threads = NULL;
187 size_t nthreads = 10;
188 int i, init_pid, j;
189 char proc_ns_path[TEST_DEFAULT_BUF_SIZE];
190 char ipc_ns_buf[TEST_DEFAULT_BUF_SIZE];
191 char net_ns_buf[TEST_DEFAULT_BUF_SIZE];
192 pthread_attr_t attr;
193 struct lxc_container *c;
194 int ret = EXIT_FAILURE;
195
196 pthread_attr_init(&attr);
197
198 c = lxc_container_new("owning-ns", NULL);
199 if (!c) {
200 lxc_error("%s", "Failed to create container \"owning-ns\"");
201 exit(ret);
202 }
203
204 if (c->is_defined(c)) {
205 lxc_error("%s\n", "Container \"owning-ns\" is defined");
206 goto on_error_stop;
207 }
208
209 if (!c->createl(c, "busybox", NULL, NULL, 0, NULL)) {
210 lxc_error("%s\n", "Failed to create busybox container \"owning-ns\"");
211 goto on_error_stop;
212 }
213
214 if (!c->is_defined(c)) {
215 lxc_error("%s\n", "Container \"owning-ns\" is not defined");
216 goto on_error_stop;
217 }
218
219 c->clear_config(c);
220
221 if (!c->load_config(c, NULL)) {
222 lxc_error("%s\n", "Failed to load config for container \"owning-ns\"");
223 goto on_error_stop;
224 }
225
226 if (!c->want_daemonize(c, true)) {
227 lxc_error("%s\n", "Failed to mark container \"owning-ns\" daemonized");
228 goto on_error_stop;
229 }
230
231 if (!c->startl(c, 0, NULL)) {
232 lxc_error("%s\n", "Failed to start container \"owning-ns\" daemonized");
233 goto on_error_stop;
234 }
235
236 init_pid = c->init_pid(c);
237 if (init_pid < 0) {
238 lxc_error("%s\n", "Failed to retrieve init pid of container \"owning-ns\"");
239 goto on_error_stop;
240 }
241
242 /* record our ipc namespace */
243 ret = snprintf(proc_ns_path, sizeof(proc_ns_path), "/proc/%d/ns/ipc", init_pid);
244 if (ret < 0 || (size_t)ret >= sizeof(proc_ns_path)) {
245 lxc_error("%s\n", "Failed to create string for container \"owning-ns\"");
246 goto on_error_stop;
247 }
248
249 ret = readlink(proc_ns_path, ipc_ns_buf, sizeof(ipc_ns_buf));
250 if (ret < 0 || (size_t)ret >= sizeof(ipc_ns_buf)) {
251 lxc_error("%s\n", "Failed to retrieve ipc namespace for container \"owning-ns\"");
252 goto on_error_stop;
253
254 }
255 ipc_ns_buf[ret] = '\0';
256
257 /* record our net namespace */
258 ret = snprintf(proc_ns_path, sizeof(proc_ns_path), "/proc/%d/ns/net", init_pid);
259 if (ret < 0 || (size_t)ret >= sizeof(proc_ns_path)) {
260 lxc_error("%s\n", "Failed to create string for container \"owning-ns\"");
261 goto on_error_stop;
262 }
263
264 ret = readlink(proc_ns_path, net_ns_buf, sizeof(net_ns_buf));
265 if (ret < 0 || (size_t)ret >= sizeof(net_ns_buf)) {
266 lxc_error("%s\n", "Failed to retrieve ipc namespace for container \"owning-ns\"");
267 goto on_error_stop;
268 }
269 net_ns_buf[ret] = '\0';
270
271 sleep(5);
272
273 args = malloc(sizeof(struct thread_args) * nthreads);
274 if (!args) {
275 lxc_error("%s\n", "Failed to allocate memory");
276 goto on_error_stop;
277 }
278
279 threads = malloc(sizeof(pthread_t) * nthreads);
280 if (!threads) {
281 lxc_error("%s\n", "Failed to allocate memory");
282 goto on_error_stop;
283 }
284
285 for (j = 0; j < 10; j++) {
286 bool had_error = false;
287
288 lxc_debug("Starting namespace sharing test iteration %d\n", j);
289
290 for (i = 0; i < nthreads; i++) {
291 memset(&args[i], 0, sizeof(struct thread_args));
292 memset(&threads[i], 0, sizeof(pthread_t));
293
294 args[i].thread_id = i;
295 args[i].success = false;
296 args[i].init_pid = init_pid;
297 snprintf(args[i].inherited_ipc_ns, sizeof(args[i].inherited_ipc_ns), "%s", ipc_ns_buf);
298 snprintf(args[i].inherited_net_ns, sizeof(args[i].inherited_net_ns), "%s", net_ns_buf);
299
300 ret = pthread_create(&threads[i], &attr, ns_sharing_wrapper, (void *)&args[i]);
301 if (ret != 0)
302 goto on_error_stop;
303 }
304
305 for (i = 0; i < nthreads; i++) {
306 ret = pthread_join(threads[i], NULL);
307 if (ret != 0)
308 goto on_error_stop;
309
310 if (!args[i].success) {
311 lxc_error("ns sharing thread %d failed\n", args[i].thread_id);
312 had_error = true;
313 }
314 }
315
316 if (had_error)
317 goto on_error_stop;
318 }
319
320 ret = EXIT_SUCCESS;
321
322 on_error_stop:
323 free(args);
324 free(threads);
325 pthread_attr_destroy(&attr);
326
327 if (c->is_running(c) && !c->stop(c))
328 lxc_error("%s\n", "Failed to stop container \"owning-ns\"");
329
330 if (!c->destroy(c))
331 lxc_error("%s\n", "Failed to destroy container \"owning-ns\"");
332
333 lxc_container_put(c);
334 if (ret == EXIT_SUCCESS)
335 lxc_debug("%s\n", "All state namespace sharing tests passed");
336
337 exit(ret);
338 }