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