pim_upstream.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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 "zclient.h"
  22. #include "memory.h"
  23. #include "thread.h"
  24. #include "linklist.h"
  25. #include "pimd.h"
  26. #include "pim_pim.h"
  27. #include "pim_str.h"
  28. #include "pim_time.h"
  29. #include "pim_iface.h"
  30. #include "pim_join.h"
  31. #include "pim_zlookup.h"
  32. #include "pim_upstream.h"
  33. #include "pim_ifchannel.h"
  34. #include "pim_neighbor.h"
  35. #include "pim_rpf.h"
  36. #include "pim_zebra.h"
  37. #include "pim_oil.h"
  38. #include "pim_macro.h"
  39. static void join_timer_start(struct pim_upstream *up);
  40. static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
  41. void pim_upstream_free(struct pim_upstream *up)
  42. {
  43. XFREE(MTYPE_PIM_UPSTREAM, up);
  44. }
  45. static void upstream_channel_oil_detach(struct pim_upstream *up)
  46. {
  47. if (up->channel_oil) {
  48. pim_channel_oil_del(up->channel_oil);
  49. up->channel_oil = 0;
  50. }
  51. }
  52. void pim_upstream_delete(struct pim_upstream *up)
  53. {
  54. THREAD_OFF(up->t_join_timer);
  55. upstream_channel_oil_detach(up);
  56. /*
  57. notice that listnode_delete() can't be moved
  58. into pim_upstream_free() because the later is
  59. called by list_delete_all_node()
  60. */
  61. listnode_delete(qpim_upstream_list, up);
  62. pim_upstream_free(up);
  63. }
  64. static void send_join(struct pim_upstream *up)
  65. {
  66. zassert(up->join_state == PIM_UPSTREAM_JOINED);
  67. if (PIM_DEBUG_PIM_TRACE) {
  68. if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
  69. char src_str[100];
  70. char grp_str[100];
  71. char rpf_str[100];
  72. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  73. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  74. pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
  75. zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s",
  76. __PRETTY_FUNCTION__,
  77. src_str, grp_str, rpf_str);
  78. /* warning only */
  79. }
  80. }
  81. /* send Join(S,G) to the current upstream neighbor */
  82. pim_joinprune_send(up->rpf.source_nexthop.interface,
  83. up->rpf.rpf_addr,
  84. up->source_addr,
  85. up->group_addr,
  86. 1 /* join */);
  87. }
  88. static int on_join_timer(struct thread *t)
  89. {
  90. struct pim_upstream *up;
  91. zassert(t);
  92. up = THREAD_ARG(t);
  93. zassert(up);
  94. send_join(up);
  95. up->t_join_timer = 0;
  96. join_timer_start(up);
  97. return 0;
  98. }
  99. static void join_timer_start(struct pim_upstream *up)
  100. {
  101. if (PIM_DEBUG_PIM_EVENTS) {
  102. char src_str[100];
  103. char grp_str[100];
  104. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  105. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  106. zlog_debug("%s: starting %d sec timer for upstream (S,G)=(%s,%s)",
  107. __PRETTY_FUNCTION__,
  108. qpim_t_periodic,
  109. src_str, grp_str);
  110. }
  111. zassert(!up->t_join_timer);
  112. THREAD_TIMER_ON(master, up->t_join_timer,
  113. on_join_timer,
  114. up, qpim_t_periodic);
  115. }
  116. void pim_upstream_join_timer_restart(struct pim_upstream *up)
  117. {
  118. THREAD_OFF(up->t_join_timer);
  119. join_timer_start(up);
  120. }
  121. static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
  122. int interval_msec)
  123. {
  124. if (PIM_DEBUG_PIM_EVENTS) {
  125. char src_str[100];
  126. char grp_str[100];
  127. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  128. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  129. zlog_debug("%s: restarting %d msec timer for upstream (S,G)=(%s,%s)",
  130. __PRETTY_FUNCTION__,
  131. interval_msec,
  132. src_str, grp_str);
  133. }
  134. THREAD_OFF(up->t_join_timer);
  135. THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
  136. on_join_timer,
  137. up, interval_msec);
  138. }
  139. void pim_upstream_join_suppress(struct pim_upstream *up,
  140. struct in_addr rpf_addr,
  141. int holdtime)
  142. {
  143. long t_joinsuppress_msec;
  144. long join_timer_remain_msec;
  145. t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
  146. 1000 * holdtime);
  147. join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
  148. if (PIM_DEBUG_PIM_TRACE) {
  149. char src_str[100];
  150. char grp_str[100];
  151. char rpf_str[100];
  152. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  153. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  154. pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
  155. zlog_debug("%s %s: detected Join(%s,%s) to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
  156. __FILE__, __PRETTY_FUNCTION__,
  157. src_str, grp_str,
  158. rpf_str,
  159. join_timer_remain_msec, t_joinsuppress_msec);
  160. }
  161. if (join_timer_remain_msec < t_joinsuppress_msec) {
  162. if (PIM_DEBUG_PIM_TRACE) {
  163. char src_str[100];
  164. char grp_str[100];
  165. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  166. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  167. zlog_debug("%s %s: suppressing Join(S,G)=(%s,%s) for %ld msec",
  168. __FILE__, __PRETTY_FUNCTION__,
  169. src_str, grp_str, t_joinsuppress_msec);
  170. }
  171. pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
  172. }
  173. }
  174. void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
  175. struct pim_upstream *up,
  176. struct in_addr rpf_addr)
  177. {
  178. long join_timer_remain_msec;
  179. int t_override_msec;
  180. join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
  181. t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
  182. if (PIM_DEBUG_PIM_TRACE) {
  183. char src_str[100];
  184. char grp_str[100];
  185. char rpf_str[100];
  186. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  187. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  188. pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
  189. zlog_debug("%s: to RPF'(%s,%s)=%s: join_timer=%ld msec t_override=%d msec",
  190. debug_label,
  191. src_str, grp_str, rpf_str,
  192. join_timer_remain_msec, t_override_msec);
  193. }
  194. if (join_timer_remain_msec > t_override_msec) {
  195. if (PIM_DEBUG_PIM_TRACE) {
  196. char src_str[100];
  197. char grp_str[100];
  198. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  199. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  200. zlog_debug("%s: decreasing (S,G)=(%s,%s) join timer to t_override=%d msec",
  201. debug_label,
  202. src_str, grp_str,
  203. t_override_msec);
  204. }
  205. pim_upstream_join_timer_restart_msec(up, t_override_msec);
  206. }
  207. }
  208. static void forward_on(struct pim_upstream *up)
  209. {
  210. struct listnode *ifnode;
  211. struct listnode *ifnextnode;
  212. struct listnode *chnode;
  213. struct listnode *chnextnode;
  214. struct interface *ifp;
  215. struct pim_interface *pim_ifp;
  216. struct pim_ifchannel *ch;
  217. /* scan all interfaces */
  218. for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  219. pim_ifp = ifp->info;
  220. if (!pim_ifp)
  221. continue;
  222. /* scan per-interface (S,G) state */
  223. for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  224. if (ch->upstream != up)
  225. continue;
  226. if (pim_macro_chisin_oiflist(ch))
  227. pim_forward_start(ch);
  228. } /* scan iface channel list */
  229. } /* scan iflist */
  230. }
  231. static void forward_off(struct pim_upstream *up)
  232. {
  233. struct listnode *ifnode;
  234. struct listnode *ifnextnode;
  235. struct listnode *chnode;
  236. struct listnode *chnextnode;
  237. struct interface *ifp;
  238. struct pim_interface *pim_ifp;
  239. struct pim_ifchannel *ch;
  240. /* scan all interfaces */
  241. for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  242. pim_ifp = ifp->info;
  243. if (!pim_ifp)
  244. continue;
  245. /* scan per-interface (S,G) state */
  246. for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  247. if (ch->upstream != up)
  248. continue;
  249. pim_forward_stop(ch);
  250. } /* scan iface channel list */
  251. } /* scan iflist */
  252. }
  253. static void pim_upstream_switch(struct pim_upstream *up,
  254. enum pim_upstream_state new_state)
  255. {
  256. enum pim_upstream_state old_state = up->join_state;
  257. zassert(old_state != new_state);
  258. up->join_state = new_state;
  259. up->state_transition = pim_time_monotonic_sec();
  260. if (PIM_DEBUG_PIM_EVENTS) {
  261. char src_str[100];
  262. char grp_str[100];
  263. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  264. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  265. zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)",
  266. __PRETTY_FUNCTION__,
  267. ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"),
  268. src_str, grp_str);
  269. }
  270. pim_upstream_update_assert_tracking_desired(up);
  271. if (new_state == PIM_UPSTREAM_JOINED) {
  272. forward_on(up);
  273. send_join(up);
  274. join_timer_start(up);
  275. }
  276. else {
  277. forward_off(up);
  278. pim_joinprune_send(up->rpf.source_nexthop.interface,
  279. up->rpf.rpf_addr,
  280. up->source_addr,
  281. up->group_addr,
  282. 0 /* prune */);
  283. zassert(up->t_join_timer);
  284. THREAD_OFF(up->t_join_timer);
  285. }
  286. }
  287. static struct pim_upstream *pim_upstream_new(struct in_addr source_addr,
  288. struct in_addr group_addr)
  289. {
  290. struct pim_upstream *up;
  291. up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
  292. if (!up) {
  293. zlog_err("%s: PIM XMALLOC(%zu) failure",
  294. __PRETTY_FUNCTION__, sizeof(*up));
  295. return 0;
  296. }
  297. up->source_addr = source_addr;
  298. up->group_addr = group_addr;
  299. up->flags = 0;
  300. up->ref_count = 1;
  301. up->t_join_timer = 0;
  302. up->join_state = 0;
  303. up->state_transition = pim_time_monotonic_sec();
  304. up->channel_oil = 0;
  305. up->rpf.source_nexthop.interface = 0;
  306. up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
  307. up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
  308. up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
  309. up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY;
  310. pim_rpf_update(up, 0);
  311. listnode_add(qpim_upstream_list, up);
  312. return up;
  313. }
  314. struct pim_upstream *pim_upstream_find(struct in_addr source_addr,
  315. struct in_addr group_addr)
  316. {
  317. struct listnode *up_node;
  318. struct pim_upstream *up;
  319. for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
  320. if (
  321. (source_addr.s_addr == up->source_addr.s_addr) &&
  322. (group_addr.s_addr == up->group_addr.s_addr)
  323. ) {
  324. return up;
  325. }
  326. }
  327. return 0;
  328. }
  329. struct pim_upstream *pim_upstream_add(struct in_addr source_addr,
  330. struct in_addr group_addr)
  331. {
  332. struct pim_upstream *up;
  333. up = pim_upstream_find(source_addr, group_addr);
  334. if (up) {
  335. ++up->ref_count;
  336. }
  337. else {
  338. up = pim_upstream_new(source_addr, group_addr);
  339. }
  340. return up;
  341. }
  342. void pim_upstream_del(struct pim_upstream *up)
  343. {
  344. --up->ref_count;
  345. if (up->ref_count < 1) {
  346. pim_upstream_delete(up);
  347. }
  348. }
  349. /*
  350. Evaluate JoinDesired(S,G):
  351. JoinDesired(S,G) is true if there is a downstream (S,G) interface I
  352. in the set:
  353. inherited_olist(S,G) =
  354. joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
  355. JoinDesired(S,G) may be affected by changes in the following:
  356. pim_ifp->primary_address
  357. pim_ifp->pim_dr_addr
  358. ch->ifassert_winner_metric
  359. ch->ifassert_winner
  360. ch->local_ifmembership
  361. ch->ifjoin_state
  362. ch->upstream->rpf.source_nexthop.mrib_metric_preference
  363. ch->upstream->rpf.source_nexthop.mrib_route_metric
  364. ch->upstream->rpf.source_nexthop.interface
  365. See also pim_upstream_update_join_desired() below.
  366. */
  367. int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
  368. {
  369. struct listnode *ifnode;
  370. struct listnode *ifnextnode;
  371. struct listnode *chnode;
  372. struct listnode *chnextnode;
  373. struct interface *ifp;
  374. struct pim_interface *pim_ifp;
  375. struct pim_ifchannel *ch;
  376. /* scan all interfaces */
  377. for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  378. pim_ifp = ifp->info;
  379. if (!pim_ifp)
  380. continue;
  381. /* scan per-interface (S,G) state */
  382. for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  383. if (ch->upstream != up)
  384. continue;
  385. if (pim_macro_ch_lost_assert(ch))
  386. continue; /* keep searching */
  387. if (pim_macro_chisin_joins_or_include(ch))
  388. return 1; /* true */
  389. } /* scan iface channel list */
  390. } /* scan iflist */
  391. return 0; /* false */
  392. }
  393. /*
  394. See also pim_upstream_evaluate_join_desired() above.
  395. */
  396. void pim_upstream_update_join_desired(struct pim_upstream *up)
  397. {
  398. int was_join_desired; /* boolean */
  399. int is_join_desired; /* boolean */
  400. was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
  401. is_join_desired = pim_upstream_evaluate_join_desired(up);
  402. if (is_join_desired)
  403. PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
  404. else
  405. PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
  406. /* switched from false to true */
  407. if (is_join_desired && !was_join_desired) {
  408. zassert(up->join_state == PIM_UPSTREAM_NOTJOINED);
  409. pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
  410. return;
  411. }
  412. /* switched from true to false */
  413. if (!is_join_desired && was_join_desired) {
  414. zassert(up->join_state == PIM_UPSTREAM_JOINED);
  415. pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
  416. return;
  417. }
  418. }
  419. /*
  420. RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
  421. Transitions from Joined State
  422. RPF'(S,G) GenID changes
  423. The upstream (S,G) state machine remains in Joined state. If the
  424. Join Timer is set to expire in more than t_override seconds, reset
  425. it so that it expires after t_override seconds.
  426. */
  427. void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
  428. {
  429. struct listnode *up_node;
  430. struct listnode *up_nextnode;
  431. struct pim_upstream *up;
  432. /*
  433. Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
  434. */
  435. for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
  436. if (PIM_DEBUG_PIM_TRACE) {
  437. char neigh_str[100];
  438. char src_str[100];
  439. char grp_str[100];
  440. char rpf_addr_str[100];
  441. pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
  442. pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  443. pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  444. pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
  445. zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s",
  446. __PRETTY_FUNCTION__,
  447. neigh_str, src_str, grp_str,
  448. up->join_state == PIM_UPSTREAM_JOINED,
  449. rpf_addr_str);
  450. }
  451. /* consider only (S,G) upstream in Joined state */
  452. if (up->join_state != PIM_UPSTREAM_JOINED)
  453. continue;
  454. /* match RPF'(S,G)=neigh_addr */
  455. if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr)
  456. continue;
  457. pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
  458. up, neigh_addr);
  459. }
  460. }
  461. void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
  462. struct interface *old_rpf_ifp)
  463. {
  464. struct listnode *ifnode;
  465. struct listnode *ifnextnode;
  466. struct interface *ifp;
  467. /* scan all interfaces */
  468. for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  469. struct listnode *chnode;
  470. struct listnode *chnextnode;
  471. struct pim_ifchannel *ch;
  472. struct pim_interface *pim_ifp;
  473. pim_ifp = ifp->info;
  474. if (!pim_ifp)
  475. continue;
  476. /* search all ifchannels */
  477. for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  478. if (ch->upstream != up)
  479. continue;
  480. if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
  481. if (
  482. /* RPF_interface(S) was NOT I */
  483. (old_rpf_ifp == ch->interface)
  484. &&
  485. /* RPF_interface(S) stopped being I */
  486. (ch->upstream->rpf.source_nexthop.interface != ch->interface)
  487. ) {
  488. assert_action_a5(ch);
  489. }
  490. } /* PIM_IFASSERT_I_AM_LOSER */
  491. pim_ifchannel_update_assert_tracking_desired(ch);
  492. }
  493. }
  494. }
  495. void pim_upstream_update_could_assert(struct pim_upstream *up)
  496. {
  497. struct listnode *ifnode;
  498. struct listnode *ifnextnode;
  499. struct listnode *chnode;
  500. struct listnode *chnextnode;
  501. struct interface *ifp;
  502. struct pim_interface *pim_ifp;
  503. struct pim_ifchannel *ch;
  504. /* scan all interfaces */
  505. for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  506. pim_ifp = ifp->info;
  507. if (!pim_ifp)
  508. continue;
  509. /* scan per-interface (S,G) state */
  510. for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  511. if (ch->upstream != up)
  512. continue;
  513. pim_ifchannel_update_could_assert(ch);
  514. } /* scan iface channel list */
  515. } /* scan iflist */
  516. }
  517. void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
  518. {
  519. struct listnode *ifnode;
  520. struct listnode *ifnextnode;
  521. struct listnode *chnode;
  522. struct listnode *chnextnode;
  523. struct interface *ifp;
  524. struct pim_interface *pim_ifp;
  525. struct pim_ifchannel *ch;
  526. /* scan all interfaces */
  527. for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  528. pim_ifp = ifp->info;
  529. if (!pim_ifp)
  530. continue;
  531. /* scan per-interface (S,G) state */
  532. for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  533. if (ch->upstream != up)
  534. continue;
  535. pim_ifchannel_update_my_assert_metric(ch);
  536. } /* scan iface channel list */
  537. } /* scan iflist */
  538. }
  539. static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
  540. {
  541. struct listnode *ifnode;
  542. struct listnode *ifnextnode;
  543. struct listnode *chnode;
  544. struct listnode *chnextnode;
  545. struct interface *ifp;
  546. struct pim_interface *pim_ifp;
  547. struct pim_ifchannel *ch;
  548. /* scan all interfaces */
  549. for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  550. pim_ifp = ifp->info;
  551. if (!pim_ifp)
  552. continue;
  553. /* scan per-interface (S,G) state */
  554. for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  555. if (ch->upstream != up)
  556. continue;
  557. pim_ifchannel_update_assert_tracking_desired(ch);
  558. } /* scan iface channel list */
  559. } /* scan iflist */
  560. }