1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Zebra NS collector and notifier for Network NameSpaces
4 * Copyright (C) 2017 6WIND
17 #include <sys/inotify.h>
24 #include "lib_errors.h"
26 #include "zebra_router.h"
27 #endif /* defined(HAVE_NETLINK) */
29 #include "zebra_netns_notify.h"
30 #include "zebra_netns_id.h"
31 #include "zebra_errors.h"
32 #include "interface.h"
36 /* upon creation of folder under /var/run/netns,
37 * wait that netns context is bound to
38 * that folder 10 seconds
40 #define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000
41 #define ZEBRA_NS_POLLING_MAX_RETRIES 200
43 DEFINE_MTYPE_STATIC(ZEBRA
, NETNS_MISC
, "ZebraNetNSInfo");
44 static struct thread
*zebra_netns_notify_current
;
46 struct zebra_netns_info
{
47 const char *netnspath
;
51 static void zebra_ns_ready_read(struct thread
*t
);
52 static void zebra_ns_notify_create_context_from_entry_name(const char *name
);
53 static int zebra_ns_continue_read(struct zebra_netns_info
*zns_info
,
55 static void zebra_ns_notify_read(struct thread
*t
);
57 static struct vrf
*vrf_handler_create(struct vty
*vty
, const char *vrfname
)
59 if (strlen(vrfname
) > VRF_NAMSIZ
) {
60 flog_warn(EC_LIB_VRF_LENGTH
,
61 "%% VRF name %s invalid: length exceeds %d bytes",
66 return vrf_get(VRF_UNKNOWN
, vrfname
);
69 static void zebra_ns_notify_create_context_from_entry_name(const char *name
)
71 char *netnspath
= ns_netns_pathname(NULL
, name
);
74 ns_id_t ns_id
, ns_id_external
, ns_id_relative
= NS_UNKNOWN
;
75 struct ns
*default_ns
;
77 if (netnspath
== NULL
)
80 frr_with_privs(&zserv_privs
) {
81 ns_id
= zebra_ns_id_get(netnspath
, -1);
83 if (ns_id
== NS_UNKNOWN
)
85 ns_id_external
= ns_map_nsid_with_external(ns_id
, true);
86 /* if VRF with NS ID already present */
87 vrf
= vrf_lookup_by_id((vrf_id_t
)ns_id_external
);
90 "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
91 vrf
->name
, netnspath
);
94 vrf
= vrf_handler_create(NULL
, name
);
96 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED
,
97 "NS notify : failed to create VRF %s", name
);
98 ns_map_nsid_with_external(ns_id
, false);
102 default_ns
= ns_get_default();
104 /* force kernel ns_id creation in that new vrf */
105 frr_with_privs(&zserv_privs
) {
106 ns_switch_to_netns(netnspath
);
107 ns_id_relative
= zebra_ns_id_get(NULL
, default_ns
->fd
);
108 ns_switchback_to_initial();
111 frr_with_privs(&zserv_privs
) {
112 ret
= zebra_vrf_netns_handler_create(NULL
, vrf
, netnspath
,
113 ns_id_external
, ns_id
,
116 if (ret
!= CMD_SUCCESS
) {
117 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED
,
118 "NS notify : failed to create NS %s", netnspath
);
119 ns_map_nsid_with_external(ns_id
, false);
123 zlog_info("NS notify : created VRF %s NS %s", name
, netnspath
);
126 static int zebra_ns_continue_read(struct zebra_netns_info
*zns_info
,
129 void *ns_path_ptr
= (void *)zns_info
->netnspath
;
132 XFREE(MTYPE_NETNS_MISC
, ns_path_ptr
);
133 XFREE(MTYPE_NETNS_MISC
, zns_info
);
136 thread_add_timer_msec(zrouter
.master
, zebra_ns_ready_read
,
137 (void *)zns_info
, ZEBRA_NS_POLLING_INTERVAL_MSEC
,
142 static int zebra_ns_delete(char *name
)
144 struct vrf
*vrf
= vrf_lookup_by_name(name
);
145 struct interface
*ifp
, *tmp
;
149 flog_warn(EC_ZEBRA_NS_DELETION_FAILED_NO_VRF
,
150 "NS notify : no VRF found using NS %s", name
);
155 * We don't receive interface down/delete notifications from kernel
156 * when a netns is deleted. Therefore we have to manually replicate
157 * the necessary actions here.
159 RB_FOREACH_SAFE (ifp
, if_name_head
, &vrf
->ifaces_by_name
, tmp
) {
160 if (!CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_ACTIVE
))
163 if (if_is_no_ptm_operative(ifp
)) {
164 UNSET_FLAG(ifp
->flags
, IFF_RUNNING
);
168 UNSET_FLAG(ifp
->flags
, IFF_UP
);
169 if_delete_update(&ifp
);
172 ns
= (struct ns
*)vrf
->ns_ctxt
;
173 /* the deletion order is the same
174 * as the one used when siging signal is received
181 zlog_info("NS notify : deleted VRF %s", name
);
185 static int zebra_ns_notify_self_identify(struct stat
*netst
)
187 char net_path
[PATH_MAX
];
190 snprintf(net_path
, sizeof(net_path
), "/proc/self/ns/net");
191 netns
= open(net_path
, O_RDONLY
);
194 if (fstat(netns
, netst
) < 0) {
202 static bool zebra_ns_notify_is_default_netns(const char *name
)
204 struct stat default_netns_stat
;
206 char netnspath
[PATH_MAX
];
208 if (zebra_ns_notify_self_identify(&default_netns_stat
))
211 memset(&st
, 0, sizeof(st
));
212 snprintf(netnspath
, sizeof(netnspath
), "%s/%s", NS_RUN_DIR
, name
);
213 /* compare with local stat */
214 if (stat(netnspath
, &st
) == 0 &&
215 (st
.st_dev
== default_netns_stat
.st_dev
) &&
216 (st
.st_ino
== default_netns_stat
.st_ino
))
221 static void zebra_ns_ready_read(struct thread
*t
)
223 struct zebra_netns_info
*zns_info
= THREAD_ARG(t
);
224 const char *netnspath
;
225 int err
, stop_retry
= 0;
229 if (!zns_info
->netnspath
) {
230 XFREE(MTYPE_NETNS_MISC
, zns_info
);
233 netnspath
= zns_info
->netnspath
;
234 if (--zns_info
->retries
== 0)
236 frr_with_privs(&zserv_privs
) {
237 err
= ns_switch_to_netns(netnspath
);
240 zebra_ns_continue_read(zns_info
, stop_retry
);
244 /* go back to default ns */
245 frr_with_privs(&zserv_privs
) {
246 err
= ns_switchback_to_initial();
249 zebra_ns_continue_read(zns_info
, stop_retry
);
253 /* check default name is not already set */
254 if (strmatch(VRF_DEFAULT_NAME
, basename(netnspath
))) {
255 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath
));
256 zebra_ns_continue_read(zns_info
, 1);
259 if (zebra_ns_notify_is_default_netns(basename(netnspath
))) {
261 "NS notify : NS %s is default VRF. Ignore VRF creation",
262 basename(netnspath
));
263 zebra_ns_continue_read(zns_info
, 1);
267 /* success : close fd and create zns context */
268 zebra_ns_notify_create_context_from_entry_name(basename(netnspath
));
269 zebra_ns_continue_read(zns_info
, 1);
272 static void zebra_ns_notify_read(struct thread
*t
)
274 int fd_monitor
= THREAD_FD(t
);
275 struct inotify_event
*event
;
278 char event_name
[NAME_MAX
+ 1];
280 thread_add_read(zrouter
.master
, zebra_ns_notify_read
, NULL
, fd_monitor
,
281 &zebra_netns_notify_current
);
282 len
= read(fd_monitor
, buf
, sizeof(buf
));
284 flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ
,
285 "NS notify read: failed to read (%s)",
286 safe_strerror(errno
));
289 for (event
= (struct inotify_event
*)buf
; (char *)event
< &buf
[len
];
290 event
= (struct inotify_event
*)((char *)event
+ sizeof(*event
)
293 struct zebra_netns_info
*netnsinfo
;
295 if (!(event
->mask
& (IN_CREATE
| IN_DELETE
)))
298 if (offsetof(struct inotify_event
, name
) + event
->len
300 flog_err(EC_ZEBRA_NS_NOTIFY_READ
,
301 "NS notify read: buffer underflow");
305 if (strnlen(event
->name
, event
->len
) == event
->len
) {
306 flog_err(EC_ZEBRA_NS_NOTIFY_READ
,
307 "NS notify error: bad event name");
312 * Coverity Scan extra steps to satisfy `STRING_NULL` warning:
313 * - Make sure event name is present by checking `len != 0`
314 * - Event name length must be at most `NAME_MAX + 1`
315 * (null byte inclusive)
316 * - Copy event name to a stack buffer to make sure it
317 * includes the null byte. `event->name` includes at least
318 * one null byte and `event->len` accounts the null bytes,
319 * so the operation after `memcpy` will look like a
320 * truncation to satisfy Coverity Scan null byte ending.
323 * if `event->name` is `abc\0` and `event->len` is 4,
324 * `memcpy` will copy the 4 bytes and then we set the
325 * null byte again at the position 4.
327 * For more information please read inotify(7) man page.
332 if (event
->len
> sizeof(event_name
)) {
333 flog_err(EC_ZEBRA_NS_NOTIFY_READ
,
334 "NS notify error: unexpected big event name");
338 memcpy(event_name
, event
->name
, event
->len
);
339 event_name
[event
->len
- 1] = 0;
341 if (event
->mask
& IN_DELETE
) {
342 zebra_ns_delete(event_name
);
345 netnspath
= ns_netns_pathname(NULL
, event_name
);
348 netnspath
= XSTRDUP(MTYPE_NETNS_MISC
, netnspath
);
349 netnsinfo
= XCALLOC(MTYPE_NETNS_MISC
,
350 sizeof(struct zebra_netns_info
));
351 netnsinfo
->retries
= ZEBRA_NS_POLLING_MAX_RETRIES
;
352 netnsinfo
->netnspath
= netnspath
;
353 thread_add_timer_msec(zrouter
.master
, zebra_ns_ready_read
,
354 (void *)netnsinfo
, 0, NULL
);
358 void zebra_ns_notify_parse(void)
361 DIR *srcdir
= opendir(NS_RUN_DIR
);
363 if (srcdir
== NULL
) {
364 flog_err_sys(EC_LIB_SYSTEM_CALL
,
365 "NS parsing init: failed to parse %s", NS_RUN_DIR
);
368 while ((dent
= readdir(srcdir
)) != NULL
) {
371 if (strcmp(dent
->d_name
, ".") == 0
372 || strcmp(dent
->d_name
, "..") == 0)
374 if (fstatat(dirfd(srcdir
), dent
->d_name
, &st
, 0) < 0) {
377 "NS parsing init: failed to parse entry %s",
381 if (S_ISDIR(st
.st_mode
)) {
382 zlog_debug("NS parsing init: %s is not a NS",
386 /* check default name is not already set */
387 if (strmatch(VRF_DEFAULT_NAME
, basename(dent
->d_name
))) {
388 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent
->d_name
);
391 if (zebra_ns_notify_is_default_netns(dent
->d_name
)) {
393 "NS notify : NS %s is default VRF. Ignore VRF creation",
397 zebra_ns_notify_create_context_from_entry_name(dent
->d_name
);
402 void zebra_ns_notify_init(void)
406 fd_monitor
= inotify_init();
407 if (fd_monitor
< 0) {
410 "NS notify init: failed to initialize inotify (%s)",
411 safe_strerror(errno
));
413 if (inotify_add_watch(fd_monitor
, NS_RUN_DIR
,
414 IN_CREATE
| IN_DELETE
) < 0) {
415 flog_err_sys(EC_LIB_SYSTEM_CALL
,
416 "NS notify watch: failed to add watch (%s)",
417 safe_strerror(errno
));
419 thread_add_read(zrouter
.master
, zebra_ns_notify_read
, NULL
, fd_monitor
,
420 &zebra_netns_notify_current
);
423 void zebra_ns_notify_close(void)
425 if (zebra_netns_notify_current
== NULL
)
430 if (zebra_netns_notify_current
->u
.fd
> 0)
431 fd
= zebra_netns_notify_current
->u
.fd
;
433 if (zebra_netns_notify_current
->master
!= NULL
)
434 THREAD_OFF(zebra_netns_notify_current
);
436 /* auto-removal of notify items */
442 void zebra_ns_notify_parse(void)
446 void zebra_ns_notify_init(void)
450 void zebra_ns_notify_close(void)
453 #endif /* !HAVE_NETLINK */