back to topotato report
topotato coverage report
Current view: top level - lib - nexthop.c (source / functions) Hit Total Coverage
Test: test_pim_basic2.py::PIMTopo2Test Lines: 136 488 27.9 %
Date: 2023-02-24 18:39:36 Functions: 27 45 60.0 %

          Line data    Source code
       1             : /* A generic nexthop structure
       2             :  * Copyright (C) 2013 Cumulus Networks, Inc.
       3             :  *
       4             :  * This file is part of Quagga.
       5             :  *
       6             :  * Quagga is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * Quagga is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : #include <zebra.h>
      21             : 
      22             : #include "prefix.h"
      23             : #include "table.h"
      24             : #include "memory.h"
      25             : #include "command.h"
      26             : #include "log.h"
      27             : #include "sockunion.h"
      28             : #include "linklist.h"
      29             : #include "prefix.h"
      30             : #include "nexthop.h"
      31             : #include "mpls.h"
      32             : #include "jhash.h"
      33             : #include "printfrr.h"
      34             : #include "vrf.h"
      35             : #include "nexthop_group.h"
      36             : 
      37          36 : DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop");
      38          36 : DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label");
      39          36 : DEFINE_MTYPE_STATIC(LIB, NH_SRV6, "Nexthop srv6");
      40             : 
      41         178 : static int _nexthop_labels_cmp(const struct nexthop *nh1,
      42             :                                const struct nexthop *nh2)
      43             : {
      44         178 :         const struct mpls_label_stack *nhl1 = NULL;
      45         178 :         const struct mpls_label_stack *nhl2 = NULL;
      46             : 
      47         178 :         nhl1 = nh1->nh_label;
      48         178 :         nhl2 = nh2->nh_label;
      49             : 
      50             :         /* No labels is a match */
      51         178 :         if (!nhl1 && !nhl2)
      52             :                 return 0;
      53             : 
      54           0 :         if (nhl1 && !nhl2)
      55             :                 return 1;
      56             : 
      57           0 :         if (nhl2 && !nhl1)
      58             :                 return -1;
      59             : 
      60           0 :         if (nhl1->num_labels > nhl2->num_labels)
      61             :                 return 1;
      62             : 
      63           0 :         if (nhl1->num_labels < nhl2->num_labels)
      64             :                 return -1;
      65             : 
      66           0 :         return memcmp(nhl1->label, nhl2->label,
      67           0 :                       (nhl1->num_labels * sizeof(mpls_label_t)));
      68             : }
      69             : 
      70         178 : static int _nexthop_srv6_cmp(const struct nexthop *nh1,
      71             :                              const struct nexthop *nh2)
      72             : {
      73         178 :         int ret = 0;
      74             : 
      75         178 :         if (!nh1->nh_srv6 && !nh2->nh_srv6)
      76             :                 return 0;
      77             : 
      78           0 :         if (nh1->nh_srv6 && !nh2->nh_srv6)
      79             :                 return 1;
      80             : 
      81           0 :         if (!nh1->nh_srv6 && nh2->nh_srv6)
      82             :                 return -1;
      83             : 
      84           0 :         if (nh1->nh_srv6->seg6local_action > nh2->nh_srv6->seg6local_action)
      85             :                 return 1;
      86             : 
      87           0 :         if (nh2->nh_srv6->seg6local_action < nh1->nh_srv6->seg6local_action)
      88             :                 return -1;
      89             : 
      90           0 :         ret = memcmp(&nh1->nh_srv6->seg6local_ctx,
      91           0 :                      &nh2->nh_srv6->seg6local_ctx,
      92             :                      sizeof(struct seg6local_context));
      93           0 :         if (ret != 0)
      94             :                 return ret;
      95             : 
      96           0 :         ret = memcmp(&nh1->nh_srv6->seg6_segs,
      97           0 :                      &nh2->nh_srv6->seg6_segs,
      98             :                      sizeof(struct in6_addr));
      99             : 
     100           0 :         return ret;
     101             : }
     102             : 
     103         178 : int nexthop_g_addr_cmp(enum nexthop_types_t type, const union g_addr *addr1,
     104             :                        const union g_addr *addr2)
     105             : {
     106         178 :         int ret = 0;
     107             : 
     108         178 :         switch (type) {
     109           0 :         case NEXTHOP_TYPE_IPV4:
     110             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
     111           0 :                 ret = IPV4_ADDR_CMP(&addr1->ipv4, &addr2->ipv4);
     112           0 :                 break;
     113           0 :         case NEXTHOP_TYPE_IPV6:
     114             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
     115           0 :                 ret = IPV6_ADDR_CMP(&addr1->ipv6, &addr2->ipv6);
     116           0 :                 break;
     117             :         case NEXTHOP_TYPE_IFINDEX:
     118             :         case NEXTHOP_TYPE_BLACKHOLE:
     119             :                 /* No addr here */
     120             :                 break;
     121             :         }
     122             : 
     123         178 :         return ret;
     124             : }
     125             : 
     126           0 : static int _nexthop_gateway_cmp(const struct nexthop *nh1,
     127             :                                 const struct nexthop *nh2)
     128             : {
     129           0 :         return nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate);
     130             : }
     131             : 
     132         178 : static int _nexthop_source_cmp(const struct nexthop *nh1,
     133             :                                const struct nexthop *nh2)
     134             : {
     135         178 :         return nexthop_g_addr_cmp(nh1->type, &nh1->src, &nh2->src);
     136             : }
     137             : 
     138         181 : static int _nexthop_cmp_no_labels(const struct nexthop *next1,
     139             :                                   const struct nexthop *next2)
     140             : {
     141         181 :         int ret = 0;
     142             : 
     143         181 :         if (next1->vrf_id < next2->vrf_id)
     144             :                 return -1;
     145             : 
     146         181 :         if (next1->vrf_id > next2->vrf_id)
     147             :                 return 1;
     148             : 
     149         181 :         if (next1->type < next2->type)
     150             :                 return -1;
     151             : 
     152         181 :         if (next1->type > next2->type)
     153             :                 return 1;
     154             : 
     155         181 :         if (next1->weight < next2->weight)
     156             :                 return -1;
     157             : 
     158         181 :         if (next1->weight > next2->weight)
     159             :                 return 1;
     160             : 
     161         181 :         switch (next1->type) {
     162             :         case NEXTHOP_TYPE_IPV4:
     163             :         case NEXTHOP_TYPE_IPV6:
     164           0 :                 ret = _nexthop_gateway_cmp(next1, next2);
     165           0 :                 if (ret != 0)
     166             :                         return ret;
     167             :                 break;
     168             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
     169             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
     170           0 :                 ret = _nexthop_gateway_cmp(next1, next2);
     171           0 :                 if (ret != 0)
     172             :                         return ret;
     173             :                 /* Intentional Fall-Through */
     174             :         case NEXTHOP_TYPE_IFINDEX:
     175         181 :                 if (next1->ifindex < next2->ifindex)
     176             :                         return -1;
     177             : 
     178         181 :                 if (next1->ifindex > next2->ifindex)
     179             :                         return 1;
     180             :                 break;
     181           0 :         case NEXTHOP_TYPE_BLACKHOLE:
     182           0 :                 if (next1->bh_type < next2->bh_type)
     183             :                         return -1;
     184             : 
     185           0 :                 if (next1->bh_type > next2->bh_type)
     186             :                         return 1;
     187             :                 break;
     188             :         }
     189             : 
     190         178 :         if (next1->srte_color < next2->srte_color)
     191             :                 return -1;
     192         178 :         if (next1->srte_color > next2->srte_color)
     193             :                 return 1;
     194             : 
     195         178 :         ret = _nexthop_source_cmp(next1, next2);
     196         178 :         if (ret != 0)
     197           0 :                 goto done;
     198             : 
     199         178 :         if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
     200         178 :             !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
     201             :                 return 0;
     202             : 
     203           0 :         if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
     204           0 :             CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
     205             :                 return -1;
     206             : 
     207           0 :         if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
     208           0 :             !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
     209             :                 return 1;
     210             : 
     211           0 :         if (next1->backup_num == 0 && next2->backup_num == 0)
     212           0 :                 goto done;
     213             : 
     214           0 :         if (next1->backup_num < next2->backup_num)
     215             :                 return -1;
     216             : 
     217           0 :         if (next1->backup_num > next2->backup_num)
     218             :                 return 1;
     219             : 
     220           0 :         ret = memcmp(next1->backup_idx,
     221           0 :                      next2->backup_idx, next1->backup_num);
     222             : 
     223             : done:
     224             :         return ret;
     225             : }
     226             : 
     227         181 : int nexthop_cmp(const struct nexthop *next1, const struct nexthop *next2)
     228             : {
     229         181 :         int ret = 0;
     230             : 
     231         181 :         ret = _nexthop_cmp_no_labels(next1, next2);
     232         181 :         if (ret != 0)
     233             :                 return ret;
     234             : 
     235         178 :         ret = _nexthop_labels_cmp(next1, next2);
     236         178 :         if (ret != 0)
     237             :                 return ret;
     238             : 
     239         178 :         ret = _nexthop_srv6_cmp(next1, next2);
     240             : 
     241         178 :         return ret;
     242             : }
     243             : 
     244             : /*
     245             :  * More-limited comparison function used to detect duplicate
     246             :  * nexthops. This is used in places where we don't need the full
     247             :  * comparison of 'nexthop_cmp()'.
     248             :  */
     249           0 : int nexthop_cmp_basic(const struct nexthop *nh1,
     250             :                       const struct nexthop *nh2)
     251             : {
     252           0 :         int ret = 0;
     253           0 :         const struct mpls_label_stack *nhl1 = NULL;
     254           0 :         const struct mpls_label_stack *nhl2 = NULL;
     255             : 
     256           0 :         if (nh1 == NULL && nh2 == NULL)
     257             :                 return 0;
     258             : 
     259           0 :         if (nh1 && !nh2)
     260             :                 return 1;
     261             : 
     262           0 :         if (!nh1 && nh2)
     263             :                 return -1;
     264             : 
     265           0 :         if (nh1->vrf_id < nh2->vrf_id)
     266             :                 return -1;
     267             : 
     268           0 :         if (nh1->vrf_id > nh2->vrf_id)
     269             :                 return 1;
     270             : 
     271           0 :         if (nh1->type < nh2->type)
     272             :                 return -1;
     273             : 
     274           0 :         if (nh1->type > nh2->type)
     275             :                 return 1;
     276             : 
     277           0 :         if (nh1->weight < nh2->weight)
     278             :                 return -1;
     279             : 
     280           0 :         if (nh1->weight > nh2->weight)
     281             :                 return 1;
     282             : 
     283           0 :         switch (nh1->type) {
     284           0 :         case NEXTHOP_TYPE_IPV4:
     285             :         case NEXTHOP_TYPE_IPV6:
     286           0 :                 ret = nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate);
     287           0 :                 if (ret != 0)
     288             :                         return ret;
     289             :                 break;
     290           0 :         case NEXTHOP_TYPE_IPV4_IFINDEX:
     291             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
     292           0 :                 ret = nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate);
     293           0 :                 if (ret != 0)
     294             :                         return ret;
     295             :                 /* Intentional Fall-Through */
     296             :         case NEXTHOP_TYPE_IFINDEX:
     297           0 :                 if (nh1->ifindex < nh2->ifindex)
     298             :                         return -1;
     299             : 
     300           0 :                 if (nh1->ifindex > nh2->ifindex)
     301             :                         return 1;
     302             :                 break;
     303           0 :         case NEXTHOP_TYPE_BLACKHOLE:
     304           0 :                 if (nh1->bh_type < nh2->bh_type)
     305             :                         return -1;
     306             : 
     307           0 :                 if (nh1->bh_type > nh2->bh_type)
     308             :                         return 1;
     309             :                 break;
     310             :         }
     311             : 
     312             :         /* Compare source addr */
     313           0 :         ret = nexthop_g_addr_cmp(nh1->type, &nh1->src, &nh2->src);
     314           0 :         if (ret != 0)
     315           0 :                 goto done;
     316             : 
     317           0 :         nhl1 = nh1->nh_label;
     318           0 :         nhl2 = nh2->nh_label;
     319             : 
     320             :         /* No labels is a match */
     321           0 :         if (!nhl1 && !nhl2)
     322             :                 return 0;
     323             : 
     324           0 :         if (nhl1 && !nhl2)
     325             :                 return 1;
     326             : 
     327           0 :         if (nhl2 && !nhl1)
     328             :                 return -1;
     329             : 
     330           0 :         if (nhl1->num_labels > nhl2->num_labels)
     331             :                 return 1;
     332             : 
     333           0 :         if (nhl1->num_labels < nhl2->num_labels)
     334             :                 return -1;
     335             : 
     336           0 :         ret = memcmp(nhl1->label, nhl2->label,
     337           0 :                      (nhl1->num_labels * sizeof(mpls_label_t)));
     338             : 
     339             : done:
     340             :         return ret;
     341             : }
     342             : 
     343             : /*
     344             :  * nexthop_type_to_str
     345             :  */
     346           0 : const char *nexthop_type_to_str(enum nexthop_types_t nh_type)
     347             : {
     348           0 :         static const char *const desc[] = {
     349             :                 "none",                "Directly connected",
     350             :                 "IPv4 nexthop",  "IPv4 nexthop with ifindex",
     351             :                 "IPv6 nexthop",  "IPv6 nexthop with ifindex",
     352             :                 "Null0 nexthop",
     353             :         };
     354             : 
     355           0 :         return desc[nh_type];
     356             : }
     357             : 
     358             : /*
     359             :  * Check if the labels match for the 2 nexthops specified.
     360             :  */
     361           0 : bool nexthop_labels_match(const struct nexthop *nh1, const struct nexthop *nh2)
     362             : {
     363           0 :         if (_nexthop_labels_cmp(nh1, nh2) != 0)
     364           0 :                 return false;
     365             : 
     366             :         return true;
     367             : }
     368             : 
     369         396 : struct nexthop *nexthop_new(void)
     370             : {
     371         396 :         struct nexthop *nh;
     372             : 
     373         396 :         nh = XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
     374             : 
     375             :         /*
     376             :          * Default the weight to 1 here for all nexthops.
     377             :          * The linux kernel does some weird stuff with adding +1 to
     378             :          * all nexthop weights it gets over netlink.
     379             :          * To handle this, just default everything to 1 right from
     380             :          * from the beginning so we don't have to special case
     381             :          * default weights in the linux netlink code.
     382             :          *
     383             :          * 1 should be a valid on all platforms anyway.
     384             :          */
     385         396 :         nh->weight = 1;
     386             : 
     387         396 :         return nh;
     388             : }
     389             : 
     390             : /* Free nexthop. */
     391         396 : void nexthop_free(struct nexthop *nexthop)
     392             : {
     393         396 :         nexthop_del_labels(nexthop);
     394         396 :         nexthop_del_srv6_seg6local(nexthop);
     395         396 :         nexthop_del_srv6_seg6(nexthop);
     396         396 :         if (nexthop->resolved)
     397           0 :                 nexthops_free(nexthop->resolved);
     398         396 :         XFREE(MTYPE_NEXTHOP, nexthop);
     399         396 : }
     400             : 
     401             : /* Frees a list of nexthops */
     402         560 : void nexthops_free(struct nexthop *nexthop)
     403             : {
     404         560 :         struct nexthop *nh, *next;
     405             : 
     406         956 :         for (nh = nexthop; nh; nh = next) {
     407         396 :                 next = nh->next;
     408         396 :                 nexthop_free(nh);
     409             :         }
     410         560 : }
     411             : 
     412         181 : bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2)
     413             : {
     414         181 :         if (nh1 && !nh2)
     415             :                 return false;
     416             : 
     417         181 :         if (!nh1 && nh2)
     418             :                 return false;
     419             : 
     420         181 :         if (nh1 == nh2)
     421             :                 return true;
     422             : 
     423         181 :         if (nexthop_cmp(nh1, nh2) != 0)
     424             :                 return false;
     425             : 
     426             :         return true;
     427             : }
     428             : 
     429           0 : bool nexthop_same_no_labels(const struct nexthop *nh1,
     430             :                             const struct nexthop *nh2)
     431             : {
     432           0 :         if (nh1 && !nh2)
     433             :                 return false;
     434             : 
     435           0 :         if (!nh1 && nh2)
     436             :                 return false;
     437             : 
     438           0 :         if (nh1 == nh2)
     439             :                 return true;
     440             : 
     441           0 :         if (_nexthop_cmp_no_labels(nh1, nh2) != 0)
     442             :                 return false;
     443             : 
     444             :         return true;
     445             : }
     446             : 
     447             : /*
     448             :  * Allocate a new nexthop object and initialize it from various args.
     449             :  */
     450           0 : struct nexthop *nexthop_from_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
     451             : {
     452           0 :         struct nexthop *nexthop;
     453             : 
     454           0 :         nexthop = nexthop_new();
     455           0 :         nexthop->type = NEXTHOP_TYPE_IFINDEX;
     456           0 :         nexthop->ifindex = ifindex;
     457           0 :         nexthop->vrf_id = vrf_id;
     458             : 
     459           0 :         return nexthop;
     460             : }
     461             : 
     462           0 : struct nexthop *nexthop_from_ipv4(const struct in_addr *ipv4,
     463             :                                   const struct in_addr *src,
     464             :                                   vrf_id_t vrf_id)
     465             : {
     466           0 :         struct nexthop *nexthop;
     467             : 
     468           0 :         nexthop = nexthop_new();
     469           0 :         nexthop->type = NEXTHOP_TYPE_IPV4;
     470           0 :         nexthop->vrf_id = vrf_id;
     471           0 :         nexthop->gate.ipv4 = *ipv4;
     472           0 :         if (src)
     473           0 :                 nexthop->src.ipv4 = *src;
     474             : 
     475           0 :         return nexthop;
     476             : }
     477             : 
     478           0 : struct nexthop *nexthop_from_ipv4_ifindex(const struct in_addr *ipv4,
     479             :                                           const struct in_addr *src,
     480             :                                           ifindex_t ifindex, vrf_id_t vrf_id)
     481             : {
     482           0 :         struct nexthop *nexthop;
     483             : 
     484           0 :         nexthop = nexthop_new();
     485           0 :         nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
     486           0 :         nexthop->vrf_id = vrf_id;
     487           0 :         nexthop->gate.ipv4 = *ipv4;
     488           0 :         if (src)
     489           0 :                 nexthop->src.ipv4 = *src;
     490           0 :         nexthop->ifindex = ifindex;
     491             : 
     492           0 :         return nexthop;
     493             : }
     494             : 
     495           0 : struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6,
     496             :                                   vrf_id_t vrf_id)
     497             : {
     498           0 :         struct nexthop *nexthop;
     499             : 
     500           0 :         nexthop = nexthop_new();
     501           0 :         nexthop->vrf_id = vrf_id;
     502           0 :         nexthop->type = NEXTHOP_TYPE_IPV6;
     503           0 :         nexthop->gate.ipv6 = *ipv6;
     504             : 
     505           0 :         return nexthop;
     506             : }
     507             : 
     508           0 : struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6,
     509             :                                           ifindex_t ifindex, vrf_id_t vrf_id)
     510             : {
     511           0 :         struct nexthop *nexthop;
     512             : 
     513           0 :         nexthop = nexthop_new();
     514           0 :         nexthop->vrf_id = vrf_id;
     515           0 :         nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
     516           0 :         nexthop->gate.ipv6 = *ipv6;
     517           0 :         nexthop->ifindex = ifindex;
     518             : 
     519           0 :         return nexthop;
     520             : }
     521             : 
     522           0 : struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type,
     523             :                                        vrf_id_t nh_vrf_id)
     524             : {
     525           0 :         struct nexthop *nexthop;
     526             : 
     527           0 :         nexthop = nexthop_new();
     528           0 :         nexthop->vrf_id = nh_vrf_id;
     529           0 :         nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
     530           0 :         nexthop->bh_type = bh_type;
     531             : 
     532           0 :         return nexthop;
     533             : }
     534             : 
     535             : /* Update nexthop with label information. */
     536           0 : void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype,
     537             :                         uint8_t num_labels, const mpls_label_t *labels)
     538             : {
     539           0 :         struct mpls_label_stack *nh_label;
     540           0 :         int i;
     541             : 
     542           0 :         if (num_labels == 0)
     543             :                 return;
     544             : 
     545             :         /* Enforce limit on label stack size */
     546           0 :         if (num_labels > MPLS_MAX_LABELS)
     547             :                 num_labels = MPLS_MAX_LABELS;
     548             : 
     549           0 :         nexthop->nh_label_type = ltype;
     550             : 
     551           0 :         nh_label = XCALLOC(MTYPE_NH_LABEL,
     552             :                            sizeof(struct mpls_label_stack)
     553             :                                    + num_labels * sizeof(mpls_label_t));
     554           0 :         nh_label->num_labels = num_labels;
     555           0 :         for (i = 0; i < num_labels; i++)
     556           0 :                 nh_label->label[i] = *(labels + i);
     557           0 :         nexthop->nh_label = nh_label;
     558             : }
     559             : 
     560             : /* Free label information of nexthop, if present. */
     561         396 : void nexthop_del_labels(struct nexthop *nexthop)
     562             : {
     563         396 :         XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
     564         396 :         nexthop->nh_label_type = ZEBRA_LSP_NONE;
     565         396 : }
     566             : 
     567           0 : void nexthop_add_srv6_seg6local(struct nexthop *nexthop, uint32_t action,
     568             :                                 const struct seg6local_context *ctx)
     569             : {
     570           0 :         if (action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
     571             :                 return;
     572             : 
     573           0 :         if (!nexthop->nh_srv6)
     574           0 :                 nexthop->nh_srv6 = XCALLOC(MTYPE_NH_SRV6,
     575             :                                            sizeof(struct nexthop_srv6));
     576             : 
     577           0 :         nexthop->nh_srv6->seg6local_action = action;
     578           0 :         nexthop->nh_srv6->seg6local_ctx = *ctx;
     579             : }
     580             : 
     581         396 : void nexthop_del_srv6_seg6local(struct nexthop *nexthop)
     582             : {
     583         396 :         if (!nexthop->nh_srv6)
     584             :                 return;
     585             : 
     586           0 :         nexthop->nh_srv6->seg6local_action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
     587             : 
     588           0 :         if (sid_zero(&nexthop->nh_srv6->seg6_segs))
     589           0 :                 XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6);
     590             : }
     591             : 
     592           0 : void nexthop_add_srv6_seg6(struct nexthop *nexthop,
     593             :                            const struct in6_addr *segs)
     594             : {
     595           0 :         if (!segs)
     596             :                 return;
     597             : 
     598           0 :         if (!nexthop->nh_srv6)
     599           0 :                 nexthop->nh_srv6 = XCALLOC(MTYPE_NH_SRV6,
     600             :                                            sizeof(struct nexthop_srv6));
     601             : 
     602           0 :         nexthop->nh_srv6->seg6_segs = *segs;
     603             : }
     604             : 
     605         396 : void nexthop_del_srv6_seg6(struct nexthop *nexthop)
     606             : {
     607         396 :         if (!nexthop->nh_srv6)
     608             :                 return;
     609             : 
     610           0 :         memset(&nexthop->nh_srv6->seg6_segs, 0,
     611             :                sizeof(nexthop->nh_srv6->seg6_segs));
     612             : 
     613           0 :         if (nexthop->nh_srv6->seg6local_action ==
     614             :             ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
     615           0 :                 XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6);
     616             : }
     617             : 
     618           0 : const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
     619             : {
     620           0 :         switch (nexthop->type) {
     621           0 :         case NEXTHOP_TYPE_IFINDEX:
     622           0 :                 snprintf(str, size, "if %u", nexthop->ifindex);
     623           0 :                 break;
     624           0 :         case NEXTHOP_TYPE_IPV4:
     625             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
     626           0 :                 snprintfrr(str, size, "%pI4 if %u", &nexthop->gate.ipv4,
     627           0 :                            nexthop->ifindex);
     628           0 :                 break;
     629           0 :         case NEXTHOP_TYPE_IPV6:
     630             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
     631           0 :                 snprintfrr(str, size, "%pI6 if %u", &nexthop->gate.ipv6,
     632           0 :                            nexthop->ifindex);
     633           0 :                 break;
     634           0 :         case NEXTHOP_TYPE_BLACKHOLE:
     635           0 :                 snprintf(str, size, "blackhole");
     636           0 :                 break;
     637             :         }
     638             : 
     639           0 :         return str;
     640             : }
     641             : 
     642             : /*
     643             :  * Iteration step for ALL_NEXTHOPS macro:
     644             :  * This is the tricky part. Check if `nexthop' has
     645             :  * NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' has
     646             :  * at least one nexthop attached to `nexthop->resolved', which will be
     647             :  * the next one.
     648             :  *
     649             :  * If NEXTHOP_FLAG_RECURSIVE is not set, `nexthop' will progress in its
     650             :  * current chain. In case its current chain end is reached, it will move
     651             :  * upwards in the recursion levels and progress there. Whenever a step
     652             :  * forward in a chain is done, recursion will be checked again.
     653             :  * In a nustshell, it's equivalent to a pre-traversal order assuming that
     654             :  * left branch is 'resolved' and right branch is 'next':
     655             :  * https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg
     656             :  */
     657         780 : struct nexthop *nexthop_next(const struct nexthop *nexthop)
     658             : {
     659         780 :         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
     660           0 :                 return nexthop->resolved;
     661             : 
     662         780 :         if (nexthop->next)
     663             :                 return nexthop->next;
     664             : 
     665         780 :         for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
     666           0 :                 if (par->next)
     667           0 :                         return par->next;
     668             : 
     669             :         return NULL;
     670             : }
     671             : 
     672             : /* Return the next nexthop in the tree that is resolved and active */
     673          41 : struct nexthop *nexthop_next_active_resolved(const struct nexthop *nexthop)
     674             : {
     675          41 :         struct nexthop *next = nexthop_next(nexthop);
     676             : 
     677          41 :         while (next
     678          41 :                && (CHECK_FLAG(next->flags, NEXTHOP_FLAG_RECURSIVE)
     679             :                    || !CHECK_FLAG(next->flags, NEXTHOP_FLAG_ACTIVE)))
     680           0 :                 next = nexthop_next(next);
     681             : 
     682          41 :         return next;
     683             : }
     684             : 
     685           0 : unsigned int nexthop_level(const struct nexthop *nexthop)
     686             : {
     687           0 :         unsigned int rv = 0;
     688             : 
     689           0 :         for (const struct nexthop *par = nexthop->rparent;
     690           0 :              par; par = par->rparent)
     691           0 :                 rv++;
     692             : 
     693           0 :         return rv;
     694             : }
     695             : 
     696             : /* Only hash word-sized things, let cmp do the rest. */
     697         296 : uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
     698             : {
     699         296 :         uint32_t key = 0x45afe398;
     700         296 :         int i;
     701             : 
     702         592 :         key = jhash_3words(nexthop->type, nexthop->vrf_id,
     703         296 :                            nexthop->nh_label_type, key);
     704             : 
     705         296 :         if (nexthop->nh_label) {
     706           0 :                 int labels = nexthop->nh_label->num_labels;
     707             : 
     708           0 :                 i = 0;
     709             : 
     710           0 :                 while (labels >= 3) {
     711           0 :                         key = jhash_3words(nexthop->nh_label->label[i],
     712           0 :                                            nexthop->nh_label->label[i + 1],
     713           0 :                                            nexthop->nh_label->label[i + 2],
     714             :                                            key);
     715           0 :                         labels -= 3;
     716           0 :                         i += 3;
     717             :                 }
     718             : 
     719           0 :                 if (labels >= 2) {
     720           0 :                         key = jhash_2words(nexthop->nh_label->label[i],
     721           0 :                                            nexthop->nh_label->label[i + 1],
     722             :                                            key);
     723           0 :                         labels -= 2;
     724           0 :                         i += 2;
     725             :                 }
     726             : 
     727           0 :                 if (labels >= 1)
     728           0 :                         key = jhash_1word(nexthop->nh_label->label[i], key);
     729             :         }
     730             : 
     731         592 :         key = jhash_2words(nexthop->ifindex,
     732         296 :                            CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
     733             :                            key);
     734             : 
     735             :         /* Include backup nexthops, if present */
     736         296 :         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
     737           0 :                 int backups = nexthop->backup_num;
     738             : 
     739           0 :                 i = 0;
     740             : 
     741           0 :                 while (backups >= 3) {
     742           0 :                         key = jhash_3words(nexthop->backup_idx[i],
     743           0 :                                            nexthop->backup_idx[i + 1],
     744           0 :                                            nexthop->backup_idx[i + 2], key);
     745           0 :                         backups -= 3;
     746           0 :                         i += 3;
     747             :                 }
     748             : 
     749           0 :                 while (backups >= 2) {
     750           0 :                         key = jhash_2words(nexthop->backup_idx[i],
     751           0 :                                            nexthop->backup_idx[i + 1], key);
     752           0 :                         backups -= 2;
     753           0 :                         i += 2;
     754             :                 }
     755             : 
     756           0 :                 if (backups >= 1)
     757           0 :                         key = jhash_1word(nexthop->backup_idx[i], key);
     758             :         }
     759             : 
     760         296 :         if (nexthop->nh_srv6) {
     761           0 :                 key = jhash_1word(nexthop->nh_srv6->seg6local_action, key);
     762           0 :                 key = jhash(&nexthop->nh_srv6->seg6local_ctx,
     763             :                             sizeof(nexthop->nh_srv6->seg6local_ctx), key);
     764           0 :                 key = jhash(&nexthop->nh_srv6->seg6_segs,
     765             :                             sizeof(nexthop->nh_srv6->seg6_segs), key);
     766             :         }
     767             : 
     768         296 :         return key;
     769             : }
     770             : 
     771             : 
     772             : #define GATE_SIZE 4 /* Number of uint32_t words in struct g_addr */
     773             : 
     774             : /* For a more granular hash */
     775         296 : uint32_t nexthop_hash(const struct nexthop *nexthop)
     776             : {
     777         296 :         uint32_t gate_src_rmap_raw[GATE_SIZE * 3] = {};
     778             :         /* Get all the quick stuff */
     779         296 :         uint32_t key = nexthop_hash_quick(nexthop);
     780             : 
     781         296 :         assert(((sizeof(nexthop->gate) + sizeof(nexthop->src)
     782             :                  + sizeof(nexthop->rmap_src))
     783             :                 / 3)
     784             :                == (GATE_SIZE * sizeof(uint32_t)));
     785             : 
     786         296 :         memcpy(gate_src_rmap_raw, &nexthop->gate, GATE_SIZE);
     787         296 :         memcpy(gate_src_rmap_raw + GATE_SIZE, &nexthop->src, GATE_SIZE);
     788         296 :         memcpy(gate_src_rmap_raw + (2 * GATE_SIZE), &nexthop->rmap_src,
     789             :                GATE_SIZE);
     790             : 
     791         296 :         key = jhash2(gate_src_rmap_raw, (GATE_SIZE * 3), key);
     792             : 
     793         296 :         return key;
     794             : }
     795             : 
     796         396 : void nexthop_copy_no_recurse(struct nexthop *copy,
     797             :                              const struct nexthop *nexthop,
     798             :                              struct nexthop *rparent)
     799             : {
     800         396 :         copy->vrf_id = nexthop->vrf_id;
     801         396 :         copy->ifindex = nexthop->ifindex;
     802         396 :         copy->type = nexthop->type;
     803         396 :         copy->flags = nexthop->flags;
     804         396 :         copy->weight = nexthop->weight;
     805             : 
     806         396 :         assert(nexthop->backup_num < NEXTHOP_MAX_BACKUPS);
     807         396 :         copy->backup_num = nexthop->backup_num;
     808         396 :         if (copy->backup_num > 0)
     809           0 :                 memcpy(copy->backup_idx, nexthop->backup_idx, copy->backup_num);
     810             : 
     811         396 :         copy->srte_color = nexthop->srte_color;
     812         396 :         memcpy(&copy->gate, &nexthop->gate, sizeof(nexthop->gate));
     813         396 :         memcpy(&copy->src, &nexthop->src, sizeof(nexthop->src));
     814         396 :         memcpy(&copy->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
     815         396 :         copy->rparent = rparent;
     816         396 :         if (nexthop->nh_label)
     817           0 :                 nexthop_add_labels(copy, nexthop->nh_label_type,
     818           0 :                                    nexthop->nh_label->num_labels,
     819           0 :                                    &nexthop->nh_label->label[0]);
     820             : 
     821         396 :         if (nexthop->nh_srv6) {
     822           0 :                 if (nexthop->nh_srv6->seg6local_action !=
     823             :                     ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
     824           0 :                         nexthop_add_srv6_seg6local(copy,
     825             :                                 nexthop->nh_srv6->seg6local_action,
     826           0 :                                 &nexthop->nh_srv6->seg6local_ctx);
     827           0 :                 if (!sid_zero(&nexthop->nh_srv6->seg6_segs))
     828           0 :                         nexthop_add_srv6_seg6(copy,
     829             :                                 &nexthop->nh_srv6->seg6_segs);
     830             :         }
     831         396 : }
     832             : 
     833         396 : void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
     834             :                   struct nexthop *rparent)
     835             : {
     836         396 :         nexthop_copy_no_recurse(copy, nexthop, rparent);
     837             : 
     838             :         /* Bit of a special case here, we need to handle the case
     839             :          * of a nexthop resolving to a group. Hence, we need to
     840             :          * use a nexthop_group API.
     841             :          */
     842         396 :         if (CHECK_FLAG(copy->flags, NEXTHOP_FLAG_RECURSIVE))
     843           0 :                 copy_nexthops(&copy->resolved, nexthop->resolved, copy);
     844         396 : }
     845             : 
     846           0 : struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop,
     847             :                                        struct nexthop *rparent)
     848             : {
     849           0 :         struct nexthop *new = nexthop_new();
     850             : 
     851           0 :         nexthop_copy_no_recurse(new, nexthop, rparent);
     852           0 :         return new;
     853             : }
     854             : 
     855         396 : struct nexthop *nexthop_dup(const struct nexthop *nexthop,
     856             :                             struct nexthop *rparent)
     857             : {
     858         396 :         struct nexthop *new = nexthop_new();
     859             : 
     860         396 :         nexthop_copy(new, nexthop, rparent);
     861         396 :         return new;
     862             : }
     863             : 
     864             : /*
     865             :  * Parse one or more backup index values, as comma-separated numbers,
     866             :  * into caller's array of uint8_ts. The array must be NEXTHOP_MAX_BACKUPS
     867             :  * in size. Mails back the number of values converted, and returns 0 on
     868             :  * success, <0 if an error in parsing.
     869             :  */
     870           0 : int nexthop_str2backups(const char *str, int *num_backups,
     871             :                         uint8_t *backups)
     872             : {
     873           0 :         char *ostr;                       /* copy of string (start) */
     874           0 :         char *lstr;                       /* working copy of string */
     875           0 :         char *nump;                       /* pointer to next segment */
     876           0 :         char *endp;                       /* end pointer */
     877           0 :         int i, ret;
     878           0 :         uint8_t tmp[NEXTHOP_MAX_BACKUPS];
     879           0 :         uint32_t lval;
     880             : 
     881             :         /* Copy incoming string; the parse is destructive */
     882           0 :         lstr = ostr = XSTRDUP(MTYPE_TMP, str);
     883           0 :         *num_backups = 0;
     884           0 :         ret = 0;
     885             : 
     886           0 :         for (i = 0; i < NEXTHOP_MAX_BACKUPS && lstr; i++) {
     887           0 :                 nump = strsep(&lstr, ",");
     888           0 :                 lval = strtoul(nump, &endp, 10);
     889             : 
     890             :                 /* Format check */
     891           0 :                 if (*endp != '\0') {
     892             :                         ret = -1;
     893             :                         break;
     894             :                 }
     895             : 
     896             :                 /* Empty value */
     897           0 :                 if (endp == nump) {
     898             :                         ret = -1;
     899             :                         break;
     900             :                 }
     901             : 
     902             :                 /* Limit to one octet */
     903           0 :                 if (lval > 255) {
     904             :                         ret = -1;
     905             :                         break;
     906             :                 }
     907             : 
     908           0 :                 tmp[i] = lval;
     909             :         }
     910             : 
     911             :         /* Excess values */
     912           0 :         if (ret == 0 && i == NEXTHOP_MAX_BACKUPS && lstr)
     913             :                 ret = -1;
     914             : 
     915           0 :         if (ret == 0) {
     916           0 :                 *num_backups = i;
     917           0 :                 memcpy(backups, tmp, i);
     918             :         }
     919             : 
     920           0 :         XFREE(MTYPE_TMP, ostr);
     921             : 
     922           0 :         return ret;
     923             : }
     924             : 
     925          12 : ssize_t printfrr_nhs(struct fbuf *buf, const struct nexthop *nexthop)
     926             : {
     927          12 :         ssize_t ret = 0;
     928             : 
     929          12 :         if (!nexthop)
     930           0 :                 return bputs(buf, "(null)");
     931             : 
     932          12 :         switch (nexthop->type) {
     933          12 :         case NEXTHOP_TYPE_IFINDEX:
     934          12 :                 ret += bprintfrr(buf, "if %u", nexthop->ifindex);
     935          12 :                 break;
     936           0 :         case NEXTHOP_TYPE_IPV4:
     937             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
     938           0 :                 ret += bprintfrr(buf, "%pI4 if %u", &nexthop->gate.ipv4,
     939           0 :                                  nexthop->ifindex);
     940           0 :                 break;
     941           0 :         case NEXTHOP_TYPE_IPV6:
     942             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
     943           0 :                 ret += bprintfrr(buf, "%pI6 if %u", &nexthop->gate.ipv6,
     944           0 :                                  nexthop->ifindex);
     945           0 :                 break;
     946           0 :         case NEXTHOP_TYPE_BLACKHOLE:
     947           0 :                 ret += bputs(buf, "blackhole");
     948           0 :                 break;
     949             :         }
     950             :         return ret;
     951             : }
     952             : 
     953             : /*
     954             :  * nexthop printing variants:
     955             :  *      %pNHvv
     956             :  *              via 1.2.3.4
     957             :  *              via 1.2.3.4, eth0
     958             :  *              is directly connected, eth0
     959             :  *              unreachable (blackhole)
     960             :  *      %pNHv
     961             :  *              1.2.3.4
     962             :  *              1.2.3.4, via eth0
     963             :  *              directly connected, eth0
     964             :  *              unreachable (blackhole)
     965             :  *      %pNHs
     966             :  *              nexthop2str()
     967             :  *      %pNHcg
     968             :  *              1.2.3.4
     969             :  *              (0-length if no IP address present)
     970             :  *      %pNHci
     971             :  *              eth0
     972             :  *              (0-length if no interface present)
     973             :  */
     974          12 : printfrr_ext_autoreg_p("NH", printfrr_nh);
     975           0 : static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea,
     976             :                            const void *ptr)
     977             : {
     978           0 :         const struct nexthop *nexthop = ptr;
     979           0 :         bool do_ifi = false;
     980           0 :         const char *v_is = "", *v_via = "", *v_viaif = "via ";
     981           0 :         ssize_t ret = 0;
     982             : 
     983           0 :         switch (*ea->fmt) {
     984           0 :         case 'v':
     985           0 :                 ea->fmt++;
     986           0 :                 if (*ea->fmt == 'v') {
     987           0 :                         v_is = "is ";
     988           0 :                         v_via = "via ";
     989           0 :                         v_viaif = "";
     990           0 :                         ea->fmt++;
     991             :                 }
     992             : 
     993           0 :                 if (!nexthop)
     994           0 :                         return bputs(buf, "(null)");
     995             : 
     996           0 :                 switch (nexthop->type) {
     997           0 :                 case NEXTHOP_TYPE_IPV4:
     998             :                 case NEXTHOP_TYPE_IPV4_IFINDEX:
     999           0 :                         ret += bprintfrr(buf, "%s%pI4", v_via,
    1000             :                                          &nexthop->gate.ipv4);
    1001           0 :                         do_ifi = true;
    1002           0 :                         break;
    1003           0 :                 case NEXTHOP_TYPE_IPV6:
    1004             :                 case NEXTHOP_TYPE_IPV6_IFINDEX:
    1005           0 :                         ret += bprintfrr(buf, "%s%pI6", v_via,
    1006             :                                          &nexthop->gate.ipv6);
    1007           0 :                         do_ifi = true;
    1008           0 :                         break;
    1009           0 :                 case NEXTHOP_TYPE_IFINDEX:
    1010           0 :                         ret += bprintfrr(buf, "%sdirectly connected, %s", v_is,
    1011           0 :                                          ifindex2ifname(nexthop->ifindex,
    1012           0 :                                                         nexthop->vrf_id));
    1013           0 :                         break;
    1014           0 :                 case NEXTHOP_TYPE_BLACKHOLE:
    1015           0 :                         ret += bputs(buf, "unreachable");
    1016             : 
    1017           0 :                         switch (nexthop->bh_type) {
    1018           0 :                         case BLACKHOLE_REJECT:
    1019           0 :                                 ret += bputs(buf, " (ICMP unreachable)");
    1020           0 :                                 break;
    1021           0 :                         case BLACKHOLE_ADMINPROHIB:
    1022           0 :                                 ret += bputs(buf, " (ICMP admin-prohibited)");
    1023           0 :                                 break;
    1024           0 :                         case BLACKHOLE_NULL:
    1025           0 :                                 ret += bputs(buf, " (blackhole)");
    1026           0 :                                 break;
    1027             :                         case BLACKHOLE_UNSPEC:
    1028             :                                 break;
    1029             :                         }
    1030             :                         break;
    1031             :                 }
    1032           0 :                 if (do_ifi && nexthop->ifindex)
    1033           0 :                         ret += bprintfrr(buf, ", %s%s", v_viaif,
    1034             :                                          ifindex2ifname(nexthop->ifindex,
    1035           0 :                                                         nexthop->vrf_id));
    1036             : 
    1037             :                 return ret;
    1038           0 :         case 's':
    1039           0 :                 ea->fmt++;
    1040             : 
    1041           0 :                 ret += printfrr_nhs(buf, nexthop);
    1042           0 :                 return ret;
    1043           0 :         case 'c':
    1044           0 :                 ea->fmt++;
    1045           0 :                 if (*ea->fmt == 'g') {
    1046           0 :                         ea->fmt++;
    1047           0 :                         if (!nexthop)
    1048           0 :                                 return bputs(buf, "(null)");
    1049           0 :                         switch (nexthop->type) {
    1050           0 :                         case NEXTHOP_TYPE_IPV4:
    1051             :                         case NEXTHOP_TYPE_IPV4_IFINDEX:
    1052           0 :                                 ret += bprintfrr(buf, "%pI4",
    1053             :                                                  &nexthop->gate.ipv4);
    1054           0 :                                 break;
    1055           0 :                         case NEXTHOP_TYPE_IPV6:
    1056             :                         case NEXTHOP_TYPE_IPV6_IFINDEX:
    1057           0 :                                 ret += bprintfrr(buf, "%pI6",
    1058             :                                                  &nexthop->gate.ipv6);
    1059           0 :                                 break;
    1060             :                         case NEXTHOP_TYPE_IFINDEX:
    1061             :                         case NEXTHOP_TYPE_BLACKHOLE:
    1062             :                                 break;
    1063             :                         }
    1064           0 :                 } else if (*ea->fmt == 'i') {
    1065           0 :                         ea->fmt++;
    1066           0 :                         if (!nexthop)
    1067           0 :                                 return bputs(buf, "(null)");
    1068           0 :                         switch (nexthop->type) {
    1069           0 :                         case NEXTHOP_TYPE_IFINDEX:
    1070           0 :                                 ret += bprintfrr(
    1071             :                                         buf, "%s",
    1072           0 :                                         ifindex2ifname(nexthop->ifindex,
    1073           0 :                                                        nexthop->vrf_id));
    1074           0 :                                 break;
    1075           0 :                         case NEXTHOP_TYPE_IPV4:
    1076             :                         case NEXTHOP_TYPE_IPV4_IFINDEX:
    1077             :                         case NEXTHOP_TYPE_IPV6:
    1078             :                         case NEXTHOP_TYPE_IPV6_IFINDEX:
    1079           0 :                                 if (nexthop->ifindex)
    1080           0 :                                         ret += bprintfrr(
    1081             :                                                 buf, "%s",
    1082             :                                                 ifindex2ifname(
    1083             :                                                         nexthop->ifindex,
    1084           0 :                                                         nexthop->vrf_id));
    1085             :                                 break;
    1086             :                         case NEXTHOP_TYPE_BLACKHOLE:
    1087             :                                 break;
    1088             :                         }
    1089             :                 }
    1090             :                 return ret;
    1091             :         }
    1092             :         return -1;
    1093             : }

Generated by: LCOV version v1.16-topotato