]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_dump.c
Merge pull request #10413 from anlancs/bfd-with-check
[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 int 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, "bgp_dump_open_file: strftime error");
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, "bgp_dump_open_file: %s: %s", 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) - (bgp_clock() - 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 int 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 return 0;
467 }
468
469 /* Dump common information. */
470 static void bgp_dump_common(struct stream *obuf, struct peer *peer,
471 int forceas4)
472 {
473 char empty[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
474
475 /* Source AS number and Destination AS number. */
476 if (forceas4 || CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
477 stream_putl(obuf, peer->as);
478 stream_putl(obuf, peer->local_as);
479 } else {
480 stream_putw(obuf, peer->as);
481 stream_putw(obuf, peer->local_as);
482 }
483
484 if (peer->su.sa.sa_family == AF_INET) {
485 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
486 stream_putw(obuf, AFI_IP);
487
488 stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
489
490 if (peer->su_local)
491 stream_put(obuf, &peer->su_local->sin.sin_addr,
492 IPV4_MAX_BYTELEN);
493 else
494 stream_put(obuf, empty, IPV4_MAX_BYTELEN);
495 } else if (peer->su.sa.sa_family == AF_INET6) {
496 /* Interface Index and Address family. */
497 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
498 stream_putw(obuf, AFI_IP6);
499
500 /* Source IP Address and Destination IP Address. */
501 stream_put(obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
502
503 if (peer->su_local)
504 stream_put(obuf, &peer->su_local->sin6.sin6_addr,
505 IPV6_MAX_BYTELEN);
506 else
507 stream_put(obuf, empty, IPV6_MAX_BYTELEN);
508 }
509 }
510
511 /* Dump BGP status change. */
512 int bgp_dump_state(struct peer *peer)
513 {
514 struct stream *obuf;
515
516 /* If dump file pointer is disabled return immediately. */
517 if (bgp_dump_all.fp == NULL)
518 return 0;
519
520 /* Make dump stream. */
521 obuf = bgp_dump_obuf;
522 stream_reset(obuf);
523
524 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
525 bgp_dump_all.type);
526 bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/
527
528 stream_putw(obuf, peer->ostatus);
529 stream_putw(obuf, peer->status);
530
531 /* Set length. */
532 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
533
534 /* Write to the stream. */
535 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_all.fp);
536 fflush(bgp_dump_all.fp);
537 return 0;
538 }
539
540 static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
541 struct stream *packet)
542 {
543 struct stream *obuf;
544 bool addpath_capable = false;
545 /* If dump file pointer is disabled return immediately. */
546 if (bgp_dump->fp == NULL)
547 return;
548 if (peer->su.sa.sa_family == AF_INET) {
549 addpath_capable =
550 bgp_addpath_encode_rx(peer, AFI_IP, SAFI_UNICAST);
551 } else if (peer->su.sa.sa_family == AF_INET6) {
552 addpath_capable =
553 bgp_addpath_encode_rx(peer, AFI_IP6, SAFI_UNICAST);
554 }
555
556 /* Make dump stream. */
557 obuf = bgp_dump_obuf;
558 stream_reset(obuf);
559
560 /* Dump header and common part. */
561 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) && addpath_capable) {
562 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP,
563 BGP4MP_MESSAGE_AS4_ADDPATH, bgp_dump->type);
564 } else if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
565 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
566 bgp_dump->type);
567 } else if (addpath_capable) {
568 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP,
569 BGP4MP_MESSAGE_ADDPATH, bgp_dump->type);
570 } else {
571 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
572 bgp_dump->type);
573 }
574 bgp_dump_common(obuf, peer, 0);
575
576 /* Packet contents. */
577 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
578
579 /* Set length. */
580 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
581
582 /* Write to the stream. */
583 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
584 fflush(bgp_dump->fp);
585 }
586
587 /* Called from bgp_packet.c when BGP packet is received. */
588 static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
589 struct stream *packet)
590 {
591 /* bgp_dump_all. */
592 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
593
594 /* bgp_dump_updates. */
595 if (type == BGP_MSG_UPDATE)
596 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
597 return 0;
598 }
599
600 static unsigned int bgp_dump_parse_time(const char *str)
601 {
602 int i;
603 int len;
604 int seen_h;
605 int seen_m;
606 int time;
607 unsigned int total;
608
609 time = 0;
610 total = 0;
611 seen_h = 0;
612 seen_m = 0;
613 len = strlen(str);
614
615 for (i = 0; i < len; i++) {
616 if (isdigit((unsigned char)str[i])) {
617 time *= 10;
618 time += str[i] - '0';
619 } else if (str[i] == 'H' || str[i] == 'h') {
620 if (seen_h)
621 return 0;
622 if (seen_m)
623 return 0;
624 total += time * 60 * 60;
625 time = 0;
626 seen_h = 1;
627 } else if (str[i] == 'M' || str[i] == 'm') {
628 if (seen_m)
629 return 0;
630 total += time * 60;
631 time = 0;
632 seen_m = 1;
633 } else
634 return 0;
635 }
636 return total + time;
637 }
638
639 static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
640 enum bgp_dump_type type, const char *path,
641 const char *interval_str)
642 {
643 unsigned int interval;
644
645 /* Don't schedule duplicate dumps if the dump command is given twice */
646 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
647 && type == bgp_dump->type) {
648 if (interval_str) {
649 if (bgp_dump->interval_str
650 && strcmp(bgp_dump->interval_str, interval_str)
651 == 0)
652 return CMD_SUCCESS;
653 } else {
654 if (!bgp_dump->interval_str)
655 return CMD_SUCCESS;
656 }
657 }
658
659 /* Removing previous config */
660 bgp_dump_unset(bgp_dump);
661
662 if (interval_str) {
663 /* Check interval string. */
664 interval = bgp_dump_parse_time(interval_str);
665 if (interval == 0) {
666 vty_out(vty, "Malformed interval string\n");
667 return CMD_WARNING_CONFIG_FAILED;
668 }
669
670 /* Setting interval string */
671 bgp_dump->interval_str =
672 XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
673 } else {
674 interval = 0;
675 }
676
677 /* Set type. */
678 bgp_dump->type = type;
679
680 /* Set interval */
681 bgp_dump->interval = interval;
682
683 /* Set file name. */
684 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
685
686 /* Create interval thread. */
687 bgp_dump_interval_add(bgp_dump, interval);
688
689 /* This should be called when interval is expired. */
690 bgp_dump_open_file(bgp_dump);
691
692 return CMD_SUCCESS;
693 }
694
695 static int bgp_dump_unset(struct bgp_dump *bgp_dump)
696 {
697 /* Removing file name. */
698 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
699
700 /* Closing file. */
701 if (bgp_dump->fp) {
702 fclose(bgp_dump->fp);
703 bgp_dump->fp = NULL;
704 }
705
706 /* Removing interval event. */
707 thread_cancel(&bgp_dump->t_interval);
708
709 bgp_dump->interval = 0;
710
711 /* Removing interval string. */
712 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
713
714 return CMD_SUCCESS;
715 }
716
717 DEFUN (dump_bgp_all,
718 dump_bgp_all_cmd,
719 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
720 "Dump packet\n"
721 "BGP packet dump\n"
722 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
723 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
724 "Dump whole BGP routing table\n"
725 "Output filename\n"
726 "Interval of output\n")
727 {
728 int idx_dump_routes = 2;
729 int idx_path = 3;
730 int idx_interval = 4;
731 int bgp_dump_type = 0;
732 const char *interval = NULL;
733 struct bgp_dump *bgp_dump_struct = NULL;
734 const struct bgp_dump_type_map *map = NULL;
735
736 for (map = bgp_dump_type_map; map->str; map++)
737 if (strmatch(argv[idx_dump_routes]->text, map->str))
738 bgp_dump_type = map->type;
739
740 switch (bgp_dump_type) {
741 case BGP_DUMP_ALL:
742 case BGP_DUMP_ALL_ET:
743 bgp_dump_struct = &bgp_dump_all;
744 break;
745 case BGP_DUMP_UPDATES:
746 case BGP_DUMP_UPDATES_ET:
747 bgp_dump_struct = &bgp_dump_updates;
748 break;
749 case BGP_DUMP_ROUTES:
750 default:
751 bgp_dump_struct = &bgp_dump_routes;
752 break;
753 }
754
755 /* When an interval is given */
756 if (argc == idx_interval + 1)
757 interval = argv[idx_interval]->arg;
758
759 return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
760 argv[idx_path]->arg, interval);
761 }
762
763 DEFUN (no_dump_bgp_all,
764 no_dump_bgp_all_cmd,
765 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
766 NO_STR
767 "Stop dump packet\n"
768 "Stop BGP packet dump\n"
769 "Stop dump process all\n"
770 "Stop dump process all-et\n"
771 "Stop dump process updates\n"
772 "Stop dump process updates-et\n"
773 "Stop dump process route-mrt\n"
774 "Output filename\n"
775 "Interval of output\n")
776 {
777 int idx_dump_routes = 3;
778 int bgp_dump_type = 0;
779 const struct bgp_dump_type_map *map = NULL;
780 struct bgp_dump *bgp_dump_struct = NULL;
781
782 for (map = bgp_dump_type_map; map->str; map++)
783 if (strmatch(argv[idx_dump_routes]->text, map->str))
784 bgp_dump_type = map->type;
785
786 switch (bgp_dump_type) {
787 case BGP_DUMP_ALL:
788 case BGP_DUMP_ALL_ET:
789 bgp_dump_struct = &bgp_dump_all;
790 break;
791 case BGP_DUMP_UPDATES:
792 case BGP_DUMP_UPDATES_ET:
793 bgp_dump_struct = &bgp_dump_updates;
794 break;
795 case BGP_DUMP_ROUTES:
796 default:
797 bgp_dump_struct = &bgp_dump_routes;
798 break;
799 }
800
801 return bgp_dump_unset(bgp_dump_struct);
802 }
803
804 static int config_write_bgp_dump(struct vty *vty);
805 /* BGP node structure. */
806 static struct cmd_node bgp_dump_node = {
807 .name = "dump",
808 .node = DUMP_NODE,
809 .prompt = "",
810 .config_write = config_write_bgp_dump,
811 };
812
813 static int config_write_bgp_dump(struct vty *vty)
814 {
815 if (bgp_dump_all.filename) {
816 const char *type_str = "all";
817 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
818 type_str = "all-et";
819
820 if (bgp_dump_all.interval_str)
821 vty_out(vty, "dump bgp %s %s %s\n", type_str,
822 bgp_dump_all.filename,
823 bgp_dump_all.interval_str);
824 else
825 vty_out(vty, "dump bgp %s %s\n", type_str,
826 bgp_dump_all.filename);
827 }
828 if (bgp_dump_updates.filename) {
829 const char *type_str = "updates";
830 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
831 type_str = "updates-et";
832
833 if (bgp_dump_updates.interval_str)
834 vty_out(vty, "dump bgp %s %s %s\n", type_str,
835 bgp_dump_updates.filename,
836 bgp_dump_updates.interval_str);
837 else
838 vty_out(vty, "dump bgp %s %s\n", type_str,
839 bgp_dump_updates.filename);
840 }
841 if (bgp_dump_routes.filename) {
842 if (bgp_dump_routes.interval_str)
843 vty_out(vty, "dump bgp routes-mrt %s %s\n",
844 bgp_dump_routes.filename,
845 bgp_dump_routes.interval_str);
846 else
847 vty_out(vty, "dump bgp routes-mrt %s\n",
848 bgp_dump_routes.filename);
849 }
850 return 0;
851 }
852
853 /* Initialize BGP packet dump functionality. */
854 void bgp_dump_init(void)
855 {
856 memset(&bgp_dump_all, 0, sizeof(struct bgp_dump));
857 memset(&bgp_dump_updates, 0, sizeof(struct bgp_dump));
858 memset(&bgp_dump_routes, 0, sizeof(struct bgp_dump));
859
860 bgp_dump_obuf =
861 stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE * 2)
862 + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
863
864 install_node(&bgp_dump_node);
865
866 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
867 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
868
869 hook_register(bgp_packet_dump, bgp_dump_packet);
870 hook_register(peer_status_changed, bgp_dump_state);
871 }
872
873 void bgp_dump_finish(void)
874 {
875 bgp_dump_unset(&bgp_dump_all);
876 bgp_dump_unset(&bgp_dump_updates);
877 bgp_dump_unset(&bgp_dump_routes);
878
879 stream_free(bgp_dump_obuf);
880 bgp_dump_obuf = NULL;
881 hook_unregister(bgp_packet_dump, bgp_dump_packet);
882 hook_unregister(peer_status_changed, bgp_dump_state);
883 }