]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
Merge pull request #6625 from ton31337/fix/network_check_import_for_static_bgp
[mirror_frr.git] / bgpd / bgp_dump.c
CommitLineData
718e3744 1/* BGP-4 dump routine
896014f4
DL
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 */
718e3744 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"
0b2aa3a0 29#include "linklist.h"
3f9c7369 30#include "queue.h"
6e919709 31#include "memory.h"
039f3a34 32#include "filter.h"
3f9c7369 33
718e3744 34#include "bgpd/bgp_table.h"
718e3744 35#include "bgpd/bgpd.h"
36#include "bgpd/bgp_route.h"
37#include "bgpd/bgp_attr.h"
38#include "bgpd/bgp_dump.h"
7077f45c 39#include "bgpd/bgp_errors.h"
584470fb 40#include "bgpd/bgp_packet.h"
6b0655a2 41
d62a17ae 42enum 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
718e3744 48};
49
4db5d90a 50static const struct bgp_dump_type_map {
d62a17ae 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};
4db5d90a 58
718e3744 59enum MRT_MSG_TYPES {
d62a17ae 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 */
718e3744 74};
75
d62a17ae 76struct bgp_dump {
77 enum bgp_dump_type type;
718e3744 78
d62a17ae 79 char *filename;
718e3744 80
d62a17ae 81 FILE *fp;
718e3744 82
d62a17ae 83 unsigned int interval;
718e3744 84
d62a17ae 85 char *interval_str;
718e3744 86
d62a17ae 87 struct thread *t_interval;
718e3744 88};
89
d62a17ae 90static int bgp_dump_unset(struct bgp_dump *bgp_dump);
91static int bgp_dump_interval_func(struct thread *);
4db5d90a 92
718e3744 93/* BGP packet dump output buffer. */
94struct stream *bgp_dump_obuf;
95
96/* BGP dump strucuture for 'dump bgp all' */
97struct bgp_dump bgp_dump_all;
98
99/* BGP dump structure for 'dump bgp updates' */
100struct bgp_dump bgp_dump_updates;
101
102/* BGP dump structure for 'dump bgp routes' */
103struct bgp_dump bgp_dump_routes;
104
d62a17ae 105static FILE *bgp_dump_open_file(struct bgp_dump *bgp_dump)
718e3744 106{
d62a17ae 107 int ret;
108 time_t clock;
a2700b50 109 struct tm tm;
d62a17ae 110 char fullpath[MAXPATHLEN];
111 char realpath[MAXPATHLEN];
112 mode_t oldumask;
113
114 time(&clock);
a2700b50 115 localtime_r(&clock, &tm);
d62a17ae 116
117 if (bgp_dump->filename[0] != DIRECTORY_SEP) {
772270f3
QY
118 snprintf(fullpath, sizeof(fullpath), "%s/%s", vty_get_cwd(),
119 bgp_dump->filename);
a2700b50 120 ret = strftime(realpath, MAXPATHLEN, fullpath, &tm);
d62a17ae 121 } else
a2700b50 122 ret = strftime(realpath, MAXPATHLEN, bgp_dump->filename, &tm);
d62a17ae 123
124 if (ret == 0) {
e50f7cfd 125 flog_warn(EC_BGP_DUMP, "bgp_dump_open_file: strftime error");
d62a17ae 126 return NULL;
127 }
718e3744 128
d62a17ae 129 if (bgp_dump->fp)
130 fclose(bgp_dump->fp);
718e3744 131
132
d62a17ae 133 oldumask = umask(0777 & ~LOGFILE_MASK);
134 bgp_dump->fp = fopen(realpath, "w");
718e3744 135
d62a17ae 136 if (bgp_dump->fp == NULL) {
e50f7cfd 137 flog_warn(EC_BGP_DUMP, "bgp_dump_open_file: %s: %s", realpath,
d62a17ae 138 strerror(errno));
139 umask(oldumask);
140 return NULL;
141 }
142 umask(oldumask);
718e3744 143
d62a17ae 144 return bgp_dump->fp;
718e3744 145}
146
d62a17ae 147static int bgp_dump_interval_add(struct bgp_dump *bgp_dump, int interval)
718e3744 148{
d62a17ae 149 int secs_into_day;
150 time_t t;
a2700b50 151 struct tm tm;
d62a17ae 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);
a2700b50
MS
162 localtime_r(&t, &tm);
163 secs_into_day = tm.tm_sec + 60 * tm.tm_min
164 + 60 * 60 * tm.tm_hour;
d62a17ae 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);
9834cd0f 177 }
fba3d22b 178
d62a17ae 179 return 0;
718e3744 180}
181
182/* Dump common header. */
d62a17ae 183static void bgp_dump_header(struct stream *obuf, int type, int subtype,
184 int dump_type)
718e3744 185{
d62a17ae 186 struct timeval clock;
187 long msecs;
188 time_t secs;
4db5d90a 189
d62a17ae 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;
4db5d90a 193
d62a17ae 194 gettimeofday(&clock, NULL);
718e3744 195
d62a17ae 196 secs = clock.tv_sec;
197 msecs = clock.tv_usec;
718e3744 198
d62a17ae 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 */
4db5d90a 204
d62a17ae 205 /* Adding microseconds for the MRT Extended Header */
206 if (type == MSG_PROTOCOL_BGP4MP_ET)
207 stream_putl(obuf, msecs);
718e3744 208}
209
d62a17ae 210static void bgp_dump_set_size(struct stream *s, int type)
718e3744 211{
d62a17ae 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);
718e3744 218}
219
d62a17ae 220static void bgp_dump_routes_index_table(struct bgp *bgp)
718e3744 221{
d62a17ae 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 */
8c1a4c10
DS
238 if (bgp->name_pretty) {
239 stream_putw(obuf, strlen(bgp->name_pretty));
240 stream_put(obuf, bgp->name_pretty, strlen(bgp->name_pretty));
d62a17ae 241 } else {
242 stream_putw(obuf, 0);
243 }
718e3744 244
d62a17ae 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) */
9d303b37
DL
250 stream_putc(obuf,
251 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
252 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
d62a17ae 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) {
d7c0a89a 283 stream_write(obuf, (uint8_t *)&peer->su.sin6.sin6_addr,
d62a17ae 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 }
718e3744 296
d62a17ae 297 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
718e3744 298
d62a17ae 299 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
300 fflush(bgp_dump_routes.fp);
718e3744 301}
302
0b2aa3a0 303
4b7e6066
DS
304static struct bgp_path_info *
305bgp_dump_route_node_record(int afi, struct bgp_node *rn,
40381db7 306 struct bgp_path_info *path, unsigned int seq)
246556b5 307{
d62a17ae 308 struct stream *obuf;
309 size_t sizep;
310 size_t endp;
b54892e0 311 const struct prefix *p = bgp_node_get_prefix(rn);
d62a17ae 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 */
b54892e0 330 stream_putc(obuf, p->prefixlen);
d62a17ae 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 */
b54892e0
DS
336 stream_write(obuf, (uint8_t *)&p->u.prefix4,
337 (p->prefixlen + 7) / 8);
d62a17ae 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 */
b54892e0
DS
341 stream_write(obuf, (uint8_t *)&p->u.prefix6,
342 (p->prefixlen + 7) / 8);
d62a17ae 343 }
246556b5 344
d62a17ae 345 /* Save where we are now, so we can overwride the entry count later */
346 sizep = stream_get_endp(obuf);
246556b5 347
d62a17ae 348 /* Entry count */
349 uint16_t entry_count = 0;
246556b5 350
d62a17ae 351 /* Entry count, note that this is overwritten later */
352 stream_putw(obuf, 0);
246556b5 353
d62a17ae 354 endp = stream_get_endp(obuf);
40381db7 355 for (; path; path = path->next) {
d62a17ae 356 size_t cur_endp;
246556b5 357
d62a17ae 358 /* Peer index */
40381db7 359 stream_putw(obuf, path->peer->table_dump_index);
246556b5 360
d62a17ae 361 /* Originated */
40381db7 362 stream_putl(obuf, time(NULL) - (bgp_clock() - path->uptime));
246556b5 363
d62a17ae 364 /* Dump attribute. */
365 /* Skip prefix & AFI/SAFI for MP_NLRI */
b54892e0 366 bgp_dump_routes_attr(obuf, path->attr, p);
246556b5 367
d62a17ae 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 }
246556b5 374
d62a17ae 375 entry_count++;
376 endp = cur_endp;
377 }
246556b5 378
d62a17ae 379 /* Overwrite the entry count, now that we know the right number */
380 stream_putw_at(obuf, sizep, entry_count);
246556b5 381
d62a17ae 382 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
383 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
246556b5 384
40381db7 385 return path;
246556b5
EU
386}
387
388
718e3744 389/* Runs under child process. */
d62a17ae 390static unsigned int bgp_dump_routes_func(int afi, int first_run,
391 unsigned int seq)
718e3744 392{
40381db7 393 struct bgp_path_info *path;
d62a17ae 394 struct bgp_node *rn;
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 (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
6f94b685 416 path = bgp_node_get_bgp_path_info(rn);
40381db7
DS
417 while (path) {
418 path = bgp_dump_route_node_record(afi, rn, path, seq);
d62a17ae 419 seq++;
420 }
421 }
0b2aa3a0 422
d62a17ae 423 fflush(bgp_dump_routes.fp);
0b2aa3a0 424
d62a17ae 425 return seq;
718e3744 426}
427
d62a17ae 428static int bgp_dump_interval_func(struct thread *t)
718e3744 429{
d62a17ae 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 }
9834cd0f 447 }
718e3744 448
d62a17ae 449 /* if interval is set reschedule */
450 if (bgp_dump->interval > 0)
451 bgp_dump_interval_add(bgp_dump, bgp_dump->interval);
fba3d22b 452
d62a17ae 453 return 0;
718e3744 454}
455
456/* Dump common information. */
d62a17ae 457static void bgp_dump_common(struct stream *obuf, struct peer *peer,
458 int forceas4)
718e3744 459{
d62a17ae 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 }
718e3744 470
d62a17ae 471 if (peer->su.sa.sa_family == AF_INET) {
194a4f2c 472 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
d62a17ae 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. */
194a4f2c 484 stream_putw(obuf, peer->ifp ? peer->ifp->ifindex : 0);
d62a17ae 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 }
718e3744 496}
497
498/* Dump BGP status change. */
7d8d0eab 499int bgp_dump_state(struct peer *peer)
718e3744 500{
d62a17ae 501 struct stream *obuf;
718e3744 502
d62a17ae 503 /* If dump file pointer is disabled return immediately. */
504 if (bgp_dump_all.fp == NULL)
7d8d0eab 505 return 0;
718e3744 506
d62a17ae 507 /* Make dump stream. */
508 obuf = bgp_dump_obuf;
509 stream_reset(obuf);
718e3744 510
d62a17ae 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*/
718e3744 514
7d8d0eab
MKS
515 stream_putw(obuf, peer->ostatus);
516 stream_putw(obuf, peer->status);
718e3744 517
d62a17ae 518 /* Set length. */
519 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 520
d62a17ae 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);
7d8d0eab 524 return 0;
718e3744 525}
526
d62a17ae 527static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer,
528 struct stream *packet)
718e3744 529{
d62a17ae 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);
718e3744 549
d62a17ae 550 /* Packet contents. */
551 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
718e3744 552
d62a17ae 553 /* Set length. */
554 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 555
d62a17ae 556 /* Write to the stream. */
557 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
558 fflush(bgp_dump->fp);
718e3744 559}
560
561/* Called from bgp_packet.c when BGP packet is received. */
584470fb
DL
562static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
563 struct stream *packet)
718e3744 564{
d62a17ae 565 /* bgp_dump_all. */
566 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
718e3744 567
d62a17ae 568 /* bgp_dump_updates. */
569 if (type == BGP_MSG_UPDATE)
570 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
584470fb 571 return 0;
718e3744 572}
6b0655a2 573
d62a17ae 574static unsigned int bgp_dump_parse_time(const char *str)
718e3744 575{
d62a17ae 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++) {
fefa5e0f 590 if (isdigit((unsigned char)str[i])) {
d62a17ae 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;
718e3744 609 }
d62a17ae 610 return total + time;
718e3744 611}
612
d62a17ae 613static 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)
718e3744 616{
d62a17ae 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 }
718e3744 631 }
45ad592e 632
d62a17ae 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 }
718e3744 650
d62a17ae 651 /* Set type. */
652 bgp_dump->type = type;
718e3744 653
d62a17ae 654 /* Set interval */
655 bgp_dump->interval = interval;
4db5d90a 656
d62a17ae 657 /* Set file name. */
658 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
4db5d90a 659
d62a17ae 660 /* Create interval thread. */
661 bgp_dump_interval_add(bgp_dump, interval);
718e3744 662
d62a17ae 663 /* This should be called when interval is expired. */
664 bgp_dump_open_file(bgp_dump);
718e3744 665
d62a17ae 666 return CMD_SUCCESS;
718e3744 667}
668
d62a17ae 669static int bgp_dump_unset(struct bgp_dump *bgp_dump)
718e3744 670{
d62a17ae 671 /* Removing file name. */
e1b36e13 672 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
718e3744 673
d62a17ae 674 /* Closing file. */
675 if (bgp_dump->fp) {
676 fclose(bgp_dump->fp);
677 bgp_dump->fp = NULL;
678 }
718e3744 679
d62a17ae 680 /* Removing interval thread. */
681 if (bgp_dump->t_interval) {
682 thread_cancel(bgp_dump->t_interval);
683 bgp_dump->t_interval = NULL;
684 }
718e3744 685
d62a17ae 686 bgp_dump->interval = 0;
718e3744 687
d62a17ae 688 /* Removing interval string. */
e1b36e13 689 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
d62a17ae 690
691 return CMD_SUCCESS;
718e3744 692}
693
694DEFUN (dump_bgp_all,
695 dump_bgp_all_cmd,
6147e2c6 696 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
718e3744 697 "Dump packet\n"
698 "BGP packet dump\n"
cbac2b1b
EU
699 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
700 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
4db5d90a 701 "Dump whole BGP routing table\n"
718e3744 702 "Output filename\n"
703 "Interval of output\n")
704{
d62a17ae 705 int idx_dump_routes = 2;
706 int idx_path = 3;
707 int idx_interval = 4;
708 int bgp_dump_type = 0;
709 const char *interval = NULL;
710 struct bgp_dump *bgp_dump_struct = NULL;
711 const struct bgp_dump_type_map *map = NULL;
712
713 for (map = bgp_dump_type_map; map->str; map++)
714 if (strmatch(argv[idx_dump_routes]->text, map->str))
715 bgp_dump_type = map->type;
716
717 switch (bgp_dump_type) {
718 case BGP_DUMP_ALL:
719 case BGP_DUMP_ALL_ET:
720 bgp_dump_struct = &bgp_dump_all;
721 break;
722 case BGP_DUMP_UPDATES:
723 case BGP_DUMP_UPDATES_ET:
724 bgp_dump_struct = &bgp_dump_updates;
725 break;
726 case BGP_DUMP_ROUTES:
727 default:
728 bgp_dump_struct = &bgp_dump_routes;
729 break;
730 }
718e3744 731
d62a17ae 732 /* When an interval is given */
733 if (argc == idx_interval + 1)
734 interval = argv[idx_interval]->arg;
718e3744 735
d62a17ae 736 return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
737 argv[idx_path]->arg, interval);
718e3744 738}
739
4db5d90a
AF
740DEFUN (no_dump_bgp_all,
741 no_dump_bgp_all_cmd,
37bc45eb 742 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
718e3744 743 NO_STR
4db5d90a
AF
744 "Stop dump packet\n"
745 "Stop BGP packet dump\n"
ca492402
DS
746 "Stop dump process all\n"
747 "Stop dump process all-et\n"
748 "Stop dump process updates\n"
749 "Stop dump process updates-et\n"
3a2d747c
QY
750 "Stop dump process route-mrt\n"
751 "Output filename\n"
752 "Interval of output\n")
718e3744 753{
d62a17ae 754 int idx_dump_routes = 3;
755 int bgp_dump_type = 0;
756 const struct bgp_dump_type_map *map = NULL;
757 struct bgp_dump *bgp_dump_struct = NULL;
758
759 for (map = bgp_dump_type_map; map->str; map++)
760 if (strmatch(argv[idx_dump_routes]->text, map->str))
761 bgp_dump_type = map->type;
762
763 switch (bgp_dump_type) {
764 case BGP_DUMP_ALL:
765 case BGP_DUMP_ALL_ET:
766 bgp_dump_struct = &bgp_dump_all;
767 break;
768 case BGP_DUMP_UPDATES:
769 case BGP_DUMP_UPDATES_ET:
770 bgp_dump_struct = &bgp_dump_updates;
771 break;
772 case BGP_DUMP_ROUTES:
773 default:
774 bgp_dump_struct = &bgp_dump_routes;
775 break;
776 }
ca492402 777
d62a17ae 778 return bgp_dump_unset(bgp_dump_struct);
718e3744 779}
780
612c2c15 781static int config_write_bgp_dump(struct vty *vty);
718e3744 782/* BGP node structure. */
62b346ee 783static struct cmd_node bgp_dump_node = {
f4b8291f 784 .name = "dump",
62b346ee
DL
785 .node = DUMP_NODE,
786 .prompt = "",
612c2c15 787 .config_write = config_write_bgp_dump,
62b346ee 788};
718e3744 789
d62a17ae 790static int config_write_bgp_dump(struct vty *vty)
718e3744 791{
d62a17ae 792 if (bgp_dump_all.filename) {
793 const char *type_str = "all";
794 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
795 type_str = "all-et";
796
797 if (bgp_dump_all.interval_str)
798 vty_out(vty, "dump bgp %s %s %s\n", type_str,
799 bgp_dump_all.filename,
800 bgp_dump_all.interval_str);
801 else
802 vty_out(vty, "dump bgp %s %s\n", type_str,
803 bgp_dump_all.filename);
804 }
805 if (bgp_dump_updates.filename) {
806 const char *type_str = "updates";
807 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
808 type_str = "updates-et";
809
810 if (bgp_dump_updates.interval_str)
811 vty_out(vty, "dump bgp %s %s %s\n", type_str,
812 bgp_dump_updates.filename,
813 bgp_dump_updates.interval_str);
814 else
815 vty_out(vty, "dump bgp %s %s\n", type_str,
816 bgp_dump_updates.filename);
817 }
818 if (bgp_dump_routes.filename) {
819 if (bgp_dump_routes.interval_str)
820 vty_out(vty, "dump bgp routes-mrt %s %s\n",
821 bgp_dump_routes.filename,
822 bgp_dump_routes.interval_str);
823 else
824 vty_out(vty, "dump bgp routes-mrt %s\n",
825 bgp_dump_routes.filename);
826 }
827 return 0;
718e3744 828}
6b0655a2 829
718e3744 830/* Initialize BGP packet dump functionality. */
d62a17ae 831void bgp_dump_init(void)
718e3744 832{
d62a17ae 833 memset(&bgp_dump_all, 0, sizeof(struct bgp_dump));
834 memset(&bgp_dump_updates, 0, sizeof(struct bgp_dump));
835 memset(&bgp_dump_routes, 0, sizeof(struct bgp_dump));
718e3744 836
d62a17ae 837 bgp_dump_obuf =
838 stream_new((BGP_MAX_PACKET_SIZE << 1) + BGP_DUMP_MSG_HEADER
839 + BGP_DUMP_HEADER_SIZE);
718e3744 840
612c2c15 841 install_node(&bgp_dump_node);
718e3744 842
d62a17ae 843 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
844 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
584470fb
DL
845
846 hook_register(bgp_packet_dump, bgp_dump_packet);
7d8d0eab 847 hook_register(peer_status_changed, bgp_dump_state);
718e3744 848}
228da428 849
d62a17ae 850void bgp_dump_finish(void)
228da428 851{
d62a17ae 852 bgp_dump_unset(&bgp_dump_all);
853 bgp_dump_unset(&bgp_dump_updates);
854 bgp_dump_unset(&bgp_dump_routes);
b8438f6d 855
d62a17ae 856 stream_free(bgp_dump_obuf);
857 bgp_dump_obuf = NULL;
376d7c50 858 hook_unregister(bgp_packet_dump, bgp_dump_packet);
7d8d0eab 859 hook_unregister(peer_status_changed, bgp_dump_state);
228da428 860}