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 void 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
, "%s: strftime error", __func__
);
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
, "%s: %s: %s", __func__
, 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 struct bgp_path_info
*
302 bgp_dump_route_node_record(int afi
, struct bgp_dest
*dest
,
303 struct bgp_path_info
*path
, unsigned int seq
)
308 bool addpath_capable
;
309 const struct prefix
*p
= bgp_dest_get_prefix(dest
);
311 obuf
= bgp_dump_obuf
;
314 addpath_capable
= bgp_addpath_encode_rx(path
->peer
, afi
, SAFI_UNICAST
);
317 if (afi
== AFI_IP
&& addpath_capable
)
318 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
319 TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH
,
321 else if (afi
== AFI_IP
)
322 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
323 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
325 else if (afi
== AFI_IP6
&& addpath_capable
)
326 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
327 TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH
,
329 else if (afi
== AFI_IP6
)
330 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
331 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
334 /* Sequence number */
335 stream_putl(obuf
, seq
);
338 stream_putc(obuf
, p
->prefixlen
);
342 /* We'll dump only the useful bits (those not 0), but have to
344 stream_write(obuf
, (uint8_t *)&p
->u
.prefix4
,
345 (p
->prefixlen
+ 7) / 8);
346 } else if (afi
== AFI_IP6
) {
347 /* We'll dump only the useful bits (those not 0), but have to
349 stream_write(obuf
, (uint8_t *)&p
->u
.prefix6
,
350 (p
->prefixlen
+ 7) / 8);
353 /* Save where we are now, so we can overwride the entry count later */
354 sizep
= stream_get_endp(obuf
);
357 uint16_t entry_count
= 0;
359 /* Entry count, note that this is overwritten later */
360 stream_putw(obuf
, 0);
362 endp
= stream_get_endp(obuf
);
363 for (; path
; path
= path
->next
) {
367 stream_putw(obuf
, path
->peer
->table_dump_index
);
370 stream_putl(obuf
, time(NULL
) - (monotime(NULL
) - path
->uptime
));
373 if (addpath_capable
) {
374 stream_putl(obuf
, path
->addpath_rx_id
);
377 /* Dump attribute. */
378 /* Skip prefix & AFI/SAFI for MP_NLRI */
379 bgp_dump_routes_attr(obuf
, path
, p
);
381 cur_endp
= stream_get_endp(obuf
);
382 if (cur_endp
> BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
383 + BGP_DUMP_MSG_HEADER
384 + BGP_DUMP_HEADER_SIZE
) {
385 stream_set_endp(obuf
, endp
);
393 /* Overwrite the entry count, now that we know the right number */
394 stream_putw_at(obuf
, sizep
, entry_count
);
396 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
397 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
403 /* Runs under child process. */
404 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
407 struct bgp_path_info
*path
;
408 struct bgp_dest
*dest
;
410 struct bgp_table
*table
;
412 bgp
= bgp_get_default();
416 if (bgp_dump_routes
.fp
== NULL
)
419 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
420 so this should only be done on the first call to
421 bgp_dump_routes_func.
422 ( this function will be called once for ipv4 and once for ipv6 ) */
424 bgp_dump_routes_index_table(bgp
);
426 /* Walk down each BGP route. */
427 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
429 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
430 path
= bgp_dest_get_bgp_path_info(dest
);
432 path
= bgp_dump_route_node_record(afi
, dest
, path
, seq
);
437 fflush(bgp_dump_routes
.fp
);
442 static void bgp_dump_interval_func(struct thread
*t
)
444 struct bgp_dump
*bgp_dump
;
445 bgp_dump
= THREAD_ARG(t
);
447 /* Reschedule dump even if file couldn't be opened this time... */
448 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
449 /* In case of bgp_dump_routes, we need special route dump
451 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
452 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
453 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
454 /* Close the file now. For a RIB dump there's no point
456 * it open until the next scheduled dump starts. */
457 fclose(bgp_dump
->fp
);
462 /* if interval is set reschedule */
463 if (bgp_dump
->interval
> 0)
464 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
467 /* Dump common information. */
468 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
471 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
473 /* Source AS number and Destination AS number. */
474 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
475 stream_putl(obuf
, peer
->as
);
476 stream_putl(obuf
, peer
->local_as
);
478 stream_putw(obuf
, peer
->as
);
479 stream_putw(obuf
, peer
->local_as
);
482 if (peer
->su
.sa
.sa_family
== AF_INET
) {
483 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
484 stream_putw(obuf
, AFI_IP
);
486 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
489 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
492 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
493 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
494 /* Interface Index and Address family. */
495 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
496 stream_putw(obuf
, AFI_IP6
);
498 /* Source IP Address and Destination IP Address. */
499 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
502 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
505 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
509 /* Dump BGP status change. */
510 int bgp_dump_state(struct peer
*peer
)
514 /* If dump file pointer is disabled return immediately. */
515 if (bgp_dump_all
.fp
== NULL
)
518 /* Make dump stream. */
519 obuf
= bgp_dump_obuf
;
522 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
524 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
526 stream_putw(obuf
, peer
->ostatus
);
527 stream_putw(obuf
, peer
->status
);
530 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
532 /* Write to the stream. */
533 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
534 fflush(bgp_dump_all
.fp
);
538 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
539 struct stream
*packet
)
542 bool addpath_capable
= false;
543 /* If dump file pointer is disabled return immediately. */
544 if (bgp_dump
->fp
== NULL
)
546 if (peer
->su
.sa
.sa_family
== AF_INET
) {
548 bgp_addpath_encode_rx(peer
, AFI_IP
, SAFI_UNICAST
);
549 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
551 bgp_addpath_encode_rx(peer
, AFI_IP6
, SAFI_UNICAST
);
554 /* Make dump stream. */
555 obuf
= bgp_dump_obuf
;
558 /* Dump header and common part. */
559 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
) && addpath_capable
) {
560 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
561 BGP4MP_MESSAGE_AS4_ADDPATH
, bgp_dump
->type
);
562 } else if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
563 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
565 } else if (addpath_capable
) {
566 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
567 BGP4MP_MESSAGE_ADDPATH
, bgp_dump
->type
);
569 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
572 bgp_dump_common(obuf
, peer
, 0);
574 /* Packet contents. */
575 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
578 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
580 /* Write to the stream. */
581 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
582 fflush(bgp_dump
->fp
);
585 /* Called from bgp_packet.c when BGP packet is received. */
586 static int bgp_dump_packet(struct peer
*peer
, uint8_t type
, bgp_size_t size
,
587 struct stream
*packet
)
590 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
592 /* bgp_dump_updates. */
593 if (type
== BGP_MSG_UPDATE
)
594 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
598 static unsigned int bgp_dump_parse_time(const char *str
)
613 for (i
= 0; i
< len
; i
++) {
614 if (isdigit((unsigned char)str
[i
])) {
616 time
+= str
[i
] - '0';
617 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
622 total
+= time
* 60 * 60;
625 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
637 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
638 enum bgp_dump_type type
, const char *path
,
639 const char *interval_str
)
641 unsigned int interval
;
643 /* Don't schedule duplicate dumps if the dump command is given twice */
644 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
645 && type
== bgp_dump
->type
) {
647 if (bgp_dump
->interval_str
648 && strcmp(bgp_dump
->interval_str
, interval_str
)
652 if (!bgp_dump
->interval_str
)
657 /* Removing previous config */
658 bgp_dump_unset(bgp_dump
);
661 /* Check interval string. */
662 interval
= bgp_dump_parse_time(interval_str
);
664 vty_out(vty
, "Malformed interval string\n");
665 return CMD_WARNING_CONFIG_FAILED
;
668 /* Setting interval string */
669 bgp_dump
->interval_str
=
670 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
676 bgp_dump
->type
= type
;
679 bgp_dump
->interval
= interval
;
682 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
684 /* Create interval thread. */
685 bgp_dump_interval_add(bgp_dump
, interval
);
687 /* This should be called when interval is expired. */
688 bgp_dump_open_file(bgp_dump
);
693 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
695 /* Removing file name. */
696 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
700 fclose(bgp_dump
->fp
);
704 /* Removing interval event. */
705 THREAD_OFF(bgp_dump
->t_interval
);
707 bgp_dump
->interval
= 0;
709 /* Removing interval string. */
710 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
717 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
720 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
721 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
722 "Dump whole BGP routing table\n"
724 "Interval of output\n")
726 int idx_dump_routes
= 2;
728 int idx_interval
= 4;
729 int bgp_dump_type
= 0;
730 const char *interval
= NULL
;
731 struct bgp_dump
*bgp_dump_struct
= NULL
;
732 const struct bgp_dump_type_map
*map
= NULL
;
734 for (map
= bgp_dump_type_map
; map
->str
; map
++)
735 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
736 bgp_dump_type
= map
->type
;
738 switch (bgp_dump_type
) {
740 case BGP_DUMP_ALL_ET
:
741 bgp_dump_struct
= &bgp_dump_all
;
743 case BGP_DUMP_UPDATES
:
744 case BGP_DUMP_UPDATES_ET
:
745 bgp_dump_struct
= &bgp_dump_updates
;
747 case BGP_DUMP_ROUTES
:
749 bgp_dump_struct
= &bgp_dump_routes
;
753 /* When an interval is given */
754 if (argc
== idx_interval
+ 1)
755 interval
= argv
[idx_interval
]->arg
;
757 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
758 argv
[idx_path
]->arg
, interval
);
761 DEFUN (no_dump_bgp_all
,
763 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
766 "Stop BGP packet dump\n"
767 "Stop dump process all\n"
768 "Stop dump process all-et\n"
769 "Stop dump process updates\n"
770 "Stop dump process updates-et\n"
771 "Stop dump process route-mrt\n"
773 "Interval of output\n")
775 int idx_dump_routes
= 3;
776 int bgp_dump_type
= 0;
777 const struct bgp_dump_type_map
*map
= NULL
;
778 struct bgp_dump
*bgp_dump_struct
= NULL
;
780 for (map
= bgp_dump_type_map
; map
->str
; map
++)
781 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
782 bgp_dump_type
= map
->type
;
784 switch (bgp_dump_type
) {
786 case BGP_DUMP_ALL_ET
:
787 bgp_dump_struct
= &bgp_dump_all
;
789 case BGP_DUMP_UPDATES
:
790 case BGP_DUMP_UPDATES_ET
:
791 bgp_dump_struct
= &bgp_dump_updates
;
793 case BGP_DUMP_ROUTES
:
795 bgp_dump_struct
= &bgp_dump_routes
;
799 return bgp_dump_unset(bgp_dump_struct
);
802 static int config_write_bgp_dump(struct vty
*vty
);
803 /* BGP node structure. */
804 static struct cmd_node bgp_dump_node
= {
808 .config_write
= config_write_bgp_dump
,
811 static int config_write_bgp_dump(struct vty
*vty
)
813 if (bgp_dump_all
.filename
) {
814 const char *type_str
= "all";
815 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
818 if (bgp_dump_all
.interval_str
)
819 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
820 bgp_dump_all
.filename
,
821 bgp_dump_all
.interval_str
);
823 vty_out(vty
, "dump bgp %s %s\n", type_str
,
824 bgp_dump_all
.filename
);
826 if (bgp_dump_updates
.filename
) {
827 const char *type_str
= "updates";
828 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
829 type_str
= "updates-et";
831 if (bgp_dump_updates
.interval_str
)
832 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
833 bgp_dump_updates
.filename
,
834 bgp_dump_updates
.interval_str
);
836 vty_out(vty
, "dump bgp %s %s\n", type_str
,
837 bgp_dump_updates
.filename
);
839 if (bgp_dump_routes
.filename
) {
840 if (bgp_dump_routes
.interval_str
)
841 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
842 bgp_dump_routes
.filename
,
843 bgp_dump_routes
.interval_str
);
845 vty_out(vty
, "dump bgp routes-mrt %s\n",
846 bgp_dump_routes
.filename
);
851 /* Initialize BGP packet dump functionality. */
852 void bgp_dump_init(void)
854 memset(&bgp_dump_all
, 0, sizeof(bgp_dump_all
));
855 memset(&bgp_dump_updates
, 0, sizeof(bgp_dump_updates
));
856 memset(&bgp_dump_routes
, 0, sizeof(bgp_dump_routes
));
859 stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
* 2)
860 + BGP_DUMP_MSG_HEADER
+ BGP_DUMP_HEADER_SIZE
);
862 install_node(&bgp_dump_node
);
864 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
865 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
867 hook_register(bgp_packet_dump
, bgp_dump_packet
);
868 hook_register(peer_status_changed
, bgp_dump_state
);
871 void bgp_dump_finish(void)
873 bgp_dump_unset(&bgp_dump_all
);
874 bgp_dump_unset(&bgp_dump_updates
);
875 bgp_dump_unset(&bgp_dump_routes
);
877 stream_free(bgp_dump_obuf
);
878 bgp_dump_obuf
= NULL
;
879 hook_unregister(bgp_packet_dump
, bgp_dump_packet
);
880 hook_unregister(peer_status_changed
, bgp_dump_state
);