2 * Zebra NS collector and notifier for Network NameSpaces
3 * Copyright (C) 2017 6WIND
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)
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
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
30 #include <sys/inotify.h>
37 #include "lib_errors.h"
40 #include "zebra_memory.h"
41 #endif /* defined(HAVE_NETLINK) */
43 #include "zebra_netns_notify.h"
44 #include "zebra_netns_id.h"
48 /* upon creation of folder under /var/run/netns,
49 * wait that netns context is bound to
50 * that folder 10 seconds
52 #define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000
53 #define ZEBRA_NS_POLLING_MAX_RETRIES 200
55 DEFINE_MTYPE_STATIC(ZEBRA
, NETNS_MISC
, "ZebraNetNSInfo")
56 static struct thread
*zebra_netns_notify_current
;
58 struct zebra_netns_info
{
59 const char *netnspath
;
63 static int zebra_ns_ready_read(struct thread
*t
);
64 static void zebra_ns_notify_create_context_from_entry_name(const char *name
);
65 static int zebra_ns_continue_read(struct zebra_netns_info
*zns_info
,
67 static int zebra_ns_notify_read(struct thread
*t
);
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
;
76 if (netnspath
== NULL
)
79 frr_elevate_privs(&zserv_privs
) {
80 ns_id
= zebra_ns_id_get(netnspath
);
82 if (ns_id
== NS_UNKNOWN
)
84 ns_id_external
= ns_map_nsid_with_external(ns_id
, true);
85 /* if VRF with NS ID already present */
86 vrf
= vrf_lookup_by_id((vrf_id_t
)ns_id_external
);
89 "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
90 vrf
->name
, netnspath
);
93 if (vrf_handler_create(NULL
, name
, &vrf
) != CMD_SUCCESS
) {
94 zlog_warn("NS notify : failed to create VRF %s", name
);
95 ns_map_nsid_with_external(ns_id
, false);
98 frr_elevate_privs(&zserv_privs
) {
99 ret
= vrf_netns_handler_create(NULL
, vrf
, netnspath
,
100 ns_id_external
, ns_id
);
102 if (ret
!= CMD_SUCCESS
) {
103 zlog_warn("NS notify : failed to create NS %s", netnspath
);
104 ns_map_nsid_with_external(ns_id
, false);
108 zlog_info("NS notify : created VRF %s NS %s", name
, netnspath
);
111 static int zebra_ns_continue_read(struct zebra_netns_info
*zns_info
,
114 void *ns_path_ptr
= (void *)zns_info
->netnspath
;
117 XFREE(MTYPE_NETNS_MISC
, ns_path_ptr
);
118 XFREE(MTYPE_NETNS_MISC
, zns_info
);
121 thread_add_timer_msec(zebrad
.master
, zebra_ns_ready_read
,
122 (void *)zns_info
, ZEBRA_NS_POLLING_INTERVAL_MSEC
,
127 static int zebra_ns_delete(char *name
)
129 struct vrf
*vrf
= vrf_lookup_by_name(name
);
134 "NS notify : no VRF found using NS %s",
138 /* Clear configured flag and invoke delete. */
139 UNSET_FLAG(vrf
->status
, VRF_CONFIGURED
);
140 ns
= (struct ns
*)vrf
->ns_ctxt
;
141 /* the deletion order is the same
142 * as the one used when siging signal is received
148 zlog_info("NS notify : deleted VRF %s", name
);
152 static int zebra_ns_notify_self_identify(struct stat
*netst
)
157 sprintf(net_path
, "/proc/self/ns/net");
158 netns
= open(net_path
, O_RDONLY
);
161 if (fstat(netns
, netst
) < 0) {
169 static bool zebra_ns_notify_is_default_netns(const char *name
)
171 struct stat default_netns_stat
;
175 if (zebra_ns_notify_self_identify(&default_netns_stat
))
178 memset(&st
, 0, sizeof(struct stat
));
179 snprintf(netnspath
, 64, "%s/%s", NS_RUN_DIR
, name
);
180 /* compare with local stat */
181 if (stat(netnspath
, &st
) == 0 &&
182 (st
.st_dev
== default_netns_stat
.st_dev
) &&
183 (st
.st_ino
== default_netns_stat
.st_ino
))
188 static int zebra_ns_ready_read(struct thread
*t
)
190 struct zebra_netns_info
*zns_info
= THREAD_ARG(t
);
191 const char *netnspath
;
192 int err
, stop_retry
= 0;
196 if (!zns_info
->netnspath
) {
197 XFREE(MTYPE_NETNS_MISC
, zns_info
);
200 netnspath
= zns_info
->netnspath
;
201 if (--zns_info
->retries
== 0)
203 frr_elevate_privs(&zserv_privs
) {
204 err
= ns_switch_to_netns(netnspath
);
207 return zebra_ns_continue_read(zns_info
, stop_retry
);
209 /* go back to default ns */
210 frr_elevate_privs(&zserv_privs
) {
211 err
= ns_switchback_to_initial();
214 return zebra_ns_continue_read(zns_info
, stop_retry
);
216 if (zebra_ns_notify_is_default_netns(basename(netnspath
))) {
218 "NS notify : NS %s is default VRF."
219 " Updating VRF Name", basename(netnspath
));
220 vrf_set_default_name(basename(netnspath
));
221 return zebra_ns_continue_read(zns_info
, 1);
224 /* success : close fd and create zns context */
225 zebra_ns_notify_create_context_from_entry_name(basename(netnspath
));
226 return zebra_ns_continue_read(zns_info
, 1);
229 static int zebra_ns_notify_read(struct thread
*t
)
231 int fd_monitor
= THREAD_FD(t
);
232 struct inotify_event
*event
;
236 zebra_netns_notify_current
= thread_add_read(
237 zebrad
.master
, zebra_ns_notify_read
, NULL
, fd_monitor
, NULL
);
238 len
= read(fd_monitor
, buf
, sizeof(buf
));
240 zlog_warn("NS notify read: failed to read (%s)",
241 safe_strerror(errno
));
244 for (event
= (struct inotify_event
*)buf
; (char *)event
< &buf
[len
];
245 event
= (struct inotify_event
*)((char *)event
+ sizeof(*event
)
248 struct zebra_netns_info
*netnsinfo
;
250 if (!(event
->mask
& (IN_CREATE
| IN_DELETE
)))
252 if (event
->mask
& IN_DELETE
)
253 return zebra_ns_delete(event
->name
);
255 if (offsetof(struct inotify_event
, name
) + event
->len
257 zlog_err("NS notify read: buffer underflow");
261 if (strnlen(event
->name
, event
->len
) == event
->len
) {
262 zlog_err("NS notify error: bad event name");
266 netnspath
= ns_netns_pathname(NULL
, event
->name
);
269 netnspath
= XSTRDUP(MTYPE_NETNS_MISC
, netnspath
);
270 netnsinfo
= XCALLOC(MTYPE_NETNS_MISC
,
271 sizeof(struct zebra_netns_info
));
272 netnsinfo
->retries
= ZEBRA_NS_POLLING_MAX_RETRIES
;
273 netnsinfo
->netnspath
= netnspath
;
274 thread_add_timer_msec(zebrad
.master
, zebra_ns_ready_read
,
275 (void *)netnsinfo
, 0, NULL
);
280 void zebra_ns_notify_parse(void)
283 DIR *srcdir
= opendir(NS_RUN_DIR
);
285 if (srcdir
== NULL
) {
286 zlog_warn("NS parsing init: failed to parse %s", NS_RUN_DIR
);
289 while ((dent
= readdir(srcdir
)) != NULL
) {
292 if (strcmp(dent
->d_name
, ".") == 0
293 || strcmp(dent
->d_name
, "..") == 0)
295 if (fstatat(dirfd(srcdir
), dent
->d_name
, &st
, 0) < 0) {
296 zlog_warn("NS parsing init: failed to parse entry %s",
300 if (S_ISDIR(st
.st_mode
)) {
301 zlog_warn("NS parsing init: %s is not a NS",
305 if (zebra_ns_notify_is_default_netns(dent
->d_name
)) {
307 "NS notify : NS %s is default VRF."
308 " Updating VRF Name", dent
->d_name
);
309 vrf_set_default_name(dent
->d_name
);
312 zebra_ns_notify_create_context_from_entry_name(dent
->d_name
);
317 void zebra_ns_notify_init(void)
321 zebra_netns_notify_current
= NULL
;
322 fd_monitor
= inotify_init();
323 if (fd_monitor
< 0) {
324 zlog_warn("NS notify init: failed to initialize inotify (%s)",
325 safe_strerror(errno
));
327 if (inotify_add_watch(fd_monitor
, NS_RUN_DIR
,
328 IN_CREATE
| IN_DELETE
) < 0) {
329 zlog_warn("NS notify watch: failed to add watch (%s)",
330 safe_strerror(errno
));
332 zebra_netns_notify_current
= thread_add_read(
333 zebrad
.master
, zebra_ns_notify_read
, NULL
, fd_monitor
, NULL
);
336 void zebra_ns_notify_close(void)
338 if (zebra_netns_notify_current
== NULL
)
343 if (zebra_netns_notify_current
->u
.fd
> 0)
344 fd
= zebra_netns_notify_current
->u
.fd
;
345 thread_cancel(zebra_netns_notify_current
);
346 /* auto-removal of inotify items */
352 void zebra_ns_notify_parse(void)
356 void zebra_ns_notify_init(void)
360 void zebra_ns_notify_close(void)
363 #endif /* !HAVE_NETLINK */