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