]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_dump.c
Merge pull request #5686 from qlyoung/fix-bgp-fqdn-capability-leak
[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_pretty) {
238 stream_putw(obuf, strlen(bgp->name_pretty));
239 stream_put(obuf, bgp->name_pretty, strlen(bgp->name_pretty));
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 int bgp_dump_state(struct peer *peer)
498 {
499 struct stream *obuf;
500
501 /* If dump file pointer is disabled return immediately. */
502 if (bgp_dump_all.fp == NULL)
503 return 0;
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, peer->ostatus);
514 stream_putw(obuf, peer->status);
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 return 0;
523 }
524
525 static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
526 struct stream *packet)
527 {
528 struct stream *obuf;
529
530 /* If dump file pointer is disabled return immediately. */
531 if (bgp_dump->fp == NULL)
532 return;
533
534 /* Make dump stream. */
535 obuf = bgp_dump_obuf;
536 stream_reset(obuf);
537
538 /* Dump header and common part. */
539 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
540 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
541 bgp_dump->type);
542 } else {
543 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
544 bgp_dump->type);
545 }
546 bgp_dump_common(obuf, peer, 0);
547
548 /* Packet contents. */
549 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
550
551 /* Set length. */
552 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
553
554 /* Write to the stream. */
555 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
556 fflush(bgp_dump->fp);
557 }
558
559 /* Called from bgp_packet.c when BGP packet is received. */
560 static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
561 struct stream *packet)
562 {
563 /* bgp_dump_all. */
564 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
565
566 /* bgp_dump_updates. */
567 if (type == BGP_MSG_UPDATE)
568 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
569 return 0;
570 }
571
572 static unsigned int bgp_dump_parse_time(const char *str)
573 {
574 int i;
575 int len;
576 int seen_h;
577 int seen_m;
578 int time;
579 unsigned int total;
580
581 time = 0;
582 total = 0;
583 seen_h = 0;
584 seen_m = 0;
585 len = strlen(str);
586
587 for (i = 0; i < len; i++) {
588 if (isdigit((unsigned char)str[i])) {
589 time *= 10;
590 time += str[i] - '0';
591 } else if (str[i] == 'H' || str[i] == 'h') {
592 if (seen_h)
593 return 0;
594 if (seen_m)
595 return 0;
596 total += time * 60 * 60;
597 time = 0;
598 seen_h = 1;
599 } else if (str[i] == 'M' || str[i] == 'm') {
600 if (seen_m)
601 return 0;
602 total += time * 60;
603 time = 0;
604 seen_m = 1;
605 } else
606 return 0;
607 }
608 return total + time;
609 }
610
611 static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
612 enum bgp_dump_type type, const char *path,
613 const char *interval_str)
614 {
615 unsigned int interval;
616
617 /* Don't schedule duplicate dumps if the dump command is given twice */
618 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
619 && type == bgp_dump->type) {
620 if (interval_str) {
621 if (bgp_dump->interval_str
622 && strcmp(bgp_dump->interval_str, interval_str)
623 == 0)
624 return CMD_SUCCESS;
625 } else {
626 if (!bgp_dump->interval_str)
627 return CMD_SUCCESS;
628 }
629 }
630
631 /* Removing previous config */
632 bgp_dump_unset(bgp_dump);
633
634 if (interval_str) {
635 /* Check interval string. */
636 interval = bgp_dump_parse_time(interval_str);
637 if (interval == 0) {
638 vty_out(vty, "Malformed interval string\n");
639 return CMD_WARNING_CONFIG_FAILED;
640 }
641
642 /* Setting interval string */
643 bgp_dump->interval_str =
644 XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
645 } else {
646 interval = 0;
647 }
648
649 /* Set type. */
650 bgp_dump->type = type;
651
652 /* Set interval */
653 bgp_dump->interval = interval;
654
655 /* Set file name. */
656 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
657
658 /* Create interval thread. */
659 bgp_dump_interval_add(bgp_dump, interval);
660
661 /* This should be called when interval is expired. */
662 bgp_dump_open_file(bgp_dump);
663
664 return CMD_SUCCESS;
665 }
666
667 static int bgp_dump_unset(struct bgp_dump *bgp_dump)
668 {
669 /* Removing file name. */
670 if (bgp_dump->filename) {
671 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
672 bgp_dump->filename = NULL;
673 }
674
675 /* Closing file. */
676 if (bgp_dump->fp) {
677 fclose(bgp_dump->fp);
678 bgp_dump->fp = NULL;
679 }
680
681 /* Removing interval thread. */
682 if (bgp_dump->t_interval) {
683 thread_cancel(bgp_dump->t_interval);
684 bgp_dump->t_interval = NULL;
685 }
686
687 bgp_dump->interval = 0;
688
689 /* Removing interval string. */
690 if (bgp_dump->interval_str) {
691 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
692 bgp_dump->interval_str = NULL;
693 }
694
695 return CMD_SUCCESS;
696 }
697
698 DEFUN (dump_bgp_all,
699 dump_bgp_all_cmd,
700 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
701 "Dump packet\n"
702 "BGP packet dump\n"
703 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
704 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
705 "Dump whole BGP routing table\n"
706 "Output filename\n"
707 "Interval of output\n")
708 {
709 int idx_dump_routes = 2;
710 int idx_path = 3;
711 int idx_interval = 4;
712 int bgp_dump_type = 0;
713 const char *interval = NULL;
714 struct bgp_dump *bgp_dump_struct = NULL;
715 const struct bgp_dump_type_map *map = NULL;
716
717 for (map = bgp_dump_type_map; map->str; map++)
718 if (strmatch(argv[idx_dump_routes]->text, map->str))
719 bgp_dump_type = map->type;
720
721 switch (bgp_dump_type) {
722 case BGP_DUMP_ALL:
723 case BGP_DUMP_ALL_ET:
724 bgp_dump_struct = &bgp_dump_all;
725 break;
726 case BGP_DUMP_UPDATES:
727 case BGP_DUMP_UPDATES_ET:
728 bgp_dump_struct = &bgp_dump_updates;
729 break;
730 case BGP_DUMP_ROUTES:
731 default:
732 bgp_dump_struct = &bgp_dump_routes;
733 break;
734 }
735
736 /* When an interval is given */
737 if (argc == idx_interval + 1)
738 interval = argv[idx_interval]->arg;
739
740 return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
741 argv[idx_path]->arg, interval);
742 }
743
744 DEFUN (no_dump_bgp_all,
745 no_dump_bgp_all_cmd,
746 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
747 NO_STR
748 "Stop dump packet\n"
749 "Stop BGP packet dump\n"
750 "Stop dump process all\n"
751 "Stop dump process all-et\n"
752 "Stop dump process updates\n"
753 "Stop dump process updates-et\n"
754 "Stop dump process route-mrt\n"
755 "Output filename\n"
756 "Interval of output\n")
757 {
758 int idx_dump_routes = 3;
759 int bgp_dump_type = 0;
760 const struct bgp_dump_type_map *map = NULL;
761 struct bgp_dump *bgp_dump_struct = NULL;
762
763 for (map = bgp_dump_type_map; map->str; map++)
764 if (strmatch(argv[idx_dump_routes]->text, map->str))
765 bgp_dump_type = map->type;
766
767 switch (bgp_dump_type) {
768 case BGP_DUMP_ALL:
769 case BGP_DUMP_ALL_ET:
770 bgp_dump_struct = &bgp_dump_all;
771 break;
772 case BGP_DUMP_UPDATES:
773 case BGP_DUMP_UPDATES_ET:
774 bgp_dump_struct = &bgp_dump_updates;
775 break;
776 case BGP_DUMP_ROUTES:
777 default:
778 bgp_dump_struct = &bgp_dump_routes;
779 break;
780 }
781
782 return bgp_dump_unset(bgp_dump_struct);
783 }
784
785 /* BGP node structure. */
786 static struct cmd_node bgp_dump_node = {DUMP_NODE, "", 1};
787
788 #if 0
789 char *
790 config_time2str (unsigned int interval)
791 {
792 static char buf[BUFSIZ];
793
794 buf[0] = '\0';
795
796 if (interval / 3600)
797 {
798 sprintf (buf, "%dh", interval / 3600);
799 interval %= 3600;
800 }
801 if (interval / 60)
802 {
803 sprintf (buf + strlen (buf), "%dm", interval /60);
804 interval %= 60;
805 }
806 if (interval)
807 {
808 sprintf (buf + strlen (buf), "%d", interval);
809 }
810 return buf;
811 }
812 #endif
813
814 static int config_write_bgp_dump(struct vty *vty)
815 {
816 if (bgp_dump_all.filename) {
817 const char *type_str = "all";
818 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
819 type_str = "all-et";
820
821 if (bgp_dump_all.interval_str)
822 vty_out(vty, "dump bgp %s %s %s\n", type_str,
823 bgp_dump_all.filename,
824 bgp_dump_all.interval_str);
825 else
826 vty_out(vty, "dump bgp %s %s\n", type_str,
827 bgp_dump_all.filename);
828 }
829 if (bgp_dump_updates.filename) {
830 const char *type_str = "updates";
831 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
832 type_str = "updates-et";
833
834 if (bgp_dump_updates.interval_str)
835 vty_out(vty, "dump bgp %s %s %s\n", type_str,
836 bgp_dump_updates.filename,
837 bgp_dump_updates.interval_str);
838 else
839 vty_out(vty, "dump bgp %s %s\n", type_str,
840 bgp_dump_updates.filename);
841 }
842 if (bgp_dump_routes.filename) {
843 if (bgp_dump_routes.interval_str)
844 vty_out(vty, "dump bgp routes-mrt %s %s\n",
845 bgp_dump_routes.filename,
846 bgp_dump_routes.interval_str);
847 else
848 vty_out(vty, "dump bgp routes-mrt %s\n",
849 bgp_dump_routes.filename);
850 }
851 return 0;
852 }
853
854 /* Initialize BGP packet dump functionality. */
855 void bgp_dump_init(void)
856 {
857 memset(&bgp_dump_all, 0, sizeof(struct bgp_dump));
858 memset(&bgp_dump_updates, 0, sizeof(struct bgp_dump));
859 memset(&bgp_dump_routes, 0, sizeof(struct bgp_dump));
860
861 bgp_dump_obuf =
862 stream_new((BGP_MAX_PACKET_SIZE << 1) + BGP_DUMP_MSG_HEADER
863 + BGP_DUMP_HEADER_SIZE);
864
865 install_node(&bgp_dump_node, config_write_bgp_dump);
866
867 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
868 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
869
870 hook_register(bgp_packet_dump, bgp_dump_packet);
871 hook_register(peer_status_changed, bgp_dump_state);
872 }
873
874 void bgp_dump_finish(void)
875 {
876 bgp_dump_unset(&bgp_dump_all);
877 bgp_dump_unset(&bgp_dump_updates);
878 bgp_dump_unset(&bgp_dump_routes);
879
880 stream_free(bgp_dump_obuf);
881 bgp_dump_obuf = NULL;
882 hook_unregister(bgp_packet_dump, bgp_dump_packet);
883 hook_unregister(peer_status_changed, bgp_dump_state);
884 }