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