pim_join.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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 "log.h"
  20. #include "prefix.h"
  21. #include "pimd.h"
  22. #include "pim_str.h"
  23. #include "pim_tlv.h"
  24. #include "pim_msg.h"
  25. #include "pim_pim.h"
  26. #include "pim_join.h"
  27. #include "pim_iface.h"
  28. #include "pim_hello.h"
  29. #include "pim_ifchannel.h"
  30. static void on_trace(const char *label,
  31. struct interface *ifp, struct in_addr src)
  32. {
  33. if (PIM_DEBUG_PIM_TRACE) {
  34. char src_str[100];
  35. pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
  36. zlog_debug("%s: from %s on %s",
  37. label, src_str, ifp->name);
  38. }
  39. }
  40. static void recv_join(struct interface *ifp,
  41. struct pim_neighbor *neigh,
  42. uint16_t holdtime,
  43. struct in_addr upstream,
  44. struct in_addr group,
  45. struct in_addr source,
  46. uint8_t source_flags)
  47. {
  48. if (PIM_DEBUG_PIM_TRACE) {
  49. char up_str[100];
  50. char src_str[100];
  51. char grp_str[100];
  52. char neigh_str[100];
  53. pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
  54. pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
  55. pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
  56. pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
  57. zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
  58. __PRETTY_FUNCTION__,
  59. src_str, grp_str,
  60. source_flags & PIM_RPT_BIT_MASK,
  61. source_flags & PIM_WILDCARD_BIT_MASK,
  62. up_str, holdtime, neigh_str, ifp->name);
  63. }
  64. /* Restart join expiry timer */
  65. pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
  66. source, group, source_flags, holdtime);
  67. }
  68. static void recv_prune(struct interface *ifp,
  69. struct pim_neighbor *neigh,
  70. uint16_t holdtime,
  71. struct in_addr upstream,
  72. struct in_addr group,
  73. struct in_addr source,
  74. uint8_t source_flags)
  75. {
  76. if (PIM_DEBUG_PIM_TRACE) {
  77. char up_str[100];
  78. char src_str[100];
  79. char grp_str[100];
  80. char neigh_str[100];
  81. pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
  82. pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
  83. pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
  84. pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
  85. zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
  86. __PRETTY_FUNCTION__,
  87. src_str, grp_str,
  88. source_flags & PIM_RPT_BIT_MASK,
  89. source_flags & PIM_WILDCARD_BIT_MASK,
  90. up_str, holdtime, neigh_str, ifp->name);
  91. }
  92. pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime);
  93. }
  94. int pim_joinprune_recv(struct interface *ifp,
  95. struct pim_neighbor *neigh,
  96. struct in_addr src_addr,
  97. uint8_t *tlv_buf, int tlv_buf_size)
  98. {
  99. struct prefix msg_upstream_addr;
  100. uint8_t msg_num_groups;
  101. uint16_t msg_holdtime;
  102. int addr_offset;
  103. uint8_t *buf;
  104. uint8_t *pastend;
  105. int remain;
  106. int group;
  107. on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
  108. buf = tlv_buf;
  109. pastend = tlv_buf + tlv_buf_size;
  110. /*
  111. Parse ucast addr
  112. */
  113. addr_offset = pim_parse_addr_ucast(ifp->name, src_addr,
  114. &msg_upstream_addr,
  115. buf, pastend - buf);
  116. #if 0
  117. zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d",
  118. __PRETTY_FUNCTION__,
  119. addr_offset);
  120. #endif
  121. if (addr_offset < 1) {
  122. char src_str[100];
  123. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  124. zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
  125. __PRETTY_FUNCTION__,
  126. src_str, ifp->name);
  127. return -1;
  128. }
  129. buf += addr_offset;
  130. /*
  131. Check upstream address family
  132. */
  133. if (msg_upstream_addr.family != AF_INET) {
  134. if (PIM_DEBUG_PIM_TRACE) {
  135. char src_str[100];
  136. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  137. zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
  138. __PRETTY_FUNCTION__,
  139. msg_upstream_addr.family, src_str, ifp->name);
  140. }
  141. return -2;
  142. }
  143. remain = pastend - buf;
  144. if (remain < 4) {
  145. char src_str[100];
  146. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  147. zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
  148. __PRETTY_FUNCTION__,
  149. remain, 4, src_str, ifp->name);
  150. return -4;
  151. }
  152. ++buf; /* skip reserved byte */
  153. msg_num_groups = *(const uint8_t *) buf;
  154. ++buf;
  155. msg_holdtime = ntohs(*(const uint16_t *) buf);
  156. ++buf;
  157. ++buf;
  158. if (PIM_DEBUG_PIM_TRACE) {
  159. char src_str[100];
  160. char upstream_str[100];
  161. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  162. pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
  163. upstream_str, sizeof(upstream_str));
  164. zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
  165. __PRETTY_FUNCTION__,
  166. upstream_str, msg_num_groups, msg_holdtime,
  167. src_str, ifp->name);
  168. }
  169. /* Scan groups */
  170. for (group = 0; group < msg_num_groups; ++group) {
  171. struct prefix msg_group_addr;
  172. struct prefix msg_source_addr;
  173. uint8_t msg_source_flags;
  174. uint16_t msg_num_joined_sources;
  175. uint16_t msg_num_pruned_sources;
  176. int source;
  177. addr_offset = pim_parse_addr_group(ifp->name, src_addr,
  178. &msg_group_addr,
  179. buf, pastend - buf);
  180. #if 0
  181. zlog_warn("%s: pim_parse_addr_group addr_offset=%d",
  182. __PRETTY_FUNCTION__,
  183. addr_offset);
  184. #endif
  185. if (addr_offset < 1) {
  186. return -5;
  187. }
  188. buf += addr_offset;
  189. remain = pastend - buf;
  190. if (remain < 4) {
  191. char src_str[100];
  192. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  193. zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
  194. __PRETTY_FUNCTION__,
  195. remain, 4, src_str, ifp->name);
  196. return -6;
  197. }
  198. msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
  199. buf += 2;
  200. msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
  201. buf += 2;
  202. if (PIM_DEBUG_PIM_TRACE) {
  203. char src_str[100];
  204. char upstream_str[100];
  205. char group_str[100];
  206. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  207. pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
  208. upstream_str, sizeof(upstream_str));
  209. pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4,
  210. group_str, sizeof(group_str));
  211. zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
  212. __PRETTY_FUNCTION__,
  213. upstream_str, group_str, msg_group_addr.prefixlen,
  214. msg_num_joined_sources, msg_num_pruned_sources,
  215. src_str, ifp->name);
  216. }
  217. /* Scan joined sources */
  218. for (source = 0; source < msg_num_joined_sources; ++source) {
  219. addr_offset = pim_parse_addr_source(ifp->name, src_addr,
  220. &msg_source_addr,
  221. &msg_source_flags,
  222. buf, pastend - buf);
  223. #if 0
  224. zlog_warn("%s: pim_parse_addr_source addr_offset=%d",
  225. __PRETTY_FUNCTION__,
  226. addr_offset);
  227. #endif
  228. if (addr_offset < 1) {
  229. return -7;
  230. }
  231. buf += addr_offset;
  232. recv_join(ifp, neigh, msg_holdtime,
  233. msg_upstream_addr.u.prefix4,
  234. msg_group_addr.u.prefix4,
  235. msg_source_addr.u.prefix4,
  236. msg_source_flags);
  237. }
  238. /* Scan pruned sources */
  239. for (source = 0; source < msg_num_pruned_sources; ++source) {
  240. addr_offset = pim_parse_addr_source(ifp->name, src_addr,
  241. &msg_source_addr,
  242. &msg_source_flags,
  243. buf, pastend - buf);
  244. if (addr_offset < 1) {
  245. return -8;
  246. }
  247. buf += addr_offset;
  248. recv_prune(ifp, neigh, msg_holdtime,
  249. msg_upstream_addr.u.prefix4,
  250. msg_group_addr.u.prefix4,
  251. msg_source_addr.u.prefix4,
  252. msg_source_flags);
  253. }
  254. } /* scan groups */
  255. return 0;
  256. }
  257. int pim_joinprune_send(struct interface *ifp,
  258. struct in_addr upstream_addr,
  259. struct in_addr source_addr,
  260. struct in_addr group_addr,
  261. int send_join)
  262. {
  263. struct pim_interface *pim_ifp;
  264. uint8_t pim_msg[1000];
  265. const uint8_t *pastend = pim_msg + sizeof(pim_msg);
  266. uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
  267. int pim_msg_size;
  268. int remain;
  269. zassert(ifp);
  270. pim_ifp = ifp->info;
  271. if (!pim_ifp) {
  272. zlog_warn("%s: multicast not enabled on interface %s",
  273. __PRETTY_FUNCTION__,
  274. ifp->name);
  275. return -1;
  276. }
  277. if (PIM_DEBUG_PIM_TRACE) {
  278. char source_str[100];
  279. char group_str[100];
  280. char dst_str[100];
  281. pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  282. pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  283. pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
  284. zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s",
  285. __PRETTY_FUNCTION__,
  286. send_join ? "Join" : "Prune",
  287. source_str, group_str, dst_str, ifp->name);
  288. }
  289. if (PIM_INADDR_IS_ANY(upstream_addr)) {
  290. if (PIM_DEBUG_PIM_TRACE) {
  291. char source_str[100];
  292. char group_str[100];
  293. char dst_str[100];
  294. pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  295. pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  296. pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
  297. zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s",
  298. __PRETTY_FUNCTION__,
  299. send_join ? "Join" : "Prune",
  300. source_str, group_str, dst_str, ifp->name);
  301. }
  302. return 0;
  303. }
  304. /*
  305. RFC 4601: 4.3.1. Sending Hello Messages
  306. Thus, if a router needs to send a Join/Prune or Assert message on
  307. an interface on which it has not yet sent a Hello message with the
  308. currently configured IP address, then it MUST immediately send the
  309. relevant Hello message without waiting for the Hello Timer to
  310. expire, followed by the Join/Prune or Assert message.
  311. */
  312. pim_hello_require(ifp);
  313. /*
  314. Build PIM message
  315. */
  316. remain = pastend - pim_msg_curr;
  317. pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
  318. remain,
  319. upstream_addr);
  320. if (!pim_msg_curr) {
  321. char dst_str[100];
  322. pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
  323. zlog_warn("%s: failure encoding destination address %s: space left=%d",
  324. __PRETTY_FUNCTION__, dst_str, remain);
  325. return -3;
  326. }
  327. remain = pastend - pim_msg_curr;
  328. if (remain < 4) {
  329. zlog_warn("%s: group will not fit: space left=%d",
  330. __PRETTY_FUNCTION__, remain);
  331. return -4;
  332. }
  333. *pim_msg_curr = 0; /* reserved */
  334. ++pim_msg_curr;
  335. *pim_msg_curr = 1; /* number of groups */
  336. ++pim_msg_curr;
  337. *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME);
  338. ++pim_msg_curr;
  339. ++pim_msg_curr;
  340. remain = pastend - pim_msg_curr;
  341. pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
  342. remain,
  343. group_addr);
  344. if (!pim_msg_curr) {
  345. char group_str[100];
  346. pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  347. zlog_warn("%s: failure encoding group address %s: space left=%d",
  348. __PRETTY_FUNCTION__, group_str, remain);
  349. return -5;
  350. }
  351. remain = pastend - pim_msg_curr;
  352. if (remain < 4) {
  353. zlog_warn("%s: sources will not fit: space left=%d",
  354. __PRETTY_FUNCTION__, remain);
  355. return -6;
  356. }
  357. /* number of joined sources */
  358. *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0);
  359. ++pim_msg_curr;
  360. ++pim_msg_curr;
  361. /* number of pruned sources */
  362. *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1);
  363. ++pim_msg_curr;
  364. ++pim_msg_curr;
  365. remain = pastend - pim_msg_curr;
  366. pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr,
  367. remain,
  368. source_addr);
  369. if (!pim_msg_curr) {
  370. char source_str[100];
  371. pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  372. zlog_warn("%s: failure encoding source address %s: space left=%d",
  373. __PRETTY_FUNCTION__, source_str, remain);
  374. return -7;
  375. }
  376. /* Add PIM header */
  377. pim_msg_size = pim_msg_curr - pim_msg;
  378. pim_msg_build_header(pim_msg, pim_msg_size,
  379. PIM_MSG_TYPE_JOIN_PRUNE);
  380. if (pim_msg_send(pim_ifp->pim_sock_fd,
  381. qpim_all_pim_routers_addr,
  382. pim_msg,
  383. pim_msg_size,
  384. ifp->name)) {
  385. zlog_warn("%s: could not send PIM message on interface %s",
  386. __PRETTY_FUNCTION__, ifp->name);
  387. return -8;
  388. }
  389. return 0;
  390. }