Annotation of embedaddon/quagga/bgpd/bgp_dump.c, revision 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>