back to topotato report
topotato coverage report
Current view: top level - lib - nexthop.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 156 531 29.4 %
Date: 2023-11-16 17:19:14 Functions: 29 89 32.6 %

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

Generated by: LCOV version v1.16-topotato