]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_dump.c
Merge pull request #7942 from donaldsharp/rpki_reload_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 static int bgp_addpath_encode_rx(struct peer *peer, afi_t afi, safi_t safi)
304 {
305
306 return (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV)
307 && CHECK_FLAG(peer->af_cap[afi][safi],
308 PEER_CAP_ADDPATH_AF_TX_RCV));
309 }
310
311 static struct bgp_path_info *
312 bgp_dump_route_node_record(int afi, struct bgp_dest *dest,
313 struct bgp_path_info *path, unsigned int seq)
314 {
315 struct stream *obuf;
316 size_t sizep;
317 size_t endp;
318 int addpath_encoded;
319 const struct prefix *p = bgp_dest_get_prefix(dest);
320
321 obuf = bgp_dump_obuf;
322 stream_reset(obuf);
323
324 addpath_encoded = bgp_addpath_encode_rx(path->peer, afi, SAFI_UNICAST);
325
326 /* MRT header */
327 if (afi == AFI_IP && addpath_encoded)
328 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
329 TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH,
330 BGP_DUMP_ROUTES);
331 else if (afi == AFI_IP)
332 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
333 TABLE_DUMP_V2_RIB_IPV4_UNICAST,
334 BGP_DUMP_ROUTES);
335 else if (afi == AFI_IP6 && addpath_encoded)
336 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
337 TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH,
338 BGP_DUMP_ROUTES);
339 else if (afi == AFI_IP6)
340 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
341 TABLE_DUMP_V2_RIB_IPV6_UNICAST,
342 BGP_DUMP_ROUTES);
343
344 /* Sequence number */
345 stream_putl(obuf, seq);
346
347 /* Prefix length */
348 stream_putc(obuf, p->prefixlen);
349
350 /* Prefix */
351 if (afi == AFI_IP) {
352 /* We'll dump only the useful bits (those not 0), but have to
353 * align on 8 bits */
354 stream_write(obuf, (uint8_t *)&p->u.prefix4,
355 (p->prefixlen + 7) / 8);
356 } else if (afi == AFI_IP6) {
357 /* We'll dump only the useful bits (those not 0), but have to
358 * align on 8 bits */
359 stream_write(obuf, (uint8_t *)&p->u.prefix6,
360 (p->prefixlen + 7) / 8);
361 }
362
363 /* Save where we are now, so we can overwride the entry count later */
364 sizep = stream_get_endp(obuf);
365
366 /* Entry count */
367 uint16_t entry_count = 0;
368
369 /* Entry count, note that this is overwritten later */
370 stream_putw(obuf, 0);
371
372 endp = stream_get_endp(obuf);
373 for (; path; path = path->next) {
374 size_t cur_endp;
375
376 /* Peer index */
377 stream_putw(obuf, path->peer->table_dump_index);
378
379 /* Originated */
380 stream_putl(obuf, time(NULL) - (bgp_clock() - path->uptime));
381
382 /*Path Identifier*/
383 if (addpath_encoded) {
384 stream_putl(obuf, path->addpath_rx_id);
385 }
386
387 /* Dump attribute. */
388 /* Skip prefix & AFI/SAFI for MP_NLRI */
389 bgp_dump_routes_attr(obuf, path->attr, p);
390
391 cur_endp = stream_get_endp(obuf);
392 if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
393 + BGP_DUMP_HEADER_SIZE) {
394 stream_set_endp(obuf, endp);
395 break;
396 }
397
398 entry_count++;
399 endp = cur_endp;
400 }
401
402 /* Overwrite the entry count, now that we know the right number */
403 stream_putw_at(obuf, sizep, entry_count);
404
405 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
406 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
407
408 return path;
409 }
410
411
412 /* Runs under child process. */
413 static unsigned int bgp_dump_routes_func(int afi, int first_run,
414 unsigned int seq)
415 {
416 struct bgp_path_info *path;
417 struct bgp_dest *dest;
418 struct bgp *bgp;
419 struct bgp_table *table;
420
421 bgp = bgp_get_default();
422 if (!bgp)
423 return seq;
424
425 if (bgp_dump_routes.fp == NULL)
426 return seq;
427
428 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
429 so this should only be done on the first call to
430 bgp_dump_routes_func.
431 ( this function will be called once for ipv4 and once for ipv6 ) */
432 if (first_run)
433 bgp_dump_routes_index_table(bgp);
434
435 /* Walk down each BGP route. */
436 table = bgp->rib[afi][SAFI_UNICAST];
437
438 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
439 path = bgp_dest_get_bgp_path_info(dest);
440 while (path) {
441 path = bgp_dump_route_node_record(afi, dest, path, seq);
442 seq++;
443 }
444 }
445
446 fflush(bgp_dump_routes.fp);
447
448 return seq;
449 }
450
451 static int bgp_dump_interval_func(struct thread *t)
452 {
453 struct bgp_dump *bgp_dump;
454 bgp_dump = THREAD_ARG(t);
455 bgp_dump->t_interval = NULL;
456
457 /* Reschedule dump even if file couldn't be opened this time... */
458 if (bgp_dump_open_file(bgp_dump) != NULL) {
459 /* In case of bgp_dump_routes, we need special route dump
460 * function. */
461 if (bgp_dump->type == BGP_DUMP_ROUTES) {
462 unsigned int seq = bgp_dump_routes_func(AFI_IP, 1, 0);
463 bgp_dump_routes_func(AFI_IP6, 0, seq);
464 /* Close the file now. For a RIB dump there's no point
465 * in leaving
466 * it open until the next scheduled dump starts. */
467 fclose(bgp_dump->fp);
468 bgp_dump->fp = NULL;
469 }
470 }
471
472 /* if interval is set reschedule */
473 if (bgp_dump->interval > 0)
474 bgp_dump_interval_add(bgp_dump, bgp_dump->interval);
475
476 return 0;
477 }
478
479 /* Dump common information. */
480 static void bgp_dump_common(struct stream *obuf, struct peer *peer,
481 int forceas4)
482 {
483 char empty[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
484
485 /* Source AS number and Destination AS number. */
486 if (forceas4 || CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
487 stream_putl(obuf, peer->as);
488 stream_putl(obuf, peer->local_as);
489 } else {
490 stream_putw(obuf, peer->as);
491 stream_putw(obuf, peer->local_as);
492 }
493
494 if (peer->su.sa.sa_family == AF_INET) {
495 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
496 stream_putw(obuf, AFI_IP);
497
498 stream_put(obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
499
500 if (peer->su_local)
501 stream_put(obuf, &peer->su_local->sin.sin_addr,
502 IPV4_MAX_BYTELEN);
503 else
504 stream_put(obuf, empty, IPV4_MAX_BYTELEN);
505 } else if (peer->su.sa.sa_family == AF_INET6) {
506 /* Interface Index and Address family. */
507 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
508 stream_putw(obuf, AFI_IP6);
509
510 /* Source IP Address and Destination IP Address. */
511 stream_put(obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
512
513 if (peer->su_local)
514 stream_put(obuf, &peer->su_local->sin6.sin6_addr,
515 IPV6_MAX_BYTELEN);
516 else
517 stream_put(obuf, empty, IPV6_MAX_BYTELEN);
518 }
519 }
520
521 /* Dump BGP status change. */
522 int bgp_dump_state(struct peer *peer)
523 {
524 struct stream *obuf;
525
526 /* If dump file pointer is disabled return immediately. */
527 if (bgp_dump_all.fp == NULL)
528 return 0;
529
530 /* Make dump stream. */
531 obuf = bgp_dump_obuf;
532 stream_reset(obuf);
533
534 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
535 bgp_dump_all.type);
536 bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/
537
538 stream_putw(obuf, peer->ostatus);
539 stream_putw(obuf, peer->status);
540
541 /* Set length. */
542 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
543
544 /* Write to the stream. */
545 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_all.fp);
546 fflush(bgp_dump_all.fp);
547 return 0;
548 }
549
550 static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
551 struct stream *packet)
552 {
553 struct stream *obuf;
554 int addpath_encoded = 0;
555 /* If dump file pointer is disabled return immediately. */
556 if (bgp_dump->fp == NULL)
557 return;
558 if (peer->su.sa.sa_family == AF_INET) {
559 addpath_encoded =
560 bgp_addpath_encode_rx(peer, AFI_IP, SAFI_UNICAST);
561 } else if (peer->su.sa.sa_family == AF_INET6) {
562 addpath_encoded =
563 bgp_addpath_encode_rx(peer, AFI_IP6, SAFI_UNICAST);
564 }
565
566 /* Make dump stream. */
567 obuf = bgp_dump_obuf;
568 stream_reset(obuf);
569
570 /* Dump header and common part. */
571 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) && addpath_encoded) {
572 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP,
573 BGP4MP_MESSAGE_AS4_ADDPATH, bgp_dump->type);
574 } else if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
575 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
576 bgp_dump->type);
577 } else if (addpath_encoded) {
578 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP,
579 BGP4MP_MESSAGE_ADDPATH, bgp_dump->type);
580 } else {
581 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
582 bgp_dump->type);
583 }
584 bgp_dump_common(obuf, peer, 0);
585
586 /* Packet contents. */
587 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
588
589 /* Set length. */
590 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
591
592 /* Write to the stream. */
593 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
594 fflush(bgp_dump->fp);
595 }
596
597 /* Called from bgp_packet.c when BGP packet is received. */
598 static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
599 struct stream *packet)
600 {
601 /* bgp_dump_all. */
602 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
603
604 /* bgp_dump_updates. */
605 if (type == BGP_MSG_UPDATE)
606 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
607 return 0;
608 }
609
610 static unsigned int bgp_dump_parse_time(const char *str)
611 {
612 int i;
613 int len;
614 int seen_h;
615 int seen_m;
616 int time;
617 unsigned int total;
618
619 time = 0;
620 total = 0;
621 seen_h = 0;
622 seen_m = 0;
623 len = strlen(str);
624
625 for (i = 0; i < len; i++) {
626 if (isdigit((unsigned char)str[i])) {
627 time *= 10;
628 time += str[i] - '0';
629 } else if (str[i] == 'H' || str[i] == 'h') {
630 if (seen_h)
631 return 0;
632 if (seen_m)
633 return 0;
634 total += time * 60 * 60;
635 time = 0;
636 seen_h = 1;
637 } else if (str[i] == 'M' || str[i] == 'm') {
638 if (seen_m)
639 return 0;
640 total += time * 60;
641 time = 0;
642 seen_m = 1;
643 } else
644 return 0;
645 }
646 return total + time;
647 }
648
649 static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
650 enum bgp_dump_type type, const char *path,
651 const char *interval_str)
652 {
653 unsigned int interval;
654
655 /* Don't schedule duplicate dumps if the dump command is given twice */
656 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
657 && type == bgp_dump->type) {
658 if (interval_str) {
659 if (bgp_dump->interval_str
660 && strcmp(bgp_dump->interval_str, interval_str)
661 == 0)
662 return CMD_SUCCESS;
663 } else {
664 if (!bgp_dump->interval_str)
665 return CMD_SUCCESS;
666 }
667 }
668
669 /* Removing previous config */
670 bgp_dump_unset(bgp_dump);
671
672 if (interval_str) {
673 /* Check interval string. */
674 interval = bgp_dump_parse_time(interval_str);
675 if (interval == 0) {
676 vty_out(vty, "Malformed interval string\n");
677 return CMD_WARNING_CONFIG_FAILED;
678 }
679
680 /* Setting interval string */
681 bgp_dump->interval_str =
682 XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
683 } else {
684 interval = 0;
685 }
686
687 /* Set type. */
688 bgp_dump->type = type;
689
690 /* Set interval */
691 bgp_dump->interval = interval;
692
693 /* Set file name. */
694 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
695
696 /* Create interval thread. */
697 bgp_dump_interval_add(bgp_dump, interval);
698
699 /* This should be called when interval is expired. */
700 bgp_dump_open_file(bgp_dump);
701
702 return CMD_SUCCESS;
703 }
704
705 static int bgp_dump_unset(struct bgp_dump *bgp_dump)
706 {
707 /* Removing file name. */
708 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
709
710 /* Closing file. */
711 if (bgp_dump->fp) {
712 fclose(bgp_dump->fp);
713 bgp_dump->fp = NULL;
714 }
715
716 /* Removing interval event. */
717 thread_cancel(&bgp_dump->t_interval);
718
719 bgp_dump->interval = 0;
720
721 /* Removing interval string. */
722 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
723
724 return CMD_SUCCESS;
725 }
726
727 DEFUN (dump_bgp_all,
728 dump_bgp_all_cmd,
729 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
730 "Dump packet\n"
731 "BGP packet dump\n"
732 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
733 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
734 "Dump whole BGP routing table\n"
735 "Output filename\n"
736 "Interval of output\n")
737 {
738 int idx_dump_routes = 2;
739 int idx_path = 3;
740 int idx_interval = 4;
741 int bgp_dump_type = 0;
742 const char *interval = NULL;
743 struct bgp_dump *bgp_dump_struct = NULL;
744 const struct bgp_dump_type_map *map = NULL;
745
746 for (map = bgp_dump_type_map; map->str; map++)
747 if (strmatch(argv[idx_dump_routes]->text, map->str))
748 bgp_dump_type = map->type;
749
750 switch (bgp_dump_type) {
751 case BGP_DUMP_ALL:
752 case BGP_DUMP_ALL_ET:
753 bgp_dump_struct = &bgp_dump_all;
754 break;
755 case BGP_DUMP_UPDATES:
756 case BGP_DUMP_UPDATES_ET:
757 bgp_dump_struct = &bgp_dump_updates;
758 break;
759 case BGP_DUMP_ROUTES:
760 default:
761 bgp_dump_struct = &bgp_dump_routes;
762 break;
763 }
764
765 /* When an interval is given */
766 if (argc == idx_interval + 1)
767 interval = argv[idx_interval]->arg;
768
769 return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
770 argv[idx_path]->arg, interval);
771 }
772
773 DEFUN (no_dump_bgp_all,
774 no_dump_bgp_all_cmd,
775 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
776 NO_STR
777 "Stop dump packet\n"
778 "Stop BGP packet dump\n"
779 "Stop dump process all\n"
780 "Stop dump process all-et\n"
781 "Stop dump process updates\n"
782 "Stop dump process updates-et\n"
783 "Stop dump process route-mrt\n"
784 "Output filename\n"
785 "Interval of output\n")
786 {
787 int idx_dump_routes = 3;
788 int bgp_dump_type = 0;
789 const struct bgp_dump_type_map *map = NULL;
790 struct bgp_dump *bgp_dump_struct = NULL;
791
792 for (map = bgp_dump_type_map; map->str; map++)
793 if (strmatch(argv[idx_dump_routes]->text, map->str))
794 bgp_dump_type = map->type;
795
796 switch (bgp_dump_type) {
797 case BGP_DUMP_ALL:
798 case BGP_DUMP_ALL_ET:
799 bgp_dump_struct = &bgp_dump_all;
800 break;
801 case BGP_DUMP_UPDATES:
802 case BGP_DUMP_UPDATES_ET:
803 bgp_dump_struct = &bgp_dump_updates;
804 break;
805 case BGP_DUMP_ROUTES:
806 default:
807 bgp_dump_struct = &bgp_dump_routes;
808 break;
809 }
810
811 return bgp_dump_unset(bgp_dump_struct);
812 }
813
814 static int config_write_bgp_dump(struct vty *vty);
815 /* BGP node structure. */
816 static struct cmd_node bgp_dump_node = {
817 .name = "dump",
818 .node = DUMP_NODE,
819 .prompt = "",
820 .config_write = config_write_bgp_dump,
821 };
822
823 static int config_write_bgp_dump(struct vty *vty)
824 {
825 if (bgp_dump_all.filename) {
826 const char *type_str = "all";
827 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
828 type_str = "all-et";
829
830 if (bgp_dump_all.interval_str)
831 vty_out(vty, "dump bgp %s %s %s\n", type_str,
832 bgp_dump_all.filename,
833 bgp_dump_all.interval_str);
834 else
835 vty_out(vty, "dump bgp %s %s\n", type_str,
836 bgp_dump_all.filename);
837 }
838 if (bgp_dump_updates.filename) {
839 const char *type_str = "updates";
840 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
841 type_str = "updates-et";
842
843 if (bgp_dump_updates.interval_str)
844 vty_out(vty, "dump bgp %s %s %s\n", type_str,
845 bgp_dump_updates.filename,
846 bgp_dump_updates.interval_str);
847 else
848 vty_out(vty, "dump bgp %s %s\n", type_str,
849 bgp_dump_updates.filename);
850 }
851 if (bgp_dump_routes.filename) {
852 if (bgp_dump_routes.interval_str)
853 vty_out(vty, "dump bgp routes-mrt %s %s\n",
854 bgp_dump_routes.filename,
855 bgp_dump_routes.interval_str);
856 else
857 vty_out(vty, "dump bgp routes-mrt %s\n",
858 bgp_dump_routes.filename);
859 }
860 return 0;
861 }
862
863 /* Initialize BGP packet dump functionality. */
864 void bgp_dump_init(void)
865 {
866 memset(&bgp_dump_all, 0, sizeof(struct bgp_dump));
867 memset(&bgp_dump_updates, 0, sizeof(struct bgp_dump));
868 memset(&bgp_dump_routes, 0, sizeof(struct bgp_dump));
869
870 bgp_dump_obuf =
871 stream_new((BGP_MAX_PACKET_SIZE << 1) + BGP_DUMP_MSG_HEADER
872 + BGP_DUMP_HEADER_SIZE);
873
874 install_node(&bgp_dump_node);
875
876 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
877 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
878
879 hook_register(bgp_packet_dump, bgp_dump_packet);
880 hook_register(peer_status_changed, bgp_dump_state);
881 }
882
883 void bgp_dump_finish(void)
884 {
885 bgp_dump_unset(&bgp_dump_all);
886 bgp_dump_unset(&bgp_dump_updates);
887 bgp_dump_unset(&bgp_dump_routes);
888
889 stream_free(bgp_dump_obuf);
890 bgp_dump_obuf = NULL;
891 hook_unregister(bgp_packet_dump, bgp_dump_packet);
892 hook_unregister(peer_status_changed, bgp_dump_state);
893 }