back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_srte.c (source / functions) Hit Total Coverage
Test: test_exabgp_demo.py::ExaBGPDemo Lines: 9 212 4.2 %
Date: 2023-02-24 18:37:55 Functions: 4 19 21.1 %

          Line data    Source code
       1             : /* Zebra SR-TE code
       2             :  * Copyright (C) 2020  NetDEF, Inc.
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra 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             :  * GNU Zebra 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             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "lib/zclient.h"
      24             : #include "lib/lib_errors.h"
      25             : 
      26             : #include "zebra/zebra_srte.h"
      27             : #include "zebra/zebra_mpls.h"
      28             : #include "zebra/zebra_rnh.h"
      29             : #include "zebra/zapi_msg.h"
      30             : 
      31           9 : DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy");
      32             : 
      33             : static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy);
      34             : 
      35             : /* Generate rb-tree of SR Policy instances. */
      36             : static inline int
      37           0 : zebra_sr_policy_instance_compare(const struct zebra_sr_policy *a,
      38             :                                  const struct zebra_sr_policy *b)
      39             : {
      40           0 :         return sr_policy_compare(&a->endpoint, &b->endpoint, a->color,
      41           0 :                                  b->color);
      42             : }
      43           0 : RB_GENERATE(zebra_sr_policy_instance_head, zebra_sr_policy, entry,
      44             :             zebra_sr_policy_instance_compare)
      45             : 
      46             : struct zebra_sr_policy_instance_head zebra_sr_policy_instances =
      47             :         RB_INITIALIZER(&zebra_sr_policy_instances);
      48             : 
      49           0 : struct zebra_sr_policy *zebra_sr_policy_add(uint32_t color,
      50             :                                             struct ipaddr *endpoint, char *name)
      51             : {
      52           0 :         struct zebra_sr_policy *policy;
      53             : 
      54           0 :         policy = XCALLOC(MTYPE_ZEBRA_SR_POLICY, sizeof(*policy));
      55           0 :         policy->color = color;
      56           0 :         policy->endpoint = *endpoint;
      57           0 :         strlcpy(policy->name, name, sizeof(policy->name));
      58           0 :         policy->status = ZEBRA_SR_POLICY_DOWN;
      59           0 :         RB_INSERT(zebra_sr_policy_instance_head, &zebra_sr_policy_instances,
      60             :                   policy);
      61             : 
      62           0 :         return policy;
      63             : }
      64             : 
      65           0 : void zebra_sr_policy_del(struct zebra_sr_policy *policy)
      66             : {
      67           0 :         if (policy->status == ZEBRA_SR_POLICY_UP)
      68           0 :                 zebra_sr_policy_deactivate(policy);
      69           0 :         RB_REMOVE(zebra_sr_policy_instance_head, &zebra_sr_policy_instances,
      70             :                   policy);
      71           0 :         XFREE(MTYPE_ZEBRA_SR_POLICY, policy);
      72           0 : }
      73             : 
      74           0 : struct zebra_sr_policy *zebra_sr_policy_find(uint32_t color,
      75             :                                              struct ipaddr *endpoint)
      76             : {
      77           0 :         struct zebra_sr_policy policy = {};
      78             : 
      79           0 :         policy.color = color;
      80           0 :         policy.endpoint = *endpoint;
      81           0 :         return RB_FIND(zebra_sr_policy_instance_head,
      82             :                        &zebra_sr_policy_instances, &policy);
      83             : }
      84             : 
      85           0 : struct zebra_sr_policy *zebra_sr_policy_find_by_name(char *name)
      86             : {
      87           0 :         struct zebra_sr_policy *policy;
      88             : 
      89             :         // TODO: create index for policy names
      90           0 :         RB_FOREACH (policy, zebra_sr_policy_instance_head,
      91             :                     &zebra_sr_policy_instances) {
      92           0 :                 if (strcmp(policy->name, name) == 0)
      93           0 :                         return policy;
      94             :         }
      95             : 
      96             :         return NULL;
      97             : }
      98             : 
      99           0 : static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy,
     100             :                                                 struct zserv *client)
     101             : {
     102           0 :         const struct zebra_nhlfe *nhlfe;
     103           0 :         struct stream *s;
     104           0 :         uint32_t message = 0;
     105           0 :         unsigned long nump = 0;
     106           0 :         uint8_t num;
     107           0 :         struct zapi_nexthop znh;
     108           0 :         int ret;
     109             : 
     110             :         /* Get output stream. */
     111           0 :         s = stream_new(ZEBRA_MAX_PACKET_SIZ);
     112             : 
     113           0 :         zclient_create_header(s, ZEBRA_NEXTHOP_UPDATE, zvrf_id(policy->zvrf));
     114             : 
     115             :         /* Message flags. */
     116           0 :         SET_FLAG(message, ZAPI_MESSAGE_SRTE);
     117           0 :         stream_putl(s, message);
     118             : 
     119           0 :         stream_putw(s, SAFI_UNICAST);
     120             :         /*
     121             :          * The prefix is copied twice because the ZEBRA_NEXTHOP_UPDATE
     122             :          * code was modified to send back both the matched against
     123             :          * as well as the actual matched.  There does not appear to
     124             :          * be an equivalent here so just send the same thing twice.
     125             :          */
     126           0 :         switch (policy->endpoint.ipa_type) {
     127           0 :         case IPADDR_V4:
     128           0 :                 stream_putw(s, AF_INET);
     129           0 :                 stream_putc(s, IPV4_MAX_BITLEN);
     130           0 :                 stream_put_in_addr(s, &policy->endpoint.ipaddr_v4);
     131           0 :                 stream_putw(s, AF_INET);
     132           0 :                 stream_putc(s, IPV4_MAX_BITLEN);
     133           0 :                 stream_put_in_addr(s, &policy->endpoint.ipaddr_v4);
     134           0 :                 break;
     135           0 :         case IPADDR_V6:
     136           0 :                 stream_putw(s, AF_INET6);
     137           0 :                 stream_putc(s, IPV6_MAX_BITLEN);
     138           0 :                 stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN);
     139           0 :                 stream_putw(s, AF_INET6);
     140           0 :                 stream_putc(s, IPV6_MAX_BITLEN);
     141           0 :                 stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN);
     142           0 :                 break;
     143           0 :         case IPADDR_NONE:
     144           0 :                 flog_warn(EC_LIB_DEVELOPMENT,
     145             :                           "%s: unknown policy endpoint address family: %u",
     146             :                           __func__, policy->endpoint.ipa_type);
     147           0 :                 exit(1);
     148             :         }
     149           0 :         stream_putl(s, policy->color);
     150             : 
     151           0 :         num = 0;
     152           0 :         frr_each (nhlfe_list_const, &policy->lsp->nhlfe_list, nhlfe) {
     153           0 :                 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
     154           0 :                     || CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
     155           0 :                         continue;
     156             : 
     157           0 :                 if (num == 0) {
     158           0 :                         stream_putc(s, re_type_from_lsp_type(nhlfe->type));
     159           0 :                         stream_putw(s, 0); /* instance - not available */
     160           0 :                         stream_putc(s, nhlfe->distance);
     161           0 :                         stream_putl(s, 0); /* metric - not available */
     162           0 :                         nump = stream_get_endp(s);
     163           0 :                         stream_putc(s, 0);
     164             :                 }
     165             : 
     166           0 :                 zapi_nexthop_from_nexthop(&znh, nhlfe->nexthop);
     167           0 :                 ret = zapi_nexthop_encode(s, &znh, 0, message);
     168           0 :                 if (ret < 0)
     169           0 :                         goto failure;
     170             : 
     171           0 :                 num++;
     172             :         }
     173           0 :         stream_putc_at(s, nump, num);
     174           0 :         stream_putw_at(s, 0, stream_get_endp(s));
     175             : 
     176           0 :         client->nh_last_upd_time = monotime(NULL);
     177           0 :         return zserv_send_message(client, s);
     178             : 
     179           0 : failure:
     180             : 
     181           0 :         stream_free(s);
     182           0 :         return -1;
     183             : }
     184             : 
     185           0 : static void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy)
     186             : {
     187           0 :         struct rnh *rnh;
     188           0 :         struct prefix p = {};
     189           0 :         struct zebra_vrf *zvrf;
     190           0 :         struct listnode *node;
     191           0 :         struct zserv *client;
     192             : 
     193           0 :         zvrf = policy->zvrf;
     194           0 :         switch (policy->endpoint.ipa_type) {
     195           0 :         case IPADDR_V4:
     196           0 :                 p.family = AF_INET;
     197           0 :                 p.prefixlen = IPV4_MAX_BITLEN;
     198           0 :                 p.u.prefix4 = policy->endpoint.ipaddr_v4;
     199           0 :                 break;
     200           0 :         case IPADDR_V6:
     201           0 :                 p.family = AF_INET6;
     202           0 :                 p.prefixlen = IPV6_MAX_BITLEN;
     203           0 :                 p.u.prefix6 = policy->endpoint.ipaddr_v6;
     204           0 :                 break;
     205           0 :         case IPADDR_NONE:
     206           0 :                 flog_warn(EC_LIB_DEVELOPMENT,
     207             :                           "%s: unknown policy endpoint address family: %u",
     208             :                           __func__, policy->endpoint.ipa_type);
     209           0 :                 exit(1);
     210             :         }
     211             : 
     212           0 :         rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), SAFI_UNICAST);
     213           0 :         if (!rnh)
     214           0 :                 return;
     215             : 
     216           0 :         for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
     217           0 :                 if (policy->status == ZEBRA_SR_POLICY_UP)
     218           0 :                         zebra_sr_policy_notify_update_client(policy, client);
     219             :                 else
     220             :                         /* Fallback to the IGP shortest path. */
     221           0 :                         zebra_send_rnh_update(rnh, client, zvrf_id(zvrf),
     222             :                                               policy->color);
     223             :         }
     224             : }
     225             : 
     226           0 : static void zebra_sr_policy_activate(struct zebra_sr_policy *policy,
     227             :                                      struct zebra_lsp *lsp)
     228             : {
     229           0 :         policy->status = ZEBRA_SR_POLICY_UP;
     230           0 :         policy->lsp = lsp;
     231           0 :         (void)zebra_sr_policy_bsid_install(policy);
     232           0 :         zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
     233           0 :                                       policy->name, ZEBRA_SR_POLICY_UP);
     234           0 :         zebra_sr_policy_notify_update(policy);
     235           0 : }
     236             : 
     237           0 : static void zebra_sr_policy_update(struct zebra_sr_policy *policy,
     238             :                                    struct zebra_lsp *lsp,
     239             :                                    struct zapi_srte_tunnel *old_tunnel)
     240             : {
     241           0 :         bool bsid_changed;
     242           0 :         bool segment_list_changed;
     243             : 
     244           0 :         policy->lsp = lsp;
     245             : 
     246           0 :         bsid_changed =
     247           0 :                 policy->segment_list.local_label != old_tunnel->local_label;
     248           0 :         segment_list_changed =
     249           0 :                 policy->segment_list.label_num != old_tunnel->label_num
     250           0 :                 || memcmp(policy->segment_list.labels, old_tunnel->labels,
     251             :                           sizeof(mpls_label_t)
     252           0 :                                   * policy->segment_list.label_num);
     253             : 
     254             :         /* Re-install label stack if necessary. */
     255           0 :         if (bsid_changed || segment_list_changed) {
     256           0 :                 zebra_sr_policy_bsid_uninstall(policy, old_tunnel->local_label);
     257           0 :                 (void)zebra_sr_policy_bsid_install(policy);
     258             :         }
     259             : 
     260           0 :         zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
     261           0 :                                       policy->name, ZEBRA_SR_POLICY_UP);
     262             : 
     263             :         /* Handle segment-list update. */
     264           0 :         if (segment_list_changed)
     265           0 :                 zebra_sr_policy_notify_update(policy);
     266           0 : }
     267             : 
     268           0 : static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy)
     269             : {
     270           0 :         policy->status = ZEBRA_SR_POLICY_DOWN;
     271           0 :         policy->lsp = NULL;
     272           0 :         zebra_sr_policy_bsid_uninstall(policy,
     273             :                                        policy->segment_list.local_label);
     274           0 :         zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
     275           0 :                                       policy->name, ZEBRA_SR_POLICY_DOWN);
     276           0 :         zebra_sr_policy_notify_update(policy);
     277           0 : }
     278             : 
     279           0 : int zebra_sr_policy_validate(struct zebra_sr_policy *policy,
     280             :                              struct zapi_srte_tunnel *new_tunnel)
     281             : {
     282           0 :         struct zapi_srte_tunnel old_tunnel = policy->segment_list;
     283           0 :         struct zebra_lsp *lsp;
     284             : 
     285           0 :         if (new_tunnel)
     286           0 :                 policy->segment_list = *new_tunnel;
     287             : 
     288             :         /* Try to resolve the Binding-SID nexthops. */
     289           0 :         lsp = mpls_lsp_find(policy->zvrf, policy->segment_list.labels[0]);
     290           0 :         if (!lsp || !lsp->best_nhlfe
     291           0 :             || lsp->addr_family != ipaddr_family(&policy->endpoint)) {
     292           0 :                 if (policy->status == ZEBRA_SR_POLICY_UP)
     293           0 :                         zebra_sr_policy_deactivate(policy);
     294           0 :                 return -1;
     295             :         }
     296             : 
     297             :         /* First label was resolved successfully. */
     298           0 :         if (policy->status == ZEBRA_SR_POLICY_DOWN)
     299           0 :                 zebra_sr_policy_activate(policy, lsp);
     300             :         else
     301           0 :                 zebra_sr_policy_update(policy, lsp, &old_tunnel);
     302             : 
     303             :         return 0;
     304             : }
     305             : 
     306           0 : int zebra_sr_policy_bsid_install(struct zebra_sr_policy *policy)
     307             : {
     308           0 :         struct zapi_srte_tunnel *zt = &policy->segment_list;
     309           0 :         struct zebra_nhlfe *nhlfe;
     310             : 
     311           0 :         if (zt->local_label == MPLS_LABEL_NONE)
     312             :                 return 0;
     313             : 
     314           0 :         frr_each_safe (nhlfe_list, &policy->lsp->nhlfe_list, nhlfe) {
     315           0 :                 uint8_t num_out_labels;
     316           0 :                 mpls_label_t *out_labels;
     317           0 :                 mpls_label_t null_label = MPLS_LABEL_IMPLICIT_NULL;
     318             : 
     319           0 :                 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
     320           0 :                     || CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
     321           0 :                         continue;
     322             : 
     323             :                 /*
     324             :                  * Don't push the first SID if the corresponding action in the
     325             :                  * LFIB is POP.
     326             :                  */
     327           0 :                 if (!nhlfe->nexthop->nh_label
     328           0 :                     || !nhlfe->nexthop->nh_label->num_labels
     329           0 :                     || nhlfe->nexthop->nh_label->label[0]
     330             :                                == MPLS_LABEL_IMPLICIT_NULL) {
     331           0 :                         if (zt->label_num > 1) {
     332           0 :                                 num_out_labels = zt->label_num - 1;
     333           0 :                                 out_labels = &zt->labels[1];
     334             :                         } else {
     335             :                                 num_out_labels = 1;
     336             :                                 out_labels = &null_label;
     337             :                         }
     338             :                 } else {
     339           0 :                         num_out_labels = zt->label_num;
     340           0 :                         out_labels = zt->labels;
     341             :                 }
     342             : 
     343           0 :                 if (mpls_lsp_install(
     344             :                             policy->zvrf, zt->type, zt->local_label,
     345             :                             num_out_labels, out_labels, nhlfe->nexthop->type,
     346           0 :                             &nhlfe->nexthop->gate, nhlfe->nexthop->ifindex)
     347             :                     < 0)
     348           0 :                         return -1;
     349             :         }
     350             : 
     351             :         return 0;
     352             : }
     353             : 
     354           0 : void zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy *policy,
     355             :                                     mpls_label_t old_bsid)
     356             : {
     357           0 :         struct zapi_srte_tunnel *zt = &policy->segment_list;
     358             : 
     359           0 :         mpls_lsp_uninstall_all_vrf(policy->zvrf, zt->type, old_bsid);
     360           0 : }
     361             : 
     362           0 : int zebra_sr_policy_label_update(mpls_label_t label,
     363             :                                  enum zebra_sr_policy_update_label_mode mode)
     364             : {
     365           0 :         struct zebra_sr_policy *policy;
     366             : 
     367           0 :         RB_FOREACH (policy, zebra_sr_policy_instance_head,
     368             :                     &zebra_sr_policy_instances) {
     369           0 :                 mpls_label_t next_hop_label;
     370             : 
     371           0 :                 next_hop_label = policy->segment_list.labels[0];
     372           0 :                 if (next_hop_label != label)
     373           0 :                         continue;
     374             : 
     375           0 :                 switch (mode) {
     376           0 :                 case ZEBRA_SR_POLICY_LABEL_CREATED:
     377             :                 case ZEBRA_SR_POLICY_LABEL_UPDATED:
     378             :                 case ZEBRA_SR_POLICY_LABEL_REMOVED:
     379           0 :                         zebra_sr_policy_validate(policy, NULL);
     380           0 :                         break;
     381             :                 }
     382             :         }
     383             : 
     384           0 :         return 0;
     385             : }
     386             : 
     387           6 : static int zebra_srte_client_close_cleanup(struct zserv *client)
     388             : {
     389           6 :         int sock = client->sock;
     390           6 :         struct zebra_sr_policy *policy, *policy_temp;
     391             : 
     392           6 :         if (!sock)
     393             :                 return 0;
     394             : 
     395          12 :         RB_FOREACH_SAFE (policy, zebra_sr_policy_instance_head,
     396             :                          &zebra_sr_policy_instances, policy_temp) {
     397           0 :                 if (policy->sock == sock)
     398           0 :                         zebra_sr_policy_del(policy);
     399             :         }
     400             :         return 1;
     401             : }
     402             : 
     403           3 : void zebra_srte_init(void)
     404             : {
     405           3 :         hook_register(zserv_client_close, zebra_srte_client_close_cleanup);
     406           3 : }

Generated by: LCOV version v1.16-topotato