]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_netns_notify.c
Merge pull request #9472 from rampxxxx/pathd_doc_augmented
[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
64static int zebra_ns_ready_read(struct thread *t);
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);
68static int zebra_ns_notify_read(struct thread *t);
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
e27dec3c
PG
234static int 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 0;
242 if (!zns_info->netnspath) {
243 XFREE(MTYPE_NETNS_MISC, zns_info);
244 return 0;
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 }
e27dec3c
PG
252 if (err < 0)
253 return zebra_ns_continue_read(zns_info, stop_retry);
254
255 /* go back to default ns */
0cf6db21 256 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
257 err = ns_switchback_to_initial();
258 }
e27dec3c
PG
259 if (err < 0)
260 return zebra_ns_continue_read(zns_info, stop_retry);
261
167b0889
PG
262 /* check default name is not already set */
263 if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) {
3efd0893 264 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath));
167b0889
PG
265 return zebra_ns_continue_read(zns_info, 1);
266 }
3ed78e8c
PG
267 if (zebra_ns_notify_is_default_netns(basename(netnspath))) {
268 zlog_warn(
3efd0893 269 "NS notify : NS %s is default VRF. Updating VRF Name", basename(netnspath));
4fe52e76 270 vrf_set_default_name(basename(netnspath), false);
3ed78e8c
PG
271 return zebra_ns_continue_read(zns_info, 1);
272 }
273
e27dec3c
PG
274 /* success : close fd and create zns context */
275 zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
276 return zebra_ns_continue_read(zns_info, 1);
277}
278
279static int zebra_ns_notify_read(struct thread *t)
280{
281 int fd_monitor = THREAD_FD(t);
282 struct inotify_event *event;
283 char buf[BUFSIZ];
284 ssize_t len;
285
ee1455dd
IR
286 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
287 &zebra_netns_notify_current);
e27dec3c
PG
288 len = read(fd_monitor, buf, sizeof(buf));
289 if (len < 0) {
e914ccbe 290 flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe
QY
291 "NS notify read: failed to read (%s)",
292 safe_strerror(errno));
e27dec3c
PG
293 return 0;
294 }
996c9314
LB
295 for (event = (struct inotify_event *)buf; (char *)event < &buf[len];
296 event = (struct inotify_event *)((char *)event + sizeof(*event)
297 + event->len)) {
e27dec3c
PG
298 char *netnspath;
299 struct zebra_netns_info *netnsinfo;
300
0c902ba5 301 if (!(event->mask & (IN_CREATE | IN_DELETE)))
e27dec3c 302 continue;
45981fda 303
304 if (offsetof(struct inotify_event, name) + event->len
305 >= sizeof(buf)) {
e914ccbe 306 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 307 "NS notify read: buffer underflow");
32ac96b2 308 break;
309 }
b6312ad1 310
311 if (strnlen(event->name, event->len) == event->len) {
e914ccbe 312 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 313 "NS notify error: bad event name");
b6312ad1 314 break;
315 }
316
f245bcae
PG
317 if (event->mask & IN_DELETE) {
318 zebra_ns_delete(event->name);
319 continue;
320 }
e27dec3c
PG
321 netnspath = ns_netns_pathname(NULL, event->name);
322 if (!netnspath)
323 continue;
324 netnspath = XSTRDUP(MTYPE_NETNS_MISC, netnspath);
325 netnsinfo = XCALLOC(MTYPE_NETNS_MISC,
326 sizeof(struct zebra_netns_info));
327 netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES;
328 netnsinfo->netnspath = netnspath;
3801e764 329 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
996c9314 330 (void *)netnsinfo, 0, NULL);
e27dec3c
PG
331 }
332 return 0;
333}
334
335void zebra_ns_notify_parse(void)
336{
337 struct dirent *dent;
338 DIR *srcdir = opendir(NS_RUN_DIR);
339
340 if (srcdir == NULL) {
450971aa 341 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe 342 "NS parsing init: failed to parse %s", NS_RUN_DIR);
e27dec3c
PG
343 return;
344 }
345 while ((dent = readdir(srcdir)) != NULL) {
346 struct stat st;
347
348 if (strcmp(dent->d_name, ".") == 0
996c9314 349 || strcmp(dent->d_name, "..") == 0)
e27dec3c
PG
350 continue;
351 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
9df414fe 352 flog_err_sys(
450971aa 353 EC_LIB_SYSTEM_CALL,
9df414fe
QY
354 "NS parsing init: failed to parse entry %s",
355 dent->d_name);
e27dec3c
PG
356 continue;
357 }
358 if (S_ISDIR(st.st_mode)) {
9df414fe
QY
359 zlog_debug("NS parsing init: %s is not a NS",
360 dent->d_name);
e27dec3c
PG
361 continue;
362 }
167b0889
PG
363 /* check default name is not already set */
364 if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) {
3efd0893 365 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name);
167b0889
PG
366 continue;
367 }
3ed78e8c
PG
368 if (zebra_ns_notify_is_default_netns(dent->d_name)) {
369 zlog_warn(
3efd0893 370 "NS notify : NS %s is default VRF. Updating VRF Name", dent->d_name);
4fe52e76 371 vrf_set_default_name(dent->d_name, false);
3ed78e8c
PG
372 continue;
373 }
e27dec3c
PG
374 zebra_ns_notify_create_context_from_entry_name(dent->d_name);
375 }
376 closedir(srcdir);
377}
378
379void zebra_ns_notify_init(void)
380{
381 int fd_monitor;
382
e27dec3c
PG
383 fd_monitor = inotify_init();
384 if (fd_monitor < 0) {
9df414fe 385 flog_err_sys(
450971aa 386 EC_LIB_SYSTEM_CALL,
9df414fe
QY
387 "NS notify init: failed to initialize inotify (%s)",
388 safe_strerror(errno));
e27dec3c 389 }
0c902ba5
PG
390 if (inotify_add_watch(fd_monitor, NS_RUN_DIR,
391 IN_CREATE | IN_DELETE) < 0) {
450971aa 392 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe
QY
393 "NS notify watch: failed to add watch (%s)",
394 safe_strerror(errno));
e27dec3c 395 }
ee1455dd
IR
396 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
397 &zebra_netns_notify_current);
e27dec3c
PG
398}
399
400void zebra_ns_notify_close(void)
401{
402 if (zebra_netns_notify_current == NULL)
403 return;
404
405 int fd = 0;
406
407 if (zebra_netns_notify_current->u.fd > 0)
408 fd = zebra_netns_notify_current->u.fd;
71077c48
MS
409
410 if (zebra_netns_notify_current->master != NULL)
b3d6bc6e 411 thread_cancel(&zebra_netns_notify_current);
71077c48
MS
412
413 /* auto-removal of notify items */
e27dec3c
PG
414 if (fd > 0)
415 close(fd);
416}
417
418#else
419void zebra_ns_notify_parse(void)
420{
421}
422
423void zebra_ns_notify_init(void)
424{
425}
426
427void zebra_ns_notify_close(void)
428{
429}
430#endif /* !HAVE_NETLINK */