Line data Source code
1 : /*
2 : * Zebra NS collector and notifier for Network NameSpaces
3 : * Copyright (C) 2017 6WIND
4 : *
5 : * This program is free software; you can redistribute it and/or modify it
6 : * under the terms of the GNU General Public License as published by the Free
7 : * Software Foundation; either version 2 of the License, or (at your option)
8 : * any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 : * more details.
14 : *
15 : * You should have received a copy of the GNU General Public License along
16 : * with this program; see the file COPYING; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 : */
19 :
20 : #include <zebra.h>
21 :
22 : #ifdef HAVE_NETLINK
23 : #ifdef HAVE_NETNS
24 : #undef _GNU_SOURCE
25 : #define _GNU_SOURCE
26 :
27 : #include <sched.h>
28 : #endif
29 : #include <dirent.h>
30 : #include <sys/inotify.h>
31 : #include <sys/stat.h>
32 :
33 : #include "thread.h"
34 : #include "ns.h"
35 : #include "command.h"
36 : #include "memory.h"
37 : #include "lib_errors.h"
38 :
39 : #include "zebra_router.h"
40 : #endif /* defined(HAVE_NETLINK) */
41 :
42 : #include "zebra_netns_notify.h"
43 : #include "zebra_netns_id.h"
44 : #include "zebra_errors.h"
45 : #include "interface.h"
46 :
47 : #ifdef HAVE_NETLINK
48 :
49 : /* upon creation of folder under /var/run/netns,
50 : * wait that netns context is bound to
51 : * that folder 10 seconds
52 : */
53 : #define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000
54 : #define ZEBRA_NS_POLLING_MAX_RETRIES 200
55 :
56 3 : DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo");
57 : static struct thread *zebra_netns_notify_current;
58 :
59 : struct zebra_netns_info {
60 : const char *netnspath;
61 : unsigned int retries;
62 : };
63 :
64 : static void zebra_ns_ready_read(struct thread *t);
65 : static void zebra_ns_notify_create_context_from_entry_name(const char *name);
66 : static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
67 : int stop_retry);
68 : static void zebra_ns_notify_read(struct thread *t);
69 :
70 0 : static struct vrf *vrf_handler_create(struct vty *vty, const char *vrfname)
71 : {
72 0 : if (strlen(vrfname) > VRF_NAMSIZ) {
73 0 : flog_warn(EC_LIB_VRF_LENGTH,
74 : "%% VRF name %s invalid: length exceeds %d bytes",
75 : vrfname, VRF_NAMSIZ);
76 0 : return NULL;
77 : }
78 :
79 0 : return vrf_get(VRF_UNKNOWN, vrfname);
80 : }
81 :
82 0 : static void zebra_ns_notify_create_context_from_entry_name(const char *name)
83 : {
84 0 : char *netnspath = ns_netns_pathname(NULL, name);
85 0 : struct vrf *vrf;
86 0 : int ret;
87 0 : ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
88 0 : struct ns *default_ns;
89 :
90 0 : if (netnspath == NULL)
91 : return;
92 :
93 0 : frr_with_privs(&zserv_privs) {
94 0 : ns_id = zebra_ns_id_get(netnspath, -1);
95 : }
96 0 : if (ns_id == NS_UNKNOWN)
97 : return;
98 0 : ns_id_external = ns_map_nsid_with_external(ns_id, true);
99 : /* if VRF with NS ID already present */
100 0 : vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
101 0 : if (vrf) {
102 0 : zlog_debug(
103 : "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
104 : vrf->name, netnspath);
105 0 : return;
106 : }
107 0 : vrf = vrf_handler_create(NULL, name);
108 0 : if (!vrf) {
109 0 : flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
110 : "NS notify : failed to create VRF %s", name);
111 0 : ns_map_nsid_with_external(ns_id, false);
112 0 : return;
113 : }
114 :
115 0 : default_ns = ns_get_default();
116 :
117 : /* force kernel ns_id creation in that new vrf */
118 0 : frr_with_privs(&zserv_privs) {
119 0 : ns_switch_to_netns(netnspath);
120 0 : ns_id_relative = zebra_ns_id_get(NULL, default_ns->fd);
121 0 : ns_switchback_to_initial();
122 : }
123 :
124 0 : frr_with_privs(&zserv_privs) {
125 0 : ret = zebra_vrf_netns_handler_create(NULL, vrf, netnspath,
126 : ns_id_external, ns_id,
127 : ns_id_relative);
128 : }
129 0 : if (ret != CMD_SUCCESS) {
130 0 : flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
131 : "NS notify : failed to create NS %s", netnspath);
132 0 : ns_map_nsid_with_external(ns_id, false);
133 0 : vrf_delete(vrf);
134 0 : return;
135 : }
136 0 : zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
137 : }
138 :
139 0 : static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
140 : int stop_retry)
141 : {
142 0 : void *ns_path_ptr = (void *)zns_info->netnspath;
143 :
144 0 : if (stop_retry) {
145 0 : XFREE(MTYPE_NETNS_MISC, ns_path_ptr);
146 0 : XFREE(MTYPE_NETNS_MISC, zns_info);
147 0 : return 0;
148 : }
149 0 : thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
150 : (void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC,
151 : NULL);
152 0 : return 0;
153 : }
154 :
155 0 : static int zebra_ns_delete(char *name)
156 : {
157 0 : struct vrf *vrf = vrf_lookup_by_name(name);
158 0 : struct interface *ifp, *tmp;
159 0 : struct ns *ns;
160 :
161 0 : if (!vrf) {
162 0 : flog_warn(EC_ZEBRA_NS_DELETION_FAILED_NO_VRF,
163 : "NS notify : no VRF found using NS %s", name);
164 0 : return 0;
165 : }
166 :
167 : /*
168 : * We don't receive interface down/delete notifications from kernel
169 : * when a netns is deleted. Therefore we have to manually replicate
170 : * the necessary actions here.
171 : */
172 0 : RB_FOREACH_SAFE (ifp, if_name_head, &vrf->ifaces_by_name, tmp) {
173 0 : if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE))
174 0 : continue;
175 :
176 0 : if (if_is_no_ptm_operative(ifp)) {
177 0 : UNSET_FLAG(ifp->flags, IFF_RUNNING);
178 0 : if_down(ifp);
179 : }
180 :
181 0 : UNSET_FLAG(ifp->flags, IFF_UP);
182 0 : if_delete_update(&ifp);
183 : }
184 :
185 0 : ns = (struct ns *)vrf->ns_ctxt;
186 : /* the deletion order is the same
187 : * as the one used when siging signal is received
188 : */
189 0 : vrf->ns_ctxt = NULL;
190 0 : vrf_delete(vrf);
191 0 : if (ns)
192 0 : ns_delete(ns);
193 :
194 0 : zlog_info("NS notify : deleted VRF %s", name);
195 0 : return 0;
196 : }
197 :
198 0 : static int zebra_ns_notify_self_identify(struct stat *netst)
199 : {
200 0 : char net_path[PATH_MAX];
201 0 : int netns;
202 :
203 0 : snprintf(net_path, sizeof(net_path), "/proc/self/ns/net");
204 0 : netns = open(net_path, O_RDONLY);
205 0 : if (netns < 0)
206 : return -1;
207 0 : if (fstat(netns, netst) < 0) {
208 0 : close(netns);
209 0 : return -1;
210 : }
211 0 : close(netns);
212 0 : return 0;
213 : }
214 :
215 0 : static bool zebra_ns_notify_is_default_netns(const char *name)
216 : {
217 0 : struct stat default_netns_stat;
218 0 : struct stat st;
219 0 : char netnspath[PATH_MAX];
220 :
221 0 : if (zebra_ns_notify_self_identify(&default_netns_stat))
222 : return false;
223 :
224 0 : memset(&st, 0, sizeof(st));
225 0 : snprintf(netnspath, sizeof(netnspath), "%s/%s", NS_RUN_DIR, name);
226 : /* compare with local stat */
227 0 : if (stat(netnspath, &st) == 0 &&
228 0 : (st.st_dev == default_netns_stat.st_dev) &&
229 0 : (st.st_ino == default_netns_stat.st_ino))
230 : return true;
231 : return false;
232 : }
233 :
234 0 : static void zebra_ns_ready_read(struct thread *t)
235 : {
236 0 : struct zebra_netns_info *zns_info = THREAD_ARG(t);
237 0 : const char *netnspath;
238 0 : int err, stop_retry = 0;
239 :
240 0 : if (!zns_info)
241 : return;
242 0 : if (!zns_info->netnspath) {
243 0 : XFREE(MTYPE_NETNS_MISC, zns_info);
244 0 : return;
245 : }
246 0 : netnspath = zns_info->netnspath;
247 0 : if (--zns_info->retries == 0)
248 0 : stop_retry = 1;
249 0 : frr_with_privs(&zserv_privs) {
250 0 : err = ns_switch_to_netns(netnspath);
251 : }
252 0 : if (err < 0) {
253 0 : zebra_ns_continue_read(zns_info, stop_retry);
254 0 : return;
255 : }
256 :
257 : /* go back to default ns */
258 0 : frr_with_privs(&zserv_privs) {
259 0 : err = ns_switchback_to_initial();
260 : }
261 0 : if (err < 0) {
262 0 : zebra_ns_continue_read(zns_info, stop_retry);
263 0 : return;
264 : }
265 :
266 : /* check default name is not already set */
267 0 : if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) {
268 0 : zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath));
269 0 : zebra_ns_continue_read(zns_info, 1);
270 0 : return;
271 : }
272 0 : if (zebra_ns_notify_is_default_netns(basename(netnspath))) {
273 0 : zlog_warn(
274 : "NS notify : NS %s is default VRF. Ignore VRF creation",
275 : basename(netnspath));
276 0 : zebra_ns_continue_read(zns_info, 1);
277 0 : return;
278 : }
279 :
280 : /* success : close fd and create zns context */
281 0 : zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
282 0 : zebra_ns_continue_read(zns_info, 1);
283 : }
284 :
285 0 : static void zebra_ns_notify_read(struct thread *t)
286 : {
287 0 : int fd_monitor = THREAD_FD(t);
288 0 : struct inotify_event *event;
289 0 : char buf[BUFSIZ];
290 0 : ssize_t len;
291 0 : char event_name[NAME_MAX + 1];
292 :
293 0 : thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
294 : &zebra_netns_notify_current);
295 0 : len = read(fd_monitor, buf, sizeof(buf));
296 0 : if (len < 0) {
297 0 : flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
298 : "NS notify read: failed to read (%s)",
299 : safe_strerror(errno));
300 0 : return;
301 : }
302 0 : for (event = (struct inotify_event *)buf; (char *)event < &buf[len];
303 0 : event = (struct inotify_event *)((char *)event + sizeof(*event)
304 0 : + event->len)) {
305 0 : char *netnspath;
306 0 : struct zebra_netns_info *netnsinfo;
307 :
308 0 : if (!(event->mask & (IN_CREATE | IN_DELETE)))
309 0 : continue;
310 :
311 0 : if (offsetof(struct inotify_event, name) + event->len
312 : >= sizeof(buf)) {
313 0 : flog_err(EC_ZEBRA_NS_NOTIFY_READ,
314 : "NS notify read: buffer underflow");
315 0 : break;
316 : }
317 :
318 0 : if (strnlen(event->name, event->len) == event->len) {
319 0 : flog_err(EC_ZEBRA_NS_NOTIFY_READ,
320 : "NS notify error: bad event name");
321 0 : break;
322 : }
323 :
324 : /*
325 : * Coverity Scan extra steps to satisfy `STRING_NULL` warning:
326 : * - Make sure event name is present by checking `len != 0`
327 : * - Event name length must be at most `NAME_MAX + 1`
328 : * (null byte inclusive)
329 : * - Copy event name to a stack buffer to make sure it
330 : * includes the null byte. `event->name` includes at least
331 : * one null byte and `event->len` accounts the null bytes,
332 : * so the operation after `memcpy` will look like a
333 : * truncation to satisfy Coverity Scan null byte ending.
334 : *
335 : * Example:
336 : * if `event->name` is `abc\0` and `event->len` is 4,
337 : * `memcpy` will copy the 4 bytes and then we set the
338 : * null byte again at the position 4.
339 : *
340 : * For more information please read inotify(7) man page.
341 : */
342 0 : if (event->len == 0)
343 0 : continue;
344 :
345 0 : if (event->len > sizeof(event_name)) {
346 0 : flog_err(EC_ZEBRA_NS_NOTIFY_READ,
347 : "NS notify error: unexpected big event name");
348 0 : break;
349 : }
350 :
351 0 : memcpy(event_name, event->name, event->len);
352 0 : event_name[event->len - 1] = 0;
353 :
354 0 : if (event->mask & IN_DELETE) {
355 0 : zebra_ns_delete(event_name);
356 0 : continue;
357 : }
358 0 : netnspath = ns_netns_pathname(NULL, event_name);
359 0 : if (!netnspath)
360 0 : continue;
361 0 : netnspath = XSTRDUP(MTYPE_NETNS_MISC, netnspath);
362 0 : netnsinfo = XCALLOC(MTYPE_NETNS_MISC,
363 : sizeof(struct zebra_netns_info));
364 0 : netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES;
365 0 : netnsinfo->netnspath = netnspath;
366 0 : thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
367 : (void *)netnsinfo, 0, NULL);
368 : }
369 : }
370 :
371 0 : void zebra_ns_notify_parse(void)
372 : {
373 0 : struct dirent *dent;
374 0 : DIR *srcdir = opendir(NS_RUN_DIR);
375 :
376 0 : if (srcdir == NULL) {
377 0 : flog_err_sys(EC_LIB_SYSTEM_CALL,
378 : "NS parsing init: failed to parse %s", NS_RUN_DIR);
379 0 : return;
380 : }
381 0 : while ((dent = readdir(srcdir)) != NULL) {
382 0 : struct stat st;
383 :
384 0 : if (strcmp(dent->d_name, ".") == 0
385 0 : || strcmp(dent->d_name, "..") == 0)
386 0 : continue;
387 0 : if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
388 0 : flog_err_sys(
389 : EC_LIB_SYSTEM_CALL,
390 : "NS parsing init: failed to parse entry %s",
391 : dent->d_name);
392 0 : continue;
393 : }
394 0 : if (S_ISDIR(st.st_mode)) {
395 0 : zlog_debug("NS parsing init: %s is not a NS",
396 : dent->d_name);
397 0 : continue;
398 : }
399 : /* check default name is not already set */
400 0 : if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) {
401 0 : zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name);
402 0 : continue;
403 : }
404 0 : if (zebra_ns_notify_is_default_netns(dent->d_name)) {
405 0 : zlog_warn(
406 : "NS notify : NS %s is default VRF. Ignore VRF creation",
407 : dent->d_name);
408 0 : continue;
409 : }
410 0 : zebra_ns_notify_create_context_from_entry_name(dent->d_name);
411 : }
412 0 : closedir(srcdir);
413 : }
414 :
415 0 : void zebra_ns_notify_init(void)
416 : {
417 0 : int fd_monitor;
418 :
419 0 : fd_monitor = inotify_init();
420 0 : if (fd_monitor < 0) {
421 0 : flog_err_sys(
422 : EC_LIB_SYSTEM_CALL,
423 : "NS notify init: failed to initialize inotify (%s)",
424 : safe_strerror(errno));
425 : }
426 0 : if (inotify_add_watch(fd_monitor, NS_RUN_DIR,
427 : IN_CREATE | IN_DELETE) < 0) {
428 0 : flog_err_sys(EC_LIB_SYSTEM_CALL,
429 : "NS notify watch: failed to add watch (%s)",
430 : safe_strerror(errno));
431 : }
432 0 : thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
433 : &zebra_netns_notify_current);
434 0 : }
435 :
436 1 : void zebra_ns_notify_close(void)
437 : {
438 1 : if (zebra_netns_notify_current == NULL)
439 : return;
440 :
441 0 : int fd = 0;
442 :
443 0 : if (zebra_netns_notify_current->u.fd > 0)
444 : fd = zebra_netns_notify_current->u.fd;
445 :
446 0 : if (zebra_netns_notify_current->master != NULL)
447 0 : THREAD_OFF(zebra_netns_notify_current);
448 :
449 : /* auto-removal of notify items */
450 0 : if (fd > 0)
451 0 : close(fd);
452 : }
453 :
454 : #else
455 : void zebra_ns_notify_parse(void)
456 : {
457 : }
458 :
459 : void zebra_ns_notify_init(void)
460 : {
461 : }
462 :
463 : void zebra_ns_notify_close(void)
464 : {
465 : }
466 : #endif /* !HAVE_NETLINK */
|