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