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