Ejemplo n.º 1
0
mrtentry_t *find_route(u_int32 source, u_int32 group, u_int16 flags, char create)
{
    srcentry_t *src	     = NULL;
    grpentry_t *grp	     = NULL;
    mrtentry_t *mrt	     = NULL;
    mrtentry_t *mrt_wc	     = NULL;
    mrtentry_t *mrt_pmbr    = NULL;
    mrtentry_t *mrt2	     = NULL;
    rpentry_t  *rp	     = NULL;
    rp_grp_entry_t *rp_grp = NULL;

    if (flags & (MRTF_SG | MRTF_WC)) {
	if (!IN_MULTICAST(ntohl(group)))
	    return NULL;
    }

    if (flags & MRTF_SG) {
	if (!inet_valid_host(source))
	    return NULL;
    }

    if (create == DONT_CREATE) {
	if (flags & (MRTF_SG | MRTF_WC)) {
	    if (search_grplist(group, &grp) == FALSE) {
		/* Group not found. Return the (*,*,RP) entry */
		if (flags & MRTF_PMBR) {
		    rp = rp_match(group);
		    if (rp)
			return rp->mrtlink;
		}

		return NULL;
	    }

	    /* Search for the source */
	    if (flags & MRTF_SG) {
		if (search_grpmrtlink(grp, source, &mrt) == TRUE) {
		    /* Exact (S,G) entry found */
		    return mrt;
		}
	    }

	    /* No (S,G) entry. Return the (*,G) entry (if exist) */
	    if ((flags & MRTF_WC) && grp->grp_route)
		return grp->grp_route;
	}

	/* Return the (*,*,RP) entry */
	if (flags & MRTF_PMBR) {
	    rp = NULL;
	    if (group != INADDR_ANY_N)
		rp = rp_match(group);
	    else if (source != INADDR_ANY_N)
		rp = rp_find(source);

	    if (rp)
		return rp->mrtlink;
	}

	return NULL;
    }


    /* Creation allowed */

    if (flags & (MRTF_SG | MRTF_WC)) {
	grp = create_grpentry(group);
	if (!grp)
	    return NULL;

	if (!grp->active_rp_grp) {
	    rp_grp = rp_grp_match(group);
	    if (!rp_grp) {
		if (!grp->mrtlink && !grp->grp_route) {
		    /* New created grpentry. Delete it. */
		    delete_grpentry(grp);
		}

		return NULL;
	    }

	    rp = rp_grp->rp->rpentry;
	    grp->active_rp_grp = rp_grp;
	    grp->rpaddr = rp->address;

	    /* Link to the top of the rp_grp_chain */
	    grp->rpnext = rp_grp->grplink;
	    rp_grp->grplink = grp;
	    if (grp->rpnext)
		grp->rpnext->rpprev = grp;
	}
	else {
	    rp = grp->active_rp_grp->rp->rpentry;
	}
    }

    mrt_wc = mrt_pmbr = NULL;

    if (flags & MRTF_WC) {
	/* Setup the (*,G) routing entry */
	mrt_wc = create_mrtentry(NULL, grp, MRTF_WC);
	if (!mrt_wc) {
	    if (!grp->mrtlink) {
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);
	    }

	    return NULL;
	}

	if (mrt_wc->flags & MRTF_NEW) {
	    mrt_pmbr = rp->mrtlink;
	    /* Copy the oif list from the (*,*,RP) entry */
	    if (mrt_pmbr) {
		VOIF_COPY(mrt_pmbr, mrt_wc);
	    }
	    mrt_wc->incoming = rp->incoming;
	    mrt_wc->upstream = rp->upstream;
	    mrt_wc->metric   = rp->metric;
	    mrt_wc->preference = rp->preference;
	    move_kernel_cache(mrt_wc, 0);
#ifdef RSRR
	    rsrr_cache_bring_up(mrt_wc);
#endif /* RSRR */
	}

	if (!(flags & MRTF_SG)) {
	    return mrt_wc;
	}
    }

    if (flags & MRTF_SG) {
	/* Setup the (S,G) routing entry */
	src = create_srcentry(source);
	if (!src) {
	    /* TODO: XXX: The MRTF_NEW flag check may be misleading?? check */
	    if ((!grp->grp_route || (grp->grp_route && (grp->grp_route->flags & MRTF_NEW)))
		&& !grp->mrtlink) {
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);
	    }

	    return NULL;
	}

	mrt = create_mrtentry(src, grp, MRTF_SG);
	if (!mrt) {
	    if ((!grp->grp_route
		 || (grp->grp_route && (grp->grp_route->flags & MRTF_NEW)))
		&& !grp->mrtlink) {
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);
	    }

	    if (!src->mrtlink)
		/* New created srcentry. Delete it. */
		delete_srcentry(src);

	    return NULL;
	}

	if (mrt->flags & MRTF_NEW) {
	    mrt2 = grp->grp_route;
	    if (!mrt2)
		mrt2 = rp->mrtlink;

	    /* Copy the oif list from the existing (*,G) or (*,*,RP) entry */
	    if (mrt2) {
		VOIF_COPY(mrt2, mrt);
		if (flags & MRTF_RP) {
		    /* ~(S,G) prune entry */
		    mrt->incoming    = mrt2->incoming;
		    mrt->upstream    = mrt2->upstream;
		    mrt->metric      = mrt2->metric;
		    mrt->preference  = mrt2->preference;
		    mrt->flags      |= MRTF_RP;
		}
	    }

	    if (!(mrt->flags & MRTF_RP)) {
		mrt->incoming   = src->incoming;
		mrt->upstream   = src->upstream;
		mrt->metric     = src->metric;
		mrt->preference = src->preference;
	    }
	    move_kernel_cache(mrt, 0);
#ifdef RSRR
	    rsrr_cache_bring_up(mrt);
#endif /* RSRR */
	}

	return mrt;
    }

    if (flags & MRTF_PMBR) {
	/* Get/return the (*,*,RP) routing entry */
	if (group != INADDR_ANY_N) {
	    rp = rp_match(group);
	} else if (source != INADDR_ANY_N) {
	    rp = rp_find(source);
	    if (!rp)
		return NULL;
	} else {
	    return NULL; /* source == group == INADDR_ANY */
	}

	if (rp->mrtlink)
	    return rp->mrtlink;

	mrt = create_mrtentry(rp, NULL, MRTF_PMBR);
	if (!mrt)
	    return NULL;

	mrt->incoming = rp->incoming;
	mrt->upstream = rp->upstream;
	mrt->metric   = rp->metric;
	mrt->preference = rp->preference;

	return mrt;
    }

    return NULL;
}
Ejemplo n.º 2
0
Archivo: mrt.c Proyecto: wgc1212/pimd
mrtentry_t *find_route(uint32_t source, uint32_t group, uint16_t flags, char create)
{
    srcentry_t *src	   = NULL;
    grpentry_t *grp	   = NULL;
    mrtentry_t *mrt	   = NULL;
    mrtentry_t *mrt_wc	   = NULL;
    mrtentry_t *mrt_pmbr   = NULL;
    mrtentry_t *mrt2	   = NULL;
    rpentry_t  *rp	   = NULL;
    rp_grp_entry_t *rp_grp = NULL;

    if (flags & (MRTF_SG | MRTF_WC)) {
	if (!IN_MULTICAST(ntohl(group))) {
	    logit(LOG_WARNING, 0, "find_route: Not a multicast group address (%s) ...",
		  inet_fmt(group, s1, sizeof(s1)));
	    return NULL;
	}
    }

    if (flags & MRTF_SG) {
	if (!inet_valid_host(source) && !IN_PIM_SSM_RANGE(group)) {
	    logit(LOG_WARNING, 0, "find_route: Not a valid host (%s) ...",
		  inet_fmt(source, s1, sizeof(s1)));
	    return NULL;
	}
    }

    if (create == DONT_CREATE) {
	if (flags & (MRTF_SG | MRTF_WC)) {
	    if (search_grplist(group, &grp) == FALSE) {
		/* Group not found. Return the (*,*,RP) entry */
		if (flags & MRTF_PMBR) {
		    rp = rp_match(group);
		    if (rp) {
			logit(LOG_DEBUG, 0 , "find_route: Group not found. Return the (*,*,RP) entry");
			return rp->mrtlink;
		    }
		}

		logit(LOG_DEBUG, 0 , "find_route: Not PMBR, return NULL");
		return NULL;
	    }

	    /* Search for the source */
	    if (flags & MRTF_SG) {
		if (search_grpmrtlink(grp, source, &mrt) == TRUE) {
		    /* Exact (S,G) entry found */
		    logit(LOG_DEBUG, 0 , "find_route: exact (S,G) entry found");
		    return mrt;
		}

		logit(LOG_DEBUG, 0 , "find_route:(S,G) entry not found");
	    }

	    /* No (S,G) entry. Return the (*,G) entry (if exist) */
	    if ((flags & MRTF_WC) && grp->grp_route) {
		logit(LOG_DEBUG, 0 , "find_route: No (S,G) entry. Return the (*,G) entry");
		return grp->grp_route;
	    }
	}

	/* Return the (*,*,RP) entry */
	if (flags & MRTF_PMBR) {
	    rp = NULL;
	    if (group != INADDR_ANY_N)
		rp = rp_match(group);
	    else if (source != INADDR_ANY_N)
		rp = rp_find(source);

	    if (rp) {
		logit(LOG_DEBUG, 0 , "find_route: Return the (*,*,RP) entry");
		return rp->mrtlink;
	    }
	}

	logit(LOG_DEBUG, 0 , "find_route: No SG|WC, return NULL");
	return NULL;
    }


    /* Creation allowed */

    if (flags & (MRTF_SG | MRTF_WC)) {
	grp = create_grpentry(group);
	if (!grp)
	    return NULL;

	if (IN_PIM_SSM_RANGE(group)) {
	    if (rp_match(group) == (rpentry_t *) NULL) {
		/* For SSM, virtual RP entry has to be created. RP is at local link 169.254.0.1
		   to be sure not to send any register messages outside, although sending them
		   has been disabled for SSM also in PIM protocol.
		   The address does not need to be really configured in any interface.
		   TODO: Avoid need for virtual RP by implementing SSM-specific state structures */
		add_rp_grp_entry(&cand_rp_list, &grp_mask_list, htonl(0xa9fe0001), 20, 90, group,
				 0xffffffff, curr_bsr_hash_mask, curr_bsr_fragment_tag);
	    }
	}

	if (!grp->active_rp_grp) {
	    rp_grp = rp_grp_match(group);
	    if (!rp_grp) {
		if (!grp->mrtlink && !grp->grp_route)
		    /* New created grpentry. Delete it. */
		    delete_grpentry(grp);

		return NULL;
	    }

	    rp = rp_grp->rp->rpentry;
	    grp->active_rp_grp = rp_grp;
	    grp->rpaddr = rp->address;

	    /* Link to the top of the rp_grp_chain */
	    grp->rpnext = rp_grp->grplink;
	    rp_grp->grplink = grp;
	    if (grp->rpnext)
		grp->rpnext->rpprev = grp;
	} else {
	    rp = grp->active_rp_grp->rp->rpentry;
	}
    }

    mrt_wc = mrt_pmbr = NULL;

    if (flags & MRTF_WC) {
	/* Setup the (*,G) routing entry */
	mrt_wc = create_mrtentry(NULL, grp, MRTF_WC);
	if (!mrt_wc) {
	    if (!grp->mrtlink)
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);

	    return NULL;
	}

	if (mrt_wc->flags & MRTF_NEW) {
	    mrt_pmbr = rp->mrtlink;

	    /* Copy the oif list from the (*,*,RP) entry */
	    if (mrt_pmbr)
		VOIF_COPY(mrt_pmbr, mrt_wc);

	    mrt_wc->incoming = rp->incoming;
	    mrt_wc->upstream = rp->upstream;
	    mrt_wc->metric   = rp->metric;
	    mrt_wc->preference = rp->preference;
	    move_kernel_cache(mrt_wc, 0);
#ifdef RSRR
	    rsrr_cache_bring_up(mrt_wc);
#endif /* RSRR */
	}

	if (!(flags & MRTF_SG))
	    return mrt_wc;
    }

    if (flags & MRTF_SG) {
	/* Setup the (S,G) routing entry */
	src = create_srcentry(source);
	if (!src) {
	    /* TODO: XXX: The MRTF_NEW flag check may be misleading?? check */
	    if ((!grp->grp_route || (grp->grp_route && (grp->grp_route->flags & MRTF_NEW)))
		&& !grp->mrtlink) {
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);
	    }

	    return NULL;
	}

	mrt = create_mrtentry(src, grp, MRTF_SG);
	if (!mrt) {
	    if ((!grp->grp_route
		 || (grp->grp_route && (grp->grp_route->flags & MRTF_NEW)))
		&& !grp->mrtlink) {
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);
	    }

	    if (!src->mrtlink)
		/* New created srcentry. Delete it. */
		delete_srcentry(src);

	    return NULL;
	}

	if (mrt->flags & MRTF_NEW) {
	    mrt2 = grp->grp_route;
	    if (!mrt2)
		mrt2 = rp->mrtlink;

	    /* Copy the oif list from the existing (*,G) or (*,*,RP) entry */
	    if (mrt2) {
		VOIF_COPY(mrt2, mrt);
		if (flags & MRTF_RP) {
		    /* ~(S,G) prune entry */
		    mrt->incoming    = mrt2->incoming;
		    mrt->upstream    = mrt2->upstream;
		    mrt->metric      = mrt2->metric;
		    mrt->preference  = mrt2->preference;
		    mrt->flags      |= MRTF_RP;
		}
	    }

	    if (!(mrt->flags & MRTF_RP)) {
		mrt->incoming   = src->incoming;
		mrt->upstream   = src->upstream;
		mrt->metric     = src->metric;
		mrt->preference = src->preference;
	    }
	    move_kernel_cache(mrt, 0);
#ifdef RSRR
	    rsrr_cache_bring_up(mrt);
#endif /* RSRR */
	}

	return mrt;
    }

    if (flags & MRTF_PMBR) {
	/* Get/return the (*,*,RP) routing entry */
	if (group != INADDR_ANY_N)
	    rp = rp_match(group);
	else if (source != INADDR_ANY_N)
	    rp = rp_find(source);
	else
	    return NULL; /* source == group == INADDR_ANY */

	if (!rp)
	    return NULL;

	if (rp->mrtlink)
	    return rp->mrtlink;

	mrt = create_mrtentry(rp, NULL, MRTF_PMBR);
	if (!mrt)
	    return NULL;

	mrt->incoming   = rp->incoming;
	mrt->upstream   = rp->upstream;
	mrt->metric     = rp->metric;
	mrt->preference = rp->preference;

	return mrt;
    }

    return NULL;
}