Coverage Report

Created: 2025-10-08 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/zebra/zebra_netns_notify.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Zebra NS collector and notifier for Network NameSpaces
4
 * Copyright (C) 2017 6WIND
5
 */
6
7
#include <zebra.h>
8
9
#ifdef HAVE_NETLINK
10
#ifdef HAVE_NETNS
11
#undef _GNU_SOURCE
12
#define _GNU_SOURCE
13
14
#include <sched.h>
15
#endif
16
#include <dirent.h>
17
#include <sys/inotify.h>
18
#include <sys/stat.h>
19
20
#include "frrevent.h"
21
#include "ns.h"
22
#include "command.h"
23
#include "memory.h"
24
#include "lib_errors.h"
25
26
#include "zebra_router.h"
27
#endif /* defined(HAVE_NETLINK) */
28
29
#include "zebra_netns_notify.h"
30
#include "zebra_netns_id.h"
31
#include "zebra_errors.h"
32
#include "interface.h"
33
34
#ifdef HAVE_NETLINK
35
36
/* upon creation of folder under /var/run/netns,
37
 * wait that netns context is bound to
38
 * that folder 10 seconds
39
 */
40
#define ZEBRA_NS_POLLING_INTERVAL_MSEC     1000
41
#define ZEBRA_NS_POLLING_MAX_RETRIES  200
42
43
2
DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo");
44
2
static struct event *zebra_netns_notify_current;
45
2
46
2
struct zebra_netns_info {
47
2
  const char *netnspath;
48
2
  unsigned int retries;
49
2
};
50
2
51
2
static void zebra_ns_ready_read(struct event *t);
52
2
static void zebra_ns_notify_create_context_from_entry_name(const char *name);
53
2
static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
54
2
          int stop_retry);
55
2
static void zebra_ns_notify_read(struct event *t);
56
2
57
2
static struct vrf *vrf_handler_create(struct vty *vty, const char *vrfname)
58
2
{
59
0
  if (strlen(vrfname) > VRF_NAMSIZ) {
60
0
    flog_warn(EC_LIB_VRF_LENGTH,
61
0
        "%% VRF name %s invalid: length exceeds %d bytes",
62
0
        vrfname, VRF_NAMSIZ);
63
0
    return NULL;
64
0
  }
65
66
0
  return vrf_get(VRF_UNKNOWN, vrfname);
67
0
}
68
69
static void zebra_ns_notify_create_context_from_entry_name(const char *name)
70
0
{
71
0
  char *netnspath = ns_netns_pathname(NULL, name);
72
0
  struct vrf *vrf;
73
0
  int ret;
74
0
  ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
75
0
  struct ns *default_ns;
76
77
0
  if (netnspath == NULL)
78
0
    return;
79
80
0
  frr_with_privs(&zserv_privs) {
81
0
    ns_id = zebra_ns_id_get(netnspath, -1);
82
0
  }
83
0
  if (ns_id == NS_UNKNOWN)
84
0
    return;
85
0
  ns_id_external = ns_map_nsid_with_external(ns_id, true);
86
  /* if VRF with NS ID already present */
87
0
  vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external);
88
0
  if (vrf) {
89
0
    zlog_debug(
90
0
      "NS notify : same NSID used by VRF %s. Ignore NS %s creation",
91
0
      vrf->name, netnspath);
92
0
    return;
93
0
  }
94
0
  vrf = vrf_handler_create(NULL, name);
95
0
  if (!vrf) {
96
0
    flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
97
0
        "NS notify : failed to create VRF %s", name);
98
0
    ns_map_nsid_with_external(ns_id, false);
99
0
    return;
100
0
  }
101
102
0
  default_ns = ns_get_default();
103
104
  /* force kernel ns_id creation in that new vrf */
105
0
  frr_with_privs(&zserv_privs) {
106
0
    ns_switch_to_netns(netnspath);
107
0
    ns_id_relative = zebra_ns_id_get(NULL, default_ns->fd);
108
0
    ns_switchback_to_initial();
109
0
  }
110
111
0
  frr_with_privs(&zserv_privs) {
112
0
    ret = zebra_vrf_netns_handler_create(NULL, vrf, netnspath,
113
0
                 ns_id_external, ns_id,
114
0
                 ns_id_relative);
115
0
  }
116
0
  if (ret != CMD_SUCCESS) {
117
0
    flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
118
0
        "NS notify : failed to create NS %s", netnspath);
119
0
    ns_map_nsid_with_external(ns_id, false);
120
0
    vrf_delete(vrf);
121
0
    return;
122
0
  }
123
0
  zlog_info("NS notify : created VRF %s NS %s", name, netnspath);
124
0
}
125
126
static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
127
          int stop_retry)
128
0
{
129
0
  void *ns_path_ptr = (void *)zns_info->netnspath;
130
0
131
0
  if (stop_retry) {
132
0
    XFREE(MTYPE_NETNS_MISC, ns_path_ptr);
133
0
    XFREE(MTYPE_NETNS_MISC, zns_info);
134
0
    return 0;
135
0
  }
136
0
  event_add_timer_msec(zrouter.master, zebra_ns_ready_read,
137
0
           (void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC,
138
0
           NULL);
139
0
  return 0;
140
0
}
141
142
static int zebra_ns_delete(char *name)
143
0
{
144
0
  struct vrf *vrf = vrf_lookup_by_name(name);
145
0
  struct interface *ifp, *tmp;
146
0
  struct ns *ns;
147
0
148
0
  if (!vrf) {
149
0
    flog_warn(EC_ZEBRA_NS_DELETION_FAILED_NO_VRF,
150
0
        "NS notify : no VRF found using NS %s", name);
151
0
    return 0;
152
0
  }
153
0
154
0
  /*
155
0
   * We don't receive interface down/delete notifications from kernel
156
0
   * when a netns is deleted. Therefore we have to manually replicate
157
0
   * the necessary actions here.
158
0
   */
159
0
  RB_FOREACH_SAFE (ifp, if_name_head, &vrf->ifaces_by_name, tmp) {
160
0
    if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE))
161
0
      continue;
162
0
163
0
    if (if_is_no_ptm_operative(ifp)) {
164
0
      UNSET_FLAG(ifp->flags, IFF_RUNNING);
165
0
      if_down(ifp);
166
0
    }
167
0
168
0
    if (IS_ZEBRA_IF_BOND(ifp))
169
0
      zebra_l2if_update_bond(ifp, false);
170
0
    if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
171
0
      zebra_l2if_update_bond_slave(ifp, IFINDEX_INTERNAL,
172
0
                 false);
173
0
    /* Special handling for bridge or VxLAN interfaces. */
174
0
    if (IS_ZEBRA_IF_BRIDGE(ifp))
175
0
      zebra_l2_bridge_del(ifp);
176
0
    else if (IS_ZEBRA_IF_VXLAN(ifp))
177
0
      zebra_l2_vxlanif_del(ifp);
178
0
179
0
    UNSET_FLAG(ifp->flags, IFF_UP);
180
0
    if_delete_update(&ifp);
181
0
  }
182
0
183
0
  ns = (struct ns *)vrf->ns_ctxt;
184
0
  /* the deletion order is the same
185
0
   * as the one used when siging signal is received
186
0
   */
187
0
  vrf->ns_ctxt = NULL;
188
0
  vrf_delete(vrf);
189
0
  if (ns)
190
0
    ns_delete(ns);
191
0
192
0
  zlog_info("NS notify : deleted VRF %s", name);
193
0
  return 0;
194
0
}
195
196
static int zebra_ns_notify_self_identify(struct stat *netst)
197
0
{
198
0
  char net_path[PATH_MAX];
199
0
  int netns;
200
201
0
  snprintf(net_path, sizeof(net_path), "/proc/self/ns/net");
202
0
  netns = open(net_path, O_RDONLY);
203
0
  if (netns < 0)
204
0
    return -1;
205
0
  if (fstat(netns, netst) < 0) {
206
0
    close(netns);
207
0
    return -1;
208
0
  }
209
0
  close(netns);
210
0
  return 0;
211
0
}
212
213
static bool zebra_ns_notify_is_default_netns(const char *name)
214
0
{
215
0
  struct stat default_netns_stat;
216
0
  struct stat st;
217
0
  char netnspath[PATH_MAX];
218
219
0
  if (zebra_ns_notify_self_identify(&default_netns_stat))
220
0
    return false;
221
222
0
  memset(&st, 0, sizeof(st));
223
0
  snprintf(netnspath, sizeof(netnspath), "%s/%s", NS_RUN_DIR, name);
224
  /* compare with local stat */
225
0
  if (stat(netnspath, &st) == 0 &&
226
0
      (st.st_dev == default_netns_stat.st_dev) &&
227
0
      (st.st_ino == default_netns_stat.st_ino))
228
0
    return true;
229
0
  return false;
230
0
}
231
232
static void zebra_ns_ready_read(struct event *t)
233
0
{
234
0
  struct zebra_netns_info *zns_info = EVENT_ARG(t);
235
0
  const char *netnspath;
236
0
  int err, stop_retry = 0;
237
0
238
0
  if (!zns_info)
239
0
    return;
240
0
  if (!zns_info->netnspath) {
241
0
    XFREE(MTYPE_NETNS_MISC, zns_info);
242
0
    return;
243
0
  }
244
0
  netnspath = zns_info->netnspath;
245
0
  if (--zns_info->retries == 0)
246
0
    stop_retry = 1;
247
0
  frr_with_privs(&zserv_privs) {
248
0
    err = ns_switch_to_netns(netnspath);
249
0
  }
250
0
  if (err < 0) {
251
0
    zebra_ns_continue_read(zns_info, stop_retry);
252
0
    return;
253
0
  }
254
0
255
0
  /* go back to default ns */
256
0
  frr_with_privs(&zserv_privs) {
257
0
    err = ns_switchback_to_initial();
258
0
  }
259
0
  if (err < 0) {
260
0
    zebra_ns_continue_read(zns_info, stop_retry);
261
0
    return;
262
0
  }
263
0
264
0
  /* check default name is not already set */
265
0
  if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) {
266
0
    zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath));
267
0
    zebra_ns_continue_read(zns_info, 1);
268
0
    return;
269
0
  }
270
0
  if (zebra_ns_notify_is_default_netns(basename(netnspath))) {
271
0
    zlog_warn(
272
0
      "NS notify : NS %s is default VRF. Ignore VRF creation",
273
0
      basename(netnspath));
274
0
    zebra_ns_continue_read(zns_info, 1);
275
0
    return;
276
0
  }
277
0
278
0
  /* success : close fd and create zns context */
279
0
  zebra_ns_notify_create_context_from_entry_name(basename(netnspath));
280
0
  zebra_ns_continue_read(zns_info, 1);
281
0
}
282
283
static void zebra_ns_notify_read(struct event *t)
284
0
{
285
0
  int fd_monitor = EVENT_FD(t);
286
0
  struct inotify_event *event;
287
0
  char buf[BUFSIZ];
288
0
  ssize_t len;
289
0
  char event_name[NAME_MAX + 1];
290
0
291
0
  event_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
292
0
           &zebra_netns_notify_current);
293
0
  len = read(fd_monitor, buf, sizeof(buf));
294
0
  if (len < 0) {
295
0
    flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
296
0
           "NS notify read: failed to read (%s)",
297
0
           safe_strerror(errno));
298
0
    return;
299
0
  }
300
0
  for (event = (struct inotify_event *)buf; (char *)event < &buf[len];
301
0
       event = (struct inotify_event *)((char *)event + sizeof(*event)
302
0
                + event->len)) {
303
0
    char *netnspath;
304
0
    struct zebra_netns_info *netnsinfo;
305
0
306
0
    if (!(event->mask & (IN_CREATE | IN_DELETE)))
307
0
      continue;
308
0
309
0
    if (offsetof(struct inotify_event, name) + event->len
310
0
        >= sizeof(buf)) {
311
0
      flog_err(EC_ZEBRA_NS_NOTIFY_READ,
312
0
         "NS notify read: buffer underflow");
313
0
      break;
314
0
    }
315
0
316
0
    if (strnlen(event->name, event->len) == event->len) {
317
0
      flog_err(EC_ZEBRA_NS_NOTIFY_READ,
318
0
         "NS notify error: bad event name");
319
0
      break;
320
0
    }
321
0
322
0
    /*
323
0
     * Coverity Scan extra steps to satisfy `STRING_NULL` warning:
324
0
     * - Make sure event name is present by checking `len != 0`
325
0
     * - Event name length must be at most `NAME_MAX + 1`
326
0
     *   (null byte inclusive)
327
0
     * - Copy event name to a stack buffer to make sure it
328
0
     *   includes the null byte. `event->name` includes at least
329
0
     *   one null byte and `event->len` accounts the null bytes,
330
0
     *   so the operation after `memcpy` will look like a
331
0
     *   truncation to satisfy Coverity Scan null byte ending.
332
0
     *
333
0
     *   Example:
334
0
     *   if `event->name` is `abc\0` and `event->len` is 4,
335
0
     *   `memcpy` will copy the 4 bytes and then we set the
336
0
     *   null byte again at the position 4.
337
0
     *
338
0
     * For more information please read inotify(7) man page.
339
0
     */
340
0
    if (event->len == 0)
341
0
      continue;
342
0
343
0
    if (event->len > sizeof(event_name)) {
344
0
      flog_err(EC_ZEBRA_NS_NOTIFY_READ,
345
0
         "NS notify error: unexpected big event name");
346
0
      break;
347
0
    }
348
0
349
0
    memcpy(event_name, event->name, event->len);
350
0
    event_name[event->len - 1] = 0;
351
0
352
0
    if (event->mask & IN_DELETE) {
353
0
      zebra_ns_delete(event_name);
354
0
      continue;
355
0
    }
356
0
    netnspath = ns_netns_pathname(NULL, event_name);
357
0
    if (!netnspath)
358
0
      continue;
359
0
    netnspath = XSTRDUP(MTYPE_NETNS_MISC, netnspath);
360
0
    netnsinfo = XCALLOC(MTYPE_NETNS_MISC,
361
0
            sizeof(struct zebra_netns_info));
362
0
    netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES;
363
0
    netnsinfo->netnspath = netnspath;
364
0
    event_add_timer_msec(zrouter.master, zebra_ns_ready_read,
365
0
             (void *)netnsinfo, 0, NULL);
366
0
  }
367
0
}
368
369
void zebra_ns_notify_parse(void)
370
0
{
371
0
  struct dirent *dent;
372
0
  DIR *srcdir = opendir(NS_RUN_DIR);
373
374
0
  if (srcdir == NULL) {
375
0
    flog_err_sys(EC_LIB_SYSTEM_CALL,
376
0
           "NS parsing init: failed to parse %s", NS_RUN_DIR);
377
0
    return;
378
0
  }
379
0
  while ((dent = readdir(srcdir)) != NULL) {
380
0
    struct stat st;
381
382
0
    if (strcmp(dent->d_name, ".") == 0
383
0
        || strcmp(dent->d_name, "..") == 0)
384
0
      continue;
385
0
    if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
386
0
      flog_err_sys(
387
0
        EC_LIB_SYSTEM_CALL,
388
0
        "NS parsing init: failed to parse entry %s",
389
0
        dent->d_name);
390
0
      continue;
391
0
    }
392
0
    if (S_ISDIR(st.st_mode)) {
393
0
      zlog_debug("NS parsing init: %s is not a NS",
394
0
           dent->d_name);
395
0
      continue;
396
0
    }
397
    /* check default name is not already set */
398
0
    if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) {
399
0
      zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name);
400
0
      continue;
401
0
    }
402
0
    if (zebra_ns_notify_is_default_netns(dent->d_name)) {
403
0
      zlog_warn(
404
0
        "NS notify : NS %s is default VRF. Ignore VRF creation",
405
0
        dent->d_name);
406
0
      continue;
407
0
    }
408
0
    zebra_ns_notify_create_context_from_entry_name(dent->d_name);
409
0
  }
410
0
  closedir(srcdir);
411
0
}
412
413
void zebra_ns_notify_init(void)
414
0
{
415
0
  int fd_monitor;
416
417
0
  fd_monitor = inotify_init();
418
0
  if (fd_monitor < 0) {
419
0
    flog_err_sys(
420
0
      EC_LIB_SYSTEM_CALL,
421
0
      "NS notify init: failed to initialize inotify (%s)",
422
0
      safe_strerror(errno));
423
0
  }
424
0
  if (inotify_add_watch(fd_monitor, NS_RUN_DIR,
425
0
            IN_CREATE | IN_DELETE) < 0) {
426
0
    flog_err_sys(EC_LIB_SYSTEM_CALL,
427
0
           "NS notify watch: failed to add watch (%s)",
428
0
           safe_strerror(errno));
429
0
  }
430
0
  event_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor,
431
0
           &zebra_netns_notify_current);
432
0
}
433
434
void zebra_ns_notify_close(void)
435
0
{
436
0
  if (zebra_netns_notify_current == NULL)
437
0
    return;
438
439
0
  int fd = 0;
440
441
0
  if (zebra_netns_notify_current->u.fd > 0)
442
0
    fd = zebra_netns_notify_current->u.fd;
443
444
0
  if (zebra_netns_notify_current->master != NULL)
445
0
    EVENT_OFF(zebra_netns_notify_current);
446
447
  /* auto-removal of notify items */
448
0
  if (fd > 0)
449
0
    close(fd);
450
0
}
451
452
#else
453
void zebra_ns_notify_parse(void)
454
{
455
}
456
457
void zebra_ns_notify_init(void)
458
{
459
}
460
461
void zebra_ns_notify_close(void)
462
{
463
}
464
#endif /* !HAVE_NETLINK */