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];
100 tm = localtime (&clock);
102 if (bgp_dump->filename[0] != DIRECTORY_SEP)
104 sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
105 ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
108 ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
112 zlog_warn ("bgp_dump_open_file: strftime error");
117 fclose (bgp_dump->fp);
120 bgp_dump->fp = fopen (realpath, "w");
122 if (bgp_dump->fp == NULL)
129 bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
131 int bgp_dump_interval_func (struct thread *);
133 bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func,
138 /* Dump common header. */
140 bgp_dump_header (struct stream *obuf, int type, int subtype)
147 /* Put dump packet header. */
148 stream_putl (obuf, now);
149 stream_putw (obuf, type);
150 stream_putw (obuf, subtype);
152 stream_putl (obuf, 0); /* len */
156 bgp_dump_set_size (struct stream *s, int type)
158 stream_putl_at (s, 8, stream_get_putp (s) - BGP_DUMP_HEADER_SIZE);
162 bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi,
163 int type, unsigned int seq)
171 /* Make dump stream. */
172 obuf = bgp_dump_obuf;
178 /* We support MRT's old format. */
179 if (type == MSG_TABLE_DUMP)
181 bgp_dump_header (obuf, MSG_TABLE_DUMP, afi);
182 stream_putw (obuf, 0); /* View # */
183 stream_putw (obuf, seq); /* Sequence number. */
187 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY);
189 stream_putl (obuf, info->uptime); /* Time Last Change */
190 stream_putw (obuf, afi); /* Address Family */
191 stream_putc (obuf, safi); /* SAFI */
196 if (type == MSG_TABLE_DUMP)
199 stream_put_in_addr (obuf, &p->u.prefix4);
200 stream_putc (obuf, p->prefixlen);
203 stream_putc (obuf, 1);
206 stream_putl (obuf, info->uptime);
208 /* Peer's IP address */
209 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
211 /* Peer's AS number. */
212 stream_putw (obuf, peer->as);
214 /* Dump attribute. */
215 bgp_dump_routes_attr (obuf, attr);
220 stream_putc (obuf, IPV4_MAX_BYTELEN);
221 stream_put_in_addr (obuf, &attr->nexthop);
222 stream_putc (obuf, p->prefixlen);
223 plen = PSIZE (p->prefixlen);
224 stream_put (obuf, &p->u.prefix4, plen);
225 bgp_dump_routes_attr (obuf, attr);
229 else if (afi == AFI_IP6)
231 if (type == MSG_TABLE_DUMP)
234 stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN);
235 stream_putc (obuf, p->prefixlen);
238 stream_putc (obuf, 1);
241 stream_putl (obuf, info->uptime);
243 /* Peer's IP address */
244 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
247 /* Peer's AS number. */
248 stream_putw (obuf, peer->as);
250 /* Dump attribute. */
251 bgp_dump_routes_attr (obuf, attr);
258 #endif /* HAVE_IPV6 */
261 bgp_dump_set_size (obuf, type);
263 fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_routes.fp);
264 fflush (bgp_dump_routes.fp);
267 /* Runs under child process. */
269 bgp_dump_routes_func (int afi)
273 struct bgp_info *info;
275 struct bgp_table *table;
276 unsigned int seq = 0;
278 obuf = bgp_dump_obuf;
280 bgp = bgp_get_default ();
284 if (bgp_dump_routes.fp == NULL)
287 /* Walk down each BGP route. */
288 table = bgp->rib[afi][SAFI_UNICAST];
290 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
291 for (info = rn->info; info; info = info->next)
292 bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++);
296 bgp_dump_interval_func (struct thread *t)
298 struct bgp_dump *bgp_dump;
300 bgp_dump = THREAD_ARG (t);
301 bgp_dump->t_interval = NULL;
303 if (bgp_dump_open_file (bgp_dump) == NULL)
306 /* In case of bgp_dump_routes, we need special route dump function. */
307 if (bgp_dump->type == BGP_DUMP_ROUTES)
309 bgp_dump_routes_func (AFI_IP);
310 bgp_dump_routes_func (AFI_IP6);
313 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
318 /* Dump common information. */
320 bgp_dump_common (struct stream *obuf, struct peer *peer)
322 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
324 /* Source AS number and Destination AS number. */
325 stream_putw (obuf, peer->as);
326 stream_putw (obuf, peer->local_as);
328 if (peer->afc[AFI_IP][SAFI_UNICAST])
330 stream_putw (obuf, peer->ifindex);
331 stream_putw (obuf, AFI_IP);
333 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
336 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
338 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
341 else if (peer->afc[AFI_IP6][SAFI_UNICAST])
343 /* Interface Index and Address family. */
344 stream_putw (obuf, peer->ifindex);
345 stream_putw (obuf, AFI_IP6);
347 /* Source IP Address and Destination IP Address. */
348 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
351 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
353 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
355 #endif /* HAVE_IPV6 */
358 /* Dump BGP status change. */
360 bgp_dump_state (struct peer *peer, int status_old, int status_new)
364 /* If dump file pointer is disabled return immediately. */
365 if (bgp_dump_all.fp == NULL)
368 /* Make dump stream. */
369 obuf = bgp_dump_obuf;
372 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE);
373 bgp_dump_common (obuf, peer);
375 stream_putw (obuf, status_old);
376 stream_putw (obuf, status_new);
379 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
381 /* Write to the stream. */
382 fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_all.fp);
383 fflush (bgp_dump_all.fp);
387 bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
388 struct stream *packet)
392 /* If dump file pointer is disabled return immediately. */
393 if (bgp_dump->fp == NULL)
396 /* Make dump stream. */
397 obuf = bgp_dump_obuf;
400 /* Dump header and common part. */
401 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
402 bgp_dump_common (obuf, peer);
404 /* Packet contents. */
405 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
408 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
410 /* Write to the stream. */
411 fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump->fp);
412 fflush (bgp_dump->fp);
415 /* Called from bgp_packet.c when BGP packet is received. */
417 bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
420 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
422 /* bgp_dump_updates. */
423 if (type == BGP_MSG_UPDATE)
424 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
428 bgp_dump_parse_time (char *str)
443 for (i = 0; i < len; i++)
445 if (isdigit ((int) str[i]))
448 time += str[i] - '0';
450 else if (str[i] == 'H' || str[i] == 'h')
456 total += time * 60 *60;
460 else if (str[i] == 'M' || str[i] == 'm')
475 bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type,
476 char *path, char *interval_str)
480 unsigned int interval;
482 /* Check interval string. */
483 interval = bgp_dump_parse_time (interval_str);
486 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
490 bgp_dump->interval = interval;
491 if (bgp_dump->interval_str)
492 free (bgp_dump->interval_str);
493 bgp_dump->interval_str = strdup (interval_str);
495 /* Create interval thread. */
496 bgp_dump_interval_add (bgp_dump, interval);
500 bgp_dump->type = type;
503 if (bgp_dump->filename)
504 free (bgp_dump->filename);
505 bgp_dump->filename = strdup (path);
507 /* This should be called when interval is expired. */
508 bgp_dump_open_file (bgp_dump);
514 bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
517 if (bgp_dump->filename)
519 free (bgp_dump->filename);
520 bgp_dump->filename = NULL;
523 /* This should be called when interval is expired. */
526 fclose (bgp_dump->fp);
530 /* Create interval thread. */
531 if (bgp_dump->t_interval)
533 thread_cancel (bgp_dump->t_interval);
534 bgp_dump->t_interval = NULL;
537 bgp_dump->interval = 0;
539 if (bgp_dump->interval_str)
541 free (bgp_dump->interval_str);
542 bgp_dump->interval_str = NULL;
554 "Dump all BGP packets\n"
557 return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
560 DEFUN (dump_bgp_all_interval,
561 dump_bgp_all_interval_cmd,
562 "dump bgp all PATH INTERVAL",
565 "Dump all BGP packets\n"
567 "Interval of output\n")
569 return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
572 DEFUN (no_dump_bgp_all,
574 "no dump bgp all [PATH] [INTERVAL]",
578 "Dump all BGP packets\n")
580 return bgp_dump_unset (vty, &bgp_dump_all);
583 DEFUN (dump_bgp_updates,
584 dump_bgp_updates_cmd,
585 "dump bgp updates PATH",
588 "Dump BGP updates only\n"
591 return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
594 DEFUN (dump_bgp_updates_interval,
595 dump_bgp_updates_interval_cmd,
596 "dump bgp updates PATH INTERVAL",
599 "Dump BGP updates only\n"
601 "Interval of output\n")
603 return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
606 DEFUN (no_dump_bgp_updates,
607 no_dump_bgp_updates_cmd,
608 "no dump bgp updates [PATH] [INTERVAL]",
612 "Dump BGP updates only\n")
614 return bgp_dump_unset (vty, &bgp_dump_updates);
617 DEFUN (dump_bgp_routes,
619 "dump bgp routes-mrt PATH",
622 "Dump whole BGP routing table\n"
625 return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
628 DEFUN (dump_bgp_routes_interval,
629 dump_bgp_routes_interval_cmd,
630 "dump bgp routes-mrt PATH INTERVAL",
633 "Dump whole BGP routing table\n"
635 "Interval of output\n")
637 return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
640 DEFUN (no_dump_bgp_routes,
641 no_dump_bgp_routes_cmd,
642 "no dump bgp routes-mrt [PATH] [INTERVAL]",
646 "Dump whole BGP routing table\n")
648 return bgp_dump_unset (vty, &bgp_dump_routes);
651 /* BGP node structure. */
652 struct cmd_node bgp_dump_node =
660 config_time2str (unsigned int interval)
662 static char buf[BUFSIZ];
668 sprintf (buf, "%dh", interval / 3600);
673 sprintf (buf + strlen (buf), "%dm", interval /60);
678 sprintf (buf + strlen (buf), "%d", interval);
685 config_write_bgp_dump (struct vty *vty)
687 if (bgp_dump_all.filename)
689 if (bgp_dump_all.interval_str)
690 vty_out (vty, "dump bgp all %s %s%s",
691 bgp_dump_all.filename, bgp_dump_all.interval_str,
694 vty_out (vty, "dump bgp all %s%s",
695 bgp_dump_all.filename, VTY_NEWLINE);
697 if (bgp_dump_updates.filename)
699 if (bgp_dump_updates.interval_str)
700 vty_out (vty, "dump bgp updates %s %s%s",
701 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
704 vty_out (vty, "dump bgp updates %s%s",
705 bgp_dump_updates.filename, VTY_NEWLINE);
707 if (bgp_dump_routes.filename)
709 if (bgp_dump_routes.interval_str)
710 vty_out (vty, "dump bgp routes-mrt %s %s%s",
711 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
714 vty_out (vty, "dump bgp routes-mrt %s%s",
715 bgp_dump_routes.filename, VTY_NEWLINE);
720 /* Initialize BGP packet dump functionality. */
724 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
725 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
726 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
728 bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_HEADER_SIZE);
730 install_node (&bgp_dump_node, config_write_bgp_dump);
732 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
733 install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd);
734 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
735 install_element (CONFIG_NODE, &dump_bgp_updates_cmd);
736 install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd);
737 install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd);
738 install_element (CONFIG_NODE, &dump_bgp_routes_cmd);
739 install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd);
740 install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd);