back to topotato report
topotato coverage report
Current view: top level - zebra - table_manager.c (source / functions) Hit Total Coverage
Test: test_pim_cbsr.py::PIMCandidateBSRTest Lines: 33 140 23.6 %
Date: 2023-02-16 02:09:14 Functions: 9 13 69.2 %

          Line data    Source code
       1             : /* zebra table Manager for routing table identifier management
       2             :  * Copyright (C) 2018 6WIND
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or modify it
       5             :  * under the terms of the GNU General Public License as published by the Free
       6             :  * Software Foundation; either version 2 of the License, or (at your option)
       7             :  * any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      11             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      12             :  * more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License along
      15             :  * with this program; see the file COPYING; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      17             :  */
      18             : 
      19             : #include "zebra.h"
      20             : 
      21             : #include <stdio.h>
      22             : #include <string.h>
      23             : #include <sys/types.h>
      24             : 
      25             : #include "lib/log.h"
      26             : #include "lib/memory.h"
      27             : #include "lib/table.h"
      28             : #include "lib/network.h"
      29             : #include "lib/stream.h"
      30             : #include "lib/zclient.h"
      31             : #include "lib/libfrr.h"
      32             : #include "lib/vrf.h"
      33             : 
      34             : #include "zebra/zserv.h"
      35             : #include "zebra/zebra_vrf.h"
      36             : #include "zebra/label_manager.h" /* for NO_PROTO */
      37             : #include "zebra/table_manager.h"
      38             : #include "zebra/zebra_errors.h"
      39             : 
      40             : /* routing table identifiers
      41             :  *
      42             :  */
      43             : #if !defined(GNU_LINUX)
      44             : /* BSD systems
      45             :  */
      46             : #else
      47             : /* Linux Systems
      48             :  */
      49             : #define RT_TABLE_ID_LOCAL                  255
      50             : #define RT_TABLE_ID_MAIN                   254
      51             : #define RT_TABLE_ID_DEFAULT                253
      52             : #define RT_TABLE_ID_COMPAT                 252
      53             : #define RT_TABLE_ID_UNSPEC                 0
      54             : #endif /* !def(GNU_LINUX) */
      55             : #define RT_TABLE_ID_UNRESERVED_MIN         1
      56             : #define RT_TABLE_ID_UNRESERVED_MAX         0xffffffff
      57             : 
      58           9 : DEFINE_MGROUP(TABLE_MGR, "Table Manager");
      59           9 : DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
      60           9 : DEFINE_MTYPE_STATIC(TABLE_MGR, TM_TABLE, "Table Manager Context");
      61             : 
      62           0 : static void delete_table_chunk(void *val)
      63             : {
      64           0 :         XFREE(MTYPE_TM_CHUNK, val);
      65           0 : }
      66             : 
      67             : /**
      68             :  * Init table manager
      69             :  */
      70           3 : void table_manager_enable(struct zebra_vrf *zvrf)
      71             : {
      72             : 
      73           3 :         if (zvrf->tbl_mgr)
      74             :                 return;
      75           3 :         if (!vrf_is_backend_netns()
      76           6 :             && strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) {
      77           0 :                 struct zebra_vrf *def = zebra_vrf_lookup_by_id(VRF_DEFAULT);
      78             : 
      79           0 :                 if (def)
      80           0 :                         zvrf->tbl_mgr = def->tbl_mgr;
      81           0 :                 return;
      82             :         }
      83           3 :         zvrf->tbl_mgr = XCALLOC(MTYPE_TM_TABLE, sizeof(struct table_manager));
      84           3 :         zvrf->tbl_mgr->lc_list = list_new();
      85           3 :         zvrf->tbl_mgr->lc_list->del = delete_table_chunk;
      86             : }
      87             : 
      88             : /**
      89             :  * Core function, assigns table chunks
      90             :  *
      91             :  * It first searches through the list to check if there's one available
      92             :  * (previously released). Otherwise it creates and assigns a new one
      93             :  *
      94             :  * @param proto Daemon protocol of client, to identify the owner
      95             :  * @param instance Instance, to identify the owner
      96             :  * @para size Size of the table chunk
      97             :  * @return Pointer to the assigned table chunk
      98             :  */
      99           0 : struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
     100             :                                                uint32_t size,
     101             :                                                struct zebra_vrf *zvrf)
     102             : {
     103           0 :         struct table_manager_chunk *tmc;
     104           0 :         struct listnode *node;
     105           0 :         uint32_t start;
     106           0 :         bool manual_conf = false;
     107             : 
     108           0 :         if (!zvrf)
     109             :                 return NULL;
     110             : 
     111             :         /* first check if there's one available */
     112           0 :         for (ALL_LIST_ELEMENTS_RO(zvrf->tbl_mgr->lc_list, node, tmc)) {
     113           0 :                 if (tmc->proto == NO_PROTO
     114           0 :                     && tmc->end - tmc->start + 1 == size) {
     115           0 :                         tmc->proto = proto;
     116           0 :                         tmc->instance = instance;
     117           0 :                         return tmc;
     118             :                 }
     119             :         }
     120             :         /* otherwise create a new one */
     121           0 :         tmc = XCALLOC(MTYPE_TM_CHUNK, sizeof(struct table_manager_chunk));
     122             : 
     123           0 :         if (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)
     124           0 :                 manual_conf = true;
     125             :         /* table RT IDs range are [1;252] and [256;0xffffffff]
     126             :          * - check if the requested range can be within the first range,
     127             :          * otherwise elect second one
     128             :          * - TODO : vrf-lites have their own table identifier.
     129             :          * In that case, table_id should be removed from the table range.
     130             :          */
     131           0 :         if (list_isempty(zvrf->tbl_mgr->lc_list)) {
     132           0 :                 if (!manual_conf)
     133             :                         start = RT_TABLE_ID_UNRESERVED_MIN;
     134             :                 else
     135           0 :                         start = zvrf->tbl_mgr->start;
     136             :         } else
     137           0 :                 start = ((struct table_manager_chunk *)listgetdata(
     138             :                                  listtail(zvrf->tbl_mgr->lc_list)))
     139           0 :                                 ->end
     140             :                         + 1;
     141             : 
     142           0 :         if (!manual_conf) {
     143             : 
     144             : #if !defined(GNU_LINUX)
     145             : /* BSD systems
     146             :  */
     147             : #else
     148             : /* Linux Systems
     149             :  */
     150             :                 /* if not enough room space between MIN and COMPAT,
     151             :                  * then begin after LOCAL
     152             :                  */
     153           0 :                 if (start < RT_TABLE_ID_COMPAT
     154           0 :                     && (size > RT_TABLE_ID_COMPAT - RT_TABLE_ID_UNRESERVED_MIN))
     155           0 :                         start = RT_TABLE_ID_LOCAL + 1;
     156             : #endif /* !def(GNU_LINUX) */
     157           0 :                 tmc->start = start;
     158           0 :                 if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
     159           0 :                         flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
     160             :                                  "Reached max table id. Start/Size %u/%u",
     161             :                                  start, size);
     162           0 :                         XFREE(MTYPE_TM_CHUNK, tmc);
     163           0 :                         return NULL;
     164             :                 }
     165             :         } else {
     166           0 :                 tmc->start = start;
     167           0 :                 if (zvrf->tbl_mgr->end - size + 1 < start) {
     168           0 :                         flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
     169             :                                  "Reached max table id. Start/Size %u/%u",
     170             :                                  start, size);
     171           0 :                         XFREE(MTYPE_TM_CHUNK, tmc);
     172           0 :                         return NULL;
     173             :                 }
     174             :         }
     175           0 :         tmc->end = tmc->start + size - 1;
     176           0 :         tmc->proto = proto;
     177           0 :         tmc->instance = instance;
     178           0 :         listnode_add(zvrf->tbl_mgr->lc_list, tmc);
     179             : 
     180           0 :         return tmc;
     181             : }
     182             : 
     183             : /**
     184             :  * Core function, release no longer used table chunks
     185             :  *
     186             :  * @param proto Daemon protocol of client, to identify the owner
     187             :  * @param instance Instance, to identify the owner
     188             :  * @param start First table RT ID of the chunk
     189             :  * @param end Last table RT ID of the chunk
     190             :  * @return 0 on success, -1 otherwise
     191             :  */
     192           0 : int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
     193             :                         uint32_t end, struct zebra_vrf *zvrf)
     194             : {
     195           0 :         struct listnode *node;
     196           0 :         struct table_manager_chunk *tmc;
     197           0 :         int ret = -1;
     198           0 :         struct table_manager *tbl_mgr;
     199             : 
     200           0 :         if (!zvrf)
     201             :                 return -1;
     202             : 
     203           0 :         tbl_mgr = zvrf->tbl_mgr;
     204           0 :         if (!tbl_mgr)
     205             :                 return ret;
     206             :         /* check that size matches */
     207           0 :         zlog_debug("Releasing table chunk: %u - %u", start, end);
     208             :         /* find chunk and disown */
     209           0 :         for (ALL_LIST_ELEMENTS_RO(tbl_mgr->lc_list, node, tmc)) {
     210           0 :                 if (tmc->start != start)
     211           0 :                         continue;
     212           0 :                 if (tmc->end != end)
     213           0 :                         continue;
     214           0 :                 if (tmc->proto != proto || tmc->instance != instance) {
     215           0 :                         flog_err(EC_ZEBRA_TM_DAEMON_MISMATCH,
     216             :                                  "%s: Daemon mismatch!!", __func__);
     217           0 :                         continue;
     218             :                 }
     219           0 :                 tmc->proto = NO_PROTO;
     220           0 :                 tmc->instance = 0;
     221           0 :                 ret = 0;
     222           0 :                 break;
     223             :         }
     224           0 :         if (ret != 0)
     225           0 :                 flog_err(EC_ZEBRA_TM_UNRELEASED_CHUNK,
     226             :                          "%s: Table chunk not released!!", __func__);
     227             : 
     228             :         return ret;
     229             : }
     230             : 
     231             : /**
     232             :  * Release table chunks from a client.
     233             :  *
     234             :  * Called on client disconnection or reconnection. It only releases chunks
     235             :  * with empty keep value.
     236             :  *
     237             :  * @param client the client to release chunks from
     238             :  * @return Number of chunks released
     239             :  */
     240           9 : int release_daemon_table_chunks(struct zserv *client)
     241             : {
     242           9 :         uint8_t proto = client->proto;
     243           9 :         uint16_t instance = client->instance;
     244           9 :         struct listnode *node;
     245           9 :         struct table_manager_chunk *tmc;
     246           9 :         int count = 0;
     247           9 :         int ret;
     248           9 :         struct vrf *vrf;
     249           9 :         struct zebra_vrf *zvrf;
     250             : 
     251          27 :         RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
     252           9 :                 zvrf = vrf->info;
     253             : 
     254           9 :                 if (!zvrf)
     255           0 :                         continue;
     256           9 :                 if (!vrf_is_backend_netns() && vrf->vrf_id != VRF_DEFAULT)
     257           0 :                         continue;
     258          18 :                 for (ALL_LIST_ELEMENTS_RO(zvrf->tbl_mgr->lc_list, node, tmc)) {
     259           0 :                         if (tmc->proto == proto && tmc->instance == instance) {
     260           0 :                                 ret = release_table_chunk(
     261             :                                         tmc->proto, tmc->instance, tmc->start,
     262             :                                         tmc->end, zvrf);
     263           0 :                                 if (ret == 0)
     264           0 :                                         count++;
     265             :                         }
     266             :                 }
     267             :         }
     268           9 :         zlog_debug("%s: Released %d table chunks", __func__, count);
     269             : 
     270           9 :         return count;
     271             : }
     272             : 
     273           0 : static void table_range_add(struct zebra_vrf *zvrf, uint32_t start,
     274             :                             uint32_t end)
     275             : {
     276           0 :         if (!zvrf->tbl_mgr)
     277             :                 return;
     278           0 :         zvrf->tbl_mgr->start = start;
     279           0 :         zvrf->tbl_mgr->end = end;
     280             : }
     281             : 
     282           3 : void table_manager_disable(struct zebra_vrf *zvrf)
     283             : {
     284           3 :         if (!zvrf->tbl_mgr)
     285             :                 return;
     286           3 :         if (!vrf_is_backend_netns()
     287           6 :             && strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) {
     288           0 :                 zvrf->tbl_mgr = NULL;
     289           0 :                 return;
     290             :         }
     291           3 :         list_delete(&zvrf->tbl_mgr->lc_list);
     292           3 :         XFREE(MTYPE_TM_TABLE, zvrf->tbl_mgr);
     293           3 :         zvrf->tbl_mgr = NULL;
     294             : }
     295             : 
     296           0 : int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf,
     297             :                         const char *start_table_str, const char *end_table_str)
     298             : {
     299           0 :         uint32_t start;
     300           0 :         uint32_t end;
     301             : 
     302           0 :         if (add) {
     303           0 :                 if (!start_table_str || !end_table_str) {
     304           0 :                         vty_out(vty, "%% Labels not specified\n");
     305           0 :                         return CMD_WARNING_CONFIG_FAILED;
     306             :                 }
     307           0 :                 start = atoi(start_table_str);
     308           0 :                 end = atoi(end_table_str);
     309           0 :                 if (end < start) {
     310           0 :                         vty_out(vty, "%% End table is less than Start table\n");
     311           0 :                         return CMD_WARNING_CONFIG_FAILED;
     312             :                 }
     313             : 
     314             : #if !defined(GNU_LINUX)
     315             : /* BSD systems
     316             :  */
     317             : #else
     318             :                 /* Linux Systems
     319             :                  */
     320           0 :                 if ((start >= RT_TABLE_ID_COMPAT && start <= RT_TABLE_ID_LOCAL)
     321           0 :                     || (end >= RT_TABLE_ID_COMPAT
     322           0 :                         && end <= RT_TABLE_ID_LOCAL)) {
     323           0 :                         vty_out(vty, "%% Values forbidden in range [%u;%u]\n",
     324             :                                 RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL);
     325           0 :                         return CMD_WARNING_CONFIG_FAILED;
     326             :                 }
     327           0 :                 if (start < RT_TABLE_ID_COMPAT && end > RT_TABLE_ID_LOCAL) {
     328           0 :                         vty_out(vty,
     329             :                                 "%% Range overlaps range [%u;%u] forbidden\n",
     330             :                                 RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL);
     331           0 :                         return CMD_WARNING_CONFIG_FAILED;
     332             :                 }
     333             : #endif
     334           0 :                 if (zvrf->tbl_mgr
     335           0 :                     && ((zvrf->tbl_mgr->start && zvrf->tbl_mgr->start != start)
     336           0 :                         || (zvrf->tbl_mgr->end && zvrf->tbl_mgr->end != end))) {
     337           0 :                         vty_out(vty,
     338             :                                 "%% New range will be taken into account at restart\n");
     339             :                 }
     340           0 :                 table_range_add(zvrf, start, end);
     341             :         } else
     342           0 :                 table_range_add(zvrf, 0, 0);
     343             :         return CMD_SUCCESS;
     344             : }

Generated by: LCOV version v1.16-topotato