]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
tools: argv_translator convert <1-255> to (1-255), ()s to <>s, etc
[mirror_frr.git] / bgpd / bgp_dump.c
CommitLineData
718e3744 1/* BGP-4 dump routine
2 Copyright (C) 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "log.h"
24#include "stream.h"
25#include "sockunion.h"
26#include "command.h"
27#include "prefix.h"
28#include "thread.h"
0b2aa3a0 29#include "linklist.h"
3f9c7369 30#include "queue.h"
6e919709 31#include "memory.h"
039f3a34 32#include "filter.h"
3f9c7369 33
718e3744 34#include "bgpd/bgp_table.h"
718e3744 35#include "bgpd/bgpd.h"
36#include "bgpd/bgp_route.h"
37#include "bgpd/bgp_attr.h"
38#include "bgpd/bgp_dump.h"
6b0655a2 39
718e3744 40enum bgp_dump_type
41{
42 BGP_DUMP_ALL,
4db5d90a 43 BGP_DUMP_ALL_ET,
718e3744 44 BGP_DUMP_UPDATES,
4db5d90a 45 BGP_DUMP_UPDATES_ET,
718e3744 46 BGP_DUMP_ROUTES
47};
48
4db5d90a
AF
49static const struct bgp_dump_type_map {
50 enum bgp_dump_type type;
51 const char *str;
52} bgp_dump_type_map[] =
53 {
54 {BGP_DUMP_ALL, "all"},
55 {BGP_DUMP_ALL_ET, "all-et"},
56 {BGP_DUMP_UPDATES, "updates"},
57 {BGP_DUMP_UPDATES_ET, "updates-et"},
58 {BGP_DUMP_ROUTES, "routes-mrt"},
59 {0, NULL},
60 };
61
718e3744 62enum MRT_MSG_TYPES {
63 MSG_NULL,
64 MSG_START, /* sender is starting up */
65 MSG_DIE, /* receiver should shut down */
66 MSG_I_AM_DEAD, /* sender is shutting down */
67 MSG_PEER_DOWN, /* sender's peer is down */
68 MSG_PROTOCOL_BGP, /* msg is a BGP packet */
69 MSG_PROTOCOL_RIP, /* msg is a RIP packet */
70 MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */
71 MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */
72 MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */
73 MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
74 MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */
0b2aa3a0
PJ
75 MSG_TABLE_DUMP, /* routing table dump */
76 MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */
718e3744 77};
78
79struct bgp_dump
80{
81 enum bgp_dump_type type;
82
83 char *filename;
84
85 FILE *fp;
86
87 unsigned int interval;
88
89 char *interval_str;
90
91 struct thread *t_interval;
92};
93
4db5d90a
AF
94static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump);
95static int bgp_dump_interval_func (struct thread *);
96
718e3744 97/* BGP packet dump output buffer. */
98struct stream *bgp_dump_obuf;
99
100/* BGP dump strucuture for 'dump bgp all' */
101struct bgp_dump bgp_dump_all;
102
103/* BGP dump structure for 'dump bgp updates' */
104struct bgp_dump bgp_dump_updates;
105
106/* BGP dump structure for 'dump bgp routes' */
107struct bgp_dump bgp_dump_routes;
108
94f2b392 109static FILE *
718e3744 110bgp_dump_open_file (struct bgp_dump *bgp_dump)
111{
112 int ret;
113 time_t clock;
114 struct tm *tm;
115 char fullpath[MAXPATHLEN];
116 char realpath[MAXPATHLEN];
aa593d5e 117 mode_t oldumask;
718e3744 118
119 time (&clock);
120 tm = localtime (&clock);
121
122 if (bgp_dump->filename[0] != DIRECTORY_SEP)
123 {
124 sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
125 ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
126 }
127 else
128 ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
129
130 if (ret == 0)
131 {
132 zlog_warn ("bgp_dump_open_file: strftime error");
133 return NULL;
134 }
135
136 if (bgp_dump->fp)
137 fclose (bgp_dump->fp);
138
139
aa593d5e 140 oldumask = umask(0777 & ~LOGFILE_MASK);
718e3744 141 bgp_dump->fp = fopen (realpath, "w");
142
143 if (bgp_dump->fp == NULL)
aa593d5e 144 {
45ad592e 145 zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno));
aa593d5e 146 umask(oldumask);
147 return NULL;
148 }
149 umask(oldumask);
718e3744 150
151 return bgp_dump->fp;
152}
153
94f2b392 154static int
718e3744 155bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
156{
45ad592e 157 int secs_into_day;
9834cd0f 158 time_t t;
159 struct tm *tm;
718e3744 160
45ad592e 161 if (interval > 0)
9834cd0f 162 {
45ad592e 163 /* Periodic dump every interval seconds */
9834cd0f 164 if ((interval < 86400) && ((86400 % interval) == 0))
165 {
45ad592e
PJ
166 /* Dump at predictable times: if a day has a whole number of
167 * intervals, dump every interval seconds starting from midnight
168 */
9834cd0f 169 (void) time(&t);
170 tm = localtime(&t);
171 secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour;
45ad592e 172 interval = interval - secs_into_day % interval; /* always > 0 */
9834cd0f 173 }
9229d914 174 bgp_dump->t_interval = thread_add_timer (bm->master, bgp_dump_interval_func,
45ad592e 175 bgp_dump, interval);
9834cd0f 176 }
fba3d22b 177 else
9834cd0f 178 {
45ad592e 179 /* One-off dump: execute immediately, don't affect any scheduled dumps */
9229d914 180 bgp_dump->t_interval = thread_add_event (bm->master, bgp_dump_interval_func,
9834cd0f 181 bgp_dump, 0);
182 }
fba3d22b 183
718e3744 184 return 0;
185}
186
187/* Dump common header. */
94f2b392 188static void
4db5d90a 189bgp_dump_header (struct stream *obuf, int type, int subtype, int dump_type)
718e3744 190{
4db5d90a
AF
191 struct timeval clock;
192 long msecs;
193 time_t secs;
194
195 if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET)
196 && type == MSG_PROTOCOL_BGP4MP)
197 type = MSG_PROTOCOL_BGP4MP_ET;
198
199 gettimeofday(&clock, NULL);
718e3744 200
4db5d90a
AF
201 secs = clock.tv_sec;
202 msecs = clock.tv_usec;
718e3744 203
204 /* Put dump packet header. */
4db5d90a 205 stream_putl (obuf, secs);
718e3744 206 stream_putw (obuf, type);
207 stream_putw (obuf, subtype);
718e3744 208 stream_putl (obuf, 0); /* len */
4db5d90a
AF
209
210 /* Adding microseconds for the MRT Extended Header */
211 if (type == MSG_PROTOCOL_BGP4MP_ET)
212 stream_putl (obuf, msecs);
718e3744 213}
214
94f2b392 215static void
718e3744 216bgp_dump_set_size (struct stream *s, int type)
217{
4db5d90a
AF
218 /*
219 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
220 * "The Microsecond Timestamp is included in the computation
221 * of the Length field value." (RFC6396 2011)
222 */
9985f83c 223 stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
718e3744 224}
225
94f2b392 226static void
0b2aa3a0 227bgp_dump_routes_index_table(struct bgp *bgp)
718e3744 228{
718e3744 229 struct peer *peer;
0b2aa3a0
PJ
230 struct listnode *node;
231 uint16_t peerno = 0;
232 struct stream *obuf;
718e3744 233
718e3744 234 obuf = bgp_dump_obuf;
235 stream_reset (obuf);
236
0b2aa3a0 237 /* MRT header */
4db5d90a
AF
238 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE,
239 BGP_DUMP_ROUTES);
718e3744 240
0b2aa3a0
PJ
241 /* Collector BGP ID */
242 stream_put_in_addr (obuf, &bgp->router_id);
243
244 /* View name */
245 if(bgp->name)
718e3744 246 {
0b2aa3a0
PJ
247 stream_putw (obuf, strlen(bgp->name));
248 stream_put(obuf, bgp->name, strlen(bgp->name));
718e3744 249 }
250 else
251 {
0b2aa3a0 252 stream_putw(obuf, 0);
718e3744 253 }
254
0b2aa3a0
PJ
255 /* Peer count */
256 stream_putw (obuf, listcount(bgp->peer));
718e3744 257
0b2aa3a0
PJ
258 /* Walk down all peers */
259 for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
718e3744 260 {
718e3744 261
0b2aa3a0
PJ
262 /* Peer's type */
263 if (sockunion_family(&peer->su) == AF_INET)
264 {
265 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
266 }
0b2aa3a0
PJ
267 else if (sockunion_family(&peer->su) == AF_INET6)
268 {
269 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
270 }
718e3744 271
0b2aa3a0
PJ
272 /* Peer's BGP ID */
273 stream_put_in_addr (obuf, &peer->remote_id);
718e3744 274
0b2aa3a0
PJ
275 /* Peer's IP address */
276 if (sockunion_family(&peer->su) == AF_INET)
277 {
278 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
279 }
0b2aa3a0
PJ
280 else if (sockunion_family(&peer->su) == AF_INET6)
281 {
282 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
283 IPV6_MAX_BYTELEN);
284 }
718e3744 285
0b2aa3a0
PJ
286 /* Peer's AS number. */
287 /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
288 stream_putl (obuf, peer->as);
718e3744 289
0b2aa3a0
PJ
290 /* Store the peer number for this peer */
291 peer->table_dump_index = peerno;
292 peerno++;
718e3744 293 }
718e3744 294
0b2aa3a0 295 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
718e3744 296
a6694fe8 297 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
718e3744 298 fflush (bgp_dump_routes.fp);
299}
300
0b2aa3a0 301
246556b5
EU
302static struct bgp_info *
303bgp_dump_route_node_record (int afi, struct bgp_node *rn,
304 struct bgp_info *info, unsigned int seq)
305{
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, TABLE_DUMP_V2_RIB_IPV4_UNICAST,
316 BGP_DUMP_ROUTES);
317 else if (afi == AFI_IP6)
318 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST,
319 BGP_DUMP_ROUTES);
320
321 /* Sequence number */
322 stream_putl (obuf, seq);
323
324 /* Prefix length */
325 stream_putc (obuf, rn->p.prefixlen);
326
327 /* Prefix */
328 if (afi == AFI_IP)
329 {
330 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
331 stream_write (obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
332 }
333 else if (afi == AFI_IP6)
334 {
335 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
336 stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
337 }
338
339 /* Save where we are now, so we can overwride the entry count later */
340 sizep = stream_get_endp (obuf);
341
342 /* Entry count */
343 uint16_t entry_count = 0;
344
345 /* Entry count, note that this is overwritten later */
346 stream_putw (obuf, 0);
347
348 endp = stream_get_endp (obuf);
349 for (; info; info = info->next)
350 {
351 size_t cur_endp;
352
353 /* Peer index */
354 stream_putw (obuf, info->peer->table_dump_index);
355
356 /* Originated */
357#ifdef HAVE_CLOCK_MONOTONIC
358 stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
359#else
360 stream_putl (obuf, info->uptime);
361#endif /* HAVE_CLOCK_MONOTONIC */
362
363 /* Dump attribute. */
364 /* Skip prefix & AFI/SAFI for MP_NLRI */
365 bgp_dump_routes_attr (obuf, info->attr, &rn->p);
366
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 {
371 stream_set_endp (obuf, endp);
372 break;
373 }
374
375 entry_count++;
376 endp = cur_endp;
377 }
378
379 /* Overwrite the entry count, now that we know the right number */
380 stream_putw_at (obuf, sizep, entry_count);
381
382 bgp_dump_set_size (obuf, MSG_TABLE_DUMP_V2);
383 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
384
385 return info;
386}
387
388
718e3744 389/* Runs under child process. */
0b2aa3a0
PJ
390static unsigned int
391bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
718e3744 392{
718e3744 393 struct bgp_info *info;
0b2aa3a0 394 struct bgp_node *rn;
718e3744 395 struct bgp *bgp;
396 struct bgp_table *table;
718e3744 397
398 bgp = bgp_get_default ();
399 if (!bgp)
0b2aa3a0 400 return seq;
718e3744 401
402 if (bgp_dump_routes.fp == NULL)
0b2aa3a0
PJ
403 return seq;
404
405 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
406 so this should only be done on the first call to bgp_dump_routes_func.
407 ( this function will be called once for ipv4 and once for ipv6 ) */
246556b5 408 if (first_run)
0b2aa3a0
PJ
409 bgp_dump_routes_index_table(bgp);
410
718e3744 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))
0b2aa3a0 415 {
246556b5
EU
416 info = rn->info;
417 while (info)
418 {
419 info = bgp_dump_route_node_record (afi, rn, info, seq);
420 seq++;
421 }
0b2aa3a0
PJ
422 }
423
424 fflush (bgp_dump_routes.fp);
425
426 return seq;
718e3744 427}
428
94f2b392 429static int
718e3744 430bgp_dump_interval_func (struct thread *t)
431{
432 struct bgp_dump *bgp_dump;
718e3744 433 bgp_dump = THREAD_ARG (t);
434 bgp_dump->t_interval = NULL;
435
9834cd0f 436 /* Reschedule dump even if file couldn't be opened this time... */
437 if (bgp_dump_open_file (bgp_dump) != NULL)
718e3744 438 {
9834cd0f 439 /* In case of bgp_dump_routes, we need special route dump function. */
440 if (bgp_dump->type == BGP_DUMP_ROUTES)
441 {
0b2aa3a0 442 unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
0b2aa3a0 443 bgp_dump_routes_func (AFI_IP6, 0, seq);
9834cd0f 444 /* Close the file now. For a RIB dump there's no point in leaving
445 * it open until the next scheduled dump starts. */
446 fclose(bgp_dump->fp); bgp_dump->fp = NULL;
447 }
718e3744 448 }
449
fba3d22b 450 /* if interval is set reschedule */
451 if (bgp_dump->interval > 0)
452 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
453
718e3744 454 return 0;
455}
456
457/* Dump common information. */
94f2b392 458static void
0b2aa3a0 459bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
718e3744 460{
461 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
462
463 /* Source AS number and Destination AS number. */
0b2aa3a0
PJ
464 if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
465 {
466 stream_putl (obuf, peer->as);
467 stream_putl (obuf, peer->local_as);
468 }
469 else
470 {
471 stream_putw (obuf, peer->as);
472 stream_putw (obuf, peer->local_as);
473 }
718e3744 474
a384592f 475 if (peer->su.sa.sa_family == AF_INET)
718e3744 476 {
477 stream_putw (obuf, peer->ifindex);
478 stream_putw (obuf, AFI_IP);
479
480 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
481
482 if (peer->su_local)
483 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
484 else
485 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
486 }
a384592f 487 else if (peer->su.sa.sa_family == AF_INET6)
718e3744 488 {
489 /* Interface Index and Address family. */
490 stream_putw (obuf, peer->ifindex);
491 stream_putw (obuf, AFI_IP6);
492
493 /* Source IP Address and Destination IP Address. */
494 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
495
496 if (peer->su_local)
497 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
498 else
499 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
500 }
718e3744 501}
502
503/* Dump BGP status change. */
504void
505bgp_dump_state (struct peer *peer, int status_old, int status_new)
506{
507 struct stream *obuf;
508
509 /* If dump file pointer is disabled return immediately. */
510 if (bgp_dump_all.fp == NULL)
511 return;
512
513 /* Make dump stream. */
514 obuf = bgp_dump_obuf;
515 stream_reset (obuf);
516
4db5d90a
AF
517 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
518 bgp_dump_all.type);
0b2aa3a0 519 bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
718e3744 520
521 stream_putw (obuf, status_old);
522 stream_putw (obuf, status_new);
523
524 /* Set length. */
525 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
526
527 /* Write to the stream. */
a6694fe8 528 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
718e3744 529 fflush (bgp_dump_all.fp);
530}
531
94f2b392 532static void
718e3744 533bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
534 struct stream *packet)
535{
536 struct stream *obuf;
537
538 /* If dump file pointer is disabled return immediately. */
539 if (bgp_dump->fp == NULL)
540 return;
541
542 /* Make dump stream. */
543 obuf = bgp_dump_obuf;
544 stream_reset (obuf);
545
546 /* Dump header and common part. */
0b2aa3a0
PJ
547 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
548 {
4db5d90a
AF
549 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
550 bgp_dump->type);
0b2aa3a0
PJ
551 }
552 else
553 {
4db5d90a
AF
554 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
555 bgp_dump->type);
0b2aa3a0
PJ
556 }
557 bgp_dump_common (obuf, peer, 0);
718e3744 558
559 /* Packet contents. */
560 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
561
562 /* Set length. */
563 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
564
565 /* Write to the stream. */
a6694fe8 566 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
718e3744 567 fflush (bgp_dump->fp);
568}
569
570/* Called from bgp_packet.c when BGP packet is received. */
571void
572bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
573{
574 /* bgp_dump_all. */
575 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
576
577 /* bgp_dump_updates. */
578 if (type == BGP_MSG_UPDATE)
579 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
580}
6b0655a2 581
94f2b392 582static unsigned int
fd79ac91 583bgp_dump_parse_time (const char *str)
718e3744 584{
585 int i;
586 int len;
587 int seen_h;
588 int seen_m;
589 int time;
590 unsigned int total;
591
592 time = 0;
593 total = 0;
594 seen_h = 0;
595 seen_m = 0;
596 len = strlen (str);
597
598 for (i = 0; i < len; i++)
599 {
600 if (isdigit ((int) str[i]))
601 {
602 time *= 10;
603 time += str[i] - '0';
604 }
605 else if (str[i] == 'H' || str[i] == 'h')
606 {
607 if (seen_h)
608 return 0;
609 if (seen_m)
610 return 0;
611 total += time * 60 *60;
612 time = 0;
613 seen_h = 1;
614 }
615 else if (str[i] == 'M' || str[i] == 'm')
616 {
617 if (seen_m)
618 return 0;
619 total += time * 60;
620 time = 0;
621 seen_h = 1;
622 }
623 else
624 return 0;
625 }
626 return total + time;
627}
628
94f2b392 629static int
45ad592e
PJ
630bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
631 enum bgp_dump_type type, const char *path,
632 const char *interval_str)
718e3744 633{
fba3d22b 634 unsigned int interval;
635
4db5d90a
AF
636 /* Don't schedule duplicate dumps if the dump command is given twice */
637 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
638 && type == bgp_dump->type)
639 {
640 if (interval_str)
641 {
642 if (bgp_dump->interval_str &&
643 strcmp(bgp_dump->interval_str, interval_str) == 0)
644 return CMD_SUCCESS;
645 }
646 else
647 {
648 if (!bgp_dump->interval_str)
649 return CMD_SUCCESS;
650 }
651 }
652
653 /* Removing previous config */
654 bgp_dump_unset(vty, bgp_dump);
655
718e3744 656 if (interval_str)
657 {
718e3744 658 /* Check interval string. */
659 interval = bgp_dump_parse_time (interval_str);
660 if (interval == 0)
661 {
662 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
663 return CMD_WARNING;
664 }
45ad592e 665
4db5d90a 666 /* Setting interval string */
6e919709 667 bgp_dump->interval_str = XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
718e3744 668 }
fba3d22b 669 else
670 {
671 interval = 0;
672 }
718e3744 673
674 /* Set type. */
675 bgp_dump->type = type;
676
4db5d90a
AF
677 /* Set interval */
678 bgp_dump->interval = interval;
679
718e3744 680 /* Set file name. */
4db5d90a
AF
681 bgp_dump->filename = XSTRDUP (MTYPE_BGP_DUMP_STR, path);
682
683 /* Create interval thread. */
684 bgp_dump_interval_add (bgp_dump, interval);
718e3744 685
686 /* This should be called when interval is expired. */
687 bgp_dump_open_file (bgp_dump);
688
689 return CMD_SUCCESS;
690}
691
94f2b392 692static int
718e3744 693bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
694{
4db5d90a 695 /* Removing file name. */
718e3744 696 if (bgp_dump->filename)
697 {
6e919709 698 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
718e3744 699 bgp_dump->filename = NULL;
700 }
701
4db5d90a 702 /* Closing file. */
718e3744 703 if (bgp_dump->fp)
704 {
705 fclose (bgp_dump->fp);
706 bgp_dump->fp = NULL;
707 }
708
4db5d90a 709 /* Removing interval thread. */
718e3744 710 if (bgp_dump->t_interval)
711 {
712 thread_cancel (bgp_dump->t_interval);
713 bgp_dump->t_interval = NULL;
714 }
715
716 bgp_dump->interval = 0;
717
4db5d90a 718 /* Removing interval string. */
718e3744 719 if (bgp_dump->interval_str)
720 {
6e919709 721 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
718e3744 722 bgp_dump->interval_str = NULL;
723 }
724
718e3744 725 return CMD_SUCCESS;
726}
727
728DEFUN (dump_bgp_all,
729 dump_bgp_all_cmd,
4db5d90a 730 "dump bgp (all|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]",
718e3744 731 "Dump packet\n"
732 "BGP packet dump\n"
cbac2b1b
EU
733 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
734 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
4db5d90a 735 "Dump whole BGP routing table\n"
718e3744 736 "Output filename\n"
737 "Interval of output\n")
738{
4db5d90a
AF
739 int bgp_dump_type = 0;
740 const char *interval = NULL;
741 struct bgp_dump *bgp_dump_struct = NULL;
742 const struct bgp_dump_type_map *map = NULL;
718e3744 743
4db5d90a 744 for (map = bgp_dump_type_map; map->str; map++)
4dcadbef 745 if (strcmp(argv[2]->arg, map->str) == 0)
4db5d90a 746 bgp_dump_type = map->type;
718e3744 747
4db5d90a
AF
748 switch (bgp_dump_type)
749 {
750 case BGP_DUMP_ALL:
751 case BGP_DUMP_ALL_ET:
752 bgp_dump_struct = &bgp_dump_all;
753 break;
754 case BGP_DUMP_UPDATES:
755 case BGP_DUMP_UPDATES_ET:
756 bgp_dump_struct = &bgp_dump_updates;
757 break;
758 case BGP_DUMP_ROUTES:
759 default:
760 bgp_dump_struct = &bgp_dump_routes;
761 break;
762 }
718e3744 763
4db5d90a
AF
764 /* When an interval is given */
765 if (argc == 3)
4dcadbef 766 interval = argv[4]->arg;
718e3744 767
4db5d90a 768 return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type,
4dcadbef 769 argv[3]->arg, interval);
718e3744 770}
771
4db5d90a
AF
772DEFUN (no_dump_bgp_all,
773 no_dump_bgp_all_cmd,
ca492402 774 "no dump bgp (all|all-et|updates|updates-et|routes-mrt) [PATH] [INTERVAL]",
718e3744 775 NO_STR
4db5d90a
AF
776 "Stop dump packet\n"
777 "Stop BGP packet dump\n"
ca492402
DS
778 "Stop dump process all\n"
779 "Stop dump process all-et\n"
780 "Stop dump process updates\n"
781 "Stop dump process updates-et\n"
4db5d90a 782 "Stop dump process route-mrt\n")
718e3744 783{
ca492402
DS
784 int bgp_dump_type = 0;
785 const struct bgp_dump_type_map *map = NULL;
786 struct bgp_dump *bgp_dump_struct = NULL;
787
788 for (map = bgp_dump_type_map; map->str; map++)
4dcadbef 789 if (strcmp(argv[3]->arg, map->str) == 0)
ca492402
DS
790 bgp_dump_type = map->type;
791
792 switch (bgp_dump_type)
793 {
794 case BGP_DUMP_ALL:
795 case BGP_DUMP_ALL_ET:
796 bgp_dump_struct = &bgp_dump_all;
797 break;
798 case BGP_DUMP_UPDATES:
799 case BGP_DUMP_UPDATES_ET:
800 bgp_dump_struct = &bgp_dump_updates;
801 break;
802 case BGP_DUMP_ROUTES:
803 default:
804 bgp_dump_struct = &bgp_dump_routes;
805 break;
806 }
807
808 return bgp_dump_unset (vty, bgp_dump_struct);
718e3744 809}
810
811/* BGP node structure. */
7fc626de 812static struct cmd_node bgp_dump_node =
718e3744 813{
814 DUMP_NODE,
815 "",
501ba490 816 1
718e3744 817};
818
819#if 0
820char *
821config_time2str (unsigned int interval)
822{
823 static char buf[BUFSIZ];
824
825 buf[0] = '\0';
826
827 if (interval / 3600)
828 {
829 sprintf (buf, "%dh", interval / 3600);
830 interval %= 3600;
831 }
832 if (interval / 60)
833 {
834 sprintf (buf + strlen (buf), "%dm", interval /60);
835 interval %= 60;
836 }
837 if (interval)
838 {
839 sprintf (buf + strlen (buf), "%d", interval);
840 }
841 return buf;
842}
843#endif
844
94f2b392 845static int
718e3744 846config_write_bgp_dump (struct vty *vty)
847{
848 if (bgp_dump_all.filename)
849 {
4db5d90a
AF
850 const char *type_str = "all";
851 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
852 type_str = "all-et";
853
718e3744 854 if (bgp_dump_all.interval_str)
4db5d90a 855 vty_out (vty, "dump bgp %s %s %s%s", type_str,
718e3744 856 bgp_dump_all.filename, bgp_dump_all.interval_str,
857 VTY_NEWLINE);
858 else
4db5d90a 859 vty_out (vty, "dump bgp %s %s%s", type_str,
718e3744 860 bgp_dump_all.filename, VTY_NEWLINE);
861 }
862 if (bgp_dump_updates.filename)
863 {
4db5d90a
AF
864 const char *type_str = "updates";
865 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
866 type_str = "updates-et";
867
718e3744 868 if (bgp_dump_updates.interval_str)
4db5d90a 869 vty_out (vty, "dump bgp %s %s %s%s", type_str,
718e3744 870 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
871 VTY_NEWLINE);
872 else
873 vty_out (vty, "dump bgp updates %s%s",
874 bgp_dump_updates.filename, VTY_NEWLINE);
875 }
876 if (bgp_dump_routes.filename)
877 {
878 if (bgp_dump_routes.interval_str)
879 vty_out (vty, "dump bgp routes-mrt %s %s%s",
880 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
881 VTY_NEWLINE);
718e3744 882 }
883 return 0;
884}
6b0655a2 885
718e3744 886/* Initialize BGP packet dump functionality. */
887void
94f2b392 888bgp_dump_init (void)
718e3744 889{
890 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
891 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
892 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
893
246556b5
EU
894 bgp_dump_obuf = stream_new ((BGP_MAX_PACKET_SIZE << 1)
895 + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
718e3744 896
897 install_node (&bgp_dump_node, config_write_bgp_dump);
898
899 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
718e3744 900 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
718e3744 901}
228da428
CC
902
903void
904bgp_dump_finish (void)
905{
906 stream_free (bgp_dump_obuf);
907 bgp_dump_obuf = NULL;
908}