back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_dump.c (source / functions) Hit Total Coverage
Test: test_bgp_minimum_holdtime.py::TestBGPMinimumHoldtime Lines: 39 379 10.3 %
Date: 2023-02-24 18:37:25 Functions: 6 20 30.0 %

          Line data    Source code
       1             : /* BGP-4 dump routine
       2             :  * Copyright (C) 1999 Kunihiro Ishiguro
       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 "log.h"
      24             : #include "stream.h"
      25             : #include "sockunion.h"
      26             : #include "command.h"
      27             : #include "prefix.h"
      28             : #include "thread.h"
      29             : #include "linklist.h"
      30             : #include "queue.h"
      31             : #include "memory.h"
      32             : #include "filter.h"
      33             : 
      34             : #include "bgpd/bgp_table.h"
      35             : #include "bgpd/bgpd.h"
      36             : #include "bgpd/bgp_route.h"
      37             : #include "bgpd/bgp_attr.h"
      38             : #include "bgpd/bgp_dump.h"
      39             : #include "bgpd/bgp_errors.h"
      40             : #include "bgpd/bgp_packet.h"
      41             : 
      42             : enum bgp_dump_type {
      43             :         BGP_DUMP_ALL,
      44             :         BGP_DUMP_ALL_ET,
      45             :         BGP_DUMP_UPDATES,
      46             :         BGP_DUMP_UPDATES_ET,
      47             :         BGP_DUMP_ROUTES
      48             : };
      49             : 
      50             : static const struct bgp_dump_type_map {
      51             :         enum bgp_dump_type type;
      52             :         const char *str;
      53             : } bgp_dump_type_map[] = {
      54             :         {BGP_DUMP_ALL, "all"},                 {BGP_DUMP_ALL_ET, "all-et"},
      55             :         {BGP_DUMP_UPDATES, "updates"},   {BGP_DUMP_UPDATES_ET, "updates-et"},
      56             :         {BGP_DUMP_ROUTES, "routes-mrt"}, {0, NULL},
      57             : };
      58             : 
      59             : enum MRT_MSG_TYPES {
      60             :         MSG_NULL,
      61             :         MSG_START,                /* sender is starting up */
      62             :         MSG_DIE,                  /* receiver should shut down */
      63             :         MSG_I_AM_DEAD,            /* sender is shutting down */
      64             :         MSG_PEER_DOWN,            /* sender's peer is down */
      65             :         MSG_PROTOCOL_BGP,        /* msg is a BGP packet */
      66             :         MSG_PROTOCOL_RIP,        /* msg is a RIP packet */
      67             :         MSG_PROTOCOL_IDRP,      /* msg is an IDRP packet */
      68             :         MSG_PROTOCOL_RIPNG,       /* msg is a RIPNG packet */
      69             :         MSG_PROTOCOL_BGP4PLUS,    /* msg is a BGP4+ packet */
      70             :         MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
      71             :         MSG_PROTOCOL_OSPF,      /* msg is an OSPF packet */
      72             :         MSG_TABLE_DUMP,           /* routing table dump */
      73             :         MSG_TABLE_DUMP_V2        /* routing table dump, version 2 */
      74             : };
      75             : 
      76             : struct bgp_dump {
      77             :         enum bgp_dump_type type;
      78             : 
      79             :         char *filename;
      80             : 
      81             :         FILE *fp;
      82             : 
      83             :         unsigned int interval;
      84             : 
      85             :         char *interval_str;
      86             : 
      87             :         struct thread *t_interval;
      88             : };
      89             : 
      90             : static int bgp_dump_unset(struct bgp_dump *bgp_dump);
      91             : static void bgp_dump_interval_func(struct thread *);
      92             : 
      93             : /* BGP packet dump output buffer. */
      94             : struct stream *bgp_dump_obuf;
      95             : 
      96             : /* BGP dump strucuture for 'dump bgp all' */
      97             : struct bgp_dump bgp_dump_all;
      98             : 
      99             : /* BGP dump structure for 'dump bgp updates' */
     100             : struct bgp_dump bgp_dump_updates;
     101             : 
     102             : /* BGP dump structure for 'dump bgp routes' */
     103             : struct bgp_dump bgp_dump_routes;
     104             : 
     105           0 : static FILE *bgp_dump_open_file(struct bgp_dump *bgp_dump)
     106             : {
     107           0 :         int ret;
     108           0 :         time_t clock;
     109           0 :         struct tm tm;
     110           0 :         char fullpath[MAXPATHLEN];
     111           0 :         char realpath[MAXPATHLEN];
     112           0 :         mode_t oldumask;
     113             : 
     114           0 :         time(&clock);
     115           0 :         localtime_r(&clock, &tm);
     116             : 
     117           0 :         if (bgp_dump->filename[0] != DIRECTORY_SEP) {
     118           0 :                 snprintf(fullpath, sizeof(fullpath), "%s/%s", vty_get_cwd(),
     119             :                          bgp_dump->filename);
     120             : #pragma GCC diagnostic push
     121             : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
     122             :                 /* user supplied date/time format string */
     123           0 :                 ret = strftime(realpath, MAXPATHLEN, fullpath, &tm);
     124             :         } else
     125           0 :                 ret = strftime(realpath, MAXPATHLEN, bgp_dump->filename, &tm);
     126             : #pragma GCC diagnostic pop
     127             : 
     128           0 :         if (ret == 0) {
     129           0 :                 flog_warn(EC_BGP_DUMP, "%s: strftime error", __func__);
     130           0 :                 return NULL;
     131             :         }
     132             : 
     133           0 :         if (bgp_dump->fp)
     134           0 :                 fclose(bgp_dump->fp);
     135             : 
     136             : 
     137           0 :         oldumask = umask(0777 & ~LOGFILE_MASK);
     138           0 :         bgp_dump->fp = fopen(realpath, "w");
     139             : 
     140           0 :         if (bgp_dump->fp == NULL) {
     141           0 :                 flog_warn(EC_BGP_DUMP, "%s: %s: %s", __func__, realpath,
     142             :                           strerror(errno));
     143           0 :                 umask(oldumask);
     144           0 :                 return NULL;
     145             :         }
     146           0 :         umask(oldumask);
     147             : 
     148           0 :         return bgp_dump->fp;
     149             : }
     150             : 
     151           0 : static int bgp_dump_interval_add(struct bgp_dump *bgp_dump, int interval)
     152             : {
     153           0 :         int secs_into_day;
     154           0 :         time_t t;
     155           0 :         struct tm tm;
     156             : 
     157           0 :         if (interval > 0) {
     158             :                 /* Periodic dump every interval seconds */
     159           0 :                 if ((interval < 86400) && ((86400 % interval) == 0)) {
     160             :                         /* Dump at predictable times: if a day has a whole
     161             :                          * number of
     162             :                          * intervals, dump every interval seconds starting from
     163             :                          * midnight
     164             :                          */
     165           0 :                         (void)time(&t);
     166           0 :                         localtime_r(&t, &tm);
     167           0 :                         secs_into_day = tm.tm_sec + 60 * tm.tm_min
     168           0 :                                         + 60 * 60 * tm.tm_hour;
     169           0 :                         interval = interval
     170           0 :                                    - secs_into_day % interval; /* always > 0 */
     171             :                 }
     172           0 :                 thread_add_timer(bm->master, bgp_dump_interval_func, bgp_dump,
     173             :                                  interval, &bgp_dump->t_interval);
     174             :         } else {
     175             :                 /* One-off dump: execute immediately, don't affect any scheduled
     176             :                  * dumps */
     177           0 :                 thread_add_event(bm->master, bgp_dump_interval_func, bgp_dump,
     178             :                                  0, &bgp_dump->t_interval);
     179             :         }
     180             : 
     181           0 :         return 0;
     182             : }
     183             : 
     184             : /* Dump common header. */
     185           0 : static void bgp_dump_header(struct stream *obuf, int type, int subtype,
     186             :                             int dump_type)
     187             : {
     188           0 :         struct timeval clock;
     189           0 :         long msecs;
     190           0 :         time_t secs;
     191             : 
     192           0 :         if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET)
     193           0 :             && type == MSG_PROTOCOL_BGP4MP)
     194           0 :                 type = MSG_PROTOCOL_BGP4MP_ET;
     195             : 
     196           0 :         gettimeofday(&clock, NULL);
     197             : 
     198           0 :         secs = clock.tv_sec;
     199           0 :         msecs = clock.tv_usec;
     200             : 
     201             :         /* Put dump packet header. */
     202           0 :         stream_putl(obuf, secs);
     203           0 :         stream_putw(obuf, type);
     204           0 :         stream_putw(obuf, subtype);
     205           0 :         stream_putl(obuf, 0); /* len */
     206             : 
     207             :         /* Adding microseconds for the MRT Extended Header */
     208           0 :         if (type == MSG_PROTOCOL_BGP4MP_ET)
     209           0 :                 stream_putl(obuf, msecs);
     210           0 : }
     211             : 
     212           0 : static void bgp_dump_set_size(struct stream *s, int type)
     213             : {
     214             :         /*
     215             :          * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
     216             :          * "The Microsecond Timestamp is included in the computation
     217             :          *  of the Length field value." (RFC6396 2011)
     218             :          */
     219           0 :         stream_putl_at(s, 8, stream_get_endp(s) - BGP_DUMP_HEADER_SIZE);
     220           0 : }
     221             : 
     222           0 : static void bgp_dump_routes_index_table(struct bgp *bgp)
     223             : {
     224           0 :         struct peer *peer;
     225           0 :         struct listnode *node;
     226           0 :         uint16_t peerno = 1;
     227           0 :         struct stream *obuf;
     228             : 
     229           0 :         obuf = bgp_dump_obuf;
     230           0 :         stream_reset(obuf);
     231             : 
     232             :         /* MRT header */
     233           0 :         bgp_dump_header(obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE,
     234             :                         BGP_DUMP_ROUTES);
     235             : 
     236             :         /* Collector BGP ID */
     237           0 :         stream_put_in_addr(obuf, &bgp->router_id);
     238             : 
     239             :         /* View name */
     240           0 :         if (bgp->name_pretty) {
     241           0 :                 stream_putw(obuf, strlen(bgp->name_pretty));
     242           0 :                 stream_put(obuf, bgp->name_pretty, strlen(bgp->name_pretty));
     243             :         } else {
     244           0 :                 stream_putw(obuf, 0);
     245             :         }
     246             : 
     247             :         /* Peer count ( plus one extra internal peer ) */
     248           0 :         stream_putw(obuf, listcount(bgp->peer) + 1);
     249             : 
     250             :         /* Populate fake peer at index 0, for locally originated routes */
     251             :         /* Peer type (IPv4) */
     252           0 :         stream_putc(obuf,
     253             :                     TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
     254             :                             + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
     255             :         /* Peer BGP ID (0.0.0.0) */
     256           0 :         stream_putl(obuf, 0);
     257             :         /* Peer IP address (0.0.0.0) */
     258           0 :         stream_putl(obuf, 0);
     259             :         /* Peer ASN (0) */
     260           0 :         stream_putl(obuf, 0);
     261             : 
     262             :         /* Walk down all peers */
     263           0 :         for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
     264             : 
     265             :                 /* Peer's type */
     266           0 :                 if (sockunion_family(&peer->su) == AF_INET) {
     267           0 :                         stream_putc(
     268             :                                 obuf,
     269             :                                 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
     270             :                                         + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
     271           0 :                 } else if (sockunion_family(&peer->su) == AF_INET6) {
     272           0 :                         stream_putc(
     273             :                                 obuf,
     274             :                                 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
     275             :                                         + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
     276             :                 }
     277             : 
     278             :                 /* Peer's BGP ID */
     279           0 :                 stream_put_in_addr(obuf, &peer->remote_id);
     280             : 
     281             :                 /* Peer's IP address */
     282           0 :                 if (sockunion_family(&peer->su) == AF_INET) {
     283           0 :                         stream_put_in_addr(obuf, &peer->su.sin.sin_addr);
     284           0 :                 } else if (sockunion_family(&peer->su) == AF_INET6) {
     285           0 :                         stream_write(obuf, (uint8_t *)&peer->su.sin6.sin6_addr,
     286             :                                      IPV6_MAX_BYTELEN);
     287             :                 }
     288             : 
     289             :                 /* Peer's AS number. */
     290             :                 /* Note that, as this is an AS4 compliant quagga, the RIB is
     291             :                  * always AS4 */
     292           0 :                 stream_putl(obuf, peer->as);
     293             : 
     294             :                 /* Store the peer number for this peer */
     295           0 :                 peer->table_dump_index = peerno;
     296           0 :                 peerno++;
     297             :         }
     298             : 
     299           0 :         bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
     300             : 
     301           0 :         fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
     302           0 :         fflush(bgp_dump_routes.fp);
     303           0 : }
     304             : 
     305             : static struct bgp_path_info *
     306           0 : bgp_dump_route_node_record(int afi, struct bgp_dest *dest,
     307             :                            struct bgp_path_info *path, unsigned int seq)
     308             : {
     309           0 :         struct stream *obuf;
     310           0 :         size_t sizep;
     311           0 :         size_t endp;
     312           0 :         bool addpath_capable;
     313           0 :         const struct prefix *p = bgp_dest_get_prefix(dest);
     314             : 
     315           0 :         obuf = bgp_dump_obuf;
     316           0 :         stream_reset(obuf);
     317             : 
     318           0 :         addpath_capable = bgp_addpath_encode_rx(path->peer, afi, SAFI_UNICAST);
     319             : 
     320             :         /* MRT header */
     321           0 :         if (afi == AFI_IP && addpath_capable)
     322           0 :                 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
     323             :                                 TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH,
     324             :                                 BGP_DUMP_ROUTES);
     325           0 :         else if (afi == AFI_IP)
     326           0 :                 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
     327             :                                 TABLE_DUMP_V2_RIB_IPV4_UNICAST,
     328             :                                 BGP_DUMP_ROUTES);
     329           0 :         else if (afi == AFI_IP6 && addpath_capable)
     330           0 :                 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
     331             :                                 TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH,
     332             :                                 BGP_DUMP_ROUTES);
     333           0 :         else if (afi == AFI_IP6)
     334           0 :                 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
     335             :                                 TABLE_DUMP_V2_RIB_IPV6_UNICAST,
     336             :                                 BGP_DUMP_ROUTES);
     337             : 
     338             :         /* Sequence number */
     339           0 :         stream_putl(obuf, seq);
     340             : 
     341             :         /* Prefix length */
     342           0 :         stream_putc(obuf, p->prefixlen);
     343             : 
     344             :         /* Prefix */
     345           0 :         if (afi == AFI_IP) {
     346             :                 /* We'll dump only the useful bits (those not 0), but have to
     347             :                  * align on 8 bits */
     348           0 :                 stream_write(obuf, (uint8_t *)&p->u.prefix4,
     349           0 :                              (p->prefixlen + 7) / 8);
     350           0 :         } else if (afi == AFI_IP6) {
     351             :                 /* We'll dump only the useful bits (those not 0), but have to
     352             :                  * align on 8 bits */
     353           0 :                 stream_write(obuf, (uint8_t *)&p->u.prefix6,
     354           0 :                              (p->prefixlen + 7) / 8);
     355             :         }
     356             : 
     357             :         /* Save where we are now, so we can overwride the entry count later */
     358           0 :         sizep = stream_get_endp(obuf);
     359             : 
     360             :         /* Entry count */
     361           0 :         uint16_t entry_count = 0;
     362             : 
     363             :         /* Entry count, note that this is overwritten later */
     364           0 :         stream_putw(obuf, 0);
     365             : 
     366           0 :         endp = stream_get_endp(obuf);
     367           0 :         for (; path; path = path->next) {
     368           0 :                 size_t cur_endp;
     369             : 
     370             :                 /* Peer index */
     371           0 :                 stream_putw(obuf, path->peer->table_dump_index);
     372             : 
     373             :                 /* Originated */
     374           0 :                 stream_putl(obuf, time(NULL) - (monotime(NULL) - path->uptime));
     375             : 
     376             :                 /*Path Identifier*/
     377           0 :                 if (addpath_capable) {
     378           0 :                         stream_putl(obuf, path->addpath_rx_id);
     379             :                 }
     380             : 
     381             :                 /* Dump attribute. */
     382             :                 /* Skip prefix & AFI/SAFI for MP_NLRI */
     383           0 :                 bgp_dump_routes_attr(obuf, path, p);
     384             : 
     385           0 :                 cur_endp = stream_get_endp(obuf);
     386           0 :                 if (cur_endp > BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
     387             :                                        + BGP_DUMP_MSG_HEADER
     388             :                                        + BGP_DUMP_HEADER_SIZE) {
     389           0 :                         stream_set_endp(obuf, endp);
     390           0 :                         break;
     391             :                 }
     392             : 
     393           0 :                 entry_count++;
     394           0 :                 endp = cur_endp;
     395             :         }
     396             : 
     397             :         /* Overwrite the entry count, now that we know the right number */
     398           0 :         stream_putw_at(obuf, sizep, entry_count);
     399             : 
     400           0 :         bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
     401           0 :         fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
     402             : 
     403           0 :         return path;
     404             : }
     405             : 
     406             : 
     407             : /* Runs under child process. */
     408           0 : static unsigned int bgp_dump_routes_func(int afi, int first_run,
     409             :                                          unsigned int seq)
     410             : {
     411           0 :         struct bgp_path_info *path;
     412           0 :         struct bgp_dest *dest;
     413           0 :         struct bgp *bgp;
     414           0 :         struct bgp_table *table;
     415             : 
     416           0 :         bgp = bgp_get_default();
     417           0 :         if (!bgp)
     418             :                 return seq;
     419             : 
     420           0 :         if (bgp_dump_routes.fp == NULL)
     421             :                 return seq;
     422             : 
     423             :         /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
     424             :            so this should only be done on the first call to
     425             :            bgp_dump_routes_func.
     426             :            ( this function will be called once for ipv4 and once for ipv6 ) */
     427           0 :         if (first_run)
     428           0 :                 bgp_dump_routes_index_table(bgp);
     429             : 
     430             :         /* Walk down each BGP route. */
     431           0 :         table = bgp->rib[afi][SAFI_UNICAST];
     432             : 
     433           0 :         for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
     434           0 :                 path = bgp_dest_get_bgp_path_info(dest);
     435           0 :                 while (path) {
     436           0 :                         path = bgp_dump_route_node_record(afi, dest, path, seq);
     437           0 :                         seq++;
     438             :                 }
     439             :         }
     440             : 
     441           0 :         fflush(bgp_dump_routes.fp);
     442             : 
     443           0 :         return seq;
     444             : }
     445             : 
     446           0 : static void bgp_dump_interval_func(struct thread *t)
     447             : {
     448           0 :         struct bgp_dump *bgp_dump;
     449           0 :         bgp_dump = THREAD_ARG(t);
     450             : 
     451             :         /* Reschedule dump even if file couldn't be opened this time... */
     452           0 :         if (bgp_dump_open_file(bgp_dump) != NULL) {
     453             :                 /* In case of bgp_dump_routes, we need special route dump
     454             :                  * function. */
     455           0 :                 if (bgp_dump->type == BGP_DUMP_ROUTES) {
     456           0 :                         unsigned int seq = bgp_dump_routes_func(AFI_IP, 1, 0);
     457           0 :                         bgp_dump_routes_func(AFI_IP6, 0, seq);
     458             :                         /* Close the file now. For a RIB dump there's no point
     459             :                          * in leaving
     460             :                          * it open until the next scheduled dump starts. */
     461           0 :                         fclose(bgp_dump->fp);
     462           0 :                         bgp_dump->fp = NULL;
     463             :                 }
     464             :         }
     465             : 
     466             :         /* if interval is set reschedule */
     467           0 :         if (bgp_dump->interval > 0)
     468           0 :                 bgp_dump_interval_add(bgp_dump, bgp_dump->interval);
     469           0 : }
     470             : 
     471             : /* Dump common information. */
     472           0 : static void bgp_dump_common(struct stream *obuf, struct peer *peer,
     473             :                             int forceas4)
     474             : {
     475           0 :         char empty[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     476             : 
     477             :         /* Source AS number and Destination AS number. */
     478           0 :         if (forceas4 || CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
     479           0 :                 stream_putl(obuf, peer->as);
     480           0 :                 stream_putl(obuf, peer->local_as);
     481             :         } else {
     482           0 :                 stream_putw(obuf, peer->as);
     483           0 :                 stream_putw(obuf, peer->local_as);
     484             :         }
     485             : 
     486           0 :         if (peer->su.sa.sa_family == AF_INET) {
     487           0 :                 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
     488           0 :                 stream_putw(obuf, AFI_IP);
     489             : 
     490           0 :                 stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
     491             : 
     492           0 :                 if (peer->su_local)
     493           0 :                         stream_put(obuf, &peer->su_local->sin.sin_addr,
     494             :                                    IPV4_MAX_BYTELEN);
     495             :                 else
     496           0 :                         stream_put(obuf, empty, IPV4_MAX_BYTELEN);
     497           0 :         } else if (peer->su.sa.sa_family == AF_INET6) {
     498             :                 /* Interface Index and Address family. */
     499           0 :                 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
     500           0 :                 stream_putw(obuf, AFI_IP6);
     501             : 
     502             :                 /* Source IP Address and Destination IP Address. */
     503           0 :                 stream_put(obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
     504             : 
     505           0 :                 if (peer->su_local)
     506           0 :                         stream_put(obuf, &peer->su_local->sin6.sin6_addr,
     507             :                                    IPV6_MAX_BYTELEN);
     508             :                 else
     509           0 :                         stream_put(obuf, empty, IPV6_MAX_BYTELEN);
     510             :         }
     511           0 : }
     512             : 
     513             : /* Dump BGP status change. */
     514          13 : int bgp_dump_state(struct peer *peer)
     515             : {
     516          13 :         struct stream *obuf;
     517             : 
     518             :         /* If dump file pointer is disabled return immediately. */
     519          13 :         if (bgp_dump_all.fp == NULL)
     520             :                 return 0;
     521             : 
     522             :         /* Make dump stream. */
     523           0 :         obuf = bgp_dump_obuf;
     524           0 :         stream_reset(obuf);
     525             : 
     526           0 :         bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
     527           0 :                         bgp_dump_all.type);
     528           0 :         bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/
     529             : 
     530           0 :         stream_putw(obuf, peer->ostatus);
     531           0 :         stream_putw(obuf, peer->status);
     532             : 
     533             :         /* Set length. */
     534           0 :         bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
     535             : 
     536             :         /* Write to the stream. */
     537           0 :         fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_all.fp);
     538           0 :         fflush(bgp_dump_all.fp);
     539           0 :         return 0;
     540             : }
     541             : 
     542           3 : static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
     543             :                                  struct stream *packet)
     544             : {
     545           3 :         struct stream *obuf;
     546           3 :         bool addpath_capable = false;
     547             :         /* If dump file pointer is disabled return immediately. */
     548           3 :         if (bgp_dump->fp == NULL)
     549             :                 return;
     550           0 :         if (peer->su.sa.sa_family == AF_INET) {
     551           0 :                 addpath_capable =
     552           0 :                         bgp_addpath_encode_rx(peer, AFI_IP, SAFI_UNICAST);
     553           0 :         } else if (peer->su.sa.sa_family == AF_INET6) {
     554           0 :                 addpath_capable =
     555           0 :                         bgp_addpath_encode_rx(peer, AFI_IP6, SAFI_UNICAST);
     556             :         }
     557             : 
     558             :         /* Make dump stream. */
     559           0 :         obuf = bgp_dump_obuf;
     560           0 :         stream_reset(obuf);
     561             : 
     562             :         /* Dump header and common part. */
     563           0 :         if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) && addpath_capable) {
     564           0 :                 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP,
     565           0 :                                 BGP4MP_MESSAGE_AS4_ADDPATH, bgp_dump->type);
     566           0 :         } else if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
     567           0 :                 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
     568           0 :                                 bgp_dump->type);
     569           0 :         } else if (addpath_capable) {
     570           0 :                 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP,
     571           0 :                                 BGP4MP_MESSAGE_ADDPATH, bgp_dump->type);
     572             :         } else {
     573           0 :                 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
     574           0 :                                 bgp_dump->type);
     575             :         }
     576           0 :         bgp_dump_common(obuf, peer, 0);
     577             : 
     578             :         /* Packet contents. */
     579           0 :         stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
     580             : 
     581             :         /* Set length. */
     582           0 :         bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
     583             : 
     584             :         /* Write to the stream. */
     585           0 :         fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
     586           0 :         fflush(bgp_dump->fp);
     587             : }
     588             : 
     589             : /* Called from bgp_packet.c when BGP packet is received. */
     590           3 : static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
     591             :                 struct stream *packet)
     592             : {
     593             :         /* bgp_dump_all. */
     594           3 :         bgp_dump_packet_func(&bgp_dump_all, peer, packet);
     595             : 
     596             :         /* bgp_dump_updates. */
     597           3 :         if (type == BGP_MSG_UPDATE)
     598           0 :                 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
     599           3 :         return 0;
     600             : }
     601             : 
     602           0 : static unsigned int bgp_dump_parse_time(const char *str)
     603             : {
     604           0 :         int i;
     605           0 :         int len;
     606           0 :         int seen_h;
     607           0 :         int seen_m;
     608           0 :         int time;
     609           0 :         unsigned int total;
     610             : 
     611           0 :         time = 0;
     612           0 :         total = 0;
     613           0 :         seen_h = 0;
     614           0 :         seen_m = 0;
     615           0 :         len = strlen(str);
     616             : 
     617           0 :         for (i = 0; i < len; i++) {
     618           0 :                 if (isdigit((unsigned char)str[i])) {
     619           0 :                         time *= 10;
     620           0 :                         time += str[i] - '0';
     621           0 :                 } else if (str[i] == 'H' || str[i] == 'h') {
     622           0 :                         if (seen_h)
     623             :                                 return 0;
     624           0 :                         if (seen_m)
     625             :                                 return 0;
     626           0 :                         total += time * 60 * 60;
     627           0 :                         time = 0;
     628           0 :                         seen_h = 1;
     629           0 :                 } else if (str[i] == 'M' || str[i] == 'm') {
     630           0 :                         if (seen_m)
     631             :                                 return 0;
     632           0 :                         total += time * 60;
     633           0 :                         time = 0;
     634           0 :                         seen_m = 1;
     635             :                 } else
     636             :                         return 0;
     637             :         }
     638           0 :         return total + time;
     639             : }
     640             : 
     641           0 : static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
     642             :                         enum bgp_dump_type type, const char *path,
     643             :                         const char *interval_str)
     644             : {
     645           0 :         unsigned int interval;
     646             : 
     647             :         /* Don't schedule duplicate dumps if the dump command is given twice */
     648           0 :         if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
     649           0 :             && type == bgp_dump->type) {
     650           0 :                 if (interval_str) {
     651           0 :                         if (bgp_dump->interval_str
     652           0 :                             && strcmp(bgp_dump->interval_str, interval_str)
     653             :                                        == 0)
     654             :                                 return CMD_SUCCESS;
     655             :                 } else {
     656           0 :                         if (!bgp_dump->interval_str)
     657             :                                 return CMD_SUCCESS;
     658             :                 }
     659             :         }
     660             : 
     661             :         /* Removing previous config */
     662           0 :         bgp_dump_unset(bgp_dump);
     663             : 
     664           0 :         if (interval_str) {
     665             :                 /* Check interval string. */
     666           0 :                 interval = bgp_dump_parse_time(interval_str);
     667           0 :                 if (interval == 0) {
     668           0 :                         vty_out(vty, "Malformed interval string\n");
     669           0 :                         return CMD_WARNING_CONFIG_FAILED;
     670             :                 }
     671             : 
     672             :                 /* Setting interval string */
     673           0 :                 bgp_dump->interval_str =
     674           0 :                         XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
     675             :         } else {
     676             :                 interval = 0;
     677             :         }
     678             : 
     679             :         /* Set type. */
     680           0 :         bgp_dump->type = type;
     681             : 
     682             :         /* Set interval */
     683           0 :         bgp_dump->interval = interval;
     684             : 
     685             :         /* Set file name. */
     686           0 :         bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
     687             : 
     688             :         /* Create interval thread. */
     689           0 :         bgp_dump_interval_add(bgp_dump, interval);
     690             : 
     691             :         /* This should be called when interval is expired. */
     692           0 :         bgp_dump_open_file(bgp_dump);
     693             : 
     694           0 :         return CMD_SUCCESS;
     695             : }
     696             : 
     697           6 : static int bgp_dump_unset(struct bgp_dump *bgp_dump)
     698             : {
     699             :         /* Removing file name. */
     700           6 :         XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
     701             : 
     702             :         /* Closing file. */
     703           6 :         if (bgp_dump->fp) {
     704           0 :                 fclose(bgp_dump->fp);
     705           0 :                 bgp_dump->fp = NULL;
     706             :         }
     707             : 
     708             :         /* Removing interval event. */
     709           6 :         THREAD_OFF(bgp_dump->t_interval);
     710             : 
     711           6 :         bgp_dump->interval = 0;
     712             : 
     713             :         /* Removing interval string. */
     714           6 :         XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
     715             : 
     716           6 :         return CMD_SUCCESS;
     717             : }
     718             : 
     719           0 : DEFUN (dump_bgp_all,
     720             :        dump_bgp_all_cmd,
     721             :        "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
     722             :        "Dump packet\n"
     723             :        "BGP packet dump\n"
     724             :        "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
     725             :        "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
     726             :        "Dump whole BGP routing table\n"
     727             :        "Output filename\n"
     728             :        "Interval of output\n")
     729             : {
     730           0 :         int idx_dump_routes = 2;
     731           0 :         int idx_path = 3;
     732           0 :         int idx_interval = 4;
     733           0 :         int bgp_dump_type = 0;
     734           0 :         const char *interval = NULL;
     735           0 :         struct bgp_dump *bgp_dump_struct = NULL;
     736           0 :         const struct bgp_dump_type_map *map = NULL;
     737             : 
     738           0 :         for (map = bgp_dump_type_map; map->str; map++)
     739           0 :                 if (strmatch(argv[idx_dump_routes]->text, map->str))
     740           0 :                         bgp_dump_type = map->type;
     741             : 
     742           0 :         switch (bgp_dump_type) {
     743             :         case BGP_DUMP_ALL:
     744             :         case BGP_DUMP_ALL_ET:
     745             :                 bgp_dump_struct = &bgp_dump_all;
     746             :                 break;
     747           0 :         case BGP_DUMP_UPDATES:
     748             :         case BGP_DUMP_UPDATES_ET:
     749           0 :                 bgp_dump_struct = &bgp_dump_updates;
     750           0 :                 break;
     751           0 :         case BGP_DUMP_ROUTES:
     752             :         default:
     753           0 :                 bgp_dump_struct = &bgp_dump_routes;
     754           0 :                 break;
     755             :         }
     756             : 
     757             :         /* When an interval is given */
     758           0 :         if (argc == idx_interval + 1)
     759           0 :                 interval = argv[idx_interval]->arg;
     760             : 
     761           0 :         return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
     762           0 :                             argv[idx_path]->arg, interval);
     763             : }
     764             : 
     765           0 : DEFUN (no_dump_bgp_all,
     766             :        no_dump_bgp_all_cmd,
     767             :        "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
     768             :        NO_STR
     769             :        "Stop dump packet\n"
     770             :        "Stop BGP packet dump\n"
     771             :        "Stop dump process all\n"
     772             :        "Stop dump process all-et\n"
     773             :        "Stop dump process updates\n"
     774             :        "Stop dump process updates-et\n"
     775             :        "Stop dump process route-mrt\n"
     776             :        "Output filename\n"
     777             :        "Interval of output\n")
     778             : {
     779           0 :         int idx_dump_routes = 3;
     780           0 :         int bgp_dump_type = 0;
     781           0 :         const struct bgp_dump_type_map *map = NULL;
     782           0 :         struct bgp_dump *bgp_dump_struct = NULL;
     783             : 
     784           0 :         for (map = bgp_dump_type_map; map->str; map++)
     785           0 :                 if (strmatch(argv[idx_dump_routes]->text, map->str))
     786           0 :                         bgp_dump_type = map->type;
     787             : 
     788           0 :         switch (bgp_dump_type) {
     789             :         case BGP_DUMP_ALL:
     790             :         case BGP_DUMP_ALL_ET:
     791             :                 bgp_dump_struct = &bgp_dump_all;
     792             :                 break;
     793           0 :         case BGP_DUMP_UPDATES:
     794             :         case BGP_DUMP_UPDATES_ET:
     795           0 :                 bgp_dump_struct = &bgp_dump_updates;
     796           0 :                 break;
     797           0 :         case BGP_DUMP_ROUTES:
     798             :         default:
     799           0 :                 bgp_dump_struct = &bgp_dump_routes;
     800           0 :                 break;
     801             :         }
     802             : 
     803           0 :         return bgp_dump_unset(bgp_dump_struct);
     804             : }
     805             : 
     806             : static int config_write_bgp_dump(struct vty *vty);
     807             : /* BGP node structure. */
     808             : static struct cmd_node bgp_dump_node = {
     809             :         .name = "dump",
     810             :         .node = DUMP_NODE,
     811             :         .prompt = "",
     812             :         .config_write = config_write_bgp_dump,
     813             : };
     814             : 
     815           0 : static int config_write_bgp_dump(struct vty *vty)
     816             : {
     817           0 :         if (bgp_dump_all.filename) {
     818           0 :                 const char *type_str = "all";
     819           0 :                 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
     820           0 :                         type_str = "all-et";
     821             : 
     822           0 :                 if (bgp_dump_all.interval_str)
     823           0 :                         vty_out(vty, "dump bgp %s %s %s\n", type_str,
     824             :                                 bgp_dump_all.filename,
     825             :                                 bgp_dump_all.interval_str);
     826             :                 else
     827           0 :                         vty_out(vty, "dump bgp %s %s\n", type_str,
     828             :                                 bgp_dump_all.filename);
     829             :         }
     830           0 :         if (bgp_dump_updates.filename) {
     831           0 :                 const char *type_str = "updates";
     832           0 :                 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
     833           0 :                         type_str = "updates-et";
     834             : 
     835           0 :                 if (bgp_dump_updates.interval_str)
     836           0 :                         vty_out(vty, "dump bgp %s %s %s\n", type_str,
     837             :                                 bgp_dump_updates.filename,
     838             :                                 bgp_dump_updates.interval_str);
     839             :                 else
     840           0 :                         vty_out(vty, "dump bgp %s %s\n", type_str,
     841             :                                 bgp_dump_updates.filename);
     842             :         }
     843           0 :         if (bgp_dump_routes.filename) {
     844           0 :                 if (bgp_dump_routes.interval_str)
     845           0 :                         vty_out(vty, "dump bgp routes-mrt %s %s\n",
     846             :                                 bgp_dump_routes.filename,
     847             :                                 bgp_dump_routes.interval_str);
     848             :                 else
     849           0 :                         vty_out(vty, "dump bgp routes-mrt %s\n",
     850             :                                 bgp_dump_routes.filename);
     851             :         }
     852           0 :         return 0;
     853             : }
     854             : 
     855             : /* Initialize BGP packet dump functionality. */
     856           2 : void bgp_dump_init(void)
     857             : {
     858           2 :         memset(&bgp_dump_all, 0, sizeof(bgp_dump_all));
     859           2 :         memset(&bgp_dump_updates, 0, sizeof(bgp_dump_updates));
     860           2 :         memset(&bgp_dump_routes, 0, sizeof(bgp_dump_routes));
     861             : 
     862           4 :         bgp_dump_obuf =
     863           2 :                 stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE * 2)
     864             :                            + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
     865             : 
     866           2 :         install_node(&bgp_dump_node);
     867             : 
     868           2 :         install_element(CONFIG_NODE, &dump_bgp_all_cmd);
     869           2 :         install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
     870             : 
     871           2 :         hook_register(bgp_packet_dump, bgp_dump_packet);
     872           2 :         hook_register(peer_status_changed, bgp_dump_state);
     873           2 : }
     874             : 
     875           2 : void bgp_dump_finish(void)
     876             : {
     877           2 :         bgp_dump_unset(&bgp_dump_all);
     878           2 :         bgp_dump_unset(&bgp_dump_updates);
     879           2 :         bgp_dump_unset(&bgp_dump_routes);
     880             : 
     881           2 :         stream_free(bgp_dump_obuf);
     882           2 :         bgp_dump_obuf = NULL;
     883           2 :         hook_unregister(bgp_packet_dump, bgp_dump_packet);
     884           2 :         hook_unregister(peer_status_changed, bgp_dump_state);
     885           2 : }

Generated by: LCOV version v1.16-topotato