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
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 #include "sockunion.h"
30 #include "bgpd/bgp_table.h"
32 #include "bgpd/bgpd.h"
33 #include "bgpd/bgp_route.h"
34 #include "bgpd/bgp_attr.h"
35 #include "bgpd/bgp_dump.h"
46 MSG_START
, /* sender is starting up */
47 MSG_DIE
, /* receiver should shut down */
48 MSG_I_AM_DEAD
, /* sender is shutting down */
49 MSG_PEER_DOWN
, /* sender's peer is down */
50 MSG_PROTOCOL_BGP
, /* msg is a BGP packet */
51 MSG_PROTOCOL_RIP
, /* msg is a RIP packet */
52 MSG_PROTOCOL_IDRP
, /* msg is an IDRP packet */
53 MSG_PROTOCOL_RIPNG
, /* msg is a RIPNG packet */
54 MSG_PROTOCOL_BGP4PLUS
, /* msg is a BGP4+ packet */
55 MSG_PROTOCOL_BGP4PLUS_01
, /* msg is a BGP4+ (draft 01) packet */
56 MSG_PROTOCOL_OSPF
, /* msg is an OSPF packet */
57 MSG_TABLE_DUMP
, /* routing table dump */
58 MSG_TABLE_DUMP_V2
/* routing table dump, version 2 */
61 static int bgp_dump_interval_func (struct thread
*);
65 enum bgp_dump_type type
;
71 unsigned int interval
;
75 struct thread
*t_interval
;
78 /* BGP packet dump output buffer. */
79 struct stream
*bgp_dump_obuf
;
81 /* BGP dump strucuture for 'dump bgp all' */
82 struct bgp_dump bgp_dump_all
;
84 /* BGP dump structure for 'dump bgp updates' */
85 struct bgp_dump bgp_dump_updates
;
87 /* BGP dump structure for 'dump bgp routes' */
88 struct bgp_dump bgp_dump_routes
;
90 /* Dump whole BGP table is very heavy process. */
91 struct thread
*t_bgp_dump_routes
;
93 /* Some define for BGP packet dump. */
95 bgp_dump_open_file (struct bgp_dump
*bgp_dump
)
100 char fullpath
[MAXPATHLEN
];
101 char realpath
[MAXPATHLEN
];
105 tm
= localtime (&clock
);
107 if (bgp_dump
->filename
[0] != DIRECTORY_SEP
)
109 sprintf (fullpath
, "%s/%s", vty_get_cwd (), bgp_dump
->filename
);
110 ret
= strftime (realpath
, MAXPATHLEN
, fullpath
, tm
);
113 ret
= strftime (realpath
, MAXPATHLEN
, bgp_dump
->filename
, tm
);
117 zlog_warn ("bgp_dump_open_file: strftime error");
122 fclose (bgp_dump
->fp
);
125 oldumask
= umask(0777 & ~LOGFILE_MASK
);
126 bgp_dump
->fp
= fopen (realpath
, "w");
128 if (bgp_dump
->fp
== NULL
)
130 zlog_warn ("bgp_dump_open_file: %s: %s", realpath
, strerror (errno
));
140 bgp_dump_interval_add (struct bgp_dump
*bgp_dump
, int interval
)
148 /* Periodic dump every interval seconds */
149 if ((interval
< 86400) && ((86400 % interval
) == 0))
151 /* Dump at predictable times: if a day has a whole number of
152 * intervals, dump every interval seconds starting from midnight
156 secs_into_day
= tm
->tm_sec
+ 60*tm
->tm_min
+ 60*60*tm
->tm_hour
;
157 interval
= interval
- secs_into_day
% interval
; /* always > 0 */
159 bgp_dump
->t_interval
= thread_add_timer (master
, bgp_dump_interval_func
,
164 /* One-off dump: execute immediately, don't affect any scheduled dumps */
165 bgp_dump
->t_interval
= thread_add_event (master
, bgp_dump_interval_func
,
172 /* Dump common header. */
174 bgp_dump_header (struct stream
*obuf
, int type
, int subtype
)
181 /* Put dump packet header. */
182 stream_putl (obuf
, now
);
183 stream_putw (obuf
, type
);
184 stream_putw (obuf
, subtype
);
186 stream_putl (obuf
, 0); /* len */
190 bgp_dump_set_size (struct stream
*s
, int type
)
192 stream_putl_at (s
, 8, stream_get_endp (s
) - BGP_DUMP_HEADER_SIZE
);
196 bgp_dump_routes_index_table(struct bgp
*bgp
)
199 struct listnode
*node
;
203 obuf
= bgp_dump_obuf
;
207 bgp_dump_header (obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_PEER_INDEX_TABLE
);
209 /* Collector BGP ID */
210 stream_put_in_addr (obuf
, &bgp
->router_id
);
215 stream_putw (obuf
, strlen(bgp
->name
));
216 stream_put(obuf
, bgp
->name
, strlen(bgp
->name
));
220 stream_putw(obuf
, 0);
224 stream_putw (obuf
, listcount(bgp
->peer
));
226 /* Walk down all peers */
227 for(ALL_LIST_ELEMENTS_RO (bgp
->peer
, node
, peer
))
231 if (sockunion_family(&peer
->su
) == AF_INET
)
233 stream_putc (obuf
, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP
);
236 else if (sockunion_family(&peer
->su
) == AF_INET6
)
238 stream_putc (obuf
, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6
);
240 #endif /* HAVE_IPV6 */
243 stream_put_in_addr (obuf
, &peer
->remote_id
);
245 /* Peer's IP address */
246 if (sockunion_family(&peer
->su
) == AF_INET
)
248 stream_put_in_addr (obuf
, &peer
->su
.sin
.sin_addr
);
251 else if (sockunion_family(&peer
->su
) == AF_INET6
)
253 stream_write (obuf
, (u_char
*)&peer
->su
.sin6
.sin6_addr
,
256 #endif /* HAVE_IPV6 */
258 /* Peer's AS number. */
259 /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
260 stream_putl (obuf
, peer
->as
);
262 /* Store the peer number for this peer */
263 peer
->table_dump_index
= peerno
;
267 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
269 fwrite (STREAM_DATA (obuf
), stream_get_endp (obuf
), 1, bgp_dump_routes
.fp
);
270 fflush (bgp_dump_routes
.fp
);
274 /* Runs under child process. */
276 bgp_dump_routes_func (int afi
, int first_run
, unsigned int seq
)
279 struct bgp_info
*info
;
282 struct bgp_table
*table
;
284 bgp
= bgp_get_default ();
288 if (bgp_dump_routes
.fp
== NULL
)
291 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
292 so this should only be done on the first call to bgp_dump_routes_func.
293 ( this function will be called once for ipv4 and once for ipv6 ) */
295 bgp_dump_routes_index_table(bgp
);
297 obuf
= bgp_dump_obuf
;
300 /* Walk down each BGP route. */
301 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
303 for (rn
= bgp_table_top (table
); rn
; rn
= bgp_route_next (rn
))
313 bgp_dump_header (obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_RIB_IPV4_UNICAST
);
316 else if (afi
== AFI_IP6
)
318 bgp_dump_header (obuf
, MSG_TABLE_DUMP_V2
, TABLE_DUMP_V2_RIB_IPV6_UNICAST
);
320 #endif /* HAVE_IPV6 */
322 /* Sequence number */
323 stream_putl(obuf
, seq
);
326 stream_putc (obuf
, rn
->p
.prefixlen
);
331 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
332 stream_write(obuf
, (u_char
*)&rn
->p
.u
.prefix4
, (rn
->p
.prefixlen
+7)/8);
335 else if (afi
== AFI_IP6
)
337 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
338 stream_write (obuf
, (u_char
*)&rn
->p
.u
.prefix6
, (rn
->p
.prefixlen
+7)/8);
340 #endif /* HAVE_IPV6 */
342 /* Save where we are now, so we can overwride the entry count later */
343 int sizep
= stream_get_endp(obuf
);
346 uint16_t entry_count
= 0;
348 /* Entry count, note that this is overwritten later */
349 stream_putw(obuf
, 0);
351 for (info
= rn
->info
; info
; info
= info
->next
)
356 stream_putw(obuf
, info
->peer
->table_dump_index
);
359 stream_putl (obuf
, info
->uptime
);
361 /* Dump attribute. */
362 /* Skip prefix & AFI/SAFI for MP_NLRI */
363 bgp_dump_routes_attr (obuf
, info
->attr
, &rn
->p
);
366 /* Overwrite the entry count, now that we know the right number */
367 stream_putw_at (obuf
, sizep
, entry_count
);
371 bgp_dump_set_size(obuf
, MSG_TABLE_DUMP_V2
);
372 fwrite (STREAM_DATA (obuf
), stream_get_endp (obuf
), 1, bgp_dump_routes
.fp
);
376 fflush (bgp_dump_routes
.fp
);
382 bgp_dump_interval_func (struct thread
*t
)
384 struct bgp_dump
*bgp_dump
;
385 bgp_dump
= THREAD_ARG (t
);
386 bgp_dump
->t_interval
= NULL
;
388 /* Reschedule dump even if file couldn't be opened this time... */
389 if (bgp_dump_open_file (bgp_dump
) != NULL
)
391 /* In case of bgp_dump_routes, we need special route dump function. */
392 if (bgp_dump
->type
== BGP_DUMP_ROUTES
)
394 unsigned int seq
= bgp_dump_routes_func (AFI_IP
, 1, 0);
396 bgp_dump_routes_func (AFI_IP6
, 0, seq
);
397 #endif /* HAVE_IPV6 */
398 /* Close the file now. For a RIB dump there's no point in leaving
399 * it open until the next scheduled dump starts. */
400 fclose(bgp_dump
->fp
); bgp_dump
->fp
= NULL
;
404 /* if interval is set reschedule */
405 if (bgp_dump
->interval
> 0)
406 bgp_dump_interval_add (bgp_dump
, bgp_dump
->interval
);
411 /* Dump common information. */
413 bgp_dump_common (struct stream
*obuf
, struct peer
*peer
, int forceas4
)
415 char empty
[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
417 /* Source AS number and Destination AS number. */
418 if (forceas4
|| CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
) )
420 stream_putl (obuf
, peer
->as
);
421 stream_putl (obuf
, peer
->local_as
);
425 stream_putw (obuf
, peer
->as
);
426 stream_putw (obuf
, peer
->local_as
);
429 if (peer
->su
.sa
.sa_family
== AF_INET
)
431 stream_putw (obuf
, peer
->ifindex
);
432 stream_putw (obuf
, AFI_IP
);
434 stream_put (obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
437 stream_put (obuf
, &peer
->su_local
->sin
.sin_addr
, IPV4_MAX_BYTELEN
);
439 stream_put (obuf
, empty
, IPV4_MAX_BYTELEN
);
442 else if (peer
->su
.sa
.sa_family
== AF_INET6
)
444 /* Interface Index and Address family. */
445 stream_putw (obuf
, peer
->ifindex
);
446 stream_putw (obuf
, AFI_IP6
);
448 /* Source IP Address and Destination IP Address. */
449 stream_put (obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
452 stream_put (obuf
, &peer
->su_local
->sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
454 stream_put (obuf
, empty
, IPV6_MAX_BYTELEN
);
456 #endif /* HAVE_IPV6 */
459 /* Dump BGP status change. */
461 bgp_dump_state (struct peer
*peer
, int status_old
, int status_new
)
465 /* If dump file pointer is disabled return immediately. */
466 if (bgp_dump_all
.fp
== NULL
)
469 /* Make dump stream. */
470 obuf
= bgp_dump_obuf
;
473 bgp_dump_header (obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE_AS4
);
474 bgp_dump_common (obuf
, peer
, 1);/* force this in as4speak*/
476 stream_putw (obuf
, status_old
);
477 stream_putw (obuf
, status_new
);
480 bgp_dump_set_size (obuf
, MSG_PROTOCOL_BGP4MP
);
482 /* Write to the stream. */
483 fwrite (STREAM_DATA (obuf
), stream_get_endp (obuf
), 1, bgp_dump_all
.fp
);
484 fflush (bgp_dump_all
.fp
);
488 bgp_dump_packet_func (struct bgp_dump
*bgp_dump
, struct peer
*peer
,
489 struct stream
*packet
)
493 /* If dump file pointer is disabled return immediately. */
494 if (bgp_dump
->fp
== NULL
)
497 /* Make dump stream. */
498 obuf
= bgp_dump_obuf
;
501 /* Dump header and common part. */
502 if (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
) )
504 bgp_dump_header (obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE_AS4
);
508 bgp_dump_header (obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
);
510 bgp_dump_common (obuf
, peer
, 0);
512 /* Packet contents. */
513 stream_put (obuf
, STREAM_DATA (packet
), stream_get_endp (packet
));
516 bgp_dump_set_size (obuf
, MSG_PROTOCOL_BGP4MP
);
518 /* Write to the stream. */
519 fwrite (STREAM_DATA (obuf
), stream_get_endp (obuf
), 1, bgp_dump
->fp
);
520 fflush (bgp_dump
->fp
);
523 /* Called from bgp_packet.c when BGP packet is received. */
525 bgp_dump_packet (struct peer
*peer
, int type
, struct stream
*packet
)
528 bgp_dump_packet_func (&bgp_dump_all
, peer
, packet
);
530 /* bgp_dump_updates. */
531 if (type
== BGP_MSG_UPDATE
)
532 bgp_dump_packet_func (&bgp_dump_updates
, peer
, packet
);
536 bgp_dump_parse_time (const char *str
)
551 for (i
= 0; i
< len
; i
++)
553 if (isdigit ((int) str
[i
]))
556 time
+= str
[i
] - '0';
558 else if (str
[i
] == 'H' || str
[i
] == 'h')
564 total
+= time
* 60 *60;
568 else if (str
[i
] == 'M' || str
[i
] == 'm')
583 bgp_dump_set (struct vty
*vty
, struct bgp_dump
*bgp_dump
,
584 enum bgp_dump_type type
, const char *path
,
585 const char *interval_str
)
587 unsigned int interval
;
592 /* Check interval string. */
593 interval
= bgp_dump_parse_time (interval_str
);
596 vty_out (vty
, "Malformed interval string%s", VTY_NEWLINE
);
600 /* Don't schedule duplicate dumps if the dump command is given twice */
601 if (interval
== bgp_dump
->interval
&&
602 type
== bgp_dump
->type
&&
603 path
&& bgp_dump
->filename
&& !strcmp (path
, bgp_dump
->filename
))
609 bgp_dump
->interval
= interval
;
610 if (bgp_dump
->interval_str
)
611 free (bgp_dump
->interval_str
);
612 bgp_dump
->interval_str
= strdup (interval_str
);
620 /* Create interval thread. */
621 bgp_dump_interval_add (bgp_dump
, interval
);
624 bgp_dump
->type
= type
;
627 if (bgp_dump
->filename
)
628 free (bgp_dump
->filename
);
629 bgp_dump
->filename
= strdup (path
);
631 /* This should be called when interval is expired. */
632 bgp_dump_open_file (bgp_dump
);
638 bgp_dump_unset (struct vty
*vty
, struct bgp_dump
*bgp_dump
)
641 if (bgp_dump
->filename
)
643 free (bgp_dump
->filename
);
644 bgp_dump
->filename
= NULL
;
647 /* This should be called when interval is expired. */
650 fclose (bgp_dump
->fp
);
654 /* Create interval thread. */
655 if (bgp_dump
->t_interval
)
657 thread_cancel (bgp_dump
->t_interval
);
658 bgp_dump
->t_interval
= NULL
;
661 bgp_dump
->interval
= 0;
663 if (bgp_dump
->interval_str
)
665 free (bgp_dump
->interval_str
);
666 bgp_dump
->interval_str
= NULL
;
678 "Dump all BGP packets\n"
681 return bgp_dump_set (vty
, &bgp_dump_all
, BGP_DUMP_ALL
, argv
[0], NULL
);
684 DEFUN (dump_bgp_all_interval
,
685 dump_bgp_all_interval_cmd
,
686 "dump bgp all PATH INTERVAL",
689 "Dump all BGP packets\n"
691 "Interval of output\n")
693 return bgp_dump_set (vty
, &bgp_dump_all
, BGP_DUMP_ALL
, argv
[0], argv
[1]);
696 DEFUN (no_dump_bgp_all
,
698 "no dump bgp all [PATH] [INTERVAL]",
702 "Dump all BGP packets\n")
704 return bgp_dump_unset (vty
, &bgp_dump_all
);
707 DEFUN (dump_bgp_updates
,
708 dump_bgp_updates_cmd
,
709 "dump bgp updates PATH",
712 "Dump BGP updates only\n"
715 return bgp_dump_set (vty
, &bgp_dump_updates
, BGP_DUMP_UPDATES
, argv
[0], NULL
);
718 DEFUN (dump_bgp_updates_interval
,
719 dump_bgp_updates_interval_cmd
,
720 "dump bgp updates PATH INTERVAL",
723 "Dump BGP updates only\n"
725 "Interval of output\n")
727 return bgp_dump_set (vty
, &bgp_dump_updates
, BGP_DUMP_UPDATES
, argv
[0], argv
[1]);
730 DEFUN (no_dump_bgp_updates
,
731 no_dump_bgp_updates_cmd
,
732 "no dump bgp updates [PATH] [INTERVAL]",
736 "Dump BGP updates only\n")
738 return bgp_dump_unset (vty
, &bgp_dump_updates
);
741 DEFUN (dump_bgp_routes
,
743 "dump bgp routes-mrt PATH",
746 "Dump whole BGP routing table\n"
749 return bgp_dump_set (vty
, &bgp_dump_routes
, BGP_DUMP_ROUTES
, argv
[0], NULL
);
752 DEFUN (dump_bgp_routes_interval
,
753 dump_bgp_routes_interval_cmd
,
754 "dump bgp routes-mrt PATH INTERVAL",
757 "Dump whole BGP routing table\n"
759 "Interval of output\n")
761 return bgp_dump_set (vty
, &bgp_dump_routes
, BGP_DUMP_ROUTES
, argv
[0], argv
[1]);
764 DEFUN (no_dump_bgp_routes
,
765 no_dump_bgp_routes_cmd
,
766 "no dump bgp routes-mrt [PATH] [INTERVAL]",
770 "Dump whole BGP routing table\n")
772 return bgp_dump_unset (vty
, &bgp_dump_routes
);
775 /* BGP node structure. */
776 struct cmd_node bgp_dump_node
=
785 config_time2str (unsigned int interval
)
787 static char buf
[BUFSIZ
];
793 sprintf (buf
, "%dh", interval
/ 3600);
798 sprintf (buf
+ strlen (buf
), "%dm", interval
/60);
803 sprintf (buf
+ strlen (buf
), "%d", interval
);
810 config_write_bgp_dump (struct vty
*vty
)
812 if (bgp_dump_all
.filename
)
814 if (bgp_dump_all
.interval_str
)
815 vty_out (vty
, "dump bgp all %s %s%s",
816 bgp_dump_all
.filename
, bgp_dump_all
.interval_str
,
819 vty_out (vty
, "dump bgp all %s%s",
820 bgp_dump_all
.filename
, VTY_NEWLINE
);
822 if (bgp_dump_updates
.filename
)
824 if (bgp_dump_updates
.interval_str
)
825 vty_out (vty
, "dump bgp updates %s %s%s",
826 bgp_dump_updates
.filename
, bgp_dump_updates
.interval_str
,
829 vty_out (vty
, "dump bgp updates %s%s",
830 bgp_dump_updates
.filename
, VTY_NEWLINE
);
832 if (bgp_dump_routes
.filename
)
834 if (bgp_dump_routes
.interval_str
)
835 vty_out (vty
, "dump bgp routes-mrt %s %s%s",
836 bgp_dump_routes
.filename
, bgp_dump_routes
.interval_str
,
839 vty_out (vty
, "dump bgp routes-mrt %s%s",
840 bgp_dump_routes
.filename
, VTY_NEWLINE
);
845 /* Initialize BGP packet dump functionality. */
849 memset (&bgp_dump_all
, 0, sizeof (struct bgp_dump
));
850 memset (&bgp_dump_updates
, 0, sizeof (struct bgp_dump
));
851 memset (&bgp_dump_routes
, 0, sizeof (struct bgp_dump
));
853 bgp_dump_obuf
= stream_new (BGP_MAX_PACKET_SIZE
+ BGP_DUMP_MSG_HEADER
854 + BGP_DUMP_HEADER_SIZE
);
856 install_node (&bgp_dump_node
, config_write_bgp_dump
);
858 install_element (CONFIG_NODE
, &dump_bgp_all_cmd
);
859 install_element (CONFIG_NODE
, &dump_bgp_all_interval_cmd
);
860 install_element (CONFIG_NODE
, &no_dump_bgp_all_cmd
);
861 install_element (CONFIG_NODE
, &dump_bgp_updates_cmd
);
862 install_element (CONFIG_NODE
, &dump_bgp_updates_interval_cmd
);
863 install_element (CONFIG_NODE
, &no_dump_bgp_updates_cmd
);
864 install_element (CONFIG_NODE
, &dump_bgp_routes_cmd
);
865 install_element (CONFIG_NODE
, &dump_bgp_routes_interval_cmd
);
866 install_element (CONFIG_NODE
, &no_dump_bgp_routes_cmd
);