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 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
161 localtime_r(&t
, &tm
);
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
)
310 const struct prefix
*p
= bgp_node_get_prefix(rn
);
312 obuf
= bgp_dump_obuf
;
317 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
318 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
320 else if (afi
== AFI_IP6
)
321 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
322 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
325 /* Sequence number */
326 stream_putl(obuf
, seq
);
329 stream_putc(obuf
, p
->prefixlen
);
333 /* We'll dump only the useful bits (those not 0), but have to
335 stream_write(obuf
, (uint8_t *)&p
->u
.prefix4
,
336 (p
->prefixlen
+ 7) / 8);
337 } else if (afi
== AFI_IP6
) {
338 /* We'll dump only the useful bits (those not 0), but have to
340 stream_write(obuf
, (uint8_t *)&p
->u
.prefix6
,
341 (p
->prefixlen
+ 7) / 8);
344 /* Save where we are now, so we can overwride the entry count later */
345 sizep
= stream_get_endp(obuf
);
348 uint16_t entry_count
= 0;
350 /* Entry count, note that this is overwritten later */
351 stream_putw(obuf
, 0);
353 endp
= stream_get_endp(obuf
);
354 for (; path
; path
= path
->next
) {
358 stream_putw(obuf
, path
->peer
->table_dump_index
);
361 stream_putl(obuf
, time(NULL
) - (bgp_clock() - path
->uptime
));
363 /* Dump attribute. */
364 /* Skip prefix & AFI/SAFI for MP_NLRI */
365 bgp_dump_routes_attr(obuf
, path
->attr
, p
);
367 cur_endp
= stream_get_endp(obuf
);
368 if (cur_endp
> BGP_MAX_PACKET_SIZE
+ BGP_DUMP_MSG_HEADER
369 + BGP_DUMP_HEADER_SIZE
) {
370 stream_set_endp(obuf
, endp
);
378 /* Overwrite the entry count, now that we know the right number */
379 stream_putw_at(obuf
, sizep
, entry_count
);
381 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
382 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
388 /* Runs under child process. */
389 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
392 struct bgp_path_info
*path
;
395 struct bgp_table
*table
;
397 bgp
= bgp_get_default();
401 if (bgp_dump_routes
.fp
== NULL
)
404 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
405 so this should only be done on the first call to
406 bgp_dump_routes_func.
407 ( this function will be called once for ipv4 and once for ipv6 ) */
409 bgp_dump_routes_index_table(bgp
);
411 /* Walk down each BGP route. */
412 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
414 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
415 path
= bgp_node_get_bgp_path_info(rn
);
417 path
= bgp_dump_route_node_record(afi
, rn
, path
, seq
);
422 fflush(bgp_dump_routes
.fp
);
427 static int bgp_dump_interval_func(struct thread
*t
)
429 struct bgp_dump
*bgp_dump
;
430 bgp_dump
= THREAD_ARG(t
);
431 bgp_dump
->t_interval
= NULL
;
433 /* Reschedule dump even if file couldn't be opened this time... */
434 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
435 /* In case of bgp_dump_routes, we need special route dump
437 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
438 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
439 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
440 /* Close the file now. For a RIB dump there's no point
442 * it open until the next scheduled dump starts. */
443 fclose(bgp_dump
->fp
);
448 /* if interval is set reschedule */
449 if (bgp_dump
->interval
> 0)
450 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
455 /* Dump common information. */
456 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
459 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
461 /* Source AS number and Destination AS number. */
462 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
463 stream_putl(obuf
, peer
->as
);
464 stream_putl(obuf
, peer
->local_as
);
466 stream_putw(obuf
, peer
->as
);
467 stream_putw(obuf
, peer
->local_as
);
470 if (peer
->su
.sa
.sa_family
== AF_INET
) {
471 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
472 stream_putw(obuf
, AFI_IP
);
474 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
477 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
480 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
481 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
482 /* Interface Index and Address family. */
483 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
484 stream_putw(obuf
, AFI_IP6
);
486 /* Source IP Address and Destination IP Address. */
487 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
490 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
493 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
497 /* Dump BGP status change. */
498 int bgp_dump_state(struct peer
*peer
)
502 /* If dump file pointer is disabled return immediately. */
503 if (bgp_dump_all
.fp
== NULL
)
506 /* Make dump stream. */
507 obuf
= bgp_dump_obuf
;
510 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
512 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
514 stream_putw(obuf
, peer
->ostatus
);
515 stream_putw(obuf
, peer
->status
);
518 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
520 /* Write to the stream. */
521 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
522 fflush(bgp_dump_all
.fp
);
526 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
527 struct stream
*packet
)
531 /* If dump file pointer is disabled return immediately. */
532 if (bgp_dump
->fp
== NULL
)
535 /* Make dump stream. */
536 obuf
= bgp_dump_obuf
;
539 /* Dump header and common part. */
540 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
541 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
544 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
547 bgp_dump_common(obuf
, peer
, 0);
549 /* Packet contents. */
550 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
553 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
555 /* Write to the stream. */
556 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
557 fflush(bgp_dump
->fp
);
560 /* Called from bgp_packet.c when BGP packet is received. */
561 static int bgp_dump_packet(struct peer
*peer
, uint8_t type
, bgp_size_t size
,
562 struct stream
*packet
)
565 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
567 /* bgp_dump_updates. */
568 if (type
== BGP_MSG_UPDATE
)
569 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
573 static unsigned int bgp_dump_parse_time(const char *str
)
588 for (i
= 0; i
< len
; i
++) {
589 if (isdigit((unsigned char)str
[i
])) {
591 time
+= str
[i
] - '0';
592 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
597 total
+= time
* 60 * 60;
600 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
612 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
613 enum bgp_dump_type type
, const char *path
,
614 const char *interval_str
)
616 unsigned int interval
;
618 /* Don't schedule duplicate dumps if the dump command is given twice */
619 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
620 && type
== bgp_dump
->type
) {
622 if (bgp_dump
->interval_str
623 && strcmp(bgp_dump
->interval_str
, interval_str
)
627 if (!bgp_dump
->interval_str
)
632 /* Removing previous config */
633 bgp_dump_unset(bgp_dump
);
636 /* Check interval string. */
637 interval
= bgp_dump_parse_time(interval_str
);
639 vty_out(vty
, "Malformed interval string\n");
640 return CMD_WARNING_CONFIG_FAILED
;
643 /* Setting interval string */
644 bgp_dump
->interval_str
=
645 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
651 bgp_dump
->type
= type
;
654 bgp_dump
->interval
= interval
;
657 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
659 /* Create interval thread. */
660 bgp_dump_interval_add(bgp_dump
, interval
);
662 /* This should be called when interval is expired. */
663 bgp_dump_open_file(bgp_dump
);
668 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
670 /* Removing file name. */
671 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
675 fclose(bgp_dump
->fp
);
679 /* Removing interval thread. */
680 if (bgp_dump
->t_interval
) {
681 thread_cancel(bgp_dump
->t_interval
);
682 bgp_dump
->t_interval
= NULL
;
685 bgp_dump
->interval
= 0;
687 /* Removing interval string. */
688 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
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 static int config_write_bgp_dump(struct vty
*vty
);
781 /* BGP node structure. */
782 static struct cmd_node bgp_dump_node
= {
786 .config_write
= config_write_bgp_dump
,
791 config_time2str (unsigned int interval
)
793 static char buf
[BUFSIZ
];
799 sprintf (buf
, "%dh", interval
/ 3600);
804 sprintf (buf
+ strlen (buf
), "%dm", interval
/60);
809 sprintf (buf
+ strlen (buf
), "%d", interval
);
815 static int config_write_bgp_dump(struct vty
*vty
)
817 if (bgp_dump_all
.filename
) {
818 const char *type_str
= "all";
819 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
822 if (bgp_dump_all
.interval_str
)
823 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
824 bgp_dump_all
.filename
,
825 bgp_dump_all
.interval_str
);
827 vty_out(vty
, "dump bgp %s %s\n", type_str
,
828 bgp_dump_all
.filename
);
830 if (bgp_dump_updates
.filename
) {
831 const char *type_str
= "updates";
832 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
833 type_str
= "updates-et";
835 if (bgp_dump_updates
.interval_str
)
836 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
837 bgp_dump_updates
.filename
,
838 bgp_dump_updates
.interval_str
);
840 vty_out(vty
, "dump bgp %s %s\n", type_str
,
841 bgp_dump_updates
.filename
);
843 if (bgp_dump_routes
.filename
) {
844 if (bgp_dump_routes
.interval_str
)
845 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
846 bgp_dump_routes
.filename
,
847 bgp_dump_routes
.interval_str
);
849 vty_out(vty
, "dump bgp routes-mrt %s\n",
850 bgp_dump_routes
.filename
);
855 /* Initialize BGP packet dump functionality. */
856 void bgp_dump_init(void)
858 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
859 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
860 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
863 stream_new((BGP_MAX_PACKET_SIZE
<< 1) + BGP_DUMP_MSG_HEADER
864 + BGP_DUMP_HEADER_SIZE
);
866 install_node(&bgp_dump_node
);
868 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
869 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
871 hook_register(bgp_packet_dump
, bgp_dump_packet
);
872 hook_register(peer_status_changed
, bgp_dump_state
);
875 void bgp_dump_finish(void)
877 bgp_dump_unset(&bgp_dump_all
);
878 bgp_dump_unset(&bgp_dump_updates
);
879 bgp_dump_unset(&bgp_dump_routes
);
881 stream_free(bgp_dump_obuf
);
882 bgp_dump_obuf
= NULL
;
883 hook_unregister(bgp_packet_dump
, bgp_dump_packet
);
884 hook_unregister(peer_status_changed
, bgp_dump_state
);