]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[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"
6b0655a2 40
d62a17ae 41enum 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
718e3744 47};
48
4db5d90a 49static const struct bgp_dump_type_map {
d62a17ae 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};
4db5d90a 57
718e3744 58enum MRT_MSG_TYPES {
d62a17ae 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 */
718e3744 73};
74
d62a17ae 75struct bgp_dump {
76 enum bgp_dump_type type;
718e3744 77
d62a17ae 78 char *filename;
718e3744 79
d62a17ae 80 FILE *fp;
718e3744 81
d62a17ae 82 unsigned int interval;
718e3744 83
d62a17ae 84 char *interval_str;
718e3744 85
d62a17ae 86 struct thread *t_interval;
718e3744 87};
88
d62a17ae 89static int bgp_dump_unset(struct bgp_dump *bgp_dump);
90static int bgp_dump_interval_func(struct thread *);
4db5d90a 91
718e3744 92/* BGP packet dump output buffer. */
93struct stream *bgp_dump_obuf;
94
95/* BGP dump strucuture for 'dump bgp all' */
96struct bgp_dump bgp_dump_all;
97
98/* BGP dump structure for 'dump bgp updates' */
99struct bgp_dump bgp_dump_updates;
100
101/* BGP dump structure for 'dump bgp routes' */
102struct bgp_dump bgp_dump_routes;
103
d62a17ae 104static FILE *bgp_dump_open_file(struct bgp_dump *bgp_dump)
718e3744 105{
d62a17ae 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) {
e50f7cfd 123 flog_warn(EC_BGP_DUMP, "bgp_dump_open_file: strftime error");
d62a17ae 124 return NULL;
125 }
718e3744 126
d62a17ae 127 if (bgp_dump->fp)
128 fclose(bgp_dump->fp);
718e3744 129
130
d62a17ae 131 oldumask = umask(0777 & ~LOGFILE_MASK);
132 bgp_dump->fp = fopen(realpath, "w");
718e3744 133
d62a17ae 134 if (bgp_dump->fp == NULL) {
e50f7cfd 135 flog_warn(EC_BGP_DUMP, "bgp_dump_open_file: %s: %s", realpath,
d62a17ae 136 strerror(errno));
137 umask(oldumask);
138 return NULL;
139 }
140 umask(oldumask);
718e3744 141
d62a17ae 142 return bgp_dump->fp;
718e3744 143}
144
d62a17ae 145static int bgp_dump_interval_add(struct bgp_dump *bgp_dump, int interval)
718e3744 146{
d62a17ae 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);
9834cd0f 175 }
fba3d22b 176
d62a17ae 177 return 0;
718e3744 178}
179
180/* Dump common header. */
d62a17ae 181static void bgp_dump_header(struct stream *obuf, int type, int subtype,
182 int dump_type)
718e3744 183{
d62a17ae 184 struct timeval clock;
185 long msecs;
186 time_t secs;
4db5d90a 187
d62a17ae 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;
4db5d90a 191
d62a17ae 192 gettimeofday(&clock, NULL);
718e3744 193
d62a17ae 194 secs = clock.tv_sec;
195 msecs = clock.tv_usec;
718e3744 196
d62a17ae 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 */
4db5d90a 202
d62a17ae 203 /* Adding microseconds for the MRT Extended Header */
204 if (type == MSG_PROTOCOL_BGP4MP_ET)
205 stream_putl(obuf, msecs);
718e3744 206}
207
d62a17ae 208static void bgp_dump_set_size(struct stream *s, int type)
718e3744 209{
d62a17ae 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);
718e3744 216}
217
d62a17ae 218static void bgp_dump_routes_index_table(struct bgp *bgp)
718e3744 219{
d62a17ae 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 }
718e3744 242
d62a17ae 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) */
9d303b37
DL
248 stream_putc(obuf,
249 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
250 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
d62a17ae 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) {
d7c0a89a 281 stream_write(obuf, (uint8_t *)&peer->su.sin6.sin6_addr,
d62a17ae 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 }
718e3744 294
d62a17ae 295 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
718e3744 296
d62a17ae 297 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
298 fflush(bgp_dump_routes.fp);
718e3744 299}
300
0b2aa3a0 301
4b7e6066
DS
302static struct bgp_path_info *
303bgp_dump_route_node_record(int afi, struct bgp_node *rn,
40381db7 304 struct bgp_path_info *path, unsigned int seq)
246556b5 305{
d62a17ae 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 */
d7c0a89a 333 stream_write(obuf, (uint8_t *)&rn->p.u.prefix4,
d62a17ae 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 */
d7c0a89a 338 stream_write(obuf, (uint8_t *)&rn->p.u.prefix6,
d62a17ae 339 (rn->p.prefixlen + 7) / 8);
340 }
246556b5 341
d62a17ae 342 /* Save where we are now, so we can overwride the entry count later */
343 sizep = stream_get_endp(obuf);
246556b5 344
d62a17ae 345 /* Entry count */
346 uint16_t entry_count = 0;
246556b5 347
d62a17ae 348 /* Entry count, note that this is overwritten later */
349 stream_putw(obuf, 0);
246556b5 350
d62a17ae 351 endp = stream_get_endp(obuf);
40381db7 352 for (; path; path = path->next) {
d62a17ae 353 size_t cur_endp;
246556b5 354
d62a17ae 355 /* Peer index */
40381db7 356 stream_putw(obuf, path->peer->table_dump_index);
246556b5 357
d62a17ae 358 /* Originated */
40381db7 359 stream_putl(obuf, time(NULL) - (bgp_clock() - path->uptime));
246556b5 360
d62a17ae 361 /* Dump attribute. */
362 /* Skip prefix & AFI/SAFI for MP_NLRI */
40381db7 363 bgp_dump_routes_attr(obuf, path->attr, &rn->p);
246556b5 364
d62a17ae 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 }
246556b5 371
d62a17ae 372 entry_count++;
373 endp = cur_endp;
374 }
246556b5 375
d62a17ae 376 /* Overwrite the entry count, now that we know the right number */
377 stream_putw_at(obuf, sizep, entry_count);
246556b5 378
d62a17ae 379 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
380 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
246556b5 381
40381db7 382 return path;
246556b5
EU
383}
384
385
718e3744 386/* Runs under child process. */
d62a17ae 387static unsigned int bgp_dump_routes_func(int afi, int first_run,
388 unsigned int seq)
718e3744 389{
40381db7 390 struct bgp_path_info *path;
d62a17ae 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)) {
6f94b685 413 path = bgp_node_get_bgp_path_info(rn);
40381db7
DS
414 while (path) {
415 path = bgp_dump_route_node_record(afi, rn, path, seq);
d62a17ae 416 seq++;
417 }
418 }
0b2aa3a0 419
d62a17ae 420 fflush(bgp_dump_routes.fp);
0b2aa3a0 421
d62a17ae 422 return seq;
718e3744 423}
424
d62a17ae 425static int bgp_dump_interval_func(struct thread *t)
718e3744 426{
d62a17ae 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 }
9834cd0f 444 }
718e3744 445
d62a17ae 446 /* if interval is set reschedule */
447 if (bgp_dump->interval > 0)
448 bgp_dump_interval_add(bgp_dump, bgp_dump->interval);
fba3d22b 449
d62a17ae 450 return 0;
718e3744 451}
452
453/* Dump common information. */
d62a17ae 454static void bgp_dump_common(struct stream *obuf, struct peer *peer,
455 int forceas4)
718e3744 456{
d62a17ae 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 }
718e3744 467
d62a17ae 468 if (peer->su.sa.sa_family == AF_INET) {
194a4f2c 469 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
d62a17ae 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. */
194a4f2c 481 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
d62a17ae 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 }
718e3744 493}
494
495/* Dump BGP status change. */
d62a17ae 496void bgp_dump_state(struct peer *peer, int status_old, int status_new)
718e3744 497{
d62a17ae 498 struct stream *obuf;
718e3744 499
d62a17ae 500 /* If dump file pointer is disabled return immediately. */
501 if (bgp_dump_all.fp == NULL)
502 return;
718e3744 503
d62a17ae 504 /* Make dump stream. */
505 obuf = bgp_dump_obuf;
506 stream_reset(obuf);
718e3744 507
d62a17ae 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*/
718e3744 511
d62a17ae 512 stream_putw(obuf, status_old);
513 stream_putw(obuf, status_new);
718e3744 514
d62a17ae 515 /* Set length. */
516 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 517
d62a17ae 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);
718e3744 521}
522
d62a17ae 523static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
524 struct stream *packet)
718e3744 525{
d62a17ae 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);
718e3744 545
d62a17ae 546 /* Packet contents. */
547 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
718e3744 548
d62a17ae 549 /* Set length. */
550 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 551
d62a17ae 552 /* Write to the stream. */
553 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
554 fflush(bgp_dump->fp);
718e3744 555}
556
557/* Called from bgp_packet.c when BGP packet is received. */
d62a17ae 558void bgp_dump_packet(struct peer *peer, int type, struct stream *packet)
718e3744 559{
d62a17ae 560 /* bgp_dump_all. */
561 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
718e3744 562
d62a17ae 563 /* bgp_dump_updates. */
564 if (type == BGP_MSG_UPDATE)
565 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
718e3744 566}
6b0655a2 567
d62a17ae 568static unsigned int bgp_dump_parse_time(const char *str)
718e3744 569{
d62a17ae 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;
718e3744 603 }
d62a17ae 604 return total + time;
718e3744 605}
606
d62a17ae 607static 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)
718e3744 610{
d62a17ae 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 }
718e3744 625 }
45ad592e 626
d62a17ae 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 }
718e3744 644
d62a17ae 645 /* Set type. */
646 bgp_dump->type = type;
718e3744 647
d62a17ae 648 /* Set interval */
649 bgp_dump->interval = interval;
4db5d90a 650
d62a17ae 651 /* Set file name. */
652 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
4db5d90a 653
d62a17ae 654 /* Create interval thread. */
655 bgp_dump_interval_add(bgp_dump, interval);
718e3744 656
d62a17ae 657 /* This should be called when interval is expired. */
658 bgp_dump_open_file(bgp_dump);
718e3744 659
d62a17ae 660 return CMD_SUCCESS;
718e3744 661}
662
d62a17ae 663static int bgp_dump_unset(struct bgp_dump *bgp_dump)
718e3744 664{
d62a17ae 665 /* Removing file name. */
666 if (bgp_dump->filename) {
667 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
668 bgp_dump->filename = NULL;
669 }
718e3744 670
d62a17ae 671 /* Closing file. */
672 if (bgp_dump->fp) {
673 fclose(bgp_dump->fp);
674 bgp_dump->fp = NULL;
675 }
718e3744 676
d62a17ae 677 /* Removing interval thread. */
678 if (bgp_dump->t_interval) {
679 thread_cancel(bgp_dump->t_interval);
680 bgp_dump->t_interval = NULL;
681 }
718e3744 682
d62a17ae 683 bgp_dump->interval = 0;
718e3744 684
d62a17ae 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;
718e3744 692}
693
694DEFUN (dump_bgp_all,
695 dump_bgp_all_cmd,
6147e2c6 696 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
718e3744 697 "Dump packet\n"
698 "BGP packet dump\n"
cbac2b1b
EU
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"
4db5d90a 701 "Dump whole BGP routing table\n"
718e3744 702 "Output filename\n"
703 "Interval of output\n")
704{
d62a17ae 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 }
718e3744 731
d62a17ae 732 /* When an interval is given */
733 if (argc == idx_interval + 1)
734 interval = argv[idx_interval]->arg;
718e3744 735
d62a17ae 736 return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
737 argv[idx_path]->arg, interval);
718e3744 738}
739
4db5d90a
AF
740DEFUN (no_dump_bgp_all,
741 no_dump_bgp_all_cmd,
37bc45eb 742 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
718e3744 743 NO_STR
4db5d90a
AF
744 "Stop dump packet\n"
745 "Stop BGP packet dump\n"
ca492402
DS
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"
3a2d747c
QY
750 "Stop dump process route-mrt\n"
751 "Output filename\n"
752 "Interval of output\n")
718e3744 753{
d62a17ae 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 }
ca492402 777
d62a17ae 778 return bgp_dump_unset(bgp_dump_struct);
718e3744 779}
780
781/* BGP node structure. */
d62a17ae 782static struct cmd_node bgp_dump_node = {DUMP_NODE, "", 1};
718e3744 783
784#if 0
785char *
786config_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
d62a17ae 810static int config_write_bgp_dump(struct vty *vty)
718e3744 811{
d62a17ae 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;
718e3744 848}
6b0655a2 849
718e3744 850/* Initialize BGP packet dump functionality. */
d62a17ae 851void bgp_dump_init(void)
718e3744 852{
d62a17ae 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));
718e3744 856
d62a17ae 857 bgp_dump_obuf =
858 stream_new((BGP_MAX_PACKET_SIZE << 1) + BGP_DUMP_MSG_HEADER
859 + BGP_DUMP_HEADER_SIZE);
718e3744 860
d62a17ae 861 install_node(&bgp_dump_node, config_write_bgp_dump);
718e3744 862
d62a17ae 863 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
864 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
718e3744 865}
228da428 866
d62a17ae 867void bgp_dump_finish(void)
228da428 868{
d62a17ae 869 bgp_dump_unset(&bgp_dump_all);
870 bgp_dump_unset(&bgp_dump_updates);
871 bgp_dump_unset(&bgp_dump_routes);
b8438f6d 872
d62a17ae 873 stream_free(bgp_dump_obuf);
874 bgp_dump_obuf = NULL;
228da428 875}