blob: 7754860126dbbccf17ba5b2eb0e157d2e3adb8b1 [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"
36
37enum 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;
92
93/* 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;
Daniel Kozlowskib07458a2012-09-26 12:01:24 +000098 int fd;
paul718e3742002-12-13 20:15:29 +000099 time_t clock;
100 struct tm *tm;
101 char fullpath[MAXPATHLEN];
102 char realpath[MAXPATHLEN];
gdtaa593d52003-12-22 20:15:53 +0000103 mode_t oldumask;
paul718e3742002-12-13 20:15:29 +0000104
105 time (&clock);
106 tm = localtime (&clock);
107
108 if (bgp_dump->filename[0] != DIRECTORY_SEP)
109 {
110 sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
111 ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
112 }
113 else
114 ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
115
116 if (ret == 0)
117 {
118 zlog_warn ("bgp_dump_open_file: strftime error");
119 return NULL;
120 }
121
122 if (bgp_dump->fp)
123 fclose (bgp_dump->fp);
124
125
gdtaa593d52003-12-22 20:15:53 +0000126 oldumask = umask(0777 & ~LOGFILE_MASK);
paul718e3742002-12-13 20:15:29 +0000127 bgp_dump->fp = fopen (realpath, "w");
128
129 if (bgp_dump->fp == NULL)
gdtaa593d52003-12-22 20:15:53 +0000130 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000131 zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno));
gdtaa593d52003-12-22 20:15:53 +0000132 umask(oldumask);
133 return NULL;
134 }
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000135 else
136 {
137 fd = fileno(bgp_dump->fp);
138 ret = flock( fd, LOCK_EX );
139 if (ret != 0)
140 {
141 zlog_warn ("bgp_dump_open_file: Unable to flock() file %s: %s", realpath, strerror (errno));
142 }
143 }
144
gdtaa593d52003-12-22 20:15:53 +0000145 umask(oldumask);
paul718e3742002-12-13 20:15:29 +0000146
147 return bgp_dump->fp;
148}
149
paul94f2b392005-06-28 12:44:16 +0000150static int
paul718e3742002-12-13 20:15:29 +0000151bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
152{
Paul Jakma45ad5922007-07-31 17:35:36 +0000153 int secs_into_day;
paul9834cd02003-10-18 01:01:19 +0000154 time_t t;
155 struct tm *tm;
paul718e3742002-12-13 20:15:29 +0000156
Paul Jakma45ad5922007-07-31 17:35:36 +0000157 if (interval > 0)
paul9834cd02003-10-18 01:01:19 +0000158 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000159 /* Periodic dump every interval seconds */
paul9834cd02003-10-18 01:01:19 +0000160 if ((interval < 86400) && ((86400 % interval) == 0))
161 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000162 /* Dump at predictable times: if a day has a whole number of
163 * intervals, dump every interval seconds starting from midnight
164 */
paul9834cd02003-10-18 01:01:19 +0000165 (void) time(&t);
166 tm = localtime(&t);
167 secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour;
Paul Jakma45ad5922007-07-31 17:35:36 +0000168 interval = interval - secs_into_day % interval; /* always > 0 */
paul9834cd02003-10-18 01:01:19 +0000169 }
170 bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func,
Paul Jakma45ad5922007-07-31 17:35:36 +0000171 bgp_dump, interval);
paul9834cd02003-10-18 01:01:19 +0000172 }
paulfba3d222003-05-10 18:33:28 +0000173 else
paul9834cd02003-10-18 01:01:19 +0000174 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000175 /* One-off dump: execute immediately, don't affect any scheduled dumps */
paul9834cd02003-10-18 01:01:19 +0000176 bgp_dump->t_interval = thread_add_event (master, bgp_dump_interval_func,
177 bgp_dump, 0);
178 }
paulfba3d222003-05-10 18:33:28 +0000179
paul718e3742002-12-13 20:15:29 +0000180 return 0;
181}
182
183/* Dump common header. */
paul94f2b392005-06-28 12:44:16 +0000184static void
paul718e3742002-12-13 20:15:29 +0000185bgp_dump_header (struct stream *obuf, int type, int subtype)
186{
187 time_t now;
188
189 /* Set header. */
190 time (&now);
191
192 /* Put dump packet header. */
193 stream_putl (obuf, now);
194 stream_putw (obuf, type);
195 stream_putw (obuf, subtype);
196
197 stream_putl (obuf, 0); /* len */
198}
199
paul94f2b392005-06-28 12:44:16 +0000200static void
paul718e3742002-12-13 20:15:29 +0000201bgp_dump_set_size (struct stream *s, int type)
202{
paul9985f832005-02-09 15:51:56 +0000203 stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000204}
205
paul94f2b392005-06-28 12:44:16 +0000206static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000207bgp_dump_routes_index_table(struct bgp *bgp)
paul718e3742002-12-13 20:15:29 +0000208{
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000209 int ret;
paul718e3742002-12-13 20:15:29 +0000210 struct peer *peer;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000211 struct listnode *node;
212 uint16_t peerno = 0;
213 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000214
paul718e3742002-12-13 20:15:29 +0000215 obuf = bgp_dump_obuf;
216 stream_reset (obuf);
217
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000218 /* MRT header */
219 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE);
paul718e3742002-12-13 20:15:29 +0000220
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000221 /* Collector BGP ID */
222 stream_put_in_addr (obuf, &bgp->router_id);
223
224 /* View name */
225 if(bgp->name)
paul718e3742002-12-13 20:15:29 +0000226 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000227 stream_putw (obuf, strlen(bgp->name));
228 stream_put(obuf, bgp->name, strlen(bgp->name));
paul718e3742002-12-13 20:15:29 +0000229 }
230 else
231 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000232 stream_putw(obuf, 0);
paul718e3742002-12-13 20:15:29 +0000233 }
234
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000235 /* Peer count */
236 stream_putw (obuf, listcount(bgp->peer));
237
238 /* Walk down all peers */
239 for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
paul718e3742002-12-13 20:15:29 +0000240 {
paul718e3742002-12-13 20:15:29 +0000241
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000242 /* Peer's type */
243 if (sockunion_family(&peer->su) == AF_INET)
244 {
245 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
246 }
paul718e3742002-12-13 20:15:29 +0000247#ifdef HAVE_IPV6
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000248 else if (sockunion_family(&peer->su) == AF_INET6)
249 {
250 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
251 }
paul718e3742002-12-13 20:15:29 +0000252#endif /* HAVE_IPV6 */
253
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000254 /* Peer's BGP ID */
255 stream_put_in_addr (obuf, &peer->remote_id);
256
257 /* Peer's IP address */
258 if (sockunion_family(&peer->su) == AF_INET)
259 {
260 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
261 }
262#ifdef HAVE_IPV6
263 else if (sockunion_family(&peer->su) == AF_INET6)
264 {
265 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
266 IPV6_MAX_BYTELEN);
267 }
268#endif /* HAVE_IPV6 */
269
270 /* Peer's AS number. */
271 /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
272 stream_putl (obuf, peer->as);
273
274 /* Store the peer number for this peer */
275 peer->table_dump_index = peerno;
276 peerno++;
277 }
278
279 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
paul718e3742002-12-13 20:15:29 +0000280
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000281 ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
282 if (ret != 1)
283 {
284 zlog_warn ("bgp_dump_routes_index_table: fwrite returned %d, expected 1: %s", ret, strerror (errno));
285 }
paul718e3742002-12-13 20:15:29 +0000286 fflush (bgp_dump_routes.fp);
287}
288
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000289
paul718e3742002-12-13 20:15:29 +0000290/* Runs under child process. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000291static unsigned int
292bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
paul718e3742002-12-13 20:15:29 +0000293{
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000294 int ret;
paul718e3742002-12-13 20:15:29 +0000295 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000296 struct bgp_info *info;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000297 struct bgp_node *rn;
paul718e3742002-12-13 20:15:29 +0000298 struct bgp *bgp;
299 struct bgp_table *table;
paul718e3742002-12-13 20:15:29 +0000300
301 bgp = bgp_get_default ();
302 if (!bgp)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000303 return seq;
paul718e3742002-12-13 20:15:29 +0000304
305 if (bgp_dump_routes.fp == NULL)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000306 return seq;
307
308 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
309 so this should only be done on the first call to bgp_dump_routes_func.
310 ( this function will be called once for ipv4 and once for ipv6 ) */
311 if(first_run)
312 bgp_dump_routes_index_table(bgp);
313
314 obuf = bgp_dump_obuf;
315 stream_reset(obuf);
paul718e3742002-12-13 20:15:29 +0000316
317 /* Walk down each BGP route. */
318 table = bgp->rib[afi][SAFI_UNICAST];
319
320 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000321 {
322 if(!rn->info)
323 continue;
324
325 stream_reset(obuf);
326
327 /* MRT header */
328 if (afi == AFI_IP)
329 {
330 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
331 }
332#ifdef HAVE_IPV6
333 else if (afi == AFI_IP6)
334 {
335 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
336 }
337#endif /* HAVE_IPV6 */
338
339 /* Sequence number */
340 stream_putl(obuf, seq);
341
342 /* Prefix length */
343 stream_putc (obuf, rn->p.prefixlen);
344
345 /* Prefix */
346 if (afi == AFI_IP)
347 {
348 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
349 stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
350 }
351#ifdef HAVE_IPV6
352 else if (afi == AFI_IP6)
353 {
354 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
355 stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
356 }
357#endif /* HAVE_IPV6 */
358
359 /* Save where we are now, so we can overwride the entry count later */
360 int sizep = stream_get_endp(obuf);
361
362 /* Entry count */
363 uint16_t entry_count = 0;
364
365 /* Entry count, note that this is overwritten later */
366 stream_putw(obuf, 0);
367
368 for (info = rn->info; info; info = info->next)
369 {
370 entry_count++;
371
372 /* Peer index */
373 stream_putw(obuf, info->peer->table_dump_index);
374
375 /* Originated */
John Kemp30b00172011-03-18 17:52:18 +0300376#ifdef HAVE_CLOCK_MONOTONIC
377 stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
378#else
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000379 stream_putl (obuf, info->uptime);
John Kemp30b00172011-03-18 17:52:18 +0300380#endif /* HAVE_CLOCK_MONOTONIC */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000381
382 /* Dump attribute. */
383 /* Skip prefix & AFI/SAFI for MP_NLRI */
384 bgp_dump_routes_attr (obuf, info->attr, &rn->p);
385 }
386
387 /* Overwrite the entry count, now that we know the right number */
388 stream_putw_at (obuf, sizep, entry_count);
389
390 seq++;
391
392 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000393 ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
394 if (ret != 1)
395 {
396 zlog_warn ("bgp_dump_routes_func: fwrite returned %d, expected 1: %s", ret, strerror (errno));
397 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000398 }
399
400 fflush (bgp_dump_routes.fp);
401
402 return seq;
paul718e3742002-12-13 20:15:29 +0000403}
404
paul94f2b392005-06-28 12:44:16 +0000405static int
paul718e3742002-12-13 20:15:29 +0000406bgp_dump_interval_func (struct thread *t)
407{
408 struct bgp_dump *bgp_dump;
paul718e3742002-12-13 20:15:29 +0000409 bgp_dump = THREAD_ARG (t);
410 bgp_dump->t_interval = NULL;
411
paul9834cd02003-10-18 01:01:19 +0000412 /* Reschedule dump even if file couldn't be opened this time... */
413 if (bgp_dump_open_file (bgp_dump) != NULL)
paul718e3742002-12-13 20:15:29 +0000414 {
paul9834cd02003-10-18 01:01:19 +0000415 /* In case of bgp_dump_routes, we need special route dump function. */
416 if (bgp_dump->type == BGP_DUMP_ROUTES)
417 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000418 unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
paula3845922003-10-18 01:30:50 +0000419#ifdef HAVE_IPV6
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000420 bgp_dump_routes_func (AFI_IP6, 0, seq);
paula3845922003-10-18 01:30:50 +0000421#endif /* HAVE_IPV6 */
paul9834cd02003-10-18 01:01:19 +0000422 /* Close the file now. For a RIB dump there's no point in leaving
423 * it open until the next scheduled dump starts. */
424 fclose(bgp_dump->fp); bgp_dump->fp = NULL;
425 }
paul718e3742002-12-13 20:15:29 +0000426 }
427
paulfba3d222003-05-10 18:33:28 +0000428 /* if interval is set reschedule */
429 if (bgp_dump->interval > 0)
430 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
431
paul718e3742002-12-13 20:15:29 +0000432 return 0;
433}
434
435/* Dump common information. */
paul94f2b392005-06-28 12:44:16 +0000436static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000437bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
paul718e3742002-12-13 20:15:29 +0000438{
439 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
440
441 /* Source AS number and Destination AS number. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000442 if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
443 {
444 stream_putl (obuf, peer->as);
445 stream_putl (obuf, peer->local_as);
446 }
447 else
448 {
449 stream_putw (obuf, peer->as);
450 stream_putw (obuf, peer->local_as);
451 }
paul718e3742002-12-13 20:15:29 +0000452
paula3845922003-10-18 01:30:50 +0000453 if (peer->su.sa.sa_family == AF_INET)
paul718e3742002-12-13 20:15:29 +0000454 {
455 stream_putw (obuf, peer->ifindex);
456 stream_putw (obuf, AFI_IP);
457
458 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
459
460 if (peer->su_local)
461 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
462 else
463 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
464 }
465#ifdef HAVE_IPV6
paula3845922003-10-18 01:30:50 +0000466 else if (peer->su.sa.sa_family == AF_INET6)
paul718e3742002-12-13 20:15:29 +0000467 {
468 /* Interface Index and Address family. */
469 stream_putw (obuf, peer->ifindex);
470 stream_putw (obuf, AFI_IP6);
471
472 /* Source IP Address and Destination IP Address. */
473 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
474
475 if (peer->su_local)
476 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
477 else
478 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
479 }
480#endif /* HAVE_IPV6 */
481}
482
483/* Dump BGP status change. */
484void
485bgp_dump_state (struct peer *peer, int status_old, int status_new)
486{
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000487 int ret;
paul718e3742002-12-13 20:15:29 +0000488 struct stream *obuf;
489
490 /* If dump file pointer is disabled return immediately. */
491 if (bgp_dump_all.fp == NULL)
492 return;
493
494 /* Make dump stream. */
495 obuf = bgp_dump_obuf;
496 stream_reset (obuf);
497
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000498 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4);
499 bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
paul718e3742002-12-13 20:15:29 +0000500
501 stream_putw (obuf, status_old);
502 stream_putw (obuf, status_new);
503
504 /* Set length. */
505 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
506
507 /* Write to the stream. */
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000508 ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
509 if (ret != 1)
510 {
511 zlog_warn ("bgp_dump_state: fwrite returned %d, expected 1: %s", ret, strerror (errno));
512 }
paul718e3742002-12-13 20:15:29 +0000513 fflush (bgp_dump_all.fp);
514}
515
paul94f2b392005-06-28 12:44:16 +0000516static void
paul718e3742002-12-13 20:15:29 +0000517bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
518 struct stream *packet)
519{
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000520 int ret;
paul718e3742002-12-13 20:15:29 +0000521 struct stream *obuf;
522
523 /* If dump file pointer is disabled return immediately. */
524 if (bgp_dump->fp == NULL)
525 return;
526
527 /* Make dump stream. */
528 obuf = bgp_dump_obuf;
529 stream_reset (obuf);
530
531 /* Dump header and common part. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000532 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
533 {
534 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4);
535 }
536 else
537 {
538 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
539 }
540 bgp_dump_common (obuf, peer, 0);
paul718e3742002-12-13 20:15:29 +0000541
542 /* Packet contents. */
543 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
544
545 /* Set length. */
546 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
547
548 /* Write to the stream. */
Daniel Kozlowskib07458a2012-09-26 12:01:24 +0000549 ret = fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
550 if (ret != 1)
551 {
552 zlog_warn ("bgp_dump_packet_func: fwrite returned %d, expected 1: %s", ret, strerror (errno));
553 }
paul718e3742002-12-13 20:15:29 +0000554 fflush (bgp_dump->fp);
555}
556
557/* Called from bgp_packet.c when BGP packet is received. */
558void
559bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
560{
561 /* bgp_dump_all. */
562 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
563
564 /* bgp_dump_updates. */
565 if (type == BGP_MSG_UPDATE)
566 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
567}
568
paul94f2b392005-06-28 12:44:16 +0000569static unsigned int
paulfd79ac92004-10-13 05:06:08 +0000570bgp_dump_parse_time (const char *str)
paul718e3742002-12-13 20:15:29 +0000571{
572 int i;
573 int len;
574 int seen_h;
575 int seen_m;
576 int time;
577 unsigned int total;
578
579 time = 0;
580 total = 0;
581 seen_h = 0;
582 seen_m = 0;
583 len = strlen (str);
584
585 for (i = 0; i < len; i++)
586 {
587 if (isdigit ((int) str[i]))
588 {
589 time *= 10;
590 time += str[i] - '0';
591 }
592 else if (str[i] == 'H' || str[i] == 'h')
593 {
594 if (seen_h)
595 return 0;
596 if (seen_m)
597 return 0;
598 total += time * 60 *60;
599 time = 0;
600 seen_h = 1;
601 }
602 else if (str[i] == 'M' || str[i] == 'm')
603 {
604 if (seen_m)
605 return 0;
606 total += time * 60;
607 time = 0;
608 seen_h = 1;
609 }
610 else
611 return 0;
612 }
613 return total + time;
614}
615
paul94f2b392005-06-28 12:44:16 +0000616static int
Paul Jakma45ad5922007-07-31 17:35:36 +0000617bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
618 enum bgp_dump_type type, const char *path,
619 const char *interval_str)
paul718e3742002-12-13 20:15:29 +0000620{
paulfba3d222003-05-10 18:33:28 +0000621 unsigned int interval;
622
paul718e3742002-12-13 20:15:29 +0000623 if (interval_str)
624 {
paulfba3d222003-05-10 18:33:28 +0000625
paul718e3742002-12-13 20:15:29 +0000626 /* Check interval string. */
627 interval = bgp_dump_parse_time (interval_str);
628 if (interval == 0)
629 {
630 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
631 return CMD_WARNING;
632 }
Paul Jakma45ad5922007-07-31 17:35:36 +0000633
634 /* Don't schedule duplicate dumps if the dump command is given twice */
635 if (interval == bgp_dump->interval &&
636 type == bgp_dump->type &&
637 path && bgp_dump->filename && !strcmp (path, bgp_dump->filename))
638 {
639 return CMD_SUCCESS;
640 }
641
paul718e3742002-12-13 20:15:29 +0000642 /* Set interval. */
643 bgp_dump->interval = interval;
644 if (bgp_dump->interval_str)
645 free (bgp_dump->interval_str);
646 bgp_dump->interval_str = strdup (interval_str);
paulfba3d222003-05-10 18:33:28 +0000647
paul718e3742002-12-13 20:15:29 +0000648 }
paulfba3d222003-05-10 18:33:28 +0000649 else
650 {
651 interval = 0;
652 }
653
654 /* Create interval thread. */
655 bgp_dump_interval_add (bgp_dump, interval);
paul718e3742002-12-13 20:15:29 +0000656
657 /* Set type. */
658 bgp_dump->type = type;
659
660 /* Set file name. */
661 if (bgp_dump->filename)
662 free (bgp_dump->filename);
663 bgp_dump->filename = strdup (path);
664
665 /* This should be called when interval is expired. */
666 bgp_dump_open_file (bgp_dump);
667
668 return CMD_SUCCESS;
669}
670
paul94f2b392005-06-28 12:44:16 +0000671static int
paul718e3742002-12-13 20:15:29 +0000672bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
673{
674 /* Set file name. */
675 if (bgp_dump->filename)
676 {
677 free (bgp_dump->filename);
678 bgp_dump->filename = NULL;
679 }
680
681 /* This should be called when interval is expired. */
682 if (bgp_dump->fp)
683 {
684 fclose (bgp_dump->fp);
685 bgp_dump->fp = NULL;
686 }
687
688 /* Create interval thread. */
689 if (bgp_dump->t_interval)
690 {
691 thread_cancel (bgp_dump->t_interval);
692 bgp_dump->t_interval = NULL;
693 }
694
695 bgp_dump->interval = 0;
696
697 if (bgp_dump->interval_str)
698 {
699 free (bgp_dump->interval_str);
700 bgp_dump->interval_str = NULL;
701 }
702
703
704 return CMD_SUCCESS;
705}
706
707DEFUN (dump_bgp_all,
708 dump_bgp_all_cmd,
709 "dump bgp all PATH",
710 "Dump packet\n"
711 "BGP packet dump\n"
712 "Dump all BGP packets\n"
713 "Output filename\n")
714{
715 return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
716}
717
718DEFUN (dump_bgp_all_interval,
719 dump_bgp_all_interval_cmd,
720 "dump bgp all PATH INTERVAL",
721 "Dump packet\n"
722 "BGP packet dump\n"
723 "Dump all BGP packets\n"
724 "Output filename\n"
725 "Interval of output\n")
726{
727 return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
728}
729
730DEFUN (no_dump_bgp_all,
731 no_dump_bgp_all_cmd,
732 "no dump bgp all [PATH] [INTERVAL]",
733 NO_STR
734 "Dump packet\n"
735 "BGP packet dump\n"
736 "Dump all BGP packets\n")
737{
738 return bgp_dump_unset (vty, &bgp_dump_all);
739}
740
741DEFUN (dump_bgp_updates,
742 dump_bgp_updates_cmd,
743 "dump bgp updates PATH",
744 "Dump packet\n"
745 "BGP packet dump\n"
746 "Dump BGP updates only\n"
747 "Output filename\n")
748{
749 return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
750}
751
752DEFUN (dump_bgp_updates_interval,
753 dump_bgp_updates_interval_cmd,
754 "dump bgp updates PATH INTERVAL",
755 "Dump packet\n"
756 "BGP packet dump\n"
757 "Dump BGP updates only\n"
758 "Output filename\n"
759 "Interval of output\n")
760{
761 return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
762}
763
764DEFUN (no_dump_bgp_updates,
765 no_dump_bgp_updates_cmd,
766 "no dump bgp updates [PATH] [INTERVAL]",
767 NO_STR
768 "Dump packet\n"
769 "BGP packet dump\n"
770 "Dump BGP updates only\n")
771{
772 return bgp_dump_unset (vty, &bgp_dump_updates);
773}
774
775DEFUN (dump_bgp_routes,
776 dump_bgp_routes_cmd,
777 "dump bgp routes-mrt PATH",
778 "Dump packet\n"
779 "BGP packet dump\n"
780 "Dump whole BGP routing table\n"
781 "Output filename\n")
782{
783 return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
784}
785
786DEFUN (dump_bgp_routes_interval,
787 dump_bgp_routes_interval_cmd,
788 "dump bgp routes-mrt PATH INTERVAL",
789 "Dump packet\n"
790 "BGP packet dump\n"
791 "Dump whole BGP routing table\n"
792 "Output filename\n"
793 "Interval of output\n")
794{
795 return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
796}
797
798DEFUN (no_dump_bgp_routes,
799 no_dump_bgp_routes_cmd,
800 "no dump bgp routes-mrt [PATH] [INTERVAL]",
801 NO_STR
802 "Dump packet\n"
803 "BGP packet dump\n"
804 "Dump whole BGP routing table\n")
805{
806 return bgp_dump_unset (vty, &bgp_dump_routes);
807}
808
809/* BGP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -0800810static struct cmd_node bgp_dump_node =
paul718e3742002-12-13 20:15:29 +0000811{
812 DUMP_NODE,
813 "",
hasso501ba492004-10-13 21:32:46 +0000814 1
paul718e3742002-12-13 20:15:29 +0000815};
816
817#if 0
818char *
819config_time2str (unsigned int interval)
820{
821 static char buf[BUFSIZ];
822
823 buf[0] = '\0';
824
825 if (interval / 3600)
826 {
827 sprintf (buf, "%dh", interval / 3600);
828 interval %= 3600;
829 }
830 if (interval / 60)
831 {
832 sprintf (buf + strlen (buf), "%dm", interval /60);
833 interval %= 60;
834 }
835 if (interval)
836 {
837 sprintf (buf + strlen (buf), "%d", interval);
838 }
839 return buf;
840}
841#endif
842
paul94f2b392005-06-28 12:44:16 +0000843static int
paul718e3742002-12-13 20:15:29 +0000844config_write_bgp_dump (struct vty *vty)
845{
846 if (bgp_dump_all.filename)
847 {
848 if (bgp_dump_all.interval_str)
849 vty_out (vty, "dump bgp all %s %s%s",
850 bgp_dump_all.filename, bgp_dump_all.interval_str,
851 VTY_NEWLINE);
852 else
853 vty_out (vty, "dump bgp all %s%s",
854 bgp_dump_all.filename, VTY_NEWLINE);
855 }
856 if (bgp_dump_updates.filename)
857 {
858 if (bgp_dump_updates.interval_str)
859 vty_out (vty, "dump bgp updates %s %s%s",
860 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
861 VTY_NEWLINE);
862 else
863 vty_out (vty, "dump bgp updates %s%s",
864 bgp_dump_updates.filename, VTY_NEWLINE);
865 }
866 if (bgp_dump_routes.filename)
867 {
868 if (bgp_dump_routes.interval_str)
869 vty_out (vty, "dump bgp routes-mrt %s %s%s",
870 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
871 VTY_NEWLINE);
872 else
873 vty_out (vty, "dump bgp routes-mrt %s%s",
874 bgp_dump_routes.filename, VTY_NEWLINE);
875 }
876 return 0;
877}
878
879/* Initialize BGP packet dump functionality. */
880void
paul94f2b392005-06-28 12:44:16 +0000881bgp_dump_init (void)
paul718e3742002-12-13 20:15:29 +0000882{
883 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
884 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
885 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
886
paul9834cd02003-10-18 01:01:19 +0000887 bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
888 + BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000889
890 install_node (&bgp_dump_node, config_write_bgp_dump);
891
892 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
893 install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd);
894 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
895 install_element (CONFIG_NODE, &dump_bgp_updates_cmd);
896 install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd);
897 install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd);
898 install_element (CONFIG_NODE, &dump_bgp_routes_cmd);
899 install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd);
900 install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd);
901}
Chris Caputo228da422009-07-18 05:44:03 +0000902
903void
904bgp_dump_finish (void)
905{
906 stream_free (bgp_dump_obuf);
907 bgp_dump_obuf = NULL;
908}