File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_assert.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (8 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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>