]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
*: remove second parameter on install_node()
[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;
a2700b50 109 struct tm tm;
d62a17ae 110 char fullpath[MAXPATHLEN];
111 char realpath[MAXPATHLEN];
112 mode_t oldumask;
113
114 time(&clock);
a2700b50 115 localtime_r(&clock, &tm);
d62a17ae 116
117 if (bgp_dump->filename[0] != DIRECTORY_SEP) {
118 sprintf(fullpath, "%s/%s", vty_get_cwd(), bgp_dump->filename);
a2700b50 119 ret = strftime(realpath, MAXPATHLEN, fullpath, &tm);
d62a17ae 120 } else
a2700b50 121 ret = strftime(realpath, MAXPATHLEN, bgp_dump->filename, &tm);
d62a17ae 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;
a2700b50 150 struct tm tm;
d62a17ae 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);
a2700b50
MS
161 localtime_r(&t, &tm);
162 secs_into_day = tm.tm_sec + 60 * tm.tm_min
163 + 60 * 60 * tm.tm_hour;
d62a17ae 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;
b54892e0 310 const struct prefix *p = bgp_node_get_prefix(rn);
d62a17ae 311
312 obuf = bgp_dump_obuf;
313 stream_reset(obuf);
314
315 /* MRT header */
316 if (afi == AFI_IP)
317 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
318 TABLE_DUMP_V2_RIB_IPV4_UNICAST,
319 BGP_DUMP_ROUTES);
320 else if (afi == AFI_IP6)
321 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
322 TABLE_DUMP_V2_RIB_IPV6_UNICAST,
323 BGP_DUMP_ROUTES);
324
325 /* Sequence number */
326 stream_putl(obuf, seq);
327
328 /* Prefix length */
b54892e0 329 stream_putc(obuf, p->prefixlen);
d62a17ae 330
331 /* Prefix */
332 if (afi == AFI_IP) {
333 /* We'll dump only the useful bits (those not 0), but have to
334 * align on 8 bits */
b54892e0
DS
335 stream_write(obuf, (uint8_t *)&p->u.prefix4,
336 (p->prefixlen + 7) / 8);
d62a17ae 337 } else if (afi == AFI_IP6) {
338 /* We'll dump only the useful bits (those not 0), but have to
339 * align on 8 bits */
b54892e0
DS
340 stream_write(obuf, (uint8_t *)&p->u.prefix6,
341 (p->prefixlen + 7) / 8);
d62a17ae 342 }
246556b5 343
d62a17ae 344 /* Save where we are now, so we can overwride the entry count later */
345 sizep = stream_get_endp(obuf);
246556b5 346
d62a17ae 347 /* Entry count */
348 uint16_t entry_count = 0;
246556b5 349
d62a17ae 350 /* Entry count, note that this is overwritten later */
351 stream_putw(obuf, 0);
246556b5 352
d62a17ae 353 endp = stream_get_endp(obuf);
40381db7 354 for (; path; path = path->next) {
d62a17ae 355 size_t cur_endp;
246556b5 356
d62a17ae 357 /* Peer index */
40381db7 358 stream_putw(obuf, path->peer->table_dump_index);
246556b5 359
d62a17ae 360 /* Originated */
40381db7 361 stream_putl(obuf, time(NULL) - (bgp_clock() - path->uptime));
246556b5 362
d62a17ae 363 /* Dump attribute. */
364 /* Skip prefix & AFI/SAFI for MP_NLRI */
b54892e0 365 bgp_dump_routes_attr(obuf, path->attr, p);
246556b5 366
d62a17ae 367 cur_endp = stream_get_endp(obuf);
368 if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
369 + BGP_DUMP_HEADER_SIZE) {
370 stream_set_endp(obuf, endp);
371 break;
372 }
246556b5 373
d62a17ae 374 entry_count++;
375 endp = cur_endp;
376 }
246556b5 377
d62a17ae 378 /* Overwrite the entry count, now that we know the right number */
379 stream_putw_at(obuf, sizep, entry_count);
246556b5 380
d62a17ae 381 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
382 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
246556b5 383
40381db7 384 return path;
246556b5
EU
385}
386
387
718e3744 388/* Runs under child process. */
d62a17ae 389static unsigned int bgp_dump_routes_func(int afi, int first_run,
390 unsigned int seq)
718e3744 391{
40381db7 392 struct bgp_path_info *path;
d62a17ae 393 struct bgp_node *rn;
394 struct bgp *bgp;
395 struct bgp_table *table;
396
397 bgp = bgp_get_default();
398 if (!bgp)
399 return seq;
400
401 if (bgp_dump_routes.fp == NULL)
402 return seq;
403
404 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
405 so this should only be done on the first call to
406 bgp_dump_routes_func.
407 ( this function will be called once for ipv4 and once for ipv6 ) */
408 if (first_run)
409 bgp_dump_routes_index_table(bgp);
410
411 /* Walk down each BGP route. */
412 table = bgp->rib[afi][SAFI_UNICAST];
413
414 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
6f94b685 415 path = bgp_node_get_bgp_path_info(rn);
40381db7
DS
416 while (path) {
417 path = bgp_dump_route_node_record(afi, rn, path, seq);
d62a17ae 418 seq++;
419 }
420 }
0b2aa3a0 421
d62a17ae 422 fflush(bgp_dump_routes.fp);
0b2aa3a0 423
d62a17ae 424 return seq;
718e3744 425}
426
d62a17ae 427static int bgp_dump_interval_func(struct thread *t)
718e3744 428{
d62a17ae 429 struct bgp_dump *bgp_dump;
430 bgp_dump = THREAD_ARG(t);
431 bgp_dump->t_interval = NULL;
432
433 /* Reschedule dump even if file couldn't be opened this time... */
434 if (bgp_dump_open_file(bgp_dump) != NULL) {
435 /* In case of bgp_dump_routes, we need special route dump
436 * function. */
437 if (bgp_dump->type == BGP_DUMP_ROUTES) {
438 unsigned int seq = bgp_dump_routes_func(AFI_IP, 1, 0);
439 bgp_dump_routes_func(AFI_IP6, 0, seq);
440 /* Close the file now. For a RIB dump there's no point
441 * in leaving
442 * it open until the next scheduled dump starts. */
443 fclose(bgp_dump->fp);
444 bgp_dump->fp = NULL;
445 }
9834cd0f 446 }
718e3744 447
d62a17ae 448 /* if interval is set reschedule */
449 if (bgp_dump->interval > 0)
450 bgp_dump_interval_add(bgp_dump, bgp_dump->interval);
fba3d22b 451
d62a17ae 452 return 0;
718e3744 453}
454
455/* Dump common information. */
d62a17ae 456static void bgp_dump_common(struct stream *obuf, struct peer *peer,
457 int forceas4)
718e3744 458{
d62a17ae 459 char empty[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
460
461 /* Source AS number and Destination AS number. */
462 if (forceas4 || CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
463 stream_putl(obuf, peer->as);
464 stream_putl(obuf, peer->local_as);
465 } else {
466 stream_putw(obuf, peer->as);
467 stream_putw(obuf, peer->local_as);
468 }
718e3744 469
d62a17ae 470 if (peer->su.sa.sa_family == AF_INET) {
194a4f2c 471 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
d62a17ae 472 stream_putw(obuf, AFI_IP);
473
474 stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
475
476 if (peer->su_local)
477 stream_put(obuf, &peer->su_local->sin.sin_addr,
478 IPV4_MAX_BYTELEN);
479 else
480 stream_put(obuf, empty, IPV4_MAX_BYTELEN);
481 } else if (peer->su.sa.sa_family == AF_INET6) {
482 /* Interface Index and Address family. */
194a4f2c 483 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
d62a17ae 484 stream_putw(obuf, AFI_IP6);
485
486 /* Source IP Address and Destination IP Address. */
487 stream_put(obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
488
489 if (peer->su_local)
490 stream_put(obuf, &peer->su_local->sin6.sin6_addr,
491 IPV6_MAX_BYTELEN);
492 else
493 stream_put(obuf, empty, IPV6_MAX_BYTELEN);
494 }
718e3744 495}
496
497/* Dump BGP status change. */
7d8d0eab 498int bgp_dump_state(struct peer *peer)
718e3744 499{
d62a17ae 500 struct stream *obuf;
718e3744 501
d62a17ae 502 /* If dump file pointer is disabled return immediately. */
503 if (bgp_dump_all.fp == NULL)
7d8d0eab 504 return 0;
718e3744 505
d62a17ae 506 /* Make dump stream. */
507 obuf = bgp_dump_obuf;
508 stream_reset(obuf);
718e3744 509
d62a17ae 510 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
511 bgp_dump_all.type);
512 bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/
718e3744 513
7d8d0eab
MKS
514 stream_putw(obuf, peer->ostatus);
515 stream_putw(obuf, peer->status);
718e3744 516
d62a17ae 517 /* Set length. */
518 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 519
d62a17ae 520 /* Write to the stream. */
521 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_all.fp);
522 fflush(bgp_dump_all.fp);
7d8d0eab 523 return 0;
718e3744 524}
525
d62a17ae 526static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
527 struct stream *packet)
718e3744 528{
d62a17ae 529 struct stream *obuf;
530
531 /* If dump file pointer is disabled return immediately. */
532 if (bgp_dump->fp == NULL)
533 return;
534
535 /* Make dump stream. */
536 obuf = bgp_dump_obuf;
537 stream_reset(obuf);
538
539 /* Dump header and common part. */
540 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
541 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
542 bgp_dump->type);
543 } else {
544 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
545 bgp_dump->type);
546 }
547 bgp_dump_common(obuf, peer, 0);
718e3744 548
d62a17ae 549 /* Packet contents. */
550 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
718e3744 551
d62a17ae 552 /* Set length. */
553 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 554
d62a17ae 555 /* Write to the stream. */
556 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
557 fflush(bgp_dump->fp);
718e3744 558}
559
560/* Called from bgp_packet.c when BGP packet is received. */
584470fb
DL
561static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
562 struct stream *packet)
718e3744 563{
d62a17ae 564 /* bgp_dump_all. */
565 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
718e3744 566
d62a17ae 567 /* bgp_dump_updates. */
568 if (type == BGP_MSG_UPDATE)
569 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
584470fb 570 return 0;
718e3744 571}
6b0655a2 572
d62a17ae 573static unsigned int bgp_dump_parse_time(const char *str)
718e3744 574{
d62a17ae 575 int i;
576 int len;
577 int seen_h;
578 int seen_m;
579 int time;
580 unsigned int total;
581
582 time = 0;
583 total = 0;
584 seen_h = 0;
585 seen_m = 0;
586 len = strlen(str);
587
588 for (i = 0; i < len; i++) {
fefa5e0f 589 if (isdigit((unsigned char)str[i])) {
d62a17ae 590 time *= 10;
591 time += str[i] - '0';
592 } else if (str[i] == 'H' || str[i] == 'h') {
593 if (seen_h)
594 return 0;
595 if (seen_m)
596 return 0;
597 total += time * 60 * 60;
598 time = 0;
599 seen_h = 1;
600 } else if (str[i] == 'M' || str[i] == 'm') {
601 if (seen_m)
602 return 0;
603 total += time * 60;
604 time = 0;
605 seen_m = 1;
606 } else
607 return 0;
718e3744 608 }
d62a17ae 609 return total + time;
718e3744 610}
611
d62a17ae 612static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
613 enum bgp_dump_type type, const char *path,
614 const char *interval_str)
718e3744 615{
d62a17ae 616 unsigned int interval;
617
618 /* Don't schedule duplicate dumps if the dump command is given twice */
619 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
620 && type == bgp_dump->type) {
621 if (interval_str) {
622 if (bgp_dump->interval_str
623 && strcmp(bgp_dump->interval_str, interval_str)
624 == 0)
625 return CMD_SUCCESS;
626 } else {
627 if (!bgp_dump->interval_str)
628 return CMD_SUCCESS;
629 }
718e3744 630 }
45ad592e 631
d62a17ae 632 /* Removing previous config */
633 bgp_dump_unset(bgp_dump);
634
635 if (interval_str) {
636 /* Check interval string. */
637 interval = bgp_dump_parse_time(interval_str);
638 if (interval == 0) {
639 vty_out(vty, "Malformed interval string\n");
640 return CMD_WARNING_CONFIG_FAILED;
641 }
642
643 /* Setting interval string */
644 bgp_dump->interval_str =
645 XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
646 } else {
647 interval = 0;
648 }
718e3744 649
d62a17ae 650 /* Set type. */
651 bgp_dump->type = type;
718e3744 652
d62a17ae 653 /* Set interval */
654 bgp_dump->interval = interval;
4db5d90a 655
d62a17ae 656 /* Set file name. */
657 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
4db5d90a 658
d62a17ae 659 /* Create interval thread. */
660 bgp_dump_interval_add(bgp_dump, interval);
718e3744 661
d62a17ae 662 /* This should be called when interval is expired. */
663 bgp_dump_open_file(bgp_dump);
718e3744 664
d62a17ae 665 return CMD_SUCCESS;
718e3744 666}
667
d62a17ae 668static int bgp_dump_unset(struct bgp_dump *bgp_dump)
718e3744 669{
d62a17ae 670 /* Removing file name. */
e1b36e13 671 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
718e3744 672
d62a17ae 673 /* Closing file. */
674 if (bgp_dump->fp) {
675 fclose(bgp_dump->fp);
676 bgp_dump->fp = NULL;
677 }
718e3744 678
d62a17ae 679 /* Removing interval thread. */
680 if (bgp_dump->t_interval) {
681 thread_cancel(bgp_dump->t_interval);
682 bgp_dump->t_interval = NULL;
683 }
718e3744 684
d62a17ae 685 bgp_dump->interval = 0;
718e3744 686
d62a17ae 687 /* Removing interval string. */
e1b36e13 688 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
d62a17ae 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
612c2c15 780static int config_write_bgp_dump(struct vty *vty);
718e3744 781/* BGP node structure. */
62b346ee
DL
782static struct cmd_node bgp_dump_node = {
783 .node = DUMP_NODE,
784 .prompt = "",
612c2c15 785 .config_write = config_write_bgp_dump,
62b346ee 786};
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
612c2c15 865 install_node(&bgp_dump_node);
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}