blob: 227fc7af09d892e10e4c61f558e3bcc09e7f43a8 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP-4 dump routine
2 Copyright (C) 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "log.h"
24#include "stream.h"
25#include "sockunion.h"
26#include "command.h"
27#include "prefix.h"
28#include "thread.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000029#include "linklist.h"
paul718e3742002-12-13 20:15:29 +000030#include "bgpd/bgp_table.h"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_route.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_dump.h"
David Lamparter6b0655a2014-06-04 06:53:35 +020036
paul718e3742002-12-13 20:15:29 +000037enum bgp_dump_type
38{
39 BGP_DUMP_ALL,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -050040 BGP_DUMP_ALL_ET,
paul718e3742002-12-13 20:15:29 +000041 BGP_DUMP_UPDATES,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -050042 BGP_DUMP_UPDATES_ET,
paul718e3742002-12-13 20:15:29 +000043 BGP_DUMP_ROUTES
44};
45
Alexis Fasqueldbe99e02015-11-16 13:55:16 -050046static const struct bgp_dump_type_map {
47 enum bgp_dump_type type;
48 const char *str;
49} bgp_dump_type_map[] =
50 {
51 {BGP_DUMP_ALL, "all"},
52 {BGP_DUMP_ALL_ET, "all-et"},
53 {BGP_DUMP_UPDATES, "updates"},
54 {BGP_DUMP_UPDATES_ET, "updates-et"},
55 {BGP_DUMP_ROUTES, "routes-mrt"},
56 {0, NULL},
57 };
58
paul718e3742002-12-13 20:15:29 +000059enum MRT_MSG_TYPES {
60 MSG_NULL,
61 MSG_START, /* sender is starting up */
62 MSG_DIE, /* receiver should shut down */
63 MSG_I_AM_DEAD, /* sender is shutting down */
64 MSG_PEER_DOWN, /* sender's peer is down */
65 MSG_PROTOCOL_BGP, /* msg is a BGP packet */
66 MSG_PROTOCOL_RIP, /* msg is a RIP packet */
67 MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */
68 MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */
69 MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */
70 MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
71 MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000072 MSG_TABLE_DUMP, /* routing table dump */
73 MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */
paul718e3742002-12-13 20:15:29 +000074};
75
76struct bgp_dump
77{
78 enum bgp_dump_type type;
79
80 char *filename;
81
82 FILE *fp;
83
84 unsigned int interval;
85
86 char *interval_str;
87
88 struct thread *t_interval;
89};
90
Alexis Fasqueldbe99e02015-11-16 13:55:16 -050091static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump);
92static int bgp_dump_interval_func (struct thread *);
93
paul718e3742002-12-13 20:15:29 +000094/* BGP packet dump output buffer. */
95struct stream *bgp_dump_obuf;
96
97/* BGP dump strucuture for 'dump bgp all' */
98struct bgp_dump bgp_dump_all;
99
100/* BGP dump structure for 'dump bgp updates' */
101struct bgp_dump bgp_dump_updates;
102
103/* BGP dump structure for 'dump bgp routes' */
104struct bgp_dump bgp_dump_routes;
105
paul94f2b392005-06-28 12:44:16 +0000106static FILE *
paul718e3742002-12-13 20:15:29 +0000107bgp_dump_open_file (struct bgp_dump *bgp_dump)
108{
109 int ret;
110 time_t clock;
111 struct tm *tm;
112 char fullpath[MAXPATHLEN];
113 char realpath[MAXPATHLEN];
gdtaa593d52003-12-22 20:15:53 +0000114 mode_t oldumask;
paul718e3742002-12-13 20:15:29 +0000115
116 time (&clock);
117 tm = localtime (&clock);
118
119 if (bgp_dump->filename[0] != DIRECTORY_SEP)
120 {
121 sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
122 ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
123 }
124 else
125 ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
126
127 if (ret == 0)
128 {
129 zlog_warn ("bgp_dump_open_file: strftime error");
130 return NULL;
131 }
132
133 if (bgp_dump->fp)
134 fclose (bgp_dump->fp);
135
136
gdtaa593d52003-12-22 20:15:53 +0000137 oldumask = umask(0777 & ~LOGFILE_MASK);
paul718e3742002-12-13 20:15:29 +0000138 bgp_dump->fp = fopen (realpath, "w");
139
140 if (bgp_dump->fp == NULL)
gdtaa593d52003-12-22 20:15:53 +0000141 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000142 zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno));
gdtaa593d52003-12-22 20:15:53 +0000143 umask(oldumask);
144 return NULL;
145 }
146 umask(oldumask);
paul718e3742002-12-13 20:15:29 +0000147
148 return bgp_dump->fp;
149}
150
paul94f2b392005-06-28 12:44:16 +0000151static int
paul718e3742002-12-13 20:15:29 +0000152bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
153{
Paul Jakma45ad5922007-07-31 17:35:36 +0000154 int secs_into_day;
paul9834cd02003-10-18 01:01:19 +0000155 time_t t;
156 struct tm *tm;
paul718e3742002-12-13 20:15:29 +0000157
Paul Jakma45ad5922007-07-31 17:35:36 +0000158 if (interval > 0)
paul9834cd02003-10-18 01:01:19 +0000159 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000160 /* Periodic dump every interval seconds */
paul9834cd02003-10-18 01:01:19 +0000161 if ((interval < 86400) && ((86400 % interval) == 0))
162 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000163 /* Dump at predictable times: if a day has a whole number of
164 * intervals, dump every interval seconds starting from midnight
165 */
paul9834cd02003-10-18 01:01:19 +0000166 (void) time(&t);
167 tm = localtime(&t);
168 secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour;
Paul Jakma45ad5922007-07-31 17:35:36 +0000169 interval = interval - secs_into_day % interval; /* always > 0 */
paul9834cd02003-10-18 01:01:19 +0000170 }
Donald Sharp774914f2015-10-14 08:50:39 -0400171 bgp_dump->t_interval = thread_add_timer (bm->master, bgp_dump_interval_func,
Paul Jakma45ad5922007-07-31 17:35:36 +0000172 bgp_dump, interval);
paul9834cd02003-10-18 01:01:19 +0000173 }
paulfba3d222003-05-10 18:33:28 +0000174 else
paul9834cd02003-10-18 01:01:19 +0000175 {
Paul Jakma45ad5922007-07-31 17:35:36 +0000176 /* One-off dump: execute immediately, don't affect any scheduled dumps */
Donald Sharp774914f2015-10-14 08:50:39 -0400177 bgp_dump->t_interval = thread_add_event (bm->master, bgp_dump_interval_func,
paul9834cd02003-10-18 01:01:19 +0000178 bgp_dump, 0);
179 }
paulfba3d222003-05-10 18:33:28 +0000180
paul718e3742002-12-13 20:15:29 +0000181 return 0;
182}
183
184/* Dump common header. */
paul94f2b392005-06-28 12:44:16 +0000185static void
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500186bgp_dump_header (struct stream *obuf, int type, int subtype, int dump_type)
paul718e3742002-12-13 20:15:29 +0000187{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500188 struct timeval clock;
189 long msecs;
190 time_t secs;
paul718e3742002-12-13 20:15:29 +0000191
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500192 if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET)
193 && type == MSG_PROTOCOL_BGP4MP)
194 type = MSG_PROTOCOL_BGP4MP_ET;
195
196 gettimeofday(&clock, NULL);
197
198 secs = clock.tv_sec;
199 msecs = clock.tv_usec;
paul718e3742002-12-13 20:15:29 +0000200
201 /* Put dump packet header. */
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500202 stream_putl (obuf, secs);
paul718e3742002-12-13 20:15:29 +0000203 stream_putw (obuf, type);
204 stream_putw (obuf, subtype);
paul718e3742002-12-13 20:15:29 +0000205 stream_putl (obuf, 0); /* len */
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500206
207 /* Adding microseconds for the MRT Extended Header */
208 if (type == MSG_PROTOCOL_BGP4MP_ET)
209 stream_putl (obuf, msecs);
paul718e3742002-12-13 20:15:29 +0000210}
211
paul94f2b392005-06-28 12:44:16 +0000212static void
paul718e3742002-12-13 20:15:29 +0000213bgp_dump_set_size (struct stream *s, int type)
214{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500215 /*
216 * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET:
217 * "The Microsecond Timestamp is included in the computation
218 * of the Length field value." (RFC6396 2011)
219 */
paul9985f832005-02-09 15:51:56 +0000220 stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000221}
222
paul94f2b392005-06-28 12:44:16 +0000223static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000224bgp_dump_routes_index_table(struct bgp *bgp)
paul718e3742002-12-13 20:15:29 +0000225{
paul718e3742002-12-13 20:15:29 +0000226 struct peer *peer;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000227 struct listnode *node;
228 uint16_t peerno = 0;
229 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000230
paul718e3742002-12-13 20:15:29 +0000231 obuf = bgp_dump_obuf;
232 stream_reset (obuf);
233
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000234 /* MRT header */
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500235 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE,
236 BGP_DUMP_ROUTES);
paul718e3742002-12-13 20:15:29 +0000237
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000238 /* Collector BGP ID */
239 stream_put_in_addr (obuf, &bgp->router_id);
240
241 /* View name */
242 if(bgp->name)
paul718e3742002-12-13 20:15:29 +0000243 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000244 stream_putw (obuf, strlen(bgp->name));
245 stream_put(obuf, bgp->name, strlen(bgp->name));
paul718e3742002-12-13 20:15:29 +0000246 }
247 else
248 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000249 stream_putw(obuf, 0);
paul718e3742002-12-13 20:15:29 +0000250 }
251
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000252 /* Peer count */
253 stream_putw (obuf, listcount(bgp->peer));
254
255 /* Walk down all peers */
256 for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
paul718e3742002-12-13 20:15:29 +0000257 {
paul718e3742002-12-13 20:15:29 +0000258
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000259 /* Peer's type */
260 if (sockunion_family(&peer->su) == AF_INET)
261 {
262 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
263 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000264 else if (sockunion_family(&peer->su) == AF_INET6)
265 {
266 stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
267 }
paul718e3742002-12-13 20:15:29 +0000268
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000269 /* Peer's BGP ID */
270 stream_put_in_addr (obuf, &peer->remote_id);
271
272 /* Peer's IP address */
273 if (sockunion_family(&peer->su) == AF_INET)
274 {
275 stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
276 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000277 else if (sockunion_family(&peer->su) == AF_INET6)
278 {
279 stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
280 IPV6_MAX_BYTELEN);
281 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000282
283 /* Peer's AS number. */
284 /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
285 stream_putl (obuf, peer->as);
286
287 /* Store the peer number for this peer */
288 peer->table_dump_index = peerno;
289 peerno++;
290 }
291
292 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
paul718e3742002-12-13 20:15:29 +0000293
David Lampartera6694fe2013-01-16 01:28:36 +0100294 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
paul718e3742002-12-13 20:15:29 +0000295 fflush (bgp_dump_routes.fp);
296}
297
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000298
paul718e3742002-12-13 20:15:29 +0000299/* Runs under child process. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000300static unsigned int
301bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
paul718e3742002-12-13 20:15:29 +0000302{
303 struct stream *obuf;
paul718e3742002-12-13 20:15:29 +0000304 struct bgp_info *info;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000305 struct bgp_node *rn;
paul718e3742002-12-13 20:15:29 +0000306 struct bgp *bgp;
307 struct bgp_table *table;
paul718e3742002-12-13 20:15:29 +0000308
309 bgp = bgp_get_default ();
310 if (!bgp)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000311 return seq;
paul718e3742002-12-13 20:15:29 +0000312
313 if (bgp_dump_routes.fp == NULL)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000314 return seq;
315
316 /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
317 so this should only be done on the first call to bgp_dump_routes_func.
318 ( this function will be called once for ipv4 and once for ipv6 ) */
319 if(first_run)
320 bgp_dump_routes_index_table(bgp);
321
322 obuf = bgp_dump_obuf;
323 stream_reset(obuf);
paul718e3742002-12-13 20:15:29 +0000324
325 /* Walk down each BGP route. */
326 table = bgp->rib[afi][SAFI_UNICAST];
327
328 for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000329 {
330 if(!rn->info)
331 continue;
332
333 stream_reset(obuf);
334
335 /* MRT header */
336 if (afi == AFI_IP)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500337 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST,
338 BGP_DUMP_ROUTES);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000339 else if (afi == AFI_IP6)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500340 bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST,
341 BGP_DUMP_ROUTES);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000342
343 /* Sequence number */
344 stream_putl(obuf, seq);
345
346 /* Prefix length */
347 stream_putc (obuf, rn->p.prefixlen);
348
349 /* Prefix */
350 if (afi == AFI_IP)
351 {
352 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
353 stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
354 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000355 else if (afi == AFI_IP6)
356 {
357 /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
358 stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
359 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000360
361 /* Save where we are now, so we can overwride the entry count later */
362 int sizep = stream_get_endp(obuf);
363
364 /* Entry count */
365 uint16_t entry_count = 0;
366
367 /* Entry count, note that this is overwritten later */
368 stream_putw(obuf, 0);
369
370 for (info = rn->info; info; info = info->next)
371 {
372 entry_count++;
373
374 /* Peer index */
375 stream_putw(obuf, info->peer->table_dump_index);
376
377 /* Originated */
John Kemp30b00172011-03-18 17:52:18 +0300378#ifdef HAVE_CLOCK_MONOTONIC
379 stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
380#else
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000381 stream_putl (obuf, info->uptime);
John Kemp30b00172011-03-18 17:52:18 +0300382#endif /* HAVE_CLOCK_MONOTONIC */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000383
384 /* Dump attribute. */
385 /* Skip prefix & AFI/SAFI for MP_NLRI */
386 bgp_dump_routes_attr (obuf, info->attr, &rn->p);
387 }
388
389 /* Overwrite the entry count, now that we know the right number */
390 stream_putw_at (obuf, sizep, entry_count);
391
392 seq++;
393
394 bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
David Lampartera6694fe2013-01-16 01:28:36 +0100395 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
396
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000397 }
398
399 fflush (bgp_dump_routes.fp);
400
401 return seq;
paul718e3742002-12-13 20:15:29 +0000402}
403
paul94f2b392005-06-28 12:44:16 +0000404static int
paul718e3742002-12-13 20:15:29 +0000405bgp_dump_interval_func (struct thread *t)
406{
407 struct bgp_dump *bgp_dump;
paul718e3742002-12-13 20:15:29 +0000408 bgp_dump = THREAD_ARG (t);
409 bgp_dump->t_interval = NULL;
410
paul9834cd02003-10-18 01:01:19 +0000411 /* Reschedule dump even if file couldn't be opened this time... */
412 if (bgp_dump_open_file (bgp_dump) != NULL)
paul718e3742002-12-13 20:15:29 +0000413 {
paul9834cd02003-10-18 01:01:19 +0000414 /* In case of bgp_dump_routes, we need special route dump function. */
415 if (bgp_dump->type == BGP_DUMP_ROUTES)
416 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000417 unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000418 bgp_dump_routes_func (AFI_IP6, 0, seq);
paul9834cd02003-10-18 01:01:19 +0000419 /* Close the file now. For a RIB dump there's no point in leaving
420 * it open until the next scheduled dump starts. */
421 fclose(bgp_dump->fp); bgp_dump->fp = NULL;
422 }
paul718e3742002-12-13 20:15:29 +0000423 }
424
paulfba3d222003-05-10 18:33:28 +0000425 /* if interval is set reschedule */
426 if (bgp_dump->interval > 0)
427 bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
428
paul718e3742002-12-13 20:15:29 +0000429 return 0;
430}
431
432/* Dump common information. */
paul94f2b392005-06-28 12:44:16 +0000433static void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000434bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
paul718e3742002-12-13 20:15:29 +0000435{
436 char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
437
438 /* Source AS number and Destination AS number. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000439 if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
440 {
441 stream_putl (obuf, peer->as);
442 stream_putl (obuf, peer->local_as);
443 }
444 else
445 {
446 stream_putw (obuf, peer->as);
447 stream_putw (obuf, peer->local_as);
448 }
paul718e3742002-12-13 20:15:29 +0000449
paula3845922003-10-18 01:30:50 +0000450 if (peer->su.sa.sa_family == AF_INET)
paul718e3742002-12-13 20:15:29 +0000451 {
452 stream_putw (obuf, peer->ifindex);
453 stream_putw (obuf, AFI_IP);
454
455 stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
456
457 if (peer->su_local)
458 stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
459 else
460 stream_put (obuf, empty, IPV4_MAX_BYTELEN);
461 }
paula3845922003-10-18 01:30:50 +0000462 else if (peer->su.sa.sa_family == AF_INET6)
paul718e3742002-12-13 20:15:29 +0000463 {
464 /* Interface Index and Address family. */
465 stream_putw (obuf, peer->ifindex);
466 stream_putw (obuf, AFI_IP6);
467
468 /* Source IP Address and Destination IP Address. */
469 stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
470
471 if (peer->su_local)
472 stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
473 else
474 stream_put (obuf, empty, IPV6_MAX_BYTELEN);
475 }
paul718e3742002-12-13 20:15:29 +0000476}
477
478/* Dump BGP status change. */
479void
480bgp_dump_state (struct peer *peer, int status_old, int status_new)
481{
482 struct stream *obuf;
483
484 /* If dump file pointer is disabled return immediately. */
485 if (bgp_dump_all.fp == NULL)
486 return;
487
488 /* Make dump stream. */
489 obuf = bgp_dump_obuf;
490 stream_reset (obuf);
491
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500492 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4,
493 bgp_dump_all.type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000494 bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
paul718e3742002-12-13 20:15:29 +0000495
496 stream_putw (obuf, status_old);
497 stream_putw (obuf, status_new);
498
499 /* Set length. */
500 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
501
502 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100503 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
paul718e3742002-12-13 20:15:29 +0000504 fflush (bgp_dump_all.fp);
505}
506
paul94f2b392005-06-28 12:44:16 +0000507static void
paul718e3742002-12-13 20:15:29 +0000508bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
509 struct stream *packet)
510{
511 struct stream *obuf;
512
513 /* If dump file pointer is disabled return immediately. */
514 if (bgp_dump->fp == NULL)
515 return;
516
517 /* Make dump stream. */
518 obuf = bgp_dump_obuf;
519 stream_reset (obuf);
520
521 /* Dump header and common part. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000522 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
523 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500524 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4,
525 bgp_dump->type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000526 }
527 else
528 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500529 bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE,
530 bgp_dump->type);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000531 }
532 bgp_dump_common (obuf, peer, 0);
paul718e3742002-12-13 20:15:29 +0000533
534 /* Packet contents. */
535 stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
536
537 /* Set length. */
538 bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
539
540 /* Write to the stream. */
David Lampartera6694fe2013-01-16 01:28:36 +0100541 fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
paul718e3742002-12-13 20:15:29 +0000542 fflush (bgp_dump->fp);
543}
544
545/* Called from bgp_packet.c when BGP packet is received. */
546void
547bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
548{
549 /* bgp_dump_all. */
550 bgp_dump_packet_func (&bgp_dump_all, peer, packet);
551
552 /* bgp_dump_updates. */
553 if (type == BGP_MSG_UPDATE)
554 bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
555}
David Lamparter6b0655a2014-06-04 06:53:35 +0200556
paul94f2b392005-06-28 12:44:16 +0000557static unsigned int
paulfd79ac92004-10-13 05:06:08 +0000558bgp_dump_parse_time (const char *str)
paul718e3742002-12-13 20:15:29 +0000559{
560 int i;
561 int len;
562 int seen_h;
563 int seen_m;
564 int time;
565 unsigned int total;
566
567 time = 0;
568 total = 0;
569 seen_h = 0;
570 seen_m = 0;
571 len = strlen (str);
572
573 for (i = 0; i < len; i++)
574 {
575 if (isdigit ((int) str[i]))
576 {
577 time *= 10;
578 time += str[i] - '0';
579 }
580 else if (str[i] == 'H' || str[i] == 'h')
581 {
582 if (seen_h)
583 return 0;
584 if (seen_m)
585 return 0;
586 total += time * 60 *60;
587 time = 0;
588 seen_h = 1;
589 }
590 else if (str[i] == 'M' || str[i] == 'm')
591 {
592 if (seen_m)
593 return 0;
594 total += time * 60;
595 time = 0;
596 seen_h = 1;
597 }
598 else
599 return 0;
600 }
601 return total + time;
602}
603
paul94f2b392005-06-28 12:44:16 +0000604static int
Paul Jakma45ad5922007-07-31 17:35:36 +0000605bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
606 enum bgp_dump_type type, const char *path,
607 const char *interval_str)
paul718e3742002-12-13 20:15:29 +0000608{
paulfba3d222003-05-10 18:33:28 +0000609 unsigned int interval;
610
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500611 /* Don't schedule duplicate dumps if the dump command is given twice */
612 if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0
613 && type == bgp_dump->type)
614 {
615 if (interval_str)
616 {
617 if (bgp_dump->interval_str &&
618 strcmp(bgp_dump->interval_str, interval_str) == 0)
619 return CMD_SUCCESS;
620 }
621 else
622 {
623 if (!bgp_dump->interval_str)
624 return CMD_SUCCESS;
625 }
626 }
627
628 /* Removing previous config */
629 bgp_dump_unset(vty, bgp_dump);
630
paul718e3742002-12-13 20:15:29 +0000631 if (interval_str)
632 {
paul718e3742002-12-13 20:15:29 +0000633 /* Check interval string. */
634 interval = bgp_dump_parse_time (interval_str);
635 if (interval == 0)
636 {
637 vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
638 return CMD_WARNING;
639 }
Paul Jakma45ad5922007-07-31 17:35:36 +0000640
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500641 /* Setting interval string */
paul718e3742002-12-13 20:15:29 +0000642 bgp_dump->interval_str = strdup (interval_str);
paul718e3742002-12-13 20:15:29 +0000643 }
paulfba3d222003-05-10 18:33:28 +0000644 else
645 {
646 interval = 0;
647 }
paul718e3742002-12-13 20:15:29 +0000648
649 /* Set type. */
650 bgp_dump->type = type;
651
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500652 /* Set interval */
653 bgp_dump->interval = interval;
654
paul718e3742002-12-13 20:15:29 +0000655 /* Set file name. */
paul718e3742002-12-13 20:15:29 +0000656 bgp_dump->filename = strdup (path);
657
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500658 /* Create interval thread. */
659 bgp_dump_interval_add (bgp_dump, interval);
660
paul718e3742002-12-13 20:15:29 +0000661 /* This should be called when interval is expired. */
662 bgp_dump_open_file (bgp_dump);
663
664 return CMD_SUCCESS;
665}
666
paul94f2b392005-06-28 12:44:16 +0000667static int
paul718e3742002-12-13 20:15:29 +0000668bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
669{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500670 /* Removing file name. */
paul718e3742002-12-13 20:15:29 +0000671 if (bgp_dump->filename)
672 {
673 free (bgp_dump->filename);
674 bgp_dump->filename = NULL;
675 }
676
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500677 /* Closing file. */
paul718e3742002-12-13 20:15:29 +0000678 if (bgp_dump->fp)
679 {
680 fclose (bgp_dump->fp);
681 bgp_dump->fp = NULL;
682 }
683
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500684 /* Removing interval thread. */
paul718e3742002-12-13 20:15:29 +0000685 if (bgp_dump->t_interval)
686 {
687 thread_cancel (bgp_dump->t_interval);
688 bgp_dump->t_interval = NULL;
689 }
690
691 bgp_dump->interval = 0;
692
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500693 /* Removing interval string. */
paul718e3742002-12-13 20:15:29 +0000694 if (bgp_dump->interval_str)
695 {
696 free (bgp_dump->interval_str);
697 bgp_dump->interval_str = NULL;
698 }
699
paul718e3742002-12-13 20:15:29 +0000700 return CMD_SUCCESS;
701}
702
703DEFUN (dump_bgp_all,
704 dump_bgp_all_cmd,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500705 "dump bgp (all|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]",
paul718e3742002-12-13 20:15:29 +0000706 "Dump packet\n"
707 "BGP packet dump\n"
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500708 "Dump all BGP packets\nDump all BGP packets (Extended Tiemstamp Header)\n"
709 "Dump BGP updates only\nDump BGP updates only (Extended Tiemstamp Header)\n"
710 "Dump whole BGP routing table\n"
paul718e3742002-12-13 20:15:29 +0000711 "Output filename\n"
712 "Interval of output\n")
713{
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500714 int bgp_dump_type = 0;
715 const char *interval = NULL;
716 struct bgp_dump *bgp_dump_struct = NULL;
717 const struct bgp_dump_type_map *map = NULL;
718
719 for (map = bgp_dump_type_map; map->str; map++)
720 if (strcmp(argv[0], map->str) == 0)
721 bgp_dump_type = map->type;
722
723 switch (bgp_dump_type)
724 {
725 case BGP_DUMP_ALL:
726 case BGP_DUMP_ALL_ET:
727 bgp_dump_struct = &bgp_dump_all;
728 break;
729 case BGP_DUMP_UPDATES:
730 case BGP_DUMP_UPDATES_ET:
731 bgp_dump_struct = &bgp_dump_updates;
732 break;
733 case BGP_DUMP_ROUTES:
734 default:
735 bgp_dump_struct = &bgp_dump_routes;
736 break;
737 }
738
739 /* When an interval is given */
740 if (argc == 3)
741 interval = argv[2];
742
743 return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type,
744 argv[1], interval);
paul718e3742002-12-13 20:15:29 +0000745}
746
747DEFUN (no_dump_bgp_all,
748 no_dump_bgp_all_cmd,
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500749 "no dump bgp (all|updates|routes-mrt) [PATH] [INTERVAL]",
paul718e3742002-12-13 20:15:29 +0000750 NO_STR
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500751 "Stop dump packet\n"
752 "Stop BGP packet dump\n"
753 "Stop dump process all/all-et\n"
754 "Stop dump process updates/updates-et\n"
755 "Stop dump process route-mrt\n")
paul718e3742002-12-13 20:15:29 +0000756{
757 return bgp_dump_unset (vty, &bgp_dump_all);
758}
759
paul718e3742002-12-13 20:15:29 +0000760/* BGP node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -0800761static struct cmd_node bgp_dump_node =
paul718e3742002-12-13 20:15:29 +0000762{
763 DUMP_NODE,
764 "",
hasso501ba492004-10-13 21:32:46 +0000765 1
paul718e3742002-12-13 20:15:29 +0000766};
767
768#if 0
769char *
770config_time2str (unsigned int interval)
771{
772 static char buf[BUFSIZ];
773
774 buf[0] = '\0';
775
776 if (interval / 3600)
777 {
778 sprintf (buf, "%dh", interval / 3600);
779 interval %= 3600;
780 }
781 if (interval / 60)
782 {
783 sprintf (buf + strlen (buf), "%dm", interval /60);
784 interval %= 60;
785 }
786 if (interval)
787 {
788 sprintf (buf + strlen (buf), "%d", interval);
789 }
790 return buf;
791}
792#endif
793
paul94f2b392005-06-28 12:44:16 +0000794static int
paul718e3742002-12-13 20:15:29 +0000795config_write_bgp_dump (struct vty *vty)
796{
797 if (bgp_dump_all.filename)
798 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500799 const char *type_str = "all";
800 if (bgp_dump_all.type == BGP_DUMP_ALL_ET)
801 type_str = "all-et";
802
paul718e3742002-12-13 20:15:29 +0000803 if (bgp_dump_all.interval_str)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500804 vty_out (vty, "dump bgp %s %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000805 bgp_dump_all.filename, bgp_dump_all.interval_str,
806 VTY_NEWLINE);
807 else
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500808 vty_out (vty, "dump bgp %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000809 bgp_dump_all.filename, VTY_NEWLINE);
810 }
811 if (bgp_dump_updates.filename)
812 {
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500813 const char *type_str = "updates";
814 if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET)
815 type_str = "updates-et";
816
paul718e3742002-12-13 20:15:29 +0000817 if (bgp_dump_updates.interval_str)
Alexis Fasqueldbe99e02015-11-16 13:55:16 -0500818 vty_out (vty, "dump bgp %s %s %s%s", type_str,
paul718e3742002-12-13 20:15:29 +0000819 bgp_dump_updates.filename, bgp_dump_updates.interval_str,
820 VTY_NEWLINE);
821 else
822 vty_out (vty, "dump bgp updates %s%s",
823 bgp_dump_updates.filename, VTY_NEWLINE);
824 }
825 if (bgp_dump_routes.filename)
826 {
827 if (bgp_dump_routes.interval_str)
828 vty_out (vty, "dump bgp routes-mrt %s %s%s",
829 bgp_dump_routes.filename, bgp_dump_routes.interval_str,
830 VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000831 }
832 return 0;
833}
David Lamparter6b0655a2014-06-04 06:53:35 +0200834
paul718e3742002-12-13 20:15:29 +0000835/* Initialize BGP packet dump functionality. */
836void
paul94f2b392005-06-28 12:44:16 +0000837bgp_dump_init (void)
paul718e3742002-12-13 20:15:29 +0000838{
839 memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
840 memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
841 memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
842
paul9834cd02003-10-18 01:01:19 +0000843 bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
844 + BGP_DUMP_HEADER_SIZE);
paul718e3742002-12-13 20:15:29 +0000845
846 install_node (&bgp_dump_node, config_write_bgp_dump);
847
848 install_element (CONFIG_NODE, &dump_bgp_all_cmd);
paul718e3742002-12-13 20:15:29 +0000849 install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
paul718e3742002-12-13 20:15:29 +0000850}
Chris Caputo228da422009-07-18 05:44:03 +0000851
852void
853bgp_dump_finish (void)
854{
855 stream_free (bgp_dump_obuf);
856 bgp_dump_obuf = NULL;
857}