File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / bgpd / bgp_dump.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

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

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