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