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 thread. */
681 if (bgp_dump
->t_interval
) {
682 thread_cancel(bgp_dump
->t_interval
);
683 bgp_dump
->t_interval
= NULL
;
686 bgp_dump
->interval
= 0;
688 /* Removing interval string. */
689 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
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 static int config_write_bgp_dump(struct vty
*vty
);
782 /* BGP node structure. */
783 static struct cmd_node bgp_dump_node
= {
787 .config_write
= config_write_bgp_dump
,
790 static int config_write_bgp_dump(struct vty
*vty
)
792 if (bgp_dump_all
.filename
) {
793 const char *type_str
= "all";
794 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
797 if (bgp_dump_all
.interval_str
)
798 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
799 bgp_dump_all
.filename
,
800 bgp_dump_all
.interval_str
);
802 vty_out(vty
, "dump bgp %s %s\n", type_str
,
803 bgp_dump_all
.filename
);
805 if (bgp_dump_updates
.filename
) {
806 const char *type_str
= "updates";
807 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
808 type_str
= "updates-et";
810 if (bgp_dump_updates
.interval_str
)
811 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
812 bgp_dump_updates
.filename
,
813 bgp_dump_updates
.interval_str
);
815 vty_out(vty
, "dump bgp %s %s\n", type_str
,
816 bgp_dump_updates
.filename
);
818 if (bgp_dump_routes
.filename
) {
819 if (bgp_dump_routes
.interval_str
)
820 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
821 bgp_dump_routes
.filename
,
822 bgp_dump_routes
.interval_str
);
824 vty_out(vty
, "dump bgp routes-mrt %s\n",
825 bgp_dump_routes
.filename
);
830 /* Initialize BGP packet dump functionality. */
831 void bgp_dump_init(void)
833 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
834 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
835 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
838 stream_new((BGP_MAX_PACKET_SIZE
<< 1) + BGP_DUMP_MSG_HEADER
839 + BGP_DUMP_HEADER_SIZE
);
841 install_node(&bgp_dump_node
);
843 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
844 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
846 hook_register(bgp_packet_dump
, bgp_dump_packet
);
847 hook_register(peer_status_changed
, bgp_dump_state
);
850 void bgp_dump_finish(void)
852 bgp_dump_unset(&bgp_dump_all
);
853 bgp_dump_unset(&bgp_dump_updates
);
854 bgp_dump_unset(&bgp_dump_routes
);
856 stream_free(bgp_dump_obuf
);
857 bgp_dump_obuf
= NULL
;
858 hook_unregister(bgp_packet_dump
, bgp_dump_packet
);
859 hook_unregister(peer_status_changed
, bgp_dump_state
);