]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_netns_notify.c
Merge pull request #10447 from ton31337/fix/json_with_whitespaces
[mirror_frr.git] / zebra / zebra_netns_notify.c
CommitLineData
e27dec3c
PG
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"
174482ef 37#include "lib_errors.h"
e27dec3c 38
3801e764 39#include "zebra_router.h"
e27dec3c
PG
40#endif /* defined(HAVE_NETLINK) */
41
42#include "zebra_netns_notify.h"
43#include "zebra_netns_id.h"
9df414fe 44#include "zebra_errors.h"
6502e5f1 45#include "interface.h"
e27dec3c
PG
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
bf8d3d6a 56DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo");
e27dec3c
PG
57static struct thread *zebra_netns_notify_current;
58
59struct zebra_netns_info {
60 const char *netnspath;
61 unsigned int retries;
62};
63
cc9f21da 64static void zebra_ns_ready_read(struct thread *t);
e27dec3c
PG
65static void zebra_ns_notify_create_context_from_entry_name(const char *name);
66static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
67 int stop_retry);
cc9f21da 68static void zebra_ns_notify_read(struct thread *t);
e27dec3c 69
62d89c64
IR
70static 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
e27dec3c
PG
82static 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;
2d4e4d39
PG
87 ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
88 struct ns *default_ns;
e27dec3c
PG
89
90 if (netnspath == NULL)
91 return;
92
0cf6db21 93 frr_with_privs(&zserv_privs) {
289b0f0d 94 ns_id = zebra_ns_id_get(netnspath, -1);
01b9e3fd 95 }
85a0edca
PG
96 if (ns_id == NS_UNKNOWN)
97 return;
03aff2d8 98 ns_id_external = ns_map_nsid_with_external(ns_id, true);
b7b816df 99 /* if VRF with NS ID already present */
03aff2d8 100 vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
b7b816df 101 if (vrf) {
9df414fe 102 zlog_debug(
996c9314
LB
103 "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
104 vrf->name, netnspath);
b7b816df
PG
105 return;
106 }
62d89c64
IR
107 vrf = vrf_handler_create(NULL, name);
108 if (!vrf) {
e914ccbe 109 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
9df414fe 110 "NS notify : failed to create VRF %s", name);
03aff2d8 111 ns_map_nsid_with_external(ns_id, false);
b7b816df
PG
112 return;
113 }
289b0f0d
PG
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
0cf6db21 124 frr_with_privs(&zserv_privs) {
62d89c64
IR
125 ret = zebra_vrf_netns_handler_create(NULL, vrf, netnspath,
126 ns_id_external, ns_id,
127 ns_id_relative);
01b9e3fd 128 }
e27dec3c 129 if (ret != CMD_SUCCESS) {
e914ccbe 130 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
9df414fe 131 "NS notify : failed to create NS %s", netnspath);
03aff2d8 132 ns_map_nsid_with_external(ns_id, false);
73899a2f 133 vrf_delete(vrf);
e27dec3c
PG
134 return;
135 }
996c9314 136 zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
e27dec3c
PG
137}
138
139static 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 }
3801e764 149 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
996c9314
LB
150 (void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC,
151 NULL);
e27dec3c
PG
152 return 0;
153}
154
0c902ba5
PG
155static int zebra_ns_delete(char *name)
156{
157 struct vrf *vrf = vrf_lookup_by_name(name);
6502e5f1 158 struct interface *ifp, *tmp;
0c902ba5
PG
159 struct ns *ns;
160
161 if (!vrf) {
e914ccbe 162 flog_warn(EC_ZEBRA_NS_DELETION_FAILED_NO_VRF,
9df414fe 163 "NS notify : no VRF found using NS %s", name);
0c902ba5
PG
164 return 0;
165 }
6502e5f1
IR
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
0c902ba5
PG
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 */
9acc98c8 189 vrf->ns_ctxt = NULL;
0c902ba5
PG
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
3ed78e8c
PG
198static int zebra_ns_notify_self_identify(struct stat *netst)
199{
2b7165e7 200 char net_path[PATH_MAX];
3ed78e8c
PG
201 int netns;
202
772270f3 203 snprintf(net_path, sizeof(net_path), "/proc/self/ns/net");
3ed78e8c
PG
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
215static bool zebra_ns_notify_is_default_netns(const char *name)
216{
217 struct stat default_netns_stat;
218 struct stat st;
f177a83e 219 char netnspath[PATH_MAX];
3ed78e8c
PG
220
221 if (zebra_ns_notify_self_identify(&default_netns_stat))
222 return false;
223
224 memset(&st, 0, sizeof(struct stat));
772270f3 225 snprintf(netnspath, sizeof(netnspath), "%s/%s", NS_RUN_DIR, name);
3ed78e8c
PG
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}
0c902ba5 233
cc9f21da 234static void zebra_ns_ready_read(struct thread *t)
e27dec3c
PG
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)
cc9f21da 241 return;
e27dec3c
PG
242 if (!zns_info->netnspath) {
243 XFREE(MTYPE_NETNS_MISC, zns_info);
cc9f21da 244 return;
e27dec3c
PG
245 }
246 netnspath = zns_info->netnspath;
247 if (--zns_info->retries == 0)
248 stop_retry = 1;
0cf6db21 249 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
250 err = ns_switch_to_netns(netnspath);
251 }
cc9f21da
DS
252 if (err < 0) {
253 zebra_ns_continue_read(zns_info, stop_retry);
254 return;
255 }
e27dec3c
PG
256
257 /* go back to default ns */
0cf6db21 258 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
259 err = ns_switchback_to_initial();
260 }
cc9f21da
DS
261 if (err < 0) {
262 zebra_ns_continue_read(zns_info, stop_retry);
263 return;
264 }
e27dec3c 265
167b0889
PG
266 /* check default name is not already set */
267 if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) {
3efd0893 268 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath));
cc9f21da
DS
269 zebra_ns_continue_read(zns_info, 1);
270 return;
167b0889 271 }
3ed78e8c
PG
272 if (zebra_ns_notify_is_default_netns(basename(netnspath))) {
273 zlog_warn(
ac2cb9bf
IR
274 "NS notify : NS %s is default VRF. Ignore VRF creation",
275 basename(netnspath));
cc9f21da
DS
276 zebra_ns_continue_read(zns_info, 1);
277 return;
3ed78e8c
PG
278 }
279
e27dec3c
PG
280 /* success : close fd and create zns context */
281 zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
cc9f21da 282 zebra_ns_continue_read(zns_info, 1);
e27dec3c
PG
283}
284
cc9f21da 285static void zebra_ns_notify_read(struct thread *t)
e27dec3c
PG
286{
287 int fd_monitor = THREAD_FD(t);
288 struct inotify_event *event;
289 char buf[BUFSIZ];
290 ssize_t len;
291
ee1455dd
IR
292 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
293 &zebra_netns_notify_current);
e27dec3c
PG
294 len = read(fd_monitor, buf, sizeof(buf));
295 if (len < 0) {
e914ccbe 296 flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe
QY
297 "NS notify read: failed to read (%s)",
298 safe_strerror(errno));
cc9f21da 299 return;
e27dec3c 300 }
996c9314
LB
301 for (event = (struct inotify_event *)buf; (char *)event < &buf[len];
302 event = (struct inotify_event *)((char *)event + sizeof(*event)
303 + event->len)) {
e27dec3c
PG
304 char *netnspath;
305 struct zebra_netns_info *netnsinfo;
306
0c902ba5 307 if (!(event->mask & (IN_CREATE | IN_DELETE)))
e27dec3c 308 continue;
45981fda 309
310 if (offsetof(struct inotify_event, name) + event->len
311 >= sizeof(buf)) {
e914ccbe 312 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 313 "NS notify read: buffer underflow");
32ac96b2 314 break;
315 }
b6312ad1 316
317 if (strnlen(event->name, event->len) == event->len) {
e914ccbe 318 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 319 "NS notify error: bad event name");
b6312ad1 320 break;
321 }
322
f245bcae
PG
323 if (event->mask & IN_DELETE) {
324 zebra_ns_delete(event->name);
325 continue;
326 }
e27dec3c
PG
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;
3801e764 335 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
996c9314 336 (void *)netnsinfo, 0, NULL);
e27dec3c 337 }
e27dec3c
PG
338}
339
340void zebra_ns_notify_parse(void)
341{
342 struct dirent *dent;
343 DIR *srcdir = opendir(NS_RUN_DIR);
344
345 if (srcdir == NULL) {
450971aa 346 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe 347 "NS parsing init: failed to parse %s", NS_RUN_DIR);
e27dec3c
PG
348 return;
349 }
350 while ((dent = readdir(srcdir)) != NULL) {
351 struct stat st;
352
353 if (strcmp(dent->d_name, ".") == 0
996c9314 354 || strcmp(dent->d_name, "..") == 0)
e27dec3c
PG
355 continue;
356 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
9df414fe 357 flog_err_sys(
450971aa 358 EC_LIB_SYSTEM_CALL,
9df414fe
QY
359 "NS parsing init: failed to parse entry %s",
360 dent->d_name);
e27dec3c
PG
361 continue;
362 }
363 if (S_ISDIR(st.st_mode)) {
9df414fe
QY
364 zlog_debug("NS parsing init: %s is not a NS",
365 dent->d_name);
e27dec3c
PG
366 continue;
367 }
167b0889
PG
368 /* check default name is not already set */
369 if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) {
3efd0893 370 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name);
167b0889
PG
371 continue;
372 }
3ed78e8c
PG
373 if (zebra_ns_notify_is_default_netns(dent->d_name)) {
374 zlog_warn(
ac2cb9bf
IR
375 "NS notify : NS %s is default VRF. Ignore VRF creation",
376 dent->d_name);
3ed78e8c
PG
377 continue;
378 }
e27dec3c
PG
379 zebra_ns_notify_create_context_from_entry_name(dent->d_name);
380 }
381 closedir(srcdir);
382}
383
384void zebra_ns_notify_init(void)
385{
386 int fd_monitor;
387
e27dec3c
PG
388 fd_monitor = inotify_init();
389 if (fd_monitor < 0) {
9df414fe 390 flog_err_sys(
450971aa 391 EC_LIB_SYSTEM_CALL,
9df414fe
QY
392 "NS notify init: failed to initialize inotify (%s)",
393 safe_strerror(errno));
e27dec3c 394 }
0c902ba5
PG
395 if (inotify_add_watch(fd_monitor, NS_RUN_DIR,
396 IN_CREATE | IN_DELETE) < 0) {
450971aa 397 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe
QY
398 "NS notify watch: failed to add watch (%s)",
399 safe_strerror(errno));
e27dec3c 400 }
ee1455dd
IR
401 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
402 &zebra_netns_notify_current);
e27dec3c
PG
403}
404
405void 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;
71077c48
MS
414
415 if (zebra_netns_notify_current->master != NULL)
b3d6bc6e 416 thread_cancel(&zebra_netns_notify_current);
71077c48
MS
417
418 /* auto-removal of notify items */
e27dec3c
PG
419 if (fd > 0)
420 close(fd);
421}
422
423#else
424void zebra_ns_notify_parse(void)
425{
426}
427
428void zebra_ns_notify_init(void)
429{
430}
431
432void zebra_ns_notify_close(void)
433{
434}
435#endif /* !HAVE_NETLINK */