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 event
*zebra_netns_notify_current
;
46 struct zebra_netns_info
{
47 const char *netnspath
;
51 static void zebra_ns_ready_read(struct event
*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 event
*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 if (IS_ZEBRA_IF_BOND(ifp
))
169 zebra_l2if_update_bond(ifp
, false);
170 if (IS_ZEBRA_IF_BOND_SLAVE(ifp
))
171 zebra_l2if_update_bond_slave(ifp
, IFINDEX_INTERNAL
,
173 /* Special handling for bridge or VxLAN interfaces. */
174 if (IS_ZEBRA_IF_BRIDGE(ifp
))
175 zebra_l2_bridge_del(ifp
);
176 else if (IS_ZEBRA_IF_VXLAN(ifp
))
177 zebra_l2_vxlanif_del(ifp
);
179 UNSET_FLAG(ifp
->flags
, IFF_UP
);
180 if_delete_update(&ifp
);
183 ns
= (struct ns
*)vrf
->ns_ctxt
;
184 /* the deletion order is the same
185 * as the one used when siging signal is received
192 zlog_info("NS notify : deleted VRF %s", name
);
196 static int zebra_ns_notify_self_identify(struct stat
*netst
)
198 char net_path
[PATH_MAX
];
201 snprintf(net_path
, sizeof(net_path
), "/proc/self/ns/net");
202 netns
= open(net_path
, O_RDONLY
);
205 if (fstat(netns
, netst
) < 0) {
213 static bool zebra_ns_notify_is_default_netns(const char *name
)
215 struct stat default_netns_stat
;
217 char netnspath
[PATH_MAX
];
219 if (zebra_ns_notify_self_identify(&default_netns_stat
))
222 memset(&st
, 0, sizeof(st
));
223 snprintf(netnspath
, sizeof(netnspath
), "%s/%s", NS_RUN_DIR
, name
);
224 /* compare with local stat */
225 if (stat(netnspath
, &st
) == 0 &&
226 (st
.st_dev
== default_netns_stat
.st_dev
) &&
227 (st
.st_ino
== default_netns_stat
.st_ino
))
232 static void zebra_ns_ready_read(struct event
*t
)
234 struct zebra_netns_info
*zns_info
= THREAD_ARG(t
);
235 const char *netnspath
;
236 int err
, stop_retry
= 0;
240 if (!zns_info
->netnspath
) {
241 XFREE(MTYPE_NETNS_MISC
, zns_info
);
244 netnspath
= zns_info
->netnspath
;
245 if (--zns_info
->retries
== 0)
247 frr_with_privs(&zserv_privs
) {
248 err
= ns_switch_to_netns(netnspath
);
251 zebra_ns_continue_read(zns_info
, stop_retry
);
255 /* go back to default ns */
256 frr_with_privs(&zserv_privs
) {
257 err
= ns_switchback_to_initial();
260 zebra_ns_continue_read(zns_info
, stop_retry
);
264 /* check default name is not already set */
265 if (strmatch(VRF_DEFAULT_NAME
, basename(netnspath
))) {
266 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath
));
267 zebra_ns_continue_read(zns_info
, 1);
270 if (zebra_ns_notify_is_default_netns(basename(netnspath
))) {
272 "NS notify : NS %s is default VRF. Ignore VRF creation",
273 basename(netnspath
));
274 zebra_ns_continue_read(zns_info
, 1);
278 /* success : close fd and create zns context */
279 zebra_ns_notify_create_context_from_entry_name(basename(netnspath
));
280 zebra_ns_continue_read(zns_info
, 1);
283 static void zebra_ns_notify_read(struct event
*t
)
285 int fd_monitor
= THREAD_FD(t
);
286 struct inotify_event
*event
;
289 char event_name
[NAME_MAX
+ 1];
291 thread_add_read(zrouter
.master
, zebra_ns_notify_read
, NULL
, fd_monitor
,
292 &zebra_netns_notify_current
);
293 len
= read(fd_monitor
, buf
, sizeof(buf
));
295 flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ
,
296 "NS notify read: failed to read (%s)",
297 safe_strerror(errno
));
300 for (event
= (struct inotify_event
*)buf
; (char *)event
< &buf
[len
];
301 event
= (struct inotify_event
*)((char *)event
+ sizeof(*event
)
304 struct zebra_netns_info
*netnsinfo
;
306 if (!(event
->mask
& (IN_CREATE
| IN_DELETE
)))
309 if (offsetof(struct inotify_event
, name
) + event
->len
311 flog_err(EC_ZEBRA_NS_NOTIFY_READ
,
312 "NS notify read: buffer underflow");
316 if (strnlen(event
->name
, event
->len
) == event
->len
) {
317 flog_err(EC_ZEBRA_NS_NOTIFY_READ
,
318 "NS notify error: bad event name");
323 * Coverity Scan extra steps to satisfy `STRING_NULL` warning:
324 * - Make sure event name is present by checking `len != 0`
325 * - Event name length must be at most `NAME_MAX + 1`
326 * (null byte inclusive)
327 * - Copy event name to a stack buffer to make sure it
328 * includes the null byte. `event->name` includes at least
329 * one null byte and `event->len` accounts the null bytes,
330 * so the operation after `memcpy` will look like a
331 * truncation to satisfy Coverity Scan null byte ending.
334 * if `event->name` is `abc\0` and `event->len` is 4,
335 * `memcpy` will copy the 4 bytes and then we set the
336 * null byte again at the position 4.
338 * For more information please read inotify(7) man page.
343 if (event
->len
> sizeof(event_name
)) {
344 flog_err(EC_ZEBRA_NS_NOTIFY_READ
,
345 "NS notify error: unexpected big event name");
349 memcpy(event_name
, event
->name
, event
->len
);
350 event_name
[event
->len
- 1] = 0;
352 if (event
->mask
& IN_DELETE
) {
353 zebra_ns_delete(event_name
);
356 netnspath
= ns_netns_pathname(NULL
, event_name
);
359 netnspath
= XSTRDUP(MTYPE_NETNS_MISC
, netnspath
);
360 netnsinfo
= XCALLOC(MTYPE_NETNS_MISC
,
361 sizeof(struct zebra_netns_info
));
362 netnsinfo
->retries
= ZEBRA_NS_POLLING_MAX_RETRIES
;
363 netnsinfo
->netnspath
= netnspath
;
364 thread_add_timer_msec(zrouter
.master
, zebra_ns_ready_read
,
365 (void *)netnsinfo
, 0, NULL
);
369 void zebra_ns_notify_parse(void)
372 DIR *srcdir
= opendir(NS_RUN_DIR
);
374 if (srcdir
== NULL
) {
375 flog_err_sys(EC_LIB_SYSTEM_CALL
,
376 "NS parsing init: failed to parse %s", NS_RUN_DIR
);
379 while ((dent
= readdir(srcdir
)) != NULL
) {
382 if (strcmp(dent
->d_name
, ".") == 0
383 || strcmp(dent
->d_name
, "..") == 0)
385 if (fstatat(dirfd(srcdir
), dent
->d_name
, &st
, 0) < 0) {
388 "NS parsing init: failed to parse entry %s",
392 if (S_ISDIR(st
.st_mode
)) {
393 zlog_debug("NS parsing init: %s is not a NS",
397 /* check default name is not already set */
398 if (strmatch(VRF_DEFAULT_NAME
, basename(dent
->d_name
))) {
399 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent
->d_name
);
402 if (zebra_ns_notify_is_default_netns(dent
->d_name
)) {
404 "NS notify : NS %s is default VRF. Ignore VRF creation",
408 zebra_ns_notify_create_context_from_entry_name(dent
->d_name
);
413 void zebra_ns_notify_init(void)
417 fd_monitor
= inotify_init();
418 if (fd_monitor
< 0) {
421 "NS notify init: failed to initialize inotify (%s)",
422 safe_strerror(errno
));
424 if (inotify_add_watch(fd_monitor
, NS_RUN_DIR
,
425 IN_CREATE
| IN_DELETE
) < 0) {
426 flog_err_sys(EC_LIB_SYSTEM_CALL
,
427 "NS notify watch: failed to add watch (%s)",
428 safe_strerror(errno
));
430 thread_add_read(zrouter
.master
, zebra_ns_notify_read
, NULL
, fd_monitor
,
431 &zebra_netns_notify_current
);
434 void zebra_ns_notify_close(void)
436 if (zebra_netns_notify_current
== NULL
)
441 if (zebra_netns_notify_current
->u
.fd
> 0)
442 fd
= zebra_netns_notify_current
->u
.fd
;
444 if (zebra_netns_notify_current
->master
!= NULL
)
445 THREAD_OFF(zebra_netns_notify_current
);
447 /* auto-removal of notify items */
453 void zebra_ns_notify_parse(void)
457 void zebra_ns_notify_init(void)
461 void zebra_ns_notify_close(void)
464 #endif /* !HAVE_NETLINK */