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