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