]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_dump.c
lib, bgpd: Remove 'struct fifo' from lib/zebra.h
[mirror_frr.git] / bgpd / bgp_dump.c
index e3c628149e9216d2ec364d5efd00d5427ac9eef4..e219d5248ebbe706a929b5130f995af6832b4314 100644 (file)
@@ -26,20 +26,39 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "command.h"
 #include "prefix.h"
 #include "thread.h"
-#include "bgpd/bgp_table.h"
+#include "linklist.h"
+#include "queue.h"
+#include "memory.h"
+#include "filter.h"
 
+#include "bgpd/bgp_table.h"
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_route.h"
 #include "bgpd/bgp_attr.h"
 #include "bgpd/bgp_dump.h"
-\f
+
 enum bgp_dump_type
 {
   BGP_DUMP_ALL,
+  BGP_DUMP_ALL_ET,
   BGP_DUMP_UPDATES,
+  BGP_DUMP_UPDATES_ET,
   BGP_DUMP_ROUTES
 };
 
+static const struct bgp_dump_type_map {
+  enum bgp_dump_type type;
+  const char *str;
+} bgp_dump_type_map[] =
+  {
+    {BGP_DUMP_ALL, "all"},
+    {BGP_DUMP_ALL_ET, "all-et"},
+    {BGP_DUMP_UPDATES, "updates"},
+    {BGP_DUMP_UPDATES_ET, "updates-et"},
+    {BGP_DUMP_ROUTES, "routes-mrt"},
+    {0, NULL},
+  };
+
 enum MRT_MSG_TYPES {
    MSG_NULL,
    MSG_START,                   /* sender is starting up */
@@ -53,7 +72,8 @@ enum MRT_MSG_TYPES {
    MSG_PROTOCOL_BGP4PLUS,       /* msg is a BGP4+ packet */
    MSG_PROTOCOL_BGP4PLUS_01,    /* msg is a BGP4+ (draft 01) packet */
    MSG_PROTOCOL_OSPF,           /* msg is an OSPF packet */
-   MSG_TABLE_DUMP               /* routing table dump */
+   MSG_TABLE_DUMP,              /* routing table dump */
+   MSG_TABLE_DUMP_V2            /* routing table dump, version 2 */
 };
 
 struct bgp_dump
@@ -71,6 +91,9 @@ struct bgp_dump
   struct thread *t_interval;
 };
 
+static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump);
+static int bgp_dump_interval_func (struct thread *);
+
 /* BGP packet dump output buffer. */
 struct stream *bgp_dump_obuf;
 
@@ -83,11 +106,7 @@ struct bgp_dump bgp_dump_updates;
 /* BGP dump structure for 'dump bgp routes' */
 struct bgp_dump bgp_dump_routes;
 
-/* Dump whole BGP table is very heavy process.  */
-struct thread *t_bgp_dump_routes;
-\f
-/* Some define for BGP packet dump. */
-FILE *
+static FILE *
 bgp_dump_open_file (struct bgp_dump *bgp_dump)
 {
   int ret;
@@ -95,6 +114,7 @@ bgp_dump_open_file (struct bgp_dump *bgp_dump)
   struct tm *tm;
   char fullpath[MAXPATHLEN];
   char realpath[MAXPATHLEN];
+  mode_t oldumask;
 
   time (&clock);
   tm = localtime (&clock);
@@ -117,42 +137,47 @@ bgp_dump_open_file (struct bgp_dump *bgp_dump)
     fclose (bgp_dump->fp);
 
 
+  oldumask = umask(0777 & ~LOGFILE_MASK);
   bgp_dump->fp = fopen (realpath, "w");
 
   if (bgp_dump->fp == NULL)
-    return NULL;
+    {
+      zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno));
+      umask(oldumask);
+      return NULL;
+    }
+  umask(oldumask);  
 
   return bgp_dump->fp;
 }
 
-int
+static int
 bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
 {
-  int bgp_dump_interval_func (struct thread *);
-  int interval2, secs_into_day;
+  int secs_into_day;
   time_t t;
   struct tm *tm;
 
-  if (interval > 0 )
+  if (interval > 0)
     {
+      /* Periodic dump every interval seconds */
       if ((interval < 86400) && ((86400 % interval) == 0))
        {
+         /* Dump at predictable times: if a day has a whole number of
+          * intervals, dump every interval seconds starting from midnight
+          */
          (void) time(&t);
          tm = localtime(&t);
          secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour;
-         interval2 = interval - secs_into_day % interval;
-         if(interval2 == 0) interval2 = interval;
+         interval = interval - secs_into_day % interval; /* always > 0 */
        }
-      else
-       {
-         interval2 = interval;
-       }
-      bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func, 
-                                              bgp_dump, interval2);
+      bgp_dump->t_interval = thread_add_timer (bm->master, bgp_dump_interval_func,
+                                              bgp_dump, interval);
     }
   else
     {
-      bgp_dump->t_interval = thread_add_event (master, bgp_dump_interval_func,
+      /* One-off dump: execute immediately, don't affect any scheduled dumps */
+      bgp_dump->t_interval = thread_add_event (bm->master, bgp_dump_interval_func,
                                               bgp_dump, 0);
     }
 
@@ -160,163 +185,248 @@ bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
 }
 
 /* Dump common header. */
-void
-bgp_dump_header (struct stream *obuf, int type, int subtype)
+static void
+bgp_dump_header (struct stream *obuf, int type, int subtype, int dump_type)
 {
-  time_t now;
+  struct timeval clock;
+  long msecs;
+  time_t secs;
+
+  if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET)
+      && type == MSG_PROTOCOL_BGP4MP)
+    type = MSG_PROTOCOL_BGP4MP_ET;
 
-  /* Set header. */
-  time (&now);
+  gettimeofday(&clock, NULL);
+
+  secs = clock.tv_sec;
+  msecs = clock.tv_usec;
 
   /* Put dump packet header. */
-  stream_putl (obuf, now);     
+  stream_putl (obuf, secs);
   stream_putw (obuf, type);
   stream_putw (obuf, subtype);
-
   stream_putl (obuf, 0);       /* len */
+
+  /* Adding microseconds for the MRT Extended Header */
+  if (type == MSG_PROTOCOL_BGP4MP_ET)
+    stream_putl (obuf, msecs);
 }
 
-void
+static void
 bgp_dump_set_size (struct stream *s, int type)
 {
-  stream_putl_at (s, 8, stream_get_putp (s) - BGP_DUMP_HEADER_SIZE);
+  /*
+   * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
+   * "The Microsecond Timestamp is included in the computation
+   *  of the Length field value." (RFC6396 2011)
+   */
+  stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
 }
 
-void
-bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi,
-                      int type, unsigned int seq)
+static void
+bgp_dump_routes_index_table(struct bgp *bgp)
 {
-  struct stream *obuf;
-  struct attr *attr;
   struct peer *peer;
-  int plen;
-  int safi = 0;
+  struct listnode *node;
+  uint16_t peerno = 0;
+  struct stream *obuf;
 
-  /* Make dump stream. */
   obuf = bgp_dump_obuf;
   stream_reset (obuf);
 
-  attr = info->attr;
-  peer = info->peer;
+  /* MRT header */
+  bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE,
+                  BGP_DUMP_ROUTES);
+
+  /* Collector BGP ID */
+  stream_put_in_addr (obuf, &bgp->router_id);
 
-  /* We support MRT's old format. */
-  if (type == MSG_TABLE_DUMP)
+  /* View name */
+  if(bgp->name)
     {
-      bgp_dump_header (obuf, MSG_TABLE_DUMP, afi);
-      stream_putw (obuf, 0);   /* View # */
-      stream_putw (obuf, seq); /* Sequence number. */
+      stream_putw (obuf, strlen(bgp->name));
+      stream_put(obuf, bgp->name, strlen(bgp->name));
     }
   else
     {
-      bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY);
-      
-      stream_putl (obuf, info->uptime); /* Time Last Change */
-      stream_putw (obuf, afi); /* Address Family */
-      stream_putc (obuf, safi);        /* SAFI */
+      stream_putw(obuf, 0);
     }
 
-  if (afi == AFI_IP)
+  /* Peer count */
+  stream_putw (obuf, listcount(bgp->peer));
+
+  /* Walk down all peers */
+  for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
     {
-      if (type == MSG_TABLE_DUMP)
-       {
-         /* Prefix */
-         stream_put_in_addr (obuf, &p->u.prefix4);
-         stream_putc (obuf, p->prefixlen);
 
-         /* Status */
-         stream_putc (obuf, 1);
+      /* Peer's type */
+      if (sockunion_family(&peer->su) == AF_INET)
+        {
+          stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
+        }
+      else if (sockunion_family(&peer->su) == AF_INET6)
+        {
+          stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
+        }
+
+      /* Peer's BGP ID */
+      stream_put_in_addr (obuf, &peer->remote_id);
+
+      /* Peer's IP address */
+      if (sockunion_family(&peer->su) == AF_INET)
+        {
+          stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
+        }
+      else if (sockunion_family(&peer->su) == AF_INET6)
+        {
+          stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
+                        IPV6_MAX_BYTELEN);
+        }
+
+      /* Peer's AS number. */
+      /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
+      stream_putl (obuf, peer->as);
+
+      /* Store the peer number for this peer */
+      peer->table_dump_index = peerno;
+      peerno++;
+    }
 
-         /* Originated */
-         stream_putl (obuf, info->uptime);
+  bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
 
-         /* Peer's IP address */
-         stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
+  fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
+  fflush (bgp_dump_routes.fp);
+}
 
-         /* Peer's AS number. */
-         stream_putw (obuf, peer->as);
 
-         /* Dump attribute. */
-         bgp_dump_routes_attr (obuf, attr, NULL);
-       }
-      else
-       {
-         /* Next-Hop-Len */
-         stream_putc (obuf, IPV4_MAX_BYTELEN);
-         stream_put_in_addr (obuf, &attr->nexthop);
-         stream_putc (obuf, p->prefixlen);
-         plen = PSIZE (p->prefixlen);
-         stream_put (obuf, &p->u.prefix4, plen);
-         bgp_dump_routes_attr (obuf, attr, NULL);
-       }
+static struct bgp_info *
+bgp_dump_route_node_record (int afi, struct bgp_node *rn,
+                           struct bgp_info *info, unsigned int seq)
+{
+  struct stream *obuf;
+  size_t sizep;
+  size_t endp;
+
+  obuf = bgp_dump_obuf;
+  stream_reset (obuf);
+
+  /* MRT header */
+  if (afi == AFI_IP)
+    bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST,
+                     BGP_DUMP_ROUTES);
+  else if (afi == AFI_IP6)
+    bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST,
+                     BGP_DUMP_ROUTES);
+
+  /* Sequence number */
+  stream_putl (obuf, seq);
+
+  /* Prefix length */
+  stream_putc (obuf, rn->p.prefixlen);
+
+  /* Prefix */
+  if (afi == AFI_IP)
+    {
+      /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
+      stream_write (obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
     }
-#ifdef HAVE_IPV6
   else if (afi == AFI_IP6)
     {
-      if (type == MSG_TABLE_DUMP)
-       {
-         /* Prefix */
-         stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN);
-         stream_putc (obuf, p->prefixlen);
+      /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
+      stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
+    }
 
-         /* Status */
-         stream_putc (obuf, 1);
+  /* Save where we are now, so we can overwride the entry count later */
+  sizep = stream_get_endp (obuf);
 
-         /* Originated */
-         stream_putl (obuf, info->uptime);
+  /* Entry count */
+  uint16_t entry_count = 0;
 
-         /* Peer's IP address */
-         stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
-                       IPV6_MAX_BYTELEN);
+  /* Entry count, note that this is overwritten later */
+  stream_putw (obuf, 0);
 
-         /* Peer's AS number. */
-         stream_putw (obuf, peer->as);
+  endp = stream_get_endp (obuf);
+  for (; info; info = info->next)
+  {
+    size_t cur_endp;
 
-         /* Dump attribute. */
-         bgp_dump_routes_attr (obuf, attr, p);
-       }
-      else
-       {
-         ;
-       }
+    /* Peer index */
+    stream_putw (obuf, info->peer->table_dump_index);
+
+    /* Originated */
+#ifdef HAVE_CLOCK_MONOTONIC
+    stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
+#else
+    stream_putl (obuf, info->uptime);
+#endif /* HAVE_CLOCK_MONOTONIC */
+
+    /* Dump attribute. */
+    /* Skip prefix & AFI/SAFI for MP_NLRI */
+    bgp_dump_routes_attr (obuf, info->attr, &rn->p);
+
+    cur_endp = stream_get_endp (obuf);
+    if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
+                   + BGP_DUMP_HEADER_SIZE)
+    {
+      stream_set_endp (obuf, endp);
+      break;
     }
-#endif /* HAVE_IPV6 */
 
-  /* Set length. */
-  bgp_dump_set_size (obuf, type);
+    entry_count++;
+    endp = cur_endp;
+  }
 
-  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_routes.fp);
-  fflush (bgp_dump_routes.fp);
+  /* Overwrite the entry count, now that we know the right number */
+  stream_putw_at (obuf, sizep, entry_count);
+
+  bgp_dump_set_size (obuf, MSG_TABLE_DUMP_V2);
+  fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
+
+  return info;
 }
 
+
 /* Runs under child process. */
-void
-bgp_dump_routes_func (int afi)
+static unsigned int
+bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
 {
-  struct stream *obuf;
-  struct bgp_node *rn;
   struct bgp_info *info;
+  struct bgp_node *rn;
   struct bgp *bgp;
   struct bgp_table *table;
-  unsigned int seq = 0;
-
-  obuf = bgp_dump_obuf;
 
   bgp = bgp_get_default ();
   if (!bgp)
-    return;
+    return seq;
 
   if (bgp_dump_routes.fp == NULL)
-    return;
+    return seq;
+
+  /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
+     so this should only be done on the first call to bgp_dump_routes_func.
+     ( this function will be called once for ipv4 and once for ipv6 ) */
+  if (first_run)
+    bgp_dump_routes_index_table(bgp);
 
   /* Walk down each BGP route. */
   table = bgp->rib[afi][SAFI_UNICAST];
 
   for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
-    for (info = rn->info; info; info = info->next)
-      bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++);
+    {
+      info = rn->info;
+      while (info)
+      {
+        info = bgp_dump_route_node_record (afi, rn, info, seq);
+        seq++;
+      }
+    }
+
+  fflush (bgp_dump_routes.fp);
+
+  return seq;
 }
 
-int
+static int
 bgp_dump_interval_func (struct thread *t)
 {
   struct bgp_dump *bgp_dump;
@@ -329,10 +439,8 @@ bgp_dump_interval_func (struct thread *t)
       /* In case of bgp_dump_routes, we need special route dump function. */
       if (bgp_dump->type == BGP_DUMP_ROUTES)
        {
-         bgp_dump_routes_func (AFI_IP);
-#ifdef HAVE_IPV6
-         bgp_dump_routes_func (AFI_IP6);
-#endif /* HAVE_IPV6 */
+         unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
+         bgp_dump_routes_func (AFI_IP6, 0, seq);
          /* Close the file now. For a RIB dump there's no point in leaving
           * it open until the next scheduled dump starts. */
          fclose(bgp_dump->fp); bgp_dump->fp = NULL;
@@ -347,14 +455,22 @@ bgp_dump_interval_func (struct thread *t)
 }
 
 /* Dump common information. */
-void
-bgp_dump_common (struct stream *obuf, struct peer *peer)
+static void
+bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
 {
   char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
   /* Source AS number and Destination AS number. */
-  stream_putw (obuf, peer->as);
-  stream_putw (obuf, peer->local_as);
+  if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
+    {
+      stream_putl (obuf, peer->as);
+      stream_putl (obuf, peer->local_as);
+    }
+  else
+    {
+      stream_putw (obuf, peer->as);
+      stream_putw (obuf, peer->local_as);
+    }
 
   if (peer->su.sa.sa_family == AF_INET)
     {
@@ -368,7 +484,6 @@ bgp_dump_common (struct stream *obuf, struct peer *peer)
       else
        stream_put (obuf, empty, IPV4_MAX_BYTELEN);
     }
-#ifdef HAVE_IPV6
   else if (peer->su.sa.sa_family == AF_INET6)
     {
       /* Interface Index and Address family. */
@@ -383,7 +498,6 @@ bgp_dump_common (struct stream *obuf, struct peer *peer)
       else
        stream_put (obuf, empty, IPV6_MAX_BYTELEN);
     }
-#endif /* HAVE_IPV6 */
 }
 
 /* Dump BGP status change. */
@@ -400,8 +514,9 @@ bgp_dump_state (struct peer *peer, int status_old, int status_new)
   obuf = bgp_dump_obuf;
   stream_reset (obuf);
 
-  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE);
-  bgp_dump_common (obuf, peer);
+  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
+                  bgp_dump_all.type);
+  bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
 
   stream_putw (obuf, status_old);
   stream_putw (obuf, status_new);
@@ -410,11 +525,11 @@ bgp_dump_state (struct peer *peer, int status_old, int status_new)
   bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
 
   /* Write to the stream. */
-  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_all.fp);
+  fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
   fflush (bgp_dump_all.fp);
 }
 
-void
+static void
 bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
                      struct stream *packet)
 {
@@ -429,8 +544,17 @@ bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
   stream_reset (obuf);
 
   /* Dump header and common part. */
-  bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
-  bgp_dump_common (obuf, peer);
+  if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
+    { 
+      bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
+                      bgp_dump->type);
+    }
+  else
+    {
+      bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
+                      bgp_dump->type);
+    }
+  bgp_dump_common (obuf, peer, 0);
 
   /* Packet contents. */
   stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
@@ -439,7 +563,7 @@ bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
   bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
 
   /* Write to the stream. */
-  fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump->fp);
+  fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
   fflush (bgp_dump->fp);
 }
 
@@ -454,9 +578,9 @@ bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
   if (type == BGP_MSG_UPDATE)
     bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
 }
-\f
-unsigned int
-bgp_dump_parse_time (char *str)
+
+static unsigned int
+bgp_dump_parse_time (const char *str)
 {
   int i;
   int len;
@@ -502,15 +626,35 @@ bgp_dump_parse_time (char *str)
   return total + time;
 }
 
-int
-bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type,
-             char *path, char *interval_str)
+static int
+bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
+              enum bgp_dump_type type, const char *path,
+              const char *interval_str)
 {
   unsigned int interval;
   
+  /* Don't schedule duplicate dumps if the dump command is given twice */
+  if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
+      && type == bgp_dump->type)
+    {
+      if (interval_str)
+       {
+          if (bgp_dump->interval_str &&
+             strcmp(bgp_dump->interval_str, interval_str) == 0)
+            return CMD_SUCCESS;
+        }
+      else
+        {
+          if (!bgp_dump->interval_str)
+            return CMD_SUCCESS;
+        }
+    }
+
+  /* Removing previous config */
+  bgp_dump_unset(vty, bgp_dump);
+
   if (interval_str)
     {
-      
       /* Check interval string. */
       interval = bgp_dump_parse_time (interval_str);
       if (interval == 0)
@@ -518,28 +662,26 @@ bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type,
          vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
          return CMD_WARNING;
        }
-      /* Set interval. */
-      bgp_dump->interval = interval;
-      if (bgp_dump->interval_str)
-       free (bgp_dump->interval_str);
-      bgp_dump->interval_str = strdup (interval_str);
-      
+
+      /* Setting interval string */
+      bgp_dump->interval_str = XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
     }
   else
     {
       interval = 0;
     }
-    
-  /* Create interval thread. */
-  bgp_dump_interval_add (bgp_dump, interval);
 
   /* Set type. */
   bgp_dump->type = type;
 
+  /* Set interval */
+  bgp_dump->interval = interval;
+
   /* Set file name. */
-  if (bgp_dump->filename)
-    free (bgp_dump->filename);
-  bgp_dump->filename = strdup (path);
+  bgp_dump->filename = XSTRDUP (MTYPE_BGP_DUMP_STR, path);
+
+  /* Create interval thread. */
+  bgp_dump_interval_add (bgp_dump, interval);
 
   /* This should be called when interval is expired. */
   bgp_dump_open_file (bgp_dump);
@@ -547,24 +689,24 @@ bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type,
   return CMD_SUCCESS;
 }
 
-int
+static int
 bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
 {
-  /* Set file name. */
+  /* Removing file name. */
   if (bgp_dump->filename)
     {
-      free (bgp_dump->filename);
+      XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
       bgp_dump->filename = NULL;
     }
 
-  /* This should be called when interval is expired. */
+  /* Closing file. */
   if (bgp_dump->fp)
     {
       fclose (bgp_dump->fp);
       bgp_dump->fp = NULL;
     }
 
-  /* Create interval thread. */
+  /* Removing interval thread. */
   if (bgp_dump->t_interval)
     {
       thread_cancel (bgp_dump->t_interval);
@@ -573,123 +715,105 @@ bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
 
   bgp_dump->interval = 0;
 
+  /* Removing interval string. */
   if (bgp_dump->interval_str)
     {
-      free (bgp_dump->interval_str);
+      XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
       bgp_dump->interval_str = NULL;
     }
   
-
   return CMD_SUCCESS;
 }
 
 DEFUN (dump_bgp_all,
        dump_bgp_all_cmd,
-       "dump bgp all PATH",
-       "Dump packet\n"
-       "BGP packet dump\n"
-       "Dump all BGP packets\n"
-       "Output filename\n")
-{
-  return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
-}
-
-DEFUN (dump_bgp_all_interval,
-       dump_bgp_all_interval_cmd,
-       "dump bgp all PATH INTERVAL",
+       "dump bgp (all|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]",
        "Dump packet\n"
        "BGP packet dump\n"
-       "Dump all BGP packets\n"
+       "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
+       "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
+       "Dump whole BGP routing table\n"
        "Output filename\n"
        "Interval of output\n")
 {
-  return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
-}
+  int bgp_dump_type = 0;
+  const char *interval = NULL;
+  struct bgp_dump *bgp_dump_struct = NULL;
+  const struct bgp_dump_type_map *map = NULL;
 
-DEFUN (no_dump_bgp_all,
-       no_dump_bgp_all_cmd,
-       "no dump bgp all [PATH] [INTERVAL]",
-       NO_STR
-       "Dump packet\n"
-       "BGP packet dump\n"
-       "Dump all BGP packets\n")
-{
-  return bgp_dump_unset (vty, &bgp_dump_all);
-}
+  for (map = bgp_dump_type_map; map->str; map++)
+    if (strcmp(argv[0], map->str) == 0)
+      bgp_dump_type = map->type;
 
-DEFUN (dump_bgp_updates,
-       dump_bgp_updates_cmd,
-       "dump bgp updates PATH",
-       "Dump packet\n"
-       "BGP packet dump\n"
-       "Dump BGP updates only\n"
-       "Output filename\n")
-{
-  return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
-}
+  switch (bgp_dump_type)
+    {
+      case BGP_DUMP_ALL:
+      case BGP_DUMP_ALL_ET:
+        bgp_dump_struct = &bgp_dump_all;
+        break;
+      case BGP_DUMP_UPDATES:
+      case BGP_DUMP_UPDATES_ET:
+        bgp_dump_struct = &bgp_dump_updates;
+        break;
+      case BGP_DUMP_ROUTES:
+      default:
+        bgp_dump_struct = &bgp_dump_routes;
+        break;
+    }
 
-DEFUN (dump_bgp_updates_interval,
-       dump_bgp_updates_interval_cmd,
-       "dump bgp updates PATH INTERVAL",
-       "Dump packet\n"
-       "BGP packet dump\n"
-       "Dump BGP updates only\n"
-       "Output filename\n"
-       "Interval of output\n")
-{
-  return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
+  /* When an interval is given */
+  if (argc == 3)
+      interval = argv[2];
+
+  return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type,
+                       argv[1], interval);
 }
 
-DEFUN (no_dump_bgp_updates,
-       no_dump_bgp_updates_cmd,
-       "no dump bgp updates [PATH] [INTERVAL]",
+DEFUN (no_dump_bgp_all,
+       no_dump_bgp_all_cmd,
+       "no dump bgp (all|all-et|updates|updates-et|routes-mrt) [PATH] [INTERVAL]",
        NO_STR
-       "Dump packet\n"
-       "BGP packet dump\n"
-       "Dump BGP updates only\n")
+       "Stop dump packet\n"
+       "Stop BGP packet dump\n"
+       "Stop dump process all\n"
+       "Stop dump process all-et\n"
+       "Stop dump process updates\n"
+       "Stop dump process updates-et\n"
+       "Stop dump process route-mrt\n")
 {
-  return bgp_dump_unset (vty, &bgp_dump_updates);
-}
+  int bgp_dump_type = 0;
+  const struct bgp_dump_type_map *map = NULL;
+  struct bgp_dump *bgp_dump_struct = NULL;
 
-DEFUN (dump_bgp_routes,
-       dump_bgp_routes_cmd,
-       "dump bgp routes-mrt PATH",
-       "Dump packet\n"
-       "BGP packet dump\n"
-       "Dump whole BGP routing table\n"
-       "Output filename\n")
-{
-  return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
-}
+  for (map = bgp_dump_type_map; map->str; map++)
+    if (strcmp(argv[0], map->str) == 0)
+      bgp_dump_type = map->type;
 
-DEFUN (dump_bgp_routes_interval,
-       dump_bgp_routes_interval_cmd,
-       "dump bgp routes-mrt PATH INTERVAL",
-       "Dump packet\n"
-       "BGP packet dump\n"
-       "Dump whole BGP routing table\n"
-       "Output filename\n"
-       "Interval of output\n")
-{
-  return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
-}
+  switch (bgp_dump_type)
+    {
+    case BGP_DUMP_ALL:
+    case BGP_DUMP_ALL_ET:
+      bgp_dump_struct = &bgp_dump_all;
+      break;
+    case BGP_DUMP_UPDATES:
+    case BGP_DUMP_UPDATES_ET:
+      bgp_dump_struct = &bgp_dump_updates;
+      break;
+    case BGP_DUMP_ROUTES:
+    default:
+      bgp_dump_struct = &bgp_dump_routes;
+      break;
+    }
 
-DEFUN (no_dump_bgp_routes,
-       no_dump_bgp_routes_cmd,
-       "no dump bgp routes-mrt [PATH] [INTERVAL]",
-       NO_STR
-       "Dump packet\n"
-       "BGP packet dump\n"
-       "Dump whole BGP routing table\n")
-{
-  return bgp_dump_unset (vty, &bgp_dump_routes);
+  return bgp_dump_unset (vty, bgp_dump_struct);
 }
 
 /* BGP node structure. */
-struct cmd_node bgp_dump_node =
+static struct cmd_node bgp_dump_node =
 {
   DUMP_NODE,
   "",
+  1
 };
 
 #if 0
@@ -718,23 +842,31 @@ config_time2str (unsigned int interval)
 }
 #endif
 
-int
+static int
 config_write_bgp_dump (struct vty *vty)
 {
   if (bgp_dump_all.filename)
     {
+      const char *type_str = "all";
+      if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
+          type_str = "all-et";
+
       if (bgp_dump_all.interval_str)
-       vty_out (vty, "dump bgp all %s %s%s", 
+       vty_out (vty, "dump bgp %s %s %s%s", type_str,
                 bgp_dump_all.filename, bgp_dump_all.interval_str,
                 VTY_NEWLINE);
       else
-       vty_out (vty, "dump bgp all %s%s", 
+       vty_out (vty, "dump bgp %s %s%s", type_str,
                 bgp_dump_all.filename, VTY_NEWLINE);
     }
   if (bgp_dump_updates.filename)
     {
+      const char *type_str = "updates";
+      if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
+        type_str = "updates-et";
+
       if (bgp_dump_updates.interval_str)
-       vty_out (vty, "dump bgp updates %s %s%s", 
+       vty_out (vty, "dump bgp %s %s %s%s", type_str,
                 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
                 VTY_NEWLINE);
       else
@@ -747,33 +879,30 @@ config_write_bgp_dump (struct vty *vty)
        vty_out (vty, "dump bgp routes-mrt %s %s%s", 
                 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
                 VTY_NEWLINE);
-      else
-       vty_out (vty, "dump bgp routes-mrt %s%s", 
-                bgp_dump_routes.filename, VTY_NEWLINE);
     }
   return 0;
 }
-\f
+
 /* Initialize BGP packet dump functionality. */
 void
-bgp_dump_init ()
+bgp_dump_init (void)
 {
   memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
   memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
   memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
 
-  bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
-                              + BGP_DUMP_HEADER_SIZE);
+  bgp_dump_obuf = stream_new ((BGP_MAX_PACKET_SIZE << 1)
+                              + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
 
   install_node (&bgp_dump_node, config_write_bgp_dump);
 
   install_element (CONFIG_NODE, &dump_bgp_all_cmd);
-  install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd);
   install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
-  install_element (CONFIG_NODE, &dump_bgp_updates_cmd);
-  install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd);
-  install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd);
-  install_element (CONFIG_NODE, &dump_bgp_routes_cmd);
-  install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd);
-  install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd);
+}
+
+void
+bgp_dump_finish (void)
+{
+  stream_free (bgp_dump_obuf);
+  bgp_dump_obuf = NULL;
 }