]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
Merge pull request #1793 from qlyoung/stylechecker
[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) */
9d303b37
DL
247 stream_putc(obuf,
248 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
249 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
d62a17ae 250 /* Peer BGP ID (0.0.0.0) */
251 stream_putl(obuf, 0);
252 /* Peer IP address (0.0.0.0) */
253 stream_putl(obuf, 0);
254 /* Peer ASN (0) */
255 stream_putl(obuf, 0);
256
257 /* Walk down all peers */
258 for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
259
260 /* Peer's type */
261 if (sockunion_family(&peer->su) == AF_INET) {
262 stream_putc(
263 obuf,
264 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
265 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
266 } else if (sockunion_family(&peer->su) == AF_INET6) {
267 stream_putc(
268 obuf,
269 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
270 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
271 }
272
273 /* Peer's BGP ID */
274 stream_put_in_addr(obuf, &peer->remote_id);
275
276 /* Peer's IP address */
277 if (sockunion_family(&peer->su) == AF_INET) {
278 stream_put_in_addr(obuf, &peer->su.sin.sin_addr);
279 } else if (sockunion_family(&peer->su) == AF_INET6) {
280 stream_write(obuf, (u_char *)&peer->su.sin6.sin6_addr,
281 IPV6_MAX_BYTELEN);
282 }
283
284 /* Peer's AS number. */
285 /* Note that, as this is an AS4 compliant quagga, the RIB is
286 * always AS4 */
287 stream_putl(obuf, peer->as);
288
289 /* Store the peer number for this peer */
290 peer->table_dump_index = peerno;
291 peerno++;
292 }
718e3744 293
d62a17ae 294 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
718e3744 295
d62a17ae 296 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
297 fflush(bgp_dump_routes.fp);
718e3744 298}
299
0b2aa3a0 300
d62a17ae 301static struct bgp_info *bgp_dump_route_node_record(int afi, struct bgp_node *rn,
302 struct bgp_info *info,
303 unsigned int seq)
246556b5 304{
d62a17ae 305 struct stream *obuf;
306 size_t sizep;
307 size_t endp;
308
309 obuf = bgp_dump_obuf;
310 stream_reset(obuf);
311
312 /* MRT header */
313 if (afi == AFI_IP)
314 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
315 TABLE_DUMP_V2_RIB_IPV4_UNICAST,
316 BGP_DUMP_ROUTES);
317 else if (afi == AFI_IP6)
318 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
319 TABLE_DUMP_V2_RIB_IPV6_UNICAST,
320 BGP_DUMP_ROUTES);
321
322 /* Sequence number */
323 stream_putl(obuf, seq);
324
325 /* Prefix length */
326 stream_putc(obuf, rn->p.prefixlen);
327
328 /* Prefix */
329 if (afi == AFI_IP) {
330 /* We'll dump only the useful bits (those not 0), but have to
331 * align on 8 bits */
332 stream_write(obuf, (u_char *)&rn->p.u.prefix4,
333 (rn->p.prefixlen + 7) / 8);
334 } else if (afi == AFI_IP6) {
335 /* We'll dump only the useful bits (those not 0), but have to
336 * align on 8 bits */
337 stream_write(obuf, (u_char *)&rn->p.u.prefix6,
338 (rn->p.prefixlen + 7) / 8);
339 }
246556b5 340
d62a17ae 341 /* Save where we are now, so we can overwride the entry count later */
342 sizep = stream_get_endp(obuf);
246556b5 343
d62a17ae 344 /* Entry count */
345 uint16_t entry_count = 0;
246556b5 346
d62a17ae 347 /* Entry count, note that this is overwritten later */
348 stream_putw(obuf, 0);
246556b5 349
d62a17ae 350 endp = stream_get_endp(obuf);
351 for (; info; info = info->next) {
352 size_t cur_endp;
246556b5 353
d62a17ae 354 /* Peer index */
355 stream_putw(obuf, info->peer->table_dump_index);
246556b5 356
d62a17ae 357 /* Originated */
358 stream_putl(obuf, time(NULL) - (bgp_clock() - info->uptime));
246556b5 359
d62a17ae 360 /* Dump attribute. */
361 /* Skip prefix & AFI/SAFI for MP_NLRI */
362 bgp_dump_routes_attr(obuf, info->attr, &rn->p);
246556b5 363
d62a17ae 364 cur_endp = stream_get_endp(obuf);
365 if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
366 + BGP_DUMP_HEADER_SIZE) {
367 stream_set_endp(obuf, endp);
368 break;
369 }
246556b5 370
d62a17ae 371 entry_count++;
372 endp = cur_endp;
373 }
246556b5 374
d62a17ae 375 /* Overwrite the entry count, now that we know the right number */
376 stream_putw_at(obuf, sizep, entry_count);
246556b5 377
d62a17ae 378 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
379 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
246556b5 380
d62a17ae 381 return info;
246556b5
EU
382}
383
384
718e3744 385/* Runs under child process. */
d62a17ae 386static unsigned int bgp_dump_routes_func(int afi, int first_run,
387 unsigned int seq)
718e3744 388{
d62a17ae 389 struct bgp_info *info;
390 struct bgp_node *rn;
391 struct bgp *bgp;
392 struct bgp_table *table;
393
394 bgp = bgp_get_default();
395 if (!bgp)
396 return seq;
397
398 if (bgp_dump_routes.fp == NULL)
399 return seq;
400
401 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
402 so this should only be done on the first call to
403 bgp_dump_routes_func.
404 ( this function will be called once for ipv4 and once for ipv6 ) */
405 if (first_run)
406 bgp_dump_routes_index_table(bgp);
407
408 /* Walk down each BGP route. */
409 table = bgp->rib[afi][SAFI_UNICAST];
410
411 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
412 info = rn->info;
413 while (info) {
414 info = bgp_dump_route_node_record(afi, rn, info, seq);
415 seq++;
416 }
417 }
0b2aa3a0 418
d62a17ae 419 fflush(bgp_dump_routes.fp);
0b2aa3a0 420
d62a17ae 421 return seq;
718e3744 422}
423
d62a17ae 424static int bgp_dump_interval_func(struct thread *t)
718e3744 425{
d62a17ae 426 struct bgp_dump *bgp_dump;
427 bgp_dump = THREAD_ARG(t);
428 bgp_dump->t_interval = NULL;
429
430 /* Reschedule dump even if file couldn't be opened this time... */
431 if (bgp_dump_open_file(bgp_dump) != NULL) {
432 /* In case of bgp_dump_routes, we need special route dump
433 * function. */
434 if (bgp_dump->type == BGP_DUMP_ROUTES) {
435 unsigned int seq = bgp_dump_routes_func(AFI_IP, 1, 0);
436 bgp_dump_routes_func(AFI_IP6, 0, seq);
437 /* Close the file now. For a RIB dump there's no point
438 * in leaving
439 * it open until the next scheduled dump starts. */
440 fclose(bgp_dump->fp);
441 bgp_dump->fp = NULL;
442 }
9834cd0f 443 }
718e3744 444
d62a17ae 445 /* if interval is set reschedule */
446 if (bgp_dump->interval > 0)
447 bgp_dump_interval_add(bgp_dump, bgp_dump->interval);
fba3d22b 448
d62a17ae 449 return 0;
718e3744 450}
451
452/* Dump common information. */
d62a17ae 453static void bgp_dump_common(struct stream *obuf, struct peer *peer,
454 int forceas4)
718e3744 455{
d62a17ae 456 char empty[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
457
458 /* Source AS number and Destination AS number. */
459 if (forceas4 || CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
460 stream_putl(obuf, peer->as);
461 stream_putl(obuf, peer->local_as);
462 } else {
463 stream_putw(obuf, peer->as);
464 stream_putw(obuf, peer->local_as);
465 }
718e3744 466
d62a17ae 467 if (peer->su.sa.sa_family == AF_INET) {
468 stream_putw(obuf, peer->ifindex);
469 stream_putw(obuf, AFI_IP);
470
471 stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
472
473 if (peer->su_local)
474 stream_put(obuf, &peer->su_local->sin.sin_addr,
475 IPV4_MAX_BYTELEN);
476 else
477 stream_put(obuf, empty, IPV4_MAX_BYTELEN);
478 } else if (peer->su.sa.sa_family == AF_INET6) {
479 /* Interface Index and Address family. */
480 stream_putw(obuf, peer->ifindex);
481 stream_putw(obuf, AFI_IP6);
482
483 /* Source IP Address and Destination IP Address. */
484 stream_put(obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
485
486 if (peer->su_local)
487 stream_put(obuf, &peer->su_local->sin6.sin6_addr,
488 IPV6_MAX_BYTELEN);
489 else
490 stream_put(obuf, empty, IPV6_MAX_BYTELEN);
491 }
718e3744 492}
493
494/* Dump BGP status change. */
d62a17ae 495void bgp_dump_state(struct peer *peer, int status_old, int status_new)
718e3744 496{
d62a17ae 497 struct stream *obuf;
718e3744 498
d62a17ae 499 /* If dump file pointer is disabled return immediately. */
500 if (bgp_dump_all.fp == NULL)
501 return;
718e3744 502
d62a17ae 503 /* Make dump stream. */
504 obuf = bgp_dump_obuf;
505 stream_reset(obuf);
718e3744 506
d62a17ae 507 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
508 bgp_dump_all.type);
509 bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/
718e3744 510
d62a17ae 511 stream_putw(obuf, status_old);
512 stream_putw(obuf, status_new);
718e3744 513
d62a17ae 514 /* Set length. */
515 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 516
d62a17ae 517 /* Write to the stream. */
518 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_all.fp);
519 fflush(bgp_dump_all.fp);
718e3744 520}
521
d62a17ae 522static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
523 struct stream *packet)
718e3744 524{
d62a17ae 525 struct stream *obuf;
526
527 /* If dump file pointer is disabled return immediately. */
528 if (bgp_dump->fp == NULL)
529 return;
530
531 /* Make dump stream. */
532 obuf = bgp_dump_obuf;
533 stream_reset(obuf);
534
535 /* Dump header and common part. */
536 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
537 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
538 bgp_dump->type);
539 } else {
540 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
541 bgp_dump->type);
542 }
543 bgp_dump_common(obuf, peer, 0);
718e3744 544
d62a17ae 545 /* Packet contents. */
546 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
718e3744 547
d62a17ae 548 /* Set length. */
549 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 550
d62a17ae 551 /* Write to the stream. */
552 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
553 fflush(bgp_dump->fp);
718e3744 554}
555
556/* Called from bgp_packet.c when BGP packet is received. */
d62a17ae 557void bgp_dump_packet(struct peer *peer, int type, struct stream *packet)
718e3744 558{
d62a17ae 559 /* bgp_dump_all. */
560 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
718e3744 561
d62a17ae 562 /* bgp_dump_updates. */
563 if (type == BGP_MSG_UPDATE)
564 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
718e3744 565}
6b0655a2 566
d62a17ae 567static unsigned int bgp_dump_parse_time(const char *str)
718e3744 568{
d62a17ae 569 int i;
570 int len;
571 int seen_h;
572 int seen_m;
573 int time;
574 unsigned int total;
575
576 time = 0;
577 total = 0;
578 seen_h = 0;
579 seen_m = 0;
580 len = strlen(str);
581
582 for (i = 0; i < len; i++) {
583 if (isdigit((int)str[i])) {
584 time *= 10;
585 time += str[i] - '0';
586 } else if (str[i] == 'H' || str[i] == 'h') {
587 if (seen_h)
588 return 0;
589 if (seen_m)
590 return 0;
591 total += time * 60 * 60;
592 time = 0;
593 seen_h = 1;
594 } else if (str[i] == 'M' || str[i] == 'm') {
595 if (seen_m)
596 return 0;
597 total += time * 60;
598 time = 0;
599 seen_m = 1;
600 } else
601 return 0;
718e3744 602 }
d62a17ae 603 return total + time;
718e3744 604}
605
d62a17ae 606static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
607 enum bgp_dump_type type, const char *path,
608 const char *interval_str)
718e3744 609{
d62a17ae 610 unsigned int interval;
611
612 /* Don't schedule duplicate dumps if the dump command is given twice */
613 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
614 && type == bgp_dump->type) {
615 if (interval_str) {
616 if (bgp_dump->interval_str
617 && strcmp(bgp_dump->interval_str, interval_str)
618 == 0)
619 return CMD_SUCCESS;
620 } else {
621 if (!bgp_dump->interval_str)
622 return CMD_SUCCESS;
623 }
718e3744 624 }
45ad592e 625
d62a17ae 626 /* Removing previous config */
627 bgp_dump_unset(bgp_dump);
628
629 if (interval_str) {
630 /* Check interval string. */
631 interval = bgp_dump_parse_time(interval_str);
632 if (interval == 0) {
633 vty_out(vty, "Malformed interval string\n");
634 return CMD_WARNING_CONFIG_FAILED;
635 }
636
637 /* Setting interval string */
638 bgp_dump->interval_str =
639 XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
640 } else {
641 interval = 0;
642 }
718e3744 643
d62a17ae 644 /* Set type. */
645 bgp_dump->type = type;
718e3744 646
d62a17ae 647 /* Set interval */
648 bgp_dump->interval = interval;
4db5d90a 649
d62a17ae 650 /* Set file name. */
651 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
4db5d90a 652
d62a17ae 653 /* Create interval thread. */
654 bgp_dump_interval_add(bgp_dump, interval);
718e3744 655
d62a17ae 656 /* This should be called when interval is expired. */
657 bgp_dump_open_file(bgp_dump);
718e3744 658
d62a17ae 659 return CMD_SUCCESS;
718e3744 660}
661
d62a17ae 662static int bgp_dump_unset(struct bgp_dump *bgp_dump)
718e3744 663{
d62a17ae 664 /* Removing file name. */
665 if (bgp_dump->filename) {
666 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
667 bgp_dump->filename = NULL;
668 }
718e3744 669
d62a17ae 670 /* Closing file. */
671 if (bgp_dump->fp) {
672 fclose(bgp_dump->fp);
673 bgp_dump->fp = NULL;
674 }
718e3744 675
d62a17ae 676 /* Removing interval thread. */
677 if (bgp_dump->t_interval) {
678 thread_cancel(bgp_dump->t_interval);
679 bgp_dump->t_interval = NULL;
680 }
718e3744 681
d62a17ae 682 bgp_dump->interval = 0;
718e3744 683
d62a17ae 684 /* Removing interval string. */
685 if (bgp_dump->interval_str) {
686 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
687 bgp_dump->interval_str = NULL;
688 }
689
690 return CMD_SUCCESS;
718e3744 691}
692
693DEFUN (dump_bgp_all,
694 dump_bgp_all_cmd,
6147e2c6 695 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
718e3744 696 "Dump packet\n"
697 "BGP packet dump\n"
cbac2b1b
EU
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"
4db5d90a 700 "Dump whole BGP routing table\n"
718e3744 701 "Output filename\n"
702 "Interval of output\n")
703{
d62a17ae 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 }
718e3744 730
d62a17ae 731 /* When an interval is given */
732 if (argc == idx_interval + 1)
733 interval = argv[idx_interval]->arg;
718e3744 734
d62a17ae 735 return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
736 argv[idx_path]->arg, interval);
718e3744 737}
738
4db5d90a
AF
739DEFUN (no_dump_bgp_all,
740 no_dump_bgp_all_cmd,
37bc45eb 741 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
718e3744 742 NO_STR
4db5d90a
AF
743 "Stop dump packet\n"
744 "Stop BGP packet dump\n"
ca492402
DS
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"
3a2d747c
QY
749 "Stop dump process route-mrt\n"
750 "Output filename\n"
751 "Interval of output\n")
718e3744 752{
d62a17ae 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 }
ca492402 776
d62a17ae 777 return bgp_dump_unset(bgp_dump_struct);
718e3744 778}
779
780/* BGP node structure. */
d62a17ae 781static struct cmd_node bgp_dump_node = {DUMP_NODE, "", 1};
718e3744 782
783#if 0
784char *
785config_time2str (unsigned int interval)
786{
787 static char buf[BUFSIZ];
788
789 buf[0] = '\0';
790
791 if (interval / 3600)
792 {
793 sprintf (buf, "%dh", interval / 3600);
794 interval %= 3600;
795 }
796 if (interval / 60)
797 {
798 sprintf (buf + strlen (buf), "%dm", interval /60);
799 interval %= 60;
800 }
801 if (interval)
802 {
803 sprintf (buf + strlen (buf), "%d", interval);
804 }
805 return buf;
806}
807#endif
808
d62a17ae 809static int config_write_bgp_dump(struct vty *vty)
718e3744 810{
d62a17ae 811 if (bgp_dump_all.filename) {
812 const char *type_str = "all";
813 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
814 type_str = "all-et";
815
816 if (bgp_dump_all.interval_str)
817 vty_out(vty, "dump bgp %s %s %s\n", type_str,
818 bgp_dump_all.filename,
819 bgp_dump_all.interval_str);
820 else
821 vty_out(vty, "dump bgp %s %s\n", type_str,
822 bgp_dump_all.filename);
823 }
824 if (bgp_dump_updates.filename) {
825 const char *type_str = "updates";
826 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
827 type_str = "updates-et";
828
829 if (bgp_dump_updates.interval_str)
830 vty_out(vty, "dump bgp %s %s %s\n", type_str,
831 bgp_dump_updates.filename,
832 bgp_dump_updates.interval_str);
833 else
834 vty_out(vty, "dump bgp %s %s\n", type_str,
835 bgp_dump_updates.filename);
836 }
837 if (bgp_dump_routes.filename) {
838 if (bgp_dump_routes.interval_str)
839 vty_out(vty, "dump bgp routes-mrt %s %s\n",
840 bgp_dump_routes.filename,
841 bgp_dump_routes.interval_str);
842 else
843 vty_out(vty, "dump bgp routes-mrt %s\n",
844 bgp_dump_routes.filename);
845 }
846 return 0;
718e3744 847}
6b0655a2 848
718e3744 849/* Initialize BGP packet dump functionality. */
d62a17ae 850void bgp_dump_init(void)
718e3744 851{
d62a17ae 852 memset(&bgp_dump_all, 0, sizeof(struct bgp_dump));
853 memset(&bgp_dump_updates, 0, sizeof(struct bgp_dump));
854 memset(&bgp_dump_routes, 0, sizeof(struct bgp_dump));
718e3744 855
d62a17ae 856 bgp_dump_obuf =
857 stream_new((BGP_MAX_PACKET_SIZE << 1) + BGP_DUMP_MSG_HEADER
858 + BGP_DUMP_HEADER_SIZE);
718e3744 859
d62a17ae 860 install_node(&bgp_dump_node, config_write_bgp_dump);
718e3744 861
d62a17ae 862 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
863 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
718e3744 864}
228da428 865
d62a17ae 866void bgp_dump_finish(void)
228da428 867{
d62a17ae 868 bgp_dump_unset(&bgp_dump_all);
869 bgp_dump_unset(&bgp_dump_updates);
870 bgp_dump_unset(&bgp_dump_routes);
b8438f6d 871
d62a17ae 872 stream_free(bgp_dump_obuf);
873 bgp_dump_obuf = NULL;
228da428 874}