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) */
248 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
249 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
250 /* Peer BGP ID (0.0.0.0) */
251 stream_putl(obuf
, 0);
252 /* Peer IP address (0.0.0.0) */
253 stream_putl(obuf
, 0);
255 stream_putl(obuf
, 0);
257 /* Walk down all peers */
258 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
261 if (sockunion_family(&peer
->su
) == AF_INET
) {
264 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
265 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
266 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
269 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
270 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
274 stream_put_in_addr(obuf
, &peer
->remote_id
);
276 /* Peer's IP address */
277 if (sockunion_family(&peer
->su
) == AF_INET
) {
278 stream_put_in_addr(obuf
, &peer
->su
.sin
.sin_addr
);
279 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
280 stream_write(obuf
, (u_char
*)&peer
->su
.sin6
.sin6_addr
,
284 /* Peer's AS number. */
285 /* Note that, as this is an AS4 compliant quagga, the RIB is
287 stream_putl(obuf
, peer
->as
);
289 /* Store the peer number for this peer */
290 peer
->table_dump_index
= peerno
;
294 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
296 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
297 fflush(bgp_dump_routes
.fp
);
301 static struct bgp_info
*bgp_dump_route_node_record(int afi
, struct bgp_node
*rn
,
302 struct bgp_info
*info
,
309 obuf
= bgp_dump_obuf
;
314 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
315 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
317 else if (afi
== AFI_IP6
)
318 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
319 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
322 /* Sequence number */
323 stream_putl(obuf
, seq
);
326 stream_putc(obuf
, rn
->p
.prefixlen
);
330 /* We'll dump only the useful bits (those not 0), but have to
332 stream_write(obuf
, (u_char
*)&rn
->p
.u
.prefix4
,
333 (rn
->p
.prefixlen
+ 7) / 8);
334 } else if (afi
== AFI_IP6
) {
335 /* We'll dump only the useful bits (those not 0), but have to
337 stream_write(obuf
, (u_char
*)&rn
->p
.u
.prefix6
,
338 (rn
->p
.prefixlen
+ 7) / 8);
341 /* Save where we are now, so we can overwride the entry count later */
342 sizep
= stream_get_endp(obuf
);
345 uint16_t entry_count
= 0;
347 /* Entry count, note that this is overwritten later */
348 stream_putw(obuf
, 0);
350 endp
= stream_get_endp(obuf
);
351 for (; info
; info
= info
->next
) {
355 stream_putw(obuf
, info
->peer
->table_dump_index
);
358 stream_putl(obuf
, time(NULL
) - (bgp_clock() - info
->uptime
));
360 /* Dump attribute. */
361 /* Skip prefix & AFI/SAFI for MP_NLRI */
362 bgp_dump_routes_attr(obuf
, info
->attr
, &rn
->p
);
364 cur_endp
= stream_get_endp(obuf
);
365 if (cur_endp
> BGP_MAX_PACKET_SIZE
+ BGP_DUMP_MSG_HEADER
366 + BGP_DUMP_HEADER_SIZE
) {
367 stream_set_endp(obuf
, endp
);
375 /* Overwrite the entry count, now that we know the right number */
376 stream_putw_at(obuf
, sizep
, entry_count
);
378 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
379 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
385 /* Runs under child process. */
386 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
389 struct bgp_info
*info
;
392 struct bgp_table
*table
;
394 bgp
= bgp_get_default();
398 if (bgp_dump_routes
.fp
== NULL
)
401 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
402 so this should only be done on the first call to
403 bgp_dump_routes_func.
404 ( this function will be called once for ipv4 and once for ipv6 ) */
406 bgp_dump_routes_index_table(bgp
);
408 /* Walk down each BGP route. */
409 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
411 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
414 info
= bgp_dump_route_node_record(afi
, rn
, info
, seq
);
419 fflush(bgp_dump_routes
.fp
);
424 static int bgp_dump_interval_func(struct thread
*t
)
426 struct bgp_dump
*bgp_dump
;
427 bgp_dump
= THREAD_ARG(t
);
428 bgp_dump
->t_interval
= NULL
;
430 /* Reschedule dump even if file couldn't be opened this time... */
431 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
432 /* In case of bgp_dump_routes, we need special route dump
434 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
435 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
436 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
437 /* Close the file now. For a RIB dump there's no point
439 * it open until the next scheduled dump starts. */
440 fclose(bgp_dump
->fp
);
445 /* if interval is set reschedule */
446 if (bgp_dump
->interval
> 0)
447 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
452 /* Dump common information. */
453 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
456 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
458 /* Source AS number and Destination AS number. */
459 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
460 stream_putl(obuf
, peer
->as
);
461 stream_putl(obuf
, peer
->local_as
);
463 stream_putw(obuf
, peer
->as
);
464 stream_putw(obuf
, peer
->local_as
);
467 if (peer
->su
.sa
.sa_family
== AF_INET
) {
468 stream_putw(obuf
, peer
->ifindex
);
469 stream_putw(obuf
, AFI_IP
);
471 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
474 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
477 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
478 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
479 /* Interface Index and Address family. */
480 stream_putw(obuf
, peer
->ifindex
);
481 stream_putw(obuf
, AFI_IP6
);
483 /* Source IP Address and Destination IP Address. */
484 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
487 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
490 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
494 /* Dump BGP status change. */
495 void bgp_dump_state(struct peer
*peer
, int status_old
, int status_new
)
499 /* If dump file pointer is disabled return immediately. */
500 if (bgp_dump_all
.fp
== NULL
)
503 /* Make dump stream. */
504 obuf
= bgp_dump_obuf
;
507 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
509 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
511 stream_putw(obuf
, status_old
);
512 stream_putw(obuf
, status_new
);
515 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
517 /* Write to the stream. */
518 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
519 fflush(bgp_dump_all
.fp
);
522 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
523 struct stream
*packet
)
527 /* If dump file pointer is disabled return immediately. */
528 if (bgp_dump
->fp
== NULL
)
531 /* Make dump stream. */
532 obuf
= bgp_dump_obuf
;
535 /* Dump header and common part. */
536 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
537 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
540 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
543 bgp_dump_common(obuf
, peer
, 0);
545 /* Packet contents. */
546 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
549 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
551 /* Write to the stream. */
552 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
553 fflush(bgp_dump
->fp
);
556 /* Called from bgp_packet.c when BGP packet is received. */
557 void bgp_dump_packet(struct peer
*peer
, int type
, struct stream
*packet
)
560 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
562 /* bgp_dump_updates. */
563 if (type
== BGP_MSG_UPDATE
)
564 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
567 static unsigned int bgp_dump_parse_time(const char *str
)
582 for (i
= 0; i
< len
; i
++) {
583 if (isdigit((int)str
[i
])) {
585 time
+= str
[i
] - '0';
586 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
591 total
+= time
* 60 * 60;
594 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
606 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
607 enum bgp_dump_type type
, const char *path
,
608 const char *interval_str
)
610 unsigned int interval
;
612 /* Don't schedule duplicate dumps if the dump command is given twice */
613 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
614 && type
== bgp_dump
->type
) {
616 if (bgp_dump
->interval_str
617 && strcmp(bgp_dump
->interval_str
, interval_str
)
621 if (!bgp_dump
->interval_str
)
626 /* Removing previous config */
627 bgp_dump_unset(bgp_dump
);
630 /* Check interval string. */
631 interval
= bgp_dump_parse_time(interval_str
);
633 vty_out(vty
, "Malformed interval string\n");
634 return CMD_WARNING_CONFIG_FAILED
;
637 /* Setting interval string */
638 bgp_dump
->interval_str
=
639 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
645 bgp_dump
->type
= type
;
648 bgp_dump
->interval
= interval
;
651 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
653 /* Create interval thread. */
654 bgp_dump_interval_add(bgp_dump
, interval
);
656 /* This should be called when interval is expired. */
657 bgp_dump_open_file(bgp_dump
);
662 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
664 /* Removing file name. */
665 if (bgp_dump
->filename
) {
666 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
667 bgp_dump
->filename
= NULL
;
672 fclose(bgp_dump
->fp
);
676 /* Removing interval thread. */
677 if (bgp_dump
->t_interval
) {
678 thread_cancel(bgp_dump
->t_interval
);
679 bgp_dump
->t_interval
= NULL
;
682 bgp_dump
->interval
= 0;
684 /* Removing interval string. */
685 if (bgp_dump
->interval_str
) {
686 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
687 bgp_dump
->interval_str
= NULL
;
695 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
698 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
699 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
700 "Dump whole BGP routing table\n"
702 "Interval of output\n")
704 int idx_dump_routes
= 2;
706 int idx_interval
= 4;
707 int bgp_dump_type
= 0;
708 const char *interval
= NULL
;
709 struct bgp_dump
*bgp_dump_struct
= NULL
;
710 const struct bgp_dump_type_map
*map
= NULL
;
712 for (map
= bgp_dump_type_map
; map
->str
; map
++)
713 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
714 bgp_dump_type
= map
->type
;
716 switch (bgp_dump_type
) {
718 case BGP_DUMP_ALL_ET
:
719 bgp_dump_struct
= &bgp_dump_all
;
721 case BGP_DUMP_UPDATES
:
722 case BGP_DUMP_UPDATES_ET
:
723 bgp_dump_struct
= &bgp_dump_updates
;
725 case BGP_DUMP_ROUTES
:
727 bgp_dump_struct
= &bgp_dump_routes
;
731 /* When an interval is given */
732 if (argc
== idx_interval
+ 1)
733 interval
= argv
[idx_interval
]->arg
;
735 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
736 argv
[idx_path
]->arg
, interval
);
739 DEFUN (no_dump_bgp_all
,
741 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
744 "Stop BGP packet dump\n"
745 "Stop dump process all\n"
746 "Stop dump process all-et\n"
747 "Stop dump process updates\n"
748 "Stop dump process updates-et\n"
749 "Stop dump process route-mrt\n"
751 "Interval of output\n")
753 int idx_dump_routes
= 3;
754 int bgp_dump_type
= 0;
755 const struct bgp_dump_type_map
*map
= NULL
;
756 struct bgp_dump
*bgp_dump_struct
= NULL
;
758 for (map
= bgp_dump_type_map
; map
->str
; map
++)
759 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
760 bgp_dump_type
= map
->type
;
762 switch (bgp_dump_type
) {
764 case BGP_DUMP_ALL_ET
:
765 bgp_dump_struct
= &bgp_dump_all
;
767 case BGP_DUMP_UPDATES
:
768 case BGP_DUMP_UPDATES_ET
:
769 bgp_dump_struct
= &bgp_dump_updates
;
771 case BGP_DUMP_ROUTES
:
773 bgp_dump_struct
= &bgp_dump_routes
;
777 return bgp_dump_unset(bgp_dump_struct
);
780 /* BGP node structure. */
781 static struct cmd_node bgp_dump_node
= {DUMP_NODE
, "", 1};
785 config_time2str (unsigned int interval
)
787 static char buf
[BUFSIZ
];
793 sprintf (buf
, "%dh", interval
/ 3600);
798 sprintf (buf
+ strlen (buf
), "%dm", interval
/60);
803 sprintf (buf
+ strlen (buf
), "%d", interval
);
809 static int config_write_bgp_dump(struct vty
*vty
)
811 if (bgp_dump_all
.filename
) {
812 const char *type_str
= "all";
813 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
816 if (bgp_dump_all
.interval_str
)
817 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
818 bgp_dump_all
.filename
,
819 bgp_dump_all
.interval_str
);
821 vty_out(vty
, "dump bgp %s %s\n", type_str
,
822 bgp_dump_all
.filename
);
824 if (bgp_dump_updates
.filename
) {
825 const char *type_str
= "updates";
826 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
827 type_str
= "updates-et";
829 if (bgp_dump_updates
.interval_str
)
830 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
831 bgp_dump_updates
.filename
,
832 bgp_dump_updates
.interval_str
);
834 vty_out(vty
, "dump bgp %s %s\n", type_str
,
835 bgp_dump_updates
.filename
);
837 if (bgp_dump_routes
.filename
) {
838 if (bgp_dump_routes
.interval_str
)
839 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
840 bgp_dump_routes
.filename
,
841 bgp_dump_routes
.interval_str
);
843 vty_out(vty
, "dump bgp routes-mrt %s\n",
844 bgp_dump_routes
.filename
);
849 /* Initialize BGP packet dump functionality. */
850 void bgp_dump_init(void)
852 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
853 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
854 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
857 stream_new((BGP_MAX_PACKET_SIZE
<< 1) + BGP_DUMP_MSG_HEADER
858 + BGP_DUMP_HEADER_SIZE
);
860 install_node(&bgp_dump_node
, config_write_bgp_dump
);
862 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
863 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
866 void bgp_dump_finish(void)
868 bgp_dump_unset(&bgp_dump_all
);
869 bgp_dump_unset(&bgp_dump_updates
);
870 bgp_dump_unset(&bgp_dump_routes
);
872 stream_free(bgp_dump_obuf
);
873 bgp_dump_obuf
= NULL
;