]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
Merge pull request #5686 from qlyoung/fix-bgp-fqdn-capability-leak
[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 */
8c1a4c10
DS
237 if (bgp->name_pretty) {
238 stream_putw(obuf, strlen(bgp->name_pretty));
239 stream_put(obuf, bgp->name_pretty, strlen(bgp->name_pretty));
d62a17ae 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. */
7d8d0eab 497int bgp_dump_state(struct peer *peer)
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)
7d8d0eab 503 return 0;
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
7d8d0eab
MKS
513 stream_putw(obuf, peer->ostatus);
514 stream_putw(obuf, peer->status);
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);
7d8d0eab 522 return 0;
718e3744 523}
524
d62a17ae 525static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
526 struct stream *packet)
718e3744 527{
d62a17ae 528 struct stream *obuf;
529
530 /* If dump file pointer is disabled return immediately. */
531 if (bgp_dump->fp == NULL)
532 return;
533
534 /* Make dump stream. */
535 obuf = bgp_dump_obuf;
536 stream_reset(obuf);
537
538 /* Dump header and common part. */
539 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
540 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
541 bgp_dump->type);
542 } else {
543 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
544 bgp_dump->type);
545 }
546 bgp_dump_common(obuf, peer, 0);
718e3744 547
d62a17ae 548 /* Packet contents. */
549 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
718e3744 550
d62a17ae 551 /* Set length. */
552 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 553
d62a17ae 554 /* Write to the stream. */
555 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
556 fflush(bgp_dump->fp);
718e3744 557}
558
559/* Called from bgp_packet.c when BGP packet is received. */
584470fb
DL
560static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
561 struct stream *packet)
718e3744 562{
d62a17ae 563 /* bgp_dump_all. */
564 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
718e3744 565
d62a17ae 566 /* bgp_dump_updates. */
567 if (type == BGP_MSG_UPDATE)
568 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
584470fb 569 return 0;
718e3744 570}
6b0655a2 571
d62a17ae 572static unsigned int bgp_dump_parse_time(const char *str)
718e3744 573{
d62a17ae 574 int i;
575 int len;
576 int seen_h;
577 int seen_m;
578 int time;
579 unsigned int total;
580
581 time = 0;
582 total = 0;
583 seen_h = 0;
584 seen_m = 0;
585 len = strlen(str);
586
587 for (i = 0; i < len; i++) {
fefa5e0f 588 if (isdigit((unsigned char)str[i])) {
d62a17ae 589 time *= 10;
590 time += str[i] - '0';
591 } else if (str[i] == 'H' || str[i] == 'h') {
592 if (seen_h)
593 return 0;
594 if (seen_m)
595 return 0;
596 total += time * 60 * 60;
597 time = 0;
598 seen_h = 1;
599 } else if (str[i] == 'M' || str[i] == 'm') {
600 if (seen_m)
601 return 0;
602 total += time * 60;
603 time = 0;
604 seen_m = 1;
605 } else
606 return 0;
718e3744 607 }
d62a17ae 608 return total + time;
718e3744 609}
610
d62a17ae 611static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
612 enum bgp_dump_type type, const char *path,
613 const char *interval_str)
718e3744 614{
d62a17ae 615 unsigned int interval;
616
617 /* Don't schedule duplicate dumps if the dump command is given twice */
618 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
619 && type == bgp_dump->type) {
620 if (interval_str) {
621 if (bgp_dump->interval_str
622 && strcmp(bgp_dump->interval_str, interval_str)
623 == 0)
624 return CMD_SUCCESS;
625 } else {
626 if (!bgp_dump->interval_str)
627 return CMD_SUCCESS;
628 }
718e3744 629 }
45ad592e 630
d62a17ae 631 /* Removing previous config */
632 bgp_dump_unset(bgp_dump);
633
634 if (interval_str) {
635 /* Check interval string. */
636 interval = bgp_dump_parse_time(interval_str);
637 if (interval == 0) {
638 vty_out(vty, "Malformed interval string\n");
639 return CMD_WARNING_CONFIG_FAILED;
640 }
641
642 /* Setting interval string */
643 bgp_dump->interval_str =
644 XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
645 } else {
646 interval = 0;
647 }
718e3744 648
d62a17ae 649 /* Set type. */
650 bgp_dump->type = type;
718e3744 651
d62a17ae 652 /* Set interval */
653 bgp_dump->interval = interval;
4db5d90a 654
d62a17ae 655 /* Set file name. */
656 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
4db5d90a 657
d62a17ae 658 /* Create interval thread. */
659 bgp_dump_interval_add(bgp_dump, interval);
718e3744 660
d62a17ae 661 /* This should be called when interval is expired. */
662 bgp_dump_open_file(bgp_dump);
718e3744 663
d62a17ae 664 return CMD_SUCCESS;
718e3744 665}
666
d62a17ae 667static int bgp_dump_unset(struct bgp_dump *bgp_dump)
718e3744 668{
d62a17ae 669 /* Removing file name. */
670 if (bgp_dump->filename) {
671 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
672 bgp_dump->filename = NULL;
673 }
718e3744 674
d62a17ae 675 /* Closing file. */
676 if (bgp_dump->fp) {
677 fclose(bgp_dump->fp);
678 bgp_dump->fp = NULL;
679 }
718e3744 680
d62a17ae 681 /* Removing interval thread. */
682 if (bgp_dump->t_interval) {
683 thread_cancel(bgp_dump->t_interval);
684 bgp_dump->t_interval = NULL;
685 }
718e3744 686
d62a17ae 687 bgp_dump->interval = 0;
718e3744 688
d62a17ae 689 /* Removing interval string. */
690 if (bgp_dump->interval_str) {
691 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
692 bgp_dump->interval_str = NULL;
693 }
694
695 return CMD_SUCCESS;
718e3744 696}
697
698DEFUN (dump_bgp_all,
699 dump_bgp_all_cmd,
6147e2c6 700 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
718e3744 701 "Dump packet\n"
702 "BGP packet dump\n"
cbac2b1b
EU
703 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
704 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
4db5d90a 705 "Dump whole BGP routing table\n"
718e3744 706 "Output filename\n"
707 "Interval of output\n")
708{
d62a17ae 709 int idx_dump_routes = 2;
710 int idx_path = 3;
711 int idx_interval = 4;
712 int bgp_dump_type = 0;
713 const char *interval = NULL;
714 struct bgp_dump *bgp_dump_struct = NULL;
715 const struct bgp_dump_type_map *map = NULL;
716
717 for (map = bgp_dump_type_map; map->str; map++)
718 if (strmatch(argv[idx_dump_routes]->text, map->str))
719 bgp_dump_type = map->type;
720
721 switch (bgp_dump_type) {
722 case BGP_DUMP_ALL:
723 case BGP_DUMP_ALL_ET:
724 bgp_dump_struct = &bgp_dump_all;
725 break;
726 case BGP_DUMP_UPDATES:
727 case BGP_DUMP_UPDATES_ET:
728 bgp_dump_struct = &bgp_dump_updates;
729 break;
730 case BGP_DUMP_ROUTES:
731 default:
732 bgp_dump_struct = &bgp_dump_routes;
733 break;
734 }
718e3744 735
d62a17ae 736 /* When an interval is given */
737 if (argc == idx_interval + 1)
738 interval = argv[idx_interval]->arg;
718e3744 739
d62a17ae 740 return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
741 argv[idx_path]->arg, interval);
718e3744 742}
743
4db5d90a
AF
744DEFUN (no_dump_bgp_all,
745 no_dump_bgp_all_cmd,
37bc45eb 746 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
718e3744 747 NO_STR
4db5d90a
AF
748 "Stop dump packet\n"
749 "Stop BGP packet dump\n"
ca492402
DS
750 "Stop dump process all\n"
751 "Stop dump process all-et\n"
752 "Stop dump process updates\n"
753 "Stop dump process updates-et\n"
3a2d747c
QY
754 "Stop dump process route-mrt\n"
755 "Output filename\n"
756 "Interval of output\n")
718e3744 757{
d62a17ae 758 int idx_dump_routes = 3;
759 int bgp_dump_type = 0;
760 const struct bgp_dump_type_map *map = NULL;
761 struct bgp_dump *bgp_dump_struct = NULL;
762
763 for (map = bgp_dump_type_map; map->str; map++)
764 if (strmatch(argv[idx_dump_routes]->text, map->str))
765 bgp_dump_type = map->type;
766
767 switch (bgp_dump_type) {
768 case BGP_DUMP_ALL:
769 case BGP_DUMP_ALL_ET:
770 bgp_dump_struct = &bgp_dump_all;
771 break;
772 case BGP_DUMP_UPDATES:
773 case BGP_DUMP_UPDATES_ET:
774 bgp_dump_struct = &bgp_dump_updates;
775 break;
776 case BGP_DUMP_ROUTES:
777 default:
778 bgp_dump_struct = &bgp_dump_routes;
779 break;
780 }
ca492402 781
d62a17ae 782 return bgp_dump_unset(bgp_dump_struct);
718e3744 783}
784
785/* BGP node structure. */
d62a17ae 786static struct cmd_node bgp_dump_node = {DUMP_NODE, "", 1};
718e3744 787
788#if 0
789char *
790config_time2str (unsigned int interval)
791{
792 static char buf[BUFSIZ];
793
794 buf[0] = '\0';
795
796 if (interval / 3600)
797 {
798 sprintf (buf, "%dh", interval / 3600);
799 interval %= 3600;
800 }
801 if (interval / 60)
802 {
803 sprintf (buf + strlen (buf), "%dm", interval /60);
804 interval %= 60;
805 }
806 if (interval)
807 {
808 sprintf (buf + strlen (buf), "%d", interval);
809 }
810 return buf;
811}
812#endif
813
d62a17ae 814static int config_write_bgp_dump(struct vty *vty)
718e3744 815{
d62a17ae 816 if (bgp_dump_all.filename) {
817 const char *type_str = "all";
818 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
819 type_str = "all-et";
820
821 if (bgp_dump_all.interval_str)
822 vty_out(vty, "dump bgp %s %s %s\n", type_str,
823 bgp_dump_all.filename,
824 bgp_dump_all.interval_str);
825 else
826 vty_out(vty, "dump bgp %s %s\n", type_str,
827 bgp_dump_all.filename);
828 }
829 if (bgp_dump_updates.filename) {
830 const char *type_str = "updates";
831 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
832 type_str = "updates-et";
833
834 if (bgp_dump_updates.interval_str)
835 vty_out(vty, "dump bgp %s %s %s\n", type_str,
836 bgp_dump_updates.filename,
837 bgp_dump_updates.interval_str);
838 else
839 vty_out(vty, "dump bgp %s %s\n", type_str,
840 bgp_dump_updates.filename);
841 }
842 if (bgp_dump_routes.filename) {
843 if (bgp_dump_routes.interval_str)
844 vty_out(vty, "dump bgp routes-mrt %s %s\n",
845 bgp_dump_routes.filename,
846 bgp_dump_routes.interval_str);
847 else
848 vty_out(vty, "dump bgp routes-mrt %s\n",
849 bgp_dump_routes.filename);
850 }
851 return 0;
718e3744 852}
6b0655a2 853
718e3744 854/* Initialize BGP packet dump functionality. */
d62a17ae 855void bgp_dump_init(void)
718e3744 856{
d62a17ae 857 memset(&bgp_dump_all, 0, sizeof(struct bgp_dump));
858 memset(&bgp_dump_updates, 0, sizeof(struct bgp_dump));
859 memset(&bgp_dump_routes, 0, sizeof(struct bgp_dump));
718e3744 860
d62a17ae 861 bgp_dump_obuf =
862 stream_new((BGP_MAX_PACKET_SIZE << 1) + BGP_DUMP_MSG_HEADER
863 + BGP_DUMP_HEADER_SIZE);
718e3744 864
d62a17ae 865 install_node(&bgp_dump_node, config_write_bgp_dump);
718e3744 866
d62a17ae 867 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
868 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
584470fb
DL
869
870 hook_register(bgp_packet_dump, bgp_dump_packet);
7d8d0eab 871 hook_register(peer_status_changed, bgp_dump_state);
718e3744 872}
228da428 873
d62a17ae 874void bgp_dump_finish(void)
228da428 875{
d62a17ae 876 bgp_dump_unset(&bgp_dump_all);
877 bgp_dump_unset(&bgp_dump_updates);
878 bgp_dump_unset(&bgp_dump_routes);
b8438f6d 879
d62a17ae 880 stream_free(bgp_dump_obuf);
881 bgp_dump_obuf = NULL;
376d7c50 882 hook_unregister(bgp_packet_dump, bgp_dump_packet);
7d8d0eab 883 hook_unregister(peer_status_changed, bgp_dump_state);
228da428 884}