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