blob: da0c2ac33b3180b404b71b542ca7ff301a478b95 [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;
Colin Petrie49c370b2016-05-11 11:56:58 +0200229 uint16_t peerno = 1;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000230 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
Colin Petrie49c370b2016-05-11 11:56:58 +0200253 /* Peer count ( plus one extra internal peer ) */
254 stream_putw (obuf, listcount(bgp->peer) + 1);
255
256 /* Populate fake peer at index 0, for locally originated routes */
257 /* Peer type (IPv4) */
258 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
259 /* Peer BGP ID (0.0.0.0) */
260 stream_putl (obuf, 0);
261 /* Peer IP address (0.0.0.0) */
262 stream_putl (obuf, 0);
263 /* Peer ASN (0) */
264 stream_putl (obuf, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000265
266 /* Walk down all peers */
267 for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
paul718e3742002-12-13 20:15:29 +0000268 {
paul718e3742002-12-13 20:15:29 +0000269
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000270 /* Peer's type */
271 if (sockunion_family(&peer->su) == AF_INET)
272 {
273 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
274 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000275 else if (sockunion_family(&peer->su) == AF_INET6)
276 {
277 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
278 }
paul718e3742002-12-13 20:15:29 +0000279
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000280 /* Peer's BGP ID */
281 stream_put_in_addr (obuf, &peer->remote_id);
282
283 /* Peer's IP address */
284 if (sockunion_family(&peer->su) == AF_INET)
285 {
286 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
287 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000288 else if (sockunion_family(&peer->su) == AF_INET6)
289 {
290 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
291 IPV6_MAX_BYTELEN);
292 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000293
294 /* Peer's AS number. */
295 /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
296 stream_putl (obuf, peer->as);
297
298 /* Store the peer number for this peer */
299 peer->table_dump_index = peerno;
300 peerno++;
301 }
302
303 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
paul718e3742002-12-13 20:15:29 +0000304
David Lampartera6694fe2013-01-16 01:28:36 +0100305 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
paul718e3742002-12-13 20:15:29 +0000306 fflush (bgp_dump_routes.fp);
307}
308
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000309
paul718e3742002-12-13 20:15:29 +0000310/* Runs under child process. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000311static unsigned int
312bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
paul718e3742002-12-13 20:15:29 +0000313{
314 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000315 struct bgp_info *info;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000316 struct bgp_node *rn;
paul718e3742002-12-13 20:15:29 +0000317 struct bgp *bgp;
318 struct bgp_table *table;
paul718e3742002-12-13 20:15:29 +0000319
320 bgp = bgp_get_default ();
321 if (!bgp)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000322 return seq;
paul718e3742002-12-13 20:15:29 +0000323
324 if (bgp_dump_routes.fp == NULL)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000325 return seq;
326
327 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
328 so this should only be done on the first call to bgp_dump_routes_func.
329 ( this function will be called once for ipv4 and once for ipv6 ) */
330 if(first_run)
331 bgp_dump_routes_index_table(bgp);
332
333 obuf = bgp_dump_obuf;
334 stream_reset(obuf);
paul718e3742002-12-13 20:15:29 +0000335
336 /* Walk down each BGP route. */
337 table = bgp->rib[afi][SAFI_UNICAST];
338
339 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000340 {
341 if(!rn->info)
342 continue;
343
344 stream_reset(obuf);
345
346 /* MRT header */
347 if (afi == AFI_IP)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500348 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST,
349 BGP_DUMP_ROUTES);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000350 else if (afi == AFI_IP6)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500351 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST,
352 BGP_DUMP_ROUTES);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000353
354 /* Sequence number */
355 stream_putl(obuf, seq);
356
357 /* Prefix length */
358 stream_putc (obuf, rn->p.prefixlen);
359
360 /* Prefix */
361 if (afi == AFI_IP)
362 {
363 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
364 stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
365 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000366 else if (afi == AFI_IP6)
367 {
368 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
369 stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
370 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000371
372 /* Save where we are now, so we can overwride the entry count later */
373 int sizep = stream_get_endp(obuf);
374
375 /* Entry count */
376 uint16_t entry_count = 0;
377
378 /* Entry count, note that this is overwritten later */
379 stream_putw(obuf, 0);
380
381 for (info = rn->info; info; info = info->next)
382 {
383 entry_count++;
384
385 /* Peer index */
386 stream_putw(obuf, info->peer->table_dump_index);
387
388 /* Originated */
John Kemp30b00172011-03-18 17:52:18 +0300389#ifdef HAVE_CLOCK_MONOTONIC
390 stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
391#else
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000392 stream_putl (obuf, info->uptime);
John Kemp30b00172011-03-18 17:52:18 +0300393#endif /* HAVE_CLOCK_MONOTONIC */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000394
395 /* Dump attribute. */
396 /* Skip prefix & AFI/SAFI for MP_NLRI */
397 bgp_dump_routes_attr (obuf, info->attr, &rn->p);
398 }
399
400 /* Overwrite the entry count, now that we know the right number */
401 stream_putw_at (obuf, sizep, entry_count);
402
403 seq++;
404
405 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
David Lampartera6694fe2013-01-16 01:28:36 +0100406 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
407
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000408 }
409
410 fflush (bgp_dump_routes.fp);
411
412 return seq;
paul718e3742002-12-13 20:15:29 +0000413}
414
paul94f2b392005-06-28 12:44:16 +0000415static int
paul718e3742002-12-13 20:15:29 +0000416bgp_dump_interval_func (struct thread *t)
417{
418 struct bgp_dump *bgp_dump;
paul718e3742002-12-13 20:15:29 +0000419 bgp_dump = THREAD_ARG (t);
420 bgp_dump->t_interval = NULL;
421
paul9834cd02003-10-18 01:01:19 +0000422 /* Reschedule dump even if file couldn't be opened this time... */
423 if (bgp_dump_open_file (bgp_dump) != NULL)
paul718e3742002-12-13 20:15:29 +0000424 {
paul9834cd02003-10-18 01:01:19 +0000425 /* In case of bgp_dump_routes, we need special route dump function. */
426 if (bgp_dump->type == BGP_DUMP_ROUTES)
427 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000428 unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000429 bgp_dump_routes_func (AFI_IP6, 0, seq);
paul9834cd02003-10-18 01:01:19 +0000430 /* Close the file now. For a RIB dump there's no point in leaving
431 * it open until the next scheduled dump starts. */
432 fclose(bgp_dump->fp); bgp_dump->fp = NULL;
433 }
paul718e3742002-12-13 20:15:29 +0000434 }
435
paulfba3d222003-05-10 18:33:28 +0000436 /* if interval is set reschedule */
437 if (bgp_dump->interval > 0)
438 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
439
paul718e3742002-12-13 20:15:29 +0000440 return 0;
441}
442
443/* Dump common information. */
paul94f2b392005-06-28 12:44:16 +0000444static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000445bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
paul718e3742002-12-13 20:15:29 +0000446{
447 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
448
449 /* Source AS number and Destination AS number. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000450 if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
451 {
452 stream_putl (obuf, peer->as);
453 stream_putl (obuf, peer->local_as);
454 }
455 else
456 {
457 stream_putw (obuf, peer->as);
458 stream_putw (obuf, peer->local_as);
459 }
paul718e3742002-12-13 20:15:29 +0000460
paula3845922003-10-18 01:30:50 +0000461 if (peer->su.sa.sa_family == AF_INET)
paul718e3742002-12-13 20:15:29 +0000462 {
463 stream_putw (obuf, peer->ifindex);
464 stream_putw (obuf, AFI_IP);
465
466 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
467
468 if (peer->su_local)
469 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
470 else
471 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
472 }
paula3845922003-10-18 01:30:50 +0000473 else if (peer->su.sa.sa_family == AF_INET6)
paul718e3742002-12-13 20:15:29 +0000474 {
475 /* Interface Index and Address family. */
476 stream_putw (obuf, peer->ifindex);
477 stream_putw (obuf, AFI_IP6);
478
479 /* Source IP Address and Destination IP Address. */
480 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
481
482 if (peer->su_local)
483 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
484 else
485 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
486 }
paul718e3742002-12-13 20:15:29 +0000487}
488
489/* Dump BGP status change. */
490void
491bgp_dump_state (struct peer *peer, int status_old, int status_new)
492{
493 struct stream *obuf;
494
495 /* If dump file pointer is disabled return immediately. */
496 if (bgp_dump_all.fp == NULL)
497 return;
498
499 /* Make dump stream. */
500 obuf = bgp_dump_obuf;
501 stream_reset (obuf);
502
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500503 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
504 bgp_dump_all.type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000505 bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
paul718e3742002-12-13 20:15:29 +0000506
507 stream_putw (obuf, status_old);
508 stream_putw (obuf, status_new);
509
510 /* Set length. */
511 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
512
513 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100514 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
paul718e3742002-12-13 20:15:29 +0000515 fflush (bgp_dump_all.fp);
516}
517
paul94f2b392005-06-28 12:44:16 +0000518static void
paul718e3742002-12-13 20:15:29 +0000519bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
520 struct stream *packet)
521{
522 struct stream *obuf;
523
524 /* If dump file pointer is disabled return immediately. */
525 if (bgp_dump->fp == NULL)
526 return;
527
528 /* Make dump stream. */
529 obuf = bgp_dump_obuf;
530 stream_reset (obuf);
531
532 /* Dump header and common part. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000533 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
534 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500535 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
536 bgp_dump->type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000537 }
538 else
539 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500540 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
541 bgp_dump->type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000542 }
543 bgp_dump_common (obuf, peer, 0);
paul718e3742002-12-13 20:15:29 +0000544
545 /* Packet contents. */
546 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
547
548 /* Set length. */
549 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
550
551 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100552 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
paul718e3742002-12-13 20:15:29 +0000553 fflush (bgp_dump->fp);
554}
555
556/* Called from bgp_packet.c when BGP packet is received. */
557void
558bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
559{
560 /* bgp_dump_all. */
561 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
562
563 /* bgp_dump_updates. */
564 if (type == BGP_MSG_UPDATE)
565 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
566}
David Lamparter6b0655a2014-06-04 06:53:35 +0200567
paul94f2b392005-06-28 12:44:16 +0000568static unsigned int
paulfd79ac92004-10-13 05:06:08 +0000569bgp_dump_parse_time (const char *str)
paul718e3742002-12-13 20:15:29 +0000570{
571 int i;
572 int len;
573 int seen_h;
574 int seen_m;
575 int time;
576 unsigned int total;
577
578 time = 0;
579 total = 0;
580 seen_h = 0;
581 seen_m = 0;
582 len = strlen (str);
583
584 for (i = 0; i < len; i++)
585 {
586 if (isdigit ((int) str[i]))
587 {
588 time *= 10;
589 time += str[i] - '0';
590 }
591 else if (str[i] == 'H' || str[i] == 'h')
592 {
593 if (seen_h)
594 return 0;
595 if (seen_m)
596 return 0;
597 total += time * 60 *60;
598 time = 0;
599 seen_h = 1;
600 }
601 else if (str[i] == 'M' || str[i] == 'm')
602 {
603 if (seen_m)
604 return 0;
605 total += time * 60;
606 time = 0;
607 seen_h = 1;
608 }
609 else
610 return 0;
611 }
612 return total + time;
613}
614
paul94f2b392005-06-28 12:44:16 +0000615static int
Paul Jakma45ad5922007-07-31 17:35:36 +0000616bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
617 enum bgp_dump_type type, const char *path,
618 const char *interval_str)
paul718e3742002-12-13 20:15:29 +0000619{
paulfba3d222003-05-10 18:33:28 +0000620 unsigned int interval;
621
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500622 /* Don't schedule duplicate dumps if the dump command is given twice */
623 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
624 && type == bgp_dump->type)
625 {
626 if (interval_str)
627 {
628 if (bgp_dump->interval_str &&
629 strcmp(bgp_dump->interval_str, interval_str) == 0)
630 return CMD_SUCCESS;
631 }
632 else
633 {
634 if (!bgp_dump->interval_str)
635 return CMD_SUCCESS;
636 }
637 }
638
639 /* Removing previous config */
640 bgp_dump_unset(vty, bgp_dump);
641
paul718e3742002-12-13 20:15:29 +0000642 if (interval_str)
643 {
paul718e3742002-12-13 20:15:29 +0000644 /* Check interval string. */
645 interval = bgp_dump_parse_time (interval_str);
646 if (interval == 0)
647 {
648 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
649 return CMD_WARNING;
650 }
Paul Jakma45ad5922007-07-31 17:35:36 +0000651
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500652 /* Setting interval string */
paul718e3742002-12-13 20:15:29 +0000653 bgp_dump->interval_str = strdup (interval_str);
paul718e3742002-12-13 20:15:29 +0000654 }
paulfba3d222003-05-10 18:33:28 +0000655 else
656 {
657 interval = 0;
658 }
paul718e3742002-12-13 20:15:29 +0000659
660 /* Set type. */
661 bgp_dump->type = type;
662
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500663 /* Set interval */
664 bgp_dump->interval = interval;
665
paul718e3742002-12-13 20:15:29 +0000666 /* Set file name. */
paul718e3742002-12-13 20:15:29 +0000667 bgp_dump->filename = strdup (path);
668
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500669 /* Create interval thread. */
670 bgp_dump_interval_add (bgp_dump, interval);
671
paul718e3742002-12-13 20:15:29 +0000672 /* This should be called when interval is expired. */
673 bgp_dump_open_file (bgp_dump);
674
675 return CMD_SUCCESS;
676}
677
paul94f2b392005-06-28 12:44:16 +0000678static int
paul718e3742002-12-13 20:15:29 +0000679bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
680{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500681 /* Removing file name. */
paul718e3742002-12-13 20:15:29 +0000682 if (bgp_dump->filename)
683 {
684 free (bgp_dump->filename);
685 bgp_dump->filename = NULL;
686 }
687
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500688 /* Closing file. */
paul718e3742002-12-13 20:15:29 +0000689 if (bgp_dump->fp)
690 {
691 fclose (bgp_dump->fp);
692 bgp_dump->fp = NULL;
693 }
694
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500695 /* Removing interval thread. */
paul718e3742002-12-13 20:15:29 +0000696 if (bgp_dump->t_interval)
697 {
698 thread_cancel (bgp_dump->t_interval);
699 bgp_dump->t_interval = NULL;
700 }
701
702 bgp_dump->interval = 0;
703
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500704 /* Removing interval string. */
paul718e3742002-12-13 20:15:29 +0000705 if (bgp_dump->interval_str)
706 {
707 free (bgp_dump->interval_str);
708 bgp_dump->interval_str = NULL;
709 }
710
paul718e3742002-12-13 20:15:29 +0000711 return CMD_SUCCESS;
712}
713
714DEFUN (dump_bgp_all,
715 dump_bgp_all_cmd,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500716 "dump bgp (all|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]",
paul718e3742002-12-13 20:15:29 +0000717 "Dump packet\n"
718 "BGP packet dump\n"
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500719 "Dump all BGP packets\nDump all BGP packets (Extended Tiemstamp Header)\n"
720 "Dump BGP updates only\nDump BGP updates only (Extended Tiemstamp Header)\n"
721 "Dump whole BGP routing table\n"
paul718e3742002-12-13 20:15:29 +0000722 "Output filename\n"
723 "Interval of output\n")
724{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500725 int bgp_dump_type = 0;
726 const char *interval = NULL;
727 struct bgp_dump *bgp_dump_struct = NULL;
728 const struct bgp_dump_type_map *map = NULL;
729
730 for (map = bgp_dump_type_map; map->str; map++)
731 if (strcmp(argv[0], map->str) == 0)
732 bgp_dump_type = map->type;
733
734 switch (bgp_dump_type)
735 {
736 case BGP_DUMP_ALL:
737 case BGP_DUMP_ALL_ET:
738 bgp_dump_struct = &bgp_dump_all;
739 break;
740 case BGP_DUMP_UPDATES:
741 case BGP_DUMP_UPDATES_ET:
742 bgp_dump_struct = &bgp_dump_updates;
743 break;
744 case BGP_DUMP_ROUTES:
745 default:
746 bgp_dump_struct = &bgp_dump_routes;
747 break;
748 }
749
750 /* When an interval is given */
751 if (argc == 3)
752 interval = argv[2];
753
754 return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type,
755 argv[1], interval);
paul718e3742002-12-13 20:15:29 +0000756}
757
758DEFUN (no_dump_bgp_all,
759 no_dump_bgp_all_cmd,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500760 "no dump bgp (all|updates|routes-mrt) [PATH] [INTERVAL]",
paul718e3742002-12-13 20:15:29 +0000761 NO_STR
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500762 "Stop dump packet\n"
763 "Stop BGP packet dump\n"
764 "Stop dump process all/all-et\n"
765 "Stop dump process updates/updates-et\n"
766 "Stop dump process route-mrt\n")
paul718e3742002-12-13 20:15:29 +0000767{
768 return bgp_dump_unset (vty, &bgp_dump_all);
769}
770
paul718e3742002-12-13 20:15:29 +0000771/* BGP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -0800772static struct cmd_node bgp_dump_node =
paul718e3742002-12-13 20:15:29 +0000773{
774 DUMP_NODE,
775 "",
hasso501ba492004-10-13 21:32:46 +0000776 1
paul718e3742002-12-13 20:15:29 +0000777};
778
779#if 0
780char *
781config_time2str (unsigned int interval)
782{
783 static char buf[BUFSIZ];
784
785 buf[0] = '\0';
786
787 if (interval / 3600)
788 {
789 sprintf (buf, "%dh", interval / 3600);
790 interval %= 3600;
791 }
792 if (interval / 60)
793 {
794 sprintf (buf + strlen (buf), "%dm", interval /60);
795 interval %= 60;
796 }
797 if (interval)
798 {
799 sprintf (buf + strlen (buf), "%d", interval);
800 }
801 return buf;
802}
803#endif
804
paul94f2b392005-06-28 12:44:16 +0000805static int
paul718e3742002-12-13 20:15:29 +0000806config_write_bgp_dump (struct vty *vty)
807{
808 if (bgp_dump_all.filename)
809 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500810 const char *type_str = "all";
811 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
812 type_str = "all-et";
813
paul718e3742002-12-13 20:15:29 +0000814 if (bgp_dump_all.interval_str)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500815 vty_out (vty, "dump bgp %s %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000816 bgp_dump_all.filename, bgp_dump_all.interval_str,
817 VTY_NEWLINE);
818 else
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500819 vty_out (vty, "dump bgp %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000820 bgp_dump_all.filename, VTY_NEWLINE);
821 }
822 if (bgp_dump_updates.filename)
823 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500824 const char *type_str = "updates";
825 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
826 type_str = "updates-et";
827
paul718e3742002-12-13 20:15:29 +0000828 if (bgp_dump_updates.interval_str)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500829 vty_out (vty, "dump bgp %s %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000830 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);
paul718e3742002-12-13 20:15:29 +0000842 }
843 return 0;
844}
David Lamparter6b0655a2014-06-04 06:53:35 +0200845
paul718e3742002-12-13 20:15:29 +0000846/* Initialize BGP packet dump functionality. */
847void
paul94f2b392005-06-28 12:44:16 +0000848bgp_dump_init (void)
paul718e3742002-12-13 20:15:29 +0000849{
850 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
851 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
852 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
853
paul9834cd02003-10-18 01:01:19 +0000854 bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
855 + BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000856
857 install_node (&bgp_dump_node, config_write_bgp_dump);
858
859 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
paul718e3742002-12-13 20:15:29 +0000860 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
paul718e3742002-12-13 20:15:29 +0000861}
Chris Caputo228da422009-07-18 05:44:03 +0000862
863void
864bgp_dump_finish (void)
865{
866 stream_free (bgp_dump_obuf);
867 bgp_dump_obuf = NULL;
868}