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 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
) - (bgp_clock() - 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
->attr
, 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 int 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
);
469 /* Dump common information. */
470 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
473 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
475 /* Source AS number and Destination AS number. */
476 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
477 stream_putl(obuf
, peer
->as
);
478 stream_putl(obuf
, peer
->local_as
);
480 stream_putw(obuf
, peer
->as
);
481 stream_putw(obuf
, peer
->local_as
);
484 if (peer
->su
.sa
.sa_family
== AF_INET
) {
485 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
486 stream_putw(obuf
, AFI_IP
);
488 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
491 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
494 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
495 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
496 /* Interface Index and Address family. */
497 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
498 stream_putw(obuf
, AFI_IP6
);
500 /* Source IP Address and Destination IP Address. */
501 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
504 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
507 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
511 /* Dump BGP status change. */
512 int bgp_dump_state(struct peer
*peer
)
516 /* If dump file pointer is disabled return immediately. */
517 if (bgp_dump_all
.fp
== NULL
)
520 /* Make dump stream. */
521 obuf
= bgp_dump_obuf
;
524 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
526 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
528 stream_putw(obuf
, peer
->ostatus
);
529 stream_putw(obuf
, peer
->status
);
532 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
534 /* Write to the stream. */
535 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
536 fflush(bgp_dump_all
.fp
);
540 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
541 struct stream
*packet
)
544 bool addpath_capable
= false;
545 /* If dump file pointer is disabled return immediately. */
546 if (bgp_dump
->fp
== NULL
)
548 if (peer
->su
.sa
.sa_family
== AF_INET
) {
550 bgp_addpath_encode_rx(peer
, AFI_IP
, SAFI_UNICAST
);
551 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
553 bgp_addpath_encode_rx(peer
, AFI_IP6
, SAFI_UNICAST
);
556 /* Make dump stream. */
557 obuf
= bgp_dump_obuf
;
560 /* Dump header and common part. */
561 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
) && addpath_capable
) {
562 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
563 BGP4MP_MESSAGE_AS4_ADDPATH
, bgp_dump
->type
);
564 } else if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
565 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
567 } else if (addpath_capable
) {
568 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
569 BGP4MP_MESSAGE_ADDPATH
, bgp_dump
->type
);
571 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
574 bgp_dump_common(obuf
, peer
, 0);
576 /* Packet contents. */
577 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
580 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
582 /* Write to the stream. */
583 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
584 fflush(bgp_dump
->fp
);
587 /* Called from bgp_packet.c when BGP packet is received. */
588 static int bgp_dump_packet(struct peer
*peer
, uint8_t type
, bgp_size_t size
,
589 struct stream
*packet
)
592 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
594 /* bgp_dump_updates. */
595 if (type
== BGP_MSG_UPDATE
)
596 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
600 static unsigned int bgp_dump_parse_time(const char *str
)
615 for (i
= 0; i
< len
; i
++) {
616 if (isdigit((unsigned char)str
[i
])) {
618 time
+= str
[i
] - '0';
619 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
624 total
+= time
* 60 * 60;
627 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
639 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
640 enum bgp_dump_type type
, const char *path
,
641 const char *interval_str
)
643 unsigned int interval
;
645 /* Don't schedule duplicate dumps if the dump command is given twice */
646 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
647 && type
== bgp_dump
->type
) {
649 if (bgp_dump
->interval_str
650 && strcmp(bgp_dump
->interval_str
, interval_str
)
654 if (!bgp_dump
->interval_str
)
659 /* Removing previous config */
660 bgp_dump_unset(bgp_dump
);
663 /* Check interval string. */
664 interval
= bgp_dump_parse_time(interval_str
);
666 vty_out(vty
, "Malformed interval string\n");
667 return CMD_WARNING_CONFIG_FAILED
;
670 /* Setting interval string */
671 bgp_dump
->interval_str
=
672 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
678 bgp_dump
->type
= type
;
681 bgp_dump
->interval
= interval
;
684 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
686 /* Create interval thread. */
687 bgp_dump_interval_add(bgp_dump
, interval
);
689 /* This should be called when interval is expired. */
690 bgp_dump_open_file(bgp_dump
);
695 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
697 /* Removing file name. */
698 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
702 fclose(bgp_dump
->fp
);
706 /* Removing interval event. */
707 thread_cancel(&bgp_dump
->t_interval
);
709 bgp_dump
->interval
= 0;
711 /* Removing interval string. */
712 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
719 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
722 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
723 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
724 "Dump whole BGP routing table\n"
726 "Interval of output\n")
728 int idx_dump_routes
= 2;
730 int idx_interval
= 4;
731 int bgp_dump_type
= 0;
732 const char *interval
= NULL
;
733 struct bgp_dump
*bgp_dump_struct
= NULL
;
734 const struct bgp_dump_type_map
*map
= NULL
;
736 for (map
= bgp_dump_type_map
; map
->str
; map
++)
737 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
738 bgp_dump_type
= map
->type
;
740 switch (bgp_dump_type
) {
742 case BGP_DUMP_ALL_ET
:
743 bgp_dump_struct
= &bgp_dump_all
;
745 case BGP_DUMP_UPDATES
:
746 case BGP_DUMP_UPDATES_ET
:
747 bgp_dump_struct
= &bgp_dump_updates
;
749 case BGP_DUMP_ROUTES
:
751 bgp_dump_struct
= &bgp_dump_routes
;
755 /* When an interval is given */
756 if (argc
== idx_interval
+ 1)
757 interval
= argv
[idx_interval
]->arg
;
759 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
760 argv
[idx_path
]->arg
, interval
);
763 DEFUN (no_dump_bgp_all
,
765 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
768 "Stop BGP packet dump\n"
769 "Stop dump process all\n"
770 "Stop dump process all-et\n"
771 "Stop dump process updates\n"
772 "Stop dump process updates-et\n"
773 "Stop dump process route-mrt\n"
775 "Interval of output\n")
777 int idx_dump_routes
= 3;
778 int bgp_dump_type
= 0;
779 const struct bgp_dump_type_map
*map
= NULL
;
780 struct bgp_dump
*bgp_dump_struct
= NULL
;
782 for (map
= bgp_dump_type_map
; map
->str
; map
++)
783 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
784 bgp_dump_type
= map
->type
;
786 switch (bgp_dump_type
) {
788 case BGP_DUMP_ALL_ET
:
789 bgp_dump_struct
= &bgp_dump_all
;
791 case BGP_DUMP_UPDATES
:
792 case BGP_DUMP_UPDATES_ET
:
793 bgp_dump_struct
= &bgp_dump_updates
;
795 case BGP_DUMP_ROUTES
:
797 bgp_dump_struct
= &bgp_dump_routes
;
801 return bgp_dump_unset(bgp_dump_struct
);
804 static int config_write_bgp_dump(struct vty
*vty
);
805 /* BGP node structure. */
806 static struct cmd_node bgp_dump_node
= {
810 .config_write
= config_write_bgp_dump
,
813 static int config_write_bgp_dump(struct vty
*vty
)
815 if (bgp_dump_all
.filename
) {
816 const char *type_str
= "all";
817 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
820 if (bgp_dump_all
.interval_str
)
821 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
822 bgp_dump_all
.filename
,
823 bgp_dump_all
.interval_str
);
825 vty_out(vty
, "dump bgp %s %s\n", type_str
,
826 bgp_dump_all
.filename
);
828 if (bgp_dump_updates
.filename
) {
829 const char *type_str
= "updates";
830 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
831 type_str
= "updates-et";
833 if (bgp_dump_updates
.interval_str
)
834 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
835 bgp_dump_updates
.filename
,
836 bgp_dump_updates
.interval_str
);
838 vty_out(vty
, "dump bgp %s %s\n", type_str
,
839 bgp_dump_updates
.filename
);
841 if (bgp_dump_routes
.filename
) {
842 if (bgp_dump_routes
.interval_str
)
843 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
844 bgp_dump_routes
.filename
,
845 bgp_dump_routes
.interval_str
);
847 vty_out(vty
, "dump bgp routes-mrt %s\n",
848 bgp_dump_routes
.filename
);
853 /* Initialize BGP packet dump functionality. */
854 void bgp_dump_init(void)
856 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
857 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
858 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
861 stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
* 2)
862 + BGP_DUMP_MSG_HEADER
+ BGP_DUMP_HEADER_SIZE
);
864 install_node(&bgp_dump_node
);
866 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
867 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
869 hook_register(bgp_packet_dump
, bgp_dump_packet
);
870 hook_register(peer_status_changed
, bgp_dump_state
);
873 void bgp_dump_finish(void)
875 bgp_dump_unset(&bgp_dump_all
);
876 bgp_dump_unset(&bgp_dump_updates
);
877 bgp_dump_unset(&bgp_dump_routes
);
879 stream_free(bgp_dump_obuf
);
880 bgp_dump_obuf
= NULL
;
881 hook_unregister(bgp_packet_dump
, bgp_dump_packet
);
882 hook_unregister(peer_status_changed
, bgp_dump_state
);