#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 */
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
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;
/* 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;
struct tm *tm;
char fullpath[MAXPATHLEN];
char realpath[MAXPATHLEN];
+ mode_t oldumask;
time (&clock);
tm = localtime (&clock);
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);
}
}
/* 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;
/* 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;
}
/* 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)
{
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. */
else
stream_put (obuf, empty, IPV6_MAX_BYTELEN);
}
-#endif /* HAVE_IPV6 */
}
/* Dump BGP status change. */
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);
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)
{
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));
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);
}
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;
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)
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);
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);
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
}
#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
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;
}