2 * Copyright (C) 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
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
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.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "sockunion.h"
34 #include "bgpd/bgp_table.h"
35 #include "bgpd/bgpd.h"
36 #include "bgpd/bgp_route.h"
37 #include "bgpd/bgp_attr.h"
38 #include "bgpd/bgp_dump.h"
39 #include "bgpd/bgp_errors.h"
49 static const struct bgp_dump_type_map
{
50 enum bgp_dump_type type
;
52 } bgp_dump_type_map
[] = {
53 {BGP_DUMP_ALL
, "all"}, {BGP_DUMP_ALL_ET
, "all-et"},
54 {BGP_DUMP_UPDATES
, "updates"}, {BGP_DUMP_UPDATES_ET
, "updates-et"},
55 {BGP_DUMP_ROUTES
, "routes-mrt"}, {0, NULL
},
60 MSG_START
, /* sender is starting up */
61 MSG_DIE
, /* receiver should shut down */
62 MSG_I_AM_DEAD
, /* sender is shutting down */
63 MSG_PEER_DOWN
, /* sender's peer is down */
64 MSG_PROTOCOL_BGP
, /* msg is a BGP packet */
65 MSG_PROTOCOL_RIP
, /* msg is a RIP packet */
66 MSG_PROTOCOL_IDRP
, /* msg is an IDRP packet */
67 MSG_PROTOCOL_RIPNG
, /* msg is a RIPNG packet */
68 MSG_PROTOCOL_BGP4PLUS
, /* msg is a BGP4+ packet */
69 MSG_PROTOCOL_BGP4PLUS_01
, /* msg is a BGP4+ (draft 01) packet */
70 MSG_PROTOCOL_OSPF
, /* msg is an OSPF packet */
71 MSG_TABLE_DUMP
, /* routing table dump */
72 MSG_TABLE_DUMP_V2
/* routing table dump, version 2 */
76 enum bgp_dump_type type
;
82 unsigned int interval
;
86 struct thread
*t_interval
;
89 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
);
90 static int bgp_dump_interval_func(struct thread
*);
92 /* BGP packet dump output buffer. */
93 struct stream
*bgp_dump_obuf
;
95 /* BGP dump strucuture for 'dump bgp all' */
96 struct bgp_dump bgp_dump_all
;
98 /* BGP dump structure for 'dump bgp updates' */
99 struct bgp_dump bgp_dump_updates
;
101 /* BGP dump structure for 'dump bgp routes' */
102 struct bgp_dump bgp_dump_routes
;
104 static FILE *bgp_dump_open_file(struct bgp_dump
*bgp_dump
)
109 char fullpath
[MAXPATHLEN
];
110 char realpath
[MAXPATHLEN
];
114 tm
= localtime(&clock
);
116 if (bgp_dump
->filename
[0] != DIRECTORY_SEP
) {
117 sprintf(fullpath
, "%s/%s", vty_get_cwd(), bgp_dump
->filename
);
118 ret
= strftime(realpath
, MAXPATHLEN
, fullpath
, tm
);
120 ret
= strftime(realpath
, MAXPATHLEN
, bgp_dump
->filename
, tm
);
123 flog_warn(EC_BGP_DUMP
, "bgp_dump_open_file: strftime error");
128 fclose(bgp_dump
->fp
);
131 oldumask
= umask(0777 & ~LOGFILE_MASK
);
132 bgp_dump
->fp
= fopen(realpath
, "w");
134 if (bgp_dump
->fp
== NULL
) {
135 flog_warn(EC_BGP_DUMP
, "bgp_dump_open_file: %s: %s", realpath
,
145 static int bgp_dump_interval_add(struct bgp_dump
*bgp_dump
, int interval
)
152 /* Periodic dump every interval seconds */
153 if ((interval
< 86400) && ((86400 % interval
) == 0)) {
154 /* Dump at predictable times: if a day has a whole
156 * intervals, dump every interval seconds starting from
161 secs_into_day
= tm
->tm_sec
+ 60 * tm
->tm_min
162 + 60 * 60 * tm
->tm_hour
;
164 - secs_into_day
% interval
; /* always > 0 */
166 bgp_dump
->t_interval
= NULL
;
167 thread_add_timer(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
168 interval
, &bgp_dump
->t_interval
);
170 /* One-off dump: execute immediately, don't affect any scheduled
172 bgp_dump
->t_interval
= NULL
;
173 thread_add_event(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
174 0, &bgp_dump
->t_interval
);
180 /* Dump common header. */
181 static void bgp_dump_header(struct stream
*obuf
, int type
, int subtype
,
184 struct timeval clock
;
188 if ((dump_type
== BGP_DUMP_ALL_ET
|| dump_type
== BGP_DUMP_UPDATES_ET
)
189 && type
== MSG_PROTOCOL_BGP4MP
)
190 type
= MSG_PROTOCOL_BGP4MP_ET
;
192 gettimeofday(&clock
, NULL
);
195 msecs
= clock
.tv_usec
;
197 /* Put dump packet header. */
198 stream_putl(obuf
, secs
);
199 stream_putw(obuf
, type
);
200 stream_putw(obuf
, subtype
);
201 stream_putl(obuf
, 0); /* len */
203 /* Adding microseconds for the MRT Extended Header */
204 if (type
== MSG_PROTOCOL_BGP4MP_ET
)
205 stream_putl(obuf
, msecs
);
208 static void bgp_dump_set_size(struct stream
*s
, int type
)
211 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
212 * "The Microsecond Timestamp is included in the computation
213 * of the Length field value." (RFC6396 2011)
215 stream_putl_at(s
, 8, stream_get_endp(s
) - BGP_DUMP_HEADER_SIZE
);
218 static void bgp_dump_routes_index_table(struct bgp
*bgp
)
221 struct listnode
*node
;
225 obuf
= bgp_dump_obuf
;
229 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_PEER_INDEX_TABLE
,
232 /* Collector BGP ID */
233 stream_put_in_addr(obuf
, &bgp
->router_id
);
237 stream_putw(obuf
, strlen(bgp
->name
));
238 stream_put(obuf
, bgp
->name
, strlen(bgp
->name
));
240 stream_putw(obuf
, 0);
243 /* Peer count ( plus one extra internal peer ) */
244 stream_putw(obuf
, listcount(bgp
->peer
) + 1);
246 /* Populate fake peer at index 0, for locally originated routes */
247 /* Peer type (IPv4) */
249 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
250 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
251 /* Peer BGP ID (0.0.0.0) */
252 stream_putl(obuf
, 0);
253 /* Peer IP address (0.0.0.0) */
254 stream_putl(obuf
, 0);
256 stream_putl(obuf
, 0);
258 /* Walk down all peers */
259 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
262 if (sockunion_family(&peer
->su
) == AF_INET
) {
265 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
266 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
267 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
270 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
271 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
275 stream_put_in_addr(obuf
, &peer
->remote_id
);
277 /* Peer's IP address */
278 if (sockunion_family(&peer
->su
) == AF_INET
) {
279 stream_put_in_addr(obuf
, &peer
->su
.sin
.sin_addr
);
280 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
281 stream_write(obuf
, (uint8_t *)&peer
->su
.sin6
.sin6_addr
,
285 /* Peer's AS number. */
286 /* Note that, as this is an AS4 compliant quagga, the RIB is
288 stream_putl(obuf
, peer
->as
);
290 /* Store the peer number for this peer */
291 peer
->table_dump_index
= peerno
;
295 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
297 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
298 fflush(bgp_dump_routes
.fp
);
302 static struct bgp_path_info
*
303 bgp_dump_route_node_record(int afi
, struct bgp_node
*rn
,
304 struct bgp_path_info
*path
, unsigned int seq
)
310 obuf
= bgp_dump_obuf
;
315 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
316 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
318 else if (afi
== AFI_IP6
)
319 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
320 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
323 /* Sequence number */
324 stream_putl(obuf
, seq
);
327 stream_putc(obuf
, rn
->p
.prefixlen
);
331 /* We'll dump only the useful bits (those not 0), but have to
333 stream_write(obuf
, (uint8_t *)&rn
->p
.u
.prefix4
,
334 (rn
->p
.prefixlen
+ 7) / 8);
335 } else if (afi
== AFI_IP6
) {
336 /* We'll dump only the useful bits (those not 0), but have to
338 stream_write(obuf
, (uint8_t *)&rn
->p
.u
.prefix6
,
339 (rn
->p
.prefixlen
+ 7) / 8);
342 /* Save where we are now, so we can overwride the entry count later */
343 sizep
= stream_get_endp(obuf
);
346 uint16_t entry_count
= 0;
348 /* Entry count, note that this is overwritten later */
349 stream_putw(obuf
, 0);
351 endp
= stream_get_endp(obuf
);
352 for (; path
; path
= path
->next
) {
356 stream_putw(obuf
, path
->peer
->table_dump_index
);
359 stream_putl(obuf
, time(NULL
) - (bgp_clock() - path
->uptime
));
361 /* Dump attribute. */
362 /* Skip prefix & AFI/SAFI for MP_NLRI */
363 bgp_dump_routes_attr(obuf
, path
->attr
, &rn
->p
);
365 cur_endp
= stream_get_endp(obuf
);
366 if (cur_endp
> BGP_MAX_PACKET_SIZE
+ BGP_DUMP_MSG_HEADER
367 + BGP_DUMP_HEADER_SIZE
) {
368 stream_set_endp(obuf
, endp
);
376 /* Overwrite the entry count, now that we know the right number */
377 stream_putw_at(obuf
, sizep
, entry_count
);
379 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
380 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
386 /* Runs under child process. */
387 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
390 struct bgp_path_info
*path
;
393 struct bgp_table
*table
;
395 bgp
= bgp_get_default();
399 if (bgp_dump_routes
.fp
== NULL
)
402 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
403 so this should only be done on the first call to
404 bgp_dump_routes_func.
405 ( this function will be called once for ipv4 and once for ipv6 ) */
407 bgp_dump_routes_index_table(bgp
);
409 /* Walk down each BGP route. */
410 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
412 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
415 path
= bgp_dump_route_node_record(afi
, rn
, path
, seq
);
420 fflush(bgp_dump_routes
.fp
);
425 static int bgp_dump_interval_func(struct thread
*t
)
427 struct bgp_dump
*bgp_dump
;
428 bgp_dump
= THREAD_ARG(t
);
429 bgp_dump
->t_interval
= NULL
;
431 /* Reschedule dump even if file couldn't be opened this time... */
432 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
433 /* In case of bgp_dump_routes, we need special route dump
435 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
436 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
437 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
438 /* Close the file now. For a RIB dump there's no point
440 * it open until the next scheduled dump starts. */
441 fclose(bgp_dump
->fp
);
446 /* if interval is set reschedule */
447 if (bgp_dump
->interval
> 0)
448 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
453 /* Dump common information. */
454 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
457 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
459 /* Source AS number and Destination AS number. */
460 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
461 stream_putl(obuf
, peer
->as
);
462 stream_putl(obuf
, peer
->local_as
);
464 stream_putw(obuf
, peer
->as
);
465 stream_putw(obuf
, peer
->local_as
);
468 if (peer
->su
.sa
.sa_family
== AF_INET
) {
469 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
470 stream_putw(obuf
, AFI_IP
);
472 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
475 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
478 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
479 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
480 /* Interface Index and Address family. */
481 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
482 stream_putw(obuf
, AFI_IP6
);
484 /* Source IP Address and Destination IP Address. */
485 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
488 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
491 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
495 /* Dump BGP status change. */
496 void bgp_dump_state(struct peer
*peer
, int status_old
, int status_new
)
500 /* If dump file pointer is disabled return immediately. */
501 if (bgp_dump_all
.fp
== NULL
)
504 /* Make dump stream. */
505 obuf
= bgp_dump_obuf
;
508 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
510 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
512 stream_putw(obuf
, status_old
);
513 stream_putw(obuf
, status_new
);
516 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
518 /* Write to the stream. */
519 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
520 fflush(bgp_dump_all
.fp
);
523 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
524 struct stream
*packet
)
528 /* If dump file pointer is disabled return immediately. */
529 if (bgp_dump
->fp
== NULL
)
532 /* Make dump stream. */
533 obuf
= bgp_dump_obuf
;
536 /* Dump header and common part. */
537 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
538 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
541 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
544 bgp_dump_common(obuf
, peer
, 0);
546 /* Packet contents. */
547 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
550 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
552 /* Write to the stream. */
553 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
554 fflush(bgp_dump
->fp
);
557 /* Called from bgp_packet.c when BGP packet is received. */
558 void bgp_dump_packet(struct peer
*peer
, int type
, struct stream
*packet
)
561 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
563 /* bgp_dump_updates. */
564 if (type
== BGP_MSG_UPDATE
)
565 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
568 static unsigned int bgp_dump_parse_time(const char *str
)
583 for (i
= 0; i
< len
; i
++) {
584 if (isdigit((int)str
[i
])) {
586 time
+= str
[i
] - '0';
587 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
592 total
+= time
* 60 * 60;
595 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
607 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
608 enum bgp_dump_type type
, const char *path
,
609 const char *interval_str
)
611 unsigned int interval
;
613 /* Don't schedule duplicate dumps if the dump command is given twice */
614 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
615 && type
== bgp_dump
->type
) {
617 if (bgp_dump
->interval_str
618 && strcmp(bgp_dump
->interval_str
, interval_str
)
622 if (!bgp_dump
->interval_str
)
627 /* Removing previous config */
628 bgp_dump_unset(bgp_dump
);
631 /* Check interval string. */
632 interval
= bgp_dump_parse_time(interval_str
);
634 vty_out(vty
, "Malformed interval string\n");
635 return CMD_WARNING_CONFIG_FAILED
;
638 /* Setting interval string */
639 bgp_dump
->interval_str
=
640 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
646 bgp_dump
->type
= type
;
649 bgp_dump
->interval
= interval
;
652 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
654 /* Create interval thread. */
655 bgp_dump_interval_add(bgp_dump
, interval
);
657 /* This should be called when interval is expired. */
658 bgp_dump_open_file(bgp_dump
);
663 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
665 /* Removing file name. */
666 if (bgp_dump
->filename
) {
667 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
668 bgp_dump
->filename
= NULL
;
673 fclose(bgp_dump
->fp
);
677 /* Removing interval thread. */
678 if (bgp_dump
->t_interval
) {
679 thread_cancel(bgp_dump
->t_interval
);
680 bgp_dump
->t_interval
= NULL
;
683 bgp_dump
->interval
= 0;
685 /* Removing interval string. */
686 if (bgp_dump
->interval_str
) {
687 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
688 bgp_dump
->interval_str
= NULL
;
696 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
699 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
700 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
701 "Dump whole BGP routing table\n"
703 "Interval of output\n")
705 int idx_dump_routes
= 2;
707 int idx_interval
= 4;
708 int bgp_dump_type
= 0;
709 const char *interval
= NULL
;
710 struct bgp_dump
*bgp_dump_struct
= NULL
;
711 const struct bgp_dump_type_map
*map
= NULL
;
713 for (map
= bgp_dump_type_map
; map
->str
; map
++)
714 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
715 bgp_dump_type
= map
->type
;
717 switch (bgp_dump_type
) {
719 case BGP_DUMP_ALL_ET
:
720 bgp_dump_struct
= &bgp_dump_all
;
722 case BGP_DUMP_UPDATES
:
723 case BGP_DUMP_UPDATES_ET
:
724 bgp_dump_struct
= &bgp_dump_updates
;
726 case BGP_DUMP_ROUTES
:
728 bgp_dump_struct
= &bgp_dump_routes
;
732 /* When an interval is given */
733 if (argc
== idx_interval
+ 1)
734 interval
= argv
[idx_interval
]->arg
;
736 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
737 argv
[idx_path
]->arg
, interval
);
740 DEFUN (no_dump_bgp_all
,
742 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
745 "Stop BGP packet dump\n"
746 "Stop dump process all\n"
747 "Stop dump process all-et\n"
748 "Stop dump process updates\n"
749 "Stop dump process updates-et\n"
750 "Stop dump process route-mrt\n"
752 "Interval of output\n")
754 int idx_dump_routes
= 3;
755 int bgp_dump_type
= 0;
756 const struct bgp_dump_type_map
*map
= NULL
;
757 struct bgp_dump
*bgp_dump_struct
= NULL
;
759 for (map
= bgp_dump_type_map
; map
->str
; map
++)
760 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
761 bgp_dump_type
= map
->type
;
763 switch (bgp_dump_type
) {
765 case BGP_DUMP_ALL_ET
:
766 bgp_dump_struct
= &bgp_dump_all
;
768 case BGP_DUMP_UPDATES
:
769 case BGP_DUMP_UPDATES_ET
:
770 bgp_dump_struct
= &bgp_dump_updates
;
772 case BGP_DUMP_ROUTES
:
774 bgp_dump_struct
= &bgp_dump_routes
;
778 return bgp_dump_unset(bgp_dump_struct
);
781 /* BGP node structure. */
782 static struct cmd_node bgp_dump_node
= {DUMP_NODE
, "", 1};
786 config_time2str (unsigned int interval
)
788 static char buf
[BUFSIZ
];
794 sprintf (buf
, "%dh", interval
/ 3600);
799 sprintf (buf
+ strlen (buf
), "%dm", interval
/60);
804 sprintf (buf
+ strlen (buf
), "%d", interval
);
810 static int config_write_bgp_dump(struct vty
*vty
)
812 if (bgp_dump_all
.filename
) {
813 const char *type_str
= "all";
814 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
817 if (bgp_dump_all
.interval_str
)
818 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
819 bgp_dump_all
.filename
,
820 bgp_dump_all
.interval_str
);
822 vty_out(vty
, "dump bgp %s %s\n", type_str
,
823 bgp_dump_all
.filename
);
825 if (bgp_dump_updates
.filename
) {
826 const char *type_str
= "updates";
827 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
828 type_str
= "updates-et";
830 if (bgp_dump_updates
.interval_str
)
831 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
832 bgp_dump_updates
.filename
,
833 bgp_dump_updates
.interval_str
);
835 vty_out(vty
, "dump bgp %s %s\n", type_str
,
836 bgp_dump_updates
.filename
);
838 if (bgp_dump_routes
.filename
) {
839 if (bgp_dump_routes
.interval_str
)
840 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
841 bgp_dump_routes
.filename
,
842 bgp_dump_routes
.interval_str
);
844 vty_out(vty
, "dump bgp routes-mrt %s\n",
845 bgp_dump_routes
.filename
);
850 /* Initialize BGP packet dump functionality. */
851 void bgp_dump_init(void)
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
));
858 stream_new((BGP_MAX_PACKET_SIZE
<< 1) + BGP_DUMP_MSG_HEADER
859 + BGP_DUMP_HEADER_SIZE
);
861 install_node(&bgp_dump_node
, config_write_bgp_dump
);
863 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
864 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
867 void bgp_dump_finish(void)
869 bgp_dump_unset(&bgp_dump_all
);
870 bgp_dump_unset(&bgp_dump_updates
);
871 bgp_dump_unset(&bgp_dump_routes
);
873 stream_free(bgp_dump_obuf
);
874 bgp_dump_obuf
= NULL
;