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