blob: 3d88dee4bf74278f15162e22992e3bd91d34a16f [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP-4 dump routine
2 Copyright (C) 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
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"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000029#include "linklist.h"
paul718e3742002-12-13 20:15:29 +000030#include "bgpd/bgp_table.h"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_route.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_dump.h"
David Lamparter6b0655a2014-06-04 06:53:35 +020036
paul718e3742002-12-13 20:15:29 +000037enum bgp_dump_type
38{
39 BGP_DUMP_ALL,
40 BGP_DUMP_UPDATES,
41 BGP_DUMP_ROUTES
42};
43
44enum MRT_MSG_TYPES {
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 */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000057 MSG_TABLE_DUMP, /* routing table dump */
58 MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */
paul718e3742002-12-13 20:15:29 +000059};
60
paul1f8ae702005-09-09 23:49:49 +000061static int bgp_dump_interval_func (struct thread *);
62
paul718e3742002-12-13 20:15:29 +000063struct bgp_dump
64{
65 enum bgp_dump_type type;
66
67 char *filename;
68
69 FILE *fp;
70
71 unsigned int interval;
72
73 char *interval_str;
74
75 struct thread *t_interval;
76};
77
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
90/* Dump whole BGP table is very heavy process. */
91struct thread *t_bgp_dump_routes;
David Lamparter6b0655a2014-06-04 06:53:35 +020092
paul718e3742002-12-13 20:15:29 +000093/* Some define for BGP packet dump. */
paul94f2b392005-06-28 12:44:16 +000094static FILE *
paul718e3742002-12-13 20:15:29 +000095bgp_dump_open_file (struct bgp_dump *bgp_dump)
96{
97 int ret;
98 time_t clock;
99 struct tm *tm;
100 char fullpath[MAXPATHLEN];
101 char realpath[MAXPATHLEN];
gdtaa593d52003-12-22 20:15:53 +0000102 mode_t oldumask;
paul718e3742002-12-13 20:15:29 +0000103
104 time (&clock);
105 tm = localtime (&clock);
106
107 if (bgp_dump->filename[0] != DIRECTORY_SEP)
108 {
109 sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
110 ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
111 }
112 else
113 ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
114
115 if (ret == 0)
116 {
117 zlog_warn ("bgp_dump_open_file: strftime error");
118 return NULL;
119 }
120
121 if (bgp_dump->fp)
122 fclose (bgp_dump->fp);
123
124
gdtaa593d52003-12-22 20:15:53 +0000125 oldumask = umask(0777 & ~LOGFILE_MASK);
paul718e3742002-12-13 20:15:29 +0000126 bgp_dump->fp = fopen (realpath, "w");
127
128 if (bgp_dump->fp == NULL)
gdtaa593d52003-12-22 20:15:53 +0000129 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000130 zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno));
gdtaa593d52003-12-22 20:15:53 +0000131 umask(oldumask);
132 return NULL;
133 }
134 umask(oldumask);
paul718e3742002-12-13 20:15:29 +0000135
136 return bgp_dump->fp;
137}
138
paul94f2b392005-06-28 12:44:16 +0000139static int
paul718e3742002-12-13 20:15:29 +0000140bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
141{
Paul Jakma45ad5922007-07-31 17:35:36 +0000142 int secs_into_day;
paul9834cd02003-10-18 01:01:19 +0000143 time_t t;
144 struct tm *tm;
paul718e3742002-12-13 20:15:29 +0000145
Paul Jakma45ad5922007-07-31 17:35:36 +0000146 if (interval > 0)
paul9834cd02003-10-18 01:01:19 +0000147 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000148 /* Periodic dump every interval seconds */
paul9834cd02003-10-18 01:01:19 +0000149 if ((interval < 86400) && ((86400 % interval) == 0))
150 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000151 /* Dump at predictable times: if a day has a whole number of
152 * intervals, dump every interval seconds starting from midnight
153 */
paul9834cd02003-10-18 01:01:19 +0000154 (void) time(&t);
155 tm = localtime(&t);
156 secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour;
Paul Jakma45ad5922007-07-31 17:35:36 +0000157 interval = interval - secs_into_day % interval; /* always > 0 */
paul9834cd02003-10-18 01:01:19 +0000158 }
Donald Sharp774914f2015-10-14 08:50:39 -0400159 bgp_dump->t_interval = thread_add_timer (bm->master, bgp_dump_interval_func,
Paul Jakma45ad5922007-07-31 17:35:36 +0000160 bgp_dump, interval);
paul9834cd02003-10-18 01:01:19 +0000161 }
paulfba3d222003-05-10 18:33:28 +0000162 else
paul9834cd02003-10-18 01:01:19 +0000163 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000164 /* One-off dump: execute immediately, don't affect any scheduled dumps */
Donald Sharp774914f2015-10-14 08:50:39 -0400165 bgp_dump->t_interval = thread_add_event (bm->master, bgp_dump_interval_func,
paul9834cd02003-10-18 01:01:19 +0000166 bgp_dump, 0);
167 }
paulfba3d222003-05-10 18:33:28 +0000168
paul718e3742002-12-13 20:15:29 +0000169 return 0;
170}
171
172/* Dump common header. */
paul94f2b392005-06-28 12:44:16 +0000173static void
paul718e3742002-12-13 20:15:29 +0000174bgp_dump_header (struct stream *obuf, int type, int subtype)
175{
176 time_t now;
177
178 /* Set header. */
179 time (&now);
180
181 /* Put dump packet header. */
182 stream_putl (obuf, now);
183 stream_putw (obuf, type);
184 stream_putw (obuf, subtype);
185
186 stream_putl (obuf, 0); /* len */
187}
188
paul94f2b392005-06-28 12:44:16 +0000189static void
paul718e3742002-12-13 20:15:29 +0000190bgp_dump_set_size (struct stream *s, int type)
191{
paul9985f832005-02-09 15:51:56 +0000192 stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000193}
194
paul94f2b392005-06-28 12:44:16 +0000195static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000196bgp_dump_routes_index_table(struct bgp *bgp)
paul718e3742002-12-13 20:15:29 +0000197{
paul718e3742002-12-13 20:15:29 +0000198 struct peer *peer;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000199 struct listnode *node;
200 uint16_t peerno = 0;
201 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000202
paul718e3742002-12-13 20:15:29 +0000203 obuf = bgp_dump_obuf;
204 stream_reset (obuf);
205
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000206 /* MRT header */
207 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE);
paul718e3742002-12-13 20:15:29 +0000208
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000209 /* Collector BGP ID */
210 stream_put_in_addr (obuf, &bgp->router_id);
211
212 /* View name */
213 if(bgp->name)
paul718e3742002-12-13 20:15:29 +0000214 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000215 stream_putw (obuf, strlen(bgp->name));
216 stream_put(obuf, bgp->name, strlen(bgp->name));
paul718e3742002-12-13 20:15:29 +0000217 }
218 else
219 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000220 stream_putw(obuf, 0);
paul718e3742002-12-13 20:15:29 +0000221 }
222
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000223 /* Peer count */
224 stream_putw (obuf, listcount(bgp->peer));
225
226 /* Walk down all peers */
227 for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
paul718e3742002-12-13 20:15:29 +0000228 {
paul718e3742002-12-13 20:15:29 +0000229
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000230 /* Peer's type */
231 if (sockunion_family(&peer->su) == AF_INET)
232 {
233 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
234 }
paul718e3742002-12-13 20:15:29 +0000235#ifdef HAVE_IPV6
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000236 else if (sockunion_family(&peer->su) == AF_INET6)
237 {
238 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
239 }
paul718e3742002-12-13 20:15:29 +0000240#endif /* HAVE_IPV6 */
241
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000242 /* Peer's BGP ID */
243 stream_put_in_addr (obuf, &peer->remote_id);
244
245 /* Peer's IP address */
246 if (sockunion_family(&peer->su) == AF_INET)
247 {
248 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
249 }
250#ifdef HAVE_IPV6
251 else if (sockunion_family(&peer->su) == AF_INET6)
252 {
253 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
254 IPV6_MAX_BYTELEN);
255 }
256#endif /* HAVE_IPV6 */
257
258 /* Peer's AS number. */
259 /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
260 stream_putl (obuf, peer->as);
261
262 /* Store the peer number for this peer */
263 peer->table_dump_index = peerno;
264 peerno++;
265 }
266
267 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
paul718e3742002-12-13 20:15:29 +0000268
David Lampartera6694fe2013-01-16 01:28:36 +0100269 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
paul718e3742002-12-13 20:15:29 +0000270 fflush (bgp_dump_routes.fp);
271}
272
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000273
paul718e3742002-12-13 20:15:29 +0000274/* Runs under child process. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000275static unsigned int
276bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
paul718e3742002-12-13 20:15:29 +0000277{
278 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000279 struct bgp_info *info;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000280 struct bgp_node *rn;
paul718e3742002-12-13 20:15:29 +0000281 struct bgp *bgp;
282 struct bgp_table *table;
paul718e3742002-12-13 20:15:29 +0000283
284 bgp = bgp_get_default ();
285 if (!bgp)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000286 return seq;
paul718e3742002-12-13 20:15:29 +0000287
288 if (bgp_dump_routes.fp == NULL)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000289 return seq;
290
291 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
292 so this should only be done on the first call to bgp_dump_routes_func.
293 ( this function will be called once for ipv4 and once for ipv6 ) */
294 if(first_run)
295 bgp_dump_routes_index_table(bgp);
296
297 obuf = bgp_dump_obuf;
298 stream_reset(obuf);
paul718e3742002-12-13 20:15:29 +0000299
300 /* Walk down each BGP route. */
301 table = bgp->rib[afi][SAFI_UNICAST];
302
303 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000304 {
305 if(!rn->info)
306 continue;
307
308 stream_reset(obuf);
309
310 /* MRT header */
311 if (afi == AFI_IP)
312 {
313 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
314 }
315#ifdef HAVE_IPV6
316 else if (afi == AFI_IP6)
317 {
318 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
319 }
320#endif /* HAVE_IPV6 */
321
322 /* Sequence number */
323 stream_putl(obuf, seq);
324
325 /* Prefix length */
326 stream_putc (obuf, rn->p.prefixlen);
327
328 /* Prefix */
329 if (afi == AFI_IP)
330 {
331 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
332 stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
333 }
334#ifdef HAVE_IPV6
335 else if (afi == AFI_IP6)
336 {
337 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
338 stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
339 }
340#endif /* HAVE_IPV6 */
341
342 /* Save where we are now, so we can overwride the entry count later */
343 int sizep = stream_get_endp(obuf);
344
345 /* Entry count */
346 uint16_t entry_count = 0;
347
348 /* Entry count, note that this is overwritten later */
349 stream_putw(obuf, 0);
350
351 for (info = rn->info; info; info = info->next)
352 {
353 entry_count++;
354
355 /* Peer index */
356 stream_putw(obuf, info->peer->table_dump_index);
357
358 /* Originated */
John Kemp30b00172011-03-18 17:52:18 +0300359#ifdef HAVE_CLOCK_MONOTONIC
360 stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
361#else
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000362 stream_putl (obuf, info->uptime);
John Kemp30b00172011-03-18 17:52:18 +0300363#endif /* HAVE_CLOCK_MONOTONIC */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000364
365 /* Dump attribute. */
366 /* Skip prefix & AFI/SAFI for MP_NLRI */
367 bgp_dump_routes_attr (obuf, info->attr, &rn->p);
368 }
369
370 /* Overwrite the entry count, now that we know the right number */
371 stream_putw_at (obuf, sizep, entry_count);
372
373 seq++;
374
375 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
David Lampartera6694fe2013-01-16 01:28:36 +0100376 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
377
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000378 }
379
380 fflush (bgp_dump_routes.fp);
381
382 return seq;
paul718e3742002-12-13 20:15:29 +0000383}
384
paul94f2b392005-06-28 12:44:16 +0000385static int
paul718e3742002-12-13 20:15:29 +0000386bgp_dump_interval_func (struct thread *t)
387{
388 struct bgp_dump *bgp_dump;
paul718e3742002-12-13 20:15:29 +0000389 bgp_dump = THREAD_ARG (t);
390 bgp_dump->t_interval = NULL;
391
paul9834cd02003-10-18 01:01:19 +0000392 /* Reschedule dump even if file couldn't be opened this time... */
393 if (bgp_dump_open_file (bgp_dump) != NULL)
paul718e3742002-12-13 20:15:29 +0000394 {
paul9834cd02003-10-18 01:01:19 +0000395 /* In case of bgp_dump_routes, we need special route dump function. */
396 if (bgp_dump->type == BGP_DUMP_ROUTES)
397 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000398 unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
paula3845922003-10-18 01:30:50 +0000399#ifdef HAVE_IPV6
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000400 bgp_dump_routes_func (AFI_IP6, 0, seq);
paula3845922003-10-18 01:30:50 +0000401#endif /* HAVE_IPV6 */
paul9834cd02003-10-18 01:01:19 +0000402 /* Close the file now. For a RIB dump there's no point in leaving
403 * it open until the next scheduled dump starts. */
404 fclose(bgp_dump->fp); bgp_dump->fp = NULL;
405 }
paul718e3742002-12-13 20:15:29 +0000406 }
407
paulfba3d222003-05-10 18:33:28 +0000408 /* if interval is set reschedule */
409 if (bgp_dump->interval > 0)
410 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
411
paul718e3742002-12-13 20:15:29 +0000412 return 0;
413}
414
415/* Dump common information. */
paul94f2b392005-06-28 12:44:16 +0000416static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000417bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
paul718e3742002-12-13 20:15:29 +0000418{
419 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
420
421 /* Source AS number and Destination AS number. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000422 if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
423 {
424 stream_putl (obuf, peer->as);
425 stream_putl (obuf, peer->local_as);
426 }
427 else
428 {
429 stream_putw (obuf, peer->as);
430 stream_putw (obuf, peer->local_as);
431 }
paul718e3742002-12-13 20:15:29 +0000432
paula3845922003-10-18 01:30:50 +0000433 if (peer->su.sa.sa_family == AF_INET)
paul718e3742002-12-13 20:15:29 +0000434 {
435 stream_putw (obuf, peer->ifindex);
436 stream_putw (obuf, AFI_IP);
437
438 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
439
440 if (peer->su_local)
441 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
442 else
443 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
444 }
445#ifdef HAVE_IPV6
paula3845922003-10-18 01:30:50 +0000446 else if (peer->su.sa.sa_family == AF_INET6)
paul718e3742002-12-13 20:15:29 +0000447 {
448 /* Interface Index and Address family. */
449 stream_putw (obuf, peer->ifindex);
450 stream_putw (obuf, AFI_IP6);
451
452 /* Source IP Address and Destination IP Address. */
453 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
454
455 if (peer->su_local)
456 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
457 else
458 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
459 }
460#endif /* HAVE_IPV6 */
461}
462
463/* Dump BGP status change. */
464void
465bgp_dump_state (struct peer *peer, int status_old, int status_new)
466{
467 struct stream *obuf;
468
469 /* If dump file pointer is disabled return immediately. */
470 if (bgp_dump_all.fp == NULL)
471 return;
472
473 /* Make dump stream. */
474 obuf = bgp_dump_obuf;
475 stream_reset (obuf);
476
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000477 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4);
478 bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
paul718e3742002-12-13 20:15:29 +0000479
480 stream_putw (obuf, status_old);
481 stream_putw (obuf, status_new);
482
483 /* Set length. */
484 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
485
486 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100487 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
paul718e3742002-12-13 20:15:29 +0000488 fflush (bgp_dump_all.fp);
489}
490
paul94f2b392005-06-28 12:44:16 +0000491static void
paul718e3742002-12-13 20:15:29 +0000492bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
493 struct stream *packet)
494{
495 struct stream *obuf;
496
497 /* If dump file pointer is disabled return immediately. */
498 if (bgp_dump->fp == NULL)
499 return;
500
501 /* Make dump stream. */
502 obuf = bgp_dump_obuf;
503 stream_reset (obuf);
504
505 /* Dump header and common part. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000506 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
507 {
508 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4);
509 }
510 else
511 {
512 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
513 }
514 bgp_dump_common (obuf, peer, 0);
paul718e3742002-12-13 20:15:29 +0000515
516 /* Packet contents. */
517 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
518
519 /* Set length. */
520 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
521
522 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100523 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
paul718e3742002-12-13 20:15:29 +0000524 fflush (bgp_dump->fp);
525}
526
527/* Called from bgp_packet.c when BGP packet is received. */
528void
529bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
530{
531 /* bgp_dump_all. */
532 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
533
534 /* bgp_dump_updates. */
535 if (type == BGP_MSG_UPDATE)
536 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
537}
David Lamparter6b0655a2014-06-04 06:53:35 +0200538
paul94f2b392005-06-28 12:44:16 +0000539static unsigned int
paulfd79ac92004-10-13 05:06:08 +0000540bgp_dump_parse_time (const char *str)
paul718e3742002-12-13 20:15:29 +0000541{
542 int i;
543 int len;
544 int seen_h;
545 int seen_m;
546 int time;
547 unsigned int total;
548
549 time = 0;
550 total = 0;
551 seen_h = 0;
552 seen_m = 0;
553 len = strlen (str);
554
555 for (i = 0; i < len; i++)
556 {
557 if (isdigit ((int) str[i]))
558 {
559 time *= 10;
560 time += str[i] - '0';
561 }
562 else if (str[i] == 'H' || str[i] == 'h')
563 {
564 if (seen_h)
565 return 0;
566 if (seen_m)
567 return 0;
568 total += time * 60 *60;
569 time = 0;
570 seen_h = 1;
571 }
572 else if (str[i] == 'M' || str[i] == 'm')
573 {
574 if (seen_m)
575 return 0;
576 total += time * 60;
577 time = 0;
578 seen_h = 1;
579 }
580 else
581 return 0;
582 }
583 return total + time;
584}
585
paul94f2b392005-06-28 12:44:16 +0000586static int
Paul Jakma45ad5922007-07-31 17:35:36 +0000587bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
588 enum bgp_dump_type type, const char *path,
589 const char *interval_str)
paul718e3742002-12-13 20:15:29 +0000590{
paulfba3d222003-05-10 18:33:28 +0000591 unsigned int interval;
592
paul718e3742002-12-13 20:15:29 +0000593 if (interval_str)
594 {
paulfba3d222003-05-10 18:33:28 +0000595
paul718e3742002-12-13 20:15:29 +0000596 /* Check interval string. */
597 interval = bgp_dump_parse_time (interval_str);
598 if (interval == 0)
599 {
600 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
601 return CMD_WARNING;
602 }
Paul Jakma45ad5922007-07-31 17:35:36 +0000603
604 /* Don't schedule duplicate dumps if the dump command is given twice */
605 if (interval == bgp_dump->interval &&
606 type == bgp_dump->type &&
607 path && bgp_dump->filename && !strcmp (path, bgp_dump->filename))
608 {
609 return CMD_SUCCESS;
610 }
611
paul718e3742002-12-13 20:15:29 +0000612 /* Set interval. */
613 bgp_dump->interval = interval;
614 if (bgp_dump->interval_str)
615 free (bgp_dump->interval_str);
616 bgp_dump->interval_str = strdup (interval_str);
paulfba3d222003-05-10 18:33:28 +0000617
paul718e3742002-12-13 20:15:29 +0000618 }
paulfba3d222003-05-10 18:33:28 +0000619 else
620 {
621 interval = 0;
622 }
623
624 /* Create interval thread. */
625 bgp_dump_interval_add (bgp_dump, interval);
paul718e3742002-12-13 20:15:29 +0000626
627 /* Set type. */
628 bgp_dump->type = type;
629
630 /* Set file name. */
631 if (bgp_dump->filename)
632 free (bgp_dump->filename);
633 bgp_dump->filename = strdup (path);
634
635 /* This should be called when interval is expired. */
636 bgp_dump_open_file (bgp_dump);
637
638 return CMD_SUCCESS;
639}
640
paul94f2b392005-06-28 12:44:16 +0000641static int
paul718e3742002-12-13 20:15:29 +0000642bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
643{
644 /* Set file name. */
645 if (bgp_dump->filename)
646 {
647 free (bgp_dump->filename);
648 bgp_dump->filename = NULL;
649 }
650
651 /* This should be called when interval is expired. */
652 if (bgp_dump->fp)
653 {
654 fclose (bgp_dump->fp);
655 bgp_dump->fp = NULL;
656 }
657
658 /* Create interval thread. */
659 if (bgp_dump->t_interval)
660 {
661 thread_cancel (bgp_dump->t_interval);
662 bgp_dump->t_interval = NULL;
663 }
664
665 bgp_dump->interval = 0;
666
667 if (bgp_dump->interval_str)
668 {
669 free (bgp_dump->interval_str);
670 bgp_dump->interval_str = NULL;
671 }
672
673
674 return CMD_SUCCESS;
675}
676
677DEFUN (dump_bgp_all,
678 dump_bgp_all_cmd,
679 "dump bgp all PATH",
680 "Dump packet\n"
681 "BGP packet dump\n"
682 "Dump all BGP packets\n"
683 "Output filename\n")
684{
685 return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
686}
687
688DEFUN (dump_bgp_all_interval,
689 dump_bgp_all_interval_cmd,
690 "dump bgp all PATH INTERVAL",
691 "Dump packet\n"
692 "BGP packet dump\n"
693 "Dump all BGP packets\n"
694 "Output filename\n"
695 "Interval of output\n")
696{
697 return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
698}
699
700DEFUN (no_dump_bgp_all,
701 no_dump_bgp_all_cmd,
702 "no dump bgp all [PATH] [INTERVAL]",
703 NO_STR
704 "Dump packet\n"
705 "BGP packet dump\n"
706 "Dump all BGP packets\n")
707{
708 return bgp_dump_unset (vty, &bgp_dump_all);
709}
710
711DEFUN (dump_bgp_updates,
712 dump_bgp_updates_cmd,
713 "dump bgp updates PATH",
714 "Dump packet\n"
715 "BGP packet dump\n"
716 "Dump BGP updates only\n"
717 "Output filename\n")
718{
719 return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
720}
721
722DEFUN (dump_bgp_updates_interval,
723 dump_bgp_updates_interval_cmd,
724 "dump bgp updates PATH INTERVAL",
725 "Dump packet\n"
726 "BGP packet dump\n"
727 "Dump BGP updates only\n"
728 "Output filename\n"
729 "Interval of output\n")
730{
731 return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
732}
733
734DEFUN (no_dump_bgp_updates,
735 no_dump_bgp_updates_cmd,
736 "no dump bgp updates [PATH] [INTERVAL]",
737 NO_STR
738 "Dump packet\n"
739 "BGP packet dump\n"
740 "Dump BGP updates only\n")
741{
742 return bgp_dump_unset (vty, &bgp_dump_updates);
743}
744
745DEFUN (dump_bgp_routes,
746 dump_bgp_routes_cmd,
747 "dump bgp routes-mrt PATH",
748 "Dump packet\n"
749 "BGP packet dump\n"
750 "Dump whole BGP routing table\n"
751 "Output filename\n")
752{
753 return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
754}
755
756DEFUN (dump_bgp_routes_interval,
757 dump_bgp_routes_interval_cmd,
758 "dump bgp routes-mrt PATH INTERVAL",
759 "Dump packet\n"
760 "BGP packet dump\n"
761 "Dump whole BGP routing table\n"
762 "Output filename\n"
763 "Interval of output\n")
764{
765 return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
766}
767
768DEFUN (no_dump_bgp_routes,
769 no_dump_bgp_routes_cmd,
770 "no dump bgp routes-mrt [PATH] [INTERVAL]",
771 NO_STR
772 "Dump packet\n"
773 "BGP packet dump\n"
774 "Dump whole BGP routing table\n")
775{
776 return bgp_dump_unset (vty, &bgp_dump_routes);
777}
778
779/* BGP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -0800780static struct cmd_node bgp_dump_node =
paul718e3742002-12-13 20:15:29 +0000781{
782 DUMP_NODE,
783 "",
hasso501ba492004-10-13 21:32:46 +0000784 1
paul718e3742002-12-13 20:15:29 +0000785};
786
787#if 0
788char *
789config_time2str (unsigned int interval)
790{
791 static char buf[BUFSIZ];
792
793 buf[0] = '\0';
794
795 if (interval / 3600)
796 {
797 sprintf (buf, "%dh", interval / 3600);
798 interval %= 3600;
799 }
800 if (interval / 60)
801 {
802 sprintf (buf + strlen (buf), "%dm", interval /60);
803 interval %= 60;
804 }
805 if (interval)
806 {
807 sprintf (buf + strlen (buf), "%d", interval);
808 }
809 return buf;
810}
811#endif
812
paul94f2b392005-06-28 12:44:16 +0000813static int
paul718e3742002-12-13 20:15:29 +0000814config_write_bgp_dump (struct vty *vty)
815{
816 if (bgp_dump_all.filename)
817 {
818 if (bgp_dump_all.interval_str)
819 vty_out (vty, "dump bgp all %s %s%s",
820 bgp_dump_all.filename, bgp_dump_all.interval_str,
821 VTY_NEWLINE);
822 else
823 vty_out (vty, "dump bgp all %s%s",
824 bgp_dump_all.filename, VTY_NEWLINE);
825 }
826 if (bgp_dump_updates.filename)
827 {
828 if (bgp_dump_updates.interval_str)
829 vty_out (vty, "dump bgp updates %s %s%s",
830 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
831 VTY_NEWLINE);
832 else
833 vty_out (vty, "dump bgp updates %s%s",
834 bgp_dump_updates.filename, VTY_NEWLINE);
835 }
836 if (bgp_dump_routes.filename)
837 {
838 if (bgp_dump_routes.interval_str)
839 vty_out (vty, "dump bgp routes-mrt %s %s%s",
840 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
841 VTY_NEWLINE);
842 else
843 vty_out (vty, "dump bgp routes-mrt %s%s",
844 bgp_dump_routes.filename, VTY_NEWLINE);
845 }
846 return 0;
847}
David Lamparter6b0655a2014-06-04 06:53:35 +0200848
paul718e3742002-12-13 20:15:29 +0000849/* Initialize BGP packet dump functionality. */
850void
paul94f2b392005-06-28 12:44:16 +0000851bgp_dump_init (void)
paul718e3742002-12-13 20:15:29 +0000852{
853 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
854 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
855 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
856
paul9834cd02003-10-18 01:01:19 +0000857 bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
858 + BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000859
860 install_node (&bgp_dump_node, config_write_bgp_dump);
861
862 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
863 install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd);
864 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
865 install_element (CONFIG_NODE, &dump_bgp_updates_cmd);
866 install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd);
867 install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd);
868 install_element (CONFIG_NODE, &dump_bgp_routes_cmd);
869 install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd);
870 install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd);
871}
Chris Caputo228da422009-07-18 05:44:03 +0000872
873void
874bgp_dump_finish (void)
875{
876 stream_free (bgp_dump_obuf);
877 bgp_dump_obuf = NULL;
878}