blob: 1fa0e658eb06d15263cdb5df5cfd4571f4037d18 [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"
Donald Sharp04907292016-01-07 10:03:01 -050030#include "filter.h"
paul718e3742002-12-13 20:15:29 +000031
Donald Sharp04907292016-01-07 10:03:01 -050032#include "bgpd/bgp_table.h"
paul718e3742002-12-13 20:15:29 +000033#include "bgpd/bgpd.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_attr.h"
36#include "bgpd/bgp_dump.h"
David Lamparter6b0655a2014-06-04 06:53:35 +020037
paul718e3742002-12-13 20:15:29 +000038enum bgp_dump_type
39{
40 BGP_DUMP_ALL,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -050041 BGP_DUMP_ALL_ET,
paul718e3742002-12-13 20:15:29 +000042 BGP_DUMP_UPDATES,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -050043 BGP_DUMP_UPDATES_ET,
paul718e3742002-12-13 20:15:29 +000044 BGP_DUMP_ROUTES
45};
46
Alexis Fasqueldbe99e02015-11-16 13:55:16 -050047static const struct bgp_dump_type_map {
48 enum bgp_dump_type type;
49 const char *str;
50} bgp_dump_type_map[] =
51 {
52 {BGP_DUMP_ALL, "all"},
53 {BGP_DUMP_ALL_ET, "all-et"},
54 {BGP_DUMP_UPDATES, "updates"},
55 {BGP_DUMP_UPDATES_ET, "updates-et"},
56 {BGP_DUMP_ROUTES, "routes-mrt"},
57 {0, NULL},
58 };
59
paul718e3742002-12-13 20:15:29 +000060enum MRT_MSG_TYPES {
61 MSG_NULL,
62 MSG_START, /* sender is starting up */
63 MSG_DIE, /* receiver should shut down */
64 MSG_I_AM_DEAD, /* sender is shutting down */
65 MSG_PEER_DOWN, /* sender's peer is down */
66 MSG_PROTOCOL_BGP, /* msg is a BGP packet */
67 MSG_PROTOCOL_RIP, /* msg is a RIP packet */
68 MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */
69 MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */
70 MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */
71 MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
72 MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000073 MSG_TABLE_DUMP, /* routing table dump */
74 MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */
paul718e3742002-12-13 20:15:29 +000075};
76
77struct bgp_dump
78{
79 enum bgp_dump_type type;
80
81 char *filename;
82
83 FILE *fp;
84
85 unsigned int interval;
86
87 char *interval_str;
88
89 struct thread *t_interval;
90};
91
Alexis Fasqueldbe99e02015-11-16 13:55:16 -050092static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump);
93static int bgp_dump_interval_func (struct thread *);
94
paul718e3742002-12-13 20:15:29 +000095/* BGP packet dump output buffer. */
96struct stream *bgp_dump_obuf;
97
98/* BGP dump strucuture for 'dump bgp all' */
99struct bgp_dump bgp_dump_all;
100
101/* BGP dump structure for 'dump bgp updates' */
102struct bgp_dump bgp_dump_updates;
103
104/* BGP dump structure for 'dump bgp routes' */
105struct bgp_dump bgp_dump_routes;
106
paul94f2b392005-06-28 12:44:16 +0000107static FILE *
paul718e3742002-12-13 20:15:29 +0000108bgp_dump_open_file (struct bgp_dump *bgp_dump)
109{
110 int ret;
111 time_t clock;
112 struct tm *tm;
113 char fullpath[MAXPATHLEN];
114 char realpath[MAXPATHLEN];
gdtaa593d52003-12-22 20:15:53 +0000115 mode_t oldumask;
paul718e3742002-12-13 20:15:29 +0000116
117 time (&clock);
118 tm = localtime (&clock);
119
120 if (bgp_dump->filename[0] != DIRECTORY_SEP)
121 {
122 sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
123 ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
124 }
125 else
126 ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
127
128 if (ret == 0)
129 {
130 zlog_warn ("bgp_dump_open_file: strftime error");
131 return NULL;
132 }
133
134 if (bgp_dump->fp)
135 fclose (bgp_dump->fp);
136
137
gdtaa593d52003-12-22 20:15:53 +0000138 oldumask = umask(0777 & ~LOGFILE_MASK);
paul718e3742002-12-13 20:15:29 +0000139 bgp_dump->fp = fopen (realpath, "w");
140
141 if (bgp_dump->fp == NULL)
gdtaa593d52003-12-22 20:15:53 +0000142 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000143 zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno));
gdtaa593d52003-12-22 20:15:53 +0000144 umask(oldumask);
145 return NULL;
146 }
147 umask(oldumask);
paul718e3742002-12-13 20:15:29 +0000148
149 return bgp_dump->fp;
150}
151
paul94f2b392005-06-28 12:44:16 +0000152static int
paul718e3742002-12-13 20:15:29 +0000153bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
154{
Paul Jakma45ad5922007-07-31 17:35:36 +0000155 int secs_into_day;
paul9834cd02003-10-18 01:01:19 +0000156 time_t t;
157 struct tm *tm;
paul718e3742002-12-13 20:15:29 +0000158
Paul Jakma45ad5922007-07-31 17:35:36 +0000159 if (interval > 0)
paul9834cd02003-10-18 01:01:19 +0000160 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000161 /* Periodic dump every interval seconds */
paul9834cd02003-10-18 01:01:19 +0000162 if ((interval < 86400) && ((86400 % interval) == 0))
163 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000164 /* Dump at predictable times: if a day has a whole number of
165 * intervals, dump every interval seconds starting from midnight
166 */
paul9834cd02003-10-18 01:01:19 +0000167 (void) time(&t);
168 tm = localtime(&t);
169 secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour;
Paul Jakma45ad5922007-07-31 17:35:36 +0000170 interval = interval - secs_into_day % interval; /* always > 0 */
paul9834cd02003-10-18 01:01:19 +0000171 }
Donald Sharp774914f2015-10-14 08:50:39 -0400172 bgp_dump->t_interval = thread_add_timer (bm->master, bgp_dump_interval_func,
Paul Jakma45ad5922007-07-31 17:35:36 +0000173 bgp_dump, interval);
paul9834cd02003-10-18 01:01:19 +0000174 }
paulfba3d222003-05-10 18:33:28 +0000175 else
paul9834cd02003-10-18 01:01:19 +0000176 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000177 /* One-off dump: execute immediately, don't affect any scheduled dumps */
Donald Sharp774914f2015-10-14 08:50:39 -0400178 bgp_dump->t_interval = thread_add_event (bm->master, bgp_dump_interval_func,
paul9834cd02003-10-18 01:01:19 +0000179 bgp_dump, 0);
180 }
paulfba3d222003-05-10 18:33:28 +0000181
paul718e3742002-12-13 20:15:29 +0000182 return 0;
183}
184
185/* Dump common header. */
paul94f2b392005-06-28 12:44:16 +0000186static void
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500187bgp_dump_header (struct stream *obuf, int type, int subtype, int dump_type)
paul718e3742002-12-13 20:15:29 +0000188{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500189 struct timeval clock;
190 long msecs;
191 time_t secs;
paul718e3742002-12-13 20:15:29 +0000192
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500193 if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET)
194 && type == MSG_PROTOCOL_BGP4MP)
195 type = MSG_PROTOCOL_BGP4MP_ET;
196
197 gettimeofday(&clock, NULL);
198
199 secs = clock.tv_sec;
200 msecs = clock.tv_usec;
paul718e3742002-12-13 20:15:29 +0000201
202 /* Put dump packet header. */
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500203 stream_putl (obuf, secs);
paul718e3742002-12-13 20:15:29 +0000204 stream_putw (obuf, type);
205 stream_putw (obuf, subtype);
paul718e3742002-12-13 20:15:29 +0000206 stream_putl (obuf, 0); /* len */
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500207
208 /* Adding microseconds for the MRT Extended Header */
209 if (type == MSG_PROTOCOL_BGP4MP_ET)
210 stream_putl (obuf, msecs);
paul718e3742002-12-13 20:15:29 +0000211}
212
paul94f2b392005-06-28 12:44:16 +0000213static void
paul718e3742002-12-13 20:15:29 +0000214bgp_dump_set_size (struct stream *s, int type)
215{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500216 /*
217 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
218 * "The Microsecond Timestamp is included in the computation
219 * of the Length field value." (RFC6396 2011)
220 */
paul9985f832005-02-09 15:51:56 +0000221 stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000222}
223
paul94f2b392005-06-28 12:44:16 +0000224static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000225bgp_dump_routes_index_table(struct bgp *bgp)
paul718e3742002-12-13 20:15:29 +0000226{
paul718e3742002-12-13 20:15:29 +0000227 struct peer *peer;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000228 struct listnode *node;
229 uint16_t peerno = 0;
230 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000231
paul718e3742002-12-13 20:15:29 +0000232 obuf = bgp_dump_obuf;
233 stream_reset (obuf);
234
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000235 /* MRT header */
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500236 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE,
237 BGP_DUMP_ROUTES);
paul718e3742002-12-13 20:15:29 +0000238
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000239 /* Collector BGP ID */
240 stream_put_in_addr (obuf, &bgp->router_id);
241
242 /* View name */
243 if(bgp->name)
paul718e3742002-12-13 20:15:29 +0000244 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000245 stream_putw (obuf, strlen(bgp->name));
246 stream_put(obuf, bgp->name, strlen(bgp->name));
paul718e3742002-12-13 20:15:29 +0000247 }
248 else
249 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000250 stream_putw(obuf, 0);
paul718e3742002-12-13 20:15:29 +0000251 }
252
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000253 /* Peer count */
254 stream_putw (obuf, listcount(bgp->peer));
255
256 /* Walk down all peers */
257 for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
paul718e3742002-12-13 20:15:29 +0000258 {
paul718e3742002-12-13 20:15:29 +0000259
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000260 /* Peer's type */
261 if (sockunion_family(&peer->su) == AF_INET)
262 {
263 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
264 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000265 else if (sockunion_family(&peer->su) == AF_INET6)
266 {
267 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
268 }
paul718e3742002-12-13 20:15:29 +0000269
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000270 /* Peer's BGP ID */
271 stream_put_in_addr (obuf, &peer->remote_id);
272
273 /* Peer's IP address */
274 if (sockunion_family(&peer->su) == AF_INET)
275 {
276 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
277 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000278 else if (sockunion_family(&peer->su) == AF_INET6)
279 {
280 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
281 IPV6_MAX_BYTELEN);
282 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000283
284 /* Peer's AS number. */
285 /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
286 stream_putl (obuf, peer->as);
287
288 /* Store the peer number for this peer */
289 peer->table_dump_index = peerno;
290 peerno++;
291 }
292
293 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
paul718e3742002-12-13 20:15:29 +0000294
David Lampartera6694fe2013-01-16 01:28:36 +0100295 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
paul718e3742002-12-13 20:15:29 +0000296 fflush (bgp_dump_routes.fp);
297}
298
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000299
paul718e3742002-12-13 20:15:29 +0000300/* Runs under child process. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000301static unsigned int
302bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
paul718e3742002-12-13 20:15:29 +0000303{
304 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000305 struct bgp_info *info;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000306 struct bgp_node *rn;
paul718e3742002-12-13 20:15:29 +0000307 struct bgp *bgp;
308 struct bgp_table *table;
paul718e3742002-12-13 20:15:29 +0000309
310 bgp = bgp_get_default ();
311 if (!bgp)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000312 return seq;
paul718e3742002-12-13 20:15:29 +0000313
314 if (bgp_dump_routes.fp == NULL)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000315 return seq;
316
317 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
318 so this should only be done on the first call to bgp_dump_routes_func.
319 ( this function will be called once for ipv4 and once for ipv6 ) */
320 if(first_run)
321 bgp_dump_routes_index_table(bgp);
322
323 obuf = bgp_dump_obuf;
324 stream_reset(obuf);
paul718e3742002-12-13 20:15:29 +0000325
326 /* Walk down each BGP route. */
327 table = bgp->rib[afi][SAFI_UNICAST];
328
329 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000330 {
331 if(!rn->info)
332 continue;
333
334 stream_reset(obuf);
335
336 /* MRT header */
337 if (afi == AFI_IP)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500338 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST,
339 BGP_DUMP_ROUTES);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000340 else if (afi == AFI_IP6)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500341 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST,
342 BGP_DUMP_ROUTES);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000343
344 /* Sequence number */
345 stream_putl(obuf, seq);
346
347 /* Prefix length */
348 stream_putc (obuf, rn->p.prefixlen);
349
350 /* Prefix */
351 if (afi == AFI_IP)
352 {
353 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
354 stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
355 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000356 else if (afi == AFI_IP6)
357 {
358 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
359 stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
360 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000361
362 /* Save where we are now, so we can overwride the entry count later */
363 int sizep = stream_get_endp(obuf);
364
365 /* Entry count */
366 uint16_t entry_count = 0;
367
368 /* Entry count, note that this is overwritten later */
369 stream_putw(obuf, 0);
370
371 for (info = rn->info; info; info = info->next)
372 {
373 entry_count++;
374
375 /* Peer index */
376 stream_putw(obuf, info->peer->table_dump_index);
377
378 /* Originated */
John Kemp30b00172011-03-18 17:52:18 +0300379#ifdef HAVE_CLOCK_MONOTONIC
380 stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
381#else
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000382 stream_putl (obuf, info->uptime);
John Kemp30b00172011-03-18 17:52:18 +0300383#endif /* HAVE_CLOCK_MONOTONIC */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000384
385 /* Dump attribute. */
386 /* Skip prefix & AFI/SAFI for MP_NLRI */
387 bgp_dump_routes_attr (obuf, info->attr, &rn->p);
388 }
389
390 /* Overwrite the entry count, now that we know the right number */
391 stream_putw_at (obuf, sizep, entry_count);
392
393 seq++;
394
395 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
David Lampartera6694fe2013-01-16 01:28:36 +0100396 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
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);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000419 bgp_dump_routes_func (AFI_IP6, 0, seq);
paul9834cd02003-10-18 01:01:19 +0000420 /* Close the file now. For a RIB dump there's no point in leaving
421 * it open until the next scheduled dump starts. */
422 fclose(bgp_dump->fp); bgp_dump->fp = NULL;
423 }
paul718e3742002-12-13 20:15:29 +0000424 }
425
paulfba3d222003-05-10 18:33:28 +0000426 /* if interval is set reschedule */
427 if (bgp_dump->interval > 0)
428 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
429
paul718e3742002-12-13 20:15:29 +0000430 return 0;
431}
432
433/* Dump common information. */
paul94f2b392005-06-28 12:44:16 +0000434static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000435bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
paul718e3742002-12-13 20:15:29 +0000436{
437 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
438
439 /* Source AS number and Destination AS number. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000440 if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
441 {
442 stream_putl (obuf, peer->as);
443 stream_putl (obuf, peer->local_as);
444 }
445 else
446 {
447 stream_putw (obuf, peer->as);
448 stream_putw (obuf, peer->local_as);
449 }
paul718e3742002-12-13 20:15:29 +0000450
paula3845922003-10-18 01:30:50 +0000451 if (peer->su.sa.sa_family == AF_INET)
paul718e3742002-12-13 20:15:29 +0000452 {
453 stream_putw (obuf, peer->ifindex);
454 stream_putw (obuf, AFI_IP);
455
456 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
457
458 if (peer->su_local)
459 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
460 else
461 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
462 }
paula3845922003-10-18 01:30:50 +0000463 else if (peer->su.sa.sa_family == AF_INET6)
paul718e3742002-12-13 20:15:29 +0000464 {
465 /* Interface Index and Address family. */
466 stream_putw (obuf, peer->ifindex);
467 stream_putw (obuf, AFI_IP6);
468
469 /* Source IP Address and Destination IP Address. */
470 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
471
472 if (peer->su_local)
473 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
474 else
475 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
476 }
paul718e3742002-12-13 20:15:29 +0000477}
478
479/* Dump BGP status change. */
480void
481bgp_dump_state (struct peer *peer, int status_old, int status_new)
482{
483 struct stream *obuf;
484
485 /* If dump file pointer is disabled return immediately. */
486 if (bgp_dump_all.fp == NULL)
487 return;
488
489 /* Make dump stream. */
490 obuf = bgp_dump_obuf;
491 stream_reset (obuf);
492
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500493 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
494 bgp_dump_all.type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000495 bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
paul718e3742002-12-13 20:15:29 +0000496
497 stream_putw (obuf, status_old);
498 stream_putw (obuf, status_new);
499
500 /* Set length. */
501 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
502
503 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100504 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
paul718e3742002-12-13 20:15:29 +0000505 fflush (bgp_dump_all.fp);
506}
507
paul94f2b392005-06-28 12:44:16 +0000508static void
paul718e3742002-12-13 20:15:29 +0000509bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
510 struct stream *packet)
511{
512 struct stream *obuf;
513
514 /* If dump file pointer is disabled return immediately. */
515 if (bgp_dump->fp == NULL)
516 return;
517
518 /* Make dump stream. */
519 obuf = bgp_dump_obuf;
520 stream_reset (obuf);
521
522 /* Dump header and common part. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000523 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
524 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500525 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
526 bgp_dump->type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000527 }
528 else
529 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500530 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
531 bgp_dump->type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000532 }
533 bgp_dump_common (obuf, peer, 0);
paul718e3742002-12-13 20:15:29 +0000534
535 /* Packet contents. */
536 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
537
538 /* Set length. */
539 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
540
541 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100542 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
paul718e3742002-12-13 20:15:29 +0000543 fflush (bgp_dump->fp);
544}
545
546/* Called from bgp_packet.c when BGP packet is received. */
547void
548bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
549{
550 /* bgp_dump_all. */
551 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
552
553 /* bgp_dump_updates. */
554 if (type == BGP_MSG_UPDATE)
555 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
556}
David Lamparter6b0655a2014-06-04 06:53:35 +0200557
paul94f2b392005-06-28 12:44:16 +0000558static unsigned int
paulfd79ac92004-10-13 05:06:08 +0000559bgp_dump_parse_time (const char *str)
paul718e3742002-12-13 20:15:29 +0000560{
561 int i;
562 int len;
563 int seen_h;
564 int seen_m;
565 int time;
566 unsigned int total;
567
568 time = 0;
569 total = 0;
570 seen_h = 0;
571 seen_m = 0;
572 len = strlen (str);
573
574 for (i = 0; i < len; i++)
575 {
576 if (isdigit ((int) str[i]))
577 {
578 time *= 10;
579 time += str[i] - '0';
580 }
581 else if (str[i] == 'H' || str[i] == 'h')
582 {
583 if (seen_h)
584 return 0;
585 if (seen_m)
586 return 0;
587 total += time * 60 *60;
588 time = 0;
589 seen_h = 1;
590 }
591 else if (str[i] == 'M' || str[i] == 'm')
592 {
593 if (seen_m)
594 return 0;
595 total += time * 60;
596 time = 0;
597 seen_h = 1;
598 }
599 else
600 return 0;
601 }
602 return total + time;
603}
604
paul94f2b392005-06-28 12:44:16 +0000605static int
Paul Jakma45ad5922007-07-31 17:35:36 +0000606bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
607 enum bgp_dump_type type, const char *path,
608 const char *interval_str)
paul718e3742002-12-13 20:15:29 +0000609{
paulfba3d222003-05-10 18:33:28 +0000610 unsigned int interval;
611
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500612 /* Don't schedule duplicate dumps if the dump command is given twice */
613 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
614 && type == bgp_dump->type)
615 {
616 if (interval_str)
617 {
618 if (bgp_dump->interval_str &&
619 strcmp(bgp_dump->interval_str, interval_str) == 0)
620 return CMD_SUCCESS;
621 }
622 else
623 {
624 if (!bgp_dump->interval_str)
625 return CMD_SUCCESS;
626 }
627 }
628
629 /* Removing previous config */
630 bgp_dump_unset(vty, bgp_dump);
631
paul718e3742002-12-13 20:15:29 +0000632 if (interval_str)
633 {
paul718e3742002-12-13 20:15:29 +0000634 /* Check interval string. */
635 interval = bgp_dump_parse_time (interval_str);
636 if (interval == 0)
637 {
638 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
639 return CMD_WARNING;
640 }
Paul Jakma45ad5922007-07-31 17:35:36 +0000641
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500642 /* Setting interval string */
paul718e3742002-12-13 20:15:29 +0000643 bgp_dump->interval_str = strdup (interval_str);
paul718e3742002-12-13 20:15:29 +0000644 }
paulfba3d222003-05-10 18:33:28 +0000645 else
646 {
647 interval = 0;
648 }
paul718e3742002-12-13 20:15:29 +0000649
650 /* Set type. */
651 bgp_dump->type = type;
652
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500653 /* Set interval */
654 bgp_dump->interval = interval;
655
paul718e3742002-12-13 20:15:29 +0000656 /* Set file name. */
paul718e3742002-12-13 20:15:29 +0000657 bgp_dump->filename = strdup (path);
658
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500659 /* Create interval thread. */
660 bgp_dump_interval_add (bgp_dump, interval);
661
paul718e3742002-12-13 20:15:29 +0000662 /* This should be called when interval is expired. */
663 bgp_dump_open_file (bgp_dump);
664
665 return CMD_SUCCESS;
666}
667
paul94f2b392005-06-28 12:44:16 +0000668static int
paul718e3742002-12-13 20:15:29 +0000669bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
670{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500671 /* Removing file name. */
paul718e3742002-12-13 20:15:29 +0000672 if (bgp_dump->filename)
673 {
674 free (bgp_dump->filename);
675 bgp_dump->filename = NULL;
676 }
677
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500678 /* Closing file. */
paul718e3742002-12-13 20:15:29 +0000679 if (bgp_dump->fp)
680 {
681 fclose (bgp_dump->fp);
682 bgp_dump->fp = NULL;
683 }
684
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500685 /* Removing interval thread. */
paul718e3742002-12-13 20:15:29 +0000686 if (bgp_dump->t_interval)
687 {
688 thread_cancel (bgp_dump->t_interval);
689 bgp_dump->t_interval = NULL;
690 }
691
692 bgp_dump->interval = 0;
693
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500694 /* Removing interval string. */
paul718e3742002-12-13 20:15:29 +0000695 if (bgp_dump->interval_str)
696 {
697 free (bgp_dump->interval_str);
698 bgp_dump->interval_str = NULL;
699 }
700
paul718e3742002-12-13 20:15:29 +0000701 return CMD_SUCCESS;
702}
703
704DEFUN (dump_bgp_all,
705 dump_bgp_all_cmd,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500706 "dump bgp (all|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]",
paul718e3742002-12-13 20:15:29 +0000707 "Dump packet\n"
708 "BGP packet dump\n"
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500709 "Dump all BGP packets\nDump all BGP packets (Extended Tiemstamp Header)\n"
710 "Dump BGP updates only\nDump BGP updates only (Extended Tiemstamp Header)\n"
711 "Dump whole BGP routing table\n"
paul718e3742002-12-13 20:15:29 +0000712 "Output filename\n"
713 "Interval of output\n")
714{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500715 int bgp_dump_type = 0;
716 const char *interval = NULL;
717 struct bgp_dump *bgp_dump_struct = NULL;
718 const struct bgp_dump_type_map *map = NULL;
719
720 for (map = bgp_dump_type_map; map->str; map++)
721 if (strcmp(argv[0], map->str) == 0)
722 bgp_dump_type = map->type;
723
724 switch (bgp_dump_type)
725 {
726 case BGP_DUMP_ALL:
727 case BGP_DUMP_ALL_ET:
728 bgp_dump_struct = &bgp_dump_all;
729 break;
730 case BGP_DUMP_UPDATES:
731 case BGP_DUMP_UPDATES_ET:
732 bgp_dump_struct = &bgp_dump_updates;
733 break;
734 case BGP_DUMP_ROUTES:
735 default:
736 bgp_dump_struct = &bgp_dump_routes;
737 break;
738 }
739
740 /* When an interval is given */
741 if (argc == 3)
742 interval = argv[2];
743
744 return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type,
745 argv[1], interval);
paul718e3742002-12-13 20:15:29 +0000746}
747
748DEFUN (no_dump_bgp_all,
749 no_dump_bgp_all_cmd,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500750 "no dump bgp (all|updates|routes-mrt) [PATH] [INTERVAL]",
paul718e3742002-12-13 20:15:29 +0000751 NO_STR
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500752 "Stop dump packet\n"
753 "Stop BGP packet dump\n"
754 "Stop dump process all/all-et\n"
755 "Stop dump process updates/updates-et\n"
756 "Stop dump process route-mrt\n")
paul718e3742002-12-13 20:15:29 +0000757{
758 return bgp_dump_unset (vty, &bgp_dump_all);
759}
760
paul718e3742002-12-13 20:15:29 +0000761/* BGP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -0800762static struct cmd_node bgp_dump_node =
paul718e3742002-12-13 20:15:29 +0000763{
764 DUMP_NODE,
765 "",
hasso501ba492004-10-13 21:32:46 +0000766 1
paul718e3742002-12-13 20:15:29 +0000767};
768
769#if 0
770char *
771config_time2str (unsigned int interval)
772{
773 static char buf[BUFSIZ];
774
775 buf[0] = '\0';
776
777 if (interval / 3600)
778 {
779 sprintf (buf, "%dh", interval / 3600);
780 interval %= 3600;
781 }
782 if (interval / 60)
783 {
784 sprintf (buf + strlen (buf), "%dm", interval /60);
785 interval %= 60;
786 }
787 if (interval)
788 {
789 sprintf (buf + strlen (buf), "%d", interval);
790 }
791 return buf;
792}
793#endif
794
paul94f2b392005-06-28 12:44:16 +0000795static int
paul718e3742002-12-13 20:15:29 +0000796config_write_bgp_dump (struct vty *vty)
797{
798 if (bgp_dump_all.filename)
799 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500800 const char *type_str = "all";
801 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
802 type_str = "all-et";
803
paul718e3742002-12-13 20:15:29 +0000804 if (bgp_dump_all.interval_str)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500805 vty_out (vty, "dump bgp %s %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000806 bgp_dump_all.filename, bgp_dump_all.interval_str,
807 VTY_NEWLINE);
808 else
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500809 vty_out (vty, "dump bgp %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000810 bgp_dump_all.filename, VTY_NEWLINE);
811 }
812 if (bgp_dump_updates.filename)
813 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500814 const char *type_str = "updates";
815 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
816 type_str = "updates-et";
817
paul718e3742002-12-13 20:15:29 +0000818 if (bgp_dump_updates.interval_str)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500819 vty_out (vty, "dump bgp %s %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000820 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
821 VTY_NEWLINE);
822 else
823 vty_out (vty, "dump bgp updates %s%s",
824 bgp_dump_updates.filename, VTY_NEWLINE);
825 }
826 if (bgp_dump_routes.filename)
827 {
828 if (bgp_dump_routes.interval_str)
829 vty_out (vty, "dump bgp routes-mrt %s %s%s",
830 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
831 VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000832 }
833 return 0;
834}
David Lamparter6b0655a2014-06-04 06:53:35 +0200835
paul718e3742002-12-13 20:15:29 +0000836/* Initialize BGP packet dump functionality. */
837void
paul94f2b392005-06-28 12:44:16 +0000838bgp_dump_init (void)
paul718e3742002-12-13 20:15:29 +0000839{
840 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
841 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
842 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
843
paul9834cd02003-10-18 01:01:19 +0000844 bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
845 + BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000846
847 install_node (&bgp_dump_node, config_write_bgp_dump);
848
849 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
paul718e3742002-12-13 20:15:29 +0000850 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
paul718e3742002-12-13 20:15:29 +0000851}
Chris Caputo228da422009-07-18 05:44:03 +0000852
853void
854bgp_dump_finish (void)
855{
856 stream_free (bgp_dump_obuf);
857 bgp_dump_obuf = NULL;
858}