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 tm
= localtime(&clock
);
117 if (bgp_dump
->filename
[0] != DIRECTORY_SEP
) {
118 sprintf(fullpath
, "%s/%s", vty_get_cwd(), bgp_dump
->filename
);
119 ret
= strftime(realpath
, MAXPATHLEN
, fullpath
, tm
);
121 ret
= strftime(realpath
, MAXPATHLEN
, bgp_dump
->filename
, tm
);
124 flog_warn(EC_BGP_DUMP
, "bgp_dump_open_file: strftime error");
129 fclose(bgp_dump
->fp
);
132 oldumask
= umask(0777 & ~LOGFILE_MASK
);
133 bgp_dump
->fp
= fopen(realpath
, "w");
135 if (bgp_dump
->fp
== NULL
) {
136 flog_warn(EC_BGP_DUMP
, "bgp_dump_open_file: %s: %s", realpath
,
146 static int bgp_dump_interval_add(struct bgp_dump
*bgp_dump
, int interval
)
153 /* Periodic dump every interval seconds */
154 if ((interval
< 86400) && ((86400 % interval
) == 0)) {
155 /* Dump at predictable times: if a day has a whole
157 * intervals, dump every interval seconds starting from
162 secs_into_day
= tm
->tm_sec
+ 60 * tm
->tm_min
163 + 60 * 60 * tm
->tm_hour
;
165 - secs_into_day
% interval
; /* always > 0 */
167 bgp_dump
->t_interval
= NULL
;
168 thread_add_timer(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
169 interval
, &bgp_dump
->t_interval
);
171 /* One-off dump: execute immediately, don't affect any scheduled
173 bgp_dump
->t_interval
= NULL
;
174 thread_add_event(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
175 0, &bgp_dump
->t_interval
);
181 /* Dump common header. */
182 static void bgp_dump_header(struct stream
*obuf
, int type
, int subtype
,
185 struct timeval clock
;
189 if ((dump_type
== BGP_DUMP_ALL_ET
|| dump_type
== BGP_DUMP_UPDATES_ET
)
190 && type
== MSG_PROTOCOL_BGP4MP
)
191 type
= MSG_PROTOCOL_BGP4MP_ET
;
193 gettimeofday(&clock
, NULL
);
196 msecs
= clock
.tv_usec
;
198 /* Put dump packet header. */
199 stream_putl(obuf
, secs
);
200 stream_putw(obuf
, type
);
201 stream_putw(obuf
, subtype
);
202 stream_putl(obuf
, 0); /* len */
204 /* Adding microseconds for the MRT Extended Header */
205 if (type
== MSG_PROTOCOL_BGP4MP_ET
)
206 stream_putl(obuf
, msecs
);
209 static void bgp_dump_set_size(struct stream
*s
, int type
)
212 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
213 * "The Microsecond Timestamp is included in the computation
214 * of the Length field value." (RFC6396 2011)
216 stream_putl_at(s
, 8, stream_get_endp(s
) - BGP_DUMP_HEADER_SIZE
);
219 static void bgp_dump_routes_index_table(struct bgp
*bgp
)
222 struct listnode
*node
;
226 obuf
= bgp_dump_obuf
;
230 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_PEER_INDEX_TABLE
,
233 /* Collector BGP ID */
234 stream_put_in_addr(obuf
, &bgp
->router_id
);
237 if (bgp
->name_pretty
) {
238 stream_putw(obuf
, strlen(bgp
->name_pretty
));
239 stream_put(obuf
, bgp
->name_pretty
, strlen(bgp
->name_pretty
));
241 stream_putw(obuf
, 0);
244 /* Peer count ( plus one extra internal peer ) */
245 stream_putw(obuf
, listcount(bgp
->peer
) + 1);
247 /* Populate fake peer at index 0, for locally originated routes */
248 /* Peer type (IPv4) */
250 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
251 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
252 /* Peer BGP ID (0.0.0.0) */
253 stream_putl(obuf
, 0);
254 /* Peer IP address (0.0.0.0) */
255 stream_putl(obuf
, 0);
257 stream_putl(obuf
, 0);
259 /* Walk down all peers */
260 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
263 if (sockunion_family(&peer
->su
) == AF_INET
) {
266 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
267 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
268 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
271 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
272 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
276 stream_put_in_addr(obuf
, &peer
->remote_id
);
278 /* Peer's IP address */
279 if (sockunion_family(&peer
->su
) == AF_INET
) {
280 stream_put_in_addr(obuf
, &peer
->su
.sin
.sin_addr
);
281 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
282 stream_write(obuf
, (uint8_t *)&peer
->su
.sin6
.sin6_addr
,
286 /* Peer's AS number. */
287 /* Note that, as this is an AS4 compliant quagga, the RIB is
289 stream_putl(obuf
, peer
->as
);
291 /* Store the peer number for this peer */
292 peer
->table_dump_index
= peerno
;
296 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
298 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
299 fflush(bgp_dump_routes
.fp
);
303 static struct bgp_path_info
*
304 bgp_dump_route_node_record(int afi
, struct bgp_node
*rn
,
305 struct bgp_path_info
*path
, unsigned int seq
)
311 obuf
= bgp_dump_obuf
;
316 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
317 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
319 else if (afi
== AFI_IP6
)
320 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
321 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
324 /* Sequence number */
325 stream_putl(obuf
, seq
);
328 stream_putc(obuf
, rn
->p
.prefixlen
);
332 /* We'll dump only the useful bits (those not 0), but have to
334 stream_write(obuf
, (uint8_t *)&rn
->p
.u
.prefix4
,
335 (rn
->p
.prefixlen
+ 7) / 8);
336 } else if (afi
== AFI_IP6
) {
337 /* We'll dump only the useful bits (those not 0), but have to
339 stream_write(obuf
, (uint8_t *)&rn
->p
.u
.prefix6
,
340 (rn
->p
.prefixlen
+ 7) / 8);
343 /* Save where we are now, so we can overwride the entry count later */
344 sizep
= stream_get_endp(obuf
);
347 uint16_t entry_count
= 0;
349 /* Entry count, note that this is overwritten later */
350 stream_putw(obuf
, 0);
352 endp
= stream_get_endp(obuf
);
353 for (; path
; path
= path
->next
) {
357 stream_putw(obuf
, path
->peer
->table_dump_index
);
360 stream_putl(obuf
, time(NULL
) - (bgp_clock() - path
->uptime
));
362 /* Dump attribute. */
363 /* Skip prefix & AFI/SAFI for MP_NLRI */
364 bgp_dump_routes_attr(obuf
, path
->attr
, &rn
->p
);
366 cur_endp
= stream_get_endp(obuf
);
367 if (cur_endp
> BGP_MAX_PACKET_SIZE
+ BGP_DUMP_MSG_HEADER
368 + BGP_DUMP_HEADER_SIZE
) {
369 stream_set_endp(obuf
, endp
);
377 /* Overwrite the entry count, now that we know the right number */
378 stream_putw_at(obuf
, sizep
, entry_count
);
380 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
381 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
387 /* Runs under child process. */
388 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
391 struct bgp_path_info
*path
;
394 struct bgp_table
*table
;
396 bgp
= bgp_get_default();
400 if (bgp_dump_routes
.fp
== NULL
)
403 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
404 so this should only be done on the first call to
405 bgp_dump_routes_func.
406 ( this function will be called once for ipv4 and once for ipv6 ) */
408 bgp_dump_routes_index_table(bgp
);
410 /* Walk down each BGP route. */
411 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
413 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
414 path
= bgp_node_get_bgp_path_info(rn
);
416 path
= bgp_dump_route_node_record(afi
, rn
, path
, seq
);
421 fflush(bgp_dump_routes
.fp
);
426 static int bgp_dump_interval_func(struct thread
*t
)
428 struct bgp_dump
*bgp_dump
;
429 bgp_dump
= THREAD_ARG(t
);
430 bgp_dump
->t_interval
= NULL
;
432 /* Reschedule dump even if file couldn't be opened this time... */
433 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
434 /* In case of bgp_dump_routes, we need special route dump
436 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
437 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
438 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
439 /* Close the file now. For a RIB dump there's no point
441 * it open until the next scheduled dump starts. */
442 fclose(bgp_dump
->fp
);
447 /* if interval is set reschedule */
448 if (bgp_dump
->interval
> 0)
449 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
454 /* Dump common information. */
455 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
458 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
460 /* Source AS number and Destination AS number. */
461 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
462 stream_putl(obuf
, peer
->as
);
463 stream_putl(obuf
, peer
->local_as
);
465 stream_putw(obuf
, peer
->as
);
466 stream_putw(obuf
, peer
->local_as
);
469 if (peer
->su
.sa
.sa_family
== AF_INET
) {
470 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
471 stream_putw(obuf
, AFI_IP
);
473 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
476 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
479 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
480 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
481 /* Interface Index and Address family. */
482 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
483 stream_putw(obuf
, AFI_IP6
);
485 /* Source IP Address and Destination IP Address. */
486 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
489 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
492 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
496 /* Dump BGP status change. */
497 int bgp_dump_state(struct peer
*peer
)
501 /* If dump file pointer is disabled return immediately. */
502 if (bgp_dump_all
.fp
== NULL
)
505 /* Make dump stream. */
506 obuf
= bgp_dump_obuf
;
509 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
511 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
513 stream_putw(obuf
, peer
->ostatus
);
514 stream_putw(obuf
, peer
->status
);
517 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
519 /* Write to the stream. */
520 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
521 fflush(bgp_dump_all
.fp
);
525 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
526 struct stream
*packet
)
530 /* If dump file pointer is disabled return immediately. */
531 if (bgp_dump
->fp
== NULL
)
534 /* Make dump stream. */
535 obuf
= bgp_dump_obuf
;
538 /* Dump header and common part. */
539 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
540 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
543 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
546 bgp_dump_common(obuf
, peer
, 0);
548 /* Packet contents. */
549 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
552 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
554 /* Write to the stream. */
555 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
556 fflush(bgp_dump
->fp
);
559 /* Called from bgp_packet.c when BGP packet is received. */
560 static int bgp_dump_packet(struct peer
*peer
, uint8_t type
, bgp_size_t size
,
561 struct stream
*packet
)
564 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
566 /* bgp_dump_updates. */
567 if (type
== BGP_MSG_UPDATE
)
568 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
572 static unsigned int bgp_dump_parse_time(const char *str
)
587 for (i
= 0; i
< len
; i
++) {
588 if (isdigit((unsigned char)str
[i
])) {
590 time
+= str
[i
] - '0';
591 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
596 total
+= time
* 60 * 60;
599 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
611 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
612 enum bgp_dump_type type
, const char *path
,
613 const char *interval_str
)
615 unsigned int interval
;
617 /* Don't schedule duplicate dumps if the dump command is given twice */
618 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
619 && type
== bgp_dump
->type
) {
621 if (bgp_dump
->interval_str
622 && strcmp(bgp_dump
->interval_str
, interval_str
)
626 if (!bgp_dump
->interval_str
)
631 /* Removing previous config */
632 bgp_dump_unset(bgp_dump
);
635 /* Check interval string. */
636 interval
= bgp_dump_parse_time(interval_str
);
638 vty_out(vty
, "Malformed interval string\n");
639 return CMD_WARNING_CONFIG_FAILED
;
642 /* Setting interval string */
643 bgp_dump
->interval_str
=
644 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
650 bgp_dump
->type
= type
;
653 bgp_dump
->interval
= interval
;
656 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
658 /* Create interval thread. */
659 bgp_dump_interval_add(bgp_dump
, interval
);
661 /* This should be called when interval is expired. */
662 bgp_dump_open_file(bgp_dump
);
667 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
669 /* Removing file name. */
670 if (bgp_dump
->filename
) {
671 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
672 bgp_dump
->filename
= NULL
;
677 fclose(bgp_dump
->fp
);
681 /* Removing interval thread. */
682 if (bgp_dump
->t_interval
) {
683 thread_cancel(bgp_dump
->t_interval
);
684 bgp_dump
->t_interval
= NULL
;
687 bgp_dump
->interval
= 0;
689 /* Removing interval string. */
690 if (bgp_dump
->interval_str
) {
691 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
692 bgp_dump
->interval_str
= NULL
;
700 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
703 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
704 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
705 "Dump whole BGP routing table\n"
707 "Interval of output\n")
709 int idx_dump_routes
= 2;
711 int idx_interval
= 4;
712 int bgp_dump_type
= 0;
713 const char *interval
= NULL
;
714 struct bgp_dump
*bgp_dump_struct
= NULL
;
715 const struct bgp_dump_type_map
*map
= NULL
;
717 for (map
= bgp_dump_type_map
; map
->str
; map
++)
718 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
719 bgp_dump_type
= map
->type
;
721 switch (bgp_dump_type
) {
723 case BGP_DUMP_ALL_ET
:
724 bgp_dump_struct
= &bgp_dump_all
;
726 case BGP_DUMP_UPDATES
:
727 case BGP_DUMP_UPDATES_ET
:
728 bgp_dump_struct
= &bgp_dump_updates
;
730 case BGP_DUMP_ROUTES
:
732 bgp_dump_struct
= &bgp_dump_routes
;
736 /* When an interval is given */
737 if (argc
== idx_interval
+ 1)
738 interval
= argv
[idx_interval
]->arg
;
740 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
741 argv
[idx_path
]->arg
, interval
);
744 DEFUN (no_dump_bgp_all
,
746 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
749 "Stop BGP packet dump\n"
750 "Stop dump process all\n"
751 "Stop dump process all-et\n"
752 "Stop dump process updates\n"
753 "Stop dump process updates-et\n"
754 "Stop dump process route-mrt\n"
756 "Interval of output\n")
758 int idx_dump_routes
= 3;
759 int bgp_dump_type
= 0;
760 const struct bgp_dump_type_map
*map
= NULL
;
761 struct bgp_dump
*bgp_dump_struct
= NULL
;
763 for (map
= bgp_dump_type_map
; map
->str
; map
++)
764 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
765 bgp_dump_type
= map
->type
;
767 switch (bgp_dump_type
) {
769 case BGP_DUMP_ALL_ET
:
770 bgp_dump_struct
= &bgp_dump_all
;
772 case BGP_DUMP_UPDATES
:
773 case BGP_DUMP_UPDATES_ET
:
774 bgp_dump_struct
= &bgp_dump_updates
;
776 case BGP_DUMP_ROUTES
:
778 bgp_dump_struct
= &bgp_dump_routes
;
782 return bgp_dump_unset(bgp_dump_struct
);
785 /* BGP node structure. */
786 static struct cmd_node bgp_dump_node
= {DUMP_NODE
, "", 1};
790 config_time2str (unsigned int interval
)
792 static char buf
[BUFSIZ
];
798 sprintf (buf
, "%dh", interval
/ 3600);
803 sprintf (buf
+ strlen (buf
), "%dm", interval
/60);
808 sprintf (buf
+ strlen (buf
), "%d", interval
);
814 static int config_write_bgp_dump(struct vty
*vty
)
816 if (bgp_dump_all
.filename
) {
817 const char *type_str
= "all";
818 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
821 if (bgp_dump_all
.interval_str
)
822 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
823 bgp_dump_all
.filename
,
824 bgp_dump_all
.interval_str
);
826 vty_out(vty
, "dump bgp %s %s\n", type_str
,
827 bgp_dump_all
.filename
);
829 if (bgp_dump_updates
.filename
) {
830 const char *type_str
= "updates";
831 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
832 type_str
= "updates-et";
834 if (bgp_dump_updates
.interval_str
)
835 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
836 bgp_dump_updates
.filename
,
837 bgp_dump_updates
.interval_str
);
839 vty_out(vty
, "dump bgp %s %s\n", type_str
,
840 bgp_dump_updates
.filename
);
842 if (bgp_dump_routes
.filename
) {
843 if (bgp_dump_routes
.interval_str
)
844 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
845 bgp_dump_routes
.filename
,
846 bgp_dump_routes
.interval_str
);
848 vty_out(vty
, "dump bgp routes-mrt %s\n",
849 bgp_dump_routes
.filename
);
854 /* Initialize BGP packet dump functionality. */
855 void bgp_dump_init(void)
857 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
858 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
859 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
862 stream_new((BGP_MAX_PACKET_SIZE
<< 1) + BGP_DUMP_MSG_HEADER
863 + BGP_DUMP_HEADER_SIZE
);
865 install_node(&bgp_dump_node
, config_write_bgp_dump
);
867 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
868 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
870 hook_register(bgp_packet_dump
, bgp_dump_packet
);
871 hook_register(peer_status_changed
, bgp_dump_state
);
874 void bgp_dump_finish(void)
876 bgp_dump_unset(&bgp_dump_all
);
877 bgp_dump_unset(&bgp_dump_updates
);
878 bgp_dump_unset(&bgp_dump_routes
);
880 stream_free(bgp_dump_obuf
);
881 bgp_dump_obuf
= NULL
;
882 hook_unregister(bgp_packet_dump
, bgp_dump_packet
);
883 hook_unregister(peer_status_changed
, bgp_dump_state
);