bgp_dump.c 22 KB

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