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