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 bgp_dump
->t_interval
= NULL
;
169 thread_add_timer(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
170 interval
, &bgp_dump
->t_interval
);
172 /* One-off dump: execute immediately, don't affect any scheduled
174 bgp_dump
->t_interval
= NULL
;
175 thread_add_event(bm
->master
, bgp_dump_interval_func
, bgp_dump
,
176 0, &bgp_dump
->t_interval
);
182 /* Dump common header. */
183 static void bgp_dump_header(struct stream
*obuf
, int type
, int subtype
,
186 struct timeval clock
;
190 if ((dump_type
== BGP_DUMP_ALL_ET
|| dump_type
== BGP_DUMP_UPDATES_ET
)
191 && type
== MSG_PROTOCOL_BGP4MP
)
192 type
= MSG_PROTOCOL_BGP4MP_ET
;
194 gettimeofday(&clock
, NULL
);
197 msecs
= clock
.tv_usec
;
199 /* Put dump packet header. */
200 stream_putl(obuf
, secs
);
201 stream_putw(obuf
, type
);
202 stream_putw(obuf
, subtype
);
203 stream_putl(obuf
, 0); /* len */
205 /* Adding microseconds for the MRT Extended Header */
206 if (type
== MSG_PROTOCOL_BGP4MP_ET
)
207 stream_putl(obuf
, msecs
);
210 static void bgp_dump_set_size(struct stream
*s
, int type
)
213 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
214 * "The Microsecond Timestamp is included in the computation
215 * of the Length field value." (RFC6396 2011)
217 stream_putl_at(s
, 8, stream_get_endp(s
) - BGP_DUMP_HEADER_SIZE
);
220 static void bgp_dump_routes_index_table(struct bgp
*bgp
)
223 struct listnode
*node
;
227 obuf
= bgp_dump_obuf
;
231 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_PEER_INDEX_TABLE
,
234 /* Collector BGP ID */
235 stream_put_in_addr(obuf
, &bgp
->router_id
);
238 if (bgp
->name_pretty
) {
239 stream_putw(obuf
, strlen(bgp
->name_pretty
));
240 stream_put(obuf
, bgp
->name_pretty
, strlen(bgp
->name_pretty
));
242 stream_putw(obuf
, 0);
245 /* Peer count ( plus one extra internal peer ) */
246 stream_putw(obuf
, listcount(bgp
->peer
) + 1);
248 /* Populate fake peer at index 0, for locally originated routes */
249 /* Peer type (IPv4) */
251 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
252 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
253 /* Peer BGP ID (0.0.0.0) */
254 stream_putl(obuf
, 0);
255 /* Peer IP address (0.0.0.0) */
256 stream_putl(obuf
, 0);
258 stream_putl(obuf
, 0);
260 /* Walk down all peers */
261 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
264 if (sockunion_family(&peer
->su
) == AF_INET
) {
267 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
268 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
269 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
272 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
273 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
277 stream_put_in_addr(obuf
, &peer
->remote_id
);
279 /* Peer's IP address */
280 if (sockunion_family(&peer
->su
) == AF_INET
) {
281 stream_put_in_addr(obuf
, &peer
->su
.sin
.sin_addr
);
282 } else if (sockunion_family(&peer
->su
) == AF_INET6
) {
283 stream_write(obuf
, (uint8_t *)&peer
->su
.sin6
.sin6_addr
,
287 /* Peer's AS number. */
288 /* Note that, as this is an AS4 compliant quagga, the RIB is
290 stream_putl(obuf
, peer
->as
);
292 /* Store the peer number for this peer */
293 peer
->table_dump_index
= peerno
;
297 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
299 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
300 fflush(bgp_dump_routes
.fp
);
303 static int bgp_addpath_encode_rx(struct peer
*peer
, afi_t afi
, safi_t safi
)
306 return (CHECK_FLAG(peer
->af_cap
[afi
][safi
], PEER_CAP_ADDPATH_AF_RX_ADV
)
307 && CHECK_FLAG(peer
->af_cap
[afi
][safi
],
308 PEER_CAP_ADDPATH_AF_TX_RCV
));
311 static struct bgp_path_info
*
312 bgp_dump_route_node_record(int afi
, struct bgp_dest
*dest
,
313 struct bgp_path_info
*path
, unsigned int seq
)
319 const struct prefix
*p
= bgp_dest_get_prefix(dest
);
321 obuf
= bgp_dump_obuf
;
324 addpath_encoded
= bgp_addpath_encode_rx(path
->peer
, afi
, SAFI_UNICAST
);
327 if (afi
== AFI_IP
&& addpath_encoded
)
328 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
329 TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH
,
331 else if (afi
== AFI_IP
)
332 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
333 TABLE_DUMP_V2_RIB_IPV4_UNICAST
,
335 else if (afi
== AFI_IP6
&& addpath_encoded
)
336 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
337 TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH
,
339 else if (afi
== AFI_IP6
)
340 bgp_dump_header(obuf
, MSG_TABLE_DUMP_V2
,
341 TABLE_DUMP_V2_RIB_IPV6_UNICAST
,
344 /* Sequence number */
345 stream_putl(obuf
, seq
);
348 stream_putc(obuf
, p
->prefixlen
);
352 /* We'll dump only the useful bits (those not 0), but have to
354 stream_write(obuf
, (uint8_t *)&p
->u
.prefix4
,
355 (p
->prefixlen
+ 7) / 8);
356 } else if (afi
== AFI_IP6
) {
357 /* We'll dump only the useful bits (those not 0), but have to
359 stream_write(obuf
, (uint8_t *)&p
->u
.prefix6
,
360 (p
->prefixlen
+ 7) / 8);
363 /* Save where we are now, so we can overwride the entry count later */
364 sizep
= stream_get_endp(obuf
);
367 uint16_t entry_count
= 0;
369 /* Entry count, note that this is overwritten later */
370 stream_putw(obuf
, 0);
372 endp
= stream_get_endp(obuf
);
373 for (; path
; path
= path
->next
) {
377 stream_putw(obuf
, path
->peer
->table_dump_index
);
380 stream_putl(obuf
, time(NULL
) - (bgp_clock() - path
->uptime
));
383 if (addpath_encoded
) {
384 stream_putl(obuf
, path
->addpath_rx_id
);
387 /* Dump attribute. */
388 /* Skip prefix & AFI/SAFI for MP_NLRI */
389 bgp_dump_routes_attr(obuf
, path
->attr
, p
);
391 cur_endp
= stream_get_endp(obuf
);
392 if (cur_endp
> BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
393 + BGP_DUMP_MSG_HEADER
394 + BGP_DUMP_HEADER_SIZE
) {
395 stream_set_endp(obuf
, endp
);
403 /* Overwrite the entry count, now that we know the right number */
404 stream_putw_at(obuf
, sizep
, entry_count
);
406 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
407 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_routes
.fp
);
413 /* Runs under child process. */
414 static unsigned int bgp_dump_routes_func(int afi
, int first_run
,
417 struct bgp_path_info
*path
;
418 struct bgp_dest
*dest
;
420 struct bgp_table
*table
;
422 bgp
= bgp_get_default();
426 if (bgp_dump_routes
.fp
== NULL
)
429 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
430 so this should only be done on the first call to
431 bgp_dump_routes_func.
432 ( this function will be called once for ipv4 and once for ipv6 ) */
434 bgp_dump_routes_index_table(bgp
);
436 /* Walk down each BGP route. */
437 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
439 for (dest
= bgp_table_top(table
); dest
; dest
= bgp_route_next(dest
)) {
440 path
= bgp_dest_get_bgp_path_info(dest
);
442 path
= bgp_dump_route_node_record(afi
, dest
, path
, seq
);
447 fflush(bgp_dump_routes
.fp
);
452 static int bgp_dump_interval_func(struct thread
*t
)
454 struct bgp_dump
*bgp_dump
;
455 bgp_dump
= THREAD_ARG(t
);
456 bgp_dump
->t_interval
= NULL
;
458 /* Reschedule dump even if file couldn't be opened this time... */
459 if (bgp_dump_open_file(bgp_dump
) != NULL
) {
460 /* In case of bgp_dump_routes, we need special route dump
462 if (bgp_dump
->type
== BGP_DUMP_ROUTES
) {
463 unsigned int seq
= bgp_dump_routes_func(AFI_IP
, 1, 0);
464 bgp_dump_routes_func(AFI_IP6
, 0, seq
);
465 /* Close the file now. For a RIB dump there's no point
467 * it open until the next scheduled dump starts. */
468 fclose(bgp_dump
->fp
);
473 /* if interval is set reschedule */
474 if (bgp_dump
->interval
> 0)
475 bgp_dump_interval_add(bgp_dump
, bgp_dump
->interval
);
480 /* Dump common information. */
481 static void bgp_dump_common(struct stream
*obuf
, struct peer
*peer
,
484 char empty
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
486 /* Source AS number and Destination AS number. */
487 if (forceas4
|| CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
488 stream_putl(obuf
, peer
->as
);
489 stream_putl(obuf
, peer
->local_as
);
491 stream_putw(obuf
, peer
->as
);
492 stream_putw(obuf
, peer
->local_as
);
495 if (peer
->su
.sa
.sa_family
== AF_INET
) {
496 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
497 stream_putw(obuf
, AFI_IP
);
499 stream_put(obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
502 stream_put(obuf
, &peer
->su_local
->sin
.sin_addr
,
505 stream_put(obuf
, empty
, IPV4_MAX_BYTELEN
);
506 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
507 /* Interface Index and Address family. */
508 stream_putw(obuf
, peer
->ifp
? peer
->ifp
->ifindex
: 0);
509 stream_putw(obuf
, AFI_IP6
);
511 /* Source IP Address and Destination IP Address. */
512 stream_put(obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
515 stream_put(obuf
, &peer
->su_local
->sin6
.sin6_addr
,
518 stream_put(obuf
, empty
, IPV6_MAX_BYTELEN
);
522 /* Dump BGP status change. */
523 int bgp_dump_state(struct peer
*peer
)
527 /* If dump file pointer is disabled return immediately. */
528 if (bgp_dump_all
.fp
== NULL
)
531 /* Make dump stream. */
532 obuf
= bgp_dump_obuf
;
535 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
,
537 bgp_dump_common(obuf
, peer
, 1); /* force this in as4speak*/
539 stream_putw(obuf
, peer
->ostatus
);
540 stream_putw(obuf
, peer
->status
);
543 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
545 /* Write to the stream. */
546 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump_all
.fp
);
547 fflush(bgp_dump_all
.fp
);
551 static void bgp_dump_packet_func(struct bgp_dump
*bgp_dump
, struct peer
*peer
,
552 struct stream
*packet
)
555 int addpath_encoded
= 0;
556 /* If dump file pointer is disabled return immediately. */
557 if (bgp_dump
->fp
== NULL
)
559 if (peer
->su
.sa
.sa_family
== AF_INET
) {
561 bgp_addpath_encode_rx(peer
, AFI_IP
, SAFI_UNICAST
);
562 } else if (peer
->su
.sa
.sa_family
== AF_INET6
) {
564 bgp_addpath_encode_rx(peer
, AFI_IP6
, SAFI_UNICAST
);
567 /* Make dump stream. */
568 obuf
= bgp_dump_obuf
;
571 /* Dump header and common part. */
572 if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
) && addpath_encoded
) {
573 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
574 BGP4MP_MESSAGE_AS4_ADDPATH
, bgp_dump
->type
);
575 } else if (CHECK_FLAG(peer
->cap
, PEER_CAP_AS4_RCV
)) {
576 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
,
578 } else if (addpath_encoded
) {
579 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
,
580 BGP4MP_MESSAGE_ADDPATH
, bgp_dump
->type
);
582 bgp_dump_header(obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
,
585 bgp_dump_common(obuf
, peer
, 0);
587 /* Packet contents. */
588 stream_put(obuf
, STREAM_DATA(packet
), stream_get_endp(packet
));
591 bgp_dump_set_size(obuf
, MSG_PROTOCOL_BGP4MP
);
593 /* Write to the stream. */
594 fwrite(STREAM_DATA(obuf
), stream_get_endp(obuf
), 1, bgp_dump
->fp
);
595 fflush(bgp_dump
->fp
);
598 /* Called from bgp_packet.c when BGP packet is received. */
599 static int bgp_dump_packet(struct peer
*peer
, uint8_t type
, bgp_size_t size
,
600 struct stream
*packet
)
603 bgp_dump_packet_func(&bgp_dump_all
, peer
, packet
);
605 /* bgp_dump_updates. */
606 if (type
== BGP_MSG_UPDATE
)
607 bgp_dump_packet_func(&bgp_dump_updates
, peer
, packet
);
611 static unsigned int bgp_dump_parse_time(const char *str
)
626 for (i
= 0; i
< len
; i
++) {
627 if (isdigit((unsigned char)str
[i
])) {
629 time
+= str
[i
] - '0';
630 } else if (str
[i
] == 'H' || str
[i
] == 'h') {
635 total
+= time
* 60 * 60;
638 } else if (str
[i
] == 'M' || str
[i
] == 'm') {
650 static int bgp_dump_set(struct vty
*vty
, struct bgp_dump
*bgp_dump
,
651 enum bgp_dump_type type
, const char *path
,
652 const char *interval_str
)
654 unsigned int interval
;
656 /* Don't schedule duplicate dumps if the dump command is given twice */
657 if (bgp_dump
->filename
&& strcmp(path
, bgp_dump
->filename
) == 0
658 && type
== bgp_dump
->type
) {
660 if (bgp_dump
->interval_str
661 && strcmp(bgp_dump
->interval_str
, interval_str
)
665 if (!bgp_dump
->interval_str
)
670 /* Removing previous config */
671 bgp_dump_unset(bgp_dump
);
674 /* Check interval string. */
675 interval
= bgp_dump_parse_time(interval_str
);
677 vty_out(vty
, "Malformed interval string\n");
678 return CMD_WARNING_CONFIG_FAILED
;
681 /* Setting interval string */
682 bgp_dump
->interval_str
=
683 XSTRDUP(MTYPE_BGP_DUMP_STR
, interval_str
);
689 bgp_dump
->type
= type
;
692 bgp_dump
->interval
= interval
;
695 bgp_dump
->filename
= XSTRDUP(MTYPE_BGP_DUMP_STR
, path
);
697 /* Create interval thread. */
698 bgp_dump_interval_add(bgp_dump
, interval
);
700 /* This should be called when interval is expired. */
701 bgp_dump_open_file(bgp_dump
);
706 static int bgp_dump_unset(struct bgp_dump
*bgp_dump
)
708 /* Removing file name. */
709 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->filename
);
713 fclose(bgp_dump
->fp
);
717 /* Removing interval event. */
718 thread_cancel(&bgp_dump
->t_interval
);
720 bgp_dump
->interval
= 0;
722 /* Removing interval string. */
723 XFREE(MTYPE_BGP_DUMP_STR
, bgp_dump
->interval_str
);
730 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
733 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
734 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
735 "Dump whole BGP routing table\n"
737 "Interval of output\n")
739 int idx_dump_routes
= 2;
741 int idx_interval
= 4;
742 int bgp_dump_type
= 0;
743 const char *interval
= NULL
;
744 struct bgp_dump
*bgp_dump_struct
= NULL
;
745 const struct bgp_dump_type_map
*map
= NULL
;
747 for (map
= bgp_dump_type_map
; map
->str
; map
++)
748 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
749 bgp_dump_type
= map
->type
;
751 switch (bgp_dump_type
) {
753 case BGP_DUMP_ALL_ET
:
754 bgp_dump_struct
= &bgp_dump_all
;
756 case BGP_DUMP_UPDATES
:
757 case BGP_DUMP_UPDATES_ET
:
758 bgp_dump_struct
= &bgp_dump_updates
;
760 case BGP_DUMP_ROUTES
:
762 bgp_dump_struct
= &bgp_dump_routes
;
766 /* When an interval is given */
767 if (argc
== idx_interval
+ 1)
768 interval
= argv
[idx_interval
]->arg
;
770 return bgp_dump_set(vty
, bgp_dump_struct
, bgp_dump_type
,
771 argv
[idx_path
]->arg
, interval
);
774 DEFUN (no_dump_bgp_all
,
776 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
779 "Stop BGP packet dump\n"
780 "Stop dump process all\n"
781 "Stop dump process all-et\n"
782 "Stop dump process updates\n"
783 "Stop dump process updates-et\n"
784 "Stop dump process route-mrt\n"
786 "Interval of output\n")
788 int idx_dump_routes
= 3;
789 int bgp_dump_type
= 0;
790 const struct bgp_dump_type_map
*map
= NULL
;
791 struct bgp_dump
*bgp_dump_struct
= NULL
;
793 for (map
= bgp_dump_type_map
; map
->str
; map
++)
794 if (strmatch(argv
[idx_dump_routes
]->text
, map
->str
))
795 bgp_dump_type
= map
->type
;
797 switch (bgp_dump_type
) {
799 case BGP_DUMP_ALL_ET
:
800 bgp_dump_struct
= &bgp_dump_all
;
802 case BGP_DUMP_UPDATES
:
803 case BGP_DUMP_UPDATES_ET
:
804 bgp_dump_struct
= &bgp_dump_updates
;
806 case BGP_DUMP_ROUTES
:
808 bgp_dump_struct
= &bgp_dump_routes
;
812 return bgp_dump_unset(bgp_dump_struct
);
815 static int config_write_bgp_dump(struct vty
*vty
);
816 /* BGP node structure. */
817 static struct cmd_node bgp_dump_node
= {
821 .config_write
= config_write_bgp_dump
,
824 static int config_write_bgp_dump(struct vty
*vty
)
826 if (bgp_dump_all
.filename
) {
827 const char *type_str
= "all";
828 if (bgp_dump_all
.type
== BGP_DUMP_ALL_ET
)
831 if (bgp_dump_all
.interval_str
)
832 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
833 bgp_dump_all
.filename
,
834 bgp_dump_all
.interval_str
);
836 vty_out(vty
, "dump bgp %s %s\n", type_str
,
837 bgp_dump_all
.filename
);
839 if (bgp_dump_updates
.filename
) {
840 const char *type_str
= "updates";
841 if (bgp_dump_updates
.type
== BGP_DUMP_UPDATES_ET
)
842 type_str
= "updates-et";
844 if (bgp_dump_updates
.interval_str
)
845 vty_out(vty
, "dump bgp %s %s %s\n", type_str
,
846 bgp_dump_updates
.filename
,
847 bgp_dump_updates
.interval_str
);
849 vty_out(vty
, "dump bgp %s %s\n", type_str
,
850 bgp_dump_updates
.filename
);
852 if (bgp_dump_routes
.filename
) {
853 if (bgp_dump_routes
.interval_str
)
854 vty_out(vty
, "dump bgp routes-mrt %s %s\n",
855 bgp_dump_routes
.filename
,
856 bgp_dump_routes
.interval_str
);
858 vty_out(vty
, "dump bgp routes-mrt %s\n",
859 bgp_dump_routes
.filename
);
864 /* Initialize BGP packet dump functionality. */
865 void bgp_dump_init(void)
867 memset(&bgp_dump_all
, 0, sizeof(struct bgp_dump
));
868 memset(&bgp_dump_updates
, 0, sizeof(struct bgp_dump
));
869 memset(&bgp_dump_routes
, 0, sizeof(struct bgp_dump
));
872 stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
* 2)
873 + BGP_DUMP_MSG_HEADER
+ BGP_DUMP_HEADER_SIZE
);
875 install_node(&bgp_dump_node
);
877 install_element(CONFIG_NODE
, &dump_bgp_all_cmd
);
878 install_element(CONFIG_NODE
, &no_dump_bgp_all_cmd
);
880 hook_register(bgp_packet_dump
, bgp_dump_packet
);
881 hook_register(peer_status_changed
, bgp_dump_state
);
884 void bgp_dump_finish(void)
886 bgp_dump_unset(&bgp_dump_all
);
887 bgp_dump_unset(&bgp_dump_updates
);
888 bgp_dump_unset(&bgp_dump_routes
);
890 stream_free(bgp_dump_obuf
);
891 bgp_dump_obuf
= NULL
;
892 hook_unregister(bgp_packet_dump
, bgp_dump_packet
);
893 hook_unregister(peer_status_changed
, bgp_dump_state
);