pim_zlookup.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. PIM for Quagga
  3. Copyright (C) 2008 Everton da Silva Marques
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program 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 this program; see the file COPYING; if not, write to the
  14. Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
  15. MA 02110-1301 USA
  16. $QuaggaId: $Format:%an, %ai, %h$ $
  17. */
  18. #include <zebra.h>
  19. #include "zebra/rib.h"
  20. #include "log.h"
  21. #include "prefix.h"
  22. #include "zclient.h"
  23. #include "stream.h"
  24. #include "network.h"
  25. #include "thread.h"
  26. #include "pimd.h"
  27. #include "pim_pim.h"
  28. #include "pim_str.h"
  29. #include "pim_zlookup.h"
  30. extern int zclient_debug;
  31. static void zclient_lookup_sched(struct zclient *zlookup, int delay);
  32. /* Connect to zebra for nexthop lookup. */
  33. static int zclient_lookup_connect(struct thread *t)
  34. {
  35. struct zclient *zlookup;
  36. zlookup = THREAD_ARG(t);
  37. zlookup->t_connect = NULL;
  38. if (zlookup->sock >= 0) {
  39. return 0;
  40. }
  41. if (zclient_socket_connect(zlookup) < 0) {
  42. ++zlookup->fail;
  43. zlog_warn("%s: failure connecting zclient socket: failures=%d",
  44. __PRETTY_FUNCTION__, zlookup->fail);
  45. }
  46. else {
  47. zlookup->fail = 0; /* reset counter on connection */
  48. }
  49. zassert(!zlookup->t_connect);
  50. if (zlookup->sock < 0) {
  51. /* Since last connect failed, retry within 10 secs */
  52. zclient_lookup_sched(zlookup, 10);
  53. return -1;
  54. }
  55. return 0;
  56. }
  57. /* Schedule connection with delay. */
  58. static void zclient_lookup_sched(struct zclient *zlookup, int delay)
  59. {
  60. zassert(!zlookup->t_connect);
  61. THREAD_TIMER_ON(master, zlookup->t_connect,
  62. zclient_lookup_connect,
  63. zlookup, delay);
  64. zlog_notice("%s: zclient lookup connection scheduled for %d seconds",
  65. __PRETTY_FUNCTION__, delay);
  66. }
  67. /* Schedule connection for now. */
  68. static void zclient_lookup_sched_now(struct zclient *zlookup)
  69. {
  70. zassert(!zlookup->t_connect);
  71. zlookup->t_connect = thread_add_event(master, zclient_lookup_connect,
  72. zlookup, 0);
  73. zlog_notice("%s: zclient lookup immediate connection scheduled",
  74. __PRETTY_FUNCTION__);
  75. }
  76. /* Schedule reconnection, if needed. */
  77. static void zclient_lookup_reconnect(struct zclient *zlookup)
  78. {
  79. if (zlookup->t_connect) {
  80. return;
  81. }
  82. zclient_lookup_sched_now(zlookup);
  83. }
  84. static void zclient_lookup_failed(struct zclient *zlookup)
  85. {
  86. if (zlookup->sock >= 0) {
  87. if (close(zlookup->sock)) {
  88. zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, zlookup->sock,
  89. errno, safe_strerror(errno));
  90. }
  91. zlookup->sock = -1;
  92. }
  93. zclient_lookup_reconnect(zlookup);
  94. }
  95. struct zclient *zclient_lookup_new()
  96. {
  97. struct zclient *zlookup;
  98. zlookup = zclient_new();
  99. if (!zlookup) {
  100. zlog_err("%s: zclient_new() failure",
  101. __PRETTY_FUNCTION__);
  102. return 0;
  103. }
  104. zlookup->sock = -1;
  105. zlookup->ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
  106. zlookup->obuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
  107. zlookup->t_connect = 0;
  108. zclient_lookup_sched_now(zlookup);
  109. zlog_notice("%s: zclient lookup socket initialized",
  110. __PRETTY_FUNCTION__);
  111. return zlookup;
  112. }
  113. static int zclient_read_nexthop(struct zclient *zlookup,
  114. struct pim_zlookup_nexthop nexthop_tab[],
  115. const int tab_size,
  116. struct in_addr addr)
  117. {
  118. int num_ifindex = 0;
  119. struct stream *s;
  120. const uint16_t MIN_LEN = 14; /* getc=1 getc=1 getw=2 getipv4=4 getc=1 getl=4 getc=1 */
  121. uint16_t length, len;
  122. u_char marker;
  123. u_char version;
  124. uint16_t command;
  125. int nbytes;
  126. struct in_addr raddr;
  127. uint8_t distance;
  128. uint32_t metric;
  129. int nexthop_num;
  130. int i;
  131. if (PIM_DEBUG_ZEBRA) {
  132. char addr_str[100];
  133. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  134. zlog_debug("%s: addr=%s",
  135. __PRETTY_FUNCTION__,
  136. addr_str);
  137. }
  138. s = zlookup->ibuf;
  139. stream_reset(s);
  140. nbytes = stream_read(s, zlookup->sock, 2);
  141. if (nbytes < 2) {
  142. zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d",
  143. __FILE__, __PRETTY_FUNCTION__, nbytes);
  144. zclient_lookup_failed(zlookup);
  145. return -1;
  146. }
  147. length = stream_getw(s);
  148. len = length - 2;
  149. if (len < MIN_LEN) {
  150. zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d",
  151. __FILE__, __PRETTY_FUNCTION__, len, MIN_LEN);
  152. zclient_lookup_failed(zlookup);
  153. return -2;
  154. }
  155. nbytes = stream_read(s, zlookup->sock, len);
  156. if (nbytes < (length - 2)) {
  157. zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d < len=%d",
  158. __FILE__, __PRETTY_FUNCTION__, nbytes, len);
  159. zclient_lookup_failed(zlookup);
  160. return -3;
  161. }
  162. marker = stream_getc(s);
  163. version = stream_getc(s);
  164. if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) {
  165. zlog_err("%s: socket %d version mismatch, marker %d, version %d",
  166. __func__, zlookup->sock, marker, version);
  167. return -4;
  168. }
  169. command = stream_getw(s);
  170. if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) {
  171. zlog_err("%s: socket %d command mismatch: %d",
  172. __func__, zlookup->sock, command);
  173. return -5;
  174. }
  175. raddr.s_addr = stream_get_ipv4(s);
  176. if (raddr.s_addr != addr.s_addr) {
  177. char addr_str[100];
  178. char raddr_str[100];
  179. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  180. pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str));
  181. zlog_warn("%s: address mismatch: addr=%s raddr=%s",
  182. __PRETTY_FUNCTION__,
  183. addr_str, raddr_str);
  184. /* warning only */
  185. }
  186. distance = stream_getc(s);
  187. metric = stream_getl(s);
  188. nexthop_num = stream_getc(s);
  189. if (nexthop_num < 1) {
  190. zlog_err("%s: socket %d bad nexthop_num=%d",
  191. __func__, zlookup->sock, nexthop_num);
  192. return -6;
  193. }
  194. len -= MIN_LEN;
  195. for (i = 0; i < nexthop_num; ++i) {
  196. enum nexthop_types_t nexthop_type;
  197. if (len < 1) {
  198. zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d",
  199. __func__, zlookup->sock, len);
  200. return -7;
  201. }
  202. nexthop_type = stream_getc(s);
  203. --len;
  204. switch (nexthop_type) {
  205. case ZEBRA_NEXTHOP_IFINDEX:
  206. case ZEBRA_NEXTHOP_IFNAME:
  207. case ZEBRA_NEXTHOP_IPV4_IFINDEX:
  208. if (num_ifindex >= tab_size) {
  209. char addr_str[100];
  210. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  211. zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s",
  212. __FILE__, __PRETTY_FUNCTION__,
  213. (num_ifindex + 1), tab_size, addr_str);
  214. return num_ifindex;
  215. }
  216. if (nexthop_type == ZEBRA_NEXTHOP_IPV4_IFINDEX) {
  217. if (len < 4) {
  218. zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d",
  219. __func__, zlookup->sock, len);
  220. return -8;
  221. }
  222. nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s);
  223. len -= 4;
  224. }
  225. else {
  226. nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
  227. }
  228. nexthop_tab[num_ifindex].ifindex = stream_getl(s);
  229. nexthop_tab[num_ifindex].protocol_distance = distance;
  230. nexthop_tab[num_ifindex].route_metric = metric;
  231. ++num_ifindex;
  232. break;
  233. case ZEBRA_NEXTHOP_IPV4:
  234. if (num_ifindex >= tab_size) {
  235. char addr_str[100];
  236. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  237. zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s",
  238. __FILE__, __PRETTY_FUNCTION__,
  239. (num_ifindex + 1), tab_size, addr_str);
  240. return num_ifindex;
  241. }
  242. nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s);
  243. len -= 4;
  244. nexthop_tab[num_ifindex].ifindex = 0;
  245. nexthop_tab[num_ifindex].protocol_distance = distance;
  246. nexthop_tab[num_ifindex].route_metric = metric;
  247. {
  248. char addr_str[100];
  249. char nexthop_str[100];
  250. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  251. pim_inet4_dump("<nexthop?>", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str));
  252. zlog_warn("%s %s: zebra returned recursive nexthop %s for address %s",
  253. __FILE__, __PRETTY_FUNCTION__,
  254. nexthop_str, addr_str);
  255. }
  256. ++num_ifindex;
  257. break;
  258. default:
  259. /* do nothing */
  260. {
  261. char addr_str[100];
  262. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  263. zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s",
  264. __FILE__, __PRETTY_FUNCTION__,
  265. nexthop_type, addr_str);
  266. }
  267. break;
  268. }
  269. }
  270. return num_ifindex;
  271. }
  272. static int zclient_lookup_nexthop_once(struct zclient *zlookup,
  273. struct pim_zlookup_nexthop nexthop_tab[],
  274. const int tab_size,
  275. struct in_addr addr)
  276. {
  277. struct stream *s;
  278. int ret;
  279. if (PIM_DEBUG_ZEBRA) {
  280. char addr_str[100];
  281. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  282. zlog_debug("%s: addr=%s",
  283. __PRETTY_FUNCTION__,
  284. addr_str);
  285. }
  286. /* Check socket. */
  287. if (zlookup->sock < 0) {
  288. zlog_err("%s %s: zclient lookup socket is not connected",
  289. __FILE__, __PRETTY_FUNCTION__);
  290. zclient_lookup_failed(zlookup);
  291. return -1;
  292. }
  293. s = zlookup->obuf;
  294. stream_reset(s);
  295. zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB);
  296. stream_put_in_addr(s, &addr);
  297. stream_putw_at(s, 0, stream_get_endp(s));
  298. ret = writen(zlookup->sock, s->data, stream_get_endp(s));
  299. if (ret < 0) {
  300. zlog_err("%s %s: writen() failure writing to zclient lookup socket",
  301. __FILE__, __PRETTY_FUNCTION__);
  302. zclient_lookup_failed(zlookup);
  303. return -2;
  304. }
  305. if (ret == 0) {
  306. zlog_err("%s %s: connection closed on zclient lookup socket",
  307. __FILE__, __PRETTY_FUNCTION__);
  308. zclient_lookup_failed(zlookup);
  309. return -3;
  310. }
  311. return zclient_read_nexthop(zlookup, nexthop_tab,
  312. tab_size, addr);
  313. }
  314. int zclient_lookup_nexthop(struct zclient *zlookup,
  315. struct pim_zlookup_nexthop nexthop_tab[],
  316. const int tab_size,
  317. struct in_addr addr,
  318. int max_lookup)
  319. {
  320. int lookup;
  321. uint32_t route_metric = 0xFFFFFFFF;
  322. uint8_t protocol_distance = 0xFF;
  323. for (lookup = 0; lookup < max_lookup; ++lookup) {
  324. int num_ifindex;
  325. int first_ifindex;
  326. struct in_addr nexthop_addr;
  327. num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab,
  328. PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr);
  329. if (num_ifindex < 1) {
  330. char addr_str[100];
  331. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  332. zlog_warn("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s",
  333. __FILE__, __PRETTY_FUNCTION__,
  334. lookup, max_lookup, addr_str);
  335. return -1;
  336. }
  337. if (lookup < 1) {
  338. /* this is the non-recursive lookup - save original metric/distance */
  339. route_metric = nexthop_tab[0].route_metric;
  340. protocol_distance = nexthop_tab[0].protocol_distance;
  341. }
  342. /*
  343. FIXME: Non-recursive nexthop ensured only for first ifindex.
  344. However, recursive route lookup should really be fixed in zebra daemon.
  345. See also TODO T24.
  346. */
  347. first_ifindex = nexthop_tab[0].ifindex;
  348. nexthop_addr = nexthop_tab[0].nexthop_addr;
  349. if (first_ifindex > 0) {
  350. /* found: first ifindex is non-recursive nexthop */
  351. if (lookup > 0) {
  352. /* Report non-recursive success after first lookup */
  353. char addr_str[100];
  354. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  355. zlog_info("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d",
  356. __FILE__, __PRETTY_FUNCTION__,
  357. lookup, max_lookup, first_ifindex, addr_str,
  358. nexthop_tab[0].protocol_distance,
  359. nexthop_tab[0].route_metric);
  360. /* use last address as nexthop address */
  361. nexthop_tab[0].nexthop_addr = addr;
  362. /* report original route metric/distance */
  363. nexthop_tab[0].route_metric = route_metric;
  364. nexthop_tab[0].protocol_distance = protocol_distance;
  365. }
  366. return num_ifindex;
  367. }
  368. {
  369. char addr_str[100];
  370. char nexthop_str[100];
  371. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  372. pim_inet4_dump("<nexthop?>", nexthop_addr, nexthop_str, sizeof(nexthop_str));
  373. zlog_warn("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d",
  374. __FILE__, __PRETTY_FUNCTION__,
  375. lookup, max_lookup, nexthop_str, addr_str,
  376. nexthop_tab[0].protocol_distance,
  377. nexthop_tab[0].route_metric);
  378. }
  379. addr = nexthop_addr; /* use nexthop addr for recursive lookup */
  380. } /* for (max_lookup) */
  381. char addr_str[100];
  382. pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
  383. zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s",
  384. __FILE__, __PRETTY_FUNCTION__,
  385. lookup, max_lookup, addr_str);
  386. return -2;
  387. }