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