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