Line data Source code
1 : /* BGP-4 dump routine
2 : Copyright (C) 1999 Kunihiro Ishiguro
3 :
4 : This file is part of GNU Zebra.
5 :
6 : GNU Zebra is free software; you can redistribute it and/or modify it
7 : under the terms of the GNU General Public License as published by the
8 : Free Software Foundation; either version 2, or (at your option) any
9 : later version.
10 :
11 : GNU Zebra is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GNU Zebra; see the file COPYING. If not, write to the Free
18 : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 : 02111-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"
29 : #include "linklist.h"
30 : #include "bgpd/bgp_table.h"
31 :
32 : #include "bgpd/bgpd.h"
33 : #include "bgpd/bgp_route.h"
34 : #include "bgpd/bgp_attr.h"
35 : #include "bgpd/bgp_dump.h"
36 :
37 : enum bgp_dump_type
38 : {
39 : BGP_DUMP_ALL,
40 : BGP_DUMP_UPDATES,
41 : BGP_DUMP_ROUTES
42 : };
43 :
44 : enum MRT_MSG_TYPES {
45 : MSG_NULL,
46 : MSG_START, /* sender is starting up */
47 : MSG_DIE, /* receiver should shut down */
48 : MSG_I_AM_DEAD, /* sender is shutting down */
49 : MSG_PEER_DOWN, /* sender's peer is down */
50 : MSG_PROTOCOL_BGP, /* msg is a BGP packet */
51 : MSG_PROTOCOL_RIP, /* msg is a RIP packet */
52 : MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */
53 : MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */
54 : MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */
55 : MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */
56 : MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */
57 : MSG_TABLE_DUMP, /* routing table dump */
58 : MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */
59 : };
60 :
61 : static int bgp_dump_interval_func (struct thread *);
62 :
63 : struct bgp_dump
64 : {
65 : enum bgp_dump_type type;
66 :
67 : char *filename;
68 :
69 : FILE *fp;
70 :
71 : unsigned int interval;
72 :
73 : char *interval_str;
74 :
75 : struct thread *t_interval;
76 : };
77 :
78 : /* BGP packet dump output buffer. */
79 : struct stream *bgp_dump_obuf;
80 :
81 : /* BGP dump strucuture for 'dump bgp all' */
82 : struct bgp_dump bgp_dump_all;
83 :
84 : /* BGP dump structure for 'dump bgp updates' */
85 : struct bgp_dump bgp_dump_updates;
86 :
87 : /* BGP dump structure for 'dump bgp routes' */
88 : struct bgp_dump bgp_dump_routes;
89 :
90 : /* Dump whole BGP table is very heavy process. */
91 : struct thread *t_bgp_dump_routes;
92 :
93 : /* Some define for BGP packet dump. */
94 : static FILE *
95 0 : bgp_dump_open_file (struct bgp_dump *bgp_dump)
96 : {
97 : int ret;
98 : time_t clock;
99 : struct tm *tm;
100 : char fullpath[MAXPATHLEN];
101 : char realpath[MAXPATHLEN];
102 : mode_t oldumask;
103 :
104 0 : time (&clock);
105 0 : tm = localtime (&clock);
106 :
107 0 : if (bgp_dump->filename[0] != DIRECTORY_SEP)
108 : {
109 0 : sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename);
110 0 : ret = strftime (realpath, MAXPATHLEN, fullpath, tm);
111 : }
112 : else
113 0 : ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm);
114 :
115 0 : if (ret == 0)
116 : {
117 0 : zlog_warn ("bgp_dump_open_file: strftime error");
118 0 : return NULL;
119 : }
120 :
121 0 : if (bgp_dump->fp)
122 0 : fclose (bgp_dump->fp);
123 :
124 :
125 0 : oldumask = umask(0777 & ~LOGFILE_MASK);
126 0 : bgp_dump->fp = fopen (realpath, "w");
127 :
128 0 : if (bgp_dump->fp == NULL)
129 : {
130 0 : zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno));
131 0 : umask(oldumask);
132 0 : return NULL;
133 : }
134 0 : umask(oldumask);
135 :
136 0 : return bgp_dump->fp;
137 : }
138 :
139 : static int
140 0 : bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval)
141 : {
142 : int secs_into_day;
143 : time_t t;
144 : struct tm *tm;
145 :
146 0 : if (interval > 0)
147 : {
148 : /* Periodic dump every interval seconds */
149 0 : if ((interval < 86400) && ((86400 % interval) == 0))
150 : {
151 : /* Dump at predictable times: if a day has a whole number of
152 : * intervals, dump every interval seconds starting from midnight
153 : */
154 0 : (void) time(&t);
155 0 : tm = localtime(&t);
156 0 : secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour;
157 0 : interval = interval - secs_into_day % interval; /* always > 0 */
158 : }
159 0 : bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func,
160 : bgp_dump, interval);
161 : }
162 : else
163 : {
164 : /* One-off dump: execute immediately, don't affect any scheduled dumps */
165 0 : bgp_dump->t_interval = thread_add_event (master, bgp_dump_interval_func,
166 : bgp_dump, 0);
167 : }
168 :
169 0 : return 0;
170 : }
171 :
172 : /* Dump common header. */
173 : static void
174 0 : bgp_dump_header (struct stream *obuf, int type, int subtype)
175 : {
176 : time_t now;
177 :
178 : /* Set header. */
179 0 : time (&now);
180 :
181 : /* Put dump packet header. */
182 0 : stream_putl (obuf, now);
183 0 : stream_putw (obuf, type);
184 0 : stream_putw (obuf, subtype);
185 :
186 0 : stream_putl (obuf, 0); /* len */
187 0 : }
188 :
189 : static void
190 0 : bgp_dump_set_size (struct stream *s, int type)
191 : {
192 0 : stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE);
193 0 : }
194 :
195 : static void
196 0 : bgp_dump_routes_index_table(struct bgp *bgp)
197 : {
198 : struct peer *peer;
199 : struct listnode *node;
200 0 : uint16_t peerno = 0;
201 : struct stream *obuf;
202 :
203 0 : obuf = bgp_dump_obuf;
204 0 : stream_reset (obuf);
205 :
206 : /* MRT header */
207 0 : bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE);
208 :
209 : /* Collector BGP ID */
210 0 : stream_put_in_addr (obuf, &bgp->router_id);
211 :
212 : /* View name */
213 0 : if(bgp->name)
214 : {
215 0 : stream_putw (obuf, strlen(bgp->name));
216 0 : stream_put(obuf, bgp->name, strlen(bgp->name));
217 : }
218 : else
219 : {
220 0 : stream_putw(obuf, 0);
221 : }
222 :
223 : /* Peer count */
224 0 : stream_putw (obuf, listcount(bgp->peer));
225 :
226 : /* Walk down all peers */
227 0 : for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
228 : {
229 :
230 : /* Peer's type */
231 0 : if (sockunion_family(&peer->su) == AF_INET)
232 : {
233 0 : stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP);
234 : }
235 : #ifdef HAVE_IPV6
236 0 : else if (sockunion_family(&peer->su) == AF_INET6)
237 : {
238 0 : stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6);
239 : }
240 : #endif /* HAVE_IPV6 */
241 :
242 : /* Peer's BGP ID */
243 0 : stream_put_in_addr (obuf, &peer->remote_id);
244 :
245 : /* Peer's IP address */
246 0 : if (sockunion_family(&peer->su) == AF_INET)
247 : {
248 0 : stream_put_in_addr (obuf, &peer->su.sin.sin_addr);
249 : }
250 : #ifdef HAVE_IPV6
251 0 : else if (sockunion_family(&peer->su) == AF_INET6)
252 : {
253 0 : stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr,
254 : IPV6_MAX_BYTELEN);
255 : }
256 : #endif /* HAVE_IPV6 */
257 :
258 : /* Peer's AS number. */
259 : /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */
260 0 : stream_putl (obuf, peer->as);
261 :
262 : /* Store the peer number for this peer */
263 0 : peer->table_dump_index = peerno;
264 0 : peerno++;
265 : }
266 :
267 0 : bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
268 :
269 0 : fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
270 0 : fflush (bgp_dump_routes.fp);
271 0 : }
272 :
273 :
274 : /* Runs under child process. */
275 : static unsigned int
276 0 : bgp_dump_routes_func (int afi, int first_run, unsigned int seq)
277 : {
278 : struct stream *obuf;
279 : struct bgp_info *info;
280 : struct bgp_node *rn;
281 : struct bgp *bgp;
282 : struct bgp_table *table;
283 :
284 0 : bgp = bgp_get_default ();
285 0 : if (!bgp)
286 0 : return seq;
287 :
288 0 : if (bgp_dump_routes.fp == NULL)
289 0 : return seq;
290 :
291 : /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers,
292 : so this should only be done on the first call to bgp_dump_routes_func.
293 : ( this function will be called once for ipv4 and once for ipv6 ) */
294 0 : if(first_run)
295 0 : bgp_dump_routes_index_table(bgp);
296 :
297 0 : obuf = bgp_dump_obuf;
298 0 : stream_reset(obuf);
299 :
300 : /* Walk down each BGP route. */
301 0 : table = bgp->rib[afi][SAFI_UNICAST];
302 :
303 0 : for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
304 : {
305 0 : if(!rn->info)
306 0 : continue;
307 :
308 0 : stream_reset(obuf);
309 :
310 : /* MRT header */
311 0 : if (afi == AFI_IP)
312 : {
313 0 : bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST);
314 : }
315 : #ifdef HAVE_IPV6
316 0 : else if (afi == AFI_IP6)
317 : {
318 0 : bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST);
319 : }
320 : #endif /* HAVE_IPV6 */
321 :
322 : /* Sequence number */
323 0 : stream_putl(obuf, seq);
324 :
325 : /* Prefix length */
326 0 : stream_putc (obuf, rn->p.prefixlen);
327 :
328 : /* Prefix */
329 0 : if (afi == AFI_IP)
330 : {
331 : /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
332 0 : stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8);
333 : }
334 : #ifdef HAVE_IPV6
335 0 : else if (afi == AFI_IP6)
336 : {
337 : /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */
338 0 : stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8);
339 : }
340 : #endif /* HAVE_IPV6 */
341 :
342 : /* Save where we are now, so we can overwride the entry count later */
343 0 : int sizep = stream_get_endp(obuf);
344 :
345 : /* Entry count */
346 0 : uint16_t entry_count = 0;
347 :
348 : /* Entry count, note that this is overwritten later */
349 0 : stream_putw(obuf, 0);
350 :
351 0 : for (info = rn->info; info; info = info->next)
352 : {
353 0 : entry_count++;
354 :
355 : /* Peer index */
356 0 : stream_putw(obuf, info->peer->table_dump_index);
357 :
358 : /* Originated */
359 : #ifdef HAVE_CLOCK_MONOTONIC
360 0 : stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime));
361 : #else
362 : stream_putl (obuf, info->uptime);
363 : #endif /* HAVE_CLOCK_MONOTONIC */
364 :
365 : /* Dump attribute. */
366 : /* Skip prefix & AFI/SAFI for MP_NLRI */
367 0 : bgp_dump_routes_attr (obuf, info->attr, &rn->p);
368 : }
369 :
370 : /* Overwrite the entry count, now that we know the right number */
371 0 : stream_putw_at (obuf, sizep, entry_count);
372 :
373 0 : seq++;
374 :
375 0 : bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2);
376 0 : fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp);
377 :
378 : }
379 :
380 0 : fflush (bgp_dump_routes.fp);
381 :
382 0 : return seq;
383 : }
384 :
385 : static int
386 0 : bgp_dump_interval_func (struct thread *t)
387 : {
388 : struct bgp_dump *bgp_dump;
389 0 : bgp_dump = THREAD_ARG (t);
390 0 : bgp_dump->t_interval = NULL;
391 :
392 : /* Reschedule dump even if file couldn't be opened this time... */
393 0 : if (bgp_dump_open_file (bgp_dump) != NULL)
394 : {
395 : /* In case of bgp_dump_routes, we need special route dump function. */
396 0 : if (bgp_dump->type == BGP_DUMP_ROUTES)
397 : {
398 0 : unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0);
399 : #ifdef HAVE_IPV6
400 0 : bgp_dump_routes_func (AFI_IP6, 0, seq);
401 : #endif /* HAVE_IPV6 */
402 : /* Close the file now. For a RIB dump there's no point in leaving
403 : * it open until the next scheduled dump starts. */
404 0 : fclose(bgp_dump->fp); bgp_dump->fp = NULL;
405 : }
406 : }
407 :
408 : /* if interval is set reschedule */
409 0 : if (bgp_dump->interval > 0)
410 0 : bgp_dump_interval_add (bgp_dump, bgp_dump->interval);
411 :
412 0 : return 0;
413 : }
414 :
415 : /* Dump common information. */
416 : static void
417 0 : bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4)
418 : {
419 0 : char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
420 :
421 : /* Source AS number and Destination AS number. */
422 0 : if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
423 : {
424 0 : stream_putl (obuf, peer->as);
425 0 : stream_putl (obuf, peer->local_as);
426 : }
427 : else
428 : {
429 0 : stream_putw (obuf, peer->as);
430 0 : stream_putw (obuf, peer->local_as);
431 : }
432 :
433 0 : if (peer->su.sa.sa_family == AF_INET)
434 : {
435 0 : stream_putw (obuf, peer->ifindex);
436 0 : stream_putw (obuf, AFI_IP);
437 :
438 0 : stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN);
439 :
440 0 : if (peer->su_local)
441 0 : stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN);
442 : else
443 0 : stream_put (obuf, empty, IPV4_MAX_BYTELEN);
444 : }
445 : #ifdef HAVE_IPV6
446 0 : else if (peer->su.sa.sa_family == AF_INET6)
447 : {
448 : /* Interface Index and Address family. */
449 0 : stream_putw (obuf, peer->ifindex);
450 0 : stream_putw (obuf, AFI_IP6);
451 :
452 : /* Source IP Address and Destination IP Address. */
453 0 : stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
454 :
455 0 : if (peer->su_local)
456 0 : stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN);
457 : else
458 0 : stream_put (obuf, empty, IPV6_MAX_BYTELEN);
459 : }
460 : #endif /* HAVE_IPV6 */
461 0 : }
462 :
463 : /* Dump BGP status change. */
464 : void
465 0 : bgp_dump_state (struct peer *peer, int status_old, int status_new)
466 : {
467 : struct stream *obuf;
468 :
469 : /* If dump file pointer is disabled return immediately. */
470 0 : if (bgp_dump_all.fp == NULL)
471 0 : return;
472 :
473 : /* Make dump stream. */
474 0 : obuf = bgp_dump_obuf;
475 0 : stream_reset (obuf);
476 :
477 0 : bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4);
478 0 : bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/
479 :
480 0 : stream_putw (obuf, status_old);
481 0 : stream_putw (obuf, status_new);
482 :
483 : /* Set length. */
484 0 : bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
485 :
486 : /* Write to the stream. */
487 0 : fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp);
488 0 : fflush (bgp_dump_all.fp);
489 : }
490 :
491 : static void
492 0 : bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer,
493 : struct stream *packet)
494 : {
495 : struct stream *obuf;
496 :
497 : /* If dump file pointer is disabled return immediately. */
498 0 : if (bgp_dump->fp == NULL)
499 0 : return;
500 :
501 : /* Make dump stream. */
502 0 : obuf = bgp_dump_obuf;
503 0 : stream_reset (obuf);
504 :
505 : /* Dump header and common part. */
506 0 : if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
507 : {
508 0 : bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4);
509 : }
510 : else
511 : {
512 0 : bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE);
513 : }
514 0 : bgp_dump_common (obuf, peer, 0);
515 :
516 : /* Packet contents. */
517 0 : stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet));
518 :
519 : /* Set length. */
520 0 : bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP);
521 :
522 : /* Write to the stream. */
523 0 : fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp);
524 0 : fflush (bgp_dump->fp);
525 : }
526 :
527 : /* Called from bgp_packet.c when BGP packet is received. */
528 : void
529 0 : bgp_dump_packet (struct peer *peer, int type, struct stream *packet)
530 : {
531 : /* bgp_dump_all. */
532 0 : bgp_dump_packet_func (&bgp_dump_all, peer, packet);
533 :
534 : /* bgp_dump_updates. */
535 0 : if (type == BGP_MSG_UPDATE)
536 0 : bgp_dump_packet_func (&bgp_dump_updates, peer, packet);
537 0 : }
538 :
539 : static unsigned int
540 0 : bgp_dump_parse_time (const char *str)
541 : {
542 : int i;
543 : int len;
544 : int seen_h;
545 : int seen_m;
546 : int time;
547 : unsigned int total;
548 :
549 0 : time = 0;
550 0 : total = 0;
551 0 : seen_h = 0;
552 0 : seen_m = 0;
553 0 : len = strlen (str);
554 :
555 0 : for (i = 0; i < len; i++)
556 : {
557 0 : if (isdigit ((int) str[i]))
558 : {
559 0 : time *= 10;
560 0 : time += str[i] - '0';
561 : }
562 0 : else if (str[i] == 'H' || str[i] == 'h')
563 : {
564 0 : if (seen_h)
565 0 : return 0;
566 0 : if (seen_m)
567 0 : return 0;
568 0 : total += time * 60 *60;
569 0 : time = 0;
570 0 : seen_h = 1;
571 : }
572 0 : else if (str[i] == 'M' || str[i] == 'm')
573 : {
574 0 : if (seen_m)
575 0 : return 0;
576 0 : total += time * 60;
577 0 : time = 0;
578 0 : seen_h = 1;
579 : }
580 : else
581 0 : return 0;
582 : }
583 0 : return total + time;
584 : }
585 :
586 : static int
587 0 : bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump,
588 : enum bgp_dump_type type, const char *path,
589 : const char *interval_str)
590 : {
591 : unsigned int interval;
592 :
593 0 : if (interval_str)
594 : {
595 :
596 : /* Check interval string. */
597 0 : interval = bgp_dump_parse_time (interval_str);
598 0 : if (interval == 0)
599 : {
600 0 : vty_out (vty, "Malformed interval string%s", VTY_NEWLINE);
601 0 : return CMD_WARNING;
602 : }
603 :
604 : /* Don't schedule duplicate dumps if the dump command is given twice */
605 0 : if (interval == bgp_dump->interval &&
606 0 : type == bgp_dump->type &&
607 0 : path && bgp_dump->filename && !strcmp (path, bgp_dump->filename))
608 : {
609 0 : return CMD_SUCCESS;
610 : }
611 :
612 : /* Set interval. */
613 0 : bgp_dump->interval = interval;
614 0 : if (bgp_dump->interval_str)
615 0 : free (bgp_dump->interval_str);
616 0 : bgp_dump->interval_str = strdup (interval_str);
617 :
618 : }
619 : else
620 : {
621 0 : interval = 0;
622 : }
623 :
624 : /* Create interval thread. */
625 0 : bgp_dump_interval_add (bgp_dump, interval);
626 :
627 : /* Set type. */
628 0 : bgp_dump->type = type;
629 :
630 : /* Set file name. */
631 0 : if (bgp_dump->filename)
632 0 : free (bgp_dump->filename);
633 0 : bgp_dump->filename = strdup (path);
634 :
635 : /* This should be called when interval is expired. */
636 0 : bgp_dump_open_file (bgp_dump);
637 :
638 0 : return CMD_SUCCESS;
639 : }
640 :
641 : static int
642 0 : bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump)
643 : {
644 : /* Set file name. */
645 0 : if (bgp_dump->filename)
646 : {
647 0 : free (bgp_dump->filename);
648 0 : bgp_dump->filename = NULL;
649 : }
650 :
651 : /* This should be called when interval is expired. */
652 0 : if (bgp_dump->fp)
653 : {
654 0 : fclose (bgp_dump->fp);
655 0 : bgp_dump->fp = NULL;
656 : }
657 :
658 : /* Create interval thread. */
659 0 : if (bgp_dump->t_interval)
660 : {
661 0 : thread_cancel (bgp_dump->t_interval);
662 0 : bgp_dump->t_interval = NULL;
663 : }
664 :
665 0 : bgp_dump->interval = 0;
666 :
667 0 : if (bgp_dump->interval_str)
668 : {
669 0 : free (bgp_dump->interval_str);
670 0 : bgp_dump->interval_str = NULL;
671 : }
672 :
673 :
674 0 : return CMD_SUCCESS;
675 : }
676 :
677 0 : DEFUN (dump_bgp_all,
678 : dump_bgp_all_cmd,
679 : "dump bgp all PATH",
680 : "Dump packet\n"
681 : "BGP packet dump\n"
682 : "Dump all BGP packets\n"
683 : "Output filename\n")
684 : {
685 0 : return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL);
686 : }
687 :
688 0 : DEFUN (dump_bgp_all_interval,
689 : dump_bgp_all_interval_cmd,
690 : "dump bgp all PATH INTERVAL",
691 : "Dump packet\n"
692 : "BGP packet dump\n"
693 : "Dump all BGP packets\n"
694 : "Output filename\n"
695 : "Interval of output\n")
696 : {
697 0 : return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]);
698 : }
699 :
700 0 : DEFUN (no_dump_bgp_all,
701 : no_dump_bgp_all_cmd,
702 : "no dump bgp all [PATH] [INTERVAL]",
703 : NO_STR
704 : "Dump packet\n"
705 : "BGP packet dump\n"
706 : "Dump all BGP packets\n")
707 : {
708 0 : return bgp_dump_unset (vty, &bgp_dump_all);
709 : }
710 :
711 0 : DEFUN (dump_bgp_updates,
712 : dump_bgp_updates_cmd,
713 : "dump bgp updates PATH",
714 : "Dump packet\n"
715 : "BGP packet dump\n"
716 : "Dump BGP updates only\n"
717 : "Output filename\n")
718 : {
719 0 : return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL);
720 : }
721 :
722 0 : DEFUN (dump_bgp_updates_interval,
723 : dump_bgp_updates_interval_cmd,
724 : "dump bgp updates PATH INTERVAL",
725 : "Dump packet\n"
726 : "BGP packet dump\n"
727 : "Dump BGP updates only\n"
728 : "Output filename\n"
729 : "Interval of output\n")
730 : {
731 0 : return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]);
732 : }
733 :
734 0 : DEFUN (no_dump_bgp_updates,
735 : no_dump_bgp_updates_cmd,
736 : "no dump bgp updates [PATH] [INTERVAL]",
737 : NO_STR
738 : "Dump packet\n"
739 : "BGP packet dump\n"
740 : "Dump BGP updates only\n")
741 : {
742 0 : return bgp_dump_unset (vty, &bgp_dump_updates);
743 : }
744 :
745 0 : DEFUN (dump_bgp_routes,
746 : dump_bgp_routes_cmd,
747 : "dump bgp routes-mrt PATH",
748 : "Dump packet\n"
749 : "BGP packet dump\n"
750 : "Dump whole BGP routing table\n"
751 : "Output filename\n")
752 : {
753 0 : return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL);
754 : }
755 :
756 0 : DEFUN (dump_bgp_routes_interval,
757 : dump_bgp_routes_interval_cmd,
758 : "dump bgp routes-mrt PATH INTERVAL",
759 : "Dump packet\n"
760 : "BGP packet dump\n"
761 : "Dump whole BGP routing table\n"
762 : "Output filename\n"
763 : "Interval of output\n")
764 : {
765 0 : return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]);
766 : }
767 :
768 0 : DEFUN (no_dump_bgp_routes,
769 : no_dump_bgp_routes_cmd,
770 : "no dump bgp routes-mrt [PATH] [INTERVAL]",
771 : NO_STR
772 : "Dump packet\n"
773 : "BGP packet dump\n"
774 : "Dump whole BGP routing table\n")
775 : {
776 0 : return bgp_dump_unset (vty, &bgp_dump_routes);
777 : }
778 :
779 : /* BGP node structure. */
780 : static struct cmd_node bgp_dump_node =
781 : {
782 : DUMP_NODE,
783 : "",
784 : 1
785 : };
786 :
787 : #if 0
788 : char *
789 : config_time2str (unsigned int interval)
790 : {
791 : static char buf[BUFSIZ];
792 :
793 : buf[0] = '\0';
794 :
795 : if (interval / 3600)
796 : {
797 : sprintf (buf, "%dh", interval / 3600);
798 : interval %= 3600;
799 : }
800 : if (interval / 60)
801 : {
802 : sprintf (buf + strlen (buf), "%dm", interval /60);
803 : interval %= 60;
804 : }
805 : if (interval)
806 : {
807 : sprintf (buf + strlen (buf), "%d", interval);
808 : }
809 : return buf;
810 : }
811 : #endif
812 :
813 : static int
814 0 : config_write_bgp_dump (struct vty *vty)
815 : {
816 0 : if (bgp_dump_all.filename)
817 : {
818 0 : if (bgp_dump_all.interval_str)
819 0 : vty_out (vty, "dump bgp all %s %s%s",
820 : bgp_dump_all.filename, bgp_dump_all.interval_str,
821 0 : VTY_NEWLINE);
822 : else
823 0 : vty_out (vty, "dump bgp all %s%s",
824 0 : bgp_dump_all.filename, VTY_NEWLINE);
825 : }
826 0 : if (bgp_dump_updates.filename)
827 : {
828 0 : if (bgp_dump_updates.interval_str)
829 0 : vty_out (vty, "dump bgp updates %s %s%s",
830 : bgp_dump_updates.filename, bgp_dump_updates.interval_str,
831 0 : VTY_NEWLINE);
832 : else
833 0 : vty_out (vty, "dump bgp updates %s%s",
834 0 : bgp_dump_updates.filename, VTY_NEWLINE);
835 : }
836 0 : if (bgp_dump_routes.filename)
837 : {
838 0 : if (bgp_dump_routes.interval_str)
839 0 : vty_out (vty, "dump bgp routes-mrt %s %s%s",
840 : bgp_dump_routes.filename, bgp_dump_routes.interval_str,
841 0 : VTY_NEWLINE);
842 : else
843 0 : vty_out (vty, "dump bgp routes-mrt %s%s",
844 0 : bgp_dump_routes.filename, VTY_NEWLINE);
845 : }
846 0 : return 0;
847 : }
848 :
849 : /* Initialize BGP packet dump functionality. */
850 : void
851 0 : bgp_dump_init (void)
852 : {
853 0 : memset (&bgp_dump_all, 0, sizeof (struct bgp_dump));
854 0 : memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump));
855 0 : memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump));
856 :
857 0 : bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
858 : + BGP_DUMP_HEADER_SIZE);
859 :
860 0 : install_node (&bgp_dump_node, config_write_bgp_dump);
861 :
862 0 : install_element (CONFIG_NODE, &dump_bgp_all_cmd);
863 0 : install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd);
864 0 : install_element (CONFIG_NODE, &no_dump_bgp_all_cmd);
865 0 : install_element (CONFIG_NODE, &dump_bgp_updates_cmd);
866 0 : install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd);
867 0 : install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd);
868 0 : install_element (CONFIG_NODE, &dump_bgp_routes_cmd);
869 0 : install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd);
870 0 : install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd);
871 0 : }
872 :
873 : void
874 0 : bgp_dump_finish (void)
875 : {
876 0 : stream_free (bgp_dump_obuf);
877 0 : bgp_dump_obuf = NULL;
878 0 : }
|