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

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

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