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"
40 #include "bgpd/bgp_packet.h"
50 static const struct bgp_dump_type_map
{
51 enum bgp_dump_type type
;
53 } bgp_dump_type_map
[] = {
54 {BGP_DUMP_ALL
, "all"}, {BGP_DUMP_ALL_ET
, "all-et"},
55 {BGP_DUMP_UPDATES
, "updates"}, {BGP_DUMP_UPDATES_ET
, "updates-et"},
56 {BGP_DUMP_ROUTES
, "routes-mrt"}, {0, NULL
},
61 MSG_START
, /* sender is starting up */
62 MSG_DIE
, /* receiver should shut down */
63 MSG_I_AM_DEAD
, /* sender is shutting down */
64 MSG_PEER_DOWN
, /* sender's peer is down */
65 MSG_PROTOCOL_BGP
, /* msg is a BGP packet */
66 MSG_PROTOCOL_RIP
, /* msg is a RIP packet */
67 MSG_PROTOCOL_IDRP
, /* msg is an IDRP packet */
68 MSG_PROTOCOL_RIPNG
, /* msg is a RIPNG packet */
69 MSG_PROTOCOL_BGP4PLUS
, /* msg is a BGP4+ packet */
70 MSG_PROTOCOL_BGP4PLUS_01
, /* msg is a BGP4+ (draft 01) packet */
71 MSG_PROTOCOL_OSPF
, /* msg is an OSPF packet */
72 MSG_TABLE_DUMP
, /* routing table dump */
73 MSG_TABLE_DUMP_V2
/* routing table dump, version 2 */
77 enum bgp_dump_type type
;
83 unsigned int interval
;
87 struct thread
*t_interval
;
90 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
);
91 static int bgp_dump_interval_func(struct thread
*);
93 /* BGP packet dump output buffer. */
94 struct stream
*bgp_dump_obuf
;
96 /* BGP dump strucuture for 'dump bgp all' */
97 struct bgp_dump bgp_dump_all
;
99 /* BGP dump structure for 'dump bgp updates' */
100 struct bgp_dump bgp_dump_updates
;
102 /* BGP dump structure for 'dump bgp routes' */
103 struct bgp_dump bgp_dump_routes
;
105 static FILE *bgp_dump_open_file(struct bgp_dump
*bgp_dump
)
110 char fullpath
[MAXPATHLEN
];
111 char realpath
[MAXPATHLEN
];
115 localtime_r(&clock
, &tm
);
117 if (bgp_dump
->filename
[0] != DIRECTORY_SEP
) {
118 snprintf(fullpath
, sizeof(fullpath
), "%s/%s", vty_get_cwd(),
120 ret
= strftime(realpath
, MAXPATHLEN
, fullpath
, &tm
);
122 ret
= strftime(realpath
, MAXPATHLEN
, bgp_dump
->filename
, &tm
);
125 flog_warn(EC_BGP_DUMP
, "bgp_dump_open_file: strftime error");
130 fclose(bgp_dump
->fp
);
133 oldumask
= umask(0777 & ~LOGFILE_MASK
);
134 bgp_dump
->fp
= fopen(realpath
, "w");
136 if (bgp_dump
->fp
== NULL
) {
137 flog_warn(EC_BGP_DUMP
, "bgp_dump_open_file: %s: %s", realpath
,
147 static int bgp_dump_interval_add(struct bgp_dump
*bgp_dump
, int interval
)
154 /* Periodic dump every interval seconds */
155 if ((interval
< 86400) && ((86400 % interval
) == 0)) {
156 /* Dump at predictable times: if a day has a whole
158 * intervals, dump every interval seconds starting from
162 localtime_r(&t
, &tm
);
163 secs_into_day
= tm
.tm_sec
+ 60 * tm
.tm_min
164 + 60 * 60 * tm
.tm_hour
;
166 - secs_into_day
% interval
; /* always > 0 */
168 bgp_dump
->t_interval
= NULL
;
169 thread_add_timer(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
170 interval
, &bgp_dump
->t_interval
);
172 /* One-off dump: execute immediately, don't affect any scheduled
174 bgp_dump
->t_interval
= NULL
;
175 thread_add_event(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
176 0, &bgp_dump
->t_interval
);
182 /* Dump common header. */
183 static void bgp_dump_header(struct stream
*obuf
, int type
, int subtype
,
186 struct timeval clock
;
190 if ((dump_type
== BGP_DUMP_ALL_ET
|| dump_type
== BGP_DUMP_UPDATES_ET
)
191 && type
== MSG_PROTOCOL_BGP4MP
)
192 type
= MSG_PROTOCOL_BGP4MP_ET
;
194 gettimeofday(&clock
, NULL
);
197 msecs
= clock
.tv_usec
;
199 /* Put dump packet header. */
200 stream_putl(obuf
, secs
);
201 stream_putw(obuf
, type
);
202 stream_putw(obuf
, subtype
);
203 stream_putl(obuf
, 0); /* len */
205 /* Adding microseconds for the MRT Extended Header */
206 if (type
== MSG_PROTOCOL_BGP4MP_ET
)
207 stream_putl(obuf
, msecs
);
210 static void bgp_dump_set_size(struct stream
*s
, int type
)
213 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
214 * "The Microsecond Timestamp is included in the computation
215 * of the Length field value." (RFC6396 2011)
217 stream_putl_at(s
, 8, stream_get_endp(s
) - BGP_DUMP_HEADER_SIZE
);
220 static void bgp_dump_routes_index_table(struct bgp
*bgp
)
223 struct listnode
*node
;
227 obuf
= bgp_dump_obuf
;
231 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_PEER_INDEX_TABLE
,
234 /* Collector BGP ID */
235 stream_put_in_addr(obuf
, &bgp
->router_id
);
238 if (bgp
->name_pretty
) {
239 stream_putw(obuf
, strlen(bgp
->name_pretty
));
240 stream_put(obuf
, bgp
->name_pretty
, strlen(bgp
->name_pretty
));
242 stream_putw(obuf
, 0);
245 /* Peer count ( plus one extra internal peer ) */
246 stream_putw(obuf
, listcount(bgp
->peer
) + 1);
248 /* Populate fake peer at index 0, for locally originated routes */
249 /* Peer type (IPv4) */
251 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
252 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
253 /* Peer BGP ID (0.0.0.0) */
254 stream_putl(obuf
, 0);
255 /* Peer IP address (0.0.0.0) */
256 stream_putl(obuf
, 0);
258 stream_putl(obuf
, 0);
260 /* Walk down all peers */
261 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
264 if (sockunion_family(&peer
->su
) == AF_INET
) {
267 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
268 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
269 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
272 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
273 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
277 stream_put_in_addr(obuf
, &peer
->remote_id
);
279 /* Peer's IP address */
280 if (sockunion_family(&peer
->su
) == AF_INET
) {
281 stream_put_in_addr(obuf
, &peer
->su
.sin
.sin_addr
);
282 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
283 stream_write(obuf
, (uint8_t *)&peer
->su
.sin6
.sin6_addr
,
287 /* Peer's AS number. */
288 /* Note that, as this is an AS4 compliant quagga, the RIB is
290 stream_putl(obuf
, peer
->as
);
292 /* Store the peer number for this peer */
293 peer
->table_dump_index
= peerno
;
297 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
299 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
300 fflush(bgp_dump_routes
.fp
);
304 static struct bgp_path_info
*
305 bgp_dump_route_node_record(int afi
, struct bgp_dest
*dest
,
306 struct bgp_path_info
*path
, unsigned int seq
)
311 const struct prefix
*p
= bgp_dest_get_prefix(dest
);
313 obuf
= bgp_dump_obuf
;
318 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
319 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
321 else if (afi
== AFI_IP6
)
322 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
323 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
326 /* Sequence number */
327 stream_putl(obuf
, seq
);
330 stream_putc(obuf
, p
->prefixlen
);
334 /* We'll dump only the useful bits (those not 0), but have to
336 stream_write(obuf
, (uint8_t *)&p
->u
.prefix4
,
337 (p
->prefixlen
+ 7) / 8);
338 } else if (afi
== AFI_IP6
) {
339 /* We'll dump only the useful bits (those not 0), but have to
341 stream_write(obuf
, (uint8_t *)&p
->u
.prefix6
,
342 (p
->prefixlen
+ 7) / 8);
345 /* Save where we are now, so we can overwride the entry count later */
346 sizep
= stream_get_endp(obuf
);
349 uint16_t entry_count
= 0;
351 /* Entry count, note that this is overwritten later */
352 stream_putw(obuf
, 0);
354 endp
= stream_get_endp(obuf
);
355 for (; path
; path
= path
->next
) {
359 stream_putw(obuf
, path
->peer
->table_dump_index
);
362 stream_putl(obuf
, time(NULL
) - (bgp_clock() - path
->uptime
));
364 /* Dump attribute. */
365 /* Skip prefix & AFI/SAFI for MP_NLRI */
366 bgp_dump_routes_attr(obuf
, path
->attr
, p
);
368 cur_endp
= stream_get_endp(obuf
);
369 if (cur_endp
> BGP_MAX_PACKET_SIZE
+ BGP_DUMP_MSG_HEADER
370 + BGP_DUMP_HEADER_SIZE
) {
371 stream_set_endp(obuf
, endp
);
379 /* Overwrite the entry count, now that we know the right number */
380 stream_putw_at(obuf
, sizep
, entry_count
);
382 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
383 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
389 /* Runs under child process. */
390 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
393 struct bgp_path_info
*path
;
394 struct bgp_dest
*dest
;
396 struct bgp_table
*table
;
398 bgp
= bgp_get_default();
402 if (bgp_dump_routes
.fp
== NULL
)
405 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
406 so this should only be done on the first call to
407 bgp_dump_routes_func.
408 ( this function will be called once for ipv4 and once for ipv6 ) */
410 bgp_dump_routes_index_table(bgp
);
412 /* Walk down each BGP route. */
413 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
415 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
416 path
= bgp_dest_get_bgp_path_info(dest
);
418 path
= bgp_dump_route_node_record(afi
, dest
, path
, seq
);
423 fflush(bgp_dump_routes
.fp
);
428 static int bgp_dump_interval_func(struct thread
*t
)
430 struct bgp_dump
*bgp_dump
;
431 bgp_dump
= THREAD_ARG(t
);
432 bgp_dump
->t_interval
= NULL
;
434 /* Reschedule dump even if file couldn't be opened this time... */
435 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
436 /* In case of bgp_dump_routes, we need special route dump
438 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
439 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
440 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
441 /* Close the file now. For a RIB dump there's no point
443 * it open until the next scheduled dump starts. */
444 fclose(bgp_dump
->fp
);
449 /* if interval is set reschedule */
450 if (bgp_dump
->interval
> 0)
451 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
456 /* Dump common information. */
457 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
460 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
462 /* Source AS number and Destination AS number. */
463 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
464 stream_putl(obuf
, peer
->as
);
465 stream_putl(obuf
, peer
->local_as
);
467 stream_putw(obuf
, peer
->as
);
468 stream_putw(obuf
, peer
->local_as
);
471 if (peer
->su
.sa
.sa_family
== AF_INET
) {
472 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
473 stream_putw(obuf
, AFI_IP
);
475 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
478 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
481 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
482 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
483 /* Interface Index and Address family. */
484 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
485 stream_putw(obuf
, AFI_IP6
);
487 /* Source IP Address and Destination IP Address. */
488 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
491 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
494 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
498 /* Dump BGP status change. */
499 int bgp_dump_state(struct peer
*peer
)
503 /* If dump file pointer is disabled return immediately. */
504 if (bgp_dump_all
.fp
== NULL
)
507 /* Make dump stream. */
508 obuf
= bgp_dump_obuf
;
511 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
513 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
515 stream_putw(obuf
, peer
->ostatus
);
516 stream_putw(obuf
, peer
->status
);
519 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
521 /* Write to the stream. */
522 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
523 fflush(bgp_dump_all
.fp
);
527 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
528 struct stream
*packet
)
532 /* If dump file pointer is disabled return immediately. */
533 if (bgp_dump
->fp
== NULL
)
536 /* Make dump stream. */
537 obuf
= bgp_dump_obuf
;
540 /* Dump header and common part. */
541 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
542 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
545 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
548 bgp_dump_common(obuf
, peer
, 0);
550 /* Packet contents. */
551 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
554 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
556 /* Write to the stream. */
557 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
558 fflush(bgp_dump
->fp
);
561 /* Called from bgp_packet.c when BGP packet is received. */
562 static int bgp_dump_packet(struct peer
*peer
, uint8_t type
, bgp_size_t size
,
563 struct stream
*packet
)
566 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
568 /* bgp_dump_updates. */
569 if (type
== BGP_MSG_UPDATE
)
570 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
574 static unsigned int bgp_dump_parse_time(const char *str
)
589 for (i
= 0; i
< len
; i
++) {
590 if (isdigit((unsigned char)str
[i
])) {
592 time
+= str
[i
] - '0';
593 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
598 total
+= time
* 60 * 60;
601 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
613 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
614 enum bgp_dump_type type
, const char *path
,
615 const char *interval_str
)
617 unsigned int interval
;
619 /* Don't schedule duplicate dumps if the dump command is given twice */
620 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
621 && type
== bgp_dump
->type
) {
623 if (bgp_dump
->interval_str
624 && strcmp(bgp_dump
->interval_str
, interval_str
)
628 if (!bgp_dump
->interval_str
)
633 /* Removing previous config */
634 bgp_dump_unset(bgp_dump
);
637 /* Check interval string. */
638 interval
= bgp_dump_parse_time(interval_str
);
640 vty_out(vty
, "Malformed interval string\n");
641 return CMD_WARNING_CONFIG_FAILED
;
644 /* Setting interval string */
645 bgp_dump
->interval_str
=
646 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
652 bgp_dump
->type
= type
;
655 bgp_dump
->interval
= interval
;
658 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
660 /* Create interval thread. */
661 bgp_dump_interval_add(bgp_dump
, interval
);
663 /* This should be called when interval is expired. */
664 bgp_dump_open_file(bgp_dump
);
669 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
671 /* Removing file name. */
672 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
676 fclose(bgp_dump
->fp
);
680 /* Removing interval event. */
681 thread_cancel(&bgp_dump
->t_interval
);
683 bgp_dump
->interval
= 0;
685 /* Removing interval string. */
686 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
693 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
696 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
697 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
698 "Dump whole BGP routing table\n"
700 "Interval of output\n")
702 int idx_dump_routes
= 2;
704 int idx_interval
= 4;
705 int bgp_dump_type
= 0;
706 const char *interval
= NULL
;
707 struct bgp_dump
*bgp_dump_struct
= NULL
;
708 const struct bgp_dump_type_map
*map
= NULL
;
710 for (map
= bgp_dump_type_map
; map
->str
; map
++)
711 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
712 bgp_dump_type
= map
->type
;
714 switch (bgp_dump_type
) {
716 case BGP_DUMP_ALL_ET
:
717 bgp_dump_struct
= &bgp_dump_all
;
719 case BGP_DUMP_UPDATES
:
720 case BGP_DUMP_UPDATES_ET
:
721 bgp_dump_struct
= &bgp_dump_updates
;
723 case BGP_DUMP_ROUTES
:
725 bgp_dump_struct
= &bgp_dump_routes
;
729 /* When an interval is given */
730 if (argc
== idx_interval
+ 1)
731 interval
= argv
[idx_interval
]->arg
;
733 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
734 argv
[idx_path
]->arg
, interval
);
737 DEFUN (no_dump_bgp_all
,
739 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
742 "Stop BGP packet dump\n"
743 "Stop dump process all\n"
744 "Stop dump process all-et\n"
745 "Stop dump process updates\n"
746 "Stop dump process updates-et\n"
747 "Stop dump process route-mrt\n"
749 "Interval of output\n")
751 int idx_dump_routes
= 3;
752 int bgp_dump_type
= 0;
753 const struct bgp_dump_type_map
*map
= NULL
;
754 struct bgp_dump
*bgp_dump_struct
= NULL
;
756 for (map
= bgp_dump_type_map
; map
->str
; map
++)
757 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
758 bgp_dump_type
= map
->type
;
760 switch (bgp_dump_type
) {
762 case BGP_DUMP_ALL_ET
:
763 bgp_dump_struct
= &bgp_dump_all
;
765 case BGP_DUMP_UPDATES
:
766 case BGP_DUMP_UPDATES_ET
:
767 bgp_dump_struct
= &bgp_dump_updates
;
769 case BGP_DUMP_ROUTES
:
771 bgp_dump_struct
= &bgp_dump_routes
;
775 return bgp_dump_unset(bgp_dump_struct
);
778 static int config_write_bgp_dump(struct vty
*vty
);
779 /* BGP node structure. */
780 static struct cmd_node bgp_dump_node
= {
784 .config_write
= config_write_bgp_dump
,
787 static int config_write_bgp_dump(struct vty
*vty
)
789 if (bgp_dump_all
.filename
) {
790 const char *type_str
= "all";
791 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
794 if (bgp_dump_all
.interval_str
)
795 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
796 bgp_dump_all
.filename
,
797 bgp_dump_all
.interval_str
);
799 vty_out(vty
, "dump bgp %s %s\n", type_str
,
800 bgp_dump_all
.filename
);
802 if (bgp_dump_updates
.filename
) {
803 const char *type_str
= "updates";
804 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
805 type_str
= "updates-et";
807 if (bgp_dump_updates
.interval_str
)
808 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
809 bgp_dump_updates
.filename
,
810 bgp_dump_updates
.interval_str
);
812 vty_out(vty
, "dump bgp %s %s\n", type_str
,
813 bgp_dump_updates
.filename
);
815 if (bgp_dump_routes
.filename
) {
816 if (bgp_dump_routes
.interval_str
)
817 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
818 bgp_dump_routes
.filename
,
819 bgp_dump_routes
.interval_str
);
821 vty_out(vty
, "dump bgp routes-mrt %s\n",
822 bgp_dump_routes
.filename
);
827 /* Initialize BGP packet dump functionality. */
828 void bgp_dump_init(void)
830 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
831 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
832 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
835 stream_new((BGP_MAX_PACKET_SIZE
<< 1) + BGP_DUMP_MSG_HEADER
836 + BGP_DUMP_HEADER_SIZE
);
838 install_node(&bgp_dump_node
);
840 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
841 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
843 hook_register(bgp_packet_dump
, bgp_dump_packet
);
844 hook_register(peer_status_changed
, bgp_dump_state
);
847 void bgp_dump_finish(void)
849 bgp_dump_unset(&bgp_dump_all
);
850 bgp_dump_unset(&bgp_dump_updates
);
851 bgp_dump_unset(&bgp_dump_routes
);
853 stream_free(bgp_dump_obuf
);
854 bgp_dump_obuf
= NULL
;
855 hook_unregister(bgp_packet_dump
, bgp_dump_packet
);
856 hook_unregister(peer_status_changed
, bgp_dump_state
);