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"
29 #include "bgpd/bgp_table.h"
31 #include "bgpd/bgpd.h"
32 #include "bgpd/bgp_route.h"
33 #include "bgpd/bgp_attr.h"
34 #include "bgpd/bgp_dump.h"
45 MSG_START
, /* sender is starting up */
46 MSG_DIE
, /* receiver should shut down */
47 MSG_I_AM_DEAD
, /* sender is shutting down */
48 MSG_PEER_DOWN
, /* sender's peer is down */
49 MSG_PROTOCOL_BGP
, /* msg is a BGP packet */
50 MSG_PROTOCOL_RIP
, /* msg is a RIP packet */
51 MSG_PROTOCOL_IDRP
, /* msg is an IDRP packet */
52 MSG_PROTOCOL_RIPNG
, /* msg is a RIPNG packet */
53 MSG_PROTOCOL_BGP4PLUS
, /* msg is a BGP4+ packet */
54 MSG_PROTOCOL_BGP4PLUS_01
, /* msg is a BGP4+ (draft 01) packet */
55 MSG_PROTOCOL_OSPF
, /* msg is an OSPF packet */
56 MSG_TABLE_DUMP
/* routing table dump */
61 enum bgp_dump_type type
;
67 unsigned int interval
;
71 struct thread
*t_interval
;
74 /* BGP packet dump output buffer. */
75 struct stream
*bgp_dump_obuf
;
77 /* BGP dump strucuture for 'dump bgp all' */
78 struct bgp_dump bgp_dump_all
;
80 /* BGP dump structure for 'dump bgp updates' */
81 struct bgp_dump bgp_dump_updates
;
83 /* BGP dump structure for 'dump bgp routes' */
84 struct bgp_dump bgp_dump_routes
;
86 /* Dump whole BGP table is very heavy process. */
87 struct thread
*t_bgp_dump_routes
;
89 /* Some define for BGP packet dump. */
91 bgp_dump_open_file (struct bgp_dump
*bgp_dump
)
96 char fullpath
[MAXPATHLEN
];
97 char realpath
[MAXPATHLEN
];
101 tm
= localtime (&clock
);
103 if (bgp_dump
->filename
[0] != DIRECTORY_SEP
)
105 sprintf (fullpath
, "%s/%s", vty_get_cwd (), bgp_dump
->filename
);
106 ret
= strftime (realpath
, MAXPATHLEN
, fullpath
, tm
);
109 ret
= strftime (realpath
, MAXPATHLEN
, bgp_dump
->filename
, tm
);
113 zlog_warn ("bgp_dump_open_file: strftime error");
118 fclose (bgp_dump
->fp
);
121 oldumask
= umask(0777 & ~LOGFILE_MASK
);
122 bgp_dump
->fp
= fopen (realpath
, "w");
124 if (bgp_dump
->fp
== NULL
)
135 bgp_dump_interval_add (struct bgp_dump
*bgp_dump
, int interval
)
137 static int bgp_dump_interval_func (struct thread
*t
);
138 int interval2
, secs_into_day
;
144 if ((interval
< 86400) && ((86400 % interval
) == 0))
148 secs_into_day
= tm
->tm_sec
+ 60*tm
->tm_min
+ 60*60*tm
->tm_hour
;
149 interval2
= interval
- secs_into_day
% interval
;
150 if(interval2
== 0) interval2
= interval
;
154 interval2
= interval
;
156 bgp_dump
->t_interval
= thread_add_timer (master
, bgp_dump_interval_func
,
157 bgp_dump
, interval2
);
161 bgp_dump
->t_interval
= thread_add_event (master
, bgp_dump_interval_func
,
168 /* Dump common header. */
170 bgp_dump_header (struct stream
*obuf
, int type
, int subtype
)
177 /* Put dump packet header. */
178 stream_putl (obuf
, now
);
179 stream_putw (obuf
, type
);
180 stream_putw (obuf
, subtype
);
182 stream_putl (obuf
, 0); /* len */
186 bgp_dump_set_size (struct stream
*s
, int type
)
188 stream_putl_at (s
, 8, stream_get_endp (s
) - BGP_DUMP_HEADER_SIZE
);
192 bgp_dump_routes_entry (struct prefix
*p
, struct bgp_info
*info
, int afi
,
193 int type
, unsigned int seq
)
201 /* Make dump stream. */
202 obuf
= bgp_dump_obuf
;
208 /* We support MRT's old format. */
209 if (type
== MSG_TABLE_DUMP
)
211 bgp_dump_header (obuf
, MSG_TABLE_DUMP
, afi
);
212 stream_putw (obuf
, 0); /* View # */
213 stream_putw (obuf
, seq
); /* Sequence number. */
217 bgp_dump_header (obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_ENTRY
);
219 stream_putl (obuf
, info
->uptime
); /* Time Last Change */
220 stream_putw (obuf
, afi
); /* Address Family */
221 stream_putc (obuf
, safi
); /* SAFI */
226 if (type
== MSG_TABLE_DUMP
)
229 stream_put_in_addr (obuf
, &p
->u
.prefix4
);
230 stream_putc (obuf
, p
->prefixlen
);
233 stream_putc (obuf
, 1);
236 stream_putl (obuf
, info
->uptime
);
238 /* Peer's IP address */
239 stream_put_in_addr (obuf
, &peer
->su
.sin
.sin_addr
);
241 /* Peer's AS number. */
242 stream_putw (obuf
, peer
->as
);
244 /* Dump attribute. */
245 bgp_dump_routes_attr (obuf
, attr
, p
);
250 stream_putc (obuf
, IPV4_MAX_BYTELEN
);
251 stream_put_in_addr (obuf
, &attr
->nexthop
);
252 stream_putc (obuf
, p
->prefixlen
);
253 plen
= PSIZE (p
->prefixlen
);
254 stream_put (obuf
, &p
->u
.prefix4
, plen
);
255 bgp_dump_routes_attr (obuf
, attr
, p
);
259 else if (afi
== AFI_IP6
)
261 if (type
== MSG_TABLE_DUMP
)
264 stream_write (obuf
, (u_char
*)&p
->u
.prefix6
, IPV6_MAX_BYTELEN
);
265 stream_putc (obuf
, p
->prefixlen
);
268 stream_putc (obuf
, 1);
271 stream_putl (obuf
, info
->uptime
);
273 /* Peer's IP address */
274 stream_write (obuf
, (u_char
*)&peer
->su
.sin6
.sin6_addr
,
277 /* Peer's AS number. */
278 stream_putw (obuf
, peer
->as
);
280 /* Dump attribute. */
281 bgp_dump_routes_attr (obuf
, attr
, p
);
288 #endif /* HAVE_IPV6 */
291 bgp_dump_set_size (obuf
, type
);
293 fwrite (STREAM_DATA (obuf
), stream_get_endp (obuf
), 1, bgp_dump_routes
.fp
);
294 fflush (bgp_dump_routes
.fp
);
297 /* Runs under child process. */
299 bgp_dump_routes_func (int afi
)
303 struct bgp_info
*info
;
305 struct bgp_table
*table
;
306 unsigned int seq
= 0;
308 obuf
= bgp_dump_obuf
;
310 bgp
= bgp_get_default ();
314 if (bgp_dump_routes
.fp
== NULL
)
317 /* Walk down each BGP route. */
318 table
= bgp
->rib
[afi
][SAFI_UNICAST
];
320 for (rn
= bgp_table_top (table
); rn
; rn
= bgp_route_next (rn
))
321 for (info
= rn
->info
; info
; info
= info
->next
)
322 bgp_dump_routes_entry (&rn
->p
, info
, afi
, MSG_TABLE_DUMP
, seq
++);
326 bgp_dump_interval_func (struct thread
*t
)
328 struct bgp_dump
*bgp_dump
;
329 bgp_dump
= THREAD_ARG (t
);
330 bgp_dump
->t_interval
= NULL
;
332 /* Reschedule dump even if file couldn't be opened this time... */
333 if (bgp_dump_open_file (bgp_dump
) != NULL
)
335 /* In case of bgp_dump_routes, we need special route dump function. */
336 if (bgp_dump
->type
== BGP_DUMP_ROUTES
)
338 bgp_dump_routes_func (AFI_IP
);
340 bgp_dump_routes_func (AFI_IP6
);
341 #endif /* HAVE_IPV6 */
342 /* Close the file now. For a RIB dump there's no point in leaving
343 * it open until the next scheduled dump starts. */
344 fclose(bgp_dump
->fp
); bgp_dump
->fp
= NULL
;
348 /* if interval is set reschedule */
349 if (bgp_dump
->interval
> 0)
350 bgp_dump_interval_add (bgp_dump
, bgp_dump
->interval
);
355 /* Dump common information. */
357 bgp_dump_common (struct stream
*obuf
, struct peer
*peer
)
359 char empty
[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
361 /* Source AS number and Destination AS number. */
362 stream_putw (obuf
, peer
->as
);
363 stream_putw (obuf
, peer
->local_as
);
365 if (peer
->su
.sa
.sa_family
== AF_INET
)
367 stream_putw (obuf
, peer
->ifindex
);
368 stream_putw (obuf
, AFI_IP
);
370 stream_put (obuf
, &peer
->su
.sin
.sin_addr
, IPV4_MAX_BYTELEN
);
373 stream_put (obuf
, &peer
->su_local
->sin
.sin_addr
, IPV4_MAX_BYTELEN
);
375 stream_put (obuf
, empty
, IPV4_MAX_BYTELEN
);
378 else if (peer
->su
.sa
.sa_family
== AF_INET6
)
380 /* Interface Index and Address family. */
381 stream_putw (obuf
, peer
->ifindex
);
382 stream_putw (obuf
, AFI_IP6
);
384 /* Source IP Address and Destination IP Address. */
385 stream_put (obuf
, &peer
->su
.sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
388 stream_put (obuf
, &peer
->su_local
->sin6
.sin6_addr
, IPV6_MAX_BYTELEN
);
390 stream_put (obuf
, empty
, IPV6_MAX_BYTELEN
);
392 #endif /* HAVE_IPV6 */
395 /* Dump BGP status change. */
397 bgp_dump_state (struct peer
*peer
, int status_old
, int status_new
)
401 /* If dump file pointer is disabled return immediately. */
402 if (bgp_dump_all
.fp
== NULL
)
405 /* Make dump stream. */
406 obuf
= bgp_dump_obuf
;
409 bgp_dump_header (obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_STATE_CHANGE
);
410 bgp_dump_common (obuf
, peer
);
412 stream_putw (obuf
, status_old
);
413 stream_putw (obuf
, status_new
);
416 bgp_dump_set_size (obuf
, MSG_PROTOCOL_BGP4MP
);
418 /* Write to the stream. */
419 fwrite (STREAM_DATA (obuf
), stream_get_endp (obuf
), 1, bgp_dump_all
.fp
);
420 fflush (bgp_dump_all
.fp
);
424 bgp_dump_packet_func (struct bgp_dump
*bgp_dump
, struct peer
*peer
,
425 struct stream
*packet
)
429 /* If dump file pointer is disabled return immediately. */
430 if (bgp_dump
->fp
== NULL
)
433 /* Make dump stream. */
434 obuf
= bgp_dump_obuf
;
437 /* Dump header and common part. */
438 bgp_dump_header (obuf
, MSG_PROTOCOL_BGP4MP
, BGP4MP_MESSAGE
);
439 bgp_dump_common (obuf
, peer
);
441 /* Packet contents. */
442 stream_put (obuf
, STREAM_DATA (packet
), stream_get_endp (packet
));
445 bgp_dump_set_size (obuf
, MSG_PROTOCOL_BGP4MP
);
447 /* Write to the stream. */
448 fwrite (STREAM_DATA (obuf
), stream_get_endp (obuf
), 1, bgp_dump
->fp
);
449 fflush (bgp_dump
->fp
);
452 /* Called from bgp_packet.c when BGP packet is received. */
454 bgp_dump_packet (struct peer
*peer
, int type
, struct stream
*packet
)
457 bgp_dump_packet_func (&bgp_dump_all
, peer
, packet
);
459 /* bgp_dump_updates. */
460 if (type
== BGP_MSG_UPDATE
)
461 bgp_dump_packet_func (&bgp_dump_updates
, peer
, packet
);
465 bgp_dump_parse_time (const char *str
)
480 for (i
= 0; i
< len
; i
++)
482 if (isdigit ((int) str
[i
]))
485 time
+= str
[i
] - '0';
487 else if (str
[i
] == 'H' || str
[i
] == 'h')
493 total
+= time
* 60 *60;
497 else if (str
[i
] == 'M' || str
[i
] == 'm')
512 bgp_dump_set (struct vty
*vty
, struct bgp_dump
*bgp_dump
, int type
,
513 const char *path
, const char *interval_str
)
515 unsigned int interval
;
520 /* Check interval string. */
521 interval
= bgp_dump_parse_time (interval_str
);
524 vty_out (vty
, "Malformed interval string%s", VTY_NEWLINE
);
528 bgp_dump
->interval
= interval
;
529 if (bgp_dump
->interval_str
)
530 free (bgp_dump
->interval_str
);
531 bgp_dump
->interval_str
= strdup (interval_str
);
539 /* Create interval thread. */
540 bgp_dump_interval_add (bgp_dump
, interval
);
543 bgp_dump
->type
= type
;
546 if (bgp_dump
->filename
)
547 free (bgp_dump
->filename
);
548 bgp_dump
->filename
= strdup (path
);
550 /* This should be called when interval is expired. */
551 bgp_dump_open_file (bgp_dump
);
557 bgp_dump_unset (struct vty
*vty
, struct bgp_dump
*bgp_dump
)
560 if (bgp_dump
->filename
)
562 free (bgp_dump
->filename
);
563 bgp_dump
->filename
= NULL
;
566 /* This should be called when interval is expired. */
569 fclose (bgp_dump
->fp
);
573 /* Create interval thread. */
574 if (bgp_dump
->t_interval
)
576 thread_cancel (bgp_dump
->t_interval
);
577 bgp_dump
->t_interval
= NULL
;
580 bgp_dump
->interval
= 0;
582 if (bgp_dump
->interval_str
)
584 free (bgp_dump
->interval_str
);
585 bgp_dump
->interval_str
= NULL
;
597 "Dump all BGP packets\n"
600 return bgp_dump_set (vty
, &bgp_dump_all
, BGP_DUMP_ALL
, argv
[0], NULL
);
603 DEFUN (dump_bgp_all_interval
,
604 dump_bgp_all_interval_cmd
,
605 "dump bgp all PATH INTERVAL",
608 "Dump all BGP packets\n"
610 "Interval of output\n")
612 return bgp_dump_set (vty
, &bgp_dump_all
, BGP_DUMP_ALL
, argv
[0], argv
[1]);
615 DEFUN (no_dump_bgp_all
,
617 "no dump bgp all [PATH] [INTERVAL]",
621 "Dump all BGP packets\n")
623 return bgp_dump_unset (vty
, &bgp_dump_all
);
626 DEFUN (dump_bgp_updates
,
627 dump_bgp_updates_cmd
,
628 "dump bgp updates PATH",
631 "Dump BGP updates only\n"
634 return bgp_dump_set (vty
, &bgp_dump_updates
, BGP_DUMP_UPDATES
, argv
[0], NULL
);
637 DEFUN (dump_bgp_updates_interval
,
638 dump_bgp_updates_interval_cmd
,
639 "dump bgp updates PATH INTERVAL",
642 "Dump BGP updates only\n"
644 "Interval of output\n")
646 return bgp_dump_set (vty
, &bgp_dump_updates
, BGP_DUMP_UPDATES
, argv
[0], argv
[1]);
649 DEFUN (no_dump_bgp_updates
,
650 no_dump_bgp_updates_cmd
,
651 "no dump bgp updates [PATH] [INTERVAL]",
655 "Dump BGP updates only\n")
657 return bgp_dump_unset (vty
, &bgp_dump_updates
);
660 DEFUN (dump_bgp_routes
,
662 "dump bgp routes-mrt PATH",
665 "Dump whole BGP routing table\n"
668 return bgp_dump_set (vty
, &bgp_dump_routes
, BGP_DUMP_ROUTES
, argv
[0], NULL
);
671 DEFUN (dump_bgp_routes_interval
,
672 dump_bgp_routes_interval_cmd
,
673 "dump bgp routes-mrt PATH INTERVAL",
676 "Dump whole BGP routing table\n"
678 "Interval of output\n")
680 return bgp_dump_set (vty
, &bgp_dump_routes
, BGP_DUMP_ROUTES
, argv
[0], argv
[1]);
683 DEFUN (no_dump_bgp_routes
,
684 no_dump_bgp_routes_cmd
,
685 "no dump bgp routes-mrt [PATH] [INTERVAL]",
689 "Dump whole BGP routing table\n")
691 return bgp_dump_unset (vty
, &bgp_dump_routes
);
694 /* BGP node structure. */
695 struct cmd_node bgp_dump_node
=
704 config_time2str (unsigned int interval
)
706 static char buf
[BUFSIZ
];
712 sprintf (buf
, "%dh", interval
/ 3600);
717 sprintf (buf
+ strlen (buf
), "%dm", interval
/60);
722 sprintf (buf
+ strlen (buf
), "%d", interval
);
729 config_write_bgp_dump (struct vty
*vty
)
731 if (bgp_dump_all
.filename
)
733 if (bgp_dump_all
.interval_str
)
734 vty_out (vty
, "dump bgp all %s %s%s",
735 bgp_dump_all
.filename
, bgp_dump_all
.interval_str
,
738 vty_out (vty
, "dump bgp all %s%s",
739 bgp_dump_all
.filename
, VTY_NEWLINE
);
741 if (bgp_dump_updates
.filename
)
743 if (bgp_dump_updates
.interval_str
)
744 vty_out (vty
, "dump bgp updates %s %s%s",
745 bgp_dump_updates
.filename
, bgp_dump_updates
.interval_str
,
748 vty_out (vty
, "dump bgp updates %s%s",
749 bgp_dump_updates
.filename
, VTY_NEWLINE
);
751 if (bgp_dump_routes
.filename
)
753 if (bgp_dump_routes
.interval_str
)
754 vty_out (vty
, "dump bgp routes-mrt %s %s%s",
755 bgp_dump_routes
.filename
, bgp_dump_routes
.interval_str
,
758 vty_out (vty
, "dump bgp routes-mrt %s%s",
759 bgp_dump_routes
.filename
, VTY_NEWLINE
);
764 /* Initialize BGP packet dump functionality. */
768 memset (&bgp_dump_all
, 0, sizeof (struct bgp_dump
));
769 memset (&bgp_dump_updates
, 0, sizeof (struct bgp_dump
));
770 memset (&bgp_dump_routes
, 0, sizeof (struct bgp_dump
));
772 bgp_dump_obuf
= stream_new (BGP_MAX_PACKET_SIZE
+ BGP_DUMP_MSG_HEADER
773 + BGP_DUMP_HEADER_SIZE
);
775 install_node (&bgp_dump_node
, config_write_bgp_dump
);
777 install_element (CONFIG_NODE
, &dump_bgp_all_cmd
);
778 install_element (CONFIG_NODE
, &dump_bgp_all_interval_cmd
);
779 install_element (CONFIG_NODE
, &no_dump_bgp_all_cmd
);
780 install_element (CONFIG_NODE
, &dump_bgp_updates_cmd
);
781 install_element (CONFIG_NODE
, &dump_bgp_updates_interval_cmd
);
782 install_element (CONFIG_NODE
, &no_dump_bgp_updates_cmd
);
783 install_element (CONFIG_NODE
, &dump_bgp_routes_cmd
);
784 install_element (CONFIG_NODE
, &dump_bgp_routes_interval_cmd
);
785 install_element (CONFIG_NODE
, &no_dump_bgp_routes_cmd
);