pim_assert.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  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_time.h"
  27. #include "pim_iface.h"
  28. #include "pim_hello.h"
  29. #include "pim_macro.h"
  30. #include "pim_assert.h"
  31. #include "pim_ifchannel.h"
  32. static int assert_action_a3(struct pim_ifchannel *ch);
  33. static void assert_action_a2(struct pim_ifchannel *ch,
  34. struct pim_assert_metric winner_metric);
  35. static void assert_action_a6(struct pim_ifchannel *ch,
  36. struct pim_assert_metric winner_metric);
  37. void pim_ifassert_winner_set(struct pim_ifchannel *ch,
  38. enum pim_ifassert_state new_state,
  39. struct in_addr winner,
  40. struct pim_assert_metric winner_metric)
  41. {
  42. int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr);
  43. int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric,
  44. &winner_metric);
  45. if (ch->ifassert_state != new_state) {
  46. char src_str[100];
  47. char grp_str[100];
  48. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  49. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  50. zlog_info("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s",
  51. __PRETTY_FUNCTION__,
  52. src_str, grp_str,
  53. pim_ifchannel_ifassert_name(ch->ifassert_state),
  54. pim_ifchannel_ifassert_name(new_state),
  55. ch->interface->name);
  56. }
  57. {
  58. char src_str[100];
  59. char grp_str[100];
  60. char winner_str[100];
  61. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  62. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  63. pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str));
  64. zlog_info("%s: (S,G)=(%s,%s) assert winner now is %s on interface %s",
  65. __PRETTY_FUNCTION__,
  66. src_str, grp_str,
  67. winner_str, ch->interface->name);
  68. }
  69. ch->ifassert_state = new_state;
  70. ch->ifassert_winner = winner;
  71. ch->ifassert_winner_metric = winner_metric;
  72. ch->ifassert_creation = pim_time_monotonic_sec();
  73. if (winner_changed || metric_changed) {
  74. pim_upstream_update_join_desired(ch->upstream);
  75. pim_ifchannel_update_could_assert(ch);
  76. pim_ifchannel_update_assert_tracking_desired(ch);
  77. }
  78. }
  79. static void on_trace(const char *label,
  80. struct interface *ifp, struct in_addr src)
  81. {
  82. if (PIM_DEBUG_PIM_TRACE) {
  83. char src_str[100];
  84. pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
  85. zlog_debug("%s: from %s on %s",
  86. label, src_str, ifp->name);
  87. }
  88. }
  89. static int preferred_assert(const struct pim_ifchannel *ch,
  90. const struct pim_assert_metric *recv_metric)
  91. {
  92. return pim_assert_metric_better(recv_metric,
  93. &ch->ifassert_winner_metric);
  94. }
  95. static int acceptable_assert(const struct pim_assert_metric *my_metric,
  96. const struct pim_assert_metric *recv_metric)
  97. {
  98. return pim_assert_metric_better(recv_metric,
  99. my_metric);
  100. }
  101. static int inferior_assert(const struct pim_assert_metric *my_metric,
  102. const struct pim_assert_metric *recv_metric)
  103. {
  104. return pim_assert_metric_better(my_metric,
  105. recv_metric);
  106. }
  107. static int cancel_assert(const struct pim_assert_metric *recv_metric)
  108. {
  109. return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
  110. &&
  111. (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX);
  112. }
  113. static void if_could_assert_do_a1(const char *caller,
  114. struct pim_ifchannel *ch)
  115. {
  116. if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
  117. if (assert_action_a1(ch)) {
  118. char src_str[100];
  119. char grp_str[100];
  120. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  121. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  122. zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
  123. __PRETTY_FUNCTION__, caller,
  124. src_str, grp_str, ch->interface->name);
  125. /* log warning only */
  126. }
  127. }
  128. }
  129. static int dispatch_assert(struct interface *ifp,
  130. struct in_addr source_addr,
  131. struct in_addr group_addr,
  132. struct pim_assert_metric recv_metric)
  133. {
  134. struct pim_ifchannel *ch;
  135. ch = pim_ifchannel_add(ifp, source_addr, group_addr);
  136. if (!ch) {
  137. char source_str[100];
  138. char group_str[100];
  139. pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  140. pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  141. zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
  142. __PRETTY_FUNCTION__,
  143. source_str, group_str, ifp->name);
  144. return -1;
  145. }
  146. switch (ch->ifassert_state) {
  147. case PIM_IFASSERT_NOINFO:
  148. if (recv_metric.rpt_bit_flag) {
  149. /* RPT bit set */
  150. if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
  151. }
  152. else {
  153. /* RPT bit clear */
  154. if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
  155. if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
  156. }
  157. else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
  158. if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)) {
  159. assert_action_a6(ch, recv_metric);
  160. }
  161. }
  162. }
  163. break;
  164. case PIM_IFASSERT_I_AM_WINNER:
  165. if (preferred_assert(ch, &recv_metric)) {
  166. assert_action_a2(ch, recv_metric);
  167. }
  168. else {
  169. if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
  170. zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
  171. assert_action_a3(ch);
  172. }
  173. }
  174. break;
  175. case PIM_IFASSERT_I_AM_LOSER:
  176. if (recv_metric.ip_address.s_addr == ch->ifassert_winner.s_addr) {
  177. /* Assert from current winner */
  178. if (cancel_assert(&recv_metric)) {
  179. assert_action_a5(ch);
  180. }
  181. else {
  182. if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
  183. assert_action_a5(ch);
  184. }
  185. else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
  186. if (!recv_metric.rpt_bit_flag) {
  187. assert_action_a2(ch, recv_metric);
  188. }
  189. }
  190. }
  191. }
  192. else if (preferred_assert(ch, &recv_metric)) {
  193. assert_action_a2(ch, recv_metric);
  194. }
  195. break;
  196. default:
  197. {
  198. char source_str[100];
  199. char group_str[100];
  200. pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  201. pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  202. zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
  203. __PRETTY_FUNCTION__,
  204. source_str, group_str, ch->ifassert_state, ifp->name);
  205. }
  206. return -2;
  207. }
  208. return 0;
  209. }
  210. int pim_assert_recv(struct interface *ifp,
  211. struct pim_neighbor *neigh,
  212. struct in_addr src_addr,
  213. char *buf, int buf_size)
  214. {
  215. struct prefix msg_group_addr;
  216. struct prefix msg_source_addr;
  217. struct pim_assert_metric msg_metric;
  218. int offset;
  219. char *curr;
  220. int curr_size;
  221. on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
  222. curr = buf;
  223. curr_size = buf_size;
  224. /*
  225. Parse assert group addr
  226. */
  227. offset = pim_parse_addr_group(ifp->name, src_addr,
  228. &msg_group_addr,
  229. curr, curr_size);
  230. if (offset < 1) {
  231. char src_str[100];
  232. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  233. zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
  234. __PRETTY_FUNCTION__,
  235. src_str, ifp->name);
  236. return -1;
  237. }
  238. curr += offset;
  239. curr_size -= offset;
  240. /*
  241. Parse assert source addr
  242. */
  243. offset = pim_parse_addr_ucast(ifp->name, src_addr,
  244. &msg_source_addr,
  245. curr, curr_size);
  246. if (offset < 1) {
  247. char src_str[100];
  248. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  249. zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
  250. __PRETTY_FUNCTION__,
  251. src_str, ifp->name);
  252. return -2;
  253. }
  254. curr += offset;
  255. curr_size -= offset;
  256. if (curr_size != 8) {
  257. char src_str[100];
  258. pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  259. zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
  260. __PRETTY_FUNCTION__,
  261. curr_size,
  262. src_str, ifp->name);
  263. return -3;
  264. }
  265. /*
  266. Parse assert metric preference
  267. */
  268. msg_metric.metric_preference = ntohl(*(const uint32_t *) curr);
  269. msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */
  270. msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */
  271. curr += 4;
  272. /*
  273. Parse assert route metric
  274. */
  275. msg_metric.route_metric = ntohl(*(const uint32_t *) curr);
  276. if (PIM_DEBUG_PIM_TRACE) {
  277. char neigh_str[100];
  278. char source_str[100];
  279. char group_str[100];
  280. pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str));
  281. pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str));
  282. pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, group_str, sizeof(group_str));
  283. zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
  284. __PRETTY_FUNCTION__, neigh_str, ifp->name,
  285. source_str, group_str,
  286. msg_metric.metric_preference,
  287. msg_metric.route_metric,
  288. PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag));
  289. }
  290. msg_metric.ip_address = src_addr;
  291. return dispatch_assert(ifp,
  292. msg_source_addr.u.prefix4,
  293. msg_group_addr.u.prefix4,
  294. msg_metric);
  295. }
  296. /*
  297. RFC 4601: 4.6.3. Assert Metrics
  298. Assert metrics are defined as:
  299. When comparing assert_metrics, the rpt_bit_flag, metric_preference,
  300. and route_metric field are compared in order, where the first lower
  301. value wins. If all fields are equal, the primary IP address of the
  302. router that sourced the Assert message is used as a tie-breaker,
  303. with the highest IP address winning.
  304. */
  305. int pim_assert_metric_better(const struct pim_assert_metric *m1,
  306. const struct pim_assert_metric *m2)
  307. {
  308. if (m1->rpt_bit_flag < m2->rpt_bit_flag)
  309. return 1;
  310. if (m1->rpt_bit_flag > m2->rpt_bit_flag)
  311. return 0;
  312. if (m1->metric_preference < m2->metric_preference)
  313. return 1;
  314. if (m1->metric_preference > m2->metric_preference)
  315. return 0;
  316. if (m1->route_metric < m2->route_metric)
  317. return 1;
  318. if (m1->route_metric > m2->route_metric)
  319. return 0;
  320. return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr);
  321. }
  322. int pim_assert_metric_match(const struct pim_assert_metric *m1,
  323. const struct pim_assert_metric *m2)
  324. {
  325. if (m1->rpt_bit_flag != m2->rpt_bit_flag)
  326. return 0;
  327. if (m1->metric_preference != m2->metric_preference)
  328. return 0;
  329. if (m1->route_metric != m2->route_metric)
  330. return 0;
  331. return m1->ip_address.s_addr == m2->ip_address.s_addr;
  332. }
  333. int pim_assert_build_msg(char *pim_msg, int buf_size,
  334. struct interface *ifp,
  335. struct in_addr group_addr,
  336. struct in_addr source_addr,
  337. uint32_t metric_preference,
  338. uint32_t route_metric,
  339. uint32_t rpt_bit_flag)
  340. {
  341. char *buf_pastend = pim_msg + buf_size;
  342. char *pim_msg_curr;
  343. int pim_msg_size;
  344. int remain;
  345. pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
  346. /* Encode group */
  347. remain = buf_pastend - pim_msg_curr;
  348. pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
  349. remain,
  350. group_addr);
  351. if (!pim_msg_curr) {
  352. char group_str[100];
  353. pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  354. zlog_warn("%s: failure encoding group address %s: space left=%d",
  355. __PRETTY_FUNCTION__, group_str, remain);
  356. return -1;
  357. }
  358. /* Encode source */
  359. remain = buf_pastend - pim_msg_curr;
  360. pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
  361. remain,
  362. source_addr);
  363. if (!pim_msg_curr) {
  364. char source_str[100];
  365. pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  366. zlog_warn("%s: failure encoding source address %s: space left=%d",
  367. __PRETTY_FUNCTION__, source_str, remain);
  368. return -2;
  369. }
  370. /* Metric preference */
  371. *((uint32_t *) pim_msg_curr) = htonl(rpt_bit_flag ?
  372. metric_preference | 0x80000000 :
  373. metric_preference);
  374. pim_msg_curr += 4;
  375. /* Route metric */
  376. *((uint32_t *) pim_msg_curr) = htonl(route_metric);
  377. pim_msg_curr += 4;
  378. /*
  379. Add PIM header
  380. */
  381. pim_msg_size = pim_msg_curr - pim_msg;
  382. pim_msg_build_header(pim_msg, pim_msg_size,
  383. PIM_MSG_TYPE_ASSERT);
  384. return pim_msg_size;
  385. }
  386. static int pim_assert_do(struct pim_ifchannel *ch,
  387. struct pim_assert_metric metric)
  388. {
  389. struct interface *ifp;
  390. struct pim_interface *pim_ifp;
  391. char pim_msg[1000];
  392. int pim_msg_size;
  393. ifp = ch->interface;
  394. zassert(ifp);
  395. pim_ifp = ifp->info;
  396. if (!pim_ifp) {
  397. zlog_warn("%s: pim not enabled on interface: %s",
  398. __PRETTY_FUNCTION__, ifp->name);
  399. return -1;
  400. }
  401. pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
  402. ch->group_addr, ch->source_addr,
  403. metric.metric_preference,
  404. metric.route_metric,
  405. metric.rpt_bit_flag);
  406. if (pim_msg_size < 1) {
  407. zlog_warn("%s: failure building PIM assert message: msg_size=%d",
  408. __PRETTY_FUNCTION__, pim_msg_size);
  409. return -2;
  410. }
  411. /*
  412. RFC 4601: 4.3.1. Sending Hello Messages
  413. Thus, if a router needs to send a Join/Prune or Assert message on
  414. an interface on which it has not yet sent a Hello message with the
  415. currently configured IP address, then it MUST immediately send the
  416. relevant Hello message without waiting for the Hello Timer to
  417. expire, followed by the Join/Prune or Assert message.
  418. */
  419. pim_hello_require(ifp);
  420. if (PIM_DEBUG_PIM_TRACE) {
  421. char source_str[100];
  422. char group_str[100];
  423. pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
  424. pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
  425. zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
  426. __PRETTY_FUNCTION__,
  427. ifp->name, source_str, group_str,
  428. metric.metric_preference,
  429. metric.route_metric,
  430. PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
  431. }
  432. if (pim_msg_send(pim_ifp->pim_sock_fd,
  433. qpim_all_pim_routers_addr,
  434. pim_msg,
  435. pim_msg_size,
  436. ifp->name)) {
  437. zlog_warn("%s: could not send PIM message on interface %s",
  438. __PRETTY_FUNCTION__, ifp->name);
  439. return -3;
  440. }
  441. return 0;
  442. }
  443. int pim_assert_send(struct pim_ifchannel *ch)
  444. {
  445. return pim_assert_do(ch, ch->ifassert_my_metric);
  446. }
  447. /*
  448. RFC 4601: 4.6.4. AssertCancel Messages
  449. An AssertCancel(S,G) is an infinite metric assert with the RPT bit
  450. set that names S as the source.
  451. */
  452. static int pim_assert_cancel(struct pim_ifchannel *ch)
  453. {
  454. struct pim_assert_metric metric;
  455. metric.rpt_bit_flag = 0;
  456. metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
  457. metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
  458. metric.ip_address = ch->source_addr;
  459. return pim_assert_do(ch, metric);
  460. }
  461. static int on_assert_timer(struct thread *t)
  462. {
  463. struct pim_ifchannel *ch;
  464. struct interface *ifp;
  465. zassert(t);
  466. ch = THREAD_ARG(t);
  467. zassert(ch);
  468. ifp = ch->interface;
  469. zassert(ifp);
  470. if (PIM_DEBUG_PIM_TRACE) {
  471. char src_str[100];
  472. char grp_str[100];
  473. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  474. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  475. zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s",
  476. __PRETTY_FUNCTION__,
  477. src_str, grp_str, ifp->name);
  478. }
  479. ch->t_ifassert_timer = 0;
  480. switch (ch->ifassert_state) {
  481. case PIM_IFASSERT_I_AM_WINNER:
  482. zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
  483. assert_action_a3(ch);
  484. break;
  485. case PIM_IFASSERT_I_AM_LOSER:
  486. assert_action_a5(ch);
  487. break;
  488. default:
  489. {
  490. char source_str[100];
  491. char group_str[100];
  492. pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
  493. pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
  494. zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
  495. __PRETTY_FUNCTION__,
  496. source_str, group_str, ch->ifassert_state, ifp->name);
  497. }
  498. }
  499. return 0;
  500. }
  501. static void assert_timer_off(struct pim_ifchannel *ch)
  502. {
  503. struct interface *ifp;
  504. zassert(ch);
  505. ifp = ch->interface;
  506. zassert(ifp);
  507. if (PIM_DEBUG_PIM_TRACE) {
  508. if (ch->t_ifassert_timer) {
  509. char src_str[100];
  510. char grp_str[100];
  511. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  512. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  513. zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
  514. __PRETTY_FUNCTION__,
  515. src_str, grp_str, ifp->name);
  516. }
  517. }
  518. THREAD_OFF(ch->t_ifassert_timer);
  519. zassert(!ch->t_ifassert_timer);
  520. }
  521. static void pim_assert_timer_set(struct pim_ifchannel *ch,
  522. int interval)
  523. {
  524. struct interface *ifp;
  525. zassert(ch);
  526. ifp = ch->interface;
  527. zassert(ifp);
  528. assert_timer_off(ch);
  529. if (PIM_DEBUG_PIM_TRACE) {
  530. char src_str[100];
  531. char grp_str[100];
  532. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  533. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  534. zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
  535. __PRETTY_FUNCTION__,
  536. src_str, grp_str, interval, ifp->name);
  537. }
  538. THREAD_TIMER_ON(master, ch->t_ifassert_timer,
  539. on_assert_timer,
  540. ch, interval);
  541. }
  542. static void pim_assert_timer_reset(struct pim_ifchannel *ch)
  543. {
  544. pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
  545. }
  546. /*
  547. RFC 4601: 4.6.1. (S,G) Assert Message State Machine
  548. (S,G) Assert State machine Actions
  549. A1: Send Assert(S,G).
  550. Set Assert Timer to (Assert_Time - Assert_Override_Interval).
  551. Store self as AssertWinner(S,G,I).
  552. Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
  553. */
  554. int assert_action_a1(struct pim_ifchannel *ch)
  555. {
  556. struct interface *ifp = ch->interface;
  557. struct pim_interface *pim_ifp;
  558. zassert(ifp);
  559. pim_ifp = ifp->info;
  560. if (!pim_ifp) {
  561. char src_str[100];
  562. char grp_str[100];
  563. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  564. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  565. zlog_warn("%s: (S,G)=(%s,%s) multicast no enabled on interface %s",
  566. __PRETTY_FUNCTION__,
  567. src_str, grp_str, ifp->name);
  568. return -1; /* must return since pim_ifp is used below */
  569. }
  570. /* Switch to I_AM_WINNER before performing action_a3 below */
  571. pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER,
  572. pim_ifp->primary_address,
  573. pim_macro_spt_assert_metric(&ch->upstream->rpf,
  574. pim_ifp->primary_address));
  575. zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
  576. if (assert_action_a3(ch)) {
  577. char src_str[100];
  578. char grp_str[100];
  579. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  580. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  581. zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
  582. __PRETTY_FUNCTION__,
  583. src_str, grp_str, ifp->name);
  584. /* warning only */
  585. }
  586. zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
  587. return 0;
  588. }
  589. /*
  590. RFC 4601: 4.6.1. (S,G) Assert Message State Machine
  591. (S,G) Assert State machine Actions
  592. A2: Store new assert winner as AssertWinner(S,G,I) and assert
  593. winner metric as AssertWinnerMetric(S,G,I).
  594. Set Assert Timer to Assert_Time.
  595. */
  596. static void assert_action_a2(struct pim_ifchannel *ch,
  597. struct pim_assert_metric winner_metric)
  598. {
  599. pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
  600. winner_metric.ip_address,
  601. winner_metric);
  602. pim_assert_timer_set(ch, PIM_ASSERT_TIME);
  603. zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
  604. }
  605. /*
  606. RFC 4601: 4.6.1. (S,G) Assert Message State Machine
  607. (S,G) Assert State machine Actions
  608. A3: Send Assert(S,G).
  609. Set Assert Timer to (Assert_Time - Assert_Override_Interval).
  610. */
  611. static int assert_action_a3(struct pim_ifchannel *ch)
  612. {
  613. zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
  614. pim_assert_timer_reset(ch);
  615. if (pim_assert_send(ch)) {
  616. char src_str[100];
  617. char grp_str[100];
  618. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  619. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  620. zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
  621. __PRETTY_FUNCTION__,
  622. src_str, grp_str, ch->interface->name);
  623. return -1;
  624. }
  625. zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
  626. return 0;
  627. }
  628. /*
  629. RFC 4601: 4.6.1. (S,G) Assert Message State Machine
  630. (S,G) Assert State machine Actions
  631. A4: Send AssertCancel(S,G).
  632. Delete assert info (AssertWinner(S,G,I) and
  633. AssertWinnerMetric(S,G,I) will then return their default
  634. values).
  635. */
  636. void assert_action_a4(struct pim_ifchannel *ch)
  637. {
  638. if (pim_assert_cancel(ch)) {
  639. char src_str[100];
  640. char grp_str[100];
  641. pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
  642. pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
  643. zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
  644. __PRETTY_FUNCTION__,
  645. src_str, grp_str, ch->interface->name);
  646. /* log warning only */
  647. }
  648. assert_action_a5(ch);
  649. zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
  650. }
  651. /*
  652. RFC 4601: 4.6.1. (S,G) Assert Message State Machine
  653. (S,G) Assert State machine Actions
  654. A5: Delete assert info (AssertWinner(S,G,I) and
  655. AssertWinnerMetric(S,G,I) will then return their default values).
  656. */
  657. void assert_action_a5(struct pim_ifchannel *ch)
  658. {
  659. reset_ifassert_state(ch);
  660. zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
  661. }
  662. /*
  663. RFC 4601: 4.6.1. (S,G) Assert Message State Machine
  664. (S,G) Assert State machine Actions
  665. A6: Store new assert winner as AssertWinner(S,G,I) and assert
  666. winner metric as AssertWinnerMetric(S,G,I).
  667. Set Assert Timer to Assert_Time.
  668. If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
  669. set SPTbit(S,G) to TRUE.
  670. */
  671. static void assert_action_a6(struct pim_ifchannel *ch,
  672. struct pim_assert_metric winner_metric)
  673. {
  674. assert_action_a2(ch, winner_metric);
  675. /*
  676. If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
  677. SPTbit(S,G) to TRUE.
  678. Notice: For PIM SSM, SPTbit(S,G) is already always true.
  679. */
  680. zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
  681. }