blob: 01f9b412fa9165074317109c36f98ab72703776e [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
Evgeny Uskovb4e01192016-01-13 13:58:00 +0300310static struct bgp_info *
311bgp_dump_route_node_record (int afi, struct bgp_node *rn,
312 struct bgp_info *info, unsigned int seq)
313{
314 struct stream *obuf;
315 size_t sizep;
316 size_t endp;
317
318 obuf = bgp_dump_obuf;
319 stream_reset (obuf);
320
321 /* MRT header */
322 if (afi == AFI_IP)
323 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST,
324 BGP_DUMP_ROUTES);
325 else if (afi == AFI_IP6)
326 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST,
327 BGP_DUMP_ROUTES);
328
329 /* Sequence number */
330 stream_putl (obuf, seq);
331
332 /* Prefix length */
333 stream_putc (obuf, rn->p.prefixlen);
334
335 /* Prefix */
336 if (afi == AFI_IP)
337 {
338 /* We'll dump only the useful bits (those not 0), but have to
339 * align on 8 bits */
340 stream_write (obuf, (u_char *) &rn->p.u.prefix4,
341 (rn->p.prefixlen + 7) / 8);
342 }
343 else if (afi == AFI_IP6)
344 {
345 /* We'll dump only the useful bits (those not 0), but have to
346 * align on 8 bits */
347 stream_write (obuf, (u_char *) &rn->p.u.prefix6,
348 (rn->p.prefixlen + 7) / 8);
349 }
350
351 /* Save where we are now, so we can overwride the entry count later */
352 sizep = stream_get_endp (obuf);
353
354 /* Entry count */
355 uint16_t entry_count = 0;
356
357 /* Entry count, note that this is overwritten later */
358 stream_putw (obuf, 0);
359
360 endp = stream_get_endp (obuf);
361 for (; info; info = info->next)
362 {
363 size_t cur_endp;
364
365 /* Peer index */
366 stream_putw (obuf, info->peer->table_dump_index);
367
368 /* Originated */
369#ifdef HAVE_CLOCK_MONOTONIC
370 stream_putl (obuf, time (NULL) - (bgp_clock () - info->uptime));
371#else
372 stream_putl (obuf, info->uptime);
373#endif /* HAVE_CLOCK_MONOTONIC */
374
375 /* Dump attribute. */
376 /* Skip prefix & AFI/SAFI for MP_NLRI */
377 bgp_dump_routes_attr (obuf, info->attr, &rn->p);
378
379 cur_endp = stream_get_endp (obuf);
380 if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
381 + BGP_DUMP_HEADER_SIZE)
382 {
383 stream_set_endp (obuf, endp);
384 break;
385 }
386
387 entry_count++;
388 endp = cur_endp;
389 }
390
391 /* Overwrite the entry count, now that we know the right number */
392 stream_putw_at (obuf, sizep, entry_count);
393
394 bgp_dump_set_size (obuf, MSG_TABLE_DUMP_V2);
395 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
396
397 return info;
398}
399
paul718e3742002-12-13 20:15:29 +0000400/* Runs under child process. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000401static unsigned int
402bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
paul718e3742002-12-13 20:15:29 +0000403{
paul718e3742002-12-13 20:15:29 +0000404 struct bgp_info *info;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000405 struct bgp_node *rn;
paul718e3742002-12-13 20:15:29 +0000406 struct bgp *bgp;
407 struct bgp_table *table;
paul718e3742002-12-13 20:15:29 +0000408
409 bgp = bgp_get_default ();
410 if (!bgp)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000411 return seq;
paul718e3742002-12-13 20:15:29 +0000412
413 if (bgp_dump_routes.fp == NULL)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000414 return seq;
415
416 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
417 so this should only be done on the first call to bgp_dump_routes_func.
418 ( this function will be called once for ipv4 and once for ipv6 ) */
419 if(first_run)
420 bgp_dump_routes_index_table(bgp);
421
paul718e3742002-12-13 20:15:29 +0000422 /* Walk down each BGP route. */
423 table = bgp->rib[afi][SAFI_UNICAST];
424
425 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000426 {
Evgeny Uskovb4e01192016-01-13 13:58:00 +0300427 info = rn->info;
428 while (info)
429 {
430 info = bgp_dump_route_node_record(afi, rn, info, seq);
431 seq++;
432 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000433 }
434
435 fflush (bgp_dump_routes.fp);
436
437 return seq;
paul718e3742002-12-13 20:15:29 +0000438}
439
paul94f2b392005-06-28 12:44:16 +0000440static int
paul718e3742002-12-13 20:15:29 +0000441bgp_dump_interval_func (struct thread *t)
442{
443 struct bgp_dump *bgp_dump;
paul718e3742002-12-13 20:15:29 +0000444 bgp_dump = THREAD_ARG (t);
445 bgp_dump->t_interval = NULL;
446
paul9834cd02003-10-18 01:01:19 +0000447 /* Reschedule dump even if file couldn't be opened this time... */
448 if (bgp_dump_open_file (bgp_dump) != NULL)
paul718e3742002-12-13 20:15:29 +0000449 {
paul9834cd02003-10-18 01:01:19 +0000450 /* In case of bgp_dump_routes, we need special route dump function. */
451 if (bgp_dump->type == BGP_DUMP_ROUTES)
452 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000453 unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000454 bgp_dump_routes_func (AFI_IP6, 0, seq);
paul9834cd02003-10-18 01:01:19 +0000455 /* Close the file now. For a RIB dump there's no point in leaving
456 * it open until the next scheduled dump starts. */
457 fclose(bgp_dump->fp); bgp_dump->fp = NULL;
458 }
paul718e3742002-12-13 20:15:29 +0000459 }
460
paulfba3d222003-05-10 18:33:28 +0000461 /* if interval is set reschedule */
462 if (bgp_dump->interval > 0)
463 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
464
paul718e3742002-12-13 20:15:29 +0000465 return 0;
466}
467
468/* Dump common information. */
paul94f2b392005-06-28 12:44:16 +0000469static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000470bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
paul718e3742002-12-13 20:15:29 +0000471{
472 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
473
474 /* Source AS number and Destination AS number. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000475 if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
476 {
477 stream_putl (obuf, peer->as);
478 stream_putl (obuf, peer->local_as);
479 }
480 else
481 {
482 stream_putw (obuf, peer->as);
483 stream_putw (obuf, peer->local_as);
484 }
paul718e3742002-12-13 20:15:29 +0000485
paula3845922003-10-18 01:30:50 +0000486 if (peer->su.sa.sa_family == AF_INET)
paul718e3742002-12-13 20:15:29 +0000487 {
488 stream_putw (obuf, peer->ifindex);
489 stream_putw (obuf, AFI_IP);
490
491 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
492
493 if (peer->su_local)
494 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
495 else
496 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
497 }
paula3845922003-10-18 01:30:50 +0000498 else if (peer->su.sa.sa_family == AF_INET6)
paul718e3742002-12-13 20:15:29 +0000499 {
500 /* Interface Index and Address family. */
501 stream_putw (obuf, peer->ifindex);
502 stream_putw (obuf, AFI_IP6);
503
504 /* Source IP Address and Destination IP Address. */
505 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
506
507 if (peer->su_local)
508 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
509 else
510 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
511 }
paul718e3742002-12-13 20:15:29 +0000512}
513
514/* Dump BGP status change. */
515void
516bgp_dump_state (struct peer *peer, int status_old, int status_new)
517{
518 struct stream *obuf;
519
520 /* If dump file pointer is disabled return immediately. */
521 if (bgp_dump_all.fp == NULL)
522 return;
523
524 /* Make dump stream. */
525 obuf = bgp_dump_obuf;
526 stream_reset (obuf);
527
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500528 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
529 bgp_dump_all.type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000530 bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
paul718e3742002-12-13 20:15:29 +0000531
532 stream_putw (obuf, status_old);
533 stream_putw (obuf, status_new);
534
535 /* Set length. */
536 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
537
538 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100539 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
paul718e3742002-12-13 20:15:29 +0000540 fflush (bgp_dump_all.fp);
541}
542
paul94f2b392005-06-28 12:44:16 +0000543static void
paul718e3742002-12-13 20:15:29 +0000544bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
545 struct stream *packet)
546{
547 struct stream *obuf;
548
549 /* If dump file pointer is disabled return immediately. */
550 if (bgp_dump->fp == NULL)
551 return;
552
553 /* Make dump stream. */
554 obuf = bgp_dump_obuf;
555 stream_reset (obuf);
556
557 /* Dump header and common part. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000558 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
559 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500560 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
561 bgp_dump->type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000562 }
563 else
564 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500565 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
566 bgp_dump->type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000567 }
568 bgp_dump_common (obuf, peer, 0);
paul718e3742002-12-13 20:15:29 +0000569
570 /* Packet contents. */
571 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
572
573 /* Set length. */
574 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
575
576 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100577 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
paul718e3742002-12-13 20:15:29 +0000578 fflush (bgp_dump->fp);
579}
580
581/* Called from bgp_packet.c when BGP packet is received. */
582void
583bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
584{
585 /* bgp_dump_all. */
586 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
587
588 /* bgp_dump_updates. */
589 if (type == BGP_MSG_UPDATE)
590 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
591}
David Lamparter6b0655a2014-06-04 06:53:35 +0200592
paul94f2b392005-06-28 12:44:16 +0000593static unsigned int
paulfd79ac92004-10-13 05:06:08 +0000594bgp_dump_parse_time (const char *str)
paul718e3742002-12-13 20:15:29 +0000595{
596 int i;
597 int len;
598 int seen_h;
599 int seen_m;
600 int time;
601 unsigned int total;
602
603 time = 0;
604 total = 0;
605 seen_h = 0;
606 seen_m = 0;
607 len = strlen (str);
608
609 for (i = 0; i < len; i++)
610 {
611 if (isdigit ((int) str[i]))
612 {
613 time *= 10;
614 time += str[i] - '0';
615 }
616 else if (str[i] == 'H' || str[i] == 'h')
617 {
618 if (seen_h)
619 return 0;
620 if (seen_m)
621 return 0;
622 total += time * 60 *60;
623 time = 0;
624 seen_h = 1;
625 }
626 else if (str[i] == 'M' || str[i] == 'm')
627 {
628 if (seen_m)
629 return 0;
630 total += time * 60;
631 time = 0;
632 seen_h = 1;
633 }
634 else
635 return 0;
636 }
637 return total + time;
638}
639
paul94f2b392005-06-28 12:44:16 +0000640static int
Paul Jakma45ad5922007-07-31 17:35:36 +0000641bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
642 enum bgp_dump_type type, const char *path,
643 const char *interval_str)
paul718e3742002-12-13 20:15:29 +0000644{
paulfba3d222003-05-10 18:33:28 +0000645 unsigned int interval;
646
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500647 /* Don't schedule duplicate dumps if the dump command is given twice */
648 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
649 && type == bgp_dump->type)
650 {
651 if (interval_str)
652 {
653 if (bgp_dump->interval_str &&
654 strcmp(bgp_dump->interval_str, interval_str) == 0)
655 return CMD_SUCCESS;
656 }
657 else
658 {
659 if (!bgp_dump->interval_str)
660 return CMD_SUCCESS;
661 }
662 }
663
664 /* Removing previous config */
665 bgp_dump_unset(vty, bgp_dump);
666
paul718e3742002-12-13 20:15:29 +0000667 if (interval_str)
668 {
paul718e3742002-12-13 20:15:29 +0000669 /* Check interval string. */
670 interval = bgp_dump_parse_time (interval_str);
671 if (interval == 0)
672 {
673 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
674 return CMD_WARNING;
675 }
Paul Jakma45ad5922007-07-31 17:35:36 +0000676
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500677 /* Setting interval string */
paul718e3742002-12-13 20:15:29 +0000678 bgp_dump->interval_str = strdup (interval_str);
paul718e3742002-12-13 20:15:29 +0000679 }
paulfba3d222003-05-10 18:33:28 +0000680 else
681 {
682 interval = 0;
683 }
paul718e3742002-12-13 20:15:29 +0000684
685 /* Set type. */
686 bgp_dump->type = type;
687
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500688 /* Set interval */
689 bgp_dump->interval = interval;
690
paul718e3742002-12-13 20:15:29 +0000691 /* Set file name. */
paul718e3742002-12-13 20:15:29 +0000692 bgp_dump->filename = strdup (path);
693
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500694 /* Create interval thread. */
695 bgp_dump_interval_add (bgp_dump, interval);
696
paul718e3742002-12-13 20:15:29 +0000697 /* This should be called when interval is expired. */
698 bgp_dump_open_file (bgp_dump);
699
700 return CMD_SUCCESS;
701}
702
paul94f2b392005-06-28 12:44:16 +0000703static int
paul718e3742002-12-13 20:15:29 +0000704bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
705{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500706 /* Removing file name. */
paul718e3742002-12-13 20:15:29 +0000707 if (bgp_dump->filename)
708 {
709 free (bgp_dump->filename);
710 bgp_dump->filename = NULL;
711 }
712
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500713 /* Closing file. */
paul718e3742002-12-13 20:15:29 +0000714 if (bgp_dump->fp)
715 {
716 fclose (bgp_dump->fp);
717 bgp_dump->fp = NULL;
718 }
719
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500720 /* Removing interval thread. */
paul718e3742002-12-13 20:15:29 +0000721 if (bgp_dump->t_interval)
722 {
723 thread_cancel (bgp_dump->t_interval);
724 bgp_dump->t_interval = NULL;
725 }
726
727 bgp_dump->interval = 0;
728
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500729 /* Removing interval string. */
paul718e3742002-12-13 20:15:29 +0000730 if (bgp_dump->interval_str)
731 {
732 free (bgp_dump->interval_str);
733 bgp_dump->interval_str = NULL;
734 }
735
paul718e3742002-12-13 20:15:29 +0000736 return CMD_SUCCESS;
737}
738
739DEFUN (dump_bgp_all,
740 dump_bgp_all_cmd,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500741 "dump bgp (all|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]",
paul718e3742002-12-13 20:15:29 +0000742 "Dump packet\n"
743 "BGP packet dump\n"
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500744 "Dump all BGP packets\nDump all BGP packets (Extended Tiemstamp Header)\n"
745 "Dump BGP updates only\nDump BGP updates only (Extended Tiemstamp Header)\n"
746 "Dump whole BGP routing table\n"
paul718e3742002-12-13 20:15:29 +0000747 "Output filename\n"
748 "Interval of output\n")
749{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500750 int bgp_dump_type = 0;
751 const char *interval = NULL;
752 struct bgp_dump *bgp_dump_struct = NULL;
753 const struct bgp_dump_type_map *map = NULL;
754
755 for (map = bgp_dump_type_map; map->str; map++)
756 if (strcmp(argv[0], map->str) == 0)
757 bgp_dump_type = map->type;
758
759 switch (bgp_dump_type)
760 {
761 case BGP_DUMP_ALL:
762 case BGP_DUMP_ALL_ET:
763 bgp_dump_struct = &bgp_dump_all;
764 break;
765 case BGP_DUMP_UPDATES:
766 case BGP_DUMP_UPDATES_ET:
767 bgp_dump_struct = &bgp_dump_updates;
768 break;
769 case BGP_DUMP_ROUTES:
770 default:
771 bgp_dump_struct = &bgp_dump_routes;
772 break;
773 }
774
775 /* When an interval is given */
776 if (argc == 3)
777 interval = argv[2];
778
779 return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type,
780 argv[1], interval);
paul718e3742002-12-13 20:15:29 +0000781}
782
783DEFUN (no_dump_bgp_all,
784 no_dump_bgp_all_cmd,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500785 "no dump bgp (all|updates|routes-mrt) [PATH] [INTERVAL]",
paul718e3742002-12-13 20:15:29 +0000786 NO_STR
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500787 "Stop dump packet\n"
788 "Stop BGP packet dump\n"
789 "Stop dump process all/all-et\n"
790 "Stop dump process updates/updates-et\n"
791 "Stop dump process route-mrt\n")
paul718e3742002-12-13 20:15:29 +0000792{
793 return bgp_dump_unset (vty, &bgp_dump_all);
794}
795
paul718e3742002-12-13 20:15:29 +0000796/* BGP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -0800797static struct cmd_node bgp_dump_node =
paul718e3742002-12-13 20:15:29 +0000798{
799 DUMP_NODE,
800 "",
hasso501ba492004-10-13 21:32:46 +0000801 1
paul718e3742002-12-13 20:15:29 +0000802};
803
804#if 0
805char *
806config_time2str (unsigned int interval)
807{
808 static char buf[BUFSIZ];
809
810 buf[0] = '\0';
811
812 if (interval / 3600)
813 {
814 sprintf (buf, "%dh", interval / 3600);
815 interval %= 3600;
816 }
817 if (interval / 60)
818 {
819 sprintf (buf + strlen (buf), "%dm", interval /60);
820 interval %= 60;
821 }
822 if (interval)
823 {
824 sprintf (buf + strlen (buf), "%d", interval);
825 }
826 return buf;
827}
828#endif
829
paul94f2b392005-06-28 12:44:16 +0000830static int
paul718e3742002-12-13 20:15:29 +0000831config_write_bgp_dump (struct vty *vty)
832{
833 if (bgp_dump_all.filename)
834 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500835 const char *type_str = "all";
836 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
837 type_str = "all-et";
838
paul718e3742002-12-13 20:15:29 +0000839 if (bgp_dump_all.interval_str)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500840 vty_out (vty, "dump bgp %s %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000841 bgp_dump_all.filename, bgp_dump_all.interval_str,
842 VTY_NEWLINE);
843 else
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500844 vty_out (vty, "dump bgp %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000845 bgp_dump_all.filename, VTY_NEWLINE);
846 }
847 if (bgp_dump_updates.filename)
848 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500849 const char *type_str = "updates";
850 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
851 type_str = "updates-et";
852
paul718e3742002-12-13 20:15:29 +0000853 if (bgp_dump_updates.interval_str)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500854 vty_out (vty, "dump bgp %s %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000855 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
856 VTY_NEWLINE);
857 else
858 vty_out (vty, "dump bgp updates %s%s",
859 bgp_dump_updates.filename, VTY_NEWLINE);
860 }
861 if (bgp_dump_routes.filename)
862 {
863 if (bgp_dump_routes.interval_str)
864 vty_out (vty, "dump bgp routes-mrt %s %s%s",
865 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
866 VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000867 }
868 return 0;
869}
David Lamparter6b0655a2014-06-04 06:53:35 +0200870
paul718e3742002-12-13 20:15:29 +0000871/* Initialize BGP packet dump functionality. */
872void
paul94f2b392005-06-28 12:44:16 +0000873bgp_dump_init (void)
paul718e3742002-12-13 20:15:29 +0000874{
875 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
876 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
877 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
878
Evgeny Uskovb4e01192016-01-13 13:58:00 +0300879 bgp_dump_obuf = stream_new ((BGP_MAX_PACKET_SIZE << 1)
880 + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000881
882 install_node (&bgp_dump_node, config_write_bgp_dump);
883
884 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
paul718e3742002-12-13 20:15:29 +0000885 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
paul718e3742002-12-13 20:15:29 +0000886}
Chris Caputo228da422009-07-18 05:44:03 +0000887
888void
889bgp_dump_finish (void)
890{
891 stream_free (bgp_dump_obuf);
892 bgp_dump_obuf = NULL;
893}