Annotation of embedaddon/quagga/bgpd/bgp_dump.c, revision 1.1.1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>