Annotation of embedaddon/quagga/bgpd/bgp_dump.c, revision 1.1.1.1
1.1 misho 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 "linklist.h"
30: #include "bgpd/bgp_table.h"
31:
32: #include "bgpd/bgpd.h"
33: #include "bgpd/bgp_route.h"
34: #include "bgpd/bgp_attr.h"
35: #include "bgpd/bgp_dump.h"
36:
37: enum bgp_dump_type
38: {
39: BGP_DUMP_ALL,
40: BGP_DUMP_UPDATES,
41: BGP_DUMP_ROUTES
42: };
43:
44: enum MRT_MSG_TYPES {
45: MSG_NULL,
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 */
59: };
60:
61: static int bgp_dump_interval_func (struct thread *);
62:
63: struct bgp_dump
64: {
65: enum bgp_dump_type type;
66:
67: char *filename;
68:
69: FILE *fp;
70:
71: unsigned int interval;
72:
73: char *interval_str;
74:
75: struct thread *t_interval;
76: };
77:
78: /* BGP packet dump output buffer. */
79: struct stream *bgp_dump_obuf;
80:
81: /* BGP dump strucuture for 'dump bgp all' */
82: struct bgp_dump bgp_dump_all;
83:
84: /* BGP dump structure for 'dump bgp updates' */
85: struct bgp_dump bgp_dump_updates;
86:
87: /* BGP dump structure for 'dump bgp routes' */
88: struct bgp_dump bgp_dump_routes;
89:
90: /* Dump whole BGP table is very heavy process. */
91: struct thread *t_bgp_dump_routes;
92:
93: /* Some define for BGP packet dump. */
94: static FILE *
95: bgp_dump_open_file (struct bgp_dump *bgp_dump)
96: {
97: int ret;
98: time_t clock;
99: struct tm *tm;
100: char fullpath[MAXPATHLEN];
101: char realpath[MAXPATHLEN];
102: mode_t oldumask;
103:
104: time (&clock);
105: tm = localtime (&clock);
106:
107: if (bgp_dump->filename[0] != DIRECTORY_SEP)
108: {
109: sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
110: ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
111: }
112: else
113: ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
114:
115: if (ret == 0)
116: {
117: zlog_warn ("bgp_dump_open_file: strftime error");
118: return NULL;
119: }
120:
121: if (bgp_dump->fp)
122: fclose (bgp_dump->fp);
123:
124:
125: oldumask = umask(0777 & ~LOGFILE_MASK);
126: bgp_dump->fp = fopen (realpath, "w");
127:
128: if (bgp_dump->fp == NULL)
129: {
130: zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno));
131: umask(oldumask);
132: return NULL;
133: }
134: umask(oldumask);
135:
136: return bgp_dump->fp;
137: }
138:
139: static int
140: bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
141: {
142: int secs_into_day;
143: time_t t;
144: struct tm *tm;
145:
146: if (interval > 0)
147: {
148: /* Periodic dump every interval seconds */
149: if ((interval < 86400) && ((86400 % interval) == 0))
150: {
151: /* Dump at predictable times: if a day has a whole number of
152: * intervals, dump every interval seconds starting from midnight
153: */
154: (void) time(&t);
155: tm = localtime(&t);
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 */
158: }
159: bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func,
160: bgp_dump, interval);
161: }
162: else
163: {
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,
166: bgp_dump, 0);
167: }
168:
169: return 0;
170: }
171:
172: /* Dump common header. */
173: static void
174: bgp_dump_header (struct stream *obuf, int type, int subtype)
175: {
176: time_t now;
177:
178: /* Set header. */
179: time (&now);
180:
181: /* Put dump packet header. */
182: stream_putl (obuf, now);
183: stream_putw (obuf, type);
184: stream_putw (obuf, subtype);
185:
186: stream_putl (obuf, 0); /* len */
187: }
188:
189: static void
190: bgp_dump_set_size (struct stream *s, int type)
191: {
192: stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
193: }
194:
195: static void
196: bgp_dump_routes_index_table(struct bgp *bgp)
197: {
198: struct peer *peer;
199: struct listnode *node;
200: uint16_t peerno = 0;
201: struct stream *obuf;
202:
203: obuf = bgp_dump_obuf;
204: stream_reset (obuf);
205:
206: /* MRT header */
207: bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE);
208:
209: /* Collector BGP ID */
210: stream_put_in_addr (obuf, &bgp->router_id);
211:
212: /* View name */
213: if(bgp->name)
214: {
215: stream_putw (obuf, strlen(bgp->name));
216: stream_put(obuf, bgp->name, strlen(bgp->name));
217: }
218: else
219: {
220: stream_putw(obuf, 0);
221: }
222:
223: /* Peer count */
224: stream_putw (obuf, listcount(bgp->peer));
225:
226: /* Walk down all peers */
227: for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
228: {
229:
230: /* Peer's type */
231: if (sockunion_family(&peer->su) == AF_INET)
232: {
233: stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
234: }
235: #ifdef HAVE_IPV6
236: else if (sockunion_family(&peer->su) == AF_INET6)
237: {
238: stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
239: }
240: #endif /* HAVE_IPV6 */
241:
242: /* Peer's BGP ID */
243: stream_put_in_addr (obuf, &peer->remote_id);
244:
245: /* Peer's IP address */
246: if (sockunion_family(&peer->su) == AF_INET)
247: {
248: stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
249: }
250: #ifdef HAVE_IPV6
251: else if (sockunion_family(&peer->su) == AF_INET6)
252: {
253: stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
254: IPV6_MAX_BYTELEN);
255: }
256: #endif /* HAVE_IPV6 */
257:
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);
261:
262: /* Store the peer number for this peer */
263: peer->table_dump_index = peerno;
264: peerno++;
265: }
266:
267: bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
268:
269: fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
270: fflush (bgp_dump_routes.fp);
271: }
272:
273:
274: /* Runs under child process. */
275: static unsigned int
276: bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
277: {
278: struct stream *obuf;
279: struct bgp_info *info;
280: struct bgp_node *rn;
281: struct bgp *bgp;
282: struct bgp_table *table;
283:
284: bgp = bgp_get_default ();
285: if (!bgp)
286: return seq;
287:
288: if (bgp_dump_routes.fp == NULL)
289: return seq;
290:
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 ) */
294: if(first_run)
295: bgp_dump_routes_index_table(bgp);
296:
297: obuf = bgp_dump_obuf;
298: stream_reset(obuf);
299:
300: /* Walk down each BGP route. */
301: table = bgp->rib[afi][SAFI_UNICAST];
302:
303: for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
304: {
305: if(!rn->info)
306: continue;
307:
308: stream_reset(obuf);
309:
310: /* MRT header */
311: if (afi == AFI_IP)
312: {
313: bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
314: }
315: #ifdef HAVE_IPV6
316: else if (afi == AFI_IP6)
317: {
318: bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
319: }
320: #endif /* HAVE_IPV6 */
321:
322: /* Sequence number */
323: stream_putl(obuf, seq);
324:
325: /* Prefix length */
326: stream_putc (obuf, rn->p.prefixlen);
327:
328: /* Prefix */
329: if (afi == AFI_IP)
330: {
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);
333: }
334: #ifdef HAVE_IPV6
335: else if (afi == AFI_IP6)
336: {
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);
339: }
340: #endif /* HAVE_IPV6 */
341:
342: /* Save where we are now, so we can overwride the entry count later */
343: int sizep = stream_get_endp(obuf);
344:
345: /* Entry count */
346: uint16_t entry_count = 0;
347:
348: /* Entry count, note that this is overwritten later */
349: stream_putw(obuf, 0);
350:
351: for (info = rn->info; info; info = info->next)
352: {
353: entry_count++;
354:
355: /* Peer index */
356: stream_putw(obuf, info->peer->table_dump_index);
357:
358: /* Originated */
359: #ifdef HAVE_CLOCK_MONOTONIC
360: stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
361: #else
362: stream_putl (obuf, info->uptime);
363: #endif /* HAVE_CLOCK_MONOTONIC */
364:
365: /* Dump attribute. */
366: /* Skip prefix & AFI/SAFI for MP_NLRI */
367: bgp_dump_routes_attr (obuf, info->attr, &rn->p);
368: }
369:
370: /* Overwrite the entry count, now that we know the right number */
371: stream_putw_at (obuf, sizep, entry_count);
372:
373: seq++;
374:
375: bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
376: fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
377:
378: }
379:
380: fflush (bgp_dump_routes.fp);
381:
382: return seq;
383: }
384:
385: static int
386: bgp_dump_interval_func (struct thread *t)
387: {
388: struct bgp_dump *bgp_dump;
389: bgp_dump = THREAD_ARG (t);
390: bgp_dump->t_interval = NULL;
391:
392: /* Reschedule dump even if file couldn't be opened this time... */
393: if (bgp_dump_open_file (bgp_dump) != NULL)
394: {
395: /* In case of bgp_dump_routes, we need special route dump function. */
396: if (bgp_dump->type == BGP_DUMP_ROUTES)
397: {
398: unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
399: #ifdef HAVE_IPV6
400: bgp_dump_routes_func (AFI_IP6, 0, seq);
401: #endif /* HAVE_IPV6 */
402: /* Close the file now. For a RIB dump there's no point in leaving
403: * it open until the next scheduled dump starts. */
404: fclose(bgp_dump->fp); bgp_dump->fp = NULL;
405: }
406: }
407:
408: /* if interval is set reschedule */
409: if (bgp_dump->interval > 0)
410: bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
411:
412: return 0;
413: }
414:
415: /* Dump common information. */
416: static void
417: bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
418: {
419: char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
420:
421: /* Source AS number and Destination AS number. */
422: if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
423: {
424: stream_putl (obuf, peer->as);
425: stream_putl (obuf, peer->local_as);
426: }
427: else
428: {
429: stream_putw (obuf, peer->as);
430: stream_putw (obuf, peer->local_as);
431: }
432:
433: if (peer->su.sa.sa_family == AF_INET)
434: {
435: stream_putw (obuf, peer->ifindex);
436: stream_putw (obuf, AFI_IP);
437:
438: stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
439:
440: if (peer->su_local)
441: stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
442: else
443: stream_put (obuf, empty, IPV4_MAX_BYTELEN);
444: }
445: #ifdef HAVE_IPV6
446: else if (peer->su.sa.sa_family == AF_INET6)
447: {
448: /* Interface Index and Address family. */
449: stream_putw (obuf, peer->ifindex);
450: stream_putw (obuf, AFI_IP6);
451:
452: /* Source IP Address and Destination IP Address. */
453: stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
454:
455: if (peer->su_local)
456: stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
457: else
458: stream_put (obuf, empty, IPV6_MAX_BYTELEN);
459: }
460: #endif /* HAVE_IPV6 */
461: }
462:
463: /* Dump BGP status change. */
464: void
465: bgp_dump_state (struct peer *peer, int status_old, int status_new)
466: {
467: struct stream *obuf;
468:
469: /* If dump file pointer is disabled return immediately. */
470: if (bgp_dump_all.fp == NULL)
471: return;
472:
473: /* Make dump stream. */
474: obuf = bgp_dump_obuf;
475: stream_reset (obuf);
476:
477: bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4);
478: bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
479:
480: stream_putw (obuf, status_old);
481: stream_putw (obuf, status_new);
482:
483: /* Set length. */
484: bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
485:
486: /* Write to the stream. */
487: fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
488: fflush (bgp_dump_all.fp);
489: }
490:
491: static void
492: bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
493: struct stream *packet)
494: {
495: struct stream *obuf;
496:
497: /* If dump file pointer is disabled return immediately. */
498: if (bgp_dump->fp == NULL)
499: return;
500:
501: /* Make dump stream. */
502: obuf = bgp_dump_obuf;
503: stream_reset (obuf);
504:
505: /* Dump header and common part. */
506: if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
507: {
508: bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4);
509: }
510: else
511: {
512: bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
513: }
514: bgp_dump_common (obuf, peer, 0);
515:
516: /* Packet contents. */
517: stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
518:
519: /* Set length. */
520: bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
521:
522: /* Write to the stream. */
523: fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
524: fflush (bgp_dump->fp);
525: }
526:
527: /* Called from bgp_packet.c when BGP packet is received. */
528: void
529: bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
530: {
531: /* bgp_dump_all. */
532: bgp_dump_packet_func (&bgp_dump_all, peer, packet);
533:
534: /* bgp_dump_updates. */
535: if (type == BGP_MSG_UPDATE)
536: bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
537: }
538:
539: static unsigned int
540: bgp_dump_parse_time (const char *str)
541: {
542: int i;
543: int len;
544: int seen_h;
545: int seen_m;
546: int time;
547: unsigned int total;
548:
549: time = 0;
550: total = 0;
551: seen_h = 0;
552: seen_m = 0;
553: len = strlen (str);
554:
555: for (i = 0; i < len; i++)
556: {
557: if (isdigit ((int) str[i]))
558: {
559: time *= 10;
560: time += str[i] - '0';
561: }
562: else if (str[i] == 'H' || str[i] == 'h')
563: {
564: if (seen_h)
565: return 0;
566: if (seen_m)
567: return 0;
568: total += time * 60 *60;
569: time = 0;
570: seen_h = 1;
571: }
572: else if (str[i] == 'M' || str[i] == 'm')
573: {
574: if (seen_m)
575: return 0;
576: total += time * 60;
577: time = 0;
578: seen_h = 1;
579: }
580: else
581: return 0;
582: }
583: return total + time;
584: }
585:
586: static int
587: bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
588: enum bgp_dump_type type, const char *path,
589: const char *interval_str)
590: {
591: unsigned int interval;
592:
593: if (interval_str)
594: {
595:
596: /* Check interval string. */
597: interval = bgp_dump_parse_time (interval_str);
598: if (interval == 0)
599: {
600: vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
601: return CMD_WARNING;
602: }
603:
604: /* Don't schedule duplicate dumps if the dump command is given twice */
605: if (interval == bgp_dump->interval &&
606: type == bgp_dump->type &&
607: path && bgp_dump->filename && !strcmp (path, bgp_dump->filename))
608: {
609: return CMD_SUCCESS;
610: }
611:
612: /* Set interval. */
613: bgp_dump->interval = interval;
614: if (bgp_dump->interval_str)
615: free (bgp_dump->interval_str);
616: bgp_dump->interval_str = strdup (interval_str);
617:
618: }
619: else
620: {
621: interval = 0;
622: }
623:
624: /* Create interval thread. */
625: bgp_dump_interval_add (bgp_dump, interval);
626:
627: /* Set type. */
628: bgp_dump->type = type;
629:
630: /* Set file name. */
631: if (bgp_dump->filename)
632: free (bgp_dump->filename);
633: bgp_dump->filename = strdup (path);
634:
635: /* This should be called when interval is expired. */
636: bgp_dump_open_file (bgp_dump);
637:
638: return CMD_SUCCESS;
639: }
640:
641: static int
642: bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
643: {
644: /* Set file name. */
645: if (bgp_dump->filename)
646: {
647: free (bgp_dump->filename);
648: bgp_dump->filename = NULL;
649: }
650:
651: /* This should be called when interval is expired. */
652: if (bgp_dump->fp)
653: {
654: fclose (bgp_dump->fp);
655: bgp_dump->fp = NULL;
656: }
657:
658: /* Create interval thread. */
659: if (bgp_dump->t_interval)
660: {
661: thread_cancel (bgp_dump->t_interval);
662: bgp_dump->t_interval = NULL;
663: }
664:
665: bgp_dump->interval = 0;
666:
667: if (bgp_dump->interval_str)
668: {
669: free (bgp_dump->interval_str);
670: bgp_dump->interval_str = NULL;
671: }
672:
673:
674: return CMD_SUCCESS;
675: }
676:
677: DEFUN (dump_bgp_all,
678: dump_bgp_all_cmd,
679: "dump bgp all PATH",
680: "Dump packet\n"
681: "BGP packet dump\n"
682: "Dump all BGP packets\n"
683: "Output filename\n")
684: {
685: return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
686: }
687:
688: DEFUN (dump_bgp_all_interval,
689: dump_bgp_all_interval_cmd,
690: "dump bgp all PATH INTERVAL",
691: "Dump packet\n"
692: "BGP packet dump\n"
693: "Dump all BGP packets\n"
694: "Output filename\n"
695: "Interval of output\n")
696: {
697: return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
698: }
699:
700: DEFUN (no_dump_bgp_all,
701: no_dump_bgp_all_cmd,
702: "no dump bgp all [PATH] [INTERVAL]",
703: NO_STR
704: "Dump packet\n"
705: "BGP packet dump\n"
706: "Dump all BGP packets\n")
707: {
708: return bgp_dump_unset (vty, &bgp_dump_all);
709: }
710:
711: DEFUN (dump_bgp_updates,
712: dump_bgp_updates_cmd,
713: "dump bgp updates PATH",
714: "Dump packet\n"
715: "BGP packet dump\n"
716: "Dump BGP updates only\n"
717: "Output filename\n")
718: {
719: return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
720: }
721:
722: DEFUN (dump_bgp_updates_interval,
723: dump_bgp_updates_interval_cmd,
724: "dump bgp updates PATH INTERVAL",
725: "Dump packet\n"
726: "BGP packet dump\n"
727: "Dump BGP updates only\n"
728: "Output filename\n"
729: "Interval of output\n")
730: {
731: return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
732: }
733:
734: DEFUN (no_dump_bgp_updates,
735: no_dump_bgp_updates_cmd,
736: "no dump bgp updates [PATH] [INTERVAL]",
737: NO_STR
738: "Dump packet\n"
739: "BGP packet dump\n"
740: "Dump BGP updates only\n")
741: {
742: return bgp_dump_unset (vty, &bgp_dump_updates);
743: }
744:
745: DEFUN (dump_bgp_routes,
746: dump_bgp_routes_cmd,
747: "dump bgp routes-mrt PATH",
748: "Dump packet\n"
749: "BGP packet dump\n"
750: "Dump whole BGP routing table\n"
751: "Output filename\n")
752: {
753: return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
754: }
755:
756: DEFUN (dump_bgp_routes_interval,
757: dump_bgp_routes_interval_cmd,
758: "dump bgp routes-mrt PATH INTERVAL",
759: "Dump packet\n"
760: "BGP packet dump\n"
761: "Dump whole BGP routing table\n"
762: "Output filename\n"
763: "Interval of output\n")
764: {
765: return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
766: }
767:
768: DEFUN (no_dump_bgp_routes,
769: no_dump_bgp_routes_cmd,
770: "no dump bgp routes-mrt [PATH] [INTERVAL]",
771: NO_STR
772: "Dump packet\n"
773: "BGP packet dump\n"
774: "Dump whole BGP routing table\n")
775: {
776: return bgp_dump_unset (vty, &bgp_dump_routes);
777: }
778:
779: /* BGP node structure. */
780: static struct cmd_node bgp_dump_node =
781: {
782: DUMP_NODE,
783: "",
784: 1
785: };
786:
787: #if 0
788: char *
789: config_time2str (unsigned int interval)
790: {
791: static char buf[BUFSIZ];
792:
793: buf[0] = '\0';
794:
795: if (interval / 3600)
796: {
797: sprintf (buf, "%dh", interval / 3600);
798: interval %= 3600;
799: }
800: if (interval / 60)
801: {
802: sprintf (buf + strlen (buf), "%dm", interval /60);
803: interval %= 60;
804: }
805: if (interval)
806: {
807: sprintf (buf + strlen (buf), "%d", interval);
808: }
809: return buf;
810: }
811: #endif
812:
813: static int
814: config_write_bgp_dump (struct vty *vty)
815: {
816: if (bgp_dump_all.filename)
817: {
818: if (bgp_dump_all.interval_str)
819: vty_out (vty, "dump bgp all %s %s%s",
820: bgp_dump_all.filename, bgp_dump_all.interval_str,
821: VTY_NEWLINE);
822: else
823: vty_out (vty, "dump bgp all %s%s",
824: bgp_dump_all.filename, VTY_NEWLINE);
825: }
826: if (bgp_dump_updates.filename)
827: {
828: if (bgp_dump_updates.interval_str)
829: vty_out (vty, "dump bgp updates %s %s%s",
830: bgp_dump_updates.filename, bgp_dump_updates.interval_str,
831: VTY_NEWLINE);
832: else
833: vty_out (vty, "dump bgp updates %s%s",
834: bgp_dump_updates.filename, VTY_NEWLINE);
835: }
836: if (bgp_dump_routes.filename)
837: {
838: if (bgp_dump_routes.interval_str)
839: vty_out (vty, "dump bgp routes-mrt %s %s%s",
840: bgp_dump_routes.filename, bgp_dump_routes.interval_str,
841: VTY_NEWLINE);
842: else
843: vty_out (vty, "dump bgp routes-mrt %s%s",
844: bgp_dump_routes.filename, VTY_NEWLINE);
845: }
846: return 0;
847: }
848:
849: /* Initialize BGP packet dump functionality. */
850: void
851: bgp_dump_init (void)
852: {
853: memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
854: memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
855: memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
856:
857: bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
858: + BGP_DUMP_HEADER_SIZE);
859:
860: install_node (&bgp_dump_node, config_write_bgp_dump);
861:
862: install_element (CONFIG_NODE, &dump_bgp_all_cmd);
863: install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd);
864: install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
865: install_element (CONFIG_NODE, &dump_bgp_updates_cmd);
866: install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd);
867: install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd);
868: install_element (CONFIG_NODE, &dump_bgp_routes_cmd);
869: install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd);
870: install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd);
871: }
872:
873: void
874: bgp_dump_finish (void)
875: {
876: stream_free (bgp_dump_obuf);
877: bgp_dump_obuf = NULL;
878: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>