]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_netns_notify.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / zebra / zebra_netns_notify.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
e27dec3c
PG
2/*
3 * Zebra NS collector and notifier for Network NameSpaces
4 * Copyright (C) 2017 6WIND
e27dec3c
PG
5 */
6
7#include <zebra.h>
8
9#ifdef HAVE_NETLINK
10#ifdef HAVE_NETNS
11#undef _GNU_SOURCE
12#define _GNU_SOURCE
13
14#include <sched.h>
15#endif
16#include <dirent.h>
17#include <sys/inotify.h>
18#include <sys/stat.h>
19
20#include "thread.h"
21#include "ns.h"
22#include "command.h"
23#include "memory.h"
174482ef 24#include "lib_errors.h"
e27dec3c 25
3801e764 26#include "zebra_router.h"
e27dec3c
PG
27#endif /* defined(HAVE_NETLINK) */
28
29#include "zebra_netns_notify.h"
30#include "zebra_netns_id.h"
9df414fe 31#include "zebra_errors.h"
6502e5f1 32#include "interface.h"
e27dec3c
PG
33
34#ifdef HAVE_NETLINK
35
36/* upon creation of folder under /var/run/netns,
37 * wait that netns context is bound to
38 * that folder 10 seconds
39 */
40#define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000
41#define ZEBRA_NS_POLLING_MAX_RETRIES 200
42
bf8d3d6a 43DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo");
e27dec3c
PG
44static struct thread *zebra_netns_notify_current;
45
46struct zebra_netns_info {
47 const char *netnspath;
48 unsigned int retries;
49};
50
cc9f21da 51static void zebra_ns_ready_read(struct thread *t);
e27dec3c
PG
52static void zebra_ns_notify_create_context_from_entry_name(const char *name);
53static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
54 int stop_retry);
cc9f21da 55static void zebra_ns_notify_read(struct thread *t);
e27dec3c 56
62d89c64
IR
57static struct vrf *vrf_handler_create(struct vty *vty, const char *vrfname)
58{
59 if (strlen(vrfname) > VRF_NAMSIZ) {
60 flog_warn(EC_LIB_VRF_LENGTH,
61 "%% VRF name %s invalid: length exceeds %d bytes",
62 vrfname, VRF_NAMSIZ);
63 return NULL;
64 }
65
66 return vrf_get(VRF_UNKNOWN, vrfname);
67}
68
e27dec3c
PG
69static void zebra_ns_notify_create_context_from_entry_name(const char *name)
70{
71 char *netnspath = ns_netns_pathname(NULL, name);
72 struct vrf *vrf;
73 int ret;
2d4e4d39
PG
74 ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
75 struct ns *default_ns;
e27dec3c
PG
76
77 if (netnspath == NULL)
78 return;
79
0cf6db21 80 frr_with_privs(&zserv_privs) {
289b0f0d 81 ns_id = zebra_ns_id_get(netnspath, -1);
01b9e3fd 82 }
85a0edca
PG
83 if (ns_id == NS_UNKNOWN)
84 return;
03aff2d8 85 ns_id_external = ns_map_nsid_with_external(ns_id, true);
b7b816df 86 /* if VRF with NS ID already present */
03aff2d8 87 vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
b7b816df 88 if (vrf) {
9df414fe 89 zlog_debug(
996c9314
LB
90 "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
91 vrf->name, netnspath);
b7b816df
PG
92 return;
93 }
62d89c64
IR
94 vrf = vrf_handler_create(NULL, name);
95 if (!vrf) {
e914ccbe 96 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
9df414fe 97 "NS notify : failed to create VRF %s", name);
03aff2d8 98 ns_map_nsid_with_external(ns_id, false);
b7b816df
PG
99 return;
100 }
289b0f0d
PG
101
102 default_ns = ns_get_default();
103
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();
109 }
110
0cf6db21 111 frr_with_privs(&zserv_privs) {
62d89c64
IR
112 ret = zebra_vrf_netns_handler_create(NULL, vrf, netnspath,
113 ns_id_external, ns_id,
114 ns_id_relative);
01b9e3fd 115 }
e27dec3c 116 if (ret != CMD_SUCCESS) {
e914ccbe 117 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
9df414fe 118 "NS notify : failed to create NS %s", netnspath);
03aff2d8 119 ns_map_nsid_with_external(ns_id, false);
73899a2f 120 vrf_delete(vrf);
e27dec3c
PG
121 return;
122 }
996c9314 123 zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
e27dec3c
PG
124}
125
126static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
127 int stop_retry)
128{
129 void *ns_path_ptr = (void *)zns_info->netnspath;
130
131 if (stop_retry) {
132 XFREE(MTYPE_NETNS_MISC, ns_path_ptr);
133 XFREE(MTYPE_NETNS_MISC, zns_info);
134 return 0;
135 }
3801e764 136 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
996c9314
LB
137 (void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC,
138 NULL);
e27dec3c
PG
139 return 0;
140}
141
0c902ba5
PG
142static int zebra_ns_delete(char *name)
143{
144 struct vrf *vrf = vrf_lookup_by_name(name);
6502e5f1 145 struct interface *ifp, *tmp;
0c902ba5
PG
146 struct ns *ns;
147
148 if (!vrf) {
e914ccbe 149 flog_warn(EC_ZEBRA_NS_DELETION_FAILED_NO_VRF,
9df414fe 150 "NS notify : no VRF found using NS %s", name);
0c902ba5
PG
151 return 0;
152 }
6502e5f1
IR
153
154 /*
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.
158 */
159 RB_FOREACH_SAFE (ifp, if_name_head, &vrf->ifaces_by_name, tmp) {
160 if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE))
161 continue;
162
163 if (if_is_no_ptm_operative(ifp)) {
164 UNSET_FLAG(ifp->flags, IFF_RUNNING);
165 if_down(ifp);
166 }
167
168 UNSET_FLAG(ifp->flags, IFF_UP);
d0438da6 169 if_delete_update(&ifp);
6502e5f1
IR
170 }
171
0c902ba5
PG
172 ns = (struct ns *)vrf->ns_ctxt;
173 /* the deletion order is the same
174 * as the one used when siging signal is received
175 */
9acc98c8 176 vrf->ns_ctxt = NULL;
0c902ba5
PG
177 vrf_delete(vrf);
178 if (ns)
179 ns_delete(ns);
180
181 zlog_info("NS notify : deleted VRF %s", name);
182 return 0;
183}
184
3ed78e8c
PG
185static int zebra_ns_notify_self_identify(struct stat *netst)
186{
2b7165e7 187 char net_path[PATH_MAX];
3ed78e8c
PG
188 int netns;
189
772270f3 190 snprintf(net_path, sizeof(net_path), "/proc/self/ns/net");
3ed78e8c
PG
191 netns = open(net_path, O_RDONLY);
192 if (netns < 0)
193 return -1;
194 if (fstat(netns, netst) < 0) {
195 close(netns);
196 return -1;
197 }
198 close(netns);
199 return 0;
200}
201
202static bool zebra_ns_notify_is_default_netns(const char *name)
203{
204 struct stat default_netns_stat;
205 struct stat st;
f177a83e 206 char netnspath[PATH_MAX];
3ed78e8c
PG
207
208 if (zebra_ns_notify_self_identify(&default_netns_stat))
209 return false;
210
6006b807 211 memset(&st, 0, sizeof(st));
772270f3 212 snprintf(netnspath, sizeof(netnspath), "%s/%s", NS_RUN_DIR, name);
3ed78e8c
PG
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))
217 return true;
218 return false;
219}
0c902ba5 220
cc9f21da 221static void zebra_ns_ready_read(struct thread *t)
e27dec3c
PG
222{
223 struct zebra_netns_info *zns_info = THREAD_ARG(t);
224 const char *netnspath;
225 int err, stop_retry = 0;
226
227 if (!zns_info)
cc9f21da 228 return;
e27dec3c
PG
229 if (!zns_info->netnspath) {
230 XFREE(MTYPE_NETNS_MISC, zns_info);
cc9f21da 231 return;
e27dec3c
PG
232 }
233 netnspath = zns_info->netnspath;
234 if (--zns_info->retries == 0)
235 stop_retry = 1;
0cf6db21 236 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
237 err = ns_switch_to_netns(netnspath);
238 }
cc9f21da
DS
239 if (err < 0) {
240 zebra_ns_continue_read(zns_info, stop_retry);
241 return;
242 }
e27dec3c
PG
243
244 /* go back to default ns */
0cf6db21 245 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
246 err = ns_switchback_to_initial();
247 }
cc9f21da
DS
248 if (err < 0) {
249 zebra_ns_continue_read(zns_info, stop_retry);
250 return;
251 }
e27dec3c 252
167b0889
PG
253 /* check default name is not already set */
254 if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) {
3efd0893 255 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath));
cc9f21da
DS
256 zebra_ns_continue_read(zns_info, 1);
257 return;
167b0889 258 }
3ed78e8c
PG
259 if (zebra_ns_notify_is_default_netns(basename(netnspath))) {
260 zlog_warn(
ac2cb9bf
IR
261 "NS notify : NS %s is default VRF. Ignore VRF creation",
262 basename(netnspath));
cc9f21da
DS
263 zebra_ns_continue_read(zns_info, 1);
264 return;
3ed78e8c
PG
265 }
266
e27dec3c
PG
267 /* success : close fd and create zns context */
268 zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
cc9f21da 269 zebra_ns_continue_read(zns_info, 1);
e27dec3c
PG
270}
271
cc9f21da 272static void zebra_ns_notify_read(struct thread *t)
e27dec3c
PG
273{
274 int fd_monitor = THREAD_FD(t);
275 struct inotify_event *event;
276 char buf[BUFSIZ];
277 ssize_t len;
da5bd13c 278 char event_name[NAME_MAX + 1];
e27dec3c 279
ee1455dd
IR
280 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
281 &zebra_netns_notify_current);
e27dec3c
PG
282 len = read(fd_monitor, buf, sizeof(buf));
283 if (len < 0) {
e914ccbe 284 flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe
QY
285 "NS notify read: failed to read (%s)",
286 safe_strerror(errno));
cc9f21da 287 return;
e27dec3c 288 }
996c9314
LB
289 for (event = (struct inotify_event *)buf; (char *)event < &buf[len];
290 event = (struct inotify_event *)((char *)event + sizeof(*event)
291 + event->len)) {
e27dec3c
PG
292 char *netnspath;
293 struct zebra_netns_info *netnsinfo;
294
0c902ba5 295 if (!(event->mask & (IN_CREATE | IN_DELETE)))
e27dec3c 296 continue;
45981fda 297
298 if (offsetof(struct inotify_event, name) + event->len
299 >= sizeof(buf)) {
e914ccbe 300 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 301 "NS notify read: buffer underflow");
32ac96b2 302 break;
303 }
b6312ad1 304
305 if (strnlen(event->name, event->len) == event->len) {
e914ccbe 306 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 307 "NS notify error: bad event name");
b6312ad1 308 break;
309 }
310
da5bd13c
RZ
311 /*
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.
321 *
322 * Example:
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.
326 *
327 * For more information please read inotify(7) man page.
328 */
329 if (event->len == 0)
330 continue;
331
332 if (event->len > sizeof(event_name)) {
333 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
334 "NS notify error: unexpected big event name");
335 break;
336 }
337
338 memcpy(event_name, event->name, event->len);
339 event_name[event->len - 1] = 0;
340
f245bcae 341 if (event->mask & IN_DELETE) {
da5bd13c 342 zebra_ns_delete(event_name);
f245bcae
PG
343 continue;
344 }
da5bd13c 345 netnspath = ns_netns_pathname(NULL, event_name);
e27dec3c
PG
346 if (!netnspath)
347 continue;
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;
3801e764 353 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
996c9314 354 (void *)netnsinfo, 0, NULL);
e27dec3c 355 }
e27dec3c
PG
356}
357
358void zebra_ns_notify_parse(void)
359{
360 struct dirent *dent;
361 DIR *srcdir = opendir(NS_RUN_DIR);
362
363 if (srcdir == NULL) {
450971aa 364 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe 365 "NS parsing init: failed to parse %s", NS_RUN_DIR);
e27dec3c
PG
366 return;
367 }
368 while ((dent = readdir(srcdir)) != NULL) {
369 struct stat st;
370
371 if (strcmp(dent->d_name, ".") == 0
996c9314 372 || strcmp(dent->d_name, "..") == 0)
e27dec3c
PG
373 continue;
374 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
9df414fe 375 flog_err_sys(
450971aa 376 EC_LIB_SYSTEM_CALL,
9df414fe
QY
377 "NS parsing init: failed to parse entry %s",
378 dent->d_name);
e27dec3c
PG
379 continue;
380 }
381 if (S_ISDIR(st.st_mode)) {
9df414fe
QY
382 zlog_debug("NS parsing init: %s is not a NS",
383 dent->d_name);
e27dec3c
PG
384 continue;
385 }
167b0889
PG
386 /* check default name is not already set */
387 if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) {
3efd0893 388 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name);
167b0889
PG
389 continue;
390 }
3ed78e8c
PG
391 if (zebra_ns_notify_is_default_netns(dent->d_name)) {
392 zlog_warn(
ac2cb9bf
IR
393 "NS notify : NS %s is default VRF. Ignore VRF creation",
394 dent->d_name);
3ed78e8c
PG
395 continue;
396 }
e27dec3c
PG
397 zebra_ns_notify_create_context_from_entry_name(dent->d_name);
398 }
399 closedir(srcdir);
400}
401
402void zebra_ns_notify_init(void)
403{
404 int fd_monitor;
405
e27dec3c
PG
406 fd_monitor = inotify_init();
407 if (fd_monitor < 0) {
9df414fe 408 flog_err_sys(
450971aa 409 EC_LIB_SYSTEM_CALL,
9df414fe
QY
410 "NS notify init: failed to initialize inotify (%s)",
411 safe_strerror(errno));
e27dec3c 412 }
0c902ba5
PG
413 if (inotify_add_watch(fd_monitor, NS_RUN_DIR,
414 IN_CREATE | IN_DELETE) < 0) {
450971aa 415 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe
QY
416 "NS notify watch: failed to add watch (%s)",
417 safe_strerror(errno));
e27dec3c 418 }
ee1455dd
IR
419 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
420 &zebra_netns_notify_current);
e27dec3c
PG
421}
422
423void zebra_ns_notify_close(void)
424{
425 if (zebra_netns_notify_current == NULL)
426 return;
427
428 int fd = 0;
429
430 if (zebra_netns_notify_current->u.fd > 0)
431 fd = zebra_netns_notify_current->u.fd;
71077c48
MS
432
433 if (zebra_netns_notify_current->master != NULL)
146bcb9b 434 THREAD_OFF(zebra_netns_notify_current);
71077c48
MS
435
436 /* auto-removal of notify items */
e27dec3c
PG
437 if (fd > 0)
438 close(fd);
439}
440
441#else
442void zebra_ns_notify_parse(void)
443{
444}
445
446void zebra_ns_notify_init(void)
447{
448}
449
450void zebra_ns_notify_close(void)
451{
452}
453#endif /* !HAVE_NETLINK */