]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_netns_notify.c
Merge pull request #10845 from opensourcerouting/feature/unify_bgp_logging
[mirror_frr.git] / zebra / zebra_netns_notify.c
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 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 static struct vrf *vrf_handler_create(struct vty *vty, const char *vrfname)
71 {
72 if (strlen(vrfname) > VRF_NAMSIZ) {
73 flog_warn(EC_LIB_VRF_LENGTH,
74 "%% VRF name %s invalid: length exceeds %d bytes",
75 vrfname, VRF_NAMSIZ);
76 return NULL;
77 }
78
79 return vrf_get(VRF_UNKNOWN, vrfname);
80 }
81
82 static void zebra_ns_notify_create_context_from_entry_name(const char *name)
83 {
84 char *netnspath = ns_netns_pathname(NULL, name);
85 struct vrf *vrf;
86 int ret;
87 ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
88 struct ns *default_ns;
89
90 if (netnspath == NULL)
91 return;
92
93 frr_with_privs(&zserv_privs) {
94 ns_id = zebra_ns_id_get(netnspath, -1);
95 }
96 if (ns_id == NS_UNKNOWN)
97 return;
98 ns_id_external = ns_map_nsid_with_external(ns_id, true);
99 /* if VRF with NS ID already present */
100 vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
101 if (vrf) {
102 zlog_debug(
103 "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
104 vrf->name, netnspath);
105 return;
106 }
107 vrf = vrf_handler_create(NULL, name);
108 if (!vrf) {
109 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
110 "NS notify : failed to create VRF %s", name);
111 ns_map_nsid_with_external(ns_id, false);
112 return;
113 }
114
115 default_ns = ns_get_default();
116
117 /* force kernel ns_id creation in that new vrf */
118 frr_with_privs(&zserv_privs) {
119 ns_switch_to_netns(netnspath);
120 ns_id_relative = zebra_ns_id_get(NULL, default_ns->fd);
121 ns_switchback_to_initial();
122 }
123
124 frr_with_privs(&zserv_privs) {
125 ret = zebra_vrf_netns_handler_create(NULL, vrf, netnspath,
126 ns_id_external, ns_id,
127 ns_id_relative);
128 }
129 if (ret != CMD_SUCCESS) {
130 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
131 "NS notify : failed to create NS %s", netnspath);
132 ns_map_nsid_with_external(ns_id, false);
133 vrf_delete(vrf);
134 return;
135 }
136 zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
137 }
138
139 static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
140 int stop_retry)
141 {
142 void *ns_path_ptr = (void *)zns_info->netnspath;
143
144 if (stop_retry) {
145 XFREE(MTYPE_NETNS_MISC, ns_path_ptr);
146 XFREE(MTYPE_NETNS_MISC, zns_info);
147 return 0;
148 }
149 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
150 (void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC,
151 NULL);
152 return 0;
153 }
154
155 static int zebra_ns_delete(char *name)
156 {
157 struct vrf *vrf = vrf_lookup_by_name(name);
158 struct interface *ifp, *tmp;
159 struct ns *ns;
160
161 if (!vrf) {
162 flog_warn(EC_ZEBRA_NS_DELETION_FAILED_NO_VRF,
163 "NS notify : no VRF found using NS %s", name);
164 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 RB_FOREACH_SAFE (ifp, if_name_head, &vrf->ifaces_by_name, tmp) {
173 if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE))
174 continue;
175
176 if (if_is_no_ptm_operative(ifp)) {
177 UNSET_FLAG(ifp->flags, IFF_RUNNING);
178 if_down(ifp);
179 }
180
181 UNSET_FLAG(ifp->flags, IFF_UP);
182 if_delete_update(&ifp);
183 }
184
185 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 vrf->ns_ctxt = NULL;
190 vrf_delete(vrf);
191 if (ns)
192 ns_delete(ns);
193
194 zlog_info("NS notify : deleted VRF %s", name);
195 return 0;
196 }
197
198 static int zebra_ns_notify_self_identify(struct stat *netst)
199 {
200 char net_path[PATH_MAX];
201 int netns;
202
203 snprintf(net_path, sizeof(net_path), "/proc/self/ns/net");
204 netns = open(net_path, O_RDONLY);
205 if (netns < 0)
206 return -1;
207 if (fstat(netns, netst) < 0) {
208 close(netns);
209 return -1;
210 }
211 close(netns);
212 return 0;
213 }
214
215 static bool zebra_ns_notify_is_default_netns(const char *name)
216 {
217 struct stat default_netns_stat;
218 struct stat st;
219 char netnspath[PATH_MAX];
220
221 if (zebra_ns_notify_self_identify(&default_netns_stat))
222 return false;
223
224 memset(&st, 0, sizeof(struct stat));
225 snprintf(netnspath, sizeof(netnspath), "%s/%s", NS_RUN_DIR, name);
226 /* compare with local stat */
227 if (stat(netnspath, &st) == 0 &&
228 (st.st_dev == default_netns_stat.st_dev) &&
229 (st.st_ino == default_netns_stat.st_ino))
230 return true;
231 return false;
232 }
233
234 static void zebra_ns_ready_read(struct thread *t)
235 {
236 struct zebra_netns_info *zns_info = THREAD_ARG(t);
237 const char *netnspath;
238 int err, stop_retry = 0;
239
240 if (!zns_info)
241 return;
242 if (!zns_info->netnspath) {
243 XFREE(MTYPE_NETNS_MISC, zns_info);
244 return;
245 }
246 netnspath = zns_info->netnspath;
247 if (--zns_info->retries == 0)
248 stop_retry = 1;
249 frr_with_privs(&zserv_privs) {
250 err = ns_switch_to_netns(netnspath);
251 }
252 if (err < 0) {
253 zebra_ns_continue_read(zns_info, stop_retry);
254 return;
255 }
256
257 /* go back to default ns */
258 frr_with_privs(&zserv_privs) {
259 err = ns_switchback_to_initial();
260 }
261 if (err < 0) {
262 zebra_ns_continue_read(zns_info, stop_retry);
263 return;
264 }
265
266 /* check default name is not already set */
267 if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) {
268 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath));
269 zebra_ns_continue_read(zns_info, 1);
270 return;
271 }
272 if (zebra_ns_notify_is_default_netns(basename(netnspath))) {
273 zlog_warn(
274 "NS notify : NS %s is default VRF. Ignore VRF creation",
275 basename(netnspath));
276 zebra_ns_continue_read(zns_info, 1);
277 return;
278 }
279
280 /* success : close fd and create zns context */
281 zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
282 zebra_ns_continue_read(zns_info, 1);
283 }
284
285 static void zebra_ns_notify_read(struct thread *t)
286 {
287 int fd_monitor = THREAD_FD(t);
288 struct inotify_event *event;
289 char buf[BUFSIZ];
290 ssize_t len;
291
292 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
293 &zebra_netns_notify_current);
294 len = read(fd_monitor, buf, sizeof(buf));
295 if (len < 0) {
296 flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
297 "NS notify read: failed to read (%s)",
298 safe_strerror(errno));
299 return;
300 }
301 for (event = (struct inotify_event *)buf; (char *)event < &buf[len];
302 event = (struct inotify_event *)((char *)event + sizeof(*event)
303 + event->len)) {
304 char *netnspath;
305 struct zebra_netns_info *netnsinfo;
306
307 if (!(event->mask & (IN_CREATE | IN_DELETE)))
308 continue;
309
310 if (offsetof(struct inotify_event, name) + event->len
311 >= sizeof(buf)) {
312 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
313 "NS notify read: buffer underflow");
314 break;
315 }
316
317 if (strnlen(event->name, event->len) == event->len) {
318 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
319 "NS notify error: bad event name");
320 break;
321 }
322
323 if (event->mask & IN_DELETE) {
324 zebra_ns_delete(event->name);
325 continue;
326 }
327 netnspath = ns_netns_pathname(NULL, event->name);
328 if (!netnspath)
329 continue;
330 netnspath = XSTRDUP(MTYPE_NETNS_MISC, netnspath);
331 netnsinfo = XCALLOC(MTYPE_NETNS_MISC,
332 sizeof(struct zebra_netns_info));
333 netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES;
334 netnsinfo->netnspath = netnspath;
335 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
336 (void *)netnsinfo, 0, NULL);
337 }
338 }
339
340 void zebra_ns_notify_parse(void)
341 {
342 struct dirent *dent;
343 DIR *srcdir = opendir(NS_RUN_DIR);
344
345 if (srcdir == NULL) {
346 flog_err_sys(EC_LIB_SYSTEM_CALL,
347 "NS parsing init: failed to parse %s", NS_RUN_DIR);
348 return;
349 }
350 while ((dent = readdir(srcdir)) != NULL) {
351 struct stat st;
352
353 if (strcmp(dent->d_name, ".") == 0
354 || strcmp(dent->d_name, "..") == 0)
355 continue;
356 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
357 flog_err_sys(
358 EC_LIB_SYSTEM_CALL,
359 "NS parsing init: failed to parse entry %s",
360 dent->d_name);
361 continue;
362 }
363 if (S_ISDIR(st.st_mode)) {
364 zlog_debug("NS parsing init: %s is not a NS",
365 dent->d_name);
366 continue;
367 }
368 /* check default name is not already set */
369 if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) {
370 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name);
371 continue;
372 }
373 if (zebra_ns_notify_is_default_netns(dent->d_name)) {
374 zlog_warn(
375 "NS notify : NS %s is default VRF. Ignore VRF creation",
376 dent->d_name);
377 continue;
378 }
379 zebra_ns_notify_create_context_from_entry_name(dent->d_name);
380 }
381 closedir(srcdir);
382 }
383
384 void zebra_ns_notify_init(void)
385 {
386 int fd_monitor;
387
388 fd_monitor = inotify_init();
389 if (fd_monitor < 0) {
390 flog_err_sys(
391 EC_LIB_SYSTEM_CALL,
392 "NS notify init: failed to initialize inotify (%s)",
393 safe_strerror(errno));
394 }
395 if (inotify_add_watch(fd_monitor, NS_RUN_DIR,
396 IN_CREATE | IN_DELETE) < 0) {
397 flog_err_sys(EC_LIB_SYSTEM_CALL,
398 "NS notify watch: failed to add watch (%s)",
399 safe_strerror(errno));
400 }
401 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
402 &zebra_netns_notify_current);
403 }
404
405 void zebra_ns_notify_close(void)
406 {
407 if (zebra_netns_notify_current == NULL)
408 return;
409
410 int fd = 0;
411
412 if (zebra_netns_notify_current->u.fd > 0)
413 fd = zebra_netns_notify_current->u.fd;
414
415 if (zebra_netns_notify_current->master != NULL)
416 thread_cancel(&zebra_netns_notify_current);
417
418 /* auto-removal of notify items */
419 if (fd > 0)
420 close(fd);
421 }
422
423 #else
424 void zebra_ns_notify_parse(void)
425 {
426 }
427
428 void zebra_ns_notify_init(void)
429 {
430 }
431
432 void zebra_ns_notify_close(void)
433 {
434 }
435 #endif /* !HAVE_NETLINK */