zebra_fpm.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  1. /*
  2. * Main implementation file for interface to Forwarding Plane Manager.
  3. *
  4. * Copyright (C) 2012 by Open Source Routing.
  5. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
  6. *
  7. * This file is part of GNU Zebra.
  8. *
  9. * GNU Zebra is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License as published by the
  11. * Free Software Foundation; either version 2, or (at your option) any
  12. * later version.
  13. *
  14. * GNU Zebra is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with GNU Zebra; see the file COPYING. If not, write to the Free
  21. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  22. * 02111-1307, USA.
  23. */
  24. #include <zebra.h>
  25. #include "log.h"
  26. #include "stream.h"
  27. #include "thread.h"
  28. #include "network.h"
  29. #include "command.h"
  30. #include "zebra/rib.h"
  31. #include "fpm/fpm.h"
  32. #include "zebra_fpm.h"
  33. #include "zebra_fpm_private.h"
  34. /*
  35. * Interval at which we attempt to connect to the FPM.
  36. */
  37. #define ZFPM_CONNECT_RETRY_IVL 5
  38. /*
  39. * Sizes of outgoing and incoming stream buffers for writing/reading
  40. * FPM messages.
  41. */
  42. #define ZFPM_OBUF_SIZE (2 * FPM_MAX_MSG_LEN)
  43. #define ZFPM_IBUF_SIZE (FPM_MAX_MSG_LEN)
  44. /*
  45. * The maximum number of times the FPM socket write callback can call
  46. * 'write' before it yields.
  47. */
  48. #define ZFPM_MAX_WRITES_PER_RUN 10
  49. /*
  50. * Interval over which we collect statistics.
  51. */
  52. #define ZFPM_STATS_IVL_SECS 10
  53. /*
  54. * Structure that holds state for iterating over all route_node
  55. * structures that are candidates for being communicated to the FPM.
  56. */
  57. typedef struct zfpm_rnodes_iter_t_
  58. {
  59. rib_tables_iter_t tables_iter;
  60. route_table_iter_t iter;
  61. } zfpm_rnodes_iter_t;
  62. /*
  63. * Statistics.
  64. */
  65. typedef struct zfpm_stats_t_ {
  66. unsigned long connect_calls;
  67. unsigned long connect_no_sock;
  68. unsigned long read_cb_calls;
  69. unsigned long write_cb_calls;
  70. unsigned long write_calls;
  71. unsigned long partial_writes;
  72. unsigned long max_writes_hit;
  73. unsigned long t_write_yields;
  74. unsigned long nop_deletes_skipped;
  75. unsigned long route_adds;
  76. unsigned long route_dels;
  77. unsigned long updates_triggered;
  78. unsigned long redundant_triggers;
  79. unsigned long non_fpm_table_triggers;
  80. unsigned long dests_del_after_update;
  81. unsigned long t_conn_down_starts;
  82. unsigned long t_conn_down_dests_processed;
  83. unsigned long t_conn_down_yields;
  84. unsigned long t_conn_down_finishes;
  85. unsigned long t_conn_up_starts;
  86. unsigned long t_conn_up_dests_processed;
  87. unsigned long t_conn_up_yields;
  88. unsigned long t_conn_up_aborts;
  89. unsigned long t_conn_up_finishes;
  90. } zfpm_stats_t;
  91. /*
  92. * States for the FPM state machine.
  93. */
  94. typedef enum {
  95. /*
  96. * In this state we are not yet ready to connect to the FPM. This
  97. * can happen when this module is disabled, or if we're cleaning up
  98. * after a connection has gone down.
  99. */
  100. ZFPM_STATE_IDLE,
  101. /*
  102. * Ready to talk to the FPM and periodically trying to connect to
  103. * it.
  104. */
  105. ZFPM_STATE_ACTIVE,
  106. /*
  107. * In the middle of bringing up a TCP connection. Specifically,
  108. * waiting for a connect() call to complete asynchronously.
  109. */
  110. ZFPM_STATE_CONNECTING,
  111. /*
  112. * TCP connection to the FPM is up.
  113. */
  114. ZFPM_STATE_ESTABLISHED
  115. } zfpm_state_t;
  116. /*
  117. * Globals.
  118. */
  119. typedef struct zfpm_glob_t_
  120. {
  121. /*
  122. * True if the FPM module has been enabled.
  123. */
  124. int enabled;
  125. struct thread_master *master;
  126. zfpm_state_t state;
  127. /*
  128. * Port on which the FPM is running.
  129. */
  130. int fpm_port;
  131. /*
  132. * List of rib_dest_t structures to be processed
  133. */
  134. TAILQ_HEAD (zfpm_dest_q, rib_dest_t_) dest_q;
  135. /*
  136. * Stream socket to the FPM.
  137. */
  138. int sock;
  139. /*
  140. * Buffers for messages to/from the FPM.
  141. */
  142. struct stream *obuf;
  143. struct stream *ibuf;
  144. /*
  145. * Threads for I/O.
  146. */
  147. struct thread *t_connect;
  148. struct thread *t_write;
  149. struct thread *t_read;
  150. /*
  151. * Thread to clean up after the TCP connection to the FPM goes down
  152. * and the state that belongs to it.
  153. */
  154. struct thread *t_conn_down;
  155. struct {
  156. zfpm_rnodes_iter_t iter;
  157. } t_conn_down_state;
  158. /*
  159. * Thread to take actions once the TCP conn to the FPM comes up, and
  160. * the state that belongs to it.
  161. */
  162. struct thread *t_conn_up;
  163. struct {
  164. zfpm_rnodes_iter_t iter;
  165. } t_conn_up_state;
  166. unsigned long connect_calls;
  167. time_t last_connect_call_time;
  168. /*
  169. * Stats from the start of the current statistics interval up to
  170. * now. These are the counters we typically update in the code.
  171. */
  172. zfpm_stats_t stats;
  173. /*
  174. * Statistics that were gathered in the last collection interval.
  175. */
  176. zfpm_stats_t last_ivl_stats;
  177. /*
  178. * Cumulative stats from the last clear to the start of the current
  179. * statistics interval.
  180. */
  181. zfpm_stats_t cumulative_stats;
  182. /*
  183. * Stats interval timer.
  184. */
  185. struct thread *t_stats;
  186. /*
  187. * If non-zero, the last time when statistics were cleared.
  188. */
  189. time_t last_stats_clear_time;
  190. } zfpm_glob_t;
  191. static zfpm_glob_t zfpm_glob_space;
  192. static zfpm_glob_t *zfpm_g = &zfpm_glob_space;
  193. static int zfpm_read_cb (struct thread *thread);
  194. static int zfpm_write_cb (struct thread *thread);
  195. static void zfpm_set_state (zfpm_state_t state, const char *reason);
  196. static void zfpm_start_connect_timer (const char *reason);
  197. static void zfpm_start_stats_timer (void);
  198. /*
  199. * zfpm_thread_should_yield
  200. */
  201. static inline int
  202. zfpm_thread_should_yield (struct thread *t)
  203. {
  204. return thread_should_yield (t);
  205. }
  206. /*
  207. * zfpm_state_to_str
  208. */
  209. static const char *
  210. zfpm_state_to_str (zfpm_state_t state)
  211. {
  212. switch (state)
  213. {
  214. case ZFPM_STATE_IDLE:
  215. return "idle";
  216. case ZFPM_STATE_ACTIVE:
  217. return "active";
  218. case ZFPM_STATE_CONNECTING:
  219. return "connecting";
  220. case ZFPM_STATE_ESTABLISHED:
  221. return "established";
  222. default:
  223. return "unknown";
  224. }
  225. }
  226. /*
  227. * zfpm_get_time
  228. */
  229. static time_t
  230. zfpm_get_time (void)
  231. {
  232. struct timeval tv;
  233. if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0)
  234. zlog_warn ("FPM: quagga_gettime failed!!");
  235. return tv.tv_sec;
  236. }
  237. /*
  238. * zfpm_get_elapsed_time
  239. *
  240. * Returns the time elapsed (in seconds) since the given time.
  241. */
  242. static time_t
  243. zfpm_get_elapsed_time (time_t reference)
  244. {
  245. time_t now;
  246. now = zfpm_get_time ();
  247. if (now < reference)
  248. {
  249. assert (0);
  250. return 0;
  251. }
  252. return now - reference;
  253. }
  254. /*
  255. * zfpm_is_table_for_fpm
  256. *
  257. * Returns TRUE if the the given table is to be communicated to the
  258. * FPM.
  259. */
  260. static inline int
  261. zfpm_is_table_for_fpm (struct route_table *table)
  262. {
  263. rib_table_info_t *info;
  264. info = rib_table_info (table);
  265. /*
  266. * We only send the unicast tables in the main instance to the FPM
  267. * at this point.
  268. */
  269. if (info->vrf->id != 0)
  270. return 0;
  271. if (info->safi != SAFI_UNICAST)
  272. return 0;
  273. return 1;
  274. }
  275. /*
  276. * zfpm_rnodes_iter_init
  277. */
  278. static inline void
  279. zfpm_rnodes_iter_init (zfpm_rnodes_iter_t *iter)
  280. {
  281. memset (iter, 0, sizeof (*iter));
  282. rib_tables_iter_init (&iter->tables_iter);
  283. /*
  284. * This is a hack, but it makes implementing 'next' easier by
  285. * ensuring that route_table_iter_next() will return NULL the first
  286. * time we call it.
  287. */
  288. route_table_iter_init (&iter->iter, NULL);
  289. route_table_iter_cleanup (&iter->iter);
  290. }
  291. /*
  292. * zfpm_rnodes_iter_next
  293. */
  294. static inline struct route_node *
  295. zfpm_rnodes_iter_next (zfpm_rnodes_iter_t *iter)
  296. {
  297. struct route_node *rn;
  298. struct route_table *table;
  299. while (1)
  300. {
  301. rn = route_table_iter_next (&iter->iter);
  302. if (rn)
  303. return rn;
  304. /*
  305. * We've made our way through this table, go to the next one.
  306. */
  307. route_table_iter_cleanup (&iter->iter);
  308. while ((table = rib_tables_iter_next (&iter->tables_iter)))
  309. {
  310. if (zfpm_is_table_for_fpm (table))
  311. break;
  312. }
  313. if (!table)
  314. return NULL;
  315. route_table_iter_init (&iter->iter, table);
  316. }
  317. return NULL;
  318. }
  319. /*
  320. * zfpm_rnodes_iter_pause
  321. */
  322. static inline void
  323. zfpm_rnodes_iter_pause (zfpm_rnodes_iter_t *iter)
  324. {
  325. route_table_iter_pause (&iter->iter);
  326. }
  327. /*
  328. * zfpm_rnodes_iter_cleanup
  329. */
  330. static inline void
  331. zfpm_rnodes_iter_cleanup (zfpm_rnodes_iter_t *iter)
  332. {
  333. route_table_iter_cleanup (&iter->iter);
  334. rib_tables_iter_cleanup (&iter->tables_iter);
  335. }
  336. /*
  337. * zfpm_stats_init
  338. *
  339. * Initialize a statistics block.
  340. */
  341. static inline void
  342. zfpm_stats_init (zfpm_stats_t *stats)
  343. {
  344. memset (stats, 0, sizeof (*stats));
  345. }
  346. /*
  347. * zfpm_stats_reset
  348. */
  349. static inline void
  350. zfpm_stats_reset (zfpm_stats_t *stats)
  351. {
  352. zfpm_stats_init (stats);
  353. }
  354. /*
  355. * zfpm_stats_copy
  356. */
  357. static inline void
  358. zfpm_stats_copy (const zfpm_stats_t *src, zfpm_stats_t *dest)
  359. {
  360. memcpy (dest, src, sizeof (*dest));
  361. }
  362. /*
  363. * zfpm_stats_compose
  364. *
  365. * Total up the statistics in two stats structures ('s1 and 's2') and
  366. * return the result in the third argument, 'result'. Note that the
  367. * pointer 'result' may be the same as 's1' or 's2'.
  368. *
  369. * For simplicity, the implementation below assumes that the stats
  370. * structure is composed entirely of counters. This can easily be
  371. * changed when necessary.
  372. */
  373. static void
  374. zfpm_stats_compose (const zfpm_stats_t *s1, const zfpm_stats_t *s2,
  375. zfpm_stats_t *result)
  376. {
  377. const unsigned long *p1, *p2;
  378. unsigned long *result_p;
  379. int i, num_counters;
  380. p1 = (const unsigned long *) s1;
  381. p2 = (const unsigned long *) s2;
  382. result_p = (unsigned long *) result;
  383. num_counters = (sizeof (zfpm_stats_t) / sizeof (unsigned long));
  384. for (i = 0; i < num_counters; i++)
  385. {
  386. result_p[i] = p1[i] + p2[i];
  387. }
  388. }
  389. /*
  390. * zfpm_read_on
  391. */
  392. static inline void
  393. zfpm_read_on (void)
  394. {
  395. assert (!zfpm_g->t_read);
  396. assert (zfpm_g->sock >= 0);
  397. THREAD_READ_ON (zfpm_g->master, zfpm_g->t_read, zfpm_read_cb, 0,
  398. zfpm_g->sock);
  399. }
  400. /*
  401. * zfpm_write_on
  402. */
  403. static inline void
  404. zfpm_write_on (void)
  405. {
  406. assert (!zfpm_g->t_write);
  407. assert (zfpm_g->sock >= 0);
  408. THREAD_WRITE_ON (zfpm_g->master, zfpm_g->t_write, zfpm_write_cb, 0,
  409. zfpm_g->sock);
  410. }
  411. /*
  412. * zfpm_read_off
  413. */
  414. static inline void
  415. zfpm_read_off (void)
  416. {
  417. THREAD_READ_OFF (zfpm_g->t_read);
  418. }
  419. /*
  420. * zfpm_write_off
  421. */
  422. static inline void
  423. zfpm_write_off (void)
  424. {
  425. THREAD_WRITE_OFF (zfpm_g->t_write);
  426. }
  427. /*
  428. * zfpm_conn_up_thread_cb
  429. *
  430. * Callback for actions to be taken when the connection to the FPM
  431. * comes up.
  432. */
  433. static int
  434. zfpm_conn_up_thread_cb (struct thread *thread)
  435. {
  436. struct route_node *rnode;
  437. zfpm_rnodes_iter_t *iter;
  438. rib_dest_t *dest;
  439. assert (zfpm_g->t_conn_up);
  440. zfpm_g->t_conn_up = NULL;
  441. iter = &zfpm_g->t_conn_up_state.iter;
  442. if (zfpm_g->state != ZFPM_STATE_ESTABLISHED)
  443. {
  444. zfpm_debug ("Connection not up anymore, conn_up thread aborting");
  445. zfpm_g->stats.t_conn_up_aborts++;
  446. goto done;
  447. }
  448. while ((rnode = zfpm_rnodes_iter_next (iter)))
  449. {
  450. dest = rib_dest_from_rnode (rnode);
  451. if (dest)
  452. {
  453. zfpm_g->stats.t_conn_up_dests_processed++;
  454. zfpm_trigger_update (rnode, NULL);
  455. }
  456. /*
  457. * Yield if need be.
  458. */
  459. if (!zfpm_thread_should_yield (thread))
  460. continue;
  461. zfpm_g->stats.t_conn_up_yields++;
  462. zfpm_rnodes_iter_pause (iter);
  463. zfpm_g->t_conn_up = thread_add_background (zfpm_g->master,
  464. zfpm_conn_up_thread_cb,
  465. 0, 0);
  466. return 0;
  467. }
  468. zfpm_g->stats.t_conn_up_finishes++;
  469. done:
  470. zfpm_rnodes_iter_cleanup (iter);
  471. return 0;
  472. }
  473. /*
  474. * zfpm_connection_up
  475. *
  476. * Called when the connection to the FPM comes up.
  477. */
  478. static void
  479. zfpm_connection_up (const char *detail)
  480. {
  481. assert (zfpm_g->sock >= 0);
  482. zfpm_read_on ();
  483. zfpm_write_on ();
  484. zfpm_set_state (ZFPM_STATE_ESTABLISHED, detail);
  485. /*
  486. * Start thread to push existing routes to the FPM.
  487. */
  488. assert (!zfpm_g->t_conn_up);
  489. zfpm_rnodes_iter_init (&zfpm_g->t_conn_up_state.iter);
  490. zfpm_debug ("Starting conn_up thread");
  491. zfpm_g->t_conn_up = thread_add_background (zfpm_g->master,
  492. zfpm_conn_up_thread_cb, 0, 0);
  493. zfpm_g->stats.t_conn_up_starts++;
  494. }
  495. /*
  496. * zfpm_connect_check
  497. *
  498. * Check if an asynchronous connect() to the FPM is complete.
  499. */
  500. static void
  501. zfpm_connect_check ()
  502. {
  503. int status;
  504. socklen_t slen;
  505. int ret;
  506. zfpm_read_off ();
  507. zfpm_write_off ();
  508. slen = sizeof (status);
  509. ret = getsockopt (zfpm_g->sock, SOL_SOCKET, SO_ERROR, (void *) &status,
  510. &slen);
  511. if (ret >= 0 && status == 0)
  512. {
  513. zfpm_connection_up ("async connect complete");
  514. return;
  515. }
  516. /*
  517. * getsockopt() failed or indicated an error on the socket.
  518. */
  519. close (zfpm_g->sock);
  520. zfpm_g->sock = -1;
  521. zfpm_start_connect_timer ("getsockopt() after async connect failed");
  522. return;
  523. }
  524. /*
  525. * zfpm_conn_down_thread_cb
  526. *
  527. * Callback that is invoked to clean up state after the TCP connection
  528. * to the FPM goes down.
  529. */
  530. static int
  531. zfpm_conn_down_thread_cb (struct thread *thread)
  532. {
  533. struct route_node *rnode;
  534. zfpm_rnodes_iter_t *iter;
  535. rib_dest_t *dest;
  536. assert (zfpm_g->state == ZFPM_STATE_IDLE);
  537. assert (zfpm_g->t_conn_down);
  538. zfpm_g->t_conn_down = NULL;
  539. iter = &zfpm_g->t_conn_down_state.iter;
  540. while ((rnode = zfpm_rnodes_iter_next (iter)))
  541. {
  542. dest = rib_dest_from_rnode (rnode);
  543. if (dest)
  544. {
  545. if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM))
  546. {
  547. TAILQ_REMOVE (&zfpm_g->dest_q, dest, fpm_q_entries);
  548. }
  549. UNSET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM);
  550. UNSET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM);
  551. zfpm_g->stats.t_conn_down_dests_processed++;
  552. /*
  553. * Check if the dest should be deleted.
  554. */
  555. rib_gc_dest(rnode);
  556. }
  557. /*
  558. * Yield if need be.
  559. */
  560. if (!zfpm_thread_should_yield (thread))
  561. continue;
  562. zfpm_g->stats.t_conn_down_yields++;
  563. zfpm_rnodes_iter_pause (iter);
  564. zfpm_g->t_conn_down = thread_add_background (zfpm_g->master,
  565. zfpm_conn_down_thread_cb,
  566. 0, 0);
  567. return 0;
  568. }
  569. zfpm_g->stats.t_conn_down_finishes++;
  570. zfpm_rnodes_iter_cleanup (iter);
  571. /*
  572. * Start the process of connecting to the FPM again.
  573. */
  574. zfpm_start_connect_timer ("cleanup complete");
  575. return 0;
  576. }
  577. /*
  578. * zfpm_connection_down
  579. *
  580. * Called when the connection to the FPM has gone down.
  581. */
  582. static void
  583. zfpm_connection_down (const char *detail)
  584. {
  585. if (!detail)
  586. detail = "unknown";
  587. assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED);
  588. zlog_info ("connection to the FPM has gone down: %s", detail);
  589. zfpm_read_off ();
  590. zfpm_write_off ();
  591. stream_reset (zfpm_g->ibuf);
  592. stream_reset (zfpm_g->obuf);
  593. if (zfpm_g->sock >= 0) {
  594. close (zfpm_g->sock);
  595. zfpm_g->sock = -1;
  596. }
  597. /*
  598. * Start thread to clean up state after the connection goes down.
  599. */
  600. assert (!zfpm_g->t_conn_down);
  601. zfpm_debug ("Starting conn_down thread");
  602. zfpm_rnodes_iter_init (&zfpm_g->t_conn_down_state.iter);
  603. zfpm_g->t_conn_down = thread_add_background (zfpm_g->master,
  604. zfpm_conn_down_thread_cb, 0, 0);
  605. zfpm_g->stats.t_conn_down_starts++;
  606. zfpm_set_state (ZFPM_STATE_IDLE, detail);
  607. }
  608. /*
  609. * zfpm_read_cb
  610. */
  611. static int
  612. zfpm_read_cb (struct thread *thread)
  613. {
  614. size_t already;
  615. struct stream *ibuf;
  616. uint16_t msg_len;
  617. fpm_msg_hdr_t *hdr;
  618. zfpm_g->stats.read_cb_calls++;
  619. assert (zfpm_g->t_read);
  620. zfpm_g->t_read = NULL;
  621. /*
  622. * Check if async connect is now done.
  623. */
  624. if (zfpm_g->state == ZFPM_STATE_CONNECTING)
  625. {
  626. zfpm_connect_check();
  627. return 0;
  628. }
  629. assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED);
  630. assert (zfpm_g->sock >= 0);
  631. ibuf = zfpm_g->ibuf;
  632. already = stream_get_endp (ibuf);
  633. if (already < FPM_MSG_HDR_LEN)
  634. {
  635. ssize_t nbyte;
  636. nbyte = stream_read_try (ibuf, zfpm_g->sock, FPM_MSG_HDR_LEN - already);
  637. if (nbyte == 0 || nbyte == -1)
  638. {
  639. zfpm_connection_down ("closed socket in read");
  640. return 0;
  641. }
  642. if (nbyte != (ssize_t) (FPM_MSG_HDR_LEN - already))
  643. goto done;
  644. already = FPM_MSG_HDR_LEN;
  645. }
  646. stream_set_getp (ibuf, 0);
  647. hdr = (fpm_msg_hdr_t *) stream_pnt (ibuf);
  648. if (!fpm_msg_hdr_ok (hdr))
  649. {
  650. zfpm_connection_down ("invalid message header");
  651. return 0;
  652. }
  653. msg_len = fpm_msg_len (hdr);
  654. /*
  655. * Read out the rest of the packet.
  656. */
  657. if (already < msg_len)
  658. {
  659. ssize_t nbyte;
  660. nbyte = stream_read_try (ibuf, zfpm_g->sock, msg_len - already);
  661. if (nbyte == 0 || nbyte == -1)
  662. {
  663. zfpm_connection_down ("failed to read message");
  664. return 0;
  665. }
  666. if (nbyte != (ssize_t) (msg_len - already))
  667. goto done;
  668. }
  669. zfpm_debug ("Read out a full fpm message");
  670. /*
  671. * Just throw it away for now.
  672. */
  673. stream_reset (ibuf);
  674. done:
  675. zfpm_read_on ();
  676. return 0;
  677. }
  678. /*
  679. * zfpm_writes_pending
  680. *
  681. * Returns TRUE if we may have something to write to the FPM.
  682. */
  683. static int
  684. zfpm_writes_pending (void)
  685. {
  686. /*
  687. * Check if there is any data in the outbound buffer that has not
  688. * been written to the socket yet.
  689. */
  690. if (stream_get_endp (zfpm_g->obuf) - stream_get_getp (zfpm_g->obuf))
  691. return 1;
  692. /*
  693. * Check if there are any prefixes on the outbound queue.
  694. */
  695. if (!TAILQ_EMPTY (&zfpm_g->dest_q))
  696. return 1;
  697. return 0;
  698. }
  699. /*
  700. * zfpm_encode_route
  701. *
  702. * Encode a message to the FPM with information about the given route.
  703. *
  704. * Returns the number of bytes written to the buffer. 0 or a negative
  705. * value indicates an error.
  706. */
  707. static inline int
  708. zfpm_encode_route (rib_dest_t *dest, struct rib *rib, char *in_buf,
  709. size_t in_buf_len)
  710. {
  711. #ifndef HAVE_NETLINK
  712. return 0;
  713. #else
  714. int cmd;
  715. cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE;
  716. return zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len);
  717. #endif /* HAVE_NETLINK */
  718. }
  719. /*
  720. * zfpm_route_for_update
  721. *
  722. * Returns the rib that is to be sent to the FPM for a given dest.
  723. */
  724. static struct rib *
  725. zfpm_route_for_update (rib_dest_t *dest)
  726. {
  727. struct rib *rib;
  728. RIB_DEST_FOREACH_ROUTE (dest, rib)
  729. {
  730. if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
  731. continue;
  732. return rib;
  733. }
  734. /*
  735. * We have no route for this destination.
  736. */
  737. return NULL;
  738. }
  739. /*
  740. * zfpm_build_updates
  741. *
  742. * Process the outgoing queue and write messages to the outbound
  743. * buffer.
  744. */
  745. static void
  746. zfpm_build_updates (void)
  747. {
  748. struct stream *s;
  749. rib_dest_t *dest;
  750. unsigned char *buf, *data, *buf_end;
  751. size_t msg_len;
  752. size_t data_len;
  753. fpm_msg_hdr_t *hdr;
  754. struct rib *rib;
  755. int is_add, write_msg;
  756. s = zfpm_g->obuf;
  757. assert (stream_empty (s));
  758. do {
  759. /*
  760. * Make sure there is enough space to write another message.
  761. */
  762. if (STREAM_WRITEABLE (s) < FPM_MAX_MSG_LEN)
  763. break;
  764. buf = STREAM_DATA (s) + stream_get_endp (s);
  765. buf_end = buf + STREAM_WRITEABLE (s);
  766. dest = TAILQ_FIRST (&zfpm_g->dest_q);
  767. if (!dest)
  768. break;
  769. assert (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM));
  770. hdr = (fpm_msg_hdr_t *) buf;
  771. hdr->version = FPM_PROTO_VERSION;
  772. hdr->msg_type = FPM_MSG_TYPE_NETLINK;
  773. data = fpm_msg_data (hdr);
  774. rib = zfpm_route_for_update (dest);
  775. is_add = rib ? 1 : 0;
  776. write_msg = 1;
  777. /*
  778. * If this is a route deletion, and we have not sent the route to
  779. * the FPM previously, skip it.
  780. */
  781. if (!is_add && !CHECK_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM))
  782. {
  783. write_msg = 0;
  784. zfpm_g->stats.nop_deletes_skipped++;
  785. }
  786. if (write_msg) {
  787. data_len = zfpm_encode_route (dest, rib, (char *) data, buf_end - data);
  788. assert (data_len);
  789. if (data_len)
  790. {
  791. msg_len = fpm_data_len_to_msg_len (data_len);
  792. hdr->msg_len = htons (msg_len);
  793. stream_forward_endp (s, msg_len);
  794. if (is_add)
  795. zfpm_g->stats.route_adds++;
  796. else
  797. zfpm_g->stats.route_dels++;
  798. }
  799. }
  800. /*
  801. * Remove the dest from the queue, and reset the flag.
  802. */
  803. UNSET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM);
  804. TAILQ_REMOVE (&zfpm_g->dest_q, dest, fpm_q_entries);
  805. if (is_add)
  806. {
  807. SET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM);
  808. }
  809. else
  810. {
  811. UNSET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM);
  812. }
  813. /*
  814. * Delete the destination if necessary.
  815. */
  816. if (rib_gc_dest (dest->rnode))
  817. zfpm_g->stats.dests_del_after_update++;
  818. } while (1);
  819. }
  820. /*
  821. * zfpm_write_cb
  822. */
  823. static int
  824. zfpm_write_cb (struct thread *thread)
  825. {
  826. struct stream *s;
  827. int num_writes;
  828. zfpm_g->stats.write_cb_calls++;
  829. assert (zfpm_g->t_write);
  830. zfpm_g->t_write = NULL;
  831. /*
  832. * Check if async connect is now done.
  833. */
  834. if (zfpm_g->state == ZFPM_STATE_CONNECTING)
  835. {
  836. zfpm_connect_check ();
  837. return 0;
  838. }
  839. assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED);
  840. assert (zfpm_g->sock >= 0);
  841. num_writes = 0;
  842. do
  843. {
  844. int bytes_to_write, bytes_written;
  845. s = zfpm_g->obuf;
  846. /*
  847. * If the stream is empty, try fill it up with data.
  848. */
  849. if (stream_empty (s))
  850. {
  851. zfpm_build_updates ();
  852. }
  853. bytes_to_write = stream_get_endp (s) - stream_get_getp (s);
  854. if (!bytes_to_write)
  855. break;
  856. bytes_written = write (zfpm_g->sock, STREAM_PNT (s), bytes_to_write);
  857. zfpm_g->stats.write_calls++;
  858. num_writes++;
  859. if (bytes_written < 0)
  860. {
  861. if (ERRNO_IO_RETRY (errno))
  862. break;
  863. zfpm_connection_down ("failed to write to socket");
  864. return 0;
  865. }
  866. if (bytes_written != bytes_to_write)
  867. {
  868. /*
  869. * Partial write.
  870. */
  871. stream_forward_getp (s, bytes_written);
  872. zfpm_g->stats.partial_writes++;
  873. break;
  874. }
  875. /*
  876. * We've written out the entire contents of the stream.
  877. */
  878. stream_reset (s);
  879. if (num_writes >= ZFPM_MAX_WRITES_PER_RUN)
  880. {
  881. zfpm_g->stats.max_writes_hit++;
  882. break;
  883. }
  884. if (zfpm_thread_should_yield (thread))
  885. {
  886. zfpm_g->stats.t_write_yields++;
  887. break;
  888. }
  889. } while (1);
  890. if (zfpm_writes_pending ())
  891. zfpm_write_on ();
  892. return 0;
  893. }
  894. /*
  895. * zfpm_connect_cb
  896. */
  897. static int
  898. zfpm_connect_cb (struct thread *t)
  899. {
  900. int sock, ret;
  901. struct sockaddr_in serv;
  902. assert (zfpm_g->t_connect);
  903. zfpm_g->t_connect = NULL;
  904. assert (zfpm_g->state == ZFPM_STATE_ACTIVE);
  905. sock = socket (AF_INET, SOCK_STREAM, 0);
  906. if (sock < 0)
  907. {
  908. zfpm_debug ("Failed to create socket for connect(): %s", strerror(errno));
  909. zfpm_g->stats.connect_no_sock++;
  910. return 0;
  911. }
  912. set_nonblocking(sock);
  913. /* Make server socket. */
  914. memset (&serv, 0, sizeof (serv));
  915. serv.sin_family = AF_INET;
  916. serv.sin_port = htons (zfpm_g->fpm_port);
  917. #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  918. serv.sin_len = sizeof (struct sockaddr_in);
  919. #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  920. serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  921. /*
  922. * Connect to the FPM.
  923. */
  924. zfpm_g->connect_calls++;
  925. zfpm_g->stats.connect_calls++;
  926. zfpm_g->last_connect_call_time = zfpm_get_time ();
  927. ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv));
  928. if (ret >= 0)
  929. {
  930. zfpm_g->sock = sock;
  931. zfpm_connection_up ("connect succeeded");
  932. return 1;
  933. }
  934. if (errno == EINPROGRESS)
  935. {
  936. zfpm_g->sock = sock;
  937. zfpm_read_on ();
  938. zfpm_write_on ();
  939. zfpm_set_state (ZFPM_STATE_CONNECTING, "async connect in progress");
  940. return 0;
  941. }
  942. zlog_info ("can't connect to FPM %d: %s", sock, safe_strerror (errno));
  943. close (sock);
  944. /*
  945. * Restart timer for retrying connection.
  946. */
  947. zfpm_start_connect_timer ("connect() failed");
  948. return 0;
  949. }
  950. /*
  951. * zfpm_set_state
  952. *
  953. * Move state machine into the given state.
  954. */
  955. static void
  956. zfpm_set_state (zfpm_state_t state, const char *reason)
  957. {
  958. zfpm_state_t cur_state = zfpm_g->state;
  959. if (!reason)
  960. reason = "Unknown";
  961. if (state == cur_state)
  962. return;
  963. zfpm_debug("beginning state transition %s -> %s. Reason: %s",
  964. zfpm_state_to_str (cur_state), zfpm_state_to_str (state),
  965. reason);
  966. switch (state) {
  967. case ZFPM_STATE_IDLE:
  968. assert (cur_state == ZFPM_STATE_ESTABLISHED);
  969. break;
  970. case ZFPM_STATE_ACTIVE:
  971. assert (cur_state == ZFPM_STATE_IDLE ||
  972. cur_state == ZFPM_STATE_CONNECTING);
  973. assert (zfpm_g->t_connect);
  974. break;
  975. case ZFPM_STATE_CONNECTING:
  976. assert (zfpm_g->sock);
  977. assert (cur_state == ZFPM_STATE_ACTIVE);
  978. assert (zfpm_g->t_read);
  979. assert (zfpm_g->t_write);
  980. break;
  981. case ZFPM_STATE_ESTABLISHED:
  982. assert (cur_state == ZFPM_STATE_ACTIVE ||
  983. cur_state == ZFPM_STATE_CONNECTING);
  984. assert (zfpm_g->sock);
  985. assert (zfpm_g->t_read);
  986. assert (zfpm_g->t_write);
  987. break;
  988. }
  989. zfpm_g->state = state;
  990. }
  991. /*
  992. * zfpm_calc_connect_delay
  993. *
  994. * Returns the number of seconds after which we should attempt to
  995. * reconnect to the FPM.
  996. */
  997. static long
  998. zfpm_calc_connect_delay (void)
  999. {
  1000. time_t elapsed;
  1001. /*
  1002. * Return 0 if this is our first attempt to connect.
  1003. */
  1004. if (zfpm_g->connect_calls == 0)
  1005. {
  1006. return 0;
  1007. }
  1008. elapsed = zfpm_get_elapsed_time (zfpm_g->last_connect_call_time);
  1009. if (elapsed > ZFPM_CONNECT_RETRY_IVL) {
  1010. return 0;
  1011. }
  1012. return ZFPM_CONNECT_RETRY_IVL - elapsed;
  1013. }
  1014. /*
  1015. * zfpm_start_connect_timer
  1016. */
  1017. static void
  1018. zfpm_start_connect_timer (const char *reason)
  1019. {
  1020. long delay_secs;
  1021. assert (!zfpm_g->t_connect);
  1022. assert (zfpm_g->sock < 0);
  1023. assert(zfpm_g->state == ZFPM_STATE_IDLE ||
  1024. zfpm_g->state == ZFPM_STATE_ACTIVE ||
  1025. zfpm_g->state == ZFPM_STATE_CONNECTING);
  1026. delay_secs = zfpm_calc_connect_delay();
  1027. zfpm_debug ("scheduling connect in %ld seconds", delay_secs);
  1028. THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_connect, zfpm_connect_cb, 0,
  1029. delay_secs);
  1030. zfpm_set_state (ZFPM_STATE_ACTIVE, reason);
  1031. }
  1032. /*
  1033. * zfpm_is_enabled
  1034. *
  1035. * Returns TRUE if the zebra FPM module has been enabled.
  1036. */
  1037. static inline int
  1038. zfpm_is_enabled (void)
  1039. {
  1040. return zfpm_g->enabled;
  1041. }
  1042. /*
  1043. * zfpm_conn_is_up
  1044. *
  1045. * Returns TRUE if the connection to the FPM is up.
  1046. */
  1047. static inline int
  1048. zfpm_conn_is_up (void)
  1049. {
  1050. if (zfpm_g->state != ZFPM_STATE_ESTABLISHED)
  1051. return 0;
  1052. assert (zfpm_g->sock >= 0);
  1053. return 1;
  1054. }
  1055. /*
  1056. * zfpm_trigger_update
  1057. *
  1058. * The zebra code invokes this function to indicate that we should
  1059. * send an update to the FPM about the given route_node.
  1060. */
  1061. void
  1062. zfpm_trigger_update (struct route_node *rn, const char *reason)
  1063. {
  1064. rib_dest_t *dest;
  1065. char buf[INET6_ADDRSTRLEN];
  1066. /*
  1067. * Ignore if the connection is down. We will update the FPM about
  1068. * all destinations once the connection comes up.
  1069. */
  1070. if (!zfpm_conn_is_up ())
  1071. return;
  1072. dest = rib_dest_from_rnode (rn);
  1073. /*
  1074. * Ignore the trigger if the dest is not in a table that we would
  1075. * send to the FPM.
  1076. */
  1077. if (!zfpm_is_table_for_fpm (rib_dest_table (dest)))
  1078. {
  1079. zfpm_g->stats.non_fpm_table_triggers++;
  1080. return;
  1081. }
  1082. if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) {
  1083. zfpm_g->stats.redundant_triggers++;
  1084. return;
  1085. }
  1086. if (reason)
  1087. {
  1088. zfpm_debug ("%s/%d triggering update to FPM - Reason: %s",
  1089. inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)),
  1090. rn->p.prefixlen, reason);
  1091. }
  1092. SET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM);
  1093. TAILQ_INSERT_TAIL (&zfpm_g->dest_q, dest, fpm_q_entries);
  1094. zfpm_g->stats.updates_triggered++;
  1095. /*
  1096. * Make sure that writes are enabled.
  1097. */
  1098. if (zfpm_g->t_write)
  1099. return;
  1100. zfpm_write_on ();
  1101. }
  1102. /*
  1103. * zfpm_stats_timer_cb
  1104. */
  1105. static int
  1106. zfpm_stats_timer_cb (struct thread *t)
  1107. {
  1108. assert (zfpm_g->t_stats);
  1109. zfpm_g->t_stats = NULL;
  1110. /*
  1111. * Remember the stats collected in the last interval for display
  1112. * purposes.
  1113. */
  1114. zfpm_stats_copy (&zfpm_g->stats, &zfpm_g->last_ivl_stats);
  1115. /*
  1116. * Add the current set of stats into the cumulative statistics.
  1117. */
  1118. zfpm_stats_compose (&zfpm_g->cumulative_stats, &zfpm_g->stats,
  1119. &zfpm_g->cumulative_stats);
  1120. /*
  1121. * Start collecting stats afresh over the next interval.
  1122. */
  1123. zfpm_stats_reset (&zfpm_g->stats);
  1124. zfpm_start_stats_timer ();
  1125. return 0;
  1126. }
  1127. /*
  1128. * zfpm_stop_stats_timer
  1129. */
  1130. static void
  1131. zfpm_stop_stats_timer (void)
  1132. {
  1133. if (!zfpm_g->t_stats)
  1134. return;
  1135. zfpm_debug ("Stopping existing stats timer");
  1136. THREAD_TIMER_OFF (zfpm_g->t_stats);
  1137. }
  1138. /*
  1139. * zfpm_start_stats_timer
  1140. */
  1141. void
  1142. zfpm_start_stats_timer (void)
  1143. {
  1144. assert (!zfpm_g->t_stats);
  1145. THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_stats, zfpm_stats_timer_cb, 0,
  1146. ZFPM_STATS_IVL_SECS);
  1147. }
  1148. /*
  1149. * Helper macro for zfpm_show_stats() below.
  1150. */
  1151. #define ZFPM_SHOW_STAT(counter) \
  1152. do { \
  1153. vty_out (vty, "%-40s %10lu %16lu%s", #counter, total_stats.counter, \
  1154. zfpm_g->last_ivl_stats.counter, VTY_NEWLINE); \
  1155. } while (0)
  1156. /*
  1157. * zfpm_show_stats
  1158. */
  1159. static void
  1160. zfpm_show_stats (struct vty *vty)
  1161. {
  1162. zfpm_stats_t total_stats;
  1163. time_t elapsed;
  1164. vty_out (vty, "%s%-40s %10s Last %2d secs%s%s", VTY_NEWLINE, "Counter",
  1165. "Total", ZFPM_STATS_IVL_SECS, VTY_NEWLINE, VTY_NEWLINE);
  1166. /*
  1167. * Compute the total stats up to this instant.
  1168. */
  1169. zfpm_stats_compose (&zfpm_g->cumulative_stats, &zfpm_g->stats,
  1170. &total_stats);
  1171. ZFPM_SHOW_STAT (connect_calls);
  1172. ZFPM_SHOW_STAT (connect_no_sock);
  1173. ZFPM_SHOW_STAT (read_cb_calls);
  1174. ZFPM_SHOW_STAT (write_cb_calls);
  1175. ZFPM_SHOW_STAT (write_calls);
  1176. ZFPM_SHOW_STAT (partial_writes);
  1177. ZFPM_SHOW_STAT (max_writes_hit);
  1178. ZFPM_SHOW_STAT (t_write_yields);
  1179. ZFPM_SHOW_STAT (nop_deletes_skipped);
  1180. ZFPM_SHOW_STAT (route_adds);
  1181. ZFPM_SHOW_STAT (route_dels);
  1182. ZFPM_SHOW_STAT (updates_triggered);
  1183. ZFPM_SHOW_STAT (non_fpm_table_triggers);
  1184. ZFPM_SHOW_STAT (redundant_triggers);
  1185. ZFPM_SHOW_STAT (dests_del_after_update);
  1186. ZFPM_SHOW_STAT (t_conn_down_starts);
  1187. ZFPM_SHOW_STAT (t_conn_down_dests_processed);
  1188. ZFPM_SHOW_STAT (t_conn_down_yields);
  1189. ZFPM_SHOW_STAT (t_conn_down_finishes);
  1190. ZFPM_SHOW_STAT (t_conn_up_starts);
  1191. ZFPM_SHOW_STAT (t_conn_up_dests_processed);
  1192. ZFPM_SHOW_STAT (t_conn_up_yields);
  1193. ZFPM_SHOW_STAT (t_conn_up_aborts);
  1194. ZFPM_SHOW_STAT (t_conn_up_finishes);
  1195. if (!zfpm_g->last_stats_clear_time)
  1196. return;
  1197. elapsed = zfpm_get_elapsed_time (zfpm_g->last_stats_clear_time);
  1198. vty_out (vty, "%sStats were cleared %lu seconds ago%s", VTY_NEWLINE,
  1199. (unsigned long) elapsed, VTY_NEWLINE);
  1200. }
  1201. /*
  1202. * zfpm_clear_stats
  1203. */
  1204. static void
  1205. zfpm_clear_stats (struct vty *vty)
  1206. {
  1207. if (!zfpm_is_enabled ())
  1208. {
  1209. vty_out (vty, "The FPM module is not enabled...%s", VTY_NEWLINE);
  1210. return;
  1211. }
  1212. zfpm_stats_reset (&zfpm_g->stats);
  1213. zfpm_stats_reset (&zfpm_g->last_ivl_stats);
  1214. zfpm_stats_reset (&zfpm_g->cumulative_stats);
  1215. zfpm_stop_stats_timer ();
  1216. zfpm_start_stats_timer ();
  1217. zfpm_g->last_stats_clear_time = zfpm_get_time();
  1218. vty_out (vty, "Cleared FPM stats%s", VTY_NEWLINE);
  1219. }
  1220. /*
  1221. * show_zebra_fpm_stats
  1222. */
  1223. DEFUN (show_zebra_fpm_stats,
  1224. show_zebra_fpm_stats_cmd,
  1225. "show zebra fpm stats",
  1226. SHOW_STR
  1227. "Zebra information\n"
  1228. "Forwarding Path Manager information\n"
  1229. "Statistics\n")
  1230. {
  1231. zfpm_show_stats (vty);
  1232. return CMD_SUCCESS;
  1233. }
  1234. /*
  1235. * clear_zebra_fpm_stats
  1236. */
  1237. DEFUN (clear_zebra_fpm_stats,
  1238. clear_zebra_fpm_stats_cmd,
  1239. "clear zebra fpm stats",
  1240. CLEAR_STR
  1241. "Zebra information\n"
  1242. "Clear Forwarding Path Manager information\n"
  1243. "Statistics\n")
  1244. {
  1245. zfpm_clear_stats (vty);
  1246. return CMD_SUCCESS;
  1247. }
  1248. /**
  1249. * zfpm_init
  1250. *
  1251. * One-time initialization of the Zebra FPM module.
  1252. *
  1253. * @param[in] port port at which FPM is running.
  1254. * @param[in] enable TRUE if the zebra FPM module should be enabled
  1255. *
  1256. * Returns TRUE on success.
  1257. */
  1258. int
  1259. zfpm_init (struct thread_master *master, int enable, uint16_t port)
  1260. {
  1261. static int initialized = 0;
  1262. if (initialized) {
  1263. return 1;
  1264. }
  1265. initialized = 1;
  1266. memset (zfpm_g, 0, sizeof (*zfpm_g));
  1267. zfpm_g->master = master;
  1268. TAILQ_INIT(&zfpm_g->dest_q);
  1269. zfpm_g->sock = -1;
  1270. zfpm_g->state = ZFPM_STATE_IDLE;
  1271. /*
  1272. * Netlink must currently be available for the Zebra-FPM interface
  1273. * to be enabled.
  1274. */
  1275. #ifndef HAVE_NETLINK
  1276. enable = 0;
  1277. #endif
  1278. zfpm_g->enabled = enable;
  1279. zfpm_stats_init (&zfpm_g->stats);
  1280. zfpm_stats_init (&zfpm_g->last_ivl_stats);
  1281. zfpm_stats_init (&zfpm_g->cumulative_stats);
  1282. install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd);
  1283. install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd);
  1284. if (!enable) {
  1285. return 1;
  1286. }
  1287. if (!port)
  1288. port = FPM_DEFAULT_PORT;
  1289. zfpm_g->fpm_port = port;
  1290. zfpm_g->obuf = stream_new (ZFPM_OBUF_SIZE);
  1291. zfpm_g->ibuf = stream_new (ZFPM_IBUF_SIZE);
  1292. zfpm_start_stats_timer ();
  1293. zfpm_start_connect_timer ("initialized");
  1294. return 1;
  1295. }