Annotation of embedaddon/quagga/pimd/pim_upstream.c, revision 1.1
1.1 ! misho 1: /*
! 2: PIM for Quagga
! 3: Copyright (C) 2008 Everton da Silva Marques
! 4:
! 5: This program is free software; you can redistribute it and/or modify
! 6: it under the terms of the GNU General Public License as published by
! 7: the Free Software Foundation; either version 2 of the License, or
! 8: (at your option) any later version.
! 9:
! 10: This program is distributed in the hope that it will be useful, but
! 11: WITHOUT ANY WARRANTY; without even the implied warranty of
! 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 13: General Public License for more details.
! 14:
! 15: You should have received a copy of the GNU General Public License
! 16: along with this program; see the file COPYING; if not, write to the
! 17: Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
! 18: MA 02110-1301 USA
! 19:
! 20: $QuaggaId: $Format:%an, %ai, %h$ $
! 21: */
! 22:
! 23: #include <zebra.h>
! 24:
! 25: #include "zebra/rib.h"
! 26:
! 27: #include "log.h"
! 28: #include "zclient.h"
! 29: #include "memory.h"
! 30: #include "thread.h"
! 31: #include "linklist.h"
! 32:
! 33: #include "pimd.h"
! 34: #include "pim_pim.h"
! 35: #include "pim_str.h"
! 36: #include "pim_time.h"
! 37: #include "pim_iface.h"
! 38: #include "pim_join.h"
! 39: #include "pim_zlookup.h"
! 40: #include "pim_upstream.h"
! 41: #include "pim_ifchannel.h"
! 42: #include "pim_neighbor.h"
! 43: #include "pim_rpf.h"
! 44: #include "pim_zebra.h"
! 45: #include "pim_oil.h"
! 46: #include "pim_macro.h"
! 47:
! 48: static void join_timer_start(struct pim_upstream *up);
! 49: static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
! 50:
! 51: void pim_upstream_free(struct pim_upstream *up)
! 52: {
! 53: XFREE(MTYPE_PIM_UPSTREAM, up);
! 54: }
! 55:
! 56: static void upstream_channel_oil_detach(struct pim_upstream *up)
! 57: {
! 58: if (up->channel_oil) {
! 59: pim_channel_oil_del(up->channel_oil);
! 60: up->channel_oil = 0;
! 61: }
! 62: }
! 63:
! 64: void pim_upstream_delete(struct pim_upstream *up)
! 65: {
! 66: THREAD_OFF(up->t_join_timer);
! 67:
! 68: upstream_channel_oil_detach(up);
! 69:
! 70: /*
! 71: notice that listnode_delete() can't be moved
! 72: into pim_upstream_free() because the later is
! 73: called by list_delete_all_node()
! 74: */
! 75: listnode_delete(qpim_upstream_list, up);
! 76:
! 77: pim_upstream_free(up);
! 78: }
! 79:
! 80: static void send_join(struct pim_upstream *up)
! 81: {
! 82: zassert(up->join_state == PIM_UPSTREAM_JOINED);
! 83:
! 84:
! 85: if (PIM_DEBUG_PIM_TRACE) {
! 86: if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
! 87: char src_str[100];
! 88: char grp_str[100];
! 89: char rpf_str[100];
! 90: pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
! 91: pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
! 92: pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
! 93: zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s",
! 94: __PRETTY_FUNCTION__,
! 95: src_str, grp_str, rpf_str);
! 96: /* warning only */
! 97: }
! 98: }
! 99:
! 100: /* send Join(S,G) to the current upstream neighbor */
! 101: pim_joinprune_send(up->rpf.source_nexthop.interface,
! 102: up->rpf.rpf_addr,
! 103: up->source_addr,
! 104: up->group_addr,
! 105: 1 /* join */);
! 106: }
! 107:
! 108: static int on_join_timer(struct thread *t)
! 109: {
! 110: struct pim_upstream *up;
! 111:
! 112: zassert(t);
! 113: up = THREAD_ARG(t);
! 114: zassert(up);
! 115:
! 116: send_join(up);
! 117:
! 118: up->t_join_timer = 0;
! 119: join_timer_start(up);
! 120:
! 121: return 0;
! 122: }
! 123:
! 124: static void join_timer_start(struct pim_upstream *up)
! 125: {
! 126: if (PIM_DEBUG_PIM_EVENTS) {
! 127: char src_str[100];
! 128: char grp_str[100];
! 129: pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
! 130: pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
! 131: zlog_debug("%s: starting %d sec timer for upstream (S,G)=(%s,%s)",
! 132: __PRETTY_FUNCTION__,
! 133: qpim_t_periodic,
! 134: src_str, grp_str);
! 135: }
! 136:
! 137: zassert(!up->t_join_timer);
! 138:
! 139: THREAD_TIMER_ON(master, up->t_join_timer,
! 140: on_join_timer,
! 141: up, qpim_t_periodic);
! 142: }
! 143:
! 144: void pim_upstream_join_timer_restart(struct pim_upstream *up)
! 145: {
! 146: THREAD_OFF(up->t_join_timer);
! 147: join_timer_start(up);
! 148: }
! 149:
! 150: static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
! 151: int interval_msec)
! 152: {
! 153: if (PIM_DEBUG_PIM_EVENTS) {
! 154: char src_str[100];
! 155: char grp_str[100];
! 156: pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
! 157: pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
! 158: zlog_debug("%s: restarting %d msec timer for upstream (S,G)=(%s,%s)",
! 159: __PRETTY_FUNCTION__,
! 160: interval_msec,
! 161: src_str, grp_str);
! 162: }
! 163:
! 164: THREAD_OFF(up->t_join_timer);
! 165: THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
! 166: on_join_timer,
! 167: up, interval_msec);
! 168: }
! 169:
! 170: void pim_upstream_join_suppress(struct pim_upstream *up,
! 171: struct in_addr rpf_addr,
! 172: int holdtime)
! 173: {
! 174: long t_joinsuppress_msec;
! 175: long join_timer_remain_msec;
! 176:
! 177: t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
! 178: 1000 * holdtime);
! 179:
! 180: join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
! 181:
! 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 %s: detected Join(%s,%s) to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
! 190: __FILE__, __PRETTY_FUNCTION__,
! 191: src_str, grp_str,
! 192: rpf_str,
! 193: join_timer_remain_msec, t_joinsuppress_msec);
! 194: }
! 195:
! 196: if (join_timer_remain_msec < t_joinsuppress_msec) {
! 197: if (PIM_DEBUG_PIM_TRACE) {
! 198: char src_str[100];
! 199: char grp_str[100];
! 200: pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
! 201: pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
! 202: zlog_debug("%s %s: suppressing Join(S,G)=(%s,%s) for %ld msec",
! 203: __FILE__, __PRETTY_FUNCTION__,
! 204: src_str, grp_str, t_joinsuppress_msec);
! 205: }
! 206:
! 207: pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
! 208: }
! 209: }
! 210:
! 211: void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
! 212: struct pim_upstream *up,
! 213: struct in_addr rpf_addr)
! 214: {
! 215: long join_timer_remain_msec;
! 216: int t_override_msec;
! 217:
! 218: join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
! 219: t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
! 220:
! 221: if (PIM_DEBUG_PIM_TRACE) {
! 222: char src_str[100];
! 223: char grp_str[100];
! 224: char rpf_str[100];
! 225: pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
! 226: pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
! 227: pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
! 228: zlog_debug("%s: to RPF'(%s,%s)=%s: join_timer=%ld msec t_override=%d msec",
! 229: debug_label,
! 230: src_str, grp_str, rpf_str,
! 231: join_timer_remain_msec, t_override_msec);
! 232: }
! 233:
! 234: if (join_timer_remain_msec > t_override_msec) {
! 235: if (PIM_DEBUG_PIM_TRACE) {
! 236: char src_str[100];
! 237: char grp_str[100];
! 238: pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
! 239: pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
! 240: zlog_debug("%s: decreasing (S,G)=(%s,%s) join timer to t_override=%d msec",
! 241: debug_label,
! 242: src_str, grp_str,
! 243: t_override_msec);
! 244: }
! 245:
! 246: pim_upstream_join_timer_restart_msec(up, t_override_msec);
! 247: }
! 248: }
! 249:
! 250: static void forward_on(struct pim_upstream *up)
! 251: {
! 252: struct listnode *ifnode;
! 253: struct listnode *ifnextnode;
! 254: struct listnode *chnode;
! 255: struct listnode *chnextnode;
! 256: struct interface *ifp;
! 257: struct pim_interface *pim_ifp;
! 258: struct pim_ifchannel *ch;
! 259:
! 260: /* scan all interfaces */
! 261: for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
! 262: pim_ifp = ifp->info;
! 263: if (!pim_ifp)
! 264: continue;
! 265:
! 266: /* scan per-interface (S,G) state */
! 267: for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
! 268:
! 269: if (ch->upstream != up)
! 270: continue;
! 271:
! 272: if (pim_macro_chisin_oiflist(ch))
! 273: pim_forward_start(ch);
! 274:
! 275: } /* scan iface channel list */
! 276: } /* scan iflist */
! 277: }
! 278:
! 279: static void forward_off(struct pim_upstream *up)
! 280: {
! 281: struct listnode *ifnode;
! 282: struct listnode *ifnextnode;
! 283: struct listnode *chnode;
! 284: struct listnode *chnextnode;
! 285: struct interface *ifp;
! 286: struct pim_interface *pim_ifp;
! 287: struct pim_ifchannel *ch;
! 288:
! 289: /* scan all interfaces */
! 290: for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
! 291: pim_ifp = ifp->info;
! 292: if (!pim_ifp)
! 293: continue;
! 294:
! 295: /* scan per-interface (S,G) state */
! 296: for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
! 297:
! 298: if (ch->upstream != up)
! 299: continue;
! 300:
! 301: pim_forward_stop(ch);
! 302:
! 303: } /* scan iface channel list */
! 304: } /* scan iflist */
! 305: }
! 306:
! 307: static void pim_upstream_switch(struct pim_upstream *up,
! 308: enum pim_upstream_state new_state)
! 309: {
! 310: enum pim_upstream_state old_state = up->join_state;
! 311:
! 312: zassert(old_state != new_state);
! 313:
! 314: up->join_state = new_state;
! 315: up->state_transition = pim_time_monotonic_sec();
! 316:
! 317: if (PIM_DEBUG_PIM_EVENTS) {
! 318: char src_str[100];
! 319: char grp_str[100];
! 320: pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
! 321: pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
! 322: zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)",
! 323: __PRETTY_FUNCTION__,
! 324: ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"),
! 325: src_str, grp_str);
! 326: }
! 327:
! 328: pim_upstream_update_assert_tracking_desired(up);
! 329:
! 330: if (new_state == PIM_UPSTREAM_JOINED) {
! 331: forward_on(up);
! 332: send_join(up);
! 333: join_timer_start(up);
! 334: }
! 335: else {
! 336: forward_off(up);
! 337: pim_joinprune_send(up->rpf.source_nexthop.interface,
! 338: up->rpf.rpf_addr,
! 339: up->source_addr,
! 340: up->group_addr,
! 341: 0 /* prune */);
! 342: zassert(up->t_join_timer);
! 343: THREAD_OFF(up->t_join_timer);
! 344: }
! 345:
! 346: }
! 347:
! 348: static struct pim_upstream *pim_upstream_new(struct in_addr source_addr,
! 349: struct in_addr group_addr)
! 350: {
! 351: struct pim_upstream *up;
! 352: enum pim_rpf_result rpf_result;
! 353:
! 354: up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
! 355: if (!up) {
! 356: zlog_err("%s: PIM XMALLOC(%zu) failure",
! 357: __PRETTY_FUNCTION__, sizeof(*up));
! 358: return 0;
! 359: }
! 360:
! 361: up->source_addr = source_addr;
! 362: up->group_addr = group_addr;
! 363: up->flags = 0;
! 364: up->ref_count = 1;
! 365: up->t_join_timer = 0;
! 366: up->join_state = 0;
! 367: up->state_transition = pim_time_monotonic_sec();
! 368: up->channel_oil = 0;
! 369:
! 370: up->rpf.source_nexthop.interface = 0;
! 371: up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
! 372: up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
! 373: up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
! 374: up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY;
! 375:
! 376: rpf_result = pim_rpf_update(up, 0);
! 377: if (rpf_result == PIM_RPF_FAILURE) {
! 378: XFREE(MTYPE_PIM_UPSTREAM, up);
! 379: return NULL;
! 380: }
! 381:
! 382: listnode_add(qpim_upstream_list, up);
! 383:
! 384: return up;
! 385: }
! 386:
! 387: struct pim_upstream *pim_upstream_find(struct in_addr source_addr,
! 388: struct in_addr group_addr)
! 389: {
! 390: struct listnode *up_node;
! 391: struct pim_upstream *up;
! 392:
! 393: for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
! 394: if (
! 395: (source_addr.s_addr == up->source_addr.s_addr) &&
! 396: (group_addr.s_addr == up->group_addr.s_addr)
! 397: ) {
! 398: return up;
! 399: }
! 400: }
! 401:
! 402: return 0;
! 403: }
! 404:
! 405: struct pim_upstream *pim_upstream_add(struct in_addr source_addr,
! 406: struct in_addr group_addr)
! 407: {
! 408: struct pim_upstream *up;
! 409:
! 410: up = pim_upstream_find(source_addr, group_addr);
! 411: if (up) {
! 412: ++up->ref_count;
! 413: }
! 414: else {
! 415: up = pim_upstream_new(source_addr, group_addr);
! 416: }
! 417:
! 418: return up;
! 419: }
! 420:
! 421: void pim_upstream_del(struct pim_upstream *up)
! 422: {
! 423: --up->ref_count;
! 424:
! 425: if (up->ref_count < 1) {
! 426: pim_upstream_delete(up);
! 427: }
! 428: }
! 429:
! 430: /*
! 431: Evaluate JoinDesired(S,G):
! 432:
! 433: JoinDesired(S,G) is true if there is a downstream (S,G) interface I
! 434: in the set:
! 435:
! 436: inherited_olist(S,G) =
! 437: joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
! 438:
! 439: JoinDesired(S,G) may be affected by changes in the following:
! 440:
! 441: pim_ifp->primary_address
! 442: pim_ifp->pim_dr_addr
! 443: ch->ifassert_winner_metric
! 444: ch->ifassert_winner
! 445: ch->local_ifmembership
! 446: ch->ifjoin_state
! 447: ch->upstream->rpf.source_nexthop.mrib_metric_preference
! 448: ch->upstream->rpf.source_nexthop.mrib_route_metric
! 449: ch->upstream->rpf.source_nexthop.interface
! 450:
! 451: See also pim_upstream_update_join_desired() below.
! 452: */
! 453: int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
! 454: {
! 455: struct listnode *ifnode;
! 456: struct listnode *ifnextnode;
! 457: struct listnode *chnode;
! 458: struct listnode *chnextnode;
! 459: struct interface *ifp;
! 460: struct pim_interface *pim_ifp;
! 461: struct pim_ifchannel *ch;
! 462:
! 463: /* scan all interfaces */
! 464: for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
! 465: pim_ifp = ifp->info;
! 466: if (!pim_ifp)
! 467: continue;
! 468:
! 469: /* scan per-interface (S,G) state */
! 470: for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
! 471: if (ch->upstream != up)
! 472: continue;
! 473:
! 474: if (pim_macro_ch_lost_assert(ch))
! 475: continue; /* keep searching */
! 476:
! 477: if (pim_macro_chisin_joins_or_include(ch))
! 478: return 1; /* true */
! 479: } /* scan iface channel list */
! 480: } /* scan iflist */
! 481:
! 482: return 0; /* false */
! 483: }
! 484:
! 485: /*
! 486: See also pim_upstream_evaluate_join_desired() above.
! 487: */
! 488: void pim_upstream_update_join_desired(struct pim_upstream *up)
! 489: {
! 490: int was_join_desired; /* boolean */
! 491: int is_join_desired; /* boolean */
! 492:
! 493: was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
! 494:
! 495: is_join_desired = pim_upstream_evaluate_join_desired(up);
! 496: if (is_join_desired)
! 497: PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
! 498: else
! 499: PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
! 500:
! 501: /* switched from false to true */
! 502: if (is_join_desired && !was_join_desired) {
! 503: zassert(up->join_state == PIM_UPSTREAM_NOTJOINED);
! 504: pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
! 505: return;
! 506: }
! 507:
! 508: /* switched from true to false */
! 509: if (!is_join_desired && was_join_desired) {
! 510: zassert(up->join_state == PIM_UPSTREAM_JOINED);
! 511: pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
! 512: return;
! 513: }
! 514: }
! 515:
! 516: /*
! 517: RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
! 518: Transitions from Joined State
! 519: RPF'(S,G) GenID changes
! 520:
! 521: The upstream (S,G) state machine remains in Joined state. If the
! 522: Join Timer is set to expire in more than t_override seconds, reset
! 523: it so that it expires after t_override seconds.
! 524: */
! 525: void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
! 526: {
! 527: struct listnode *up_node;
! 528: struct listnode *up_nextnode;
! 529: struct pim_upstream *up;
! 530:
! 531: /*
! 532: Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
! 533: */
! 534: for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
! 535:
! 536: if (PIM_DEBUG_PIM_TRACE) {
! 537: char neigh_str[100];
! 538: char src_str[100];
! 539: char grp_str[100];
! 540: char rpf_addr_str[100];
! 541: pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
! 542: pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
! 543: pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
! 544: pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
! 545: zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s",
! 546: __PRETTY_FUNCTION__,
! 547: neigh_str, src_str, grp_str,
! 548: up->join_state == PIM_UPSTREAM_JOINED,
! 549: rpf_addr_str);
! 550: }
! 551:
! 552: /* consider only (S,G) upstream in Joined state */
! 553: if (up->join_state != PIM_UPSTREAM_JOINED)
! 554: continue;
! 555:
! 556: /* match RPF'(S,G)=neigh_addr */
! 557: if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr)
! 558: continue;
! 559:
! 560: pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
! 561: up, neigh_addr);
! 562: }
! 563: }
! 564:
! 565:
! 566: void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
! 567: struct interface *old_rpf_ifp)
! 568: {
! 569: struct listnode *ifnode;
! 570: struct listnode *ifnextnode;
! 571: struct interface *ifp;
! 572:
! 573: /* scan all interfaces */
! 574: for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
! 575: struct listnode *chnode;
! 576: struct listnode *chnextnode;
! 577: struct pim_ifchannel *ch;
! 578: struct pim_interface *pim_ifp;
! 579:
! 580: pim_ifp = ifp->info;
! 581: if (!pim_ifp)
! 582: continue;
! 583:
! 584: /* search all ifchannels */
! 585: for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
! 586: if (ch->upstream != up)
! 587: continue;
! 588:
! 589: if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
! 590: if (
! 591: /* RPF_interface(S) was NOT I */
! 592: (old_rpf_ifp == ch->interface)
! 593: &&
! 594: /* RPF_interface(S) stopped being I */
! 595: (ch->upstream->rpf.source_nexthop.interface != ch->interface)
! 596: ) {
! 597: assert_action_a5(ch);
! 598: }
! 599: } /* PIM_IFASSERT_I_AM_LOSER */
! 600:
! 601: pim_ifchannel_update_assert_tracking_desired(ch);
! 602: }
! 603: }
! 604: }
! 605:
! 606: void pim_upstream_update_could_assert(struct pim_upstream *up)
! 607: {
! 608: struct listnode *ifnode;
! 609: struct listnode *ifnextnode;
! 610: struct listnode *chnode;
! 611: struct listnode *chnextnode;
! 612: struct interface *ifp;
! 613: struct pim_interface *pim_ifp;
! 614: struct pim_ifchannel *ch;
! 615:
! 616: /* scan all interfaces */
! 617: for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
! 618: pim_ifp = ifp->info;
! 619: if (!pim_ifp)
! 620: continue;
! 621:
! 622: /* scan per-interface (S,G) state */
! 623: for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
! 624:
! 625: if (ch->upstream != up)
! 626: continue;
! 627:
! 628: pim_ifchannel_update_could_assert(ch);
! 629:
! 630: } /* scan iface channel list */
! 631: } /* scan iflist */
! 632: }
! 633:
! 634: void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
! 635: {
! 636: struct listnode *ifnode;
! 637: struct listnode *ifnextnode;
! 638: struct listnode *chnode;
! 639: struct listnode *chnextnode;
! 640: struct interface *ifp;
! 641: struct pim_interface *pim_ifp;
! 642: struct pim_ifchannel *ch;
! 643:
! 644: /* scan all interfaces */
! 645: for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
! 646: pim_ifp = ifp->info;
! 647: if (!pim_ifp)
! 648: continue;
! 649:
! 650: /* scan per-interface (S,G) state */
! 651: for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
! 652:
! 653: if (ch->upstream != up)
! 654: continue;
! 655:
! 656: pim_ifchannel_update_my_assert_metric(ch);
! 657:
! 658: } /* scan iface channel list */
! 659: } /* scan iflist */
! 660: }
! 661:
! 662: static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
! 663: {
! 664: struct listnode *ifnode;
! 665: struct listnode *ifnextnode;
! 666: struct listnode *chnode;
! 667: struct listnode *chnextnode;
! 668: struct interface *ifp;
! 669: struct pim_interface *pim_ifp;
! 670: struct pim_ifchannel *ch;
! 671:
! 672: /* scan all interfaces */
! 673: for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
! 674: pim_ifp = ifp->info;
! 675: if (!pim_ifp)
! 676: continue;
! 677:
! 678: /* scan per-interface (S,G) state */
! 679: for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
! 680:
! 681: if (ch->upstream != up)
! 682: continue;
! 683:
! 684: pim_ifchannel_update_assert_tracking_desired(ch);
! 685:
! 686: } /* scan iface channel list */
! 687: } /* scan iflist */
! 688: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>