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