back to topotato report
topotato coverage report
Current view: top level - lib - netns_linux.c (source / functions) Hit Total Coverage
Test: test_pim6_basic.py::PIM6Basic Lines: 130 254 51.2 %
Date: 2023-02-24 18:38:38 Functions: 23 33 69.7 %

          Line data    Source code
       1             : /*
       2             :  * NS functions.
       3             :  * Copyright (C) 2014 6WIND S.A.
       4             :  *
       5             :  * This file is part of GNU Zebra.
       6             :  *
       7             :  * GNU Zebra is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published
       9             :  * by the Free Software Foundation; either version 2, or (at your
      10             :  * option) any later version.
      11             :  *
      12             :  * GNU Zebra is distributed in the hope that it will be useful, but
      13             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with this program; see the file COPYING; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : 
      24             : #ifdef HAVE_NETNS
      25             : #undef _GNU_SOURCE
      26             : #define _GNU_SOURCE
      27             : 
      28             : #include <sched.h>
      29             : #endif
      30             : 
      31             : /* for basename */
      32             : #include <libgen.h>
      33             : 
      34             : #include "if.h"
      35             : #include "ns.h"
      36             : #include "log.h"
      37             : #include "memory.h"
      38             : #include "command.h"
      39             : #include "vty.h"
      40             : #include "vrf.h"
      41             : #include "lib_errors.h"
      42             : 
      43          22 : DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context");
      44          22 : DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name");
      45             : 
      46             : static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
      47             : static struct ns *ns_lookup_name_internal(const char *name);
      48             : 
      49          23 : RB_GENERATE(ns_head, ns, entry, ns_compare)
      50             : 
      51             : static struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
      52             : 
      53             : static struct ns *default_ns;
      54             : static int ns_current_ns_fd;
      55             : static int ns_default_ns_fd;
      56             : 
      57             : static int ns_debug;
      58             : 
      59             : struct ns_map_nsid {
      60             :         RB_ENTRY(ns_map_nsid) id_entry;
      61             :         ns_id_t ns_id_external;
      62             :         ns_id_t ns_id;
      63             : };
      64             : 
      65           0 : static inline int ns_map_compare(const struct ns_map_nsid *a,
      66             :                                    const struct ns_map_nsid *b)
      67             : {
      68           0 :         return (a->ns_id - b->ns_id);
      69             : }
      70             : 
      71             : RB_HEAD(ns_map_nsid_head, ns_map_nsid);
      72           4 : RB_PROTOTYPE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare);
      73           0 : RB_GENERATE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare);
      74             : static struct ns_map_nsid_head ns_map_nsid_list =
      75             :                 RB_INITIALIZER(&ns_map_nsid_list);
      76             : 
      77             : static ns_id_t ns_id_external_numbering;
      78             : 
      79             : 
      80             : #ifndef CLONE_NEWNET
      81             : #define CLONE_NEWNET 0x40000000
      82             : /* New network namespace (lo, device, names sockets, etc) */
      83             : #endif
      84             : 
      85             : #ifndef HAVE_SETNS
      86             : static inline int setns(int fd, int nstype)
      87             : {
      88             : #ifdef __NR_setns
      89             :         return syscall(__NR_setns, fd, nstype);
      90             : #else
      91             :         errno = EINVAL;
      92             :         return -1;
      93             : #endif
      94             : }
      95             : #endif /* !HAVE_SETNS */
      96             : 
      97             : #ifdef HAVE_NETNS
      98             : static int have_netns_enabled = -1;
      99             : #endif /* HAVE_NETNS */
     100             : 
     101          34 : static int have_netns(void)
     102             : {
     103             : #ifdef HAVE_NETNS
     104          34 :         if (have_netns_enabled < 0) {
     105           6 :                 int fd = open(NS_DEFAULT_NAME, O_RDONLY);
     106             : 
     107           6 :                 if (fd < 0)
     108           0 :                         have_netns_enabled = 0;
     109             :                 else {
     110           6 :                         have_netns_enabled = 1;
     111           6 :                         close(fd);
     112             :                 }
     113             :         }
     114          34 :         return have_netns_enabled;
     115             : #else
     116             :         return 0;
     117             : #endif
     118             : }
     119             : 
     120             : /* Holding NS hooks  */
     121             : static struct ns_master {
     122             :         int (*ns_new_hook)(struct ns *ns);
     123             :         int (*ns_delete_hook)(struct ns *ns);
     124             :         int (*ns_enable_hook)(struct ns *ns);
     125             :         int (*ns_disable_hook)(struct ns *ns);
     126             : } ns_master = {
     127             :         0,
     128             : };
     129             : 
     130             : static int ns_is_enabled(struct ns *ns);
     131             : 
     132          23 : static inline int ns_compare(const struct ns *a, const struct ns *b)
     133             : {
     134          23 :         return (a->ns_id - b->ns_id);
     135             : }
     136             : 
     137             : /* Look up a NS by identifier. */
     138          25 : static struct ns *ns_lookup_internal(ns_id_t ns_id)
     139             : {
     140          25 :         struct ns ns;
     141             : 
     142          25 :         ns.ns_id = ns_id;
     143          50 :         return RB_FIND(ns_head, &ns_tree, &ns);
     144             : }
     145             : 
     146             : /* Look up a NS by name */
     147           0 : static struct ns *ns_lookup_name_internal(const char *name)
     148             : {
     149           0 :         struct ns *ns = NULL;
     150             : 
     151           0 :         RB_FOREACH (ns, ns_head, &ns_tree) {
     152           0 :                 if (ns->name != NULL) {
     153           0 :                         if (strcmp(name, ns->name) == 0)
     154           0 :                                 return ns;
     155             :                 }
     156             :         }
     157             :         return NULL;
     158             : }
     159             : 
     160           2 : static struct ns *ns_get_created_internal(struct ns *ns, char *name,
     161             :                                           ns_id_t ns_id)
     162             : {
     163           2 :         int created = 0;
     164             :         /*
     165             :          * Initialize interfaces.
     166             :          */
     167           2 :         if (!ns && !name && ns_id != NS_UNKNOWN)
     168           2 :                 ns = ns_lookup_internal(ns_id);
     169           2 :         if (!ns && name)
     170           0 :                 ns = ns_lookup_name_internal(name);
     171           2 :         if (!ns) {
     172           2 :                 ns = XCALLOC(MTYPE_NS, sizeof(struct ns));
     173           2 :                 ns->ns_id = ns_id;
     174           2 :                 if (name)
     175           0 :                         ns->name = XSTRDUP(MTYPE_NS_NAME, name);
     176           2 :                 ns->fd = -1;
     177           2 :                 RB_INSERT(ns_head, &ns_tree, ns);
     178           2 :                 created = 1;
     179             :         }
     180           2 :         if (ns_id != ns->ns_id) {
     181           0 :                 RB_REMOVE(ns_head, &ns_tree, ns);
     182           0 :                 ns->ns_id = ns_id;
     183           0 :                 RB_INSERT(ns_head, &ns_tree, ns);
     184             :         }
     185           2 :         if (!created)
     186             :                 return ns;
     187           2 :         if (ns_debug) {
     188           0 :                 if (ns->ns_id != NS_UNKNOWN)
     189           0 :                         zlog_info("NS %u is created.", ns->ns_id);
     190             :                 else
     191           0 :                         zlog_info("NS %s is created.", ns->name);
     192             :         }
     193           2 :         if (ns_master.ns_new_hook)
     194           0 :                 (*ns_master.ns_new_hook)(ns);
     195             :         return ns;
     196             : }
     197             : 
     198             : /*
     199             :  * Enable a NS - that is, let the NS be ready to use.
     200             :  * The NS_ENABLE_HOOK callback will be called to inform
     201             :  * that they can allocate resources in this NS.
     202             :  *
     203             :  * RETURN: 1 - enabled successfully; otherwise, 0.
     204             :  */
     205           2 : static int ns_enable_internal(struct ns *ns, void (*func)(ns_id_t, void *))
     206             : {
     207           2 :         if (!ns_is_enabled(ns)) {
     208           0 :                 if (have_netns()) {
     209           0 :                         ns->fd = open(ns->name, O_RDONLY);
     210             :                 } else {
     211           0 :                         ns->fd = -2;
     212             :                         /* Remember ns_enable_hook has been called */
     213           0 :                         errno = -ENOTSUP;
     214             :                 }
     215             : 
     216           0 :                 if (!ns_is_enabled(ns)) {
     217           0 :                         flog_err_sys(EC_LIB_SYSTEM_CALL,
     218             :                                      "Can not enable NS %u: %s!", ns->ns_id,
     219             :                                      safe_strerror(errno));
     220           0 :                         return 0;
     221             :                 }
     222             : 
     223             :                 /* Non default NS. leave */
     224           0 :                 if (ns->ns_id == NS_UNKNOWN) {
     225           0 :                         flog_err(EC_LIB_NS,
     226             :                                  "Can not enable NS %s %u: Invalid NSID",
     227             :                                  ns->name, ns->ns_id);
     228           0 :                         return 0;
     229             :                 }
     230           0 :                 if (func)
     231           0 :                         func(ns->ns_id, (void *)ns->vrf_ctxt);
     232           0 :                 if (ns_debug) {
     233           0 :                         if (have_netns())
     234           0 :                                 zlog_info("NS %u is associated with NETNS %s.",
     235             :                                           ns->ns_id, ns->name);
     236           0 :                         zlog_info("NS %u is enabled.", ns->ns_id);
     237             :                 }
     238             :                 /* zebra first receives NS enable event,
     239             :                  * then VRF enable event
     240             :                  */
     241           0 :                 if (ns_master.ns_enable_hook)
     242           0 :                         (*ns_master.ns_enable_hook)(ns);
     243             :         }
     244             : 
     245             :         return 1;
     246             : }
     247             : 
     248             : /*
     249             :  * Check whether the NS is enabled - that is, whether the NS
     250             :  * is ready to allocate resources. Currently there's only one
     251             :  * type of resource: socket.
     252             :  */
     253          14 : static int ns_is_enabled(struct ns *ns)
     254             : {
     255          14 :         if (have_netns())
     256          14 :                 return ns && ns->fd >= 0;
     257             :         else
     258           0 :                 return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT;
     259             : }
     260             : 
     261             : /*
     262             :  * Disable a NS - that is, let the NS be unusable.
     263             :  * The NS_DELETE_HOOK callback will be called to inform
     264             :  * that they must release the resources in the NS.
     265             :  */
     266           2 : static void ns_disable_internal(struct ns *ns)
     267             : {
     268           2 :         if (ns_is_enabled(ns)) {
     269           2 :                 if (ns_debug)
     270           0 :                         zlog_info("NS %u is to be disabled.", ns->ns_id);
     271             : 
     272           2 :                 if (ns_master.ns_disable_hook)
     273           0 :                         (*ns_master.ns_disable_hook)(ns);
     274             : 
     275           2 :                 if (have_netns())
     276           2 :                         close(ns->fd);
     277             : 
     278           2 :                 ns->fd = -1;
     279             :         }
     280           2 : }
     281             : 
     282             : /* VRF list existence check by name. */
     283           2 : static struct ns_map_nsid *ns_map_nsid_lookup_by_nsid(ns_id_t ns_id)
     284             : {
     285           2 :         struct ns_map_nsid ns_map;
     286             : 
     287           2 :         ns_map.ns_id = ns_id;
     288           4 :         return RB_FIND(ns_map_nsid_head, &ns_map_nsid_list, &ns_map);
     289             : }
     290             : 
     291           2 : ns_id_t ns_map_nsid_with_external(ns_id_t ns_id, bool map)
     292             : {
     293           2 :         struct ns_map_nsid *ns_map;
     294           2 :         vrf_id_t ns_id_external;
     295             : 
     296           2 :         ns_map = ns_map_nsid_lookup_by_nsid(ns_id);
     297           2 :         if (ns_map && !map) {
     298           0 :                 ns_id_external = ns_map->ns_id_external;
     299           0 :                 RB_REMOVE(ns_map_nsid_head, &ns_map_nsid_list, ns_map);
     300           0 :                 return ns_id_external;
     301             :         }
     302           2 :         if (ns_map)
     303           0 :                 return ns_map->ns_id_external;
     304           2 :         ns_map = XCALLOC(MTYPE_NS, sizeof(struct ns_map_nsid));
     305             :         /* increase vrf_id
     306             :          * default vrf is the first one : 0
     307             :          */
     308           2 :         ns_map->ns_id_external = ns_id_external_numbering++;
     309           2 :         ns_map->ns_id = ns_id;
     310           2 :         RB_INSERT(ns_map_nsid_head, &ns_map_nsid_list, ns_map);
     311           2 :         return ns_map->ns_id_external;
     312             : }
     313             : 
     314           0 : struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id)
     315             : {
     316           0 :         return ns_get_created_internal(ns, name, ns_id);
     317             : }
     318             : 
     319           0 : int ns_have_netns(void)
     320             : {
     321           0 :         return have_netns();
     322             : }
     323             : 
     324             : /* Delete a NS. This is called in ns_terminate(). */
     325           2 : void ns_delete(struct ns *ns)
     326             : {
     327           2 :         if (ns_debug)
     328           0 :                 zlog_info("NS %u is to be deleted.", ns->ns_id);
     329             : 
     330           2 :         ns_disable(ns);
     331             : 
     332           2 :         if (ns_master.ns_delete_hook)
     333           0 :                 (*ns_master.ns_delete_hook)(ns);
     334             : 
     335             :         /*
     336             :          * I'm not entirely sure if the vrf->iflist
     337             :          * needs to be moved into here or not.
     338             :          */
     339             :         // if_terminate (&ns->iflist);
     340             : 
     341           2 :         RB_REMOVE(ns_head, &ns_tree, ns);
     342           2 :         XFREE(MTYPE_NS_NAME, ns->name);
     343             : 
     344           2 :         XFREE(MTYPE_NS, ns);
     345           2 : }
     346             : 
     347             : /* Look up the data pointer of the specified VRF. */
     348           0 : void *ns_info_lookup(ns_id_t ns_id)
     349             : {
     350           0 :         struct ns *ns = ns_lookup_internal(ns_id);
     351             : 
     352           0 :         return ns ? ns->info : NULL;
     353             : }
     354             : 
     355             : /* Look up a NS by name */
     356           0 : struct ns *ns_lookup_name(const char *name)
     357             : {
     358           0 :         return ns_lookup_name_internal(name);
     359             : }
     360             : 
     361           2 : int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *))
     362             : {
     363           2 :         return ns_enable_internal(ns, func);
     364             : }
     365             : 
     366           2 : void ns_disable(struct ns *ns)
     367             : {
     368           2 :         ns_disable_internal(ns);
     369           2 : }
     370             : 
     371          23 : struct ns *ns_lookup(ns_id_t ns_id)
     372             : {
     373          23 :         return ns_lookup_internal(ns_id);
     374             : }
     375             : 
     376           4 : void ns_walk_func(int (*func)(struct ns *,
     377             :                               void *param_in,
     378             :                               void **param_out),
     379             :                   void *param_in,
     380             :                   void **param_out)
     381             : {
     382           4 :         struct ns *ns = NULL;
     383           4 :         int ret;
     384             : 
     385          12 :         RB_FOREACH (ns, ns_head, &ns_tree) {
     386           4 :                 ret = func(ns, param_in, param_out);
     387           4 :                 if (ret == NS_WALK_STOP)
     388             :                         return;
     389             :         }
     390             : }
     391             : 
     392           0 : const char *ns_get_name(struct ns *ns)
     393             : {
     394           0 :         if (!ns)
     395             :                 return NULL;
     396           0 :         return ns->name;
     397             : }
     398             : 
     399             : /* Add a NS hook. Please add hooks before calling ns_init(). */
     400           0 : void ns_add_hook(int type, int (*func)(struct ns *))
     401             : {
     402           0 :         switch (type) {
     403           0 :         case NS_NEW_HOOK:
     404           0 :                 ns_master.ns_new_hook = func;
     405           0 :                 break;
     406           0 :         case NS_DELETE_HOOK:
     407           0 :                 ns_master.ns_delete_hook = func;
     408           0 :                 break;
     409           0 :         case NS_ENABLE_HOOK:
     410           0 :                 ns_master.ns_enable_hook = func;
     411           0 :                 break;
     412           0 :         case NS_DISABLE_HOOK:
     413           0 :                 ns_master.ns_disable_hook = func;
     414           0 :                 break;
     415             :         default:
     416             :                 break;
     417             :         }
     418           0 : }
     419             : 
     420             : /*
     421             :  * NS realization with NETNS
     422             :  */
     423             : 
     424           0 : char *ns_netns_pathname(struct vty *vty, const char *name)
     425             : {
     426           0 :         static char pathname[PATH_MAX];
     427           0 :         char *result;
     428           0 :         char *check_base;
     429             : 
     430           0 :         if (name[0] == '/') /* absolute pathname */
     431           0 :                 result = realpath(name, pathname);
     432             :         else {
     433             :                 /* relevant pathname */
     434           0 :                 char tmp_name[PATH_MAX];
     435             : 
     436           0 :                 snprintf(tmp_name, sizeof(tmp_name), "%s/%s", NS_RUN_DIR, name);
     437           0 :                 result = realpath(tmp_name, pathname);
     438             :         }
     439             : 
     440           0 :         if (!result) {
     441           0 :                 if (vty)
     442           0 :                         vty_out(vty, "Invalid pathname for %s: %s\n",
     443             :                                 pathname,
     444           0 :                                 safe_strerror(errno));
     445             :                 else
     446           0 :                         flog_warn(EC_LIB_LINUX_NS,
     447             :                                   "Invalid pathname for %s: %s", pathname,
     448             :                                   safe_strerror(errno));
     449           0 :                 return NULL;
     450             :         }
     451           0 :         check_base = basename(pathname);
     452           0 :         if (check_base != NULL && strlen(check_base) + 1 > NS_NAMSIZ) {
     453           0 :                 if (vty)
     454           0 :                         vty_out(vty, "NS name (%s) invalid: too long (>%d)\n",
     455             :                                 check_base, NS_NAMSIZ - 1);
     456             :                 else
     457           0 :                         flog_warn(EC_LIB_LINUX_NS,
     458             :                                   "NS name (%s) invalid: too long (>%d)",
     459             :                                   check_base, NS_NAMSIZ - 1);
     460           0 :                 return NULL;
     461             :         }
     462             :         return pathname;
     463             : }
     464             : 
     465           8 : void ns_init(void)
     466             : {
     467           8 :         static int ns_initialised;
     468             : 
     469           8 :         ns_debug = 0;
     470             :         /* silently return as initialisation done */
     471           8 :         if (ns_initialised == 1)
     472             :                 return;
     473           6 :         errno = 0;
     474           6 :         if (have_netns())
     475           6 :                 ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY);
     476             :         else {
     477           0 :                 ns_default_ns_fd = -1;
     478           0 :                 default_ns = NULL;
     479             :         }
     480           6 :         ns_current_ns_fd = -1;
     481           6 :         ns_initialised = 1;
     482             : }
     483             : 
     484             : /* Initialize NS module. */
     485           2 : void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns)
     486             : {
     487           2 :         int fd;
     488             : 
     489           2 :         ns_init();
     490           2 :         default_ns = ns_get_created_internal(NULL, NULL, default_ns_id);
     491           2 :         if (!default_ns) {
     492           0 :                 flog_err(EC_LIB_NS, "%s: failed to create the default NS!",
     493             :                          __func__);
     494           0 :                 exit(1);
     495             :         }
     496           2 :         if (have_netns()) {
     497           2 :                 fd = open(NS_DEFAULT_NAME, O_RDONLY);
     498           2 :                 default_ns->fd = fd;
     499             :         }
     500           2 :         default_ns->internal_ns_id = internal_ns;
     501             : 
     502             :         /* Set the default NS name. */
     503           2 :         default_ns->name = XSTRDUP(MTYPE_NS_NAME, NS_DEFAULT_NAME);
     504           2 :         if (ns_debug)
     505           0 :                 zlog_info("%s: default NSID is %u", __func__,
     506             :                           default_ns->ns_id);
     507             : 
     508             :         /* Enable the default NS. */
     509           2 :         if (!ns_enable(default_ns, NULL)) {
     510           0 :                 flog_err(EC_LIB_NS, "%s: failed to enable the default NS!",
     511             :                          __func__);
     512           0 :                 exit(1);
     513             :         }
     514           2 : }
     515             : 
     516             : /* Terminate NS module. */
     517           2 : void ns_terminate(void)
     518             : {
     519           2 :         struct ns *ns;
     520             : 
     521           4 :         while (!RB_EMPTY(ns_head, &ns_tree)) {
     522           2 :                 ns = RB_ROOT(ns_head, &ns_tree);
     523             : 
     524           2 :                 ns_delete(ns);
     525             :         }
     526           2 : }
     527             : 
     528           0 : int ns_switch_to_netns(const char *name)
     529             : {
     530           0 :         int ret;
     531           0 :         int fd;
     532             : 
     533           0 :         if (name == NULL)
     534             :                 return -1;
     535           0 :         if (ns_default_ns_fd == -1)
     536             :                 return -1;
     537           0 :         fd = open(name, O_RDONLY);
     538           0 :         if (fd == -1) {
     539           0 :                 errno = EINVAL;
     540           0 :                 return -1;
     541             :         }
     542           0 :         ret = setns(fd, CLONE_NEWNET);
     543           0 :         ns_current_ns_fd = fd;
     544           0 :         close(fd);
     545           0 :         return ret;
     546             : }
     547             : 
     548             : /* returns 1 if switch() was not called before
     549             :  * return status of setns() otherwise
     550             :  */
     551          15 : int ns_switchback_to_initial(void)
     552             : {
     553          15 :         if (ns_current_ns_fd != -1 && ns_default_ns_fd != -1) {
     554           0 :                 int ret;
     555             : 
     556           0 :                 ret = setns(ns_default_ns_fd, CLONE_NEWNET);
     557           0 :                 ns_current_ns_fd = -1;
     558           0 :                 return ret;
     559             :         }
     560             :         /* silently ignore if setns() is not called */
     561             :         return 1;
     562             : }
     563             : 
     564             : /* Create a socket for the NS. */
     565          10 : int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
     566             : {
     567          10 :         struct ns *ns = ns_lookup(ns_id);
     568          10 :         int ret;
     569             : 
     570          10 :         if (!ns || !ns_is_enabled(ns)) {
     571           0 :                 errno = EINVAL;
     572           0 :                 return -1;
     573             :         }
     574          10 :         if (have_netns()) {
     575          10 :                 ret = (ns_id != NS_DEFAULT) ? setns(ns->fd, CLONE_NEWNET) : 0;
     576           0 :                 if (ret >= 0) {
     577          10 :                         ret = socket(domain, type, protocol);
     578          10 :                         if (ns_id != NS_DEFAULT) {
     579           0 :                                 setns(ns_lookup(NS_DEFAULT)->fd, CLONE_NEWNET);
     580           0 :                                 ns_current_ns_fd = ns_id;
     581             :                         }
     582             :                 }
     583             :         } else
     584           0 :                 ret = socket(domain, type, protocol);
     585             : 
     586             :         return ret;
     587             : }
     588             : 
     589             : /* if relative link_nsid matches default netns,
     590             :  * then return default absolute netns value
     591             :  * otherwise, return NS_UNKNOWN
     592             :  */
     593          11 : ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid)
     594             : {
     595          11 :         struct ns *ns;
     596             : 
     597          11 :         ns = ns_lookup(ns_id_reference);
     598          11 :         if (!ns)
     599             :                 return NS_UNKNOWN;
     600             : 
     601          11 :         if (ns->relative_default_ns != link_nsid)
     602             :                 return NS_UNKNOWN;
     603             : 
     604          11 :         ns = ns_get_default();
     605          11 :         assert(ns);
     606          11 :         return ns->ns_id;
     607             : }
     608             : 
     609          13 : struct ns *ns_get_default(void)
     610             : {
     611          13 :         return default_ns;
     612             : }

Generated by: LCOV version v1.16-topotato