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