]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
2003-10-15 sowmini.varadhan@sun.com
[mirror_frr.git] / bgpd / bgp_dump.c
CommitLineData
718e3744 1/* BGP-4 dump routine
2 Copyright (C) 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "log.h"
24#include "stream.h"
25#include "sockunion.h"
26#include "command.h"
27#include "prefix.h"
28#include "thread.h"
29#include "bgpd/bgp_table.h"
30
31#include "bgpd/bgpd.h"
32#include "bgpd/bgp_route.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_dump.h"
35\f
36enum bgp_dump_type
37{
38 BGP_DUMP_ALL,
39 BGP_DUMP_UPDATES,
40 BGP_DUMP_ROUTES
41};
42
43enum MRT_MSG_TYPES {
44 MSG_NULL,
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 */
57};
58
59struct bgp_dump
60{
61 enum bgp_dump_type type;
62
63 char *filename;
64
65 FILE *fp;
66
67 unsigned int interval;
68
69 char *interval_str;
70
71 struct thread *t_interval;
72};
73
74/* BGP packet dump output buffer. */
75struct stream *bgp_dump_obuf;
76
77/* BGP dump strucuture for 'dump bgp all' */
78struct bgp_dump bgp_dump_all;
79
80/* BGP dump structure for 'dump bgp updates' */
81struct bgp_dump bgp_dump_updates;
82
83/* BGP dump structure for 'dump bgp routes' */
84struct bgp_dump bgp_dump_routes;
85
86/* Dump whole BGP table is very heavy process. */
87struct thread *t_bgp_dump_routes;
88\f
89/* Some define for BGP packet dump. */
90FILE *
91bgp_dump_open_file (struct bgp_dump *bgp_dump)
92{
93 int ret;
94 time_t clock;
95 struct tm *tm;
96 char fullpath[MAXPATHLEN];
97 char realpath[MAXPATHLEN];
98
99 time (&clock);
100 tm = localtime (&clock);
101
102 if (bgp_dump->filename[0] != DIRECTORY_SEP)
103 {
104 sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
105 ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
106 }
107 else
108 ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
109
110 if (ret == 0)
111 {
112 zlog_warn ("bgp_dump_open_file: strftime error");
113 return NULL;
114 }
115
116 if (bgp_dump->fp)
117 fclose (bgp_dump->fp);
118
119
120 bgp_dump->fp = fopen (realpath, "w");
121
122 if (bgp_dump->fp == NULL)
123 return NULL;
124
125 return bgp_dump->fp;
126}
127
128int
129bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
130{
131 int bgp_dump_interval_func (struct thread *);
132
fba3d22b 133 if (interval > 0 )
134 bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func,
135 bgp_dump, interval);
136 else
137 bgp_dump->t_interval = thread_add_event (master, bgp_dump_interval_func,
138 bgp_dump, 0);
139
718e3744 140 return 0;
141}
142
143/* Dump common header. */
144void
145bgp_dump_header (struct stream *obuf, int type, int subtype)
146{
147 time_t now;
148
149 /* Set header. */
150 time (&now);
151
152 /* Put dump packet header. */
153 stream_putl (obuf, now);
154 stream_putw (obuf, type);
155 stream_putw (obuf, subtype);
156
157 stream_putl (obuf, 0); /* len */
158}
159
160void
161bgp_dump_set_size (struct stream *s, int type)
162{
163 stream_putl_at (s, 8, stream_get_putp (s) - BGP_DUMP_HEADER_SIZE);
164}
165
166void
167bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi,
168 int type, unsigned int seq)
169{
170 struct stream *obuf;
171 struct attr *attr;
172 struct peer *peer;
173 int plen;
174 int safi = 0;
175
176 /* Make dump stream. */
177 obuf = bgp_dump_obuf;
178 stream_reset (obuf);
179
180 attr = info->attr;
181 peer = info->peer;
182
183 /* We support MRT's old format. */
184 if (type == MSG_TABLE_DUMP)
185 {
186 bgp_dump_header (obuf, MSG_TABLE_DUMP, afi);
187 stream_putw (obuf, 0); /* View # */
188 stream_putw (obuf, seq); /* Sequence number. */
189 }
190 else
191 {
192 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY);
193
194 stream_putl (obuf, info->uptime); /* Time Last Change */
195 stream_putw (obuf, afi); /* Address Family */
196 stream_putc (obuf, safi); /* SAFI */
197 }
198
199 if (afi == AFI_IP)
200 {
201 if (type == MSG_TABLE_DUMP)
202 {
203 /* Prefix */
204 stream_put_in_addr (obuf, &p->u.prefix4);
205 stream_putc (obuf, p->prefixlen);
206
207 /* Status */
208 stream_putc (obuf, 1);
209
210 /* Originated */
211 stream_putl (obuf, info->uptime);
212
213 /* Peer's IP address */
214 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
215
216 /* Peer's AS number. */
217 stream_putw (obuf, peer->as);
218
219 /* Dump attribute. */
220 bgp_dump_routes_attr (obuf, attr);
221 }
222 else
223 {
224 /* Next-Hop-Len */
225 stream_putc (obuf, IPV4_MAX_BYTELEN);
226 stream_put_in_addr (obuf, &attr->nexthop);
227 stream_putc (obuf, p->prefixlen);
228 plen = PSIZE (p->prefixlen);
229 stream_put (obuf, &p->u.prefix4, plen);
230 bgp_dump_routes_attr (obuf, attr);
231 }
232 }
233#ifdef HAVE_IPV6
234 else if (afi == AFI_IP6)
235 {
236 if (type == MSG_TABLE_DUMP)
237 {
238 /* Prefix */
239 stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN);
240 stream_putc (obuf, p->prefixlen);
241
242 /* Status */
243 stream_putc (obuf, 1);
244
245 /* Originated */
246 stream_putl (obuf, info->uptime);
247
248 /* Peer's IP address */
249 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
250 IPV6_MAX_BYTELEN);
251
252 /* Peer's AS number. */
253 stream_putw (obuf, peer->as);
254
255 /* Dump attribute. */
256 bgp_dump_routes_attr (obuf, attr);
257 }
258 else
259 {
260 ;
261 }
262 }
263#endif /* HAVE_IPV6 */
264
265 /* Set length. */
266 bgp_dump_set_size (obuf, type);
267
268 fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_routes.fp);
269 fflush (bgp_dump_routes.fp);
270}
271
272/* Runs under child process. */
273void
274bgp_dump_routes_func (int afi)
275{
276 struct stream *obuf;
277 struct bgp_node *rn;
278 struct bgp_info *info;
279 struct bgp *bgp;
280 struct bgp_table *table;
281 unsigned int seq = 0;
282
283 obuf = bgp_dump_obuf;
284
285 bgp = bgp_get_default ();
286 if (!bgp)
287 return;
288
289 if (bgp_dump_routes.fp == NULL)
290 return;
291
292 /* Walk down each BGP route. */
293 table = bgp->rib[afi][SAFI_UNICAST];
294
295 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
296 for (info = rn->info; info; info = info->next)
297 bgp_dump_routes_entry (&rn->p, info, afi, MSG_TABLE_DUMP, seq++);
298}
299
300int
301bgp_dump_interval_func (struct thread *t)
302{
303 struct bgp_dump *bgp_dump;
718e3744 304 bgp_dump = THREAD_ARG (t);
305 bgp_dump->t_interval = NULL;
306
307 if (bgp_dump_open_file (bgp_dump) == NULL)
308 return 0;
309
310 /* In case of bgp_dump_routes, we need special route dump function. */
311 if (bgp_dump->type == BGP_DUMP_ROUTES)
312 {
313 bgp_dump_routes_func (AFI_IP);
314 bgp_dump_routes_func (AFI_IP6);
315 }
316
fba3d22b 317 /* if interval is set reschedule */
318 if (bgp_dump->interval > 0)
319 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
320
321
718e3744 322 return 0;
323}
324
325/* Dump common information. */
326void
327bgp_dump_common (struct stream *obuf, struct peer *peer)
328{
329 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
330
331 /* Source AS number and Destination AS number. */
332 stream_putw (obuf, peer->as);
333 stream_putw (obuf, peer->local_as);
334
335 if (peer->afc[AFI_IP][SAFI_UNICAST])
336 {
337 stream_putw (obuf, peer->ifindex);
338 stream_putw (obuf, AFI_IP);
339
340 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
341
342 if (peer->su_local)
343 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
344 else
345 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
346 }
347#ifdef HAVE_IPV6
348 else if (peer->afc[AFI_IP6][SAFI_UNICAST])
349 {
350 /* Interface Index and Address family. */
351 stream_putw (obuf, peer->ifindex);
352 stream_putw (obuf, AFI_IP6);
353
354 /* Source IP Address and Destination IP Address. */
355 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
356
357 if (peer->su_local)
358 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
359 else
360 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
361 }
362#endif /* HAVE_IPV6 */
363}
364
365/* Dump BGP status change. */
366void
367bgp_dump_state (struct peer *peer, int status_old, int status_new)
368{
369 struct stream *obuf;
370
371 /* If dump file pointer is disabled return immediately. */
372 if (bgp_dump_all.fp == NULL)
373 return;
374
375 /* Make dump stream. */
376 obuf = bgp_dump_obuf;
377 stream_reset (obuf);
378
379 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE);
380 bgp_dump_common (obuf, peer);
381
382 stream_putw (obuf, status_old);
383 stream_putw (obuf, status_new);
384
385 /* Set length. */
386 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
387
388 /* Write to the stream. */
389 fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_all.fp);
390 fflush (bgp_dump_all.fp);
391}
392
393void
394bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
395 struct stream *packet)
396{
397 struct stream *obuf;
398
399 /* If dump file pointer is disabled return immediately. */
400 if (bgp_dump->fp == NULL)
401 return;
402
403 /* Make dump stream. */
404 obuf = bgp_dump_obuf;
405 stream_reset (obuf);
406
407 /* Dump header and common part. */
408 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
409 bgp_dump_common (obuf, peer);
410
411 /* Packet contents. */
412 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
413
414 /* Set length. */
415 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
416
417 /* Write to the stream. */
418 fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump->fp);
419 fflush (bgp_dump->fp);
420}
421
422/* Called from bgp_packet.c when BGP packet is received. */
423void
424bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
425{
426 /* bgp_dump_all. */
427 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
428
429 /* bgp_dump_updates. */
430 if (type == BGP_MSG_UPDATE)
431 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
432}
433\f
434unsigned int
435bgp_dump_parse_time (char *str)
436{
437 int i;
438 int len;
439 int seen_h;
440 int seen_m;
441 int time;
442 unsigned int total;
443
444 time = 0;
445 total = 0;
446 seen_h = 0;
447 seen_m = 0;
448 len = strlen (str);
449
450 for (i = 0; i < len; i++)
451 {
452 if (isdigit ((int) str[i]))
453 {
454 time *= 10;
455 time += str[i] - '0';
456 }
457 else if (str[i] == 'H' || str[i] == 'h')
458 {
459 if (seen_h)
460 return 0;
461 if (seen_m)
462 return 0;
463 total += time * 60 *60;
464 time = 0;
465 seen_h = 1;
466 }
467 else if (str[i] == 'M' || str[i] == 'm')
468 {
469 if (seen_m)
470 return 0;
471 total += time * 60;
472 time = 0;
473 seen_h = 1;
474 }
475 else
476 return 0;
477 }
478 return total + time;
479}
480
481int
482bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type,
483 char *path, char *interval_str)
484{
fba3d22b 485 unsigned int interval;
486
718e3744 487 if (interval_str)
488 {
fba3d22b 489
718e3744 490 /* Check interval string. */
491 interval = bgp_dump_parse_time (interval_str);
492 if (interval == 0)
493 {
494 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
495 return CMD_WARNING;
496 }
497 /* Set interval. */
498 bgp_dump->interval = interval;
499 if (bgp_dump->interval_str)
500 free (bgp_dump->interval_str);
501 bgp_dump->interval_str = strdup (interval_str);
fba3d22b 502
718e3744 503 }
fba3d22b 504 else
505 {
506 interval = 0;
507 }
508
509 /* Create interval thread. */
510 bgp_dump_interval_add (bgp_dump, interval);
718e3744 511
512 /* Set type. */
513 bgp_dump->type = type;
514
515 /* Set file name. */
516 if (bgp_dump->filename)
517 free (bgp_dump->filename);
518 bgp_dump->filename = strdup (path);
519
520 /* This should be called when interval is expired. */
521 bgp_dump_open_file (bgp_dump);
522
523 return CMD_SUCCESS;
524}
525
526int
527bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
528{
529 /* Set file name. */
530 if (bgp_dump->filename)
531 {
532 free (bgp_dump->filename);
533 bgp_dump->filename = NULL;
534 }
535
536 /* This should be called when interval is expired. */
537 if (bgp_dump->fp)
538 {
539 fclose (bgp_dump->fp);
540 bgp_dump->fp = NULL;
541 }
542
543 /* Create interval thread. */
544 if (bgp_dump->t_interval)
545 {
546 thread_cancel (bgp_dump->t_interval);
547 bgp_dump->t_interval = NULL;
548 }
549
550 bgp_dump->interval = 0;
551
552 if (bgp_dump->interval_str)
553 {
554 free (bgp_dump->interval_str);
555 bgp_dump->interval_str = NULL;
556 }
557
558
559 return CMD_SUCCESS;
560}
561
562DEFUN (dump_bgp_all,
563 dump_bgp_all_cmd,
564 "dump bgp all PATH",
565 "Dump packet\n"
566 "BGP packet dump\n"
567 "Dump all BGP packets\n"
568 "Output filename\n")
569{
570 return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
571}
572
573DEFUN (dump_bgp_all_interval,
574 dump_bgp_all_interval_cmd,
575 "dump bgp all PATH INTERVAL",
576 "Dump packet\n"
577 "BGP packet dump\n"
578 "Dump all BGP packets\n"
579 "Output filename\n"
580 "Interval of output\n")
581{
582 return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
583}
584
585DEFUN (no_dump_bgp_all,
586 no_dump_bgp_all_cmd,
587 "no dump bgp all [PATH] [INTERVAL]",
588 NO_STR
589 "Dump packet\n"
590 "BGP packet dump\n"
591 "Dump all BGP packets\n")
592{
593 return bgp_dump_unset (vty, &bgp_dump_all);
594}
595
596DEFUN (dump_bgp_updates,
597 dump_bgp_updates_cmd,
598 "dump bgp updates PATH",
599 "Dump packet\n"
600 "BGP packet dump\n"
601 "Dump BGP updates only\n"
602 "Output filename\n")
603{
604 return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
605}
606
607DEFUN (dump_bgp_updates_interval,
608 dump_bgp_updates_interval_cmd,
609 "dump bgp updates PATH INTERVAL",
610 "Dump packet\n"
611 "BGP packet dump\n"
612 "Dump BGP updates only\n"
613 "Output filename\n"
614 "Interval of output\n")
615{
616 return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
617}
618
619DEFUN (no_dump_bgp_updates,
620 no_dump_bgp_updates_cmd,
621 "no dump bgp updates [PATH] [INTERVAL]",
622 NO_STR
623 "Dump packet\n"
624 "BGP packet dump\n"
625 "Dump BGP updates only\n")
626{
627 return bgp_dump_unset (vty, &bgp_dump_updates);
628}
629
630DEFUN (dump_bgp_routes,
631 dump_bgp_routes_cmd,
632 "dump bgp routes-mrt PATH",
633 "Dump packet\n"
634 "BGP packet dump\n"
635 "Dump whole BGP routing table\n"
636 "Output filename\n")
637{
638 return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
639}
640
641DEFUN (dump_bgp_routes_interval,
642 dump_bgp_routes_interval_cmd,
643 "dump bgp routes-mrt PATH INTERVAL",
644 "Dump packet\n"
645 "BGP packet dump\n"
646 "Dump whole BGP routing table\n"
647 "Output filename\n"
648 "Interval of output\n")
649{
650 return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
651}
652
653DEFUN (no_dump_bgp_routes,
654 no_dump_bgp_routes_cmd,
655 "no dump bgp routes-mrt [PATH] [INTERVAL]",
656 NO_STR
657 "Dump packet\n"
658 "BGP packet dump\n"
659 "Dump whole BGP routing table\n")
660{
661 return bgp_dump_unset (vty, &bgp_dump_routes);
662}
663
664/* BGP node structure. */
665struct cmd_node bgp_dump_node =
666{
667 DUMP_NODE,
668 "",
669};
670
671#if 0
672char *
673config_time2str (unsigned int interval)
674{
675 static char buf[BUFSIZ];
676
677 buf[0] = '\0';
678
679 if (interval / 3600)
680 {
681 sprintf (buf, "%dh", interval / 3600);
682 interval %= 3600;
683 }
684 if (interval / 60)
685 {
686 sprintf (buf + strlen (buf), "%dm", interval /60);
687 interval %= 60;
688 }
689 if (interval)
690 {
691 sprintf (buf + strlen (buf), "%d", interval);
692 }
693 return buf;
694}
695#endif
696
697int
698config_write_bgp_dump (struct vty *vty)
699{
700 if (bgp_dump_all.filename)
701 {
702 if (bgp_dump_all.interval_str)
703 vty_out (vty, "dump bgp all %s %s%s",
704 bgp_dump_all.filename, bgp_dump_all.interval_str,
705 VTY_NEWLINE);
706 else
707 vty_out (vty, "dump bgp all %s%s",
708 bgp_dump_all.filename, VTY_NEWLINE);
709 }
710 if (bgp_dump_updates.filename)
711 {
712 if (bgp_dump_updates.interval_str)
713 vty_out (vty, "dump bgp updates %s %s%s",
714 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
715 VTY_NEWLINE);
716 else
717 vty_out (vty, "dump bgp updates %s%s",
718 bgp_dump_updates.filename, VTY_NEWLINE);
719 }
720 if (bgp_dump_routes.filename)
721 {
722 if (bgp_dump_routes.interval_str)
723 vty_out (vty, "dump bgp routes-mrt %s %s%s",
724 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
725 VTY_NEWLINE);
726 else
727 vty_out (vty, "dump bgp routes-mrt %s%s",
728 bgp_dump_routes.filename, VTY_NEWLINE);
729 }
730 return 0;
731}
732\f
733/* Initialize BGP packet dump functionality. */
734void
735bgp_dump_init ()
736{
737 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
738 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
739 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
740
741 bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_HEADER_SIZE);
742
743 install_node (&bgp_dump_node, config_write_bgp_dump);
744
745 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
746 install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd);
747 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
748 install_element (CONFIG_NODE, &dump_bgp_updates_cmd);
749 install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd);
750 install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd);
751 install_element (CONFIG_NODE, &dump_bgp_routes_cmd);
752 install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd);
753 install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd);
754}