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 #pragma GCC diagnostic push
121 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
122 /* user supplied date/time format string */
123 ret
= strftime(realpath
, MAXPATHLEN
, fullpath
, &tm
);
125 ret
= strftime(realpath
, MAXPATHLEN
, bgp_dump
->filename
, &tm
);
126 #pragma GCC diagnostic pop
129 flog_warn(EC_BGP_DUMP
, "%s: strftime error", __func__
);
134 fclose(bgp_dump
->fp
);
137 oldumask
= umask(0777 & ~LOGFILE_MASK
);
138 bgp_dump
->fp
= fopen(realpath
, "w");
140 if (bgp_dump
->fp
== NULL
) {
141 flog_warn(EC_BGP_DUMP
, "%s: %s: %s", __func__
, realpath
,
151 static int bgp_dump_interval_add(struct bgp_dump
*bgp_dump
, int interval
)
158 /* Periodic dump every interval seconds */
159 if ((interval
< 86400) && ((86400 % interval
) == 0)) {
160 /* Dump at predictable times: if a day has a whole
162 * intervals, dump every interval seconds starting from
166 localtime_r(&t
, &tm
);
167 secs_into_day
= tm
.tm_sec
+ 60 * tm
.tm_min
168 + 60 * 60 * tm
.tm_hour
;
170 - secs_into_day
% interval
; /* always > 0 */
172 thread_add_timer(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
173 interval
, &bgp_dump
->t_interval
);
175 /* One-off dump: execute immediately, don't affect any scheduled
177 thread_add_event(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
178 0, &bgp_dump
->t_interval
);
184 /* Dump common header. */
185 static void bgp_dump_header(struct stream
*obuf
, int type
, int subtype
,
188 struct timeval clock
;
192 if ((dump_type
== BGP_DUMP_ALL_ET
|| dump_type
== BGP_DUMP_UPDATES_ET
)
193 && type
== MSG_PROTOCOL_BGP4MP
)
194 type
= MSG_PROTOCOL_BGP4MP_ET
;
196 gettimeofday(&clock
, NULL
);
199 msecs
= clock
.tv_usec
;
201 /* Put dump packet header. */
202 stream_putl(obuf
, secs
);
203 stream_putw(obuf
, type
);
204 stream_putw(obuf
, subtype
);
205 stream_putl(obuf
, 0); /* len */
207 /* Adding microseconds for the MRT Extended Header */
208 if (type
== MSG_PROTOCOL_BGP4MP_ET
)
209 stream_putl(obuf
, msecs
);
212 static void bgp_dump_set_size(struct stream
*s
, int type
)
215 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
216 * "The Microsecond Timestamp is included in the computation
217 * of the Length field value." (RFC6396 2011)
219 stream_putl_at(s
, 8, stream_get_endp(s
) - BGP_DUMP_HEADER_SIZE
);
222 static void bgp_dump_routes_index_table(struct bgp
*bgp
)
225 struct listnode
*node
;
229 obuf
= bgp_dump_obuf
;
233 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_PEER_INDEX_TABLE
,
236 /* Collector BGP ID */
237 stream_put_in_addr(obuf
, &bgp
->router_id
);
240 if (bgp
->name_pretty
) {
241 stream_putw(obuf
, strlen(bgp
->name_pretty
));
242 stream_put(obuf
, bgp
->name_pretty
, strlen(bgp
->name_pretty
));
244 stream_putw(obuf
, 0);
247 /* Peer count ( plus one extra internal peer ) */
248 stream_putw(obuf
, listcount(bgp
->peer
) + 1);
250 /* Populate fake peer at index 0, for locally originated routes */
251 /* Peer type (IPv4) */
253 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
254 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
255 /* Peer BGP ID (0.0.0.0) */
256 stream_putl(obuf
, 0);
257 /* Peer IP address (0.0.0.0) */
258 stream_putl(obuf
, 0);
260 stream_putl(obuf
, 0);
262 /* Walk down all peers */
263 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
266 if (sockunion_family(&peer
->su
) == AF_INET
) {
269 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
270 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
271 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
274 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
275 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
279 stream_put_in_addr(obuf
, &peer
->remote_id
);
281 /* Peer's IP address */
282 if (sockunion_family(&peer
->su
) == AF_INET
) {
283 stream_put_in_addr(obuf
, &peer
->su
.sin
.sin_addr
);
284 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
285 stream_write(obuf
, (uint8_t *)&peer
->su
.sin6
.sin6_addr
,
289 /* Peer's AS number. */
290 /* Note that, as this is an AS4 compliant quagga, the RIB is
292 stream_putl(obuf
, peer
->as
);
294 /* Store the peer number for this peer */
295 peer
->table_dump_index
= peerno
;
299 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
301 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
302 fflush(bgp_dump_routes
.fp
);
305 static struct bgp_path_info
*
306 bgp_dump_route_node_record(int afi
, struct bgp_dest
*dest
,
307 struct bgp_path_info
*path
, unsigned int seq
)
312 bool addpath_capable
;
313 const struct prefix
*p
= bgp_dest_get_prefix(dest
);
315 obuf
= bgp_dump_obuf
;
318 addpath_capable
= bgp_addpath_encode_rx(path
->peer
, afi
, SAFI_UNICAST
);
321 if (afi
== AFI_IP
&& addpath_capable
)
322 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
323 TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH
,
325 else if (afi
== AFI_IP
)
326 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
327 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
329 else if (afi
== AFI_IP6
&& addpath_capable
)
330 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
331 TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH
,
333 else if (afi
== AFI_IP6
)
334 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
335 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
338 /* Sequence number */
339 stream_putl(obuf
, seq
);
342 stream_putc(obuf
, p
->prefixlen
);
346 /* We'll dump only the useful bits (those not 0), but have to
348 stream_write(obuf
, (uint8_t *)&p
->u
.prefix4
,
349 (p
->prefixlen
+ 7) / 8);
350 } else if (afi
== AFI_IP6
) {
351 /* We'll dump only the useful bits (those not 0), but have to
353 stream_write(obuf
, (uint8_t *)&p
->u
.prefix6
,
354 (p
->prefixlen
+ 7) / 8);
357 /* Save where we are now, so we can overwride the entry count later */
358 sizep
= stream_get_endp(obuf
);
361 uint16_t entry_count
= 0;
363 /* Entry count, note that this is overwritten later */
364 stream_putw(obuf
, 0);
366 endp
= stream_get_endp(obuf
);
367 for (; path
; path
= path
->next
) {
371 stream_putw(obuf
, path
->peer
->table_dump_index
);
374 stream_putl(obuf
, time(NULL
) - (monotime(NULL
) - path
->uptime
));
377 if (addpath_capable
) {
378 stream_putl(obuf
, path
->addpath_rx_id
);
381 /* Dump attribute. */
382 /* Skip prefix & AFI/SAFI for MP_NLRI */
383 bgp_dump_routes_attr(obuf
, path
, p
);
385 cur_endp
= stream_get_endp(obuf
);
386 if (cur_endp
> BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
387 + BGP_DUMP_MSG_HEADER
388 + BGP_DUMP_HEADER_SIZE
) {
389 stream_set_endp(obuf
, endp
);
397 /* Overwrite the entry count, now that we know the right number */
398 stream_putw_at(obuf
, sizep
, entry_count
);
400 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
401 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
407 /* Runs under child process. */
408 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
411 struct bgp_path_info
*path
;
412 struct bgp_dest
*dest
;
414 struct bgp_table
*table
;
416 bgp
= bgp_get_default();
420 if (bgp_dump_routes
.fp
== NULL
)
423 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
424 so this should only be done on the first call to
425 bgp_dump_routes_func.
426 ( this function will be called once for ipv4 and once for ipv6 ) */
428 bgp_dump_routes_index_table(bgp
);
430 /* Walk down each BGP route. */
431 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
433 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
434 path
= bgp_dest_get_bgp_path_info(dest
);
436 path
= bgp_dump_route_node_record(afi
, dest
, path
, seq
);
441 fflush(bgp_dump_routes
.fp
);
446 static void bgp_dump_interval_func(struct thread
*t
)
448 struct bgp_dump
*bgp_dump
;
449 bgp_dump
= THREAD_ARG(t
);
451 /* Reschedule dump even if file couldn't be opened this time... */
452 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
453 /* In case of bgp_dump_routes, we need special route dump
455 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
456 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
457 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
458 /* Close the file now. For a RIB dump there's no point
460 * it open until the next scheduled dump starts. */
461 fclose(bgp_dump
->fp
);
466 /* if interval is set reschedule */
467 if (bgp_dump
->interval
> 0)
468 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
471 /* Dump common information. */
472 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
475 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
477 /* Source AS number and Destination AS number. */
478 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
479 stream_putl(obuf
, peer
->as
);
480 stream_putl(obuf
, peer
->local_as
);
482 stream_putw(obuf
, peer
->as
);
483 stream_putw(obuf
, peer
->local_as
);
486 if (peer
->su
.sa
.sa_family
== AF_INET
) {
487 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
488 stream_putw(obuf
, AFI_IP
);
490 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
493 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
496 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
497 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
498 /* Interface Index and Address family. */
499 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
500 stream_putw(obuf
, AFI_IP6
);
502 /* Source IP Address and Destination IP Address. */
503 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
506 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
509 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
513 /* Dump BGP status change. */
514 int bgp_dump_state(struct peer
*peer
)
518 /* If dump file pointer is disabled return immediately. */
519 if (bgp_dump_all
.fp
== NULL
)
522 /* Make dump stream. */
523 obuf
= bgp_dump_obuf
;
526 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
528 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
530 stream_putw(obuf
, peer
->ostatus
);
531 stream_putw(obuf
, peer
->status
);
534 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
536 /* Write to the stream. */
537 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
538 fflush(bgp_dump_all
.fp
);
542 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
543 struct stream
*packet
)
546 bool addpath_capable
= false;
547 /* If dump file pointer is disabled return immediately. */
548 if (bgp_dump
->fp
== NULL
)
550 if (peer
->su
.sa
.sa_family
== AF_INET
) {
552 bgp_addpath_encode_rx(peer
, AFI_IP
, SAFI_UNICAST
);
553 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
555 bgp_addpath_encode_rx(peer
, AFI_IP6
, SAFI_UNICAST
);
558 /* Make dump stream. */
559 obuf
= bgp_dump_obuf
;
562 /* Dump header and common part. */
563 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
) && addpath_capable
) {
564 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
565 BGP4MP_MESSAGE_AS4_ADDPATH
, bgp_dump
->type
);
566 } else if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
567 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
569 } else if (addpath_capable
) {
570 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
571 BGP4MP_MESSAGE_ADDPATH
, bgp_dump
->type
);
573 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
576 bgp_dump_common(obuf
, peer
, 0);
578 /* Packet contents. */
579 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
582 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
584 /* Write to the stream. */
585 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
586 fflush(bgp_dump
->fp
);
589 /* Called from bgp_packet.c when BGP packet is received. */
590 static int bgp_dump_packet(struct peer
*peer
, uint8_t type
, bgp_size_t size
,
591 struct stream
*packet
)
594 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
596 /* bgp_dump_updates. */
597 if (type
== BGP_MSG_UPDATE
)
598 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
602 static unsigned int bgp_dump_parse_time(const char *str
)
617 for (i
= 0; i
< len
; i
++) {
618 if (isdigit((unsigned char)str
[i
])) {
620 time
+= str
[i
] - '0';
621 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
626 total
+= time
* 60 * 60;
629 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
641 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
642 enum bgp_dump_type type
, const char *path
,
643 const char *interval_str
)
645 unsigned int interval
;
647 /* Don't schedule duplicate dumps if the dump command is given twice */
648 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
649 && type
== bgp_dump
->type
) {
651 if (bgp_dump
->interval_str
652 && strcmp(bgp_dump
->interval_str
, interval_str
)
656 if (!bgp_dump
->interval_str
)
661 /* Removing previous config */
662 bgp_dump_unset(bgp_dump
);
665 /* Check interval string. */
666 interval
= bgp_dump_parse_time(interval_str
);
668 vty_out(vty
, "Malformed interval string\n");
669 return CMD_WARNING_CONFIG_FAILED
;
672 /* Setting interval string */
673 bgp_dump
->interval_str
=
674 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
680 bgp_dump
->type
= type
;
683 bgp_dump
->interval
= interval
;
686 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
688 /* Create interval thread. */
689 bgp_dump_interval_add(bgp_dump
, interval
);
691 /* This should be called when interval is expired. */
692 bgp_dump_open_file(bgp_dump
);
697 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
699 /* Removing file name. */
700 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
704 fclose(bgp_dump
->fp
);
708 /* Removing interval event. */
709 THREAD_OFF(bgp_dump
->t_interval
);
711 bgp_dump
->interval
= 0;
713 /* Removing interval string. */
714 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
721 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
724 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
725 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
726 "Dump whole BGP routing table\n"
728 "Interval of output\n")
730 int idx_dump_routes
= 2;
732 int idx_interval
= 4;
733 int bgp_dump_type
= 0;
734 const char *interval
= NULL
;
735 struct bgp_dump
*bgp_dump_struct
= NULL
;
736 const struct bgp_dump_type_map
*map
= NULL
;
738 for (map
= bgp_dump_type_map
; map
->str
; map
++)
739 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
740 bgp_dump_type
= map
->type
;
742 switch (bgp_dump_type
) {
744 case BGP_DUMP_ALL_ET
:
745 bgp_dump_struct
= &bgp_dump_all
;
747 case BGP_DUMP_UPDATES
:
748 case BGP_DUMP_UPDATES_ET
:
749 bgp_dump_struct
= &bgp_dump_updates
;
751 case BGP_DUMP_ROUTES
:
753 bgp_dump_struct
= &bgp_dump_routes
;
757 /* When an interval is given */
758 if (argc
== idx_interval
+ 1)
759 interval
= argv
[idx_interval
]->arg
;
761 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
762 argv
[idx_path
]->arg
, interval
);
765 DEFUN (no_dump_bgp_all
,
767 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
770 "Stop BGP packet dump\n"
771 "Stop dump process all\n"
772 "Stop dump process all-et\n"
773 "Stop dump process updates\n"
774 "Stop dump process updates-et\n"
775 "Stop dump process route-mrt\n"
777 "Interval of output\n")
779 int idx_dump_routes
= 3;
780 int bgp_dump_type
= 0;
781 const struct bgp_dump_type_map
*map
= NULL
;
782 struct bgp_dump
*bgp_dump_struct
= NULL
;
784 for (map
= bgp_dump_type_map
; map
->str
; map
++)
785 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
786 bgp_dump_type
= map
->type
;
788 switch (bgp_dump_type
) {
790 case BGP_DUMP_ALL_ET
:
791 bgp_dump_struct
= &bgp_dump_all
;
793 case BGP_DUMP_UPDATES
:
794 case BGP_DUMP_UPDATES_ET
:
795 bgp_dump_struct
= &bgp_dump_updates
;
797 case BGP_DUMP_ROUTES
:
799 bgp_dump_struct
= &bgp_dump_routes
;
803 return bgp_dump_unset(bgp_dump_struct
);
806 static int config_write_bgp_dump(struct vty
*vty
);
807 /* BGP node structure. */
808 static struct cmd_node bgp_dump_node
= {
812 .config_write
= config_write_bgp_dump
,
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(bgp_dump_all
));
859 memset(&bgp_dump_updates
, 0, sizeof(bgp_dump_updates
));
860 memset(&bgp_dump_routes
, 0, sizeof(bgp_dump_routes
));
863 stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
* 2)
864 + BGP_DUMP_MSG_HEADER
+ 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
);