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