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