1/* BGP-4 dump routine 2 Copyright (C) 1999 Kunihiro Ishiguro 3 4This file is part of GNU Zebra. 5 6GNU Zebra is free software; you can redistribute it and/or modify it 7under the terms of the GNU General Public License as published by the 8Free Software Foundation; either version 2, or (at your option) any 9later version. 10 11GNU Zebra is distributed in the hope that it will be useful, but 12WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with GNU Zebra; see the file COPYING. If not, write to the Free 18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 1902111-1307, USA. */ 20 21#include <zebra.h> 22 23#include "log.h" 24#include "stream.h" 25#include "sockunion.h" 26#include "command.h" 27#include "prefix.h" 28#include "thread.h" 29#include "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 37enum bgp_dump_type 38{ 39 BGP_DUMP_ALL, 40 BGP_DUMP_UPDATES, 41 BGP_DUMP_ROUTES 42}; 43 44enum 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 61static int bgp_dump_interval_func (struct thread *); 62 63struct 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. */ 79struct stream *bgp_dump_obuf; 80 81/* BGP dump strucuture for 'dump bgp all' */ 82struct bgp_dump bgp_dump_all; 83 84/* BGP dump structure for 'dump bgp updates' */ 85struct bgp_dump bgp_dump_updates; 86 87/* BGP dump structure for 'dump bgp routes' */ 88struct bgp_dump bgp_dump_routes; 89 90/* Dump whole BGP table is very heavy process. */ 91struct thread *t_bgp_dump_routes; 92 93/* Some define for BGP packet dump. */ 94static FILE * 95bgp_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 139static int 140bgp_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. */ 173static void 174bgp_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 189static void 190bgp_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 195static void 196bgp_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. */ 275static unsigned int 276bgp_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 385static int 386bgp_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. */ 416static void 417bgp_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. */ 464void 465bgp_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 491static void 492bgp_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. */ 528void 529bgp_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 539static unsigned int 540bgp_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 586static int 587bgp_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 641static int 642bgp_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 677DEFUN (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 688DEFUN (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 700DEFUN (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 711DEFUN (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 722DEFUN (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 734DEFUN (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 745DEFUN (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 756DEFUN (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 768DEFUN (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. */ 780static struct cmd_node bgp_dump_node = 781{ 782 DUMP_NODE, 783 "", 784 1 785}; 786 787#if 0 788char * 789config_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 813static int 814config_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. */ 850void 851bgp_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 873void 874bgp_dump_finish (void) 875{ 876 stream_free (bgp_dump_obuf); 877 bgp_dump_obuf = NULL; 878} 879