File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimdd / route.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:58:55 2017 UTC (7 years ago) by misho
Branches: pimdd, MAIN
CVS tags: v0_2_1p0, v0_2_1, HEAD
pimdd-dense 0.2.1.0_2

    1: /*
    2:  *  Copyright (c) 1998 by the University of Oregon.
    3:  *  All rights reserved.
    4:  *
    5:  *  Permission to use, copy, modify, and distribute this software and
    6:  *  its documentation in source and binary forms for lawful
    7:  *  purposes and without fee is hereby granted, provided
    8:  *  that the above copyright notice appear in all copies and that both
    9:  *  the copyright notice and this permission notice appear in supporting
   10:  *  documentation, and that any documentation, advertising materials,
   11:  *  and other materials related to such distribution and use acknowledge
   12:  *  that the software was developed by the University of Oregon.
   13:  *  The name of the University of Oregon may not be used to endorse or 
   14:  *  promote products derived from this software without specific prior 
   15:  *  written permission.
   16:  *
   17:  *  THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
   18:  *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
   19:  *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
   20:  *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   21:  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 
   22:  *  NON-INFRINGEMENT.
   23:  *
   24:  *  IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
   25:  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
   26:  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
   27:  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
   28:  *
   29:  *  Other copyrights might apply to parts of this software and are so
   30:  *  noted when applicable.
   31:  */
   32: /*
   33:  *  Questions concerning this software should be directed to 
   34:  *  Kurt Windisch (kurtw@antc.uoregon.edu)
   35:  *
   36:  *  $Id: route.c,v 1.1.1.1 2017/06/12 07:58:55 misho Exp $
   37:  */
   38: /*
   39:  * Part of this program has been derived from PIM sparse-mode pimd.
   40:  * The pimd program is covered by the license in the accompanying file
   41:  * named "LICENSE.pimd".
   42:  *  
   43:  * The pimd program is COPYRIGHT 1998 by University of Southern California.
   44:  *
   45:  * Part of this program has been derived from mrouted.
   46:  * The mrouted program is covered by the license in the accompanying file
   47:  * named "LICENSE.mrouted".
   48:  * 
   49:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
   50:  * Leland Stanford Junior University.
   51:  *
   52:  */
   53: 
   54: #include "defs.h"
   55: 
   56: 
   57: static void   process_cache_miss  __P((struct igmpmsg *igmpctl));
   58: static void   process_wrong_iif   __P((struct igmpmsg *igmpctl));
   59: 
   60: u_int32         default_source_preference = DEFAULT_LOCAL_PREF;
   61: u_int32         default_source_metric     = DEFAULT_LOCAL_METRIC;
   62: 
   63: /* Return the iif for given address */
   64: vifi_t
   65: get_iif(address)
   66:     u_int32 address;
   67: {
   68:     struct rpfctl rpfc;
   69: 
   70:     k_req_incoming(address, &rpfc);
   71:     if (rpfc.rpfneighbor.s_addr == INADDR_ANY_N)
   72: 	return (NO_VIF);
   73:     return (rpfc.iif);
   74: }
   75: 
   76: /* Return the PIM neighbor toward a source */
   77: /* If route not found or if a local source or if a directly connected source,
   78:  * but is not PIM router, or if the first hop router is not a PIM router,
   79:  * then return NULL.
   80:  */
   81: pim_nbr_entry_t *
   82: find_pim_nbr(source)
   83:     u_int32 source;
   84: {
   85:     struct rpfctl rpfc;
   86:     pim_nbr_entry_t *pim_nbr;
   87:     u_int32 next_hop_router_addr;
   88: 
   89:     if (local_address(source) != NO_VIF)
   90: 	return (pim_nbr_entry_t *)NULL;
   91:     k_req_incoming(source, &rpfc);
   92:     if ((rpfc.rpfneighbor.s_addr == INADDR_ANY_N)
   93: 	|| (rpfc.iif == NO_VIF))
   94: 	return (pim_nbr_entry_t *)NULL;
   95:     next_hop_router_addr = rpfc.rpfneighbor.s_addr;
   96:     for (pim_nbr = uvifs[rpfc.iif].uv_pim_neighbors;
   97: 	 pim_nbr != (pim_nbr_entry_t *)NULL;
   98: 	 pim_nbr = pim_nbr->next)
   99: 	if (pim_nbr->address == next_hop_router_addr)
  100: 	    return(pim_nbr);
  101:     return (pim_nbr_entry_t *)NULL;
  102: }
  103: 
  104: 
  105: /* TODO: check again the exact setup if the source is local or directly
  106:  * connected!!!
  107:  */
  108: /* TODO: XXX: change the metric and preference for all (S,G) entries per
  109:  * source?
  110:  */
  111: /* PIMDM TODO - If possible, this would be the place to correct set the
  112:  * source's preference and metric to that obtained from the kernel
  113:  * and/or unicast routing protocol.  For now, set it to the configured
  114:  * default for local pref/metric.
  115:  */
  116: /*
  117:  * Set the iif, upstream router, preference and metric for the route
  118:  * toward the source. Return TRUE is the route was found, othewise FALSE.
  119:  * If srctype==PIM_IIF_SOURCE and if the source is directly connected
  120:  * then the "upstream" is set to NULL. 
  121:  * Note that srctype is a hold-over from the PIM-SM daemon and is unused.
  122:  */
  123: int
  124: set_incoming(srcentry_ptr, srctype)
  125:     srcentry_t *srcentry_ptr;
  126:     int srctype;
  127: {
  128:     struct rpfctl rpfc;
  129:     u_int32 source = srcentry_ptr->address;
  130:     u_int32 neighbor_addr;
  131:     register struct uvif *v;
  132:     register pim_nbr_entry_t *n;
  133: 
  134:     /* Preference will be 0 if directly connected */
  135:     srcentry_ptr->preference = 0; 
  136:     srcentry_ptr->metric = 0;
  137: 
  138:     if ((srcentry_ptr->incoming = local_address(source)) != NO_VIF) {
  139: 	/* The source is a local address */
  140: 	/* TODO: set the upstream to myself? */
  141: 	srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
  142: 	return (TRUE);
  143:     }
  144: 
  145:     if ((srcentry_ptr->incoming = find_vif_direct(source)) == NO_VIF) {
  146:     /* TODO: probably need to check the case if the iif is disabled */
  147: 	/* Use the lastest resource: the kernel unicast routing table */
  148: 	k_req_incoming(source, &rpfc);
  149: 	if ((rpfc.iif == NO_VIF) ||
  150: 	    rpfc.rpfneighbor.s_addr == INADDR_ANY_N) {
  151: 	    /* couldn't find a route */
  152: 	    IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF)
  153: 		log(LOG_DEBUG, 0, "NO ROUTE found for %s",
  154: 		    inet_fmt(source, s1));
  155: 	    return(FALSE);
  156: 	}
  157: 	srcentry_ptr->incoming = rpfc.iif;
  158: 	neighbor_addr = rpfc.rpfneighbor.s_addr;
  159:     }
  160:     else {
  161: 	/* The source is directly connected. 
  162: 	 */
  163: 	srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
  164: 	return (TRUE);
  165:     }
  166: 
  167:     /* set the preference for sources that aren't directly connected. */
  168:     v = &uvifs[srcentry_ptr->incoming];
  169:     srcentry_ptr->preference = v->uv_local_pref;
  170:     srcentry_ptr->metric = v->uv_local_metric;
  171: 
  172:     /*
  173:      * The upstream router must be a (PIM router) neighbor, otherwise we
  174:      * are in big trouble ;-)
  175:      */
  176:     for (n = v->uv_pim_neighbors; n != NULL; n = n->next) {
  177: 	if (ntohl(neighbor_addr) < ntohl(n->address))
  178: 	    continue;
  179: 	if (neighbor_addr == n->address) {
  180: 	    /*
  181: 	     *The upstream router is found in the list of neighbors.
  182: 	     * We are safe!
  183: 	     */
  184: 	    srcentry_ptr->upstream = n;
  185: 	    IF_DEBUG(DEBUG_RPF)
  186: 		log(LOG_DEBUG, 0,
  187: 		    "For src %s, iif is %d, next hop router is %s",
  188: 		    inet_fmt(source, s1), srcentry_ptr->incoming,
  189: 		    inet_fmt(neighbor_addr, s2));
  190: 	    return(TRUE);
  191: 	}
  192: 	else break;
  193:     }
  194:     
  195:     /* TODO: control the number of messages! */
  196:     log(LOG_INFO, 0,
  197: 	"For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER",
  198: 	inet_fmt(source, s1), srcentry_ptr->incoming,
  199: 	inet_fmt(neighbor_addr, s2));
  200:     srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL; 
  201: 
  202:     return(FALSE);
  203: }
  204: 
  205: 
  206: /* Set the leaves in a new mrtentry */
  207: void set_leaves(mrtentry_ptr)
  208:      mrtentry_t *mrtentry_ptr;
  209: {
  210:     vifi_t vifi;
  211:     struct uvif *v;
  212:     
  213:     /* Check for a group report on each vif */
  214:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) 
  215: 	if(check_grp_membership(v, mrtentry_ptr->group->group)) 
  216: 	    VIFM_SET(vifi, mrtentry_ptr->leaves);
  217: }
  218: 
  219: 
  220: /* Handle new receiver
  221:  *
  222:  * TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where
  223:  * we have source-specific Join/Prune.
  224:  */
  225: void
  226: add_leaf(vifi, source, group)
  227:     vifi_t vifi;
  228:     u_int32 source;
  229:     u_int32 group;
  230: {
  231:     grpentry_t *grpentry_ptr;
  232:     mrtentry_t *mrtentry_srcs;
  233:     vifbitmap_t new_leaves;
  234:     int state_change;
  235: 
  236:     grpentry_ptr = find_group(group);
  237:     if (grpentry_ptr == (grpentry_t *)NULL)
  238: 	return;
  239: 
  240:     /* walk the source list for the group and add vif to oiflist */
  241:     for (mrtentry_srcs = grpentry_ptr->mrtlink;
  242: 	 mrtentry_srcs != (mrtentry_t *)NULL;
  243: 	 mrtentry_srcs = mrtentry_srcs->grpnext) {
  244: 
  245: 	/* if applicable, add the vif to the leaves */
  246: 	if (mrtentry_srcs->incoming == vifi) 
  247: 	    continue;
  248: 
  249: 	if(!(VIFM_ISSET(vifi, mrtentry_srcs->leaves))) {
  250: 
  251: 	    IF_DEBUG(DEBUG_MRT)
  252: 		log(LOG_DEBUG, 0, "Adding leaf vif %d for src %s group %s", 
  253: 		    vifi,
  254: 		    inet_fmt(mrtentry_srcs->source->address, s1),
  255: 		    inet_fmt(group, s2));
  256: 	    
  257: 	    VIFM_COPY(mrtentry_srcs->leaves, new_leaves);
  258: 	    VIFM_SET(vifi, new_leaves);    /* Add the leaf */
  259: 	    
  260: 	    state_change = 
  261: 		change_interfaces(mrtentry_srcs,
  262: 				  mrtentry_srcs->incoming,
  263: 				  mrtentry_srcs->pruned_oifs,
  264: 				  new_leaves);
  265: 
  266: 	    /* Handle transition from negative cache */
  267: 	    if(state_change == 1) 
  268: 		trigger_join_alert(mrtentry_srcs);
  269: 	}
  270:     }
  271: }
  272: 
  273: 
  274: /*
  275:  * TODO: XXX: currently `source` is not used. To be used with IGMPv3 where
  276:  * we have source-specific joins/prunes.
  277:  */
  278: void
  279: delete_leaf(vifi, source, group)
  280:     vifi_t vifi;
  281:     u_int32 source;
  282:     u_int32 group;
  283: {
  284:     grpentry_t *grpentry_ptr;
  285:     mrtentry_t *mrtentry_srcs;
  286:     vifbitmap_t new_leaves;
  287:     int state_change;
  288: 
  289:     /* mrtentry_t *mrtentry_ptr;
  290:      * mrtentry_t *mrtentry_srcs;
  291:      * vifbitmap_t new_oifs;
  292:      * vifbitmap_t old_oifs;
  293:      * vifbitmap_t new_leaves;
  294:      */
  295: 
  296:     grpentry_ptr = find_group(group);
  297:     if (grpentry_ptr == (grpentry_t *)NULL)
  298: 	return;
  299: 
  300:     /* walk the source list for the group and delete vif to leaves */
  301:     for (mrtentry_srcs = grpentry_ptr->mrtlink;
  302: 	 mrtentry_srcs != (mrtentry_t *)NULL;
  303: 	 mrtentry_srcs = mrtentry_srcs->grpnext) {
  304: 
  305: 	/* if applicable, delete the vif from the leaves */
  306: 	if (mrtentry_srcs->incoming == vifi) 
  307: 	    continue;
  308: 
  309: 	if(VIFM_ISSET(vifi, mrtentry_srcs->leaves)) {
  310: 
  311: 	    IF_DEBUG(DEBUG_MRT)
  312: 		log(LOG_DEBUG, 0, "Deleting leaf vif %d for src %s, group %s",
  313: 		    vifi,
  314: 		    inet_fmt(mrtentry_srcs->source->address, s1), 
  315: 		    inet_fmt(group, s2));
  316: 	    
  317: 	    VIFM_COPY(mrtentry_srcs->leaves, new_leaves);
  318: 	    VIFM_CLR(vifi, new_leaves);    /* Remove the leaf */
  319: 	    
  320: 	    state_change = 
  321: 		change_interfaces(mrtentry_srcs,
  322: 				  mrtentry_srcs->incoming,
  323: 				  mrtentry_srcs->pruned_oifs,
  324: 				  new_leaves);
  325: 
  326: 	    /* Handle transition to negative cache */
  327: 	    if(state_change == -1)
  328: 		trigger_prune_alert(mrtentry_srcs);
  329: 	}
  330:     }
  331: }
  332: 
  333: void
  334: calc_oifs(mrtentry_ptr, oifs_ptr)
  335:     mrtentry_t *mrtentry_ptr;
  336:     vifbitmap_t *oifs_ptr;
  337: {
  338:     vifbitmap_t oifs;
  339: 
  340:     /*
  341:      * oifs =
  342:      * ((nbr_ifs - my_prune) + my_leaves) - incoming_interface,
  343:      * i.e. `leaves` have higher priority than `prunes`. 
  344:      * Asserted oifs (those that lost assert) are handled as pruned oifs.
  345:      * The incoming interface is always deleted from the oifs
  346:      */
  347: 
  348:     if (mrtentry_ptr == (mrtentry_t *)NULL) {
  349:         VIFM_CLRALL(*oifs_ptr);
  350:         return;
  351:     }
  352:  
  353:     VIFM_COPY(nbr_vifs, oifs);
  354:     VIFM_CLR_MASK(oifs, mrtentry_ptr->pruned_oifs);
  355:     VIFM_MERGE(oifs, mrtentry_ptr->leaves, oifs);
  356:     VIFM_CLR(mrtentry_ptr->incoming, oifs);
  357:     VIFM_COPY(oifs, *oifs_ptr);
  358: }
  359: 
  360: 
  361: /*
  362:  * Set the iif, join/prune/leaves/asserted interfaces. Calculate and
  363:  * set the oifs.
  364:  * Return 1 if oifs change from NULL to not-NULL.
  365:  * Return -1 if oifs change from non-NULL to NULL
  366:  *  else return 0
  367:  * If the iif change or if the oifs change from NULL to non-NULL
  368:  * or vice-versa, then schedule that mrtentry join/prune timer to
  369:  * timeout immediately. 
  370:  */
  371: int
  372: change_interfaces(mrtentry_ptr, new_iif, new_pruned_oifs,
  373: 		  new_leaves_)
  374:     mrtentry_t *mrtentry_ptr;
  375:     vifi_t new_iif;
  376:     vifbitmap_t new_pruned_oifs;
  377:     vifbitmap_t new_leaves_;
  378: {
  379:     vifbitmap_t old_pruned_oifs;
  380:     vifbitmap_t old_leaves;
  381:     vifbitmap_t new_leaves;
  382:     vifbitmap_t new_real_oifs;    /* The result oifs */
  383:     vifbitmap_t old_real_oifs;
  384:     vifi_t      old_iif;
  385:     int return_value;
  386:     
  387:     if (mrtentry_ptr == (mrtentry_t *)NULL)
  388: 	return (0);
  389: 
  390:     VIFM_COPY(new_leaves_, new_leaves);
  391: 
  392:     old_iif = mrtentry_ptr->incoming;
  393:     VIFM_COPY(mrtentry_ptr->leaves, old_leaves);
  394:     VIFM_COPY(mrtentry_ptr->pruned_oifs, old_pruned_oifs);
  395: 
  396:     VIFM_COPY(mrtentry_ptr->oifs, old_real_oifs);
  397:     
  398:     mrtentry_ptr->incoming = new_iif;
  399:     VIFM_COPY(new_pruned_oifs, mrtentry_ptr->pruned_oifs);
  400:     VIFM_COPY(new_leaves, mrtentry_ptr->leaves);
  401:     calc_oifs(mrtentry_ptr, &new_real_oifs);
  402: 
  403:     if (VIFM_ISEMPTY(old_real_oifs)) {
  404: 	if (VIFM_ISEMPTY(new_real_oifs))
  405: 	    return_value = 0;
  406: 	else
  407: 	    return_value = 1;
  408:     } else {
  409: 	if (VIFM_ISEMPTY(new_real_oifs))
  410: 	    return_value = -1;
  411: 	else
  412: 	    return_value = 0;
  413:     }
  414: 
  415:     if ((VIFM_SAME(new_real_oifs, old_real_oifs))
  416: 	&& (new_iif == old_iif))
  417: 	return 0;                  /* Nothing to change */
  418: 
  419:     VIFM_COPY(new_real_oifs, mrtentry_ptr->oifs);
  420:     
  421:     k_chg_mfc(igmp_socket, mrtentry_ptr->source->address,
  422: 	      mrtentry_ptr->group->group, new_iif, new_real_oifs);
  423: 
  424: #ifdef RSRR
  425:     rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
  426: #endif /* RSRR */
  427: 
  428:     return (return_value);
  429: }
  430:     
  431: 
  432: /* TODO: implement it. Required to allow changing of the physical interfaces
  433:  * configuration without need to restart pimd.
  434:  */
  435: int
  436: delete_vif_from_mrt(vifi)
  437: vifi_t vifi;
  438: {
  439:     return TRUE;
  440: }
  441: 
  442: 
  443: static u_int16
  444: max_prune_timeout(mrtentry_ptr)
  445:      mrtentry_t *mrtentry_ptr;
  446: {
  447:     vifi_t vifi;
  448:     u_int16 time_left, max_holdtime = 0;
  449: 
  450:     for(vifi=0; vifi < numvifs; ++vifi) 
  451: 	if(VIFM_ISSET(vifi, mrtentry_ptr->pruned_oifs))
  452: 	    IF_TIMER_SET(mrtentry_ptr->prune_timers[vifi]) 
  453: 		/* XXX - too expensive ? */
  454: 		/* XXX: TIMER implem. dependency! */
  455: 		if(mrtentry_ptr->prune_timers[vifi] > max_holdtime) 
  456: 		    max_holdtime = time_left;
  457:     
  458:     if(max_holdtime == 0) 
  459: 	max_holdtime = (u_int16)PIM_JOIN_PRUNE_HOLDTIME;
  460: 
  461:     return(max_holdtime);
  462: }
  463: 
  464: 
  465: void process_kernel_call()
  466: {
  467:     register struct igmpmsg *igmpctl; /* igmpmsg control struct */
  468:     
  469:     igmpctl = (struct igmpmsg *) igmp_recv_buf;
  470:     
  471:     switch (igmpctl->im_msgtype) {
  472:     case IGMPMSG_NOCACHE:
  473: 	process_cache_miss(igmpctl);
  474: 	break;
  475:     case IGMPMSG_WRONGVIF:
  476: 	process_wrong_iif(igmpctl);
  477: 	break;
  478:     default:
  479: 	IF_DEBUG(DEBUG_KERN)
  480: 	    log(LOG_DEBUG, 0, "Unknown kernel_call code");
  481: 	break;
  482:     }
  483: }
  484: 
  485: 
  486: /*
  487:  * Protocol actions:
  488:  *   1. Create (S,G) entry (find_route(CREATE))
  489:  *      a. set iif and oifs
  490:  */
  491: static void
  492: process_cache_miss(igmpctl)
  493:     struct igmpmsg *igmpctl;
  494: {
  495:     u_int32 source;
  496:     u_int32 group;
  497:     mrtentry_t *mrtentry_ptr;
  498: 
  499:     /*
  500:      * When there is a cache miss, we check only the header of the packet
  501:      * (and only it should be sent up by the kernel.
  502:      */
  503: 
  504:     group  = igmpctl->im_dst.s_addr;
  505:     source = igmpctl->im_src.s_addr;
  506:     
  507:     IF_DEBUG(DEBUG_MFC)
  508: 	log(LOG_DEBUG, 0, "Cache miss, src %s, dst %s",
  509: 	    inet_fmt(source, s1), inet_fmt(group, s2)); 
  510: 
  511:     /* Don't create routing entries for the LAN scoped addresses */
  512:     if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
  513: 	return; 
  514:     
  515:     /* Create the (S,G) entry */
  516:     mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE);
  517:     if (mrtentry_ptr == (mrtentry_t *)NULL)
  518: 	return;
  519:     mrtentry_ptr->flags &= ~MRTF_NEW;
  520:     
  521:     /* Initialize Entry Timer */
  522:     SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
  523:     
  524:     /* Set oifs */	
  525:     set_leaves(mrtentry_ptr);
  526:     calc_oifs(mrtentry_ptr, &(mrtentry_ptr->oifs));
  527: 
  528:     /* Add it to the kernel */
  529:     k_chg_mfc(igmp_socket, source, group, mrtentry_ptr->incoming,
  530: 	      mrtentry_ptr->oifs);
  531: 
  532: #ifdef RSRR
  533:     rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
  534: #endif /* RSRR */
  535: 
  536:     /* No need to call change_interfaces, but check for NULL oiflist */
  537:     if(VIFM_ISEMPTY(mrtentry_ptr->oifs))
  538: 	trigger_prune_alert(mrtentry_ptr);
  539: }
  540: 
  541: 
  542: /*
  543:  * A multicast packet has been received on wrong iif by the kernel.
  544:  * If the packet was received on a point-to-point interface, rate-limit
  545:  * prunes.  if the packet was received on a LAN interface, rate-limit 
  546:  * asserts.
  547:  */
  548: static void
  549: process_wrong_iif(igmpctl)
  550:     struct igmpmsg *igmpctl;
  551: {
  552:     u_int32 source;
  553:     u_int32 group;
  554:     vifi_t  vifi;
  555:     mrtentry_t *mrtentry_ptr;
  556: 
  557:     group  = igmpctl->im_dst.s_addr;
  558:     source = igmpctl->im_src.s_addr;
  559:     vifi   = igmpctl->im_vif;
  560: 
  561:     /* PIMDM TODO Don't create routing entries for the LAN scoped addresses */
  562:     if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
  563: 	return;
  564: 
  565:     /* Ratelimit prunes or asserts */
  566:     if(uvifs[vifi].uv_flags & VIFF_POINT_TO_POINT) {
  567: 
  568: 	mrtentry_ptr = find_route(source, group, MRTF_SG, DONT_CREATE);
  569: 	if(mrtentry_ptr == (mrtentry_t *)NULL)
  570: 	    return;
  571: 
  572: 	/* Wrong vif on P2P interface - rate-limit prunes */
  573: 
  574: 	if(mrtentry_ptr->last_prune[vifi] == virtual_time)
  575: 	    /* Skip due to rate-limiting */
  576: 	    return;
  577: 	mrtentry_ptr->last_prune[vifi] = virtual_time;
  578: 
  579: 	if(uvifs[vifi].uv_rmt_addr)
  580: 	    send_pim_jp(mrtentry_ptr, PIM_ACTION_PRUNE, vifi, 
  581: 			uvifs[vifi].uv_rmt_addr, 
  582: 			max_prune_timeout(mrtentry_ptr));
  583: 	else 
  584: 	    log(LOG_WARNING, 0, 
  585: 		"Can't send wrongvif prune on p2p %s: no remote address",
  586: 		uvifs[vifi].uv_lcl_addr);
  587:     } else {
  588: 	u_int32 pref, metric;
  589: 
  590: 	/* Wrong vif on LAN interface - rate-limit asserts */
  591: 
  592: 	mrtentry_ptr = find_route(source, group, MRTF_SG, DONT_CREATE);
  593: 	if(mrtentry_ptr == (mrtentry_t *)NULL) {
  594: 	    pref = 0x7fffffff;
  595: 	    metric = 0x7fffffff;
  596: 	}
  597: 	else {
  598: 	    pref = mrtentry_ptr->source->preference;
  599: 	    metric = mrtentry_ptr->source->metric;
  600: 	}
  601: 	    
  602: 	if(mrtentry_ptr->last_assert[vifi] == virtual_time)
  603: 	    /* Skip due to rate-limiting */
  604: 	    return;
  605: 	mrtentry_ptr->last_assert[vifi] = virtual_time;
  606: 
  607: 	/* Send the assert */
  608: 	send_pim_assert(source, group, vifi, pref, metric);
  609:     }
  610: }
  611: 
  612: 
  613: void trigger_prune_alert(mrtentry_ptr)
  614:      mrtentry_t *mrtentry_ptr;
  615: {
  616:     IF_DEBUG(DEBUG_MRT)
  617: 	log(LOG_DEBUG, 0, "Now negative cache for src %s, grp %s - pruning",
  618: 	    inet_fmt(mrtentry_ptr->source->address, s1), 
  619: 	    inet_fmt(mrtentry_ptr->group->group, s2));
  620: 
  621:     /* Set the entry timer to the max of the prune timers */
  622:     SET_TIMER(mrtentry_ptr->timer, max_prune_timeout(mrtentry_ptr));
  623: 
  624:     /* Send a prune */
  625:     if(mrtentry_ptr->upstream) 
  626: 	send_pim_jp(mrtentry_ptr, PIM_ACTION_PRUNE, mrtentry_ptr->incoming,
  627: 		    mrtentry_ptr->upstream->address, 
  628: 		    max_prune_timeout(mrtentry_ptr));
  629: }
  630: 
  631: void trigger_join_alert(mrtentry_ptr)
  632:      mrtentry_t *mrtentry_ptr;
  633: {
  634:     IF_DEBUG(DEBUG_MRT)
  635: 	log(LOG_DEBUG, 0, "Now forwarding state for src %s, grp %s - grafting",
  636: 	    inet_fmt(mrtentry_ptr->source->address, s1), 
  637: 	    inet_fmt(mrtentry_ptr->group->group, s2));
  638: 
  639:     /* Refresh the entry timer */
  640:     SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
  641: 
  642:     /* Send graft */
  643:     send_pim_graft(mrtentry_ptr);
  644: }

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