back to topotato report
topotato coverage report
Current view: top level - zebra - netconf_netlink.c (source / functions) Hit Total Coverage
Test: test_bgp_distance_change.py::BGPDistanceChange Lines: 57 88 64.8 %
Date: 2023-02-24 18:37:13 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /*
       2             :  * netconf_netlink.c - netconf interaction with the kernel using
       3             :  * netlink
       4             :  * Copyright (C) 2021  Nvidia, Inc.
       5             :  *                     Donald Sharp
       6             :  *
       7             :  * This file is part of FRR.
       8             :  *
       9             :  * FRR is free software; you can redistribute it and/or modify it
      10             :  * under the terms of the GNU General Public License as published by the
      11             :  * Free Software Foundation; either version 2, or (at your option) any
      12             :  * later version.
      13             :  *
      14             :  * FRR is distributed in the hope that it will be useful, but
      15             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU General Public License
      20             :  * along with FRR; see the file COPYING.  If not, write to the Free
      21             :  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      22             :  * 02111-1307, USA.
      23             :  */
      24             : #include <zebra.h>
      25             : 
      26             : #ifdef HAVE_NETLINK /* Netlink OSes only */
      27             : 
      28             : #include <ns.h>
      29             : 
      30             : #include "linux/netconf.h"
      31             : 
      32             : #include "lib/lib_errors.h"
      33             : #include "zebra/zebra_ns.h"
      34             : #include "zebra/zebra_dplane.h"
      35             : #include "zebra/kernel_netlink.h"
      36             : #include "zebra/netconf_netlink.h"
      37             : #include "zebra/debug.h"
      38             : 
      39          16 : static struct rtattr *netconf_rta(struct netconfmsg *ncm)
      40             : {
      41          16 :         return (struct rtattr *)((char *)ncm +
      42             :                                  NLMSG_ALIGN(sizeof(struct netconfmsg)));
      43             : }
      44             : 
      45             : /*
      46             :  * Handle netconf update about a single interface: create dplane
      47             :  * context, and enqueue for processing in the main zebra pthread.
      48             :  */
      49             : static int
      50          16 : netlink_netconf_dplane_update(ns_id_t ns_id, afi_t afi, ifindex_t ifindex,
      51             :                               enum dplane_netconf_status_e mpls_on,
      52             :                               enum dplane_netconf_status_e mcast_on,
      53             :                               enum dplane_netconf_status_e linkdown_on)
      54             : {
      55          16 :         struct zebra_dplane_ctx *ctx;
      56             : 
      57          16 :         ctx = dplane_ctx_alloc();
      58          16 :         dplane_ctx_set_op(ctx, DPLANE_OP_INTF_NETCONFIG);
      59          16 :         dplane_ctx_set_ns_id(ctx, ns_id);
      60          16 :         dplane_ctx_set_afi(ctx, afi);
      61          16 :         dplane_ctx_set_ifindex(ctx, ifindex);
      62             : 
      63          16 :         dplane_ctx_set_netconf_mpls(ctx, mpls_on);
      64          16 :         dplane_ctx_set_netconf_mcast(ctx, mcast_on);
      65          16 :         dplane_ctx_set_netconf_linkdown(ctx, linkdown_on);
      66             : 
      67             :         /* Enqueue ctx for main pthread to process */
      68          16 :         dplane_provider_enqueue_to_zebra(ctx);
      69             : 
      70          16 :         return 0;
      71             : }
      72             : 
      73             : /*
      74             :  * Parse and process an incoming netlink netconf update.
      75             :  */
      76          16 : int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
      77             : {
      78          16 :         struct netconfmsg *ncm;
      79          16 :         struct rtattr *tb[NETCONFA_MAX + 1] = {};
      80          16 :         int len;
      81          16 :         ifindex_t ifindex;
      82          16 :         uint32_t ival;
      83          16 :         afi_t afi;
      84          16 :         enum dplane_netconf_status_e mpls_on = DPLANE_NETCONF_STATUS_UNKNOWN;
      85          16 :         enum dplane_netconf_status_e mcast_on = DPLANE_NETCONF_STATUS_UNKNOWN;
      86          16 :         enum dplane_netconf_status_e linkdown_on =
      87             :                 DPLANE_NETCONF_STATUS_UNKNOWN;
      88             : 
      89          16 :         if (h->nlmsg_type != RTM_NEWNETCONF && h->nlmsg_type != RTM_DELNETCONF)
      90             :                 return 0;
      91             : 
      92          16 :         len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct netconfmsg));
      93          16 :         if (len < 0) {
      94           0 :                 zlog_err("%s: Message received from netlink is of a broken size: %d, min %zu",
      95             :                          __func__, h->nlmsg_len,
      96             :                          (size_t)NLMSG_LENGTH(sizeof(struct netconfmsg)));
      97           0 :                 return -1;
      98             :         }
      99             : 
     100          16 :         ncm = NLMSG_DATA(h);
     101             : 
     102             :         /*
     103             :          * FRR does not have an internal representation of afi_t for
     104             :          * the MPLS Address Family that the kernel has.  So let's
     105             :          * just call it v4.  This is ok because the kernel appears
     106             :          * to do a good job of not sending data that is mixed/matched
     107             :          * across families
     108             :          */
     109             : #ifdef AF_MPLS
     110          16 :         if (ncm->ncm_family == AF_MPLS)
     111             :                 afi = AFI_IP;
     112             :         else
     113             : #endif /* AF_MPLS */
     114          16 :                 afi = family2afi(ncm->ncm_family);
     115             : 
     116          16 :         netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len);
     117             : 
     118          16 :         if (!tb[NETCONFA_IFINDEX]) {
     119           0 :                 zlog_err("NETCONF message received from netlink without an ifindex");
     120           0 :                 return 0;
     121             :         }
     122             : 
     123          16 :         ifindex = *(ifindex_t *)RTA_DATA(tb[NETCONFA_IFINDEX]);
     124             : 
     125          16 :         if (tb[NETCONFA_INPUT]) {
     126           0 :                 ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_INPUT]);
     127           0 :                 if (ival != 0)
     128             :                         mpls_on = DPLANE_NETCONF_STATUS_ENABLED;
     129             :                 else
     130           0 :                         mpls_on = DPLANE_NETCONF_STATUS_DISABLED;
     131             :         }
     132             : 
     133          16 :         if (tb[NETCONFA_MC_FORWARDING]) {
     134          16 :                 ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]);
     135          16 :                 if (ival != 0)
     136             :                         mcast_on = DPLANE_NETCONF_STATUS_ENABLED;
     137             :                 else
     138          16 :                         mcast_on = DPLANE_NETCONF_STATUS_DISABLED;
     139             :         }
     140             : 
     141          16 :         if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) {
     142          16 :                 ival = *(uint32_t *)RTA_DATA(
     143             :                         tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]);
     144          16 :                 if (ival != 0)
     145             :                         linkdown_on = DPLANE_NETCONF_STATUS_ENABLED;
     146             :                 else
     147          16 :                         linkdown_on = DPLANE_NETCONF_STATUS_DISABLED;
     148             :         }
     149             : 
     150          16 :         if (IS_ZEBRA_DEBUG_KERNEL)
     151           0 :                 zlog_debug(
     152             :                         "%s: interface %u is mpls on: %d multicast on: %d linkdown: %d",
     153             :                         __func__, ifindex, mpls_on, mcast_on, linkdown_on);
     154             : 
     155             :         /* Create a dplane context and pass it along for processing */
     156          16 :         netlink_netconf_dplane_update(ns_id, afi, ifindex, mpls_on, mcast_on,
     157             :                                       linkdown_on);
     158             : 
     159          16 :         return 0;
     160             : }
     161             : 
     162             : /*
     163             :  * Request info from the host OS. This only sends the request; any replies
     164             :  * are processed asynchronously.
     165             :  */
     166           2 : int netlink_request_netconf(int sockfd)
     167             : {
     168           2 :         struct nlsock *nls;
     169           2 :         struct {
     170             :                 struct nlmsghdr n;
     171             :                 struct netconfmsg ncm;
     172             :                 char buf[1024];
     173           2 :         } req = {};
     174             : 
     175           2 :         nls = kernel_netlink_nlsock_lookup(sockfd);
     176             : 
     177           2 :         if (IS_ZEBRA_DEBUG_KERNEL)
     178           0 :                 zlog_debug("%s: nlsock %s", __func__, nls ? nls->name : "NULL");
     179             : 
     180           2 :         if (nls == NULL)
     181             :                 return -1;
     182             : 
     183           2 :         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg));
     184           2 :         req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
     185           2 :         req.n.nlmsg_type = RTM_GETNETCONF;
     186           2 :         req.ncm.ncm_family = AF_UNSPEC;
     187             : 
     188           2 :         return netlink_request(nls, &req);
     189             : }
     190             : 
     191             : extern struct zebra_privs_t zserv_privs;
     192             : /*
     193             :  * Currently netconf has no ability to set from netlink.
     194             :  * So we've received a request to do this work in the data plane.
     195             :  * as such we need to set the value via the /proc system
     196             :  */
     197           0 : enum netlink_msg_status netlink_put_intf_netconfig(struct nl_batch *bth,
     198             :                                                    struct zebra_dplane_ctx *ctx)
     199             : {
     200           0 :         const char *ifname = dplane_ctx_get_ifname(ctx);
     201           0 :         enum dplane_netconf_status_e mpls_on = dplane_ctx_get_netconf_mpls(ctx);
     202           0 :         char set[64];
     203           0 :         char mpls_proc[PATH_MAX];
     204           0 :         int fd, ret = FRR_NETLINK_ERROR;
     205             : 
     206           0 :         snprintf(mpls_proc, sizeof(mpls_proc),
     207             :                  "/proc/sys/net/mpls/conf/%s/input", ifname);
     208             : 
     209           0 :         if (mpls_on == DPLANE_NETCONF_STATUS_ENABLED)
     210           0 :                 snprintf(set, sizeof(set), "1\n");
     211           0 :         else if (mpls_on == DPLANE_NETCONF_STATUS_DISABLED)
     212           0 :                 snprintf(set, sizeof(set), "0\n");
     213             :         else {
     214           0 :                 flog_err_sys(
     215             :                         EC_LIB_DEVELOPMENT,
     216             :                         "%s: Expected interface %s to be set to ENABLED or DISABLED was %d",
     217             :                         __func__, ifname, mpls_on);
     218           0 :                 return ret;
     219             :         }
     220             : 
     221           0 :         frr_with_privs (&zserv_privs) {
     222           0 :                 fd = open(mpls_proc, O_WRONLY);
     223           0 :                 if (fd < 0) {
     224           0 :                         flog_err_sys(
     225             :                                 EC_LIB_SOCKET,
     226             :                                 "%s: Unable to open %s for writing: %s(%d)",
     227             :                                 __func__, mpls_proc, safe_strerror(errno),
     228             :                                 errno);
     229           0 :                         return ret;
     230             :                 }
     231           0 :                 if (write(fd, set, 2) == 2)
     232             :                         ret = FRR_NETLINK_SUCCESS;
     233             :                 else
     234           0 :                         flog_err_sys(EC_LIB_SOCKET,
     235             :                                      "%s: Unsuccessful write to %s: %s(%d)",
     236             :                                      __func__, mpls_proc, safe_strerror(errno),
     237             :                                      errno);
     238           0 :                 close(fd);
     239             :         }
     240           0 :         return ret;
     241             : }
     242             : 
     243             : #endif  /* HAVE_NETLINK */

Generated by: LCOV version v1.16-topotato