]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
*: add indent control files
[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"
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
b8438f6d 94static int bgp_dump_unset (struct bgp_dump *bgp_dump);
4db5d90a
AF
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 }
66e78ae6
QY
174 bgp_dump->t_interval = NULL;
175 thread_add_timer(bm->master, bgp_dump_interval_func, bgp_dump, interval,
176 &bgp_dump->t_interval);
9834cd0f 177 }
fba3d22b 178 else
9834cd0f 179 {
45ad592e 180 /* One-off dump: execute immediately, don't affect any scheduled dumps */
66e78ae6
QY
181 bgp_dump->t_interval = NULL;
182 thread_add_event(bm->master, bgp_dump_interval_func, bgp_dump, 0,
183 &bgp_dump->t_interval);
9834cd0f 184 }
fba3d22b 185
718e3744 186 return 0;
187}
188
189/* Dump common header. */
94f2b392 190static void
4db5d90a 191bgp_dump_header (struct stream *obuf, int type, int subtype, int dump_type)
718e3744 192{
4db5d90a
AF
193 struct timeval clock;
194 long msecs;
195 time_t secs;
196
197 if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET)
198 && type == MSG_PROTOCOL_BGP4MP)
199 type = MSG_PROTOCOL_BGP4MP_ET;
200
201 gettimeofday(&clock, NULL);
718e3744 202
4db5d90a
AF
203 secs = clock.tv_sec;
204 msecs = clock.tv_usec;
718e3744 205
206 /* Put dump packet header. */
4db5d90a 207 stream_putl (obuf, secs);
718e3744 208 stream_putw (obuf, type);
209 stream_putw (obuf, subtype);
718e3744 210 stream_putl (obuf, 0); /* len */
4db5d90a
AF
211
212 /* Adding microseconds for the MRT Extended Header */
213 if (type == MSG_PROTOCOL_BGP4MP_ET)
214 stream_putl (obuf, msecs);
718e3744 215}
216
94f2b392 217static void
718e3744 218bgp_dump_set_size (struct stream *s, int type)
219{
4db5d90a
AF
220 /*
221 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
222 * "The Microsecond Timestamp is included in the computation
223 * of the Length field value." (RFC6396 2011)
224 */
9985f83c 225 stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
718e3744 226}
227
94f2b392 228static void
0b2aa3a0 229bgp_dump_routes_index_table(struct bgp *bgp)
718e3744 230{
718e3744 231 struct peer *peer;
0b2aa3a0 232 struct listnode *node;
0df81134 233 uint16_t peerno = 1;
0b2aa3a0 234 struct stream *obuf;
718e3744 235
718e3744 236 obuf = bgp_dump_obuf;
237 stream_reset (obuf);
238
0b2aa3a0 239 /* MRT header */
4db5d90a
AF
240 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE,
241 BGP_DUMP_ROUTES);
718e3744 242
0b2aa3a0
PJ
243 /* Collector BGP ID */
244 stream_put_in_addr (obuf, &bgp->router_id);
245
246 /* View name */
247 if(bgp->name)
718e3744 248 {
0b2aa3a0
PJ
249 stream_putw (obuf, strlen(bgp->name));
250 stream_put(obuf, bgp->name, strlen(bgp->name));
718e3744 251 }
252 else
253 {
0b2aa3a0 254 stream_putw(obuf, 0);
718e3744 255 }
256
0df81134
CP
257 /* Peer count ( plus one extra internal peer ) */
258 stream_putw (obuf, listcount(bgp->peer) + 1);
259
260 /* Populate fake peer at index 0, for locally originated routes */
261 /* Peer type (IPv4) */
262 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
263 /* Peer BGP ID (0.0.0.0) */
264 stream_putl (obuf, 0);
265 /* Peer IP address (0.0.0.0) */
266 stream_putl (obuf, 0);
267 /* Peer ASN (0) */
268 stream_putl (obuf, 0);
718e3744 269
0b2aa3a0
PJ
270 /* Walk down all peers */
271 for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
718e3744 272 {
718e3744 273
0b2aa3a0
PJ
274 /* Peer's type */
275 if (sockunion_family(&peer->su) == AF_INET)
276 {
277 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
278 }
0b2aa3a0
PJ
279 else if (sockunion_family(&peer->su) == AF_INET6)
280 {
281 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
282 }
718e3744 283
0b2aa3a0
PJ
284 /* Peer's BGP ID */
285 stream_put_in_addr (obuf, &peer->remote_id);
718e3744 286
0b2aa3a0
PJ
287 /* Peer's IP address */
288 if (sockunion_family(&peer->su) == AF_INET)
289 {
290 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
291 }
0b2aa3a0
PJ
292 else if (sockunion_family(&peer->su) == AF_INET6)
293 {
294 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
295 IPV6_MAX_BYTELEN);
296 }
718e3744 297
0b2aa3a0
PJ
298 /* Peer's AS number. */
299 /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
300 stream_putl (obuf, peer->as);
718e3744 301
0b2aa3a0
PJ
302 /* Store the peer number for this peer */
303 peer->table_dump_index = peerno;
304 peerno++;
718e3744 305 }
718e3744 306
0b2aa3a0 307 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
718e3744 308
a6694fe8 309 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
718e3744 310 fflush (bgp_dump_routes.fp);
311}
312
0b2aa3a0 313
246556b5
EU
314static struct bgp_info *
315bgp_dump_route_node_record (int afi, struct bgp_node *rn,
316 struct bgp_info *info, unsigned int seq)
317{
318 struct stream *obuf;
319 size_t sizep;
320 size_t endp;
321
322 obuf = bgp_dump_obuf;
323 stream_reset (obuf);
324
325 /* MRT header */
326 if (afi == AFI_IP)
327 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST,
328 BGP_DUMP_ROUTES);
329 else if (afi == AFI_IP6)
330 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST,
331 BGP_DUMP_ROUTES);
332
333 /* Sequence number */
334 stream_putl (obuf, seq);
335
336 /* Prefix length */
337 stream_putc (obuf, rn->p.prefixlen);
338
339 /* Prefix */
340 if (afi == AFI_IP)
341 {
342 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
343 stream_write (obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
344 }
345 else if (afi == AFI_IP6)
346 {
347 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
348 stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
349 }
350
351 /* Save where we are now, so we can overwride the entry count later */
352 sizep = stream_get_endp (obuf);
353
354 /* Entry count */
355 uint16_t entry_count = 0;
356
357 /* Entry count, note that this is overwritten later */
358 stream_putw (obuf, 0);
359
360 endp = stream_get_endp (obuf);
361 for (; info; info = info->next)
362 {
363 size_t cur_endp;
364
365 /* Peer index */
366 stream_putw (obuf, info->peer->table_dump_index);
367
368 /* Originated */
246556b5 369 stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
246556b5
EU
370
371 /* Dump attribute. */
372 /* Skip prefix & AFI/SAFI for MP_NLRI */
373 bgp_dump_routes_attr (obuf, info->attr, &rn->p);
374
375 cur_endp = stream_get_endp (obuf);
376 if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
377 + BGP_DUMP_HEADER_SIZE)
378 {
379 stream_set_endp (obuf, endp);
380 break;
381 }
382
383 entry_count++;
384 endp = cur_endp;
385 }
386
387 /* Overwrite the entry count, now that we know the right number */
388 stream_putw_at (obuf, sizep, entry_count);
389
390 bgp_dump_set_size (obuf, MSG_TABLE_DUMP_V2);
391 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
392
393 return info;
394}
395
396
718e3744 397/* Runs under child process. */
0b2aa3a0
PJ
398static unsigned int
399bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
718e3744 400{
718e3744 401 struct bgp_info *info;
0b2aa3a0 402 struct bgp_node *rn;
718e3744 403 struct bgp *bgp;
404 struct bgp_table *table;
718e3744 405
406 bgp = bgp_get_default ();
407 if (!bgp)
0b2aa3a0 408 return seq;
718e3744 409
410 if (bgp_dump_routes.fp == NULL)
0b2aa3a0
PJ
411 return seq;
412
413 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
414 so this should only be done on the first call to bgp_dump_routes_func.
415 ( this function will be called once for ipv4 and once for ipv6 ) */
246556b5 416 if (first_run)
0b2aa3a0
PJ
417 bgp_dump_routes_index_table(bgp);
418
718e3744 419 /* Walk down each BGP route. */
420 table = bgp->rib[afi][SAFI_UNICAST];
421
422 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
0b2aa3a0 423 {
246556b5
EU
424 info = rn->info;
425 while (info)
426 {
427 info = bgp_dump_route_node_record (afi, rn, info, seq);
428 seq++;
429 }
0b2aa3a0
PJ
430 }
431
432 fflush (bgp_dump_routes.fp);
433
434 return seq;
718e3744 435}
436
94f2b392 437static int
718e3744 438bgp_dump_interval_func (struct thread *t)
439{
440 struct bgp_dump *bgp_dump;
718e3744 441 bgp_dump = THREAD_ARG (t);
442 bgp_dump->t_interval = NULL;
443
9834cd0f 444 /* Reschedule dump even if file couldn't be opened this time... */
445 if (bgp_dump_open_file (bgp_dump) != NULL)
718e3744 446 {
9834cd0f 447 /* In case of bgp_dump_routes, we need special route dump function. */
448 if (bgp_dump->type == BGP_DUMP_ROUTES)
449 {
0b2aa3a0 450 unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
0b2aa3a0 451 bgp_dump_routes_func (AFI_IP6, 0, seq);
9834cd0f 452 /* Close the file now. For a RIB dump there's no point in leaving
453 * it open until the next scheduled dump starts. */
454 fclose(bgp_dump->fp); bgp_dump->fp = NULL;
455 }
718e3744 456 }
457
fba3d22b 458 /* if interval is set reschedule */
459 if (bgp_dump->interval > 0)
460 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
461
718e3744 462 return 0;
463}
464
465/* Dump common information. */
94f2b392 466static void
0b2aa3a0 467bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
718e3744 468{
469 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
470
471 /* Source AS number and Destination AS number. */
0b2aa3a0
PJ
472 if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
473 {
474 stream_putl (obuf, peer->as);
475 stream_putl (obuf, peer->local_as);
476 }
477 else
478 {
479 stream_putw (obuf, peer->as);
480 stream_putw (obuf, peer->local_as);
481 }
718e3744 482
a384592f 483 if (peer->su.sa.sa_family == AF_INET)
718e3744 484 {
485 stream_putw (obuf, peer->ifindex);
486 stream_putw (obuf, AFI_IP);
487
488 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
489
490 if (peer->su_local)
491 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
492 else
493 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
494 }
a384592f 495 else if (peer->su.sa.sa_family == AF_INET6)
718e3744 496 {
497 /* Interface Index and Address family. */
498 stream_putw (obuf, peer->ifindex);
499 stream_putw (obuf, AFI_IP6);
500
501 /* Source IP Address and Destination IP Address. */
502 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
503
504 if (peer->su_local)
505 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
506 else
507 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
508 }
718e3744 509}
510
511/* Dump BGP status change. */
512void
513bgp_dump_state (struct peer *peer, int status_old, int status_new)
514{
515 struct stream *obuf;
516
517 /* If dump file pointer is disabled return immediately. */
518 if (bgp_dump_all.fp == NULL)
519 return;
520
521 /* Make dump stream. */
522 obuf = bgp_dump_obuf;
523 stream_reset (obuf);
524
4db5d90a
AF
525 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
526 bgp_dump_all.type);
0b2aa3a0 527 bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
718e3744 528
529 stream_putw (obuf, status_old);
530 stream_putw (obuf, status_new);
531
532 /* Set length. */
533 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
534
535 /* Write to the stream. */
a6694fe8 536 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
718e3744 537 fflush (bgp_dump_all.fp);
538}
539
94f2b392 540static void
718e3744 541bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
542 struct stream *packet)
543{
544 struct stream *obuf;
545
546 /* If dump file pointer is disabled return immediately. */
547 if (bgp_dump->fp == NULL)
548 return;
549
550 /* Make dump stream. */
551 obuf = bgp_dump_obuf;
552 stream_reset (obuf);
553
554 /* Dump header and common part. */
0b2aa3a0
PJ
555 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
556 {
4db5d90a
AF
557 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
558 bgp_dump->type);
0b2aa3a0
PJ
559 }
560 else
561 {
4db5d90a
AF
562 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
563 bgp_dump->type);
0b2aa3a0
PJ
564 }
565 bgp_dump_common (obuf, peer, 0);
718e3744 566
567 /* Packet contents. */
568 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
569
570 /* Set length. */
571 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
572
573 /* Write to the stream. */
a6694fe8 574 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
718e3744 575 fflush (bgp_dump->fp);
576}
577
578/* Called from bgp_packet.c when BGP packet is received. */
579void
580bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
581{
582 /* bgp_dump_all. */
583 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
584
585 /* bgp_dump_updates. */
586 if (type == BGP_MSG_UPDATE)
587 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
588}
6b0655a2 589
94f2b392 590static unsigned int
fd79ac91 591bgp_dump_parse_time (const char *str)
718e3744 592{
593 int i;
594 int len;
595 int seen_h;
596 int seen_m;
597 int time;
598 unsigned int total;
599
600 time = 0;
601 total = 0;
602 seen_h = 0;
603 seen_m = 0;
604 len = strlen (str);
605
606 for (i = 0; i < len; i++)
607 {
608 if (isdigit ((int) str[i]))
609 {
610 time *= 10;
611 time += str[i] - '0';
612 }
613 else if (str[i] == 'H' || str[i] == 'h')
614 {
615 if (seen_h)
616 return 0;
617 if (seen_m)
618 return 0;
619 total += time * 60 *60;
620 time = 0;
621 seen_h = 1;
622 }
623 else if (str[i] == 'M' || str[i] == 'm')
624 {
625 if (seen_m)
626 return 0;
627 total += time * 60;
628 time = 0;
46c3ce83 629 seen_m = 1;
718e3744 630 }
631 else
632 return 0;
633 }
634 return total + time;
635}
636
94f2b392 637static int
45ad592e
PJ
638bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
639 enum bgp_dump_type type, const char *path,
640 const char *interval_str)
718e3744 641{
fba3d22b 642 unsigned int interval;
643
4db5d90a
AF
644 /* Don't schedule duplicate dumps if the dump command is given twice */
645 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
646 && type == bgp_dump->type)
647 {
648 if (interval_str)
649 {
650 if (bgp_dump->interval_str &&
651 strcmp(bgp_dump->interval_str, interval_str) == 0)
652 return CMD_SUCCESS;
653 }
654 else
655 {
656 if (!bgp_dump->interval_str)
657 return CMD_SUCCESS;
658 }
659 }
660
661 /* Removing previous config */
b8438f6d 662 bgp_dump_unset(bgp_dump);
4db5d90a 663
718e3744 664 if (interval_str)
665 {
718e3744 666 /* Check interval string. */
667 interval = bgp_dump_parse_time (interval_str);
668 if (interval == 0)
669 {
5c7571d4 670 vty_out (vty, "Malformed interval string\n");
f1a05de9 671 return CMD_WARNING_CONFIG_FAILED;
718e3744 672 }
45ad592e 673
4db5d90a 674 /* Setting interval string */
6e919709 675 bgp_dump->interval_str = XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
718e3744 676 }
fba3d22b 677 else
678 {
679 interval = 0;
680 }
718e3744 681
682 /* Set type. */
683 bgp_dump->type = type;
684
4db5d90a
AF
685 /* Set interval */
686 bgp_dump->interval = interval;
687
718e3744 688 /* Set file name. */
4db5d90a
AF
689 bgp_dump->filename = XSTRDUP (MTYPE_BGP_DUMP_STR, path);
690
691 /* Create interval thread. */
692 bgp_dump_interval_add (bgp_dump, interval);
718e3744 693
694 /* This should be called when interval is expired. */
695 bgp_dump_open_file (bgp_dump);
696
697 return CMD_SUCCESS;
698}
699
94f2b392 700static int
b8438f6d 701bgp_dump_unset (struct bgp_dump *bgp_dump)
718e3744 702{
4db5d90a 703 /* Removing file name. */
718e3744 704 if (bgp_dump->filename)
705 {
6e919709 706 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
718e3744 707 bgp_dump->filename = NULL;
708 }
709
4db5d90a 710 /* Closing file. */
718e3744 711 if (bgp_dump->fp)
712 {
713 fclose (bgp_dump->fp);
714 bgp_dump->fp = NULL;
715 }
716
4db5d90a 717 /* Removing interval thread. */
718e3744 718 if (bgp_dump->t_interval)
719 {
720 thread_cancel (bgp_dump->t_interval);
721 bgp_dump->t_interval = NULL;
722 }
723
724 bgp_dump->interval = 0;
725
4db5d90a 726 /* Removing interval string. */
718e3744 727 if (bgp_dump->interval_str)
728 {
6e919709 729 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
718e3744 730 bgp_dump->interval_str = NULL;
731 }
732
718e3744 733 return CMD_SUCCESS;
734}
735
736DEFUN (dump_bgp_all,
737 dump_bgp_all_cmd,
6147e2c6 738 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
718e3744 739 "Dump packet\n"
740 "BGP packet dump\n"
cbac2b1b
EU
741 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
742 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
4db5d90a 743 "Dump whole BGP routing table\n"
718e3744 744 "Output filename\n"
745 "Interval of output\n")
746{
c500ae40
DW
747 int idx_dump_routes = 2;
748 int idx_path = 3;
749 int idx_interval = 4;
4db5d90a
AF
750 int bgp_dump_type = 0;
751 const char *interval = NULL;
752 struct bgp_dump *bgp_dump_struct = NULL;
753 const struct bgp_dump_type_map *map = NULL;
718e3744 754
4db5d90a 755 for (map = bgp_dump_type_map; map->str; map++)
7e045c3d 756 if (strmatch(argv[idx_dump_routes]->text, map->str))
4db5d90a 757 bgp_dump_type = map->type;
718e3744 758
4db5d90a
AF
759 switch (bgp_dump_type)
760 {
761 case BGP_DUMP_ALL:
762 case BGP_DUMP_ALL_ET:
763 bgp_dump_struct = &bgp_dump_all;
764 break;
765 case BGP_DUMP_UPDATES:
766 case BGP_DUMP_UPDATES_ET:
767 bgp_dump_struct = &bgp_dump_updates;
768 break;
769 case BGP_DUMP_ROUTES:
770 default:
771 bgp_dump_struct = &bgp_dump_routes;
772 break;
773 }
718e3744 774
4db5d90a 775 /* When an interval is given */
00d7d2d3 776 if (argc == idx_interval + 1)
c500ae40 777 interval = argv[idx_interval]->arg;
718e3744 778
4db5d90a 779 return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type,
c500ae40 780 argv[idx_path]->arg, interval);
718e3744 781}
782
4db5d90a
AF
783DEFUN (no_dump_bgp_all,
784 no_dump_bgp_all_cmd,
37bc45eb 785 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
718e3744 786 NO_STR
4db5d90a
AF
787 "Stop dump packet\n"
788 "Stop BGP packet dump\n"
ca492402
DS
789 "Stop dump process all\n"
790 "Stop dump process all-et\n"
791 "Stop dump process updates\n"
792 "Stop dump process updates-et\n"
3a2d747c
QY
793 "Stop dump process route-mrt\n"
794 "Output filename\n"
795 "Interval of output\n")
718e3744 796{
c500ae40 797 int idx_dump_routes = 3;
ca492402
DS
798 int bgp_dump_type = 0;
799 const struct bgp_dump_type_map *map = NULL;
800 struct bgp_dump *bgp_dump_struct = NULL;
801
802 for (map = bgp_dump_type_map; map->str; map++)
7e045c3d 803 if (strmatch(argv[idx_dump_routes]->text, map->str))
ca492402
DS
804 bgp_dump_type = map->type;
805
806 switch (bgp_dump_type)
807 {
808 case BGP_DUMP_ALL:
809 case BGP_DUMP_ALL_ET:
810 bgp_dump_struct = &bgp_dump_all;
811 break;
812 case BGP_DUMP_UPDATES:
813 case BGP_DUMP_UPDATES_ET:
814 bgp_dump_struct = &bgp_dump_updates;
815 break;
816 case BGP_DUMP_ROUTES:
817 default:
818 bgp_dump_struct = &bgp_dump_routes;
819 break;
820 }
821
b8438f6d 822 return bgp_dump_unset (bgp_dump_struct);
718e3744 823}
824
825/* BGP node structure. */
7fc626de 826static struct cmd_node bgp_dump_node =
718e3744 827{
828 DUMP_NODE,
829 "",
501ba490 830 1
718e3744 831};
832
833#if 0
834char *
835config_time2str (unsigned int interval)
836{
837 static char buf[BUFSIZ];
838
839 buf[0] = '\0';
840
841 if (interval / 3600)
842 {
843 sprintf (buf, "%dh", interval / 3600);
844 interval %= 3600;
845 }
846 if (interval / 60)
847 {
848 sprintf (buf + strlen (buf), "%dm", interval /60);
849 interval %= 60;
850 }
851 if (interval)
852 {
853 sprintf (buf + strlen (buf), "%d", interval);
854 }
855 return buf;
856}
857#endif
858
94f2b392 859static int
718e3744 860config_write_bgp_dump (struct vty *vty)
861{
862 if (bgp_dump_all.filename)
863 {
4db5d90a
AF
864 const char *type_str = "all";
865 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
866 type_str = "all-et";
867
718e3744 868 if (bgp_dump_all.interval_str)
5c7571d4 869 vty_out (vty, "dump bgp %s %s %s\n", type_str,
96ade3ed 870 bgp_dump_all.filename,bgp_dump_all.interval_str);
718e3744 871 else
5c7571d4 872 vty_out (vty, "dump bgp %s %s\n", type_str,
96ade3ed 873 bgp_dump_all.filename);
718e3744 874 }
875 if (bgp_dump_updates.filename)
876 {
4db5d90a
AF
877 const char *type_str = "updates";
878 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
879 type_str = "updates-et";
880
718e3744 881 if (bgp_dump_updates.interval_str)
5c7571d4 882 vty_out (vty, "dump bgp %s %s %s\n", type_str,
96ade3ed 883 bgp_dump_updates.filename,bgp_dump_updates.interval_str);
718e3744 884 else
5c7571d4 885 vty_out (vty, "dump bgp %s %s\n", type_str,
96ade3ed 886 bgp_dump_updates.filename);
718e3744 887 }
888 if (bgp_dump_routes.filename)
889 {
890 if (bgp_dump_routes.interval_str)
5c7571d4 891 vty_out (vty, "dump bgp routes-mrt %s %s\n",
96ade3ed 892 bgp_dump_routes.filename,bgp_dump_routes.interval_str);
37bc45eb 893 else
5c7571d4 894 vty_out (vty, "dump bgp routes-mrt %s\n",
96ade3ed 895 bgp_dump_routes.filename);
37bc45eb 896
718e3744 897 }
898 return 0;
899}
6b0655a2 900
718e3744 901/* Initialize BGP packet dump functionality. */
902void
94f2b392 903bgp_dump_init (void)
718e3744 904{
905 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
906 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
907 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
908
246556b5
EU
909 bgp_dump_obuf = stream_new ((BGP_MAX_PACKET_SIZE << 1)
910 + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
718e3744 911
912 install_node (&bgp_dump_node, config_write_bgp_dump);
913
914 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
718e3744 915 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
718e3744 916}
228da428
CC
917
918void
919bgp_dump_finish (void)
920{
b8438f6d
DL
921 bgp_dump_unset (&bgp_dump_all);
922 bgp_dump_unset (&bgp_dump_updates);
923 bgp_dump_unset (&bgp_dump_routes);
924
228da428
CC
925 stream_free (bgp_dump_obuf);
926 bgp_dump_obuf = NULL;
927}