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