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 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 thread_add_event(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
174 0, &bgp_dump
->t_interval
);
180 /* Dump common header. */
181 static void bgp_dump_header(struct stream
*obuf
, int type
, int subtype
,
184 struct timeval clock
;
188 if ((dump_type
== BGP_DUMP_ALL_ET
|| dump_type
== BGP_DUMP_UPDATES_ET
)
189 && type
== MSG_PROTOCOL_BGP4MP
)
190 type
= MSG_PROTOCOL_BGP4MP_ET
;
192 gettimeofday(&clock
, NULL
);
195 msecs
= clock
.tv_usec
;
197 /* Put dump packet header. */
198 stream_putl(obuf
, secs
);
199 stream_putw(obuf
, type
);
200 stream_putw(obuf
, subtype
);
201 stream_putl(obuf
, 0); /* len */
203 /* Adding microseconds for the MRT Extended Header */
204 if (type
== MSG_PROTOCOL_BGP4MP_ET
)
205 stream_putl(obuf
, msecs
);
208 static void bgp_dump_set_size(struct stream
*s
, int type
)
211 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
212 * "The Microsecond Timestamp is included in the computation
213 * of the Length field value." (RFC6396 2011)
215 stream_putl_at(s
, 8, stream_get_endp(s
) - BGP_DUMP_HEADER_SIZE
);
218 static void bgp_dump_routes_index_table(struct bgp
*bgp
)
221 struct listnode
*node
;
225 obuf
= bgp_dump_obuf
;
229 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_PEER_INDEX_TABLE
,
232 /* Collector BGP ID */
233 stream_put_in_addr(obuf
, &bgp
->router_id
);
236 if (bgp
->name_pretty
) {
237 stream_putw(obuf
, strlen(bgp
->name_pretty
));
238 stream_put(obuf
, bgp
->name_pretty
, strlen(bgp
->name_pretty
));
240 stream_putw(obuf
, 0);
243 /* Peer count ( plus one extra internal peer ) */
244 stream_putw(obuf
, listcount(bgp
->peer
) + 1);
246 /* Populate fake peer at index 0, for locally originated routes */
247 /* Peer type (IPv4) */
249 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
250 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
251 /* Peer BGP ID (0.0.0.0) */
252 stream_putl(obuf
, 0);
253 /* Peer IP address (0.0.0.0) */
254 stream_putl(obuf
, 0);
256 stream_putl(obuf
, 0);
258 /* Walk down all peers */
259 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
262 if (sockunion_family(&peer
->su
) == AF_INET
) {
265 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
266 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
267 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
270 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
271 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
275 stream_put_in_addr(obuf
, &peer
->remote_id
);
277 /* Peer's IP address */
278 if (sockunion_family(&peer
->su
) == AF_INET
) {
279 stream_put_in_addr(obuf
, &peer
->su
.sin
.sin_addr
);
280 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
281 stream_write(obuf
, (uint8_t *)&peer
->su
.sin6
.sin6_addr
,
285 /* Peer's AS number. */
286 /* Note that, as this is an AS4 compliant quagga, the RIB is
288 stream_putl(obuf
, peer
->as
);
290 /* Store the peer number for this peer */
291 peer
->table_dump_index
= peerno
;
295 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
297 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
298 fflush(bgp_dump_routes
.fp
);
301 static int bgp_addpath_encode_rx(struct peer
*peer
, afi_t afi
, safi_t safi
)
304 return (CHECK_FLAG(peer
->af_cap
[afi
][safi
], PEER_CAP_ADDPATH_AF_RX_ADV
)
305 && CHECK_FLAG(peer
->af_cap
[afi
][safi
],
306 PEER_CAP_ADDPATH_AF_TX_RCV
));
309 static struct bgp_path_info
*
310 bgp_dump_route_node_record(int afi
, struct bgp_dest
*dest
,
311 struct bgp_path_info
*path
, unsigned int seq
)
317 const struct prefix
*p
= bgp_dest_get_prefix(dest
);
319 obuf
= bgp_dump_obuf
;
322 addpath_encoded
= bgp_addpath_encode_rx(path
->peer
, afi
, SAFI_UNICAST
);
325 if (afi
== AFI_IP
&& addpath_encoded
)
326 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
327 TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH
,
329 else if (afi
== AFI_IP
)
330 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
331 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
333 else if (afi
== AFI_IP6
&& addpath_encoded
)
334 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
335 TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH
,
337 else if (afi
== AFI_IP6
)
338 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
339 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
342 /* Sequence number */
343 stream_putl(obuf
, seq
);
346 stream_putc(obuf
, p
->prefixlen
);
350 /* We'll dump only the useful bits (those not 0), but have to
352 stream_write(obuf
, (uint8_t *)&p
->u
.prefix4
,
353 (p
->prefixlen
+ 7) / 8);
354 } else if (afi
== AFI_IP6
) {
355 /* We'll dump only the useful bits (those not 0), but have to
357 stream_write(obuf
, (uint8_t *)&p
->u
.prefix6
,
358 (p
->prefixlen
+ 7) / 8);
361 /* Save where we are now, so we can overwride the entry count later */
362 sizep
= stream_get_endp(obuf
);
365 uint16_t entry_count
= 0;
367 /* Entry count, note that this is overwritten later */
368 stream_putw(obuf
, 0);
370 endp
= stream_get_endp(obuf
);
371 for (; path
; path
= path
->next
) {
375 stream_putw(obuf
, path
->peer
->table_dump_index
);
378 stream_putl(obuf
, time(NULL
) - (bgp_clock() - path
->uptime
));
381 if (addpath_encoded
) {
382 stream_putl(obuf
, path
->addpath_rx_id
);
385 /* Dump attribute. */
386 /* Skip prefix & AFI/SAFI for MP_NLRI */
387 bgp_dump_routes_attr(obuf
, path
->attr
, p
);
389 cur_endp
= stream_get_endp(obuf
);
390 if (cur_endp
> BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
391 + BGP_DUMP_MSG_HEADER
392 + BGP_DUMP_HEADER_SIZE
) {
393 stream_set_endp(obuf
, endp
);
401 /* Overwrite the entry count, now that we know the right number */
402 stream_putw_at(obuf
, sizep
, entry_count
);
404 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
405 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
411 /* Runs under child process. */
412 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
415 struct bgp_path_info
*path
;
416 struct bgp_dest
*dest
;
418 struct bgp_table
*table
;
420 bgp
= bgp_get_default();
424 if (bgp_dump_routes
.fp
== NULL
)
427 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
428 so this should only be done on the first call to
429 bgp_dump_routes_func.
430 ( this function will be called once for ipv4 and once for ipv6 ) */
432 bgp_dump_routes_index_table(bgp
);
434 /* Walk down each BGP route. */
435 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
437 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
438 path
= bgp_dest_get_bgp_path_info(dest
);
440 path
= bgp_dump_route_node_record(afi
, dest
, path
, seq
);
445 fflush(bgp_dump_routes
.fp
);
450 static int bgp_dump_interval_func(struct thread
*t
)
452 struct bgp_dump
*bgp_dump
;
453 bgp_dump
= THREAD_ARG(t
);
455 /* Reschedule dump even if file couldn't be opened this time... */
456 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
457 /* In case of bgp_dump_routes, we need special route dump
459 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
460 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
461 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
462 /* Close the file now. For a RIB dump there's no point
464 * it open until the next scheduled dump starts. */
465 fclose(bgp_dump
->fp
);
470 /* if interval is set reschedule */
471 if (bgp_dump
->interval
> 0)
472 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
477 /* Dump common information. */
478 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
481 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
483 /* Source AS number and Destination AS number. */
484 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
485 stream_putl(obuf
, peer
->as
);
486 stream_putl(obuf
, peer
->local_as
);
488 stream_putw(obuf
, peer
->as
);
489 stream_putw(obuf
, peer
->local_as
);
492 if (peer
->su
.sa
.sa_family
== AF_INET
) {
493 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
494 stream_putw(obuf
, AFI_IP
);
496 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
499 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
502 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
503 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
504 /* Interface Index and Address family. */
505 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
506 stream_putw(obuf
, AFI_IP6
);
508 /* Source IP Address and Destination IP Address. */
509 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
512 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
515 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
519 /* Dump BGP status change. */
520 int bgp_dump_state(struct peer
*peer
)
524 /* If dump file pointer is disabled return immediately. */
525 if (bgp_dump_all
.fp
== NULL
)
528 /* Make dump stream. */
529 obuf
= bgp_dump_obuf
;
532 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
534 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
536 stream_putw(obuf
, peer
->ostatus
);
537 stream_putw(obuf
, peer
->status
);
540 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
542 /* Write to the stream. */
543 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
544 fflush(bgp_dump_all
.fp
);
548 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
549 struct stream
*packet
)
552 int addpath_encoded
= 0;
553 /* If dump file pointer is disabled return immediately. */
554 if (bgp_dump
->fp
== NULL
)
556 if (peer
->su
.sa
.sa_family
== AF_INET
) {
558 bgp_addpath_encode_rx(peer
, AFI_IP
, SAFI_UNICAST
);
559 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
561 bgp_addpath_encode_rx(peer
, AFI_IP6
, SAFI_UNICAST
);
564 /* Make dump stream. */
565 obuf
= bgp_dump_obuf
;
568 /* Dump header and common part. */
569 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
) && addpath_encoded
) {
570 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
571 BGP4MP_MESSAGE_AS4_ADDPATH
, bgp_dump
->type
);
572 } else if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
573 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
575 } else if (addpath_encoded
) {
576 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
577 BGP4MP_MESSAGE_ADDPATH
, bgp_dump
->type
);
579 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
582 bgp_dump_common(obuf
, peer
, 0);
584 /* Packet contents. */
585 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
588 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
590 /* Write to the stream. */
591 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
592 fflush(bgp_dump
->fp
);
595 /* Called from bgp_packet.c when BGP packet is received. */
596 static int bgp_dump_packet(struct peer
*peer
, uint8_t type
, bgp_size_t size
,
597 struct stream
*packet
)
600 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
602 /* bgp_dump_updates. */
603 if (type
== BGP_MSG_UPDATE
)
604 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
608 static unsigned int bgp_dump_parse_time(const char *str
)
623 for (i
= 0; i
< len
; i
++) {
624 if (isdigit((unsigned char)str
[i
])) {
626 time
+= str
[i
] - '0';
627 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
632 total
+= time
* 60 * 60;
635 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
647 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
648 enum bgp_dump_type type
, const char *path
,
649 const char *interval_str
)
651 unsigned int interval
;
653 /* Don't schedule duplicate dumps if the dump command is given twice */
654 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
655 && type
== bgp_dump
->type
) {
657 if (bgp_dump
->interval_str
658 && strcmp(bgp_dump
->interval_str
, interval_str
)
662 if (!bgp_dump
->interval_str
)
667 /* Removing previous config */
668 bgp_dump_unset(bgp_dump
);
671 /* Check interval string. */
672 interval
= bgp_dump_parse_time(interval_str
);
674 vty_out(vty
, "Malformed interval string\n");
675 return CMD_WARNING_CONFIG_FAILED
;
678 /* Setting interval string */
679 bgp_dump
->interval_str
=
680 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
686 bgp_dump
->type
= type
;
689 bgp_dump
->interval
= interval
;
692 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
694 /* Create interval thread. */
695 bgp_dump_interval_add(bgp_dump
, interval
);
697 /* This should be called when interval is expired. */
698 bgp_dump_open_file(bgp_dump
);
703 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
705 /* Removing file name. */
706 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
710 fclose(bgp_dump
->fp
);
714 /* Removing interval event. */
715 thread_cancel(&bgp_dump
->t_interval
);
717 bgp_dump
->interval
= 0;
719 /* Removing interval string. */
720 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
727 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
730 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
731 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
732 "Dump whole BGP routing table\n"
734 "Interval of output\n")
736 int idx_dump_routes
= 2;
738 int idx_interval
= 4;
739 int bgp_dump_type
= 0;
740 const char *interval
= NULL
;
741 struct bgp_dump
*bgp_dump_struct
= NULL
;
742 const struct bgp_dump_type_map
*map
= NULL
;
744 for (map
= bgp_dump_type_map
; map
->str
; map
++)
745 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
746 bgp_dump_type
= map
->type
;
748 switch (bgp_dump_type
) {
750 case BGP_DUMP_ALL_ET
:
751 bgp_dump_struct
= &bgp_dump_all
;
753 case BGP_DUMP_UPDATES
:
754 case BGP_DUMP_UPDATES_ET
:
755 bgp_dump_struct
= &bgp_dump_updates
;
757 case BGP_DUMP_ROUTES
:
759 bgp_dump_struct
= &bgp_dump_routes
;
763 /* When an interval is given */
764 if (argc
== idx_interval
+ 1)
765 interval
= argv
[idx_interval
]->arg
;
767 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
768 argv
[idx_path
]->arg
, interval
);
771 DEFUN (no_dump_bgp_all
,
773 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
776 "Stop BGP packet dump\n"
777 "Stop dump process all\n"
778 "Stop dump process all-et\n"
779 "Stop dump process updates\n"
780 "Stop dump process updates-et\n"
781 "Stop dump process route-mrt\n"
783 "Interval of output\n")
785 int idx_dump_routes
= 3;
786 int bgp_dump_type
= 0;
787 const struct bgp_dump_type_map
*map
= NULL
;
788 struct bgp_dump
*bgp_dump_struct
= NULL
;
790 for (map
= bgp_dump_type_map
; map
->str
; map
++)
791 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
792 bgp_dump_type
= map
->type
;
794 switch (bgp_dump_type
) {
796 case BGP_DUMP_ALL_ET
:
797 bgp_dump_struct
= &bgp_dump_all
;
799 case BGP_DUMP_UPDATES
:
800 case BGP_DUMP_UPDATES_ET
:
801 bgp_dump_struct
= &bgp_dump_updates
;
803 case BGP_DUMP_ROUTES
:
805 bgp_dump_struct
= &bgp_dump_routes
;
809 return bgp_dump_unset(bgp_dump_struct
);
812 static int config_write_bgp_dump(struct vty
*vty
);
813 /* BGP node structure. */
814 static struct cmd_node bgp_dump_node
= {
818 .config_write
= config_write_bgp_dump
,
821 static int config_write_bgp_dump(struct vty
*vty
)
823 if (bgp_dump_all
.filename
) {
824 const char *type_str
= "all";
825 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
828 if (bgp_dump_all
.interval_str
)
829 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
830 bgp_dump_all
.filename
,
831 bgp_dump_all
.interval_str
);
833 vty_out(vty
, "dump bgp %s %s\n", type_str
,
834 bgp_dump_all
.filename
);
836 if (bgp_dump_updates
.filename
) {
837 const char *type_str
= "updates";
838 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
839 type_str
= "updates-et";
841 if (bgp_dump_updates
.interval_str
)
842 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
843 bgp_dump_updates
.filename
,
844 bgp_dump_updates
.interval_str
);
846 vty_out(vty
, "dump bgp %s %s\n", type_str
,
847 bgp_dump_updates
.filename
);
849 if (bgp_dump_routes
.filename
) {
850 if (bgp_dump_routes
.interval_str
)
851 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
852 bgp_dump_routes
.filename
,
853 bgp_dump_routes
.interval_str
);
855 vty_out(vty
, "dump bgp routes-mrt %s\n",
856 bgp_dump_routes
.filename
);
861 /* Initialize BGP packet dump functionality. */
862 void bgp_dump_init(void)
864 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
865 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
866 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
869 stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
* 2)
870 + BGP_DUMP_MSG_HEADER
+ BGP_DUMP_HEADER_SIZE
);
872 install_node(&bgp_dump_node
);
874 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
875 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
877 hook_register(bgp_packet_dump
, bgp_dump_packet
);
878 hook_register(peer_status_changed
, bgp_dump_state
);
881 void bgp_dump_finish(void)
883 bgp_dump_unset(&bgp_dump_all
);
884 bgp_dump_unset(&bgp_dump_updates
);
885 bgp_dump_unset(&bgp_dump_routes
);
887 stream_free(bgp_dump_obuf
);
888 bgp_dump_obuf
= NULL
;
889 hook_unregister(bgp_packet_dump
, bgp_dump_packet
);
890 hook_unregister(peer_status_changed
, bgp_dump_state
);