]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_dump.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_dump.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
718e3744 2/* BGP-4 dump routine
896014f4 3 * Copyright (C) 1999 Kunihiro Ishiguro
896014f4 4 */
718e3744 5
6#include <zebra.h>
7
8#include "log.h"
9#include "stream.h"
10#include "sockunion.h"
11#include "command.h"
12#include "prefix.h"
13#include "thread.h"
0b2aa3a0 14#include "linklist.h"
3f9c7369 15#include "queue.h"
6e919709 16#include "memory.h"
039f3a34 17#include "filter.h"
3f9c7369 18
718e3744 19#include "bgpd/bgp_table.h"
718e3744 20#include "bgpd/bgpd.h"
21#include "bgpd/bgp_route.h"
22#include "bgpd/bgp_attr.h"
23#include "bgpd/bgp_dump.h"
7077f45c 24#include "bgpd/bgp_errors.h"
584470fb 25#include "bgpd/bgp_packet.h"
6b0655a2 26
d62a17ae 27enum bgp_dump_type {
28 BGP_DUMP_ALL,
29 BGP_DUMP_ALL_ET,
30 BGP_DUMP_UPDATES,
31 BGP_DUMP_UPDATES_ET,
32 BGP_DUMP_ROUTES
718e3744 33};
34
4db5d90a 35static const struct bgp_dump_type_map {
d62a17ae 36 enum bgp_dump_type type;
37 const char *str;
38} bgp_dump_type_map[] = {
39 {BGP_DUMP_ALL, "all"}, {BGP_DUMP_ALL_ET, "all-et"},
40 {BGP_DUMP_UPDATES, "updates"}, {BGP_DUMP_UPDATES_ET, "updates-et"},
41 {BGP_DUMP_ROUTES, "routes-mrt"}, {0, NULL},
42};
4db5d90a 43
718e3744 44enum MRT_MSG_TYPES {
d62a17ae 45 MSG_NULL,
46 MSG_START, /* sender is starting up */
47 MSG_DIE, /* receiver should shut down */
48 MSG_I_AM_DEAD, /* sender is shutting down */
49 MSG_PEER_DOWN, /* sender's peer is down */
50 MSG_PROTOCOL_BGP, /* msg is a BGP packet */
51 MSG_PROTOCOL_RIP, /* msg is a RIP packet */
52 MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */
53 MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */
54 MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */
55 MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
56 MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */
57 MSG_TABLE_DUMP, /* routing table dump */
58 MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */
718e3744 59};
60
d62a17ae 61struct bgp_dump {
62 enum bgp_dump_type type;
718e3744 63
d62a17ae 64 char *filename;
718e3744 65
d62a17ae 66 FILE *fp;
718e3744 67
d62a17ae 68 unsigned int interval;
718e3744 69
d62a17ae 70 char *interval_str;
718e3744 71
d62a17ae 72 struct thread *t_interval;
718e3744 73};
74
d62a17ae 75static int bgp_dump_unset(struct bgp_dump *bgp_dump);
cc9f21da 76static void bgp_dump_interval_func(struct thread *);
4db5d90a 77
718e3744 78/* BGP packet dump output buffer. */
79struct stream *bgp_dump_obuf;
80
81/* BGP dump strucuture for 'dump bgp all' */
82struct bgp_dump bgp_dump_all;
83
84/* BGP dump structure for 'dump bgp updates' */
85struct bgp_dump bgp_dump_updates;
86
87/* BGP dump structure for 'dump bgp routes' */
88struct bgp_dump bgp_dump_routes;
89
d62a17ae 90static FILE *bgp_dump_open_file(struct bgp_dump *bgp_dump)
718e3744 91{
d62a17ae 92 int ret;
93 time_t clock;
a2700b50 94 struct tm tm;
d62a17ae 95 char fullpath[MAXPATHLEN];
96 char realpath[MAXPATHLEN];
97 mode_t oldumask;
98
99 time(&clock);
a2700b50 100 localtime_r(&clock, &tm);
d62a17ae 101
102 if (bgp_dump->filename[0] != DIRECTORY_SEP) {
772270f3
QY
103 snprintf(fullpath, sizeof(fullpath), "%s/%s", vty_get_cwd(),
104 bgp_dump->filename);
c84e5187
DL
105#pragma GCC diagnostic push
106#pragma GCC diagnostic ignored "-Wformat-nonliteral"
107 /* user supplied date/time format string */
a2700b50 108 ret = strftime(realpath, MAXPATHLEN, fullpath, &tm);
d62a17ae 109 } else
a2700b50 110 ret = strftime(realpath, MAXPATHLEN, bgp_dump->filename, &tm);
c84e5187 111#pragma GCC diagnostic pop
d62a17ae 112
113 if (ret == 0) {
a10c2872 114 flog_warn(EC_BGP_DUMP, "%s: strftime error", __func__);
d62a17ae 115 return NULL;
116 }
718e3744 117
d62a17ae 118 if (bgp_dump->fp)
119 fclose(bgp_dump->fp);
718e3744 120
121
d62a17ae 122 oldumask = umask(0777 & ~LOGFILE_MASK);
123 bgp_dump->fp = fopen(realpath, "w");
718e3744 124
d62a17ae 125 if (bgp_dump->fp == NULL) {
a10c2872 126 flog_warn(EC_BGP_DUMP, "%s: %s: %s", __func__, realpath,
d62a17ae 127 strerror(errno));
128 umask(oldumask);
129 return NULL;
130 }
131 umask(oldumask);
718e3744 132
d62a17ae 133 return bgp_dump->fp;
718e3744 134}
135
d62a17ae 136static int bgp_dump_interval_add(struct bgp_dump *bgp_dump, int interval)
718e3744 137{
d62a17ae 138 int secs_into_day;
139 time_t t;
a2700b50 140 struct tm tm;
d62a17ae 141
142 if (interval > 0) {
143 /* Periodic dump every interval seconds */
144 if ((interval < 86400) && ((86400 % interval) == 0)) {
145 /* Dump at predictable times: if a day has a whole
146 * number of
147 * intervals, dump every interval seconds starting from
148 * midnight
149 */
150 (void)time(&t);
a2700b50
MS
151 localtime_r(&t, &tm);
152 secs_into_day = tm.tm_sec + 60 * tm.tm_min
153 + 60 * 60 * tm.tm_hour;
d62a17ae 154 interval = interval
155 - secs_into_day % interval; /* always > 0 */
156 }
d62a17ae 157 thread_add_timer(bm->master, bgp_dump_interval_func, bgp_dump,
158 interval, &bgp_dump->t_interval);
159 } else {
160 /* One-off dump: execute immediately, don't affect any scheduled
161 * dumps */
d62a17ae 162 thread_add_event(bm->master, bgp_dump_interval_func, bgp_dump,
163 0, &bgp_dump->t_interval);
9834cd0f 164 }
fba3d22b 165
d62a17ae 166 return 0;
718e3744 167}
168
169/* Dump common header. */
d62a17ae 170static void bgp_dump_header(struct stream *obuf, int type, int subtype,
171 int dump_type)
718e3744 172{
d62a17ae 173 struct timeval clock;
174 long msecs;
175 time_t secs;
4db5d90a 176
d62a17ae 177 if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET)
178 && type == MSG_PROTOCOL_BGP4MP)
179 type = MSG_PROTOCOL_BGP4MP_ET;
4db5d90a 180
d62a17ae 181 gettimeofday(&clock, NULL);
718e3744 182
d62a17ae 183 secs = clock.tv_sec;
184 msecs = clock.tv_usec;
718e3744 185
d62a17ae 186 /* Put dump packet header. */
187 stream_putl(obuf, secs);
188 stream_putw(obuf, type);
189 stream_putw(obuf, subtype);
190 stream_putl(obuf, 0); /* len */
4db5d90a 191
d62a17ae 192 /* Adding microseconds for the MRT Extended Header */
193 if (type == MSG_PROTOCOL_BGP4MP_ET)
194 stream_putl(obuf, msecs);
718e3744 195}
196
d62a17ae 197static void bgp_dump_set_size(struct stream *s, int type)
718e3744 198{
d62a17ae 199 /*
200 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
201 * "The Microsecond Timestamp is included in the computation
202 * of the Length field value." (RFC6396 2011)
203 */
204 stream_putl_at(s, 8, stream_get_endp(s) - BGP_DUMP_HEADER_SIZE);
718e3744 205}
206
d62a17ae 207static void bgp_dump_routes_index_table(struct bgp *bgp)
718e3744 208{
d62a17ae 209 struct peer *peer;
210 struct listnode *node;
211 uint16_t peerno = 1;
212 struct stream *obuf;
213
214 obuf = bgp_dump_obuf;
215 stream_reset(obuf);
216
217 /* MRT header */
218 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE,
219 BGP_DUMP_ROUTES);
220
221 /* Collector BGP ID */
222 stream_put_in_addr(obuf, &bgp->router_id);
223
224 /* View name */
8c1a4c10
DS
225 if (bgp->name_pretty) {
226 stream_putw(obuf, strlen(bgp->name_pretty));
227 stream_put(obuf, bgp->name_pretty, strlen(bgp->name_pretty));
d62a17ae 228 } else {
229 stream_putw(obuf, 0);
230 }
718e3744 231
d62a17ae 232 /* Peer count ( plus one extra internal peer ) */
233 stream_putw(obuf, listcount(bgp->peer) + 1);
234
235 /* Populate fake peer at index 0, for locally originated routes */
236 /* Peer type (IPv4) */
9d303b37
DL
237 stream_putc(obuf,
238 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
239 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
d62a17ae 240 /* Peer BGP ID (0.0.0.0) */
241 stream_putl(obuf, 0);
242 /* Peer IP address (0.0.0.0) */
243 stream_putl(obuf, 0);
244 /* Peer ASN (0) */
245 stream_putl(obuf, 0);
246
247 /* Walk down all peers */
248 for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
249
250 /* Peer's type */
251 if (sockunion_family(&peer->su) == AF_INET) {
252 stream_putc(
253 obuf,
254 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
255 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
256 } else if (sockunion_family(&peer->su) == AF_INET6) {
257 stream_putc(
258 obuf,
259 TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4
260 + TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
261 }
262
263 /* Peer's BGP ID */
264 stream_put_in_addr(obuf, &peer->remote_id);
265
266 /* Peer's IP address */
267 if (sockunion_family(&peer->su) == AF_INET) {
268 stream_put_in_addr(obuf, &peer->su.sin.sin_addr);
269 } else if (sockunion_family(&peer->su) == AF_INET6) {
d7c0a89a 270 stream_write(obuf, (uint8_t *)&peer->su.sin6.sin6_addr,
d62a17ae 271 IPV6_MAX_BYTELEN);
272 }
273
274 /* Peer's AS number. */
275 /* Note that, as this is an AS4 compliant quagga, the RIB is
276 * always AS4 */
277 stream_putl(obuf, peer->as);
278
279 /* Store the peer number for this peer */
280 peer->table_dump_index = peerno;
281 peerno++;
282 }
718e3744 283
d62a17ae 284 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
718e3744 285
d62a17ae 286 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
287 fflush(bgp_dump_routes.fp);
718e3744 288}
289
4b7e6066 290static struct bgp_path_info *
9bcb3eef 291bgp_dump_route_node_record(int afi, struct bgp_dest *dest,
40381db7 292 struct bgp_path_info *path, unsigned int seq)
246556b5 293{
d62a17ae 294 struct stream *obuf;
295 size_t sizep;
296 size_t endp;
be92fc9f 297 bool addpath_capable;
9bcb3eef 298 const struct prefix *p = bgp_dest_get_prefix(dest);
d62a17ae 299
300 obuf = bgp_dump_obuf;
301 stream_reset(obuf);
302
be92fc9f 303 addpath_capable = bgp_addpath_encode_rx(path->peer, afi, SAFI_UNICAST);
1073f44d 304
d62a17ae 305 /* MRT header */
be92fc9f 306 if (afi == AFI_IP && addpath_capable)
1073f44d
DT
307 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
308 TABLE_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH,
309 BGP_DUMP_ROUTES);
310 else if (afi == AFI_IP)
d62a17ae 311 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
312 TABLE_DUMP_V2_RIB_IPV4_UNICAST,
313 BGP_DUMP_ROUTES);
be92fc9f 314 else if (afi == AFI_IP6 && addpath_capable)
1073f44d
DT
315 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
316 TABLE_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH,
317 BGP_DUMP_ROUTES);
d62a17ae 318 else if (afi == AFI_IP6)
319 bgp_dump_header(obuf, MSG_TABLE_DUMP_V2,
320 TABLE_DUMP_V2_RIB_IPV6_UNICAST,
321 BGP_DUMP_ROUTES);
322
323 /* Sequence number */
324 stream_putl(obuf, seq);
325
326 /* Prefix length */
b54892e0 327 stream_putc(obuf, p->prefixlen);
d62a17ae 328
329 /* Prefix */
330 if (afi == AFI_IP) {
331 /* We'll dump only the useful bits (those not 0), but have to
332 * align on 8 bits */
b54892e0
DS
333 stream_write(obuf, (uint8_t *)&p->u.prefix4,
334 (p->prefixlen + 7) / 8);
d62a17ae 335 } else if (afi == AFI_IP6) {
336 /* We'll dump only the useful bits (those not 0), but have to
337 * align on 8 bits */
b54892e0
DS
338 stream_write(obuf, (uint8_t *)&p->u.prefix6,
339 (p->prefixlen + 7) / 8);
d62a17ae 340 }
246556b5 341
d62a17ae 342 /* Save where we are now, so we can overwride the entry count later */
343 sizep = stream_get_endp(obuf);
246556b5 344
d62a17ae 345 /* Entry count */
346 uint16_t entry_count = 0;
246556b5 347
d62a17ae 348 /* Entry count, note that this is overwritten later */
349 stream_putw(obuf, 0);
246556b5 350
d62a17ae 351 endp = stream_get_endp(obuf);
40381db7 352 for (; path; path = path->next) {
d62a17ae 353 size_t cur_endp;
246556b5 354
d62a17ae 355 /* Peer index */
40381db7 356 stream_putw(obuf, path->peer->table_dump_index);
246556b5 357
d62a17ae 358 /* Originated */
083ec940 359 stream_putl(obuf, time(NULL) - (monotime(NULL) - path->uptime));
246556b5 360
1073f44d 361 /*Path Identifier*/
be92fc9f 362 if (addpath_capable) {
1073f44d
DT
363 stream_putl(obuf, path->addpath_rx_id);
364 }
365
d62a17ae 366 /* Dump attribute. */
367 /* Skip prefix & AFI/SAFI for MP_NLRI */
97a52c82 368 bgp_dump_routes_attr(obuf, path, p);
246556b5 369
d62a17ae 370 cur_endp = stream_get_endp(obuf);
556beacf
QY
371 if (cur_endp > BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
372 + BGP_DUMP_MSG_HEADER
d62a17ae 373 + BGP_DUMP_HEADER_SIZE) {
374 stream_set_endp(obuf, endp);
375 break;
376 }
246556b5 377
d62a17ae 378 entry_count++;
379 endp = cur_endp;
380 }
246556b5 381
d62a17ae 382 /* Overwrite the entry count, now that we know the right number */
383 stream_putw_at(obuf, sizep, entry_count);
246556b5 384
d62a17ae 385 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
386 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_routes.fp);
246556b5 387
40381db7 388 return path;
246556b5
EU
389}
390
391
718e3744 392/* Runs under child process. */
d62a17ae 393static unsigned int bgp_dump_routes_func(int afi, int first_run,
394 unsigned int seq)
718e3744 395{
40381db7 396 struct bgp_path_info *path;
9bcb3eef 397 struct bgp_dest *dest;
d62a17ae 398 struct bgp *bgp;
399 struct bgp_table *table;
400
401 bgp = bgp_get_default();
402 if (!bgp)
403 return seq;
404
405 if (bgp_dump_routes.fp == NULL)
406 return seq;
407
408 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
409 so this should only be done on the first call to
410 bgp_dump_routes_func.
411 ( this function will be called once for ipv4 and once for ipv6 ) */
412 if (first_run)
413 bgp_dump_routes_index_table(bgp);
414
415 /* Walk down each BGP route. */
416 table = bgp->rib[afi][SAFI_UNICAST];
417
9bcb3eef
DS
418 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
419 path = bgp_dest_get_bgp_path_info(dest);
40381db7 420 while (path) {
9bcb3eef 421 path = bgp_dump_route_node_record(afi, dest, path, seq);
d62a17ae 422 seq++;
423 }
424 }
0b2aa3a0 425
d62a17ae 426 fflush(bgp_dump_routes.fp);
0b2aa3a0 427
d62a17ae 428 return seq;
718e3744 429}
430
cc9f21da 431static void bgp_dump_interval_func(struct thread *t)
718e3744 432{
d62a17ae 433 struct bgp_dump *bgp_dump;
434 bgp_dump = THREAD_ARG(t);
d62a17ae 435
436 /* Reschedule dump even if file couldn't be opened this time... */
437 if (bgp_dump_open_file(bgp_dump) != NULL) {
438 /* In case of bgp_dump_routes, we need special route dump
439 * function. */
440 if (bgp_dump->type == BGP_DUMP_ROUTES) {
441 unsigned int seq = bgp_dump_routes_func(AFI_IP, 1, 0);
442 bgp_dump_routes_func(AFI_IP6, 0, seq);
443 /* Close the file now. For a RIB dump there's no point
444 * in leaving
445 * it open until the next scheduled dump starts. */
446 fclose(bgp_dump->fp);
447 bgp_dump->fp = NULL;
448 }
9834cd0f 449 }
718e3744 450
d62a17ae 451 /* if interval is set reschedule */
452 if (bgp_dump->interval > 0)
453 bgp_dump_interval_add(bgp_dump, bgp_dump->interval);
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;
be92fc9f 531 bool addpath_capable = false;
d62a17ae 532 /* If dump file pointer is disabled return immediately. */
533 if (bgp_dump->fp == NULL)
534 return;
1073f44d 535 if (peer->su.sa.sa_family == AF_INET) {
be92fc9f 536 addpath_capable =
1073f44d
DT
537 bgp_addpath_encode_rx(peer, AFI_IP, SAFI_UNICAST);
538 } else if (peer->su.sa.sa_family == AF_INET6) {
be92fc9f 539 addpath_capable =
1073f44d
DT
540 bgp_addpath_encode_rx(peer, AFI_IP6, SAFI_UNICAST);
541 }
d62a17ae 542
543 /* Make dump stream. */
544 obuf = bgp_dump_obuf;
545 stream_reset(obuf);
546
547 /* Dump header and common part. */
be92fc9f 548 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) && addpath_capable) {
1073f44d
DT
549 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP,
550 BGP4MP_MESSAGE_AS4_ADDPATH, bgp_dump->type);
551 } else if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
d62a17ae 552 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
553 bgp_dump->type);
be92fc9f 554 } else if (addpath_capable) {
1073f44d
DT
555 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP,
556 BGP4MP_MESSAGE_ADDPATH, bgp_dump->type);
d62a17ae 557 } else {
558 bgp_dump_header(obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
559 bgp_dump->type);
560 }
561 bgp_dump_common(obuf, peer, 0);
718e3744 562
d62a17ae 563 /* Packet contents. */
564 stream_put(obuf, STREAM_DATA(packet), stream_get_endp(packet));
718e3744 565
d62a17ae 566 /* Set length. */
567 bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP);
718e3744 568
d62a17ae 569 /* Write to the stream. */
570 fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump->fp);
571 fflush(bgp_dump->fp);
718e3744 572}
573
574/* Called from bgp_packet.c when BGP packet is received. */
584470fb
DL
575static int bgp_dump_packet(struct peer *peer, uint8_t type, bgp_size_t size,
576 struct stream *packet)
718e3744 577{
d62a17ae 578 /* bgp_dump_all. */
579 bgp_dump_packet_func(&bgp_dump_all, peer, packet);
718e3744 580
d62a17ae 581 /* bgp_dump_updates. */
582 if (type == BGP_MSG_UPDATE)
583 bgp_dump_packet_func(&bgp_dump_updates, peer, packet);
584470fb 584 return 0;
718e3744 585}
6b0655a2 586
d62a17ae 587static unsigned int bgp_dump_parse_time(const char *str)
718e3744 588{
d62a17ae 589 int i;
590 int len;
591 int seen_h;
592 int seen_m;
593 int time;
594 unsigned int total;
595
596 time = 0;
597 total = 0;
598 seen_h = 0;
599 seen_m = 0;
600 len = strlen(str);
601
602 for (i = 0; i < len; i++) {
fefa5e0f 603 if (isdigit((unsigned char)str[i])) {
d62a17ae 604 time *= 10;
605 time += str[i] - '0';
606 } else if (str[i] == 'H' || str[i] == 'h') {
607 if (seen_h)
608 return 0;
609 if (seen_m)
610 return 0;
611 total += time * 60 * 60;
612 time = 0;
613 seen_h = 1;
614 } else if (str[i] == 'M' || str[i] == 'm') {
615 if (seen_m)
616 return 0;
617 total += time * 60;
618 time = 0;
619 seen_m = 1;
620 } else
621 return 0;
718e3744 622 }
d62a17ae 623 return total + time;
718e3744 624}
625
d62a17ae 626static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
627 enum bgp_dump_type type, const char *path,
628 const char *interval_str)
718e3744 629{
d62a17ae 630 unsigned int interval;
631
632 /* Don't schedule duplicate dumps if the dump command is given twice */
633 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
634 && type == bgp_dump->type) {
635 if (interval_str) {
636 if (bgp_dump->interval_str
637 && strcmp(bgp_dump->interval_str, interval_str)
638 == 0)
639 return CMD_SUCCESS;
640 } else {
641 if (!bgp_dump->interval_str)
642 return CMD_SUCCESS;
643 }
718e3744 644 }
45ad592e 645
d62a17ae 646 /* Removing previous config */
647 bgp_dump_unset(bgp_dump);
648
649 if (interval_str) {
650 /* Check interval string. */
651 interval = bgp_dump_parse_time(interval_str);
652 if (interval == 0) {
653 vty_out(vty, "Malformed interval string\n");
654 return CMD_WARNING_CONFIG_FAILED;
655 }
656
657 /* Setting interval string */
658 bgp_dump->interval_str =
659 XSTRDUP(MTYPE_BGP_DUMP_STR, interval_str);
660 } else {
661 interval = 0;
662 }
718e3744 663
d62a17ae 664 /* Set type. */
665 bgp_dump->type = type;
718e3744 666
d62a17ae 667 /* Set interval */
668 bgp_dump->interval = interval;
4db5d90a 669
d62a17ae 670 /* Set file name. */
671 bgp_dump->filename = XSTRDUP(MTYPE_BGP_DUMP_STR, path);
4db5d90a 672
d62a17ae 673 /* Create interval thread. */
674 bgp_dump_interval_add(bgp_dump, interval);
718e3744 675
d62a17ae 676 /* This should be called when interval is expired. */
677 bgp_dump_open_file(bgp_dump);
718e3744 678
d62a17ae 679 return CMD_SUCCESS;
718e3744 680}
681
d62a17ae 682static int bgp_dump_unset(struct bgp_dump *bgp_dump)
718e3744 683{
d62a17ae 684 /* Removing file name. */
e1b36e13 685 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
718e3744 686
d62a17ae 687 /* Closing file. */
688 if (bgp_dump->fp) {
689 fclose(bgp_dump->fp);
690 bgp_dump->fp = NULL;
691 }
718e3744 692
b3d6bc6e 693 /* Removing interval event. */
c3aaa89a 694 THREAD_OFF(bgp_dump->t_interval);
718e3744 695
d62a17ae 696 bgp_dump->interval = 0;
718e3744 697
d62a17ae 698 /* Removing interval string. */
e1b36e13 699 XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
d62a17ae 700
701 return CMD_SUCCESS;
718e3744 702}
703
704DEFUN (dump_bgp_all,
705 dump_bgp_all_cmd,
6147e2c6 706 "dump bgp <all|all-et|updates|updates-et|routes-mrt> PATH [INTERVAL]",
718e3744 707 "Dump packet\n"
708 "BGP packet dump\n"
cbac2b1b
EU
709 "Dump all BGP packets\nDump all BGP packets (Extended Timestamp Header)\n"
710 "Dump BGP updates only\nDump BGP updates only (Extended Timestamp Header)\n"
4db5d90a 711 "Dump whole BGP routing table\n"
718e3744 712 "Output filename\n"
713 "Interval of output\n")
714{
d62a17ae 715 int idx_dump_routes = 2;
716 int idx_path = 3;
717 int idx_interval = 4;
718 int bgp_dump_type = 0;
719 const char *interval = NULL;
720 struct bgp_dump *bgp_dump_struct = NULL;
721 const struct bgp_dump_type_map *map = NULL;
722
723 for (map = bgp_dump_type_map; map->str; map++)
724 if (strmatch(argv[idx_dump_routes]->text, map->str))
725 bgp_dump_type = map->type;
726
727 switch (bgp_dump_type) {
728 case BGP_DUMP_ALL:
729 case BGP_DUMP_ALL_ET:
730 bgp_dump_struct = &bgp_dump_all;
731 break;
732 case BGP_DUMP_UPDATES:
733 case BGP_DUMP_UPDATES_ET:
734 bgp_dump_struct = &bgp_dump_updates;
735 break;
736 case BGP_DUMP_ROUTES:
737 default:
738 bgp_dump_struct = &bgp_dump_routes;
739 break;
740 }
718e3744 741
d62a17ae 742 /* When an interval is given */
743 if (argc == idx_interval + 1)
744 interval = argv[idx_interval]->arg;
718e3744 745
d62a17ae 746 return bgp_dump_set(vty, bgp_dump_struct, bgp_dump_type,
747 argv[idx_path]->arg, interval);
718e3744 748}
749
4db5d90a
AF
750DEFUN (no_dump_bgp_all,
751 no_dump_bgp_all_cmd,
37bc45eb 752 "no dump bgp <all|all-et|updates|updates-et|routes-mrt> [PATH [INTERVAL]]",
718e3744 753 NO_STR
4db5d90a
AF
754 "Stop dump packet\n"
755 "Stop BGP packet dump\n"
ca492402
DS
756 "Stop dump process all\n"
757 "Stop dump process all-et\n"
758 "Stop dump process updates\n"
759 "Stop dump process updates-et\n"
3a2d747c
QY
760 "Stop dump process route-mrt\n"
761 "Output filename\n"
762 "Interval of output\n")
718e3744 763{
d62a17ae 764 int idx_dump_routes = 3;
765 int bgp_dump_type = 0;
766 const struct bgp_dump_type_map *map = NULL;
767 struct bgp_dump *bgp_dump_struct = NULL;
768
769 for (map = bgp_dump_type_map; map->str; map++)
770 if (strmatch(argv[idx_dump_routes]->text, map->str))
771 bgp_dump_type = map->type;
772
773 switch (bgp_dump_type) {
774 case BGP_DUMP_ALL:
775 case BGP_DUMP_ALL_ET:
776 bgp_dump_struct = &bgp_dump_all;
777 break;
778 case BGP_DUMP_UPDATES:
779 case BGP_DUMP_UPDATES_ET:
780 bgp_dump_struct = &bgp_dump_updates;
781 break;
782 case BGP_DUMP_ROUTES:
783 default:
784 bgp_dump_struct = &bgp_dump_routes;
785 break;
786 }
ca492402 787
d62a17ae 788 return bgp_dump_unset(bgp_dump_struct);
718e3744 789}
790
612c2c15 791static int config_write_bgp_dump(struct vty *vty);
718e3744 792/* BGP node structure. */
62b346ee 793static struct cmd_node bgp_dump_node = {
f4b8291f 794 .name = "dump",
62b346ee
DL
795 .node = DUMP_NODE,
796 .prompt = "",
612c2c15 797 .config_write = config_write_bgp_dump,
62b346ee 798};
718e3744 799
d62a17ae 800static int config_write_bgp_dump(struct vty *vty)
718e3744 801{
d62a17ae 802 if (bgp_dump_all.filename) {
803 const char *type_str = "all";
804 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
805 type_str = "all-et";
806
807 if (bgp_dump_all.interval_str)
808 vty_out(vty, "dump bgp %s %s %s\n", type_str,
809 bgp_dump_all.filename,
810 bgp_dump_all.interval_str);
811 else
812 vty_out(vty, "dump bgp %s %s\n", type_str,
813 bgp_dump_all.filename);
814 }
815 if (bgp_dump_updates.filename) {
816 const char *type_str = "updates";
817 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
818 type_str = "updates-et";
819
820 if (bgp_dump_updates.interval_str)
821 vty_out(vty, "dump bgp %s %s %s\n", type_str,
822 bgp_dump_updates.filename,
823 bgp_dump_updates.interval_str);
824 else
825 vty_out(vty, "dump bgp %s %s\n", type_str,
826 bgp_dump_updates.filename);
827 }
828 if (bgp_dump_routes.filename) {
829 if (bgp_dump_routes.interval_str)
830 vty_out(vty, "dump bgp routes-mrt %s %s\n",
831 bgp_dump_routes.filename,
832 bgp_dump_routes.interval_str);
833 else
834 vty_out(vty, "dump bgp routes-mrt %s\n",
835 bgp_dump_routes.filename);
836 }
837 return 0;
718e3744 838}
6b0655a2 839
718e3744 840/* Initialize BGP packet dump functionality. */
d62a17ae 841void bgp_dump_init(void)
718e3744 842{
6006b807
DA
843 memset(&bgp_dump_all, 0, sizeof(bgp_dump_all));
844 memset(&bgp_dump_updates, 0, sizeof(bgp_dump_updates));
845 memset(&bgp_dump_routes, 0, sizeof(bgp_dump_routes));
718e3744 846
d62a17ae 847 bgp_dump_obuf =
556beacf
QY
848 stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE * 2)
849 + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
718e3744 850
612c2c15 851 install_node(&bgp_dump_node);
718e3744 852
d62a17ae 853 install_element(CONFIG_NODE, &dump_bgp_all_cmd);
854 install_element(CONFIG_NODE, &no_dump_bgp_all_cmd);
584470fb
DL
855
856 hook_register(bgp_packet_dump, bgp_dump_packet);
7d8d0eab 857 hook_register(peer_status_changed, bgp_dump_state);
718e3744 858}
228da428 859
d62a17ae 860void bgp_dump_finish(void)
228da428 861{
d62a17ae 862 bgp_dump_unset(&bgp_dump_all);
863 bgp_dump_unset(&bgp_dump_updates);
864 bgp_dump_unset(&bgp_dump_routes);
b8438f6d 865
d62a17ae 866 stream_free(bgp_dump_obuf);
867 bgp_dump_obuf = NULL;
376d7c50 868 hook_unregister(bgp_packet_dump, bgp_dump_packet);
7d8d0eab 869 hook_unregister(peer_status_changed, bgp_dump_state);
228da428 870}