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