]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_dump.c
Merge pull request #6147 from opensourcerouting/ldpd-broken-lsps
[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 localtime_r(&clock, &tm);
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 localtime_r(&t, &tm);
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 const struct prefix *p = bgp_node_get_prefix(rn);
311
312 obuf = bgp_dump_obuf;
313 stream_reset(obuf);
314
315 /* MRT header */
316 if (afi == AFI_IP)
317 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
318 TABLE_DUMP_V2_RIB_IPV4_UNICAST,
319 BGP_DUMP_ROUTES);
320 else if (afi == AFI_IP6)
321 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
322 TABLE_DUMP_V2_RIB_IPV6_UNICAST,
323 BGP_DUMP_ROUTES);
324
325 /* Sequence number */
326 stream_putl(obuf, seq);
327
328 /* Prefix length */
329 stream_putc(obuf, p->prefixlen);
330
331 /* Prefix */
332 if (afi == AFI_IP) {
333 /* We'll dump only the useful bits (those not 0), but have to
334 * align on 8 bits */
335 stream_write(obuf, (uint8_t *)&p->u.prefix4,
336 (p->prefixlen + 7) / 8);
337 } else if (afi == AFI_IP6) {
338 /* We'll dump only the useful bits (those not 0), but have to
339 * align on 8 bits */
340 stream_write(obuf, (uint8_t *)&p->u.prefix6,
341 (p->prefixlen + 7) / 8);
342 }
343
344 /* Save where we are now, so we can overwride the entry count later */
345 sizep = stream_get_endp(obuf);
346
347 /* Entry count */
348 uint16_t entry_count = 0;
349
350 /* Entry count, note that this is overwritten later */
351 stream_putw(obuf, 0);
352
353 endp = stream_get_endp(obuf);
354 for (; path; path = path->next) {
355 size_t cur_endp;
356
357 /* Peer index */
358 stream_putw(obuf, path->peer->table_dump_index);
359
360 /* Originated */
361 stream_putl(obuf, time(NULL) - (bgp_clock() - path->uptime));
362
363 /* Dump attribute. */
364 /* Skip prefix & AFI/SAFI for MP_NLRI */
365 bgp_dump_routes_attr(obuf, path->attr, p);
366
367 cur_endp = stream_get_endp(obuf);
368 if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
369 + BGP_DUMP_HEADER_SIZE) {
370 stream_set_endp(obuf, endp);
371 break;
372 }
373
374 entry_count++;
375 endp = cur_endp;
376 }
377
378 /* Overwrite the entry count, now that we know the right number */
379 stream_putw_at(obuf, sizep, entry_count);
380
381 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
382 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
383
384 return path;
385 }
386
387
388 /* Runs under child process. */
389 static unsigned int bgp_dump_routes_func(int afi, int first_run,
390 unsigned int seq)
391 {
392 struct bgp_path_info *path;
393 struct bgp_node *rn;
394 struct bgp *bgp;
395 struct bgp_table *table;
396
397 bgp = bgp_get_default();
398 if (!bgp)
399 return seq;
400
401 if (bgp_dump_routes.fp == NULL)
402 return seq;
403
404 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
405 so this should only be done on the first call to
406 bgp_dump_routes_func.
407 ( this function will be called once for ipv4 and once for ipv6 ) */
408 if (first_run)
409 bgp_dump_routes_index_table(bgp);
410
411 /* Walk down each BGP route. */
412 table = bgp->rib[afi][SAFI_UNICAST];
413
414 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
415 path = bgp_node_get_bgp_path_info(rn);
416 while (path) {
417 path = bgp_dump_route_node_record(afi, rn, path, seq);
418 seq++;
419 }
420 }
421
422 fflush(bgp_dump_routes.fp);
423
424 return seq;
425 }
426
427 static int bgp_dump_interval_func(struct thread *t)
428 {
429 struct bgp_dump *bgp_dump;
430 bgp_dump = THREAD_ARG(t);
431 bgp_dump->t_interval = NULL;
432
433 /* Reschedule dump even if file couldn't be opened this time... */
434 if (bgp_dump_open_file(bgp_dump) != NULL) {
435 /* In case of bgp_dump_routes, we need special route dump
436 * function. */
437 if (bgp_dump->type == BGP_DUMP_ROUTES) {
438 unsigned int seq = bgp_dump_routes_func(AFI_IP, 1, 0);
439 bgp_dump_routes_func(AFI_IP6, 0, seq);
440 /* Close the file now. For a RIB dump there's no point
441 * in leaving
442 * it open until the next scheduled dump starts. */
443 fclose(bgp_dump->fp);
444 bgp_dump->fp = NULL;
445 }
446 }
447
448 /* if interval is set reschedule */
449 if (bgp_dump->interval > 0)
450 bgp_dump_interval_add(bgp_dump, bgp_dump->interval);
451
452 return 0;
453 }
454
455 /* Dump common information. */
456 static void bgp_dump_common(struct stream *obuf, struct peer *peer,
457 int forceas4)
458 {
459 char empty[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
460
461 /* Source AS number and Destination AS number. */
462 if (forceas4 || CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
463 stream_putl(obuf, peer->as);
464 stream_putl(obuf, peer->local_as);
465 } else {
466 stream_putw(obuf, peer->as);
467 stream_putw(obuf, peer->local_as);
468 }
469
470 if (peer->su.sa.sa_family == AF_INET) {
471 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
472 stream_putw(obuf, AFI_IP);
473
474 stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
475
476 if (peer->su_local)
477 stream_put(obuf, &peer->su_local->sin.sin_addr,
478 IPV4_MAX_BYTELEN);
479 else
480 stream_put(obuf, empty, IPV4_MAX_BYTELEN);
481 } else if (peer->su.sa.sa_family == AF_INET6) {
482 /* Interface Index and Address family. */
483 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
484 stream_putw(obuf, AFI_IP6);
485
486 /* Source IP Address and Destination IP Address. */
487 stream_put(obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
488
489 if (peer->su_local)
490 stream_put(obuf, &peer->su_local->sin6.sin6_addr,
491 IPV6_MAX_BYTELEN);
492 else
493 stream_put(obuf, empty, IPV6_MAX_BYTELEN);
494 }
495 }
496
497 /* Dump BGP status change. */
498 int bgp_dump_state(struct peer *peer)
499 {
500 struct stream *obuf;
501
502 /* If dump file pointer is disabled return immediately. */
503 if (bgp_dump_all.fp == NULL)
504 return 0;
505
506 /* Make dump stream. */
507 obuf = bgp_dump_obuf;
508 stream_reset(obuf);
509
510 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
511 bgp_dump_all.type);
512 bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/
513
514 stream_putw(obuf, peer->ostatus);
515 stream_putw(obuf, peer->status);
516
517 /* Set length. */
518 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
519
520 /* Write to the stream. */
521 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_all.fp);
522 fflush(bgp_dump_all.fp);
523 return 0;
524 }
525
526 static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
527 struct stream *packet)
528 {
529 struct stream *obuf;
530
531 /* If dump file pointer is disabled return immediately. */
532 if (bgp_dump->fp == NULL)
533 return;
534
535 /* Make dump stream. */
536 obuf = bgp_dump_obuf;
537 stream_reset(obuf);
538
539 /* Dump header and common part. */
540 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
541 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
542 bgp_dump->type);
543 } else {
544 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
545 bgp_dump->type);
546 }
547 bgp_dump_common(obuf, peer, 0);
548
549 /* Packet contents. */
550 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
551
552 /* Set length. */
553 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
554
555 /* Write to the stream. */
556 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
557 fflush(bgp_dump->fp);
558 }
559
560 /* Called from bgp_packet.c when BGP packet is received. */
561 static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
562 struct stream *packet)
563 {
564 /* bgp_dump_all. */
565 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
566
567 /* bgp_dump_updates. */
568 if (type == BGP_MSG_UPDATE)
569 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
570 return 0;
571 }
572
573 static unsigned int bgp_dump_parse_time(const char *str)
574 {
575 int i;
576 int len;
577 int seen_h;
578 int seen_m;
579 int time;
580 unsigned int total;
581
582 time = 0;
583 total = 0;
584 seen_h = 0;
585 seen_m = 0;
586 len = strlen(str);
587
588 for (i = 0; i < len; i++) {
589 if (isdigit((unsigned char)str[i])) {
590 time *= 10;
591 time += str[i] - '0';
592 } else if (str[i] == 'H' || str[i] == 'h') {
593 if (seen_h)
594 return 0;
595 if (seen_m)
596 return 0;
597 total += time * 60 * 60;
598 time = 0;
599 seen_h = 1;
600 } else if (str[i] == 'M' || str[i] == 'm') {
601 if (seen_m)
602 return 0;
603 total += time * 60;
604 time = 0;
605 seen_m = 1;
606 } else
607 return 0;
608 }
609 return total + time;
610 }
611
612 static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
613 enum bgp_dump_type type, const char *path,
614 const char *interval_str)
615 {
616 unsigned int interval;
617
618 /* Don't schedule duplicate dumps if the dump command is given twice */
619 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
620 && type == bgp_dump->type) {
621 if (interval_str) {
622 if (bgp_dump->interval_str
623 && strcmp(bgp_dump->interval_str, interval_str)
624 == 0)
625 return CMD_SUCCESS;
626 } else {
627 if (!bgp_dump->interval_str)
628 return CMD_SUCCESS;
629 }
630 }
631
632 /* Removing previous config */
633 bgp_dump_unset(bgp_dump);
634
635 if (interval_str) {
636 /* Check interval string. */
637 interval = bgp_dump_parse_time(interval_str);
638 if (interval == 0) {
639 vty_out(vty, "Malformed interval string\n");
640 return CMD_WARNING_CONFIG_FAILED;
641 }
642
643 /* Setting interval string */
644 bgp_dump->interval_str =
645 XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
646 } else {
647 interval = 0;
648 }
649
650 /* Set type. */
651 bgp_dump->type = type;
652
653 /* Set interval */
654 bgp_dump->interval = interval;
655
656 /* Set file name. */
657 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
658
659 /* Create interval thread. */
660 bgp_dump_interval_add(bgp_dump, interval);
661
662 /* This should be called when interval is expired. */
663 bgp_dump_open_file(bgp_dump);
664
665 return CMD_SUCCESS;
666 }
667
668 static int bgp_dump_unset(struct bgp_dump *bgp_dump)
669 {
670 /* Removing file name. */
671 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
672
673 /* Closing file. */
674 if (bgp_dump->fp) {
675 fclose(bgp_dump->fp);
676 bgp_dump->fp = NULL;
677 }
678
679 /* Removing interval thread. */
680 if (bgp_dump->t_interval) {
681 thread_cancel(bgp_dump->t_interval);
682 bgp_dump->t_interval = NULL;
683 }
684
685 bgp_dump->interval = 0;
686
687 /* Removing interval string. */
688 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
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 static int config_write_bgp_dump(struct vty *vty);
781 /* BGP node structure. */
782 static struct cmd_node bgp_dump_node = {
783 .name = "dump",
784 .node = DUMP_NODE,
785 .prompt = "",
786 .config_write = config_write_bgp_dump,
787 };
788
789 #if 0
790 char *
791 config_time2str (unsigned int interval)
792 {
793 static char buf[BUFSIZ];
794
795 buf[0] = '\0';
796
797 if (interval / 3600)
798 {
799 sprintf (buf, "%dh", interval / 3600);
800 interval %= 3600;
801 }
802 if (interval / 60)
803 {
804 sprintf (buf + strlen (buf), "%dm", interval /60);
805 interval %= 60;
806 }
807 if (interval)
808 {
809 sprintf (buf + strlen (buf), "%d", interval);
810 }
811 return buf;
812 }
813 #endif
814
815 static int config_write_bgp_dump(struct vty *vty)
816 {
817 if (bgp_dump_all.filename) {
818 const char *type_str = "all";
819 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
820 type_str = "all-et";
821
822 if (bgp_dump_all.interval_str)
823 vty_out(vty, "dump bgp %s %s %s\n", type_str,
824 bgp_dump_all.filename,
825 bgp_dump_all.interval_str);
826 else
827 vty_out(vty, "dump bgp %s %s\n", type_str,
828 bgp_dump_all.filename);
829 }
830 if (bgp_dump_updates.filename) {
831 const char *type_str = "updates";
832 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
833 type_str = "updates-et";
834
835 if (bgp_dump_updates.interval_str)
836 vty_out(vty, "dump bgp %s %s %s\n", type_str,
837 bgp_dump_updates.filename,
838 bgp_dump_updates.interval_str);
839 else
840 vty_out(vty, "dump bgp %s %s\n", type_str,
841 bgp_dump_updates.filename);
842 }
843 if (bgp_dump_routes.filename) {
844 if (bgp_dump_routes.interval_str)
845 vty_out(vty, "dump bgp routes-mrt %s %s\n",
846 bgp_dump_routes.filename,
847 bgp_dump_routes.interval_str);
848 else
849 vty_out(vty, "dump bgp routes-mrt %s\n",
850 bgp_dump_routes.filename);
851 }
852 return 0;
853 }
854
855 /* Initialize BGP packet dump functionality. */
856 void bgp_dump_init(void)
857 {
858 memset(&bgp_dump_all, 0, sizeof(struct bgp_dump));
859 memset(&bgp_dump_updates, 0, sizeof(struct bgp_dump));
860 memset(&bgp_dump_routes, 0, sizeof(struct bgp_dump));
861
862 bgp_dump_obuf =
863 stream_new((BGP_MAX_PACKET_SIZE << 1) + BGP_DUMP_MSG_HEADER
864 + BGP_DUMP_HEADER_SIZE);
865
866 install_node(&bgp_dump_node);
867
868 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
869 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
870
871 hook_register(bgp_packet_dump, bgp_dump_packet);
872 hook_register(peer_status_changed, bgp_dump_state);
873 }
874
875 void bgp_dump_finish(void)
876 {
877 bgp_dump_unset(&bgp_dump_all);
878 bgp_dump_unset(&bgp_dump_updates);
879 bgp_dump_unset(&bgp_dump_routes);
880
881 stream_free(bgp_dump_obuf);
882 bgp_dump_obuf = NULL;
883 hook_unregister(bgp_packet_dump, bgp_dump_packet);
884 hook_unregister(peer_status_changed, bgp_dump_state);
885 }