File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / bgpd / bgp_dump.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

    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>