File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_join.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, 8 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_join.h"
   34: #include "pim_iface.h"
   35: #include "pim_hello.h"
   36: #include "pim_ifchannel.h"
   37: 
   38: static void on_trace(const char *label,
   39: 		     struct interface *ifp, struct in_addr src)
   40: {
   41:   if (PIM_DEBUG_PIM_TRACE) {
   42:     char src_str[100];
   43:     pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
   44:     zlog_debug("%s: from %s on %s",
   45: 	       label, src_str, ifp->name);
   46:   }
   47: }
   48: 
   49: static void recv_join(struct interface *ifp,
   50: 		      struct pim_neighbor *neigh,
   51: 		      uint16_t holdtime,
   52: 		      struct in_addr upstream,
   53: 		      struct in_addr group,
   54: 		      struct in_addr source,
   55: 		      uint8_t source_flags)
   56: {
   57:   if (PIM_DEBUG_PIM_TRACE) {
   58:     char up_str[100];
   59:     char src_str[100];
   60:     char grp_str[100];
   61:     char neigh_str[100];
   62:     pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
   63:     pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
   64:     pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
   65:     pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
   66:     zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
   67: 	      __PRETTY_FUNCTION__,
   68: 	      src_str, grp_str,
   69: 	      source_flags & PIM_RPT_BIT_MASK,
   70: 	      source_flags & PIM_WILDCARD_BIT_MASK,
   71: 	      up_str, holdtime, neigh_str, ifp->name);
   72:   }
   73:   
   74:   /* Restart join expiry timer */
   75:   pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
   76: 			 source, group, source_flags, holdtime);
   77: }
   78: 
   79: static void recv_prune(struct interface *ifp,
   80: 		       struct pim_neighbor *neigh,
   81: 		       uint16_t holdtime,
   82: 		       struct in_addr upstream,
   83: 		       struct in_addr group,
   84: 		       struct in_addr source,
   85: 		       uint8_t source_flags)
   86: {
   87:   if (PIM_DEBUG_PIM_TRACE) {
   88:     char up_str[100];
   89:     char src_str[100];
   90:     char grp_str[100];
   91:     char neigh_str[100];
   92:     pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
   93:     pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
   94:     pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
   95:     pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
   96:     zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
   97: 	      __PRETTY_FUNCTION__,
   98: 	      src_str, grp_str,
   99: 	      source_flags & PIM_RPT_BIT_MASK,
  100: 	      source_flags & PIM_WILDCARD_BIT_MASK,
  101: 	      up_str, holdtime, neigh_str, ifp->name);
  102:   }
  103:   
  104:   pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime);
  105: }
  106: 
  107: int pim_joinprune_recv(struct interface *ifp,
  108: 		       struct pim_neighbor *neigh,
  109: 		       struct in_addr src_addr,
  110: 		       uint8_t *tlv_buf, int tlv_buf_size)
  111: {
  112:   struct prefix   msg_upstream_addr;
  113:   uint8_t         msg_num_groups;
  114:   uint16_t        msg_holdtime;
  115:   int             addr_offset;
  116:   uint8_t        *buf;
  117:   uint8_t        *pastend;
  118:   int             remain;
  119:   int             group;
  120: 
  121:   on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
  122: 
  123:   buf     = tlv_buf;
  124:   pastend = tlv_buf + tlv_buf_size;
  125: 
  126:   /*
  127:     Parse ucast addr
  128:   */
  129:   addr_offset = pim_parse_addr_ucast(ifp->name, src_addr,
  130: 				     &msg_upstream_addr,
  131: 				     buf, pastend - buf);
  132: #if 0
  133:   zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d",
  134:             __PRETTY_FUNCTION__,
  135:             addr_offset);
  136: #endif
  137:   if (addr_offset < 1) {
  138:     char src_str[100];
  139:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  140:     zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
  141: 	      __PRETTY_FUNCTION__,
  142: 	      src_str, ifp->name);
  143:     return -1;
  144:   }
  145:   buf += addr_offset;
  146: 
  147:   /*
  148:     Check upstream address family
  149:    */
  150:   if (msg_upstream_addr.family != AF_INET) {
  151:     if (PIM_DEBUG_PIM_TRACE) {
  152:       char src_str[100];
  153:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  154:       zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
  155: 		__PRETTY_FUNCTION__,
  156: 		msg_upstream_addr.family, src_str, ifp->name);
  157:     }
  158:     return -2;
  159:   }
  160: 
  161:   remain = pastend - buf;
  162:   if (remain < 4) {
  163:     char src_str[100];
  164:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  165:     zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
  166: 	      __PRETTY_FUNCTION__,
  167: 	      remain, 4, src_str, ifp->name);
  168:     return -4;
  169:   }
  170: 
  171:   ++buf; /* skip reserved byte */
  172:   msg_num_groups = *(const uint8_t *) buf;
  173:   ++buf;
  174:   msg_holdtime = ntohs(*(const uint16_t *) buf);
  175:   ++buf;
  176:   ++buf;
  177: 
  178:   if (PIM_DEBUG_PIM_TRACE) {
  179:     char src_str[100];
  180:     char upstream_str[100];
  181:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  182:     pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
  183: 		   upstream_str, sizeof(upstream_str));
  184:     zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
  185: 	      __PRETTY_FUNCTION__,
  186: 	      upstream_str, msg_num_groups, msg_holdtime,
  187: 	      src_str, ifp->name);
  188:   }
  189: 
  190:   /* Scan groups */
  191:   for (group = 0; group < msg_num_groups; ++group) {
  192:     struct prefix msg_group_addr;
  193:     struct prefix msg_source_addr;
  194:     uint8_t       msg_source_flags;
  195:     uint16_t      msg_num_joined_sources;
  196:     uint16_t      msg_num_pruned_sources;
  197:     int           source;
  198: 
  199:     addr_offset = pim_parse_addr_group(ifp->name, src_addr,
  200: 				       &msg_group_addr,
  201: 				       buf, pastend - buf);
  202: #if 0
  203:     zlog_warn("%s: pim_parse_addr_group addr_offset=%d",
  204:               __PRETTY_FUNCTION__,
  205:               addr_offset);
  206: #endif
  207:     if (addr_offset < 1) {
  208:       return -5;
  209:     }
  210:     buf += addr_offset;
  211: 
  212:     remain = pastend - buf;
  213:     if (remain < 4) {
  214:       char src_str[100];
  215:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  216:       zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
  217: 		__PRETTY_FUNCTION__,
  218: 		remain, 4, src_str, ifp->name);
  219:       return -6;
  220:     }
  221: 
  222:     msg_num_joined_sources = ntohs(*(const uint16_t *) buf);
  223:     buf += 2;
  224:     msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
  225:     buf += 2;
  226: 
  227:     if (PIM_DEBUG_PIM_TRACE) {
  228:       char src_str[100];
  229:       char upstream_str[100];
  230:       char group_str[100];
  231:       pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
  232:       pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
  233: 		     upstream_str, sizeof(upstream_str));
  234:       pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4,
  235: 		     group_str, sizeof(group_str));
  236:       zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
  237: 		__PRETTY_FUNCTION__,
  238: 		upstream_str, group_str, msg_group_addr.prefixlen,
  239: 		msg_num_joined_sources, msg_num_pruned_sources,
  240: 		src_str, ifp->name);
  241:     }
  242: 
  243:     /* Scan joined sources */
  244:     for (source = 0; source < msg_num_joined_sources; ++source) {
  245:       addr_offset = pim_parse_addr_source(ifp->name, src_addr,
  246: 					  &msg_source_addr,
  247: 					  &msg_source_flags,
  248: 					  buf, pastend - buf);
  249: #if 0
  250:       zlog_warn("%s: pim_parse_addr_source addr_offset=%d",
  251:                 __PRETTY_FUNCTION__,
  252:                 addr_offset);
  253: #endif
  254:       if (addr_offset < 1) {
  255: 	return -7;
  256:       }
  257: 
  258:       buf += addr_offset;
  259: 
  260:       recv_join(ifp, neigh, msg_holdtime,
  261: 		msg_upstream_addr.u.prefix4,
  262: 		msg_group_addr.u.prefix4,
  263: 		msg_source_addr.u.prefix4,
  264: 		msg_source_flags);
  265:     }
  266: 
  267:     /* Scan pruned sources */
  268:     for (source = 0; source < msg_num_pruned_sources; ++source) {
  269:       addr_offset = pim_parse_addr_source(ifp->name, src_addr,
  270: 					  &msg_source_addr,
  271: 					  &msg_source_flags,
  272: 					  buf, pastend - buf);
  273:       if (addr_offset < 1) {
  274: 	return -8;
  275:       }
  276: 
  277:       buf += addr_offset;
  278: 
  279:       recv_prune(ifp, neigh, msg_holdtime,
  280: 		 msg_upstream_addr.u.prefix4,
  281: 		 msg_group_addr.u.prefix4,
  282: 		 msg_source_addr.u.prefix4,
  283: 		 msg_source_flags);
  284:     }
  285: 
  286:   } /* scan groups */
  287: 
  288:   return 0;
  289: }
  290: 
  291: int pim_joinprune_send(struct interface *ifp,
  292: 		       struct in_addr upstream_addr,
  293: 		       struct in_addr source_addr,
  294: 		       struct in_addr group_addr,
  295: 		       int send_join)
  296: {
  297:   struct pim_interface *pim_ifp;
  298:   uint8_t pim_msg[1000];
  299:   const uint8_t *pastend = pim_msg + sizeof(pim_msg);
  300:   uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
  301:   int pim_msg_size;
  302:   int remain;
  303: 
  304:   zassert(ifp);
  305: 
  306:   pim_ifp = ifp->info;
  307: 
  308:   if (!pim_ifp) {
  309:     zlog_warn("%s: multicast not enabled on interface %s",
  310: 	      __PRETTY_FUNCTION__,
  311: 	      ifp->name);
  312:     return -1;
  313:   }
  314: 
  315:   if (PIM_DEBUG_PIM_TRACE) {
  316:     char source_str[100];
  317:     char group_str[100];
  318:     char dst_str[100];
  319:     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  320:     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  321:     pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
  322:     zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s",
  323: 	       __PRETTY_FUNCTION__,
  324: 	       send_join ? "Join" : "Prune",
  325: 	       source_str, group_str, dst_str, ifp->name);
  326:   }
  327: 
  328:   if (PIM_INADDR_IS_ANY(upstream_addr)) {
  329:     if (PIM_DEBUG_PIM_TRACE) {
  330:       char source_str[100];
  331:       char group_str[100];
  332:       char dst_str[100];
  333:       pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  334:       pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  335:       pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
  336:       zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s",
  337: 		 __PRETTY_FUNCTION__,
  338: 		 send_join ? "Join" : "Prune",
  339: 		 source_str, group_str, dst_str, ifp->name);
  340:     }
  341:     return 0;
  342:   }
  343: 
  344:   /*
  345:     RFC 4601: 4.3.1.  Sending Hello Messages
  346: 
  347:     Thus, if a router needs to send a Join/Prune or Assert message on
  348:     an interface on which it has not yet sent a Hello message with the
  349:     currently configured IP address, then it MUST immediately send the
  350:     relevant Hello message without waiting for the Hello Timer to
  351:     expire, followed by the Join/Prune or Assert message.
  352:   */
  353:   pim_hello_require(ifp);
  354: 
  355:   /*
  356:     Build PIM message
  357:   */
  358: 
  359:   remain = pastend - pim_msg_curr;
  360:   pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
  361: 						remain,
  362: 						upstream_addr);
  363:   if (!pim_msg_curr) {
  364:     char dst_str[100];
  365:     pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
  366:     zlog_warn("%s: failure encoding destination address %s: space left=%d",
  367: 	      __PRETTY_FUNCTION__, dst_str, remain);
  368:     return -3;
  369:   }
  370: 
  371:   remain = pastend - pim_msg_curr;
  372:   if (remain < 4) {
  373:     zlog_warn("%s: group will not fit: space left=%d",
  374: 	    __PRETTY_FUNCTION__, remain);
  375:     return -4;
  376:   }
  377: 
  378:   *pim_msg_curr = 0; /* reserved */
  379:   ++pim_msg_curr;
  380:   *pim_msg_curr = 1; /* number of groups */
  381:   ++pim_msg_curr;
  382:   *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME);
  383:   ++pim_msg_curr;
  384:   ++pim_msg_curr;
  385: 
  386:   remain = pastend - pim_msg_curr;
  387:   pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
  388: 						remain,
  389: 						group_addr);
  390:   if (!pim_msg_curr) {
  391:     char group_str[100];
  392:     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  393:     zlog_warn("%s: failure encoding group address %s: space left=%d",
  394: 	      __PRETTY_FUNCTION__, group_str, remain);
  395:     return -5;
  396:   }
  397: 
  398:   remain = pastend - pim_msg_curr;
  399:   if (remain < 4) {
  400:     zlog_warn("%s: sources will not fit: space left=%d",
  401: 	      __PRETTY_FUNCTION__, remain);
  402:     return -6;
  403:   }
  404: 
  405:   /* number of joined sources */
  406:   *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0);
  407:   ++pim_msg_curr;
  408:   ++pim_msg_curr;
  409: 
  410:   /* number of pruned sources */
  411:   *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1);
  412:   ++pim_msg_curr;
  413:   ++pim_msg_curr;
  414: 
  415:   remain = pastend - pim_msg_curr;
  416:   pim_msg_curr = pim_msg_addr_encode_ipv4_source(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 -7;
  425:   }
  426: 
  427:   /* Add PIM header */
  428: 
  429:   pim_msg_size = pim_msg_curr - pim_msg;
  430: 
  431:   pim_msg_build_header(pim_msg, pim_msg_size,
  432: 		       PIM_MSG_TYPE_JOIN_PRUNE);
  433: 
  434:   if (pim_msg_send(pim_ifp->pim_sock_fd,
  435: 		   qpim_all_pim_routers_addr,
  436: 		   pim_msg,
  437: 		   pim_msg_size,
  438: 		   ifp->name)) {
  439:     zlog_warn("%s: could not send PIM message on interface %s",
  440: 	      __PRETTY_FUNCTION__, ifp->name);
  441:     return -8;
  442:   }
  443: 
  444:   return 0;
  445: }

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