]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_netns_notify.c
Merge pull request #9930 from donaldsharp/all_protocol_sporadic
[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"
e27dec3c
PG
45
46#ifdef HAVE_NETLINK
47
48/* upon creation of folder under /var/run/netns,
49 * wait that netns context is bound to
50 * that folder 10 seconds
51 */
52#define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000
53#define ZEBRA_NS_POLLING_MAX_RETRIES 200
54
bf8d3d6a 55DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo");
e27dec3c
PG
56static struct thread *zebra_netns_notify_current;
57
58struct zebra_netns_info {
59 const char *netnspath;
60 unsigned int retries;
61};
62
63static int zebra_ns_ready_read(struct thread *t);
64static void zebra_ns_notify_create_context_from_entry_name(const char *name);
65static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
66 int stop_retry);
67static int zebra_ns_notify_read(struct thread *t);
68
62d89c64
IR
69static struct vrf *vrf_handler_create(struct vty *vty, const char *vrfname)
70{
71 if (strlen(vrfname) > VRF_NAMSIZ) {
72 flog_warn(EC_LIB_VRF_LENGTH,
73 "%% VRF name %s invalid: length exceeds %d bytes",
74 vrfname, VRF_NAMSIZ);
75 return NULL;
76 }
77
78 return vrf_get(VRF_UNKNOWN, vrfname);
79}
80
e27dec3c
PG
81static void zebra_ns_notify_create_context_from_entry_name(const char *name)
82{
83 char *netnspath = ns_netns_pathname(NULL, name);
84 struct vrf *vrf;
85 int ret;
2d4e4d39
PG
86 ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
87 struct ns *default_ns;
e27dec3c
PG
88
89 if (netnspath == NULL)
90 return;
91
0cf6db21 92 frr_with_privs(&zserv_privs) {
289b0f0d 93 ns_id = zebra_ns_id_get(netnspath, -1);
01b9e3fd 94 }
85a0edca
PG
95 if (ns_id == NS_UNKNOWN)
96 return;
03aff2d8 97 ns_id_external = ns_map_nsid_with_external(ns_id, true);
b7b816df 98 /* if VRF with NS ID already present */
03aff2d8 99 vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
b7b816df 100 if (vrf) {
9df414fe 101 zlog_debug(
996c9314
LB
102 "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
103 vrf->name, netnspath);
b7b816df
PG
104 return;
105 }
62d89c64
IR
106 vrf = vrf_handler_create(NULL, name);
107 if (!vrf) {
e914ccbe 108 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
9df414fe 109 "NS notify : failed to create VRF %s", name);
03aff2d8 110 ns_map_nsid_with_external(ns_id, false);
b7b816df
PG
111 return;
112 }
289b0f0d
PG
113
114 default_ns = ns_get_default();
115
116 /* force kernel ns_id creation in that new vrf */
117 frr_with_privs(&zserv_privs) {
118 ns_switch_to_netns(netnspath);
119 ns_id_relative = zebra_ns_id_get(NULL, default_ns->fd);
120 ns_switchback_to_initial();
121 }
122
0cf6db21 123 frr_with_privs(&zserv_privs) {
62d89c64
IR
124 ret = zebra_vrf_netns_handler_create(NULL, vrf, netnspath,
125 ns_id_external, ns_id,
126 ns_id_relative);
01b9e3fd 127 }
e27dec3c 128 if (ret != CMD_SUCCESS) {
e914ccbe 129 flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
9df414fe 130 "NS notify : failed to create NS %s", netnspath);
03aff2d8 131 ns_map_nsid_with_external(ns_id, false);
73899a2f 132 vrf_delete(vrf);
e27dec3c
PG
133 return;
134 }
996c9314 135 zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
e27dec3c
PG
136}
137
138static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
139 int stop_retry)
140{
141 void *ns_path_ptr = (void *)zns_info->netnspath;
142
143 if (stop_retry) {
144 XFREE(MTYPE_NETNS_MISC, ns_path_ptr);
145 XFREE(MTYPE_NETNS_MISC, zns_info);
146 return 0;
147 }
3801e764 148 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
996c9314
LB
149 (void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC,
150 NULL);
e27dec3c
PG
151 return 0;
152}
153
0c902ba5
PG
154static int zebra_ns_delete(char *name)
155{
156 struct vrf *vrf = vrf_lookup_by_name(name);
157 struct ns *ns;
158
159 if (!vrf) {
e914ccbe 160 flog_warn(EC_ZEBRA_NS_DELETION_FAILED_NO_VRF,
9df414fe 161 "NS notify : no VRF found using NS %s", name);
0c902ba5
PG
162 return 0;
163 }
0c902ba5
PG
164 ns = (struct ns *)vrf->ns_ctxt;
165 /* the deletion order is the same
166 * as the one used when siging signal is received
167 */
168 vrf_delete(vrf);
169 if (ns)
170 ns_delete(ns);
171
172 zlog_info("NS notify : deleted VRF %s", name);
173 return 0;
174}
175
3ed78e8c
PG
176static int zebra_ns_notify_self_identify(struct stat *netst)
177{
2b7165e7 178 char net_path[PATH_MAX];
3ed78e8c
PG
179 int netns;
180
772270f3 181 snprintf(net_path, sizeof(net_path), "/proc/self/ns/net");
3ed78e8c
PG
182 netns = open(net_path, O_RDONLY);
183 if (netns < 0)
184 return -1;
185 if (fstat(netns, netst) < 0) {
186 close(netns);
187 return -1;
188 }
189 close(netns);
190 return 0;
191}
192
193static bool zebra_ns_notify_is_default_netns(const char *name)
194{
195 struct stat default_netns_stat;
196 struct stat st;
f177a83e 197 char netnspath[PATH_MAX];
3ed78e8c
PG
198
199 if (zebra_ns_notify_self_identify(&default_netns_stat))
200 return false;
201
202 memset(&st, 0, sizeof(struct stat));
772270f3 203 snprintf(netnspath, sizeof(netnspath), "%s/%s", NS_RUN_DIR, name);
3ed78e8c
PG
204 /* compare with local stat */
205 if (stat(netnspath, &st) == 0 &&
206 (st.st_dev == default_netns_stat.st_dev) &&
207 (st.st_ino == default_netns_stat.st_ino))
208 return true;
209 return false;
210}
0c902ba5 211
e27dec3c
PG
212static int zebra_ns_ready_read(struct thread *t)
213{
214 struct zebra_netns_info *zns_info = THREAD_ARG(t);
215 const char *netnspath;
216 int err, stop_retry = 0;
217
218 if (!zns_info)
219 return 0;
220 if (!zns_info->netnspath) {
221 XFREE(MTYPE_NETNS_MISC, zns_info);
222 return 0;
223 }
224 netnspath = zns_info->netnspath;
225 if (--zns_info->retries == 0)
226 stop_retry = 1;
0cf6db21 227 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
228 err = ns_switch_to_netns(netnspath);
229 }
e27dec3c
PG
230 if (err < 0)
231 return zebra_ns_continue_read(zns_info, stop_retry);
232
233 /* go back to default ns */
0cf6db21 234 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
235 err = ns_switchback_to_initial();
236 }
e27dec3c
PG
237 if (err < 0)
238 return zebra_ns_continue_read(zns_info, stop_retry);
239
167b0889
PG
240 /* check default name is not already set */
241 if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) {
3efd0893 242 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath));
167b0889
PG
243 return zebra_ns_continue_read(zns_info, 1);
244 }
3ed78e8c
PG
245 if (zebra_ns_notify_is_default_netns(basename(netnspath))) {
246 zlog_warn(
3efd0893 247 "NS notify : NS %s is default VRF. Updating VRF Name", basename(netnspath));
4fe52e76 248 vrf_set_default_name(basename(netnspath), false);
3ed78e8c
PG
249 return zebra_ns_continue_read(zns_info, 1);
250 }
251
e27dec3c
PG
252 /* success : close fd and create zns context */
253 zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
254 return zebra_ns_continue_read(zns_info, 1);
255}
256
257static int zebra_ns_notify_read(struct thread *t)
258{
259 int fd_monitor = THREAD_FD(t);
260 struct inotify_event *event;
261 char buf[BUFSIZ];
262 ssize_t len;
263
ee1455dd
IR
264 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
265 &zebra_netns_notify_current);
e27dec3c
PG
266 len = read(fd_monitor, buf, sizeof(buf));
267 if (len < 0) {
e914ccbe 268 flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe
QY
269 "NS notify read: failed to read (%s)",
270 safe_strerror(errno));
e27dec3c
PG
271 return 0;
272 }
996c9314
LB
273 for (event = (struct inotify_event *)buf; (char *)event < &buf[len];
274 event = (struct inotify_event *)((char *)event + sizeof(*event)
275 + event->len)) {
e27dec3c
PG
276 char *netnspath;
277 struct zebra_netns_info *netnsinfo;
278
0c902ba5 279 if (!(event->mask & (IN_CREATE | IN_DELETE)))
e27dec3c 280 continue;
45981fda 281
282 if (offsetof(struct inotify_event, name) + event->len
283 >= sizeof(buf)) {
e914ccbe 284 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 285 "NS notify read: buffer underflow");
32ac96b2 286 break;
287 }
b6312ad1 288
289 if (strnlen(event->name, event->len) == event->len) {
e914ccbe 290 flog_err(EC_ZEBRA_NS_NOTIFY_READ,
9df414fe 291 "NS notify error: bad event name");
b6312ad1 292 break;
293 }
294
f245bcae
PG
295 if (event->mask & IN_DELETE) {
296 zebra_ns_delete(event->name);
297 continue;
298 }
e27dec3c
PG
299 netnspath = ns_netns_pathname(NULL, event->name);
300 if (!netnspath)
301 continue;
302 netnspath = XSTRDUP(MTYPE_NETNS_MISC, netnspath);
303 netnsinfo = XCALLOC(MTYPE_NETNS_MISC,
304 sizeof(struct zebra_netns_info));
305 netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES;
306 netnsinfo->netnspath = netnspath;
3801e764 307 thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
996c9314 308 (void *)netnsinfo, 0, NULL);
e27dec3c
PG
309 }
310 return 0;
311}
312
313void zebra_ns_notify_parse(void)
314{
315 struct dirent *dent;
316 DIR *srcdir = opendir(NS_RUN_DIR);
317
318 if (srcdir == NULL) {
450971aa 319 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe 320 "NS parsing init: failed to parse %s", NS_RUN_DIR);
e27dec3c
PG
321 return;
322 }
323 while ((dent = readdir(srcdir)) != NULL) {
324 struct stat st;
325
326 if (strcmp(dent->d_name, ".") == 0
996c9314 327 || strcmp(dent->d_name, "..") == 0)
e27dec3c
PG
328 continue;
329 if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
9df414fe 330 flog_err_sys(
450971aa 331 EC_LIB_SYSTEM_CALL,
9df414fe
QY
332 "NS parsing init: failed to parse entry %s",
333 dent->d_name);
e27dec3c
PG
334 continue;
335 }
336 if (S_ISDIR(st.st_mode)) {
9df414fe
QY
337 zlog_debug("NS parsing init: %s is not a NS",
338 dent->d_name);
e27dec3c
PG
339 continue;
340 }
167b0889
PG
341 /* check default name is not already set */
342 if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) {
3efd0893 343 zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name);
167b0889
PG
344 continue;
345 }
3ed78e8c
PG
346 if (zebra_ns_notify_is_default_netns(dent->d_name)) {
347 zlog_warn(
3efd0893 348 "NS notify : NS %s is default VRF. Updating VRF Name", dent->d_name);
4fe52e76 349 vrf_set_default_name(dent->d_name, false);
3ed78e8c
PG
350 continue;
351 }
e27dec3c
PG
352 zebra_ns_notify_create_context_from_entry_name(dent->d_name);
353 }
354 closedir(srcdir);
355}
356
357void zebra_ns_notify_init(void)
358{
359 int fd_monitor;
360
e27dec3c
PG
361 fd_monitor = inotify_init();
362 if (fd_monitor < 0) {
9df414fe 363 flog_err_sys(
450971aa 364 EC_LIB_SYSTEM_CALL,
9df414fe
QY
365 "NS notify init: failed to initialize inotify (%s)",
366 safe_strerror(errno));
e27dec3c 367 }
0c902ba5
PG
368 if (inotify_add_watch(fd_monitor, NS_RUN_DIR,
369 IN_CREATE | IN_DELETE) < 0) {
450971aa 370 flog_err_sys(EC_LIB_SYSTEM_CALL,
9df414fe
QY
371 "NS notify watch: failed to add watch (%s)",
372 safe_strerror(errno));
e27dec3c 373 }
ee1455dd
IR
374 thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
375 &zebra_netns_notify_current);
e27dec3c
PG
376}
377
378void zebra_ns_notify_close(void)
379{
380 if (zebra_netns_notify_current == NULL)
381 return;
382
383 int fd = 0;
384
385 if (zebra_netns_notify_current->u.fd > 0)
386 fd = zebra_netns_notify_current->u.fd;
71077c48
MS
387
388 if (zebra_netns_notify_current->master != NULL)
b3d6bc6e 389 thread_cancel(&zebra_netns_notify_current);
71077c48
MS
390
391 /* auto-removal of notify items */
e27dec3c
PG
392 if (fd > 0)
393 close(fd);
394}
395
396#else
397void zebra_ns_notify_parse(void)
398{
399}
400
401void zebra_ns_notify_init(void)
402{
403}
404
405void zebra_ns_notify_close(void)
406{
407}
408#endif /* !HAVE_NETLINK */