back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_netns_id.c (source / functions) Hit Total Coverage
Test: test_ospf_topo1.py::OSPFTopo1Test Lines: 8 163 4.9 %
Date: 2023-02-24 18:38:32 Functions: 1 5 20.0 %

          Line data    Source code
       1             : /* zebra NETNS ID handling routines
       2             :  * those routines are implemented locally to avoid having external dependencies.
       3             :  * Copyright (C) 2018 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             : #include "ns.h"
      23             : #include "vrf.h"
      24             : #include "log.h"
      25             : #include "lib_errors.h"
      26             : #include "network.h"
      27             : 
      28             : #include "zebra/rib.h"
      29             : #include "zebra/zebra_dplane.h"
      30             : #if defined(HAVE_NETLINK)
      31             : 
      32             : #include <linux/net_namespace.h>
      33             : #include <linux/netlink.h>
      34             : #include <linux/rtnetlink.h>
      35             : 
      36             : #include "zebra_ns.h"
      37             : #include "kernel_netlink.h"
      38             : #endif /* defined(HAVE_NETLINK) */
      39             : 
      40             : #include "zebra/zebra_netns_id.h"
      41             : #include "zebra/zebra_errors.h"
      42             : 
      43             : /* in case NEWNSID not available, the NSID will be locally obtained
      44             :  */
      45             : #define NS_BASE_NSID 0
      46             : 
      47             : #if defined(HAVE_NETLINK)
      48             : 
      49             : #define NETLINK_SOCKET_BUFFER_SIZE 512
      50             : #define NETLINK_ALIGNTO             4
      51             : #define NETLINK_ALIGN(len)                                                     \
      52             :         (((len) + NETLINK_ALIGNTO - 1) & ~(NETLINK_ALIGNTO - 1))
      53             : #define NETLINK_NLATTR_LEN(_a, _b)   (unsigned int)((char *)_a - (char *)_b)
      54             : 
      55             : #endif /* defined(HAVE_NETLINK) */
      56             : 
      57           0 : static ns_id_t zebra_ns_id_get_fallback(const char *netnspath)
      58             : {
      59           0 :         static int zebra_ns_id_local;
      60             : 
      61           0 :         return zebra_ns_id_local++;
      62             : }
      63             : 
      64             : #if defined(HAVE_NETLINK)
      65             : 
      66           0 : static struct nlmsghdr *initiate_nlh(char *buf, unsigned int *seq, int type)
      67             : {
      68           0 :         struct nlmsghdr *nlh;
      69             : 
      70           0 :         nlh = (struct nlmsghdr *)buf;
      71           0 :         nlh->nlmsg_len = NETLINK_ALIGN(sizeof(struct nlmsghdr));
      72             : 
      73           0 :         nlh->nlmsg_type = type;
      74           0 :         nlh->nlmsg_flags = NLM_F_REQUEST;
      75           0 :         if (type == RTM_NEWNSID)
      76           0 :                 nlh->nlmsg_flags |= NLM_F_ACK;
      77           0 :         nlh->nlmsg_seq = *seq = frr_sequence32_next();
      78           0 :         return nlh;
      79             : }
      80             : 
      81           0 : static int send_receive(int sock, struct nlmsghdr *nlh, unsigned int seq,
      82             :                         char *buf)
      83             : {
      84           0 :         int ret;
      85           0 :         static const struct sockaddr_nl snl = {.nl_family = AF_NETLINK};
      86             : 
      87           0 :         ret = sendto(sock, (const void *)nlh, (size_t)nlh->nlmsg_len, 0,
      88             :                      (struct sockaddr *)&snl, (socklen_t)sizeof(snl));
      89           0 :         if (ret < 0) {
      90           0 :                 flog_err_sys(EC_LIB_SOCKET, "netlink( %u) sendmsg() error: %s",
      91             :                              sock, safe_strerror(errno));
      92           0 :                 return -1;
      93             :         }
      94             : 
      95             :         /* reception */
      96           0 :         struct sockaddr_nl addr;
      97           0 :         struct iovec iov = {
      98             :                 .iov_base = buf, .iov_len = NETLINK_SOCKET_BUFFER_SIZE,
      99             :         };
     100           0 :         struct msghdr msg = {
     101             :                 .msg_name = &addr,
     102             :                 .msg_namelen = sizeof(struct sockaddr_nl),
     103             :                 .msg_iov = &iov,
     104             :                 .msg_iovlen = 1,
     105             :                 .msg_control = NULL,
     106             :                 .msg_controllen = 0,
     107             :                 .msg_flags = 0,
     108             :         };
     109           0 :         ret = recvmsg(sock, &msg, 0);
     110           0 :         if (ret < 0) {
     111           0 :                 flog_err_sys(EC_LIB_SOCKET,
     112             :                              "netlink recvmsg: error %d (errno %u)", ret,
     113             :                              errno);
     114           0 :                 return -1;
     115             :         }
     116           0 :         if (msg.msg_flags & MSG_TRUNC) {
     117           0 :                 flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR,
     118             :                          "netlink recvmsg : error message truncated");
     119           0 :                 return -1;
     120             :         }
     121             :         /* nlh already points to buf */
     122           0 :         if (nlh->nlmsg_seq != seq) {
     123           0 :                 flog_err(
     124             :                         EC_ZEBRA_NETLINK_BAD_SEQUENCE,
     125             :                         "netlink recvmsg: bad sequence number %x (expected %x)",
     126             :                         seq, nlh->nlmsg_seq);
     127           0 :                 return -1;
     128             :         }
     129             :         return ret;
     130             : }
     131             : 
     132             : /* extract on a valid nlmsg the nsid
     133             :  * valid nlmsghdr - not a nlmsgerr
     134             :  */
     135           0 : static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf)
     136             : {
     137           0 :         ns_id_t ns_id = NS_UNKNOWN;
     138           0 :         int offset = NETLINK_ALIGN(sizeof(struct nlmsghdr))
     139             :                      + NETLINK_ALIGN(sizeof(struct rtgenmsg));
     140           0 :         void *tail = (void *)((char *)nlh + NETLINK_ALIGN(nlh->nlmsg_len));
     141           0 :         struct nlattr *attr;
     142             : 
     143           0 :         for (attr = (struct nlattr *)(buf + offset);
     144           0 :              NETLINK_NLATTR_LEN(tail, attr) >= sizeof(struct nlattr)
     145           0 :              && attr->nla_len >= sizeof(struct nlattr)
     146           0 :              && attr->nla_len <= NETLINK_NLATTR_LEN(tail, attr);
     147           0 :              attr += NETLINK_ALIGN(attr->nla_len)) {
     148           0 :                 if ((attr->nla_type & NLA_TYPE_MASK) == NETNSA_NSID) {
     149           0 :                         uint32_t *ptr = (uint32_t *)(attr);
     150             : 
     151           0 :                         ns_id = ptr[1];
     152           0 :                         break;
     153             :                 }
     154             :         }
     155           0 :         return ns_id;
     156             : }
     157             : 
     158             : /* fd_param = -1 is ignored.
     159             :  * netnspath set to null is ignored.
     160             :  * one of the 2 params is mandatory. netnspath is looked in priority
     161             :  */
     162           0 : ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param)
     163             : {
     164           0 :         int ns_id = -1;
     165           0 :         struct sockaddr_nl snl;
     166           0 :         int fd = -1, sock, ret;
     167           0 :         unsigned int seq;
     168           0 :         ns_id_t return_nsid = NS_UNKNOWN;
     169             : 
     170             :         /* netns path check */
     171           0 :         if (!netnspath && fd_param == -1)
     172             :                 return NS_UNKNOWN;
     173           0 :         if (netnspath)  {
     174           0 :                 fd = open(netnspath, O_RDONLY);
     175           0 :                 if (fd == -1)
     176             :                         return NS_UNKNOWN;
     177           0 :         } else if (fd_param != -1)
     178           0 :                 fd = fd_param;
     179             :         /* netlink socket */
     180           0 :         sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     181           0 :         if (sock < 0) {
     182           0 :                 flog_err_sys(EC_LIB_SOCKET, "netlink( %u) socket() error: %s",
     183             :                              sock, safe_strerror(errno));
     184           0 :                 if (netnspath)
     185           0 :                         close(fd);
     186           0 :                 return NS_UNKNOWN;
     187             :         }
     188           0 :         memset(&snl, 0, sizeof(snl));
     189           0 :         snl.nl_family = AF_NETLINK;
     190           0 :         snl.nl_groups = RTNLGRP_NSID;
     191           0 :         snl.nl_pid = 0; /* AUTO PID */
     192           0 :         ret = bind(sock, (struct sockaddr *)&snl, sizeof(snl));
     193           0 :         if (ret < 0) {
     194           0 :                 flog_err_sys(EC_LIB_SOCKET,
     195             :                              "netlink( %u) socket() bind error: %s", sock,
     196             :                              safe_strerror(errno));
     197           0 :                 close(sock);
     198           0 :                 if (netnspath)
     199           0 :                         close(fd);
     200           0 :                 return NS_UNKNOWN;
     201             :         }
     202             : 
     203             :         /* message to send to netlink,and response : NEWNSID */
     204           0 :         char buf[NETLINK_SOCKET_BUFFER_SIZE];
     205           0 :         struct nlmsghdr *nlh;
     206           0 :         struct rtgenmsg *rt;
     207           0 :         int len;
     208             : 
     209           0 :         memset(buf, 0, NETLINK_SOCKET_BUFFER_SIZE);
     210           0 :         nlh = initiate_nlh(buf, &seq, RTM_NEWNSID);
     211           0 :         rt = (struct rtgenmsg *)(buf + nlh->nlmsg_len);
     212           0 :         nlh->nlmsg_len += NETLINK_ALIGN(sizeof(struct rtgenmsg));
     213           0 :         rt->rtgen_family = AF_UNSPEC;
     214             : 
     215           0 :         nl_attr_put32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_FD, fd);
     216           0 :         nl_attr_put32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_NSID, ns_id);
     217             : 
     218           0 :         ret = send_receive(sock, nlh, seq, buf);
     219           0 :         if (ret < 0) {
     220           0 :                 close(sock);
     221           0 :                 if (netnspath)
     222           0 :                         close(fd);
     223           0 :                 return NS_UNKNOWN;
     224             :         }
     225           0 :         nlh = (struct nlmsghdr *)buf;
     226             : 
     227             :         /* message to analyse : NEWNSID response */
     228           0 :         ret = 0;
     229           0 :         if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
     230           0 :                 return_nsid = extract_nsid(nlh, buf);
     231             :         } else {
     232           0 :                 if (nlh->nlmsg_type == NLMSG_ERROR) {
     233           0 :                         struct nlmsgerr *err =
     234             :                                 (struct nlmsgerr
     235             :                                          *)((char *)nlh
     236             :                                             + NETLINK_ALIGN(
     237             :                                                       sizeof(struct nlmsghdr)));
     238             : 
     239           0 :                         ret = -1;
     240           0 :                         if (err->error < 0)
     241           0 :                                 errno = -err->error;
     242             :                         else
     243           0 :                                 errno = err->error;
     244           0 :                         if (errno == 0) {
     245             :                                 /* request NEWNSID was successfull
     246             :                                  * return EEXIST error to get GETNSID
     247             :                                  */
     248           0 :                                 errno = EEXIST;
     249             :                         }
     250             :                 } else {
     251             :                         /* other errors ignored
     252             :                          * attempt to get nsid
     253             :                          */
     254           0 :                         ret = -1;
     255           0 :                         errno = EEXIST;
     256             :                 }
     257             :         }
     258             : 
     259           0 :         if (errno != EEXIST && ret != 0) {
     260           0 :                 flog_err(EC_LIB_SOCKET,
     261             :                          "netlink( %u) recvfrom() error 2 when reading: %s", fd,
     262             :                          safe_strerror(errno));
     263           0 :                 close(sock);
     264           0 :                 if (netnspath)
     265           0 :                         close(fd);
     266           0 :                 if (errno == ENOTSUP) {
     267           0 :                         zlog_debug("NEWNSID locally generated");
     268           0 :                         return zebra_ns_id_get_fallback(netnspath);
     269             :                 }
     270             :                 return NS_UNKNOWN;
     271             :         }
     272             :         /* message to send to netlink : GETNSID */
     273           0 :         memset(buf, 0, NETLINK_SOCKET_BUFFER_SIZE);
     274           0 :         nlh = initiate_nlh(buf, &seq, RTM_GETNSID);
     275           0 :         rt = (struct rtgenmsg *)(buf + nlh->nlmsg_len);
     276           0 :         nlh->nlmsg_len += NETLINK_ALIGN(sizeof(struct rtgenmsg));
     277           0 :         rt->rtgen_family = AF_UNSPEC;
     278             : 
     279           0 :         nl_attr_put32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_FD, fd);
     280           0 :         nl_attr_put32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_NSID, ns_id);
     281             : 
     282           0 :         ret = send_receive(sock, nlh, seq, buf);
     283           0 :         if (ret < 0) {
     284           0 :                 close(sock);
     285           0 :                 if (netnspath)
     286           0 :                         close(fd);
     287           0 :                 return NS_UNKNOWN;
     288             :         }
     289             :         nlh = (struct nlmsghdr *)buf;
     290             :         len = ret;
     291           0 :         ret = 0;
     292           0 :         do {
     293           0 :                 if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
     294           0 :                         return_nsid = extract_nsid(nlh, buf);
     295           0 :                         if (return_nsid != NS_UNKNOWN)
     296             :                                 break;
     297           0 :                 } else if (nlh->nlmsg_type == NLMSG_ERROR) {
     298           0 :                         struct nlmsgerr *err =
     299             :                                 (struct nlmsgerr *)((char *)nlh +
     300             :                                                     NETLINK_ALIGN(sizeof(
     301             :                                                             struct nlmsghdr)));
     302           0 :                         if (err->error < 0)
     303           0 :                                 errno = -err->error;
     304             :                         else
     305           0 :                                 errno = err->error;
     306             :                         break;
     307             :                 }
     308           0 :                 len = len - NETLINK_ALIGN(nlh->nlmsg_len);
     309           0 :                 nlh = (struct nlmsghdr *)((char *)nlh +
     310           0 :                                           NETLINK_ALIGN(nlh->nlmsg_len));
     311           0 :         } while (len != 0 && ret == 0);
     312             : 
     313           0 :         if (netnspath)
     314           0 :                 close(fd);
     315           0 :         close(sock);
     316           0 :         return return_nsid;
     317             : }
     318             : 
     319             : #else
     320             : ns_id_t zebra_ns_id_get(const char *netnspath, int fd __attribute__ ((unused)))
     321             : {
     322             :         return zebra_ns_id_get_fallback(netnspath);
     323             : }
     324             : 
     325             : #endif /* ! defined(HAVE_NETLINK) */
     326             : 
     327             : #ifdef HAVE_NETNS
     328           0 : static void zebra_ns_create_netns_directory(void)
     329             : {
     330             :         /* check that /var/run/netns is created */
     331             :         /* S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH */
     332           0 :         if (mkdir(NS_RUN_DIR, 0755)) {
     333           0 :                 if (errno != EEXIST) {
     334           0 :                         flog_warn(EC_ZEBRA_NAMESPACE_DIR_INACCESSIBLE,
     335             :                                   "NS check: failed to access %s", NS_RUN_DIR);
     336           0 :                         return;
     337             :                 }
     338             :         }
     339             : }
     340             : #endif
     341             : 
     342           4 : ns_id_t zebra_ns_id_get_default(void)
     343             : {
     344             : #ifdef HAVE_NETNS
     345           4 :         int fd;
     346             : #endif /* !HAVE_NETNS */
     347             : 
     348             : #ifdef HAVE_NETNS
     349           4 :         if (vrf_is_backend_netns())
     350           0 :                 zebra_ns_create_netns_directory();
     351           4 :         fd = open(NS_DEFAULT_NAME, O_RDONLY);
     352             : 
     353           4 :         if (fd == -1)
     354             :                 return NS_DEFAULT;
     355           4 :         if (!vrf_is_backend_netns()) {
     356           4 :                 close(fd);
     357           4 :                 return NS_DEFAULT;
     358             :         }
     359           0 :         close(fd);
     360           0 :         return zebra_ns_id_get((char *)NS_DEFAULT_NAME, -1);
     361             : #else  /* HAVE_NETNS */
     362             :         return NS_DEFAULT;
     363             : #endif /* !HAVE_NETNS */
     364             : }

Generated by: LCOV version v1.16-topotato