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"
48 static const struct bgp_dump_type_map
{
49 enum bgp_dump_type type
;
51 } bgp_dump_type_map
[] = {
52 {BGP_DUMP_ALL
, "all"}, {BGP_DUMP_ALL_ET
, "all-et"},
53 {BGP_DUMP_UPDATES
, "updates"}, {BGP_DUMP_UPDATES_ET
, "updates-et"},
54 {BGP_DUMP_ROUTES
, "routes-mrt"}, {0, NULL
},
59 MSG_START
, /* sender is starting up */
60 MSG_DIE
, /* receiver should shut down */
61 MSG_I_AM_DEAD
, /* sender is shutting down */
62 MSG_PEER_DOWN
, /* sender's peer is down */
63 MSG_PROTOCOL_BGP
, /* msg is a BGP packet */
64 MSG_PROTOCOL_RIP
, /* msg is a RIP packet */
65 MSG_PROTOCOL_IDRP
, /* msg is an IDRP packet */
66 MSG_PROTOCOL_RIPNG
, /* msg is a RIPNG packet */
67 MSG_PROTOCOL_BGP4PLUS
, /* msg is a BGP4+ packet */
68 MSG_PROTOCOL_BGP4PLUS_01
, /* msg is a BGP4+ (draft 01) packet */
69 MSG_PROTOCOL_OSPF
, /* msg is an OSPF packet */
70 MSG_TABLE_DUMP
, /* routing table dump */
71 MSG_TABLE_DUMP_V2
/* routing table dump, version 2 */
75 enum bgp_dump_type type
;
81 unsigned int interval
;
85 struct thread
*t_interval
;
88 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
);
89 static int bgp_dump_interval_func(struct thread
*);
91 /* BGP packet dump output buffer. */
92 struct stream
*bgp_dump_obuf
;
94 /* BGP dump strucuture for 'dump bgp all' */
95 struct bgp_dump bgp_dump_all
;
97 /* BGP dump structure for 'dump bgp updates' */
98 struct bgp_dump bgp_dump_updates
;
100 /* BGP dump structure for 'dump bgp routes' */
101 struct bgp_dump bgp_dump_routes
;
103 static FILE *bgp_dump_open_file(struct bgp_dump
*bgp_dump
)
108 char fullpath
[MAXPATHLEN
];
109 char realpath
[MAXPATHLEN
];
113 tm
= localtime(&clock
);
115 if (bgp_dump
->filename
[0] != DIRECTORY_SEP
) {
116 sprintf(fullpath
, "%s/%s", vty_get_cwd(), bgp_dump
->filename
);
117 ret
= strftime(realpath
, MAXPATHLEN
, fullpath
, tm
);
119 ret
= strftime(realpath
, MAXPATHLEN
, bgp_dump
->filename
, tm
);
122 zlog_warn("bgp_dump_open_file: strftime error");
127 fclose(bgp_dump
->fp
);
130 oldumask
= umask(0777 & ~LOGFILE_MASK
);
131 bgp_dump
->fp
= fopen(realpath
, "w");
133 if (bgp_dump
->fp
== NULL
) {
134 zlog_warn("bgp_dump_open_file: %s: %s", realpath
,
144 static int bgp_dump_interval_add(struct bgp_dump
*bgp_dump
, int interval
)
151 /* Periodic dump every interval seconds */
152 if ((interval
< 86400) && ((86400 % interval
) == 0)) {
153 /* Dump at predictable times: if a day has a whole
155 * intervals, dump every interval seconds starting from
160 secs_into_day
= tm
->tm_sec
+ 60 * tm
->tm_min
161 + 60 * 60 * tm
->tm_hour
;
163 - secs_into_day
% interval
; /* always > 0 */
165 bgp_dump
->t_interval
= NULL
;
166 thread_add_timer(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
167 interval
, &bgp_dump
->t_interval
);
169 /* One-off dump: execute immediately, don't affect any scheduled
171 bgp_dump
->t_interval
= NULL
;
172 thread_add_event(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
173 0, &bgp_dump
->t_interval
);
179 /* Dump common header. */
180 static void bgp_dump_header(struct stream
*obuf
, int type
, int subtype
,
183 struct timeval clock
;
187 if ((dump_type
== BGP_DUMP_ALL_ET
|| dump_type
== BGP_DUMP_UPDATES_ET
)
188 && type
== MSG_PROTOCOL_BGP4MP
)
189 type
= MSG_PROTOCOL_BGP4MP_ET
;
191 gettimeofday(&clock
, NULL
);
194 msecs
= clock
.tv_usec
;
196 /* Put dump packet header. */
197 stream_putl(obuf
, secs
);
198 stream_putw(obuf
, type
);
199 stream_putw(obuf
, subtype
);
200 stream_putl(obuf
, 0); /* len */
202 /* Adding microseconds for the MRT Extended Header */
203 if (type
== MSG_PROTOCOL_BGP4MP_ET
)
204 stream_putl(obuf
, msecs
);
207 static void bgp_dump_set_size(struct stream
*s
, int type
)
210 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
211 * "The Microsecond Timestamp is included in the computation
212 * of the Length field value." (RFC6396 2011)
214 stream_putl_at(s
, 8, stream_get_endp(s
) - BGP_DUMP_HEADER_SIZE
);
217 static void bgp_dump_routes_index_table(struct bgp
*bgp
)
220 struct listnode
*node
;
224 obuf
= bgp_dump_obuf
;
228 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_PEER_INDEX_TABLE
,
231 /* Collector BGP ID */
232 stream_put_in_addr(obuf
, &bgp
->router_id
);
236 stream_putw(obuf
, strlen(bgp
->name
));
237 stream_put(obuf
, bgp
->name
, strlen(bgp
->name
));
239 stream_putw(obuf
, 0);
242 /* Peer count ( plus one extra internal peer ) */
243 stream_putw(obuf
, listcount(bgp
->peer
) + 1);
245 /* Populate fake peer at index 0, for locally originated routes */
246 /* Peer type (IPv4) */
247 stream_putc(obuf
, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
248 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
249 /* Peer BGP ID (0.0.0.0) */
250 stream_putl(obuf
, 0);
251 /* Peer IP address (0.0.0.0) */
252 stream_putl(obuf
, 0);
254 stream_putl(obuf
, 0);
256 /* Walk down all peers */
257 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
260 if (sockunion_family(&peer
->su
) == AF_INET
) {
263 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
264 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
265 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
268 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
269 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
273 stream_put_in_addr(obuf
, &peer
->remote_id
);
275 /* Peer's IP address */
276 if (sockunion_family(&peer
->su
) == AF_INET
) {
277 stream_put_in_addr(obuf
, &peer
->su
.sin
.sin_addr
);
278 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
279 stream_write(obuf
, (u_char
*)&peer
->su
.sin6
.sin6_addr
,
283 /* Peer's AS number. */
284 /* Note that, as this is an AS4 compliant quagga, the RIB is
286 stream_putl(obuf
, peer
->as
);
288 /* Store the peer number for this peer */
289 peer
->table_dump_index
= peerno
;
293 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
295 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
296 fflush(bgp_dump_routes
.fp
);
300 static struct bgp_info
*bgp_dump_route_node_record(int afi
, struct bgp_node
*rn
,
301 struct bgp_info
*info
,
308 obuf
= bgp_dump_obuf
;
313 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
314 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
316 else if (afi
== AFI_IP6
)
317 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
318 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
321 /* Sequence number */
322 stream_putl(obuf
, seq
);
325 stream_putc(obuf
, rn
->p
.prefixlen
);
329 /* We'll dump only the useful bits (those not 0), but have to
331 stream_write(obuf
, (u_char
*)&rn
->p
.u
.prefix4
,
332 (rn
->p
.prefixlen
+ 7) / 8);
333 } else if (afi
== AFI_IP6
) {
334 /* We'll dump only the useful bits (those not 0), but have to
336 stream_write(obuf
, (u_char
*)&rn
->p
.u
.prefix6
,
337 (rn
->p
.prefixlen
+ 7) / 8);
340 /* Save where we are now, so we can overwride the entry count later */
341 sizep
= stream_get_endp(obuf
);
344 uint16_t entry_count
= 0;
346 /* Entry count, note that this is overwritten later */
347 stream_putw(obuf
, 0);
349 endp
= stream_get_endp(obuf
);
350 for (; info
; info
= info
->next
) {
354 stream_putw(obuf
, info
->peer
->table_dump_index
);
357 stream_putl(obuf
, time(NULL
) - (bgp_clock() - info
->uptime
));
359 /* Dump attribute. */
360 /* Skip prefix & AFI/SAFI for MP_NLRI */
361 bgp_dump_routes_attr(obuf
, info
->attr
, &rn
->p
);
363 cur_endp
= stream_get_endp(obuf
);
364 if (cur_endp
> BGP_MAX_PACKET_SIZE
+ BGP_DUMP_MSG_HEADER
365 + BGP_DUMP_HEADER_SIZE
) {
366 stream_set_endp(obuf
, endp
);
374 /* Overwrite the entry count, now that we know the right number */
375 stream_putw_at(obuf
, sizep
, entry_count
);
377 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
378 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
384 /* Runs under child process. */
385 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
388 struct bgp_info
*info
;
391 struct bgp_table
*table
;
393 bgp
= bgp_get_default();
397 if (bgp_dump_routes
.fp
== NULL
)
400 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
401 so this should only be done on the first call to
402 bgp_dump_routes_func.
403 ( this function will be called once for ipv4 and once for ipv6 ) */
405 bgp_dump_routes_index_table(bgp
);
407 /* Walk down each BGP route. */
408 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
410 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
413 info
= bgp_dump_route_node_record(afi
, rn
, info
, seq
);
418 fflush(bgp_dump_routes
.fp
);
423 static int bgp_dump_interval_func(struct thread
*t
)
425 struct bgp_dump
*bgp_dump
;
426 bgp_dump
= THREAD_ARG(t
);
427 bgp_dump
->t_interval
= NULL
;
429 /* Reschedule dump even if file couldn't be opened this time... */
430 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
431 /* In case of bgp_dump_routes, we need special route dump
433 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
434 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
435 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
436 /* Close the file now. For a RIB dump there's no point
438 * it open until the next scheduled dump starts. */
439 fclose(bgp_dump
->fp
);
444 /* if interval is set reschedule */
445 if (bgp_dump
->interval
> 0)
446 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
451 /* Dump common information. */
452 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
455 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
457 /* Source AS number and Destination AS number. */
458 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
459 stream_putl(obuf
, peer
->as
);
460 stream_putl(obuf
, peer
->local_as
);
462 stream_putw(obuf
, peer
->as
);
463 stream_putw(obuf
, peer
->local_as
);
466 if (peer
->su
.sa
.sa_family
== AF_INET
) {
467 stream_putw(obuf
, peer
->ifindex
);
468 stream_putw(obuf
, AFI_IP
);
470 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
473 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
476 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
477 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
478 /* Interface Index and Address family. */
479 stream_putw(obuf
, peer
->ifindex
);
480 stream_putw(obuf
, AFI_IP6
);
482 /* Source IP Address and Destination IP Address. */
483 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
486 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
489 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
493 /* Dump BGP status change. */
494 void bgp_dump_state(struct peer
*peer
, int status_old
, int status_new
)
498 /* If dump file pointer is disabled return immediately. */
499 if (bgp_dump_all
.fp
== NULL
)
502 /* Make dump stream. */
503 obuf
= bgp_dump_obuf
;
506 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
508 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
510 stream_putw(obuf
, status_old
);
511 stream_putw(obuf
, status_new
);
514 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
516 /* Write to the stream. */
517 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
518 fflush(bgp_dump_all
.fp
);
521 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
522 struct stream
*packet
)
526 /* If dump file pointer is disabled return immediately. */
527 if (bgp_dump
->fp
== NULL
)
530 /* Make dump stream. */
531 obuf
= bgp_dump_obuf
;
534 /* Dump header and common part. */
535 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
536 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
539 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
542 bgp_dump_common(obuf
, peer
, 0);
544 /* Packet contents. */
545 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
548 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
550 /* Write to the stream. */
551 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
552 fflush(bgp_dump
->fp
);
555 /* Called from bgp_packet.c when BGP packet is received. */
556 void bgp_dump_packet(struct peer
*peer
, int type
, struct stream
*packet
)
559 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
561 /* bgp_dump_updates. */
562 if (type
== BGP_MSG_UPDATE
)
563 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
566 static unsigned int bgp_dump_parse_time(const char *str
)
581 for (i
= 0; i
< len
; i
++) {
582 if (isdigit((int)str
[i
])) {
584 time
+= str
[i
] - '0';
585 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
590 total
+= time
* 60 * 60;
593 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
605 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
606 enum bgp_dump_type type
, const char *path
,
607 const char *interval_str
)
609 unsigned int interval
;
611 /* Don't schedule duplicate dumps if the dump command is given twice */
612 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
613 && type
== bgp_dump
->type
) {
615 if (bgp_dump
->interval_str
616 && strcmp(bgp_dump
->interval_str
, interval_str
)
620 if (!bgp_dump
->interval_str
)
625 /* Removing previous config */
626 bgp_dump_unset(bgp_dump
);
629 /* Check interval string. */
630 interval
= bgp_dump_parse_time(interval_str
);
632 vty_out(vty
, "Malformed interval string\n");
633 return CMD_WARNING_CONFIG_FAILED
;
636 /* Setting interval string */
637 bgp_dump
->interval_str
=
638 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
644 bgp_dump
->type
= type
;
647 bgp_dump
->interval
= interval
;
650 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
652 /* Create interval thread. */
653 bgp_dump_interval_add(bgp_dump
, interval
);
655 /* This should be called when interval is expired. */
656 bgp_dump_open_file(bgp_dump
);
661 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
663 /* Removing file name. */
664 if (bgp_dump
->filename
) {
665 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
666 bgp_dump
->filename
= NULL
;
671 fclose(bgp_dump
->fp
);
675 /* Removing interval thread. */
676 if (bgp_dump
->t_interval
) {
677 thread_cancel(bgp_dump
->t_interval
);
678 bgp_dump
->t_interval
= NULL
;
681 bgp_dump
->interval
= 0;
683 /* Removing interval string. */
684 if (bgp_dump
->interval_str
) {
685 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
686 bgp_dump
->interval_str
= NULL
;
694 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
697 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
698 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
699 "Dump whole BGP routing table\n"
701 "Interval of output\n")
703 int idx_dump_routes
= 2;
705 int idx_interval
= 4;
706 int bgp_dump_type
= 0;
707 const char *interval
= NULL
;
708 struct bgp_dump
*bgp_dump_struct
= NULL
;
709 const struct bgp_dump_type_map
*map
= NULL
;
711 for (map
= bgp_dump_type_map
; map
->str
; map
++)
712 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
713 bgp_dump_type
= map
->type
;
715 switch (bgp_dump_type
) {
717 case BGP_DUMP_ALL_ET
:
718 bgp_dump_struct
= &bgp_dump_all
;
720 case BGP_DUMP_UPDATES
:
721 case BGP_DUMP_UPDATES_ET
:
722 bgp_dump_struct
= &bgp_dump_updates
;
724 case BGP_DUMP_ROUTES
:
726 bgp_dump_struct
= &bgp_dump_routes
;
730 /* When an interval is given */
731 if (argc
== idx_interval
+ 1)
732 interval
= argv
[idx_interval
]->arg
;
734 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
735 argv
[idx_path
]->arg
, interval
);
738 DEFUN (no_dump_bgp_all
,
740 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
743 "Stop BGP packet dump\n"
744 "Stop dump process all\n"
745 "Stop dump process all-et\n"
746 "Stop dump process updates\n"
747 "Stop dump process updates-et\n"
748 "Stop dump process route-mrt\n"
750 "Interval of output\n")
752 int idx_dump_routes
= 3;
753 int bgp_dump_type
= 0;
754 const struct bgp_dump_type_map
*map
= NULL
;
755 struct bgp_dump
*bgp_dump_struct
= NULL
;
757 for (map
= bgp_dump_type_map
; map
->str
; map
++)
758 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
759 bgp_dump_type
= map
->type
;
761 switch (bgp_dump_type
) {
763 case BGP_DUMP_ALL_ET
:
764 bgp_dump_struct
= &bgp_dump_all
;
766 case BGP_DUMP_UPDATES
:
767 case BGP_DUMP_UPDATES_ET
:
768 bgp_dump_struct
= &bgp_dump_updates
;
770 case BGP_DUMP_ROUTES
:
772 bgp_dump_struct
= &bgp_dump_routes
;
776 return bgp_dump_unset(bgp_dump_struct
);
779 /* BGP node structure. */
780 static struct cmd_node bgp_dump_node
= {DUMP_NODE
, "", 1};
784 config_time2str (unsigned int interval
)
786 static char buf
[BUFSIZ
];
792 sprintf (buf
, "%dh", interval
/ 3600);
797 sprintf (buf
+ strlen (buf
), "%dm", interval
/60);
802 sprintf (buf
+ strlen (buf
), "%d", interval
);
808 static int config_write_bgp_dump(struct vty
*vty
)
810 if (bgp_dump_all
.filename
) {
811 const char *type_str
= "all";
812 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
815 if (bgp_dump_all
.interval_str
)
816 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
817 bgp_dump_all
.filename
,
818 bgp_dump_all
.interval_str
);
820 vty_out(vty
, "dump bgp %s %s\n", type_str
,
821 bgp_dump_all
.filename
);
823 if (bgp_dump_updates
.filename
) {
824 const char *type_str
= "updates";
825 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
826 type_str
= "updates-et";
828 if (bgp_dump_updates
.interval_str
)
829 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
830 bgp_dump_updates
.filename
,
831 bgp_dump_updates
.interval_str
);
833 vty_out(vty
, "dump bgp %s %s\n", type_str
,
834 bgp_dump_updates
.filename
);
836 if (bgp_dump_routes
.filename
) {
837 if (bgp_dump_routes
.interval_str
)
838 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
839 bgp_dump_routes
.filename
,
840 bgp_dump_routes
.interval_str
);
842 vty_out(vty
, "dump bgp routes-mrt %s\n",
843 bgp_dump_routes
.filename
);
848 /* Initialize BGP packet dump functionality. */
849 void bgp_dump_init(void)
851 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
852 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
853 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
856 stream_new((BGP_MAX_PACKET_SIZE
<< 1) + BGP_DUMP_MSG_HEADER
857 + BGP_DUMP_HEADER_SIZE
);
859 install_node(&bgp_dump_node
, config_write_bgp_dump
);
861 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
862 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
865 void bgp_dump_finish(void)
867 bgp_dump_unset(&bgp_dump_all
);
868 bgp_dump_unset(&bgp_dump_updates
);
869 bgp_dump_unset(&bgp_dump_routes
);
871 stream_free(bgp_dump_obuf
);
872 bgp_dump_obuf
= NULL
;