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