]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_netns_notify.c
*: Rename thread.[ch] to event.[ch]
[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
cb37cb33 20#include "event.h"
e27dec3c
PG
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
7eefea98
PJD
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,
172 false);
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);
178
6502e5f1 179 UNSET_FLAG(ifp->flags, IFF_UP);
d0438da6 180 if_delete_update(&ifp);
6502e5f1
IR
181 }
182
0c902ba5
PG
183 ns = (struct ns *)vrf->ns_ctxt;
184 /* the deletion order is the same
185 * as the one used when siging signal is received
186 */
9acc98c8 187 vrf->ns_ctxt = NULL;
0c902ba5
PG
188 vrf_delete(vrf);
189 if (ns)
190 ns_delete(ns);
191
192 zlog_info("NS notify : deleted VRF %s", name);
193 return 0;
194}
195
3ed78e8c
PG
196static int zebra_ns_notify_self_identify(struct stat *netst)
197{
2b7165e7 198 char net_path[PATH_MAX];
3ed78e8c
PG
199 int netns;
200
772270f3 201 snprintf(net_path, sizeof(net_path), "/proc/self/ns/net");
3ed78e8c
PG
202 netns = open(net_path, O_RDONLY);
203 if (netns < 0)
204 return -1;
205 if (fstat(netns, netst) < 0) {
206 close(netns);
207 return -1;
208 }
209 close(netns);
210 return 0;
211}
212
213static bool zebra_ns_notify_is_default_netns(const char *name)
214{
215 struct stat default_netns_stat;
216 struct stat st;
f177a83e 217 char netnspath[PATH_MAX];
3ed78e8c
PG
218
219 if (zebra_ns_notify_self_identify(&default_netns_stat))
220 return false;
221
6006b807 222 memset(&st, 0, sizeof(st));
772270f3 223 snprintf(netnspath, sizeof(netnspath), "%s/%s", NS_RUN_DIR, name);
3ed78e8c
PG
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))
228 return true;
229 return false;
230}
0c902ba5 231
cc9f21da 232static void zebra_ns_ready_read(struct thread *t)
e27dec3c
PG
233{
234 struct zebra_netns_info *zns_info = THREAD_ARG(t);
235 const char *netnspath;
236 int err, stop_retry = 0;
237
238 if (!zns_info)
cc9f21da 239 return;
e27dec3c
PG
240 if (!zns_info->netnspath) {
241 XFREE(MTYPE_NETNS_MISC, zns_info);
cc9f21da 242 return;
e27dec3c
PG
243 }
244 netnspath = zns_info->netnspath;
245 if (--zns_info->retries == 0)
246 stop_retry = 1;
0cf6db21 247 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
248 err = ns_switch_to_netns(netnspath);
249 }
cc9f21da
DS
250 if (err < 0) {
251 zebra_ns_continue_read(zns_info, stop_retry);
252 return;
253 }
e27dec3c
PG
254
255 /* go back to default ns */
0cf6db21 256 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
257 err = ns_switchback_to_initial();
258 }
cc9f21da
DS
259 if (err < 0) {
260 zebra_ns_continue_read(zns_info, stop_retry);
261 return;
262 }
e27dec3c 263
167b0889
PG
264 /* check default name is not already set */
265 if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) {
3efd0893 266 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath));
cc9f21da
DS
267 zebra_ns_continue_read(zns_info, 1);
268 return;
167b0889 269 }
3ed78e8c
PG
270 if (zebra_ns_notify_is_default_netns(basename(netnspath))) {
271 zlog_warn(
ac2cb9bf
IR
272 "NS notify : NS %s is default VRF. Ignore VRF creation",
273 basename(netnspath));
cc9f21da
DS
274 zebra_ns_continue_read(zns_info, 1);
275 return;
3ed78e8c
PG
276 }
277
e27dec3c
PG
278 /* success : close fd and create zns context */
279 zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
cc9f21da 280 zebra_ns_continue_read(zns_info, 1);
e27dec3c
PG
281}
282
cc9f21da 283static void zebra_ns_notify_read(struct thread *t)
e27dec3c
PG
284{
285 int fd_monitor = THREAD_FD(t);
286 struct inotify_event *event;
287 char buf[BUFSIZ];
288 ssize_t len;
da5bd13c 289 char event_name[NAME_MAX + 1];
e27dec3c 290
ee1455dd
IR
291 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
292 &zebra_netns_notify_current);
e27dec3c
PG
293 len = read(fd_monitor, buf, sizeof(buf));
294 if (len < 0) {
e914ccbe 295 flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe
QY
296 "NS notify read: failed to read (%s)",
297 safe_strerror(errno));
cc9f21da 298 return;
e27dec3c 299 }
996c9314
LB
300 for (event = (struct inotify_event *)buf; (char *)event < &buf[len];
301 event = (struct inotify_event *)((char *)event + sizeof(*event)
302 + event->len)) {
e27dec3c
PG
303 char *netnspath;
304 struct zebra_netns_info *netnsinfo;
305
0c902ba5 306 if (!(event->mask & (IN_CREATE | IN_DELETE)))
e27dec3c 307 continue;
45981fda 308
309 if (offsetof(struct inotify_event, name) + event->len
310 >= sizeof(buf)) {
e914ccbe 311 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 312 "NS notify read: buffer underflow");
32ac96b2 313 break;
314 }
b6312ad1 315
316 if (strnlen(event->name, event->len) == event->len) {
e914ccbe 317 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 318 "NS notify error: bad event name");
b6312ad1 319 break;
320 }
321
da5bd13c
RZ
322 /*
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.
332 *
333 * Example:
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.
337 *
338 * For more information please read inotify(7) man page.
339 */
340 if (event->len == 0)
341 continue;
342
343 if (event->len > sizeof(event_name)) {
344 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
345 "NS notify error: unexpected big event name");
346 break;
347 }
348
349 memcpy(event_name, event->name, event->len);
350 event_name[event->len - 1] = 0;
351
f245bcae 352 if (event->mask & IN_DELETE) {
da5bd13c 353 zebra_ns_delete(event_name);
f245bcae
PG
354 continue;
355 }
da5bd13c 356 netnspath = ns_netns_pathname(NULL, event_name);
e27dec3c
PG
357 if (!netnspath)
358 continue;
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;
3801e764 364 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
996c9314 365 (void *)netnsinfo, 0, NULL);
e27dec3c 366 }
e27dec3c
PG
367}
368
369void zebra_ns_notify_parse(void)
370{
371 struct dirent *dent;
372 DIR *srcdir = opendir(NS_RUN_DIR);
373
374 if (srcdir == NULL) {
450971aa 375 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe 376 "NS parsing init: failed to parse %s", NS_RUN_DIR);
e27dec3c
PG
377 return;
378 }
379 while ((dent = readdir(srcdir)) != NULL) {
380 struct stat st;
381
382 if (strcmp(dent->d_name, ".") == 0
996c9314 383 || strcmp(dent->d_name, "..") == 0)
e27dec3c
PG
384 continue;
385 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
9df414fe 386 flog_err_sys(
450971aa 387 EC_LIB_SYSTEM_CALL,
9df414fe
QY
388 "NS parsing init: failed to parse entry %s",
389 dent->d_name);
e27dec3c
PG
390 continue;
391 }
392 if (S_ISDIR(st.st_mode)) {
9df414fe
QY
393 zlog_debug("NS parsing init: %s is not a NS",
394 dent->d_name);
e27dec3c
PG
395 continue;
396 }
167b0889
PG
397 /* check default name is not already set */
398 if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) {
3efd0893 399 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name);
167b0889
PG
400 continue;
401 }
3ed78e8c
PG
402 if (zebra_ns_notify_is_default_netns(dent->d_name)) {
403 zlog_warn(
ac2cb9bf
IR
404 "NS notify : NS %s is default VRF. Ignore VRF creation",
405 dent->d_name);
3ed78e8c
PG
406 continue;
407 }
e27dec3c
PG
408 zebra_ns_notify_create_context_from_entry_name(dent->d_name);
409 }
410 closedir(srcdir);
411}
412
413void zebra_ns_notify_init(void)
414{
415 int fd_monitor;
416
e27dec3c
PG
417 fd_monitor = inotify_init();
418 if (fd_monitor < 0) {
9df414fe 419 flog_err_sys(
450971aa 420 EC_LIB_SYSTEM_CALL,
9df414fe
QY
421 "NS notify init: failed to initialize inotify (%s)",
422 safe_strerror(errno));
e27dec3c 423 }
0c902ba5
PG
424 if (inotify_add_watch(fd_monitor, NS_RUN_DIR,
425 IN_CREATE | IN_DELETE) < 0) {
450971aa 426 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe
QY
427 "NS notify watch: failed to add watch (%s)",
428 safe_strerror(errno));
e27dec3c 429 }
ee1455dd
IR
430 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
431 &zebra_netns_notify_current);
e27dec3c
PG
432}
433
434void zebra_ns_notify_close(void)
435{
436 if (zebra_netns_notify_current == NULL)
437 return;
438
439 int fd = 0;
440
441 if (zebra_netns_notify_current->u.fd > 0)
442 fd = zebra_netns_notify_current->u.fd;
71077c48
MS
443
444 if (zebra_netns_notify_current->master != NULL)
146bcb9b 445 THREAD_OFF(zebra_netns_notify_current);
71077c48
MS
446
447 /* auto-removal of notify items */
e27dec3c
PG
448 if (fd > 0)
449 close(fd);
450}
451
452#else
453void zebra_ns_notify_parse(void)
454{
455}
456
457void zebra_ns_notify_init(void)
458{
459}
460
461void zebra_ns_notify_close(void)
462{
463}
464#endif /* !HAVE_NETLINK */