added files
[bcm963xx.git] / userapps / opensource / zebra / bgpd / bgp_dump.c
1 /* BGP-4 dump routine
2    Copyright (C) 1999 Kunihiro Ishiguro
3
4 This file is part of GNU Zebra.
5
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
9 later version.
10
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.
15
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
19 02111-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
36 enum bgp_dump_type
37 {
38   BGP_DUMP_ALL,
39   BGP_DUMP_UPDATES,
40   BGP_DUMP_ROUTES
41 };
42
43 enum 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
59 struct 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. */
75 struct stream *bgp_dump_obuf;
76
77 /* BGP dump strucuture for 'dump bgp all' */
78 struct bgp_dump bgp_dump_all;
79
80 /* BGP dump structure for 'dump bgp updates' */
81 struct bgp_dump bgp_dump_updates;
82
83 /* BGP dump structure for 'dump bgp routes' */
84 struct bgp_dump bgp_dump_routes;
85
86 /* Dump whole BGP table is very heavy process.  */
87 struct thread *t_bgp_dump_routes;
88 \f
89 /* Some define for BGP packet dump. */
90 FILE *
91 bgp_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
128 int
129 bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
130 {
131   int bgp_dump_interval_func (struct thread *);
132
133   bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func, 
134                                            bgp_dump, interval);
135   return 0;
136 }
137
138 /* Dump common header. */
139 void
140 bgp_dump_header (struct stream *obuf, int type, int subtype)
141 {
142   time_t now;
143
144   /* Set header. */
145   time (&now);
146
147   /* Put dump packet header. */
148   stream_putl (obuf, now);      
149   stream_putw (obuf, type);
150   stream_putw (obuf, subtype);
151
152   stream_putl (obuf, 0);        /* len */
153 }
154
155 void
156 bgp_dump_set_size (struct stream *s, int type)
157 {
158   stream_putl_at (s, 8, stream_get_putp (s) - BGP_DUMP_HEADER_SIZE);
159 }
160
161 void
162 bgp_dump_routes_entry (struct prefix *p, struct bgp_info *info, int afi,
163                        int type, unsigned int seq)
164 {
165   struct stream *obuf;
166   struct attr *attr;
167   struct peer *peer;
168   int plen;
169   int safi = 0;
170
171   /* Make dump stream. */
172   obuf = bgp_dump_obuf;
173   stream_reset (obuf);
174
175   attr = info->attr;
176   peer = info->peer;
177
178   /* We support MRT's old format. */
179   if (type == MSG_TABLE_DUMP)
180     {
181       bgp_dump_header (obuf, MSG_TABLE_DUMP, afi);
182       stream_putw (obuf, 0);    /* View # */
183       stream_putw (obuf, seq);  /* Sequence number. */
184     }
185   else
186     {
187       bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY);
188       
189       stream_putl (obuf, info->uptime); /* Time Last Change */
190       stream_putw (obuf, afi);  /* Address Family */
191       stream_putc (obuf, safi); /* SAFI */
192     }
193
194   if (afi == AFI_IP)
195     {
196       if (type == MSG_TABLE_DUMP)
197         {
198           /* Prefix */
199           stream_put_in_addr (obuf, &p->u.prefix4);
200           stream_putc (obuf, p->prefixlen);
201
202           /* Status */
203           stream_putc (obuf, 1);
204
205           /* Originated */
206           stream_putl (obuf, info->uptime);
207
208           /* Peer's IP address */
209           stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
210
211           /* Peer's AS number. */
212           stream_putw (obuf, peer->as);
213
214           /* Dump attribute. */
215           bgp_dump_routes_attr (obuf, attr);
216         }
217       else
218         {
219           /* Next-Hop-Len */
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);
226         }
227     }
228 #ifdef HAVE_IPV6
229   else if (afi == AFI_IP6)
230     {
231       if (type == MSG_TABLE_DUMP)
232         {
233           /* Prefix */
234           stream_write (obuf, (u_char *)&p->u.prefix6, IPV6_MAX_BYTELEN);
235           stream_putc (obuf, p->prefixlen);
236
237           /* Status */
238           stream_putc (obuf, 1);
239
240           /* Originated */
241           stream_putl (obuf, info->uptime);
242
243           /* Peer's IP address */
244           stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
245                         IPV6_MAX_BYTELEN);
246
247           /* Peer's AS number. */
248           stream_putw (obuf, peer->as);
249
250           /* Dump attribute. */
251           bgp_dump_routes_attr (obuf, attr);
252         }
253       else
254         {
255           ;
256         }
257     }
258 #endif /* HAVE_IPV6 */
259
260   /* Set length. */
261   bgp_dump_set_size (obuf, type);
262
263   fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump_routes.fp);
264   fflush (bgp_dump_routes.fp);
265 }
266
267 /* Runs under child process. */
268 void
269 bgp_dump_routes_func (int afi)
270 {
271   struct stream *obuf;
272   struct bgp_node *rn;
273   struct bgp_info *info;
274   struct bgp *bgp;
275   struct bgp_table *table;
276   unsigned int seq = 0;
277
278   obuf = bgp_dump_obuf;
279
280   bgp = bgp_get_default ();
281   if (!bgp)
282     return;
283
284   if (bgp_dump_routes.fp == NULL)
285     return;
286
287   /* Walk down each BGP route. */
288   table = bgp->rib[afi][SAFI_UNICAST];
289
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++);
293 }
294
295 int
296 bgp_dump_interval_func (struct thread *t)
297 {
298   struct bgp_dump *bgp_dump;
299
300   bgp_dump = THREAD_ARG (t);
301   bgp_dump->t_interval = NULL;
302
303   if (bgp_dump_open_file (bgp_dump) == NULL)
304     return 0;
305
306   /* In case of bgp_dump_routes, we need special route dump function. */
307   if (bgp_dump->type == BGP_DUMP_ROUTES)
308     {
309       bgp_dump_routes_func (AFI_IP);
310       bgp_dump_routes_func (AFI_IP6);
311     }
312
313   bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
314   
315   return 0;
316 }
317
318 /* Dump common information. */
319 void
320 bgp_dump_common (struct stream *obuf, struct peer *peer)
321 {
322   char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
323
324   /* Source AS number and Destination AS number. */
325   stream_putw (obuf, peer->as);
326   stream_putw (obuf, peer->local_as);
327
328   if (peer->afc[AFI_IP][SAFI_UNICAST])
329     {
330       stream_putw (obuf, peer->ifindex);
331       stream_putw (obuf, AFI_IP);
332
333       stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
334
335       if (peer->su_local)
336         stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
337       else
338         stream_put (obuf, empty, IPV4_MAX_BYTELEN);
339     }
340 #ifdef HAVE_IPV6
341   else if (peer->afc[AFI_IP6][SAFI_UNICAST])
342     {
343       /* Interface Index and Address family. */
344       stream_putw (obuf, peer->ifindex);
345       stream_putw (obuf, AFI_IP6);
346
347       /* Source IP Address and Destination IP Address. */
348       stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
349
350       if (peer->su_local)
351         stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
352       else
353         stream_put (obuf, empty, IPV6_MAX_BYTELEN);
354     }
355 #endif /* HAVE_IPV6 */
356 }
357
358 /* Dump BGP status change. */
359 void
360 bgp_dump_state (struct peer *peer, int status_old, int status_new)
361 {
362   struct stream *obuf;
363
364   /* If dump file pointer is disabled return immediately. */
365   if (bgp_dump_all.fp == NULL)
366     return;
367
368   /* Make dump stream. */
369   obuf = bgp_dump_obuf;
370   stream_reset (obuf);
371
372   bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE);
373   bgp_dump_common (obuf, peer);
374
375   stream_putw (obuf, status_old);
376   stream_putw (obuf, status_new);
377
378   /* Set length. */
379   bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
380
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);
384 }
385
386 void
387 bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
388                       struct stream *packet)
389 {
390   struct stream *obuf;
391
392   /* If dump file pointer is disabled return immediately. */
393   if (bgp_dump->fp == NULL)
394     return;
395
396   /* Make dump stream. */
397   obuf = bgp_dump_obuf;
398   stream_reset (obuf);
399
400   /* Dump header and common part. */
401   bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
402   bgp_dump_common (obuf, peer);
403
404   /* Packet contents. */
405   stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
406   
407   /* Set length. */
408   bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
409
410   /* Write to the stream. */
411   fwrite (STREAM_DATA (obuf), stream_get_putp (obuf), 1, bgp_dump->fp);
412   fflush (bgp_dump->fp);
413 }
414
415 /* Called from bgp_packet.c when BGP packet is received. */
416 void
417 bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
418 {
419   /* bgp_dump_all. */
420   bgp_dump_packet_func (&bgp_dump_all, peer, packet);
421
422   /* bgp_dump_updates. */
423   if (type == BGP_MSG_UPDATE)
424     bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
425 }
426 \f
427 unsigned int
428 bgp_dump_parse_time (char *str)
429 {
430   int i;
431   int len;
432   int seen_h;
433   int seen_m;
434   int time;
435   unsigned int total;
436
437   time = 0;
438   total = 0;
439   seen_h = 0;
440   seen_m = 0;
441   len = strlen (str);
442
443   for (i = 0; i < len; i++)
444     {
445       if (isdigit ((int) str[i]))
446         {
447           time *= 10;
448           time += str[i] - '0';
449         }
450       else if (str[i] == 'H' || str[i] == 'h')
451         {
452           if (seen_h)
453             return 0;
454           if (seen_m)
455             return 0;
456           total += time * 60 *60;
457           time = 0;
458           seen_h = 1;
459         }
460       else if (str[i] == 'M' || str[i] == 'm')
461         {
462           if (seen_m)
463             return 0;
464           total += time * 60;
465           time = 0;
466           seen_h = 1;
467         }
468       else
469         return 0;
470     }
471   return total + time;
472 }
473
474 int
475 bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, int type,
476               char *path, char *interval_str)
477 {
478   if (interval_str)
479     {
480       unsigned int interval;
481
482       /* Check interval string. */
483       interval = bgp_dump_parse_time (interval_str);
484       if (interval == 0)
485         {
486           vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
487           return CMD_WARNING;
488         }
489       /* Set interval. */
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);
494
495       /* Create interval thread. */
496       bgp_dump_interval_add (bgp_dump, interval);
497     }
498
499   /* Set type. */
500   bgp_dump->type = type;
501
502   /* Set file name. */
503   if (bgp_dump->filename)
504     free (bgp_dump->filename);
505   bgp_dump->filename = strdup (path);
506
507   /* This should be called when interval is expired. */
508   bgp_dump_open_file (bgp_dump);
509
510   return CMD_SUCCESS;
511 }
512
513 int
514 bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
515 {
516   /* Set file name. */
517   if (bgp_dump->filename)
518     {
519       free (bgp_dump->filename);
520       bgp_dump->filename = NULL;
521     }
522
523   /* This should be called when interval is expired. */
524   if (bgp_dump->fp)
525     {
526       fclose (bgp_dump->fp);
527       bgp_dump->fp = NULL;
528     }
529
530   /* Create interval thread. */
531   if (bgp_dump->t_interval)
532     {
533       thread_cancel (bgp_dump->t_interval);
534       bgp_dump->t_interval = NULL;
535     }
536
537   bgp_dump->interval = 0;
538
539   if (bgp_dump->interval_str)
540     {
541       free (bgp_dump->interval_str);
542       bgp_dump->interval_str = NULL;
543     }
544   
545
546   return CMD_SUCCESS;
547 }
548
549 DEFUN (dump_bgp_all,
550        dump_bgp_all_cmd,
551        "dump bgp all PATH",
552        "Dump packet\n"
553        "BGP packet dump\n"
554        "Dump all BGP packets\n"
555        "Output filename\n")
556 {
557   return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
558 }
559
560 DEFUN (dump_bgp_all_interval,
561        dump_bgp_all_interval_cmd,
562        "dump bgp all PATH INTERVAL",
563        "Dump packet\n"
564        "BGP packet dump\n"
565        "Dump all BGP packets\n"
566        "Output filename\n"
567        "Interval of output\n")
568 {
569   return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
570 }
571
572 DEFUN (no_dump_bgp_all,
573        no_dump_bgp_all_cmd,
574        "no dump bgp all [PATH] [INTERVAL]",
575        NO_STR
576        "Dump packet\n"
577        "BGP packet dump\n"
578        "Dump all BGP packets\n")
579 {
580   return bgp_dump_unset (vty, &bgp_dump_all);
581 }
582
583 DEFUN (dump_bgp_updates,
584        dump_bgp_updates_cmd,
585        "dump bgp updates PATH",
586        "Dump packet\n"
587        "BGP packet dump\n"
588        "Dump BGP updates only\n"
589        "Output filename\n")
590 {
591   return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
592 }
593
594 DEFUN (dump_bgp_updates_interval,
595        dump_bgp_updates_interval_cmd,
596        "dump bgp updates PATH INTERVAL",
597        "Dump packet\n"
598        "BGP packet dump\n"
599        "Dump BGP updates only\n"
600        "Output filename\n"
601        "Interval of output\n")
602 {
603   return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
604 }
605
606 DEFUN (no_dump_bgp_updates,
607        no_dump_bgp_updates_cmd,
608        "no dump bgp updates [PATH] [INTERVAL]",
609        NO_STR
610        "Dump packet\n"
611        "BGP packet dump\n"
612        "Dump BGP updates only\n")
613 {
614   return bgp_dump_unset (vty, &bgp_dump_updates);
615 }
616
617 DEFUN (dump_bgp_routes,
618        dump_bgp_routes_cmd,
619        "dump bgp routes-mrt PATH",
620        "Dump packet\n"
621        "BGP packet dump\n"
622        "Dump whole BGP routing table\n"
623        "Output filename\n")
624 {
625   return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
626 }
627
628 DEFUN (dump_bgp_routes_interval,
629        dump_bgp_routes_interval_cmd,
630        "dump bgp routes-mrt PATH INTERVAL",
631        "Dump packet\n"
632        "BGP packet dump\n"
633        "Dump whole BGP routing table\n"
634        "Output filename\n"
635        "Interval of output\n")
636 {
637   return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
638 }
639
640 DEFUN (no_dump_bgp_routes,
641        no_dump_bgp_routes_cmd,
642        "no dump bgp routes-mrt [PATH] [INTERVAL]",
643        NO_STR
644        "Dump packet\n"
645        "BGP packet dump\n"
646        "Dump whole BGP routing table\n")
647 {
648   return bgp_dump_unset (vty, &bgp_dump_routes);
649 }
650
651 /* BGP node structure. */
652 struct cmd_node bgp_dump_node =
653 {
654   DUMP_NODE,
655   "",
656 };
657
658 #if 0
659 char *
660 config_time2str (unsigned int interval)
661 {
662   static char buf[BUFSIZ];
663
664   buf[0] = '\0';
665
666   if (interval / 3600)
667     {
668       sprintf (buf, "%dh", interval / 3600);
669       interval %= 3600;
670     }
671   if (interval / 60)
672     {
673       sprintf (buf + strlen (buf), "%dm", interval /60);
674       interval %= 60;
675     }
676   if (interval)
677     {
678       sprintf (buf + strlen (buf), "%d", interval);
679     }
680   return buf;
681 }
682 #endif
683
684 int
685 config_write_bgp_dump (struct vty *vty)
686 {
687   if (bgp_dump_all.filename)
688     {
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,
692                  VTY_NEWLINE);
693       else
694         vty_out (vty, "dump bgp all %s%s", 
695                  bgp_dump_all.filename, VTY_NEWLINE);
696     }
697   if (bgp_dump_updates.filename)
698     {
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,
702                  VTY_NEWLINE);
703       else
704         vty_out (vty, "dump bgp updates %s%s", 
705                  bgp_dump_updates.filename, VTY_NEWLINE);
706     }
707   if (bgp_dump_routes.filename)
708     {
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,
712                  VTY_NEWLINE);
713       else
714         vty_out (vty, "dump bgp routes-mrt %s%s", 
715                  bgp_dump_routes.filename, VTY_NEWLINE);
716     }
717   return 0;
718 }
719 \f
720 /* Initialize BGP packet dump functionality. */
721 void
722 bgp_dump_init ()
723 {
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));
727
728   bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_HEADER_SIZE);
729
730   install_node (&bgp_dump_node, config_write_bgp_dump);
731
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);
741 }