back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_srv6.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 9 167 5.4 %
Date: 2023-02-24 14:41:08 Functions: 6 26 23.1 %

          Line data    Source code
       1             : /*
       2             :  * Zebra SRv6 definitions
       3             :  * Copyright (C) 2020  Hiroki Shirokura, LINE Corporation
       4             :  * Copyright (C) 2020  Masakazu Asama
       5             :  *
       6             :  * This program 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 Free
       8             :  * Software Foundation; either version 2 of the License, or (at your option)
       9             :  * any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      12             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      14             :  * 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 "network.h"
      24             : #include "prefix.h"
      25             : #include "stream.h"
      26             : #include "srv6.h"
      27             : #include "zebra/debug.h"
      28             : #include "zebra/zapi_msg.h"
      29             : #include "zebra/zserv.h"
      30             : #include "zebra/zebra_router.h"
      31             : #include "zebra/zebra_srv6.h"
      32             : #include "zebra/zebra_errors.h"
      33             : #include <stdio.h>
      34             : #include <string.h>
      35             : #include <stdlib.h>
      36             : #include <arpa/inet.h>
      37             : #include <netinet/in.h>
      38             : 
      39             : #include <stdio.h>
      40             : #include <string.h>
      41             : #include <stdlib.h>
      42             : #include <arpa/inet.h>
      43             : #include <netinet/in.h>
      44             : 
      45             : 
      46         237 : DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager");
      47         237 : DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk");
      48             : 
      49             : /* define hooks for the basic API, so that it can be specialized or served
      50             :  * externally
      51             :  */
      52             : 
      53           0 : DEFINE_HOOK(srv6_manager_client_connect,
      54             :             (struct zserv *client, vrf_id_t vrf_id),
      55             :             (client, vrf_id));
      56           0 : DEFINE_HOOK(srv6_manager_client_disconnect,
      57             :             (struct zserv *client), (client));
      58           0 : DEFINE_HOOK(srv6_manager_get_chunk,
      59             :             (struct srv6_locator **loc,
      60             :              struct zserv *client,
      61             :              const char *locator_name,
      62             :              vrf_id_t vrf_id),
      63             :             (loc, client, locator_name, vrf_id));
      64           0 : DEFINE_HOOK(srv6_manager_release_chunk,
      65             :             (struct zserv *client,
      66             :              const char *locator_name,
      67             :              vrf_id_t vrf_id),
      68             :             (client, locator_name, vrf_id));
      69             : 
      70             : /* define wrappers to be called in zapi_msg.c (as hooks must be called in
      71             :  * source file where they were defined)
      72             :  */
      73             : 
      74           0 : void srv6_manager_client_connect_call(struct zserv *client, vrf_id_t vrf_id)
      75             : {
      76           0 :         hook_call(srv6_manager_client_connect, client, vrf_id);
      77           0 : }
      78             : 
      79           0 : void srv6_manager_get_locator_chunk_call(struct srv6_locator **loc,
      80             :                                          struct zserv *client,
      81             :                                          const char *locator_name,
      82             :                                          vrf_id_t vrf_id)
      83             : {
      84           0 :         hook_call(srv6_manager_get_chunk, loc, client, locator_name, vrf_id);
      85           0 : }
      86             : 
      87           0 : void srv6_manager_release_locator_chunk_call(struct zserv *client,
      88             :                                              const char *locator_name,
      89             :                                              vrf_id_t vrf_id)
      90             : {
      91           0 :         hook_call(srv6_manager_release_chunk, client, locator_name, vrf_id);
      92           0 : }
      93             : 
      94           0 : int srv6_manager_client_disconnect_cb(struct zserv *client)
      95             : {
      96           0 :         hook_call(srv6_manager_client_disconnect, client);
      97           0 :         return 0;
      98             : }
      99             : 
     100         171 : static int zebra_srv6_cleanup(struct zserv *client)
     101             : {
     102         171 :         return 0;
     103             : }
     104             : 
     105           0 : void zebra_srv6_locator_add(struct srv6_locator *locator)
     106             : {
     107           0 :         struct zebra_srv6 *srv6 = zebra_srv6_get_default();
     108           0 :         struct srv6_locator *tmp;
     109           0 :         struct listnode *node;
     110           0 :         struct zserv *client;
     111             : 
     112           0 :         tmp = zebra_srv6_locator_lookup(locator->name);
     113           0 :         if (!tmp)
     114           0 :                 listnode_add(srv6->locators, locator);
     115             : 
     116             :         /*
     117             :          * Notify new locator info to zclients.
     118             :          *
     119             :          * The srv6 locators and their prefixes are managed by zserv(zebra).
     120             :          * And an actual configuration the srv6 sid in the srv6 locator is done
     121             :          * by zclient(bgpd, isisd, etc). The configuration of each locator
     122             :          * allocation and specify it by zserv and zclient should be
     123             :          * asynchronous. For that, zclient should be received the event via
     124             :          * ZAPI when a srv6 locator is added on zebra.
     125             :          * Basically, in SRv6, adding/removing SRv6 locators is performed less
     126             :          * frequently than adding rib entries, so a broad to all zclients will
     127             :          * not degrade the overall performance of FRRouting.
     128             :          */
     129           0 :         for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
     130           0 :                 zsend_zebra_srv6_locator_add(client, locator);
     131           0 : }
     132             : 
     133           0 : void zebra_srv6_locator_delete(struct srv6_locator *locator)
     134             : {
     135           0 :         struct listnode *n;
     136           0 :         struct srv6_locator_chunk *c;
     137           0 :         struct zebra_srv6 *srv6 = zebra_srv6_get_default();
     138           0 :         struct zserv *client;
     139             : 
     140             :         /*
     141             :          * Notify deleted locator info to zclients if needed.
     142             :          *
     143             :          * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
     144             :          * uses it for its own purpose. For example, in the case of BGP L3VPN,
     145             :          * the SID assigned to vpn unicast rib will be given.
     146             :          * And when the locator is deleted by zserv(zebra), those SIDs need to
     147             :          * be withdrawn. The zclient must initiate the withdrawal of the SIDs
     148             :          * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
     149             :          * owner of each chunk.
     150             :          */
     151           0 :         for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
     152           0 :                 if (c->proto == ZEBRA_ROUTE_SYSTEM)
     153           0 :                         continue;
     154           0 :                 client = zserv_find_client(c->proto, c->instance);
     155           0 :                 if (!client) {
     156           0 :                         zlog_warn(
     157             :                                 "%s: Not found zclient(proto=%u, instance=%u).",
     158             :                                 __func__, c->proto, c->instance);
     159           0 :                         continue;
     160             :                 }
     161           0 :                 zsend_zebra_srv6_locator_delete(client, locator);
     162             :         }
     163             : 
     164           0 :         listnode_delete(srv6->locators, locator);
     165           0 :         srv6_locator_free(locator);
     166           0 : }
     167             : 
     168           0 : struct srv6_locator *zebra_srv6_locator_lookup(const char *name)
     169             : {
     170           0 :         struct zebra_srv6 *srv6 = zebra_srv6_get_default();
     171           0 :         struct srv6_locator *locator;
     172           0 :         struct listnode *node;
     173             : 
     174           0 :         for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator))
     175           0 :                 if (!strncmp(name, locator->name, SRV6_LOCNAME_SIZE))
     176           0 :                         return locator;
     177             :         return NULL;
     178             : }
     179             : 
     180           0 : void zebra_notify_srv6_locator_add(struct srv6_locator *locator)
     181             : {
     182           0 :         struct listnode *node;
     183           0 :         struct zserv *client;
     184             : 
     185             :         /*
     186             :          * Notify new locator info to zclients.
     187             :          *
     188             :          * The srv6 locators and their prefixes are managed by zserv(zebra).
     189             :          * And an actual configuration the srv6 sid in the srv6 locator is done
     190             :          * by zclient(bgpd, isisd, etc). The configuration of each locator
     191             :          * allocation and specify it by zserv and zclient should be
     192             :          * asynchronous. For that, zclient should be received the event via
     193             :          * ZAPI when a srv6 locator is added on zebra.
     194             :          * Basically, in SRv6, adding/removing SRv6 locators is performed less
     195             :          * frequently than adding rib entries, so a broad to all zclients will
     196             :          * not degrade the overall performance of FRRouting.
     197             :          */
     198           0 :         for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
     199           0 :                 zsend_zebra_srv6_locator_add(client, locator);
     200           0 : }
     201             : 
     202           0 : void zebra_notify_srv6_locator_delete(struct srv6_locator *locator)
     203             : {
     204           0 :         struct listnode *n;
     205           0 :         struct srv6_locator_chunk *c;
     206           0 :         struct zserv *client;
     207             : 
     208             :         /*
     209             :          * Notify deleted locator info to zclients if needed.
     210             :          *
     211             :          * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
     212             :          * uses it for its own purpose. For example, in the case of BGP L3VPN,
     213             :          * the SID assigned to vpn unicast rib will be given.
     214             :          * And when the locator is deleted by zserv(zebra), those SIDs need to
     215             :          * be withdrawn. The zclient must initiate the withdrawal of the SIDs
     216             :          * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
     217             :          * owner of each chunk.
     218             :          */
     219           0 :         for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
     220           0 :                 if (c->proto == ZEBRA_ROUTE_SYSTEM)
     221           0 :                         continue;
     222           0 :                 client = zserv_find_client(c->proto, c->instance);
     223           0 :                 if (!client) {
     224           0 :                         zlog_warn("Not found zclient(proto=%u, instance=%u).",
     225             :                                   c->proto, c->instance);
     226           0 :                         continue;
     227             :                 }
     228           0 :                 zsend_zebra_srv6_locator_delete(client, locator);
     229             :         }
     230           0 : }
     231             : 
     232           0 : struct zebra_srv6 *zebra_srv6_get_default(void)
     233             : {
     234           0 :         static struct zebra_srv6 srv6;
     235           0 :         static bool first_execution = true;
     236             : 
     237           0 :         if (first_execution) {
     238           0 :                 first_execution = false;
     239           0 :                 srv6.locators = list_new();
     240             :         }
     241           0 :         return &srv6;
     242             : }
     243             : 
     244             : /**
     245             :  * Core function, assigns srv6-locator chunks
     246             :  *
     247             :  * It first searches through the list to check if there's one available
     248             :  * (previously released). Otherwise it creates and assigns a new one
     249             :  *
     250             :  * @param proto Daemon protocol of client, to identify the owner
     251             :  * @param instance Instance, to identify the owner
     252             :  * @param session_id SessionID of client
     253             :  * @param name Name of SRv6-locator
     254             :  * @return Pointer to the assigned srv6-locator chunk,
     255             :  *         or NULL if the request could not be satisfied
     256             :  */
     257             : static struct srv6_locator *
     258           0 : assign_srv6_locator_chunk(uint8_t proto,
     259             :                           uint16_t instance,
     260             :                           uint32_t session_id,
     261             :                           const char *locator_name)
     262             : {
     263           0 :         bool chunk_found = false;
     264           0 :         struct listnode *node = NULL;
     265           0 :         struct srv6_locator *loc = NULL;
     266           0 :         struct srv6_locator_chunk *chunk = NULL;
     267             : 
     268           0 :         loc = zebra_srv6_locator_lookup(locator_name);
     269           0 :         if (!loc) {
     270           0 :                 zlog_info("%s: locator %s was not found",
     271             :                           __func__, locator_name);
     272           0 :                 return NULL;
     273             :         }
     274             : 
     275           0 :         for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
     276           0 :                 if (chunk->proto != NO_PROTO && chunk->proto != proto)
     277           0 :                         continue;
     278             :                 chunk_found = true;
     279             :                 break;
     280             :         }
     281             : 
     282           0 :         if (!chunk_found) {
     283           0 :                 zlog_info("%s: locator is already owned", __func__);
     284           0 :                 return NULL;
     285             :         }
     286             : 
     287           0 :         chunk->proto = proto;
     288           0 :         chunk->instance = instance;
     289           0 :         chunk->session_id = session_id;
     290           0 :         return loc;
     291             : }
     292             : 
     293           0 : static int zebra_srv6_manager_get_locator_chunk(struct srv6_locator **loc,
     294             :                                                 struct zserv *client,
     295             :                                                 const char *locator_name,
     296             :                                                 vrf_id_t vrf_id)
     297             : {
     298           0 :         int ret = 0;
     299             : 
     300           0 :         *loc = assign_srv6_locator_chunk(client->proto, client->instance,
     301             :                                          client->session_id, locator_name);
     302             : 
     303           0 :         if (!*loc)
     304           0 :                 zlog_err("Unable to assign locator chunk to %s instance %u",
     305             :                          zebra_route_string(client->proto), client->instance);
     306           0 :         else if (IS_ZEBRA_DEBUG_PACKET)
     307           0 :                 zlog_info("Assigned locator chunk %s to %s instance %u",
     308             :                           (*loc)->name, zebra_route_string(client->proto),
     309             :                           client->instance);
     310             : 
     311           0 :         if (*loc && (*loc)->status_up)
     312           0 :                 ret = zsend_srv6_manager_get_locator_chunk_response(client,
     313             :                                                                     vrf_id,
     314             :                                                                     *loc);
     315           0 :         return ret;
     316             : }
     317             : 
     318             : /**
     319             :  * Core function, release no longer used srv6-locator chunks
     320             :  *
     321             :  * @param proto Daemon protocol of client, to identify the owner
     322             :  * @param instance Instance, to identify the owner
     323             :  * @param session_id Zclient session ID, to identify the zclient session
     324             :  * @param locator_name SRv6-locator name, to identify the actual locator
     325             :  * @return 0 on success, -1 otherwise
     326             :  */
     327           0 : static int release_srv6_locator_chunk(uint8_t proto, uint16_t instance,
     328             :                                       uint32_t session_id,
     329             :                                       const char *locator_name)
     330             : {
     331           0 :         int ret = -1;
     332           0 :         struct listnode *node;
     333           0 :         struct srv6_locator_chunk *chunk;
     334           0 :         struct srv6_locator *loc = NULL;
     335             : 
     336           0 :         loc = zebra_srv6_locator_lookup(locator_name);
     337           0 :         if (!loc)
     338             :                 return -1;
     339             : 
     340           0 :         if (IS_ZEBRA_DEBUG_PACKET)
     341           0 :                 zlog_debug("%s: Releasing srv6-locator on %s", __func__,
     342             :                            locator_name);
     343             : 
     344           0 :         for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
     345           0 :                 if (chunk->proto != proto ||
     346           0 :                     chunk->instance != instance ||
     347           0 :                     chunk->session_id != session_id)
     348           0 :                         continue;
     349           0 :                 chunk->proto = NO_PROTO;
     350           0 :                 chunk->instance = 0;
     351           0 :                 chunk->session_id = 0;
     352           0 :                 chunk->keep = 0;
     353           0 :                 ret = 0;
     354           0 :                 break;
     355             :         }
     356             : 
     357           0 :         if (ret != 0)
     358           0 :                 flog_err(EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
     359             :                          "%s: SRv6 locator chunk not released", __func__);
     360             : 
     361             :         return ret;
     362             : }
     363             : 
     364           0 : static int zebra_srv6_manager_release_locator_chunk(struct zserv *client,
     365             :                                                     const char *locator_name,
     366             :                                                     vrf_id_t vrf_id)
     367             : {
     368           0 :         if (vrf_id != VRF_DEFAULT) {
     369           0 :                 zlog_err("SRv6 locator doesn't support vrf");
     370           0 :                 return -1;
     371             :         }
     372             : 
     373           0 :         return release_srv6_locator_chunk(client->proto, client->instance,
     374             :                                           client->session_id, locator_name);
     375             : }
     376             : 
     377             : /**
     378             :  * Release srv6-locator chunks from a client.
     379             :  *
     380             :  * Called on client disconnection or reconnection. It only releases chunks
     381             :  * with empty keep value.
     382             :  *
     383             :  * @param proto Daemon protocol of client, to identify the owner
     384             :  * @param instance Instance, to identify the owner
     385             :  * @return Number of chunks released
     386             :  */
     387           0 : int release_daemon_srv6_locator_chunks(struct zserv *client)
     388             : {
     389           0 :         int ret;
     390           0 :         int count = 0;
     391           0 :         struct zebra_srv6 *srv6 = zebra_srv6_get_default();
     392           0 :         struct listnode *loc_node;
     393           0 :         struct listnode *chunk_node;
     394           0 :         struct srv6_locator *loc;
     395           0 :         struct srv6_locator_chunk *chunk;
     396             : 
     397           0 :         if (IS_ZEBRA_DEBUG_PACKET)
     398           0 :                 zlog_debug("%s: Releasing chunks for client proto %s, instance %d, session %u",
     399             :                            __func__, zebra_route_string(client->proto),
     400             :                            client->instance, client->session_id);
     401             : 
     402           0 :         for (ALL_LIST_ELEMENTS_RO(srv6->locators, loc_node, loc)) {
     403           0 :                 for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, chunk)) {
     404           0 :                         if (chunk->proto == client->proto &&
     405           0 :                             chunk->instance == client->instance &&
     406           0 :                             chunk->session_id == client->session_id &&
     407           0 :                             chunk->keep == 0) {
     408           0 :                                 ret = release_srv6_locator_chunk(
     409             :                                                 chunk->proto, chunk->instance,
     410           0 :                                                 chunk->session_id, loc->name);
     411           0 :                                 if (ret == 0)
     412           0 :                                         count++;
     413             :                         }
     414             :                 }
     415             :         }
     416             : 
     417           0 :         if (IS_ZEBRA_DEBUG_PACKET)
     418           0 :                 zlog_debug("%s: Released %d srv6-locator chunks",
     419             :                            __func__, count);
     420             : 
     421           0 :         return count;
     422             : }
     423             : 
     424          79 : void zebra_srv6_init(void)
     425             : {
     426          79 :         hook_register(zserv_client_close, zebra_srv6_cleanup);
     427          79 :         hook_register(srv6_manager_get_chunk,
     428             :                       zebra_srv6_manager_get_locator_chunk);
     429          79 :         hook_register(srv6_manager_release_chunk,
     430             :                       zebra_srv6_manager_release_locator_chunk);
     431          79 : }
     432             : 
     433           0 : bool zebra_srv6_is_enable(void)
     434             : {
     435           0 :         struct zebra_srv6 *srv6 = zebra_srv6_get_default();
     436             : 
     437           0 :         return listcount(srv6->locators);
     438             : }

Generated by: LCOV version v1.16-topotato