File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_hello.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 (7 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: 
   27: #include "pimd.h"
   28: #include "pim_pim.h"
   29: #include "pim_str.h"
   30: #include "pim_tlv.h"
   31: #include "pim_util.h"
   32: #include "pim_hello.h"
   33: #include "pim_iface.h"
   34: #include "pim_neighbor.h"
   35: #include "pim_upstream.h"
   36: 
   37: static void on_trace(const char *label,
   38: 		     struct interface *ifp, struct in_addr src)
   39: {
   40:   if (PIM_DEBUG_PIM_TRACE) {
   41:     char src_str[100];
   42:     pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
   43:     zlog_debug("%s: from %s on %s",
   44: 	       label, src_str, ifp->name);
   45:   }
   46: }
   47: 
   48: static void tlv_trace_bool(const char *label, const char *tlv_name,
   49: 			   const char *ifname, struct in_addr src_addr,
   50: 			   int isset, int value)
   51: {
   52:   if (isset) {
   53:     char src_str[100];
   54:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
   55:     zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d",
   56: 	       label, 
   57: 	       src_str, ifname,
   58: 	       tlv_name, value);
   59:   }
   60: }
   61: 
   62: static void tlv_trace_uint16(const char *label, const char *tlv_name,
   63: 			     const char *ifname, struct in_addr src_addr,
   64: 			     int isset, uint16_t value)
   65: {
   66:   if (isset) {
   67:     char src_str[100];
   68:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
   69:     zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
   70: 	       label, 
   71: 	       src_str, ifname,
   72: 	       tlv_name, value);
   73:   }
   74: }
   75: 
   76: static void tlv_trace_uint32(const char *label, const char *tlv_name,
   77: 			     const char *ifname, struct in_addr src_addr,
   78: 			     int isset, uint32_t value)
   79: {
   80:   if (isset) {
   81:     char src_str[100];
   82:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
   83:     zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
   84: 	       label, 
   85: 	       src_str, ifname,
   86: 	       tlv_name, value);
   87:   }
   88: }
   89: 
   90: static void tlv_trace_uint32_hex(const char *label, const char *tlv_name,
   91: 				 const char *ifname, struct in_addr src_addr,
   92: 				 int isset, uint32_t value)
   93: {
   94:   if (isset) {
   95:     char src_str[100];
   96:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
   97:     zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x",
   98: 	       label, 
   99: 	       src_str, ifname,
  100: 	       tlv_name, value);
  101:   }
  102: }
  103: 
  104: #if 0
  105: static void tlv_trace(const char *label, const char *tlv_name,
  106: 		      const char *ifname, struct in_addr src_addr,
  107: 		      int isset)
  108: {
  109:   if (isset) {
  110:     char src_str[100];
  111:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  112:     zlog_debug("%s: PIM hello option from %s on interface %s: %s",
  113: 	       label, 
  114: 	       src_str, ifname,
  115: 	       tlv_name);
  116:   }
  117: }
  118: #endif
  119: 
  120: static void tlv_trace_list(const char *label, const char *tlv_name,
  121: 			   const char *ifname, struct in_addr src_addr,
  122: 			   int isset, struct list *addr_list)
  123: {
  124:   if (isset) {
  125:     char src_str[100];
  126:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  127:     zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p",
  128: 	       label, 
  129: 	       src_str, ifname,
  130: 	       tlv_name,
  131: 	       addr_list ? ((int) listcount(addr_list)) : -1,
  132: 	       (void *) addr_list);
  133:   }
  134: }
  135: 
  136: #define FREE_ADDR_LIST \
  137:   if (hello_option_addr_list) { \
  138:     list_delete(hello_option_addr_list); \
  139:   }
  140: 
  141: #define FREE_ADDR_LIST_THEN_RETURN(code) \
  142: { \
  143:   FREE_ADDR_LIST \
  144:   return (code); \
  145: }
  146: 
  147: int pim_hello_recv(struct interface *ifp,
  148: 		   struct in_addr src_addr,
  149: 		   uint8_t *tlv_buf, int tlv_buf_size)
  150: {
  151:   struct pim_interface *pim_ifp;
  152:   struct pim_neighbor *neigh;
  153:   uint8_t *tlv_curr;
  154:   uint8_t *tlv_pastend;
  155:   pim_hello_options hello_options = 0; /* bit array recording options found */
  156:   uint16_t hello_option_holdtime = 0;
  157:   uint16_t hello_option_propagation_delay = 0;
  158:   uint16_t hello_option_override_interval = 0;
  159:   uint32_t hello_option_dr_priority = 0;
  160:   uint32_t hello_option_generation_id = 0;
  161:   struct list *hello_option_addr_list = 0;
  162: 
  163:   if (PIM_DEBUG_PIM_HELLO)
  164:     on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
  165: 
  166:   pim_ifp = ifp->info;
  167:   zassert(pim_ifp);
  168: 
  169:   ++pim_ifp->pim_ifstat_hello_recv;
  170: 
  171:   /*
  172:     Parse PIM hello TLVs
  173:    */
  174:   zassert(tlv_buf_size >= 0);
  175:   tlv_curr = tlv_buf;
  176:   tlv_pastend = tlv_buf + tlv_buf_size;
  177: 
  178:   while (tlv_curr < tlv_pastend) {
  179:     uint16_t option_type; 
  180:     uint16_t option_len;
  181:     int remain = tlv_pastend - tlv_curr;
  182: 
  183:     if (remain < PIM_TLV_MIN_SIZE) {
  184:       if (PIM_DEBUG_PIM_HELLO) {
  185: 	char src_str[100];
  186: 	pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  187: 	zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s",
  188: 		   __PRETTY_FUNCTION__,
  189: 		   remain, PIM_TLV_MIN_SIZE,
  190: 		   src_str, ifp->name);
  191:       }
  192:       FREE_ADDR_LIST_THEN_RETURN(-1);
  193:     }
  194: 
  195:     option_type = PIM_TLV_GET_TYPE(tlv_curr);
  196:     tlv_curr += PIM_TLV_TYPE_SIZE;
  197:     option_len = PIM_TLV_GET_LENGTH(tlv_curr);
  198:     tlv_curr += PIM_TLV_LENGTH_SIZE;
  199: 
  200:     if ((tlv_curr + option_len) > tlv_pastend) {
  201:       if (PIM_DEBUG_PIM_HELLO) {
  202: 	char src_str[100];
  203: 	pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  204: 	zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s",
  205: 		   __PRETTY_FUNCTION__,
  206: 		   option_type, option_len, tlv_pastend - tlv_curr,
  207: 		   src_str, ifp->name);
  208:       }
  209:       FREE_ADDR_LIST_THEN_RETURN(-2);
  210:     }
  211: 
  212:     if (PIM_DEBUG_PIM_HELLO) {
  213:       char src_str[100];
  214:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  215:       zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s",
  216: 		 __PRETTY_FUNCTION__,
  217: 		 remain,
  218: 		 option_type, option_len,
  219: 		 src_str, ifp->name);
  220:     }
  221: 
  222:     switch (option_type) {
  223:     case PIM_MSG_OPTION_TYPE_HOLDTIME:
  224:       if (pim_tlv_parse_holdtime(ifp->name, src_addr,
  225: 				 &hello_options,
  226: 				 &hello_option_holdtime,
  227: 				 option_len,
  228: 				 tlv_curr)) {
  229: 	FREE_ADDR_LIST_THEN_RETURN(-3);
  230:       }
  231:       break;
  232:     case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY:
  233:       if (pim_tlv_parse_lan_prune_delay(ifp->name, src_addr,
  234: 					&hello_options,
  235: 					&hello_option_propagation_delay,
  236: 					&hello_option_override_interval,
  237: 					option_len,
  238: 					tlv_curr)) {
  239: 	FREE_ADDR_LIST_THEN_RETURN(-4);
  240:       }
  241:       break;
  242:     case PIM_MSG_OPTION_TYPE_DR_PRIORITY:
  243:       if (pim_tlv_parse_dr_priority(ifp->name, src_addr,
  244: 				    &hello_options,
  245: 				    &hello_option_dr_priority,
  246: 				    option_len,
  247: 				    tlv_curr)) {
  248: 	FREE_ADDR_LIST_THEN_RETURN(-5);
  249:       }
  250:       break;
  251:     case PIM_MSG_OPTION_TYPE_GENERATION_ID:
  252:       if (pim_tlv_parse_generation_id(ifp->name, src_addr,
  253: 				      &hello_options,
  254: 				      &hello_option_generation_id,
  255: 				      option_len,
  256: 				      tlv_curr)) {
  257: 	FREE_ADDR_LIST_THEN_RETURN(-6);
  258:       }
  259:       break;
  260:     case PIM_MSG_OPTION_TYPE_ADDRESS_LIST:
  261:       if (pim_tlv_parse_addr_list(ifp->name, src_addr,
  262: 				  &hello_options,
  263: 				  &hello_option_addr_list,
  264: 				  option_len,
  265: 				  tlv_curr)) {
  266: 	return -7;
  267:       }
  268:       break;
  269:     case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH:
  270:       if (PIM_DEBUG_PIM_HELLO) {
  271: 	char src_str[100];
  272: 	pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  273: 	zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s",
  274: 		   __PRETTY_FUNCTION__,
  275: 		   option_type, option_len,
  276: 		   src_str, ifp->name);
  277:       }
  278:       break;
  279:     default:
  280:       if (PIM_DEBUG_PIM_HELLO) {
  281: 	char src_str[100];
  282: 	pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  283: 	zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s",
  284: 		   __PRETTY_FUNCTION__,
  285: 		   option_type, option_len,
  286: 		   src_str, ifp->name);
  287:       }
  288:     }
  289: 
  290:     tlv_curr += option_len;
  291:   }
  292: 
  293:   /*
  294:     Check received PIM hello options
  295:   */
  296: 
  297:   if (PIM_DEBUG_PIM_HELLO) {
  298:     tlv_trace_uint16(__PRETTY_FUNCTION__, "holdtime",
  299: 		     ifp->name, src_addr,
  300: 		     PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME),
  301: 		     hello_option_holdtime);
  302:     tlv_trace_uint16(__PRETTY_FUNCTION__, "propagation_delay",
  303: 		     ifp->name, src_addr,
  304: 		     PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY),
  305: 		     hello_option_propagation_delay);
  306:     tlv_trace_uint16(__PRETTY_FUNCTION__, "override_interval",
  307: 		     ifp->name, src_addr,
  308: 		     PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY),
  309: 		     hello_option_override_interval);
  310:     tlv_trace_bool(__PRETTY_FUNCTION__, "can_disable_join_suppression",
  311: 		   ifp->name, src_addr,
  312: 		   PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY),
  313: 		   PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION));
  314:     tlv_trace_uint32(__PRETTY_FUNCTION__, "dr_priority",
  315: 		     ifp->name, src_addr,
  316: 		     PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY),
  317: 		     hello_option_dr_priority);
  318:     tlv_trace_uint32_hex(__PRETTY_FUNCTION__, "generation_id",
  319: 			 ifp->name, src_addr,
  320: 			 PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID),
  321: 			 hello_option_generation_id);
  322:     tlv_trace_list(__PRETTY_FUNCTION__, "address_list",
  323: 		   ifp->name, src_addr,
  324: 		   PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_ADDRESS_LIST),
  325: 		   hello_option_addr_list);
  326:   }
  327: 
  328:   if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
  329:     if (PIM_DEBUG_PIM_HELLO) {
  330:       char src_str[100];
  331:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  332:       zlog_debug("%s: PIM hello missing holdtime from %s on interface %s",
  333: 		__PRETTY_FUNCTION__,
  334: 		src_str, ifp->name);
  335:     }
  336:   }
  337: 
  338:   /*
  339:     New neighbor?
  340:   */
  341: 
  342:   neigh = pim_neighbor_find(ifp, src_addr);
  343:   if (!neigh) {
  344:     /* Add as new neighbor */
  345:     
  346:     neigh = pim_neighbor_add(ifp, src_addr,
  347: 			     hello_options,
  348: 			     hello_option_holdtime,
  349: 			     hello_option_propagation_delay,
  350: 			     hello_option_override_interval,
  351: 			     hello_option_dr_priority,
  352: 			     hello_option_generation_id,
  353: 			     hello_option_addr_list);
  354:     if (!neigh) {
  355:       if (PIM_DEBUG_PIM_HELLO) {
  356: 	char src_str[100];
  357: 	pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  358: 	zlog_warn("%s: failure creating PIM neighbor %s on interface %s",
  359: 		  __PRETTY_FUNCTION__,
  360: 		  src_str, ifp->name);
  361:       }
  362:       FREE_ADDR_LIST_THEN_RETURN(-8);
  363:     }
  364: 
  365:     /* actual addr list has been saved under neighbor */
  366:     return 0;
  367:   }
  368: 
  369:   /*
  370:     Received generation ID ?
  371:   */
  372:   
  373:   if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID)) {
  374:     /* GenID mismatch ? */
  375:     if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ||
  376: 	(hello_option_generation_id != neigh->generation_id)) {
  377: 
  378:       /* GenID changed */
  379: 
  380:       pim_upstream_rpf_genid_changed(neigh->source_addr);
  381: 
  382:       /* GenID mismatch, then replace neighbor */
  383:       
  384:       if (PIM_DEBUG_PIM_HELLO) {
  385: 	char src_str[100];
  386: 	pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  387: 	zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s",
  388: 		   __PRETTY_FUNCTION__,
  389: 		   hello_option_generation_id,
  390: 		   neigh->generation_id,
  391: 		   src_str, ifp->name);
  392:       }
  393: 
  394:       pim_upstream_rpf_genid_changed(neigh->source_addr);
  395:       
  396:       pim_neighbor_delete(ifp, neigh, "GenID mismatch");
  397:       neigh = pim_neighbor_add(ifp, src_addr,
  398: 			       hello_options,
  399: 			       hello_option_holdtime,
  400: 			       hello_option_propagation_delay,
  401: 			       hello_option_override_interval,
  402: 			       hello_option_dr_priority,
  403: 			       hello_option_generation_id,
  404: 			       hello_option_addr_list);
  405:       if (!neigh) {
  406: 	if (PIM_DEBUG_PIM_HELLO) {
  407: 	  char src_str[100];
  408: 	  pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  409: 	  zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s",
  410: 		     __PRETTY_FUNCTION__,
  411: 		     src_str, ifp->name);
  412: 	}
  413: 	FREE_ADDR_LIST_THEN_RETURN(-9);
  414:       }
  415:       /* actual addr list is saved under neighbor */
  416:       return 0;
  417: 
  418:     } /* GenId mismatch: replace neighbor */
  419:     
  420:   } /* GenId received */
  421: 
  422:   /*
  423:     Update existing neighbor
  424:   */
  425: 
  426:   pim_neighbor_update(neigh,
  427: 		      hello_options,
  428: 		      hello_option_holdtime,
  429: 		      hello_option_dr_priority,
  430: 		      hello_option_addr_list);
  431:   /* actual addr list is saved under neighbor */
  432:   return 0;
  433: }
  434: 
  435: int pim_hello_build_tlv(const char *ifname,
  436: 			uint8_t *tlv_buf, int tlv_buf_size,
  437: 			uint16_t holdtime,
  438: 			uint32_t dr_priority,
  439: 			uint32_t generation_id,
  440: 			uint16_t propagation_delay,
  441: 			uint16_t override_interval,
  442: 			int can_disable_join_suppression,
  443: 			struct list *ifconnected)
  444: {
  445:   uint8_t *curr = tlv_buf;
  446:   uint8_t *pastend = tlv_buf + tlv_buf_size;
  447:   uint8_t *tmp;
  448: 
  449:   /*
  450:    * Append options
  451:    */
  452: 
  453:   /* Holdtime */
  454:   curr = pim_tlv_append_uint16(curr,
  455: 			       pastend,
  456: 			       PIM_MSG_OPTION_TYPE_HOLDTIME,
  457: 			       holdtime);
  458:   if (!curr) {
  459:     if (PIM_DEBUG_PIM_HELLO) {
  460:       zlog_debug("%s: could not set PIM hello Holdtime option for interface %s",
  461: 		 __PRETTY_FUNCTION__, ifname);
  462:     }
  463:     return -1;
  464:   }
  465: 
  466:   /* LAN Prune Delay */
  467:   tmp = pim_tlv_append_2uint16(curr,
  468: 			       pastend,
  469: 			       PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY,
  470: 			       propagation_delay,
  471: 			       override_interval);
  472:   if (!tmp) {
  473:     if (PIM_DEBUG_PIM_HELLO) {
  474:       zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s",
  475: 		 __PRETTY_FUNCTION__, ifname);
  476:     }
  477:     return -1;
  478:   }
  479:   if (can_disable_join_suppression) {
  480:     *((uint8_t*)(curr) + 4) |= 0x80; /* enable T bit */
  481:   }
  482:   curr = tmp;
  483: 
  484:   /* DR Priority */
  485:   curr = pim_tlv_append_uint32(curr,
  486: 			       pastend,
  487: 			       PIM_MSG_OPTION_TYPE_DR_PRIORITY,
  488: 			       dr_priority);
  489:   if (!curr) {
  490:     if (PIM_DEBUG_PIM_HELLO) {
  491:       zlog_debug("%s: could not set PIM hello DR Priority option for interface %s",
  492: 		 __PRETTY_FUNCTION__, ifname);
  493:     }
  494:     return -2;
  495:   }
  496: 
  497:   /* Generation ID */
  498:   curr = pim_tlv_append_uint32(curr,
  499: 			       pastend,
  500: 			       PIM_MSG_OPTION_TYPE_GENERATION_ID,
  501: 			       generation_id);
  502:   if (!curr) {
  503:     if (PIM_DEBUG_PIM_HELLO) {
  504:       zlog_debug("%s: could not set PIM hello Generation ID option for interface %s",
  505: 		 __PRETTY_FUNCTION__, ifname);
  506:     }
  507:     return -3;
  508:   }
  509: 
  510:   /* Secondary Address List */
  511:   if (ifconnected) {
  512:     curr = pim_tlv_append_addrlist_ucast(curr,
  513: 					 pastend,
  514: 					 ifconnected);
  515:     if (!curr) {
  516:       if (PIM_DEBUG_PIM_HELLO) {
  517: 	zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s",
  518: 		  __PRETTY_FUNCTION__, ifname);
  519:       }
  520:       return -4;
  521:     }
  522:   }
  523: 
  524:   return curr - tlv_buf;
  525: }
  526: 
  527: /*
  528:   RFC 4601: 4.3.1.  Sending Hello Messages
  529: 
  530:   Thus, if a router needs to send a Join/Prune or Assert message on an
  531:   interface on which it has not yet sent a Hello message with the
  532:   currently configured IP address, then it MUST immediately send the
  533:   relevant Hello message without waiting for the Hello Timer to
  534:   expire, followed by the Join/Prune or Assert message.
  535: */
  536: void pim_hello_require(struct interface *ifp)
  537: {
  538:   struct pim_interface *pim_ifp;
  539: 
  540:   zassert(ifp);
  541: 
  542:   pim_ifp = ifp->info;
  543: 
  544:   zassert(pim_ifp);
  545: 
  546:   if (pim_ifp->pim_ifstat_hello_sent)
  547:     return;
  548: 
  549:   pim_hello_restart_now(ifp); /* Send hello and restart timer */
  550: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>