Пример #1
0
/**
 * parseBSR - Parse the candidate BSR configured information.
 * @s: String token
 *
 * Syntax:
 * cand_bootstrap_router [address | ifname] [priority <0-255>]
 */
int parseBSR(char *s)
{
    char *w;
    uint32_t local    = INADDR_ANY_N;
    uint32_t priority = PIM_DEFAULT_BSR_PRIORITY;

    cand_bsr_flag = FALSE;
    while (!EQUAL((w = next_word(&s)), "")) {
	if (EQUAL(w, "priority")) {
	    if (EQUAL((w = next_word(&s)), "")) {
		WARN("Missing Cand-BSR priority, defaulting to %u", PIM_DEFAULT_BSR_PRIORITY);
		priority = PIM_DEFAULT_BSR_PRIORITY;
		continue;
	    }

	    if (sscanf(w, "%u", &priority) != 1) {
		WARN("Invalid Cand-BSR priority %s, defaulting to %u", PIM_DEFAULT_BSR_PRIORITY);
		priority = PIM_DEFAULT_BSR_PRIORITY;
		continue;
	    }

	    if (priority > PIM_MAX_CAND_BSR_PRIORITY) {
		WARN("Too high Cand-BSR priority %u, defaulting to %d", priority, PIM_MAX_CAND_BSR_PRIORITY);
		priority = PIM_MAX_CAND_BSR_PRIORITY;
	    }

	    my_bsr_priority = (u_int8)priority;
	    continue;
	}

	/* Cand-BSR interface or address */
	local = ifname2addr(w);
	if (!local)
	    local = inet_parse(w, 4);

	if (!inet_valid_host(local)) {
	    local = max_local_address();
	    WARN("Invalid Cand-BSR address '%s', defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
	    continue;
	}

	if (local_address(local) == NO_VIF) {
	    local = max_local_address();
	    WARN("Cand-BSR address '%s' is not local, defaulting to %s", w, inet_fmt(local, s1, sizeof(s1)));
	}
    }

    if (local == INADDR_ANY_N) {
	/* If address not provided, use the max. local */
	local = max_local_address();
    }

    my_bsr_address  = local;
    my_bsr_priority = priority;
    MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, my_bsr_hash_mask);
    cand_bsr_flag   = TRUE;
    logit(LOG_INFO, 0, "Local Cand-BSR address %s, priority %u", inet_fmt(local, s1, sizeof(s1)), priority);

    return TRUE;
}
Пример #2
0
/*
 * Leave a multicast group on virtual interface 'v'.
 */
void k_leave(int socket, u_int32 grp, struct uvif *v)
{
#ifdef __linux__
    struct ip_mreqn mreq;
#else
    struct ip_mreq mreq;
#endif /* __linux__ */

#ifdef __linux__
    mreq.imr_ifindex	      = v->uv_ifindex;
    mreq.imr_address.s_addr   = v->uv_lcl_addr;
#else
    mreq.imr_interface.s_addr = v->uv_lcl_addr;
#endif /* __linux__ */
    mreq.imr_multiaddr.s_addr = grp;

    if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) {
#ifdef __linux__
	logit(LOG_WARNING, errno,
	      "Cannot leave group %s on interface %s (ifindex %d)",
	      inet_fmt(grp, s1, sizeof(s1)), inet_fmt(v->uv_lcl_addr, s2, sizeof(s2)), v->uv_ifindex);
#else
	logit(LOG_WARNING, errno,
	      "Cannot leave group %s on interface %s",
	      inet_fmt(grp, s1, sizeof(s1)), inet_fmt(v->uv_lcl_addr, s2, sizeof(s2)));
#endif /* __linux__ */
    }
}
Пример #3
0
/*
 * Start routing on all virtual interfaces that are not down or
 * administratively disabled.
 */
void init_installvifs(void)
{
    vifi_t vifi;
    struct uvif *v;

    logit(LOG_INFO, 0, "Installing vifs in kernel...");
    for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
	if (!(v->uv_flags & VIFF_DISABLED)) {
	    if (!(v->uv_flags & VIFF_DOWN)) {
		if (v->uv_flags & VIFF_TUNNEL) {
		    logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
			  inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
			  inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)));
		} else {
		    logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
			  inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
		}
		k_add_vif(vifi, &uvifs[vifi]);
	    } else {
		logit(LOG_INFO, 0, "%s is not yet up; vif #%u not in service",
		      v->uv_name, vifi);
	    }
	}
    }
}
Пример #4
0
JNIEXPORT void JNICALL Java_ow_ipmulticast_Native_sendMulticast(JNIEnv *env, jclass clazz,
		jint srcaddr, jint srcport, jint destaddr, jint destport, jint id, jint ttl, jint datalen, jbyteArray jdata) {
	jsize datasize;
	jbyte *data;

	srcaddr = htonl(srcaddr);
	destaddr = htonl(destaddr);

	if (jdata != NULL) {
		datasize = (*env)->GetArrayLength(env, jdata);
		data = (*env)->GetByteArrayElements(env, jdata, NULL);
	}
	else {
		datasize = 0;
		data = NULL;
	}

	if (datalen > datasize) {
		datalen = datasize;
	}
#if 0
printf("send\n");
printf("  src:   %s\n", inet_fmt(srcaddr, s1));
printf("  dest:  %s:%d\n", inet_fmt(destaddr, s1), destport);
printf("  datasize: %d\n", datasize);
printf("  datalen:  %d\n", datalen);
fflush(stdout);
#endif

	send_dgram((uint32_t)srcaddr, (uint16_t)srcport, (uint32_t)destaddr, (uint16_t)destport, (uint16_t)id, (uint8_t)ttl, (char *)data, (int)datalen);

	if (jdata != NULL) {
		(*env)->ReleaseByteArrayElements(env, jdata, data, JNI_ABORT);
	}
}
Пример #5
0
JNIEXPORT void JNICALL Java_ow_ipmulticast_Native_sendIGMP(JNIEnv *env, jclass clazz,
		jint src, jint dest, jint type, jint code, jint group, jbyteArray jdata) {
	jsize datalen;
	jbyte *data;

	src = htonl(src);
	dest = htonl(dest);
	group = htonl(group);

	if (jdata != NULL) {
		datalen = (*env)->GetArrayLength(env, jdata);
		data = (*env)->GetByteArrayElements(env, jdata, NULL);
	}
	else {
		datalen = 0;
		data = NULL;
	}
#if 0
printf("send\n");
printf("  src:   %s\n", inet_fmt(src, s1));
printf("  dest:  %s\n", inet_fmt(dest, s1));
printf("  group: %s\n", inet_fmt(group, s1));
printf("  datalen: %d\n", datalen);
fflush(stdout);
#endif

	send_igmp((uint32_t)src, (uint32_t)dest, (int)type, (int)code, (uint32_t)group, (char *)data, (int)datalen);

	if (jdata != NULL) {
		(*env)->ReleaseByteArrayElements(env, jdata, data, JNI_ABORT);
	}
}
Пример #6
0
/*
 * Dumps the local Cand-RP-set
 */
int dump_rp_set(FILE *fp)
{
    cand_rp_t      *rp;
    rp_grp_entry_t *rpgrp;

    fprintf(fp, "Candidate Rendezvous-Point Set ===============================================\n");
    fprintf(fp, "RP address       Incoming  Group Prefix        Priority  Holdtime\n");
    fprintf(fp, "---------------  --------  ------------------  --------  ---------------------\n");
    for (rp = cand_rp_list; rp; rp = rp->next) {
	fprintf(fp, "%-15s  %-8d  ",
		inet_fmt(rp->rpentry->address, s1, sizeof(s1)),
		rp->rpentry->incoming);

	rpgrp = rp->rp_grp_next;
	if (rpgrp) {
	    dump_rpgrp(fp, rpgrp, 0);

	    for (rpgrp = rpgrp->rp_grp_next; rpgrp; rpgrp = rpgrp->rp_grp_next)
		dump_rpgrp(fp, rpgrp, 1);
	}
    }

    fprintf(fp, "------------------------------------------------------------------------------\n");
    fprintf(fp, "Current BSR address: %s\n\n", inet_fmt(curr_bsr_address, s1, sizeof(s1)));

    return TRUE;
}
Пример #7
0
void delete_single_kernel_cache(mrtentry_t *mrt, kernel_cache_t *node)
{
    if (!mrt || !node)
	return;

    if (!node->prev) {
	mrt->kernel_cache = node->next;
	if (!mrt->kernel_cache)
	    mrt->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
    } else {
	node->prev->next = node->next;
    }

    if (node->next)
	node->next->prev = node->prev;

    IF_DEBUG(DEBUG_MFC) {
	logit(LOG_DEBUG, 0, "Deleting MFC entry for source %s and group %s",
	      inet_fmt(node->source, s1, sizeof(s1)),
	      inet_fmt(node->group, s2, sizeof(s2)));
    }

    k_del_mfc(igmp_socket, node->source, node->group);
    free(node);
}
Пример #8
0
void pim_input()
{//接收,检查报文类型,交由相应的函数处理
	int length;
	u_int32 src,dst;
	struct ip *ip;
	struct pim *pim;
	int iphdrlen,pimlen;
	
	length=recvfrom(pimsocket,pim_receive_buf,64*1024,0,NULL,NULL);

	if(length<sizeof(struct ip))
	{
		log(LOG_INFO,"PIM packet too short,receive failed!");
	}

	ip=(struct ip *)pim_receive_buf;
	src=ip->ip_src.s_addr;
	dst=ip->ip_dst.s_addr;
	iphdrlen=ip->ip_hl<<2;

	pim=(struct pim *)(pim_receive_buf+iphdrlen);
	pimlen=length-iphdrlen;

	if (pimlen<sizeof(pim)) 
	{
		log(LOG_INFO,"PIM packet too short,receive failed!");
		return;
    }
    
    switch (pim->pim_type) 
	{
		case PIM_HELLO:
			receive_hello(src,dst,(char *)(pim),pimlen);
		return;
	
		case PIM_JOIN_PRUNE:
			receive_join_prune(src,dst,(char *)(pim),pimlen);
		return;
	
		case PIM_ASSERT:
			receive_assert(src,dst,(char *)(pim),pimlen);
		return;
		
		case PIM_GRAFT:
			receive_pim_graft(src,dst,(char *)(pim),pimlen);
		return;
		
		case PIM_GRAFT_ACK:
			receive_pim_graft_ack(src,dst,(char *)(pim),pimlen);
		return;

		default:
			log(LOG_INFO,"ignoring unused PIM packet from %s to %s",inet_fmt(src, s1), inet_fmt(dst, s2));
		return;
    }
}
Пример #9
0
Файл: mrt.c Проект: wgc1212/pimd
void delete_single_kernel_cache_addr(mrtentry_t *mrt, uint32_t source, uint32_t group)
{
    uint32_t source_h;
    uint32_t group_h;
    kernel_cache_t *node;

    if (!mrt)
	return;

    source_h = ntohl(source);
    group_h  = ntohl(group);

    /* Find the exact (S,G) kernel_cache entry */
    for (node = mrt->kernel_cache; node; node = node->next) {
	if (ntohl(node->group) < group_h)
	    continue;
	if (ntohl(node->group) > group_h)
	    return;	/* Not found */
	if (ntohl(node->source) < source_h)
	    continue;
	if (ntohl(node->source) > source_h)
	    return;	/* Not found */

	/* Found exact match */
	break;
    }

    if (!node)
	return;

    /* Found. Delete it */
    if (!node->prev) {
	mrt->kernel_cache = node->next;
	if (!mrt->kernel_cache)
	    mrt->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
    } else{
	node->prev->next = node->next;
    }

    if (node->next)
	node->next->prev = node->prev;

    IF_DEBUG(DEBUG_MFC) {
	logit(LOG_DEBUG, 0, "Deleting MFC entry for source %s and group %s",
	      inet_fmt(node->source, s1, sizeof(s1)),
	      inet_fmt(node->group, s2, sizeof(s2)));
    }

    logit(LOG_DEBUG, 0, "delete_single_kernel_cache_addr: SG");
    k_del_mfc(igmp_socket, node->source, node->group);
    free(node);
}
Пример #10
0
/*
 * Print the contents of the routing table on file 'fp'.
 */
void
dump_routes(FILE *fp)
{
    register struct rtentry *r;
    register vifi_t i;


    fprintf(fp,
            "Multicast Routing Table (%u %s)\n%s\n",
            nroutes, (nroutes == 1) ? "entry" : "entries",
            " Origin-Subnet      From-Gateway    Metric Tmr In-Vif  Out-Vifs");

    for (r = routing_table; r != NULL; r = r->rt_next) {

        fprintf(fp, " %-18s %-15s ",
                inet_fmts(r->rt_origin, r->rt_originmask, s1),
                (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2));

        fprintf(fp, (r->rt_metric == UNREACHABLE) ? "  NR " : "%4u ",
                r->rt_metric);

        fprintf(fp, "  %3u %3u   ", r->rt_timer, r->rt_parent);

        for (i = 0; i < numvifs; ++i) {
            if (VIFM_ISSET(i, r->rt_children)) {
                fprintf(fp, " %u%c",
                        i, VIFM_ISSET(i, r->rt_leaves) ? '*' : ' ');
            }
        }
        fprintf(fp, "\n");
    }
    fprintf(fp, "\n");
}
Пример #11
0
void pim_assert_output(u_int32 source,u_int32 group,vifi_t vif,u_int32 preference,u_int32 metric)
{//发送assert
	char *mydata;
	struct encode_unicast_option *unicast_option;
	struct encode_group_address *group_address;
	u_int32 *mypreference;
	u_int32 *mymetric;
	u_int32 *unicast_address;
	int length;

	mydata=(char *)(pim_send_buf+sizeof(struct ip)+sizeof(struct pim));
	group_address=(struct encode_group_address *)mydata;
	group_address->address_family=1;
	group_address->encode_type=0;
	group_address->reserved=0;
	group_address->mask_len=32;
	group_address->group_address=group;
	
	mydata=mydata+sizeof(struct encode_group_address);
	unicast_option=(struct encode_unicast_option *)mydata;
	unicast_option->address_family=1;//协议族是ipv4
	unicast_option->encode_type=0;
	mydata=mydata+sizeof(struct encode_unicast_option);
	unicast_address=(u_int32 *)mydata;
	*unicast_address=source;

	mydata=mydata+sizeof(u_int32);
	mypreference=(u_int32 *)mydata;
	*mypreference=preference;
	
	mydata=mydata+sizeof(u_int32);
	mymetric=(u_int32 *)mydata;
	*mymetric=metric;

	length=sizeof(struct encode_group_address)+sizeof(struct encode_group_address)+2*sizeof(u_int32);
	if(pimdm_output(pim_send_buf,myvifs[vif].address,allpimrouters,PIM_ASSERT,length)!=1)
	{
		log(LOG_INFO,"Send Pim Assert Packet On %s(%s) Error!",myvifs[vif].name,inet_fmt(myvifs[vif].address,s1));
	}
	else
	{
		log(LOG_INFO,"Send Pim Assert Packet On %s(%s) Success!",myvifs[vif].name,inet_fmt(myvifs[vif].address,s1));
	
	}	
	return;
}
Пример #12
0
/**
 * parse_group_prefix - Parse group_prefix configured information.
 * @s: String token

 * Syntax:
 * group_prefix <group-addr>[/<masklen>]
 *              <group-addr> [masklen <masklen>]
 *
 * Returns:
 * %TRUE if the parsing was successful, o.w. %FALSE
 */
int parse_group_prefix(char *s)
{
    char *w;
    uint32_t group_addr;
    uint32_t  masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;

    w = next_word(&s);
    if (EQUAL(w, "")) {
	WARN("Missing group_prefix address");
	return FALSE;
    }

    parse_prefix_len (w, &masklen);

    group_addr = inet_parse(w, 4);
    if (!IN_MULTICAST(ntohl(group_addr))) {
	WARN("Group address '%s' is not a valid multicast address", inet_fmt(group_addr, s1, sizeof(s1)));
	return FALSE;
    }

    /* Was if (!(~(*cand_rp_adv_message.prefix_cnt_ptr))) which Arm GCC 4.4.2 dislikes:
     *  --> "config.c:693: warning: promoted ~unsigned is always non-zero"
     * The prefix_cnt_ptr is a u_int8 so it seems this check was to prevent overruns.
     * I've changed the check to see if we've already read 255 entries, if so the cnt
     * is maximized and we need to tell the user. --Joachim Nilsson 2010-01-16 */
    if (*cand_rp_adv_message.prefix_cnt_ptr == 255) {
	WARN("Too many multicast groups configured!");
	return FALSE;
    }

    if (EQUAL((w = next_word(&s)), "masklen")) {
	w = next_word(&s);
	if (!sscanf(w, "%u", &masklen))
	    masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
    }

    validate_prefix_len(&masklen);

    PUT_EGADDR(group_addr, (u_int8)masklen, 0, cand_rp_adv_message.insert_data_ptr);
    (*cand_rp_adv_message.prefix_cnt_ptr)++;

    logit(LOG_INFO, 0, "Adding Cand-RP group prefix %s/%d", inet_fmt(group_addr, s1, sizeof(s1)), masklen);

    return TRUE;
}
Пример #13
0
/*
 * function name: parseBSR
 * input: char *s
 * output: int
 * operation: parse the candidate BSR configured information.
 *	General form:
 *	'cand_bootstrap_router <local-addr> [priority <number>]'.
 */
int parseBSR(char *s)
{
    char *w;
    u_int32 local    = INADDR_ANY_N;
    u_int32 priority = PIM_DEFAULT_BSR_PRIORITY;

    cand_bsr_flag = FALSE;
    while (!EQUAL((w = next_word(&s)), "")) {
        if (EQUAL(w, "priority")) {
            if (EQUAL((w = next_word(&s)), "")) {
                logit(LOG_WARNING, 0,
                      "Missing priority; set to default %u (0 is lowest)\n",
                      PIM_DEFAULT_BSR_PRIORITY);
                priority = PIM_DEFAULT_BSR_PRIORITY;
                continue;
            }
            if (sscanf(w, "%u", &priority) != 1) {
                logit(LOG_WARNING, 0,
                      "invalid priority %s; set to default %u (0 is lowest)",
                      PIM_DEFAULT_BSR_PRIORITY);
                priority = PIM_DEFAULT_BSR_PRIORITY;
                continue;
            }
            if (priority > (my_bsr_priority = ~0))
                priority = my_bsr_priority;
            my_bsr_priority = (u_int8)priority;
            continue;
        }

        /* BSR address */
        local = inet_parse(w, 4);
        if (!inet_valid_host(local)) {
            local = max_local_address();
            logit(LOG_WARNING, 0, "Invalid BSR address provided '%s' in %s. Will use the largest enabled local address.",
                  w, configfilename);
            continue;
        }
        if (local_address(local) == NO_VIF) {
            local = max_local_address();
            logit(LOG_WARNING, 0,
                  "Cand-BSR address is not local '%s' in %s. Will use the largest enabled local address.",
                  w, configfilename);
        }
    }		/* while not empty */

    if (local == INADDR_ANY_N)
        /* If address not provided, use the max. local */
        local = max_local_address();
    my_bsr_address  = local;
    my_bsr_priority = priority;
    MASKLEN_TO_MASK(RP_DEFAULT_IPV4_HASHMASKLEN, my_bsr_hash_mask);
    cand_bsr_flag   = TRUE;
    logit(LOG_INFO, 0, "Local Cand-BSR address is %s", inet_fmt(local, s1, sizeof(s1)));
    logit(LOG_INFO, 0, "Local Cand-BSR priority is %u", priority);

    return TRUE;
}
Пример #14
0
static grpentry_t *create_grpentry(u_int32 group)
{
    grpentry_t *node;
    grpentry_t *prev;

    /* If already exists, return it.  Otheriwse search_grplist() returns the
     * insertion point in prev. */
    if (search_grplist(group, &prev) == TRUE)
	return prev;

    node = calloc(1, sizeof(grpentry_t));
    if (!node) {
	logit(LOG_WARNING, 0, "Memory allocation error for grpentry %s",
	      inet_fmt(group, s1, sizeof(s1)));
	return NULL;
    }

    /*
     * TODO: XXX: Note that this is NOT a (*,G) routing entry, but simply
     * a group entry, probably used to search the routing table (to find
     * (S,G) entries for example.)
     * To become (*,G) routing entry, we must setup node->grp_route
     */
    node->group		= group;
    node->rpaddr	= INADDR_ANY_N;
    node->mrtlink	= NULL;
    node->active_rp_grp	= NULL;
    node->grp_route	= NULL;
    node->rpnext	= NULL;
    node->rpprev	= NULL;

    /* Now it is safe to include the new group entry */
    node->next		= prev->next;
    prev->next		= node;
    node->prev		= prev;
    if (node->next)
	node->next->prev = node;

    IF_DEBUG(DEBUG_MFC) {
	logit(LOG_DEBUG, 0, "create group entry, group %s", inet_fmt(group, s1, sizeof(s1)));
    }

    return node;
}
Пример #15
0
void receive_hello(u_int32 src,u_int32 dst,char *data,int length)
{//收到Hello报文
	vifi_t vif;
	struct pim_neighbor *pimneighbor;
	
	int holdtime;
	vif=find_vif_direct(src);
	if(valid_packet(src,data,length)==0)
	{
		return;
	
	}
	holdtime=get_hold_time(data,length);
	if(holdtime==-1)
	{
		log(LOG_INFO,"Get hold time error!");
	}
	log(LOG_INFO,"Receive PIM Hello message,get Hold time=%d from %s",holdtime,inet_fmt(src,s1));
	for(pimneighbor=myvifs[vif].neighbor;pimneighbor!=NULL;pimneighbor=pimneighbor->next)
	{
		if(pimneighbor->address==src)
		{
			if(holdtime==0)
			{
				delete_pim_neighbor(pimneighbor);
				return;
			}
			pimneighbor->holdtime=holdtime;
			if(pimneighbor->timeoutid!=-1)
			{
				timer_clearTimer(pimneighbor->timeoutid);
			}
			pimneighbor->timeoutid=timer_setTimer(holdtime,delete_pim_neighbor,pimneighbor);
			log(LOG_INFO,"Refresh hold time of neighbor %s to %d",inet_fmt(pimneighbor->address,s1),holdtime);
			return;
		}
	}
	add_pim_neighbor(src,holdtime,vif);
	return;
	//根据所得到的时间,采取相应的操作*/
}
Пример #16
0
/*
 * Process an incoming host membership query
 */
void accept_membership_query(u_int32 src, u_int32 dst __attribute__((unused)), u_int32 group, int tmo)
{
    vifi_t vifi;
    struct uvif *v;

    /* Ignore my own membership query */
    if (local_address(src) != NO_VIF)
	return;

    /* TODO: modify for DVMRP?? */
    if ((vifi = find_vif_direct(src)) == NO_VIF) {
	IF_DEBUG(DEBUG_IGMP)
	    logit(LOG_INFO, 0,
		  "ignoring group membership query from non-adjacent host %s",
		  inet_fmt(src, s1, sizeof(s1)));
	return;
    }

    v = &uvifs[vifi];

    if ((tmo == 0 && !(v->uv_flags & VIFF_IGMPV1)) ||
	(tmo != 0 &&  (v->uv_flags & VIFF_IGMPV1))) {
	int i;

	/*
	 * Exponentially back-off warning rate
	 */
	i = ++v->uv_igmpv1_warn;
	while (i && !(i & 1))
	    i >>= 1;
	if (i == 1) {
	    logit(LOG_WARNING, 0, "%s %s on vif %d, %s",
		  tmo == 0 ? "Received IGMPv1 report from"
		  : "Received IGMPv2 report from",
		  inet_fmt(src, s1, sizeof(s1)),
		  vifi,
		  tmo == 0 ? "please configure vif for IGMPv1"
		  : "but I am configured for IGMPv1");
	}
    }
Пример #17
0
/*
 * function name: parse_group_prefix
 * input: char *s
 * output: int
 * operation: parse group_prefix configured information.
 *	General form: 'group_prefix <group-addr> [masklen <masklen>]'.
 */
int parse_group_prefix(char *s)
{
    char *w;
    u_int32 group_addr;
    u_int32  masklen;

    w = next_word(&s);
    if (EQUAL(w, "")) {
        logit(LOG_WARNING, 0,
              "Configuration error for 'group_prefix' in %s: no group_addr. Ignoring...", configfilename);
        return FALSE;
    }
    group_addr = inet_parse(w, 4);
    if (!IN_MULTICAST(ntohl(group_addr))) {
        logit(LOG_WARNING, 0,
              "Config error for 'group_prefix' in %s: %s is not a mcast addr. Ignoring...", configfilename, inet_fmt(group_addr, s1, sizeof(s1)));
        return FALSE;
    }

    /* Was if (!(~(*cand_rp_adv_message.prefix_cnt_ptr))) which Arm GCC 4.4.2 dislikes:
     *  --> "config.c:693: warning: promoted ~unsigned is always non-zero"
     * The prefix_cnt_ptr is a u_int8 so it seems this check was to prevent overruns.
     * I've changed the check to see if we've already read 255 entries, if so the cnt
     * is maximized and we need to tell the user. --Joachim Nilsson 2010-01-16 */
    if (*cand_rp_adv_message.prefix_cnt_ptr == 255) {
        logit(LOG_WARNING, 0,
              "Too many group_prefix configured. Truncating...");
        return FALSE;
    }

    if (EQUAL((w = next_word(&s)), "masklen")) {
        w = next_word(&s);
        if (sscanf(w, "%u", &masklen) == 1) {
            if (masklen > (sizeof(group_addr)*8))
                masklen = (sizeof(group_addr)*8);
            else if (masklen < 4)
                masklen = 4;
        }
        else
            masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
    }
    else
        masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;

    PUT_EGADDR(group_addr, (u_int8)masklen, 0,
               cand_rp_adv_message.insert_data_ptr);
    (*cand_rp_adv_message.prefix_cnt_ptr)++;

    logit(LOG_INFO, 0, "Adding prefix %s/%d", inet_fmt(group_addr, s1, sizeof(s1)), masklen);

    return TRUE;
}
Пример #18
0
void pim_graft_output(struct mrt *mrtdata)
{//
	struct mrt *mymrt;
	struct pim_join_prune_header *graftheader;
	struct pim_join_prune_group *graftgroup;
	struct encode_source_address *source_address;
	struct encode_unicast_option *unicast_option;
	int length;
	char *mydata;

	mymrt=mrtdata;
	mydata=(char *)(pim_send_buf+sizeof(struct ip)+sizeof(struct pim));
	unicast_option=(struct encode_unicast_option *)mydata;
	unicast_option->address_family=1;//协议族是ipv4
	unicast_option->encode_type=0;
	
	mydata=mydata+sizeof(struct encode_unicast_option);
	graftheader=(struct pim_join_prune_header *)mydata;
	graftheader->upstream=mymrt->upstream;
	graftheader->reserved=0;
	graftheader->num_groups=1;
	graftheader->holdtime=0;
	
	mydata=mydata+sizeof(struct pim_join_prune_header);
	graftgroup=(struct pim_join_prune_group *)mydata;
	graftgroup->group_address.address_family=1;
	graftgroup->group_address.encode_type=0;
	graftgroup->group_address.reserved=0;
	graftgroup->group_address.mask_len=32;
	graftgroup->group_address.group_address=mymrt->group;

	mydata=mydata+sizeof(struct pim_join_prune_group);
	graftgroup->join_number=htons(1);
	graftgroup->prune_number=0;
	
	source_address=(struct encode_source_address *)mydata;
	source_address->address_family=1;
	source_address->encode_type=0;
	source_address->reserved=0;
	source_address->mask_len=32;
	source_address->source_address=mymrt->source;

	length=sizeof(struct encode_unicast_option)+sizeof(struct pim_join_prune_header)+sizeof(struct pim_join_prune_group)+sizeof(struct encode_source_address);
	if(pimdm_output(pim_send_buf,myvifs[mymrt->incoming].address,mymrt->upstream,PIM_GRAFT,length)!=1)
	{
		log(LOG_INFO,"Send Pim Graft Packet On %s(%s) Error!",myvifs[mymrt->incoming].name,inet_fmt(myvifs[mymrt->incoming].address,s1));
	}
	else
	{
		log(LOG_INFO,"Send Pim Graft Packet On %s(%s) Success!",myvifs[mymrt->incoming].name,inet_fmt(myvifs[mymrt->incoming].address,s1));
	}	
}
Пример #19
0
/* 
 * Call build_igmp() to build an IGMP message in the output packet buffer.
 * Then send the message from the interface with IP address 'src' to
 * destination 'dst'.
 */
void send_igmp(u_int32 src, u_int32 dst, int type, int code, u_int32 group, int datalen)
{
    struct sockaddr_in sdst;
    int setloop = 0;
    size_t len;

    len = build_igmp(src, dst, type, code, group, datalen);

    if (IN_MULTICAST(ntohl(dst))) {
	k_set_if(src);
	if (type != IGMP_DVMRP || dst == allhosts_group) {
	    setloop = 1;
	    k_set_loop(TRUE);
	}
    }

    memset(&sdst, 0, sizeof(sdst));
    sdst.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
    sdst.sin_len = sizeof(sdst);
#endif
    sdst.sin_addr.s_addr = dst;
    if (sendto(igmp_socket, send_buf, len, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
	if (errno == ENETDOWN)
	    check_vif_state();
	else
	    logit(igmp_log_level(type, code), errno,
		"sendto to %s on %s",
		inet_fmt(dst, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2)));
    }

    if (setloop)
	    k_set_loop(FALSE);

    IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code))
    logit(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
	igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
				 inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
}
Пример #20
0
void set_prune(void *data)
{//在prune计时器超时后,执行操作
	struct pim_prune_data *prunedata;
	struct mrt *mymrt;
	log(LOG_INFO,"Begin Prune");
	prunedata=(struct pim_prune_data *)data;
	mymrt=find_sg(prunedata->source,prunedata->group);
	log(LOG_INFO,"Prune source:%s Group:%s",inet_fmt(prunedata->source,s1),inet_fmt(prunedata->group,s2));
	if(mymrt==NULL)
	{
		return;
	}
	else
	{
		mymrt->prune_delay_timer_id[prunedata->vif]=0;
		mymrt->outvif[prunedata->vif]=0;
		change_mfc(igmpsocket,mymrt->source,mymrt->group,mymrt->incoming);
		check_pim_state(DEL_LEAF);
		log(LOG_INFO,"miss,handle set the prune");
		mymrt->prune_timer_id[prunedata->vif]=timer_setTimer(5,prune_time_out,prunedata);
	}
}
Пример #21
0
/*
 * Set the IP_MULTICAST_IF option on local interface ifa.
 */
void k_set_if(int socket, u_int32 ifa)
{
    struct in_addr adr;

    adr.s_addr = ifa;
    if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&adr, sizeof(adr)) < 0) {
	if (errno == EADDRNOTAVAIL || errno == EINVAL)
	    return;

	logit(LOG_ERR, errno, "Failed setting IP_MULTICAST_IF option on %s",
	      inet_fmt(adr.s_addr, s1, sizeof(s1)));
    }
}
Пример #22
0
static srcentry_t *create_srcentry(u_int32 source)
{
    srcentry_t *node;
    srcentry_t *prev;

    if (search_srclist(source, &prev) == TRUE)
	return prev;

    node = calloc(1, sizeof(srcentry_t));
    if (!node) {
	logit(LOG_WARNING, 0, "Memory allocation error for srcentry %s",
	      inet_fmt(source, s1, sizeof(s1)));
	return NULL;
    }

    node->address = source;
    /* Free the memory if there is error getting the iif and
     * the next hop (upstream) router. */
    if (set_incoming(node, PIM_IIF_SOURCE) == FALSE) {
	free(node);
	return NULL;
    }

    RESET_TIMER(node->timer);
    node->mrtlink = NULL;
    node->cand_rp = NULL;
    node->next	  = prev->next;
    prev->next    = node;
    node->prev    = prev;
    if (node->next)
	node->next->prev = node;

    IF_DEBUG(DEBUG_MFC) {
	logit(LOG_DEBUG, 0, "create source entry, source %s",
	      inet_fmt(source, s1, sizeof(s1)));
    }

    return node;
}
Пример #23
0
/*
 * Process an incoming neighbor probe message.
 */
void
accept_probe(u_int32_t src, u_int32_t dst, char *p, int datalen,
             u_int32_t level)
{
    vifi_t vifi;

    if ((vifi = find_vif(src, dst)) == NO_VIF) {
        logit(LOG_INFO, 0,
              "ignoring probe from non-neighbor %s", inet_fmt(src, s1));
        return;
    }

    update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level);
}
Пример #24
0
void pim_hello_output(void *arg)
{//给定Holdtime,发送一条PIM的Hello报文
	struct pim_hello_output_data *hello_data;//参考实验指导书
	struct pim_hello_header *option;
	char *mydata;
	short *hold_time;
	int length;
	
	hello_data=(struct pim_hello_output_data *)arg;
	mydata=(char *)(pim_send_buf+sizeof(struct ip)+sizeof(struct pim));

	option=(struct pim_hello_header *)mydata;
	option->option_type=htons(1);
	option->option_length=htons(2);

	mydata=mydata+sizeof(struct pim_hello_header);
	hold_time=(short *)mydata;
	*hold_time=htons(hello_data->holdtime);

	length=sizeof(struct pim_hello_header)+sizeof(short);

	
	if(hello_data->regular==1)
	
	{
		
		timer_setTimer(PIM_HELLO_PERIOD,pim_hello_output,hello_data);
	
	}
	if(pimdm_output(pim_send_buf,myvifs[hello_data->vif].address,allpimrouters,PIM_HELLO,length)!=1)
	{
		log(LOG_INFO,"Send Pim Hello Packet On %s(%s) Error!",myvifs[hello_data->vif].name,inet_fmt(myvifs[hello_data->vif].address,s1));
	}
	else
	{
		log(LOG_INFO,"Send Pim Hello Packet On %s(%s) Success!",myvifs[hello_data->vif].name,inet_fmt(myvifs[hello_data->vif].address,s1));
	
	}
	return;
}
Пример #25
0
Файл: route.c Проект: F0rth/pimd
/*
 * TODO: when cache miss, check the iif, because probably ASSERTS
 * shoult take place
 */
static void process_cache_miss(struct igmpmsg *igmpctl)
{
    u_int32 source, mfc_source;
    u_int32 group;
    u_int32 rp_addr;
    vifi_t iif;
    mrtentry_t *mrtentry_ptr;
    mrtentry_t *mrtentry_rp;

    /*
     * When there is a cache miss, we check only the header of the packet
     * (and only it should be sent up by the kernel.
     */

    group  = igmpctl->im_dst.s_addr;
    source = mfc_source = igmpctl->im_src.s_addr;
    iif    = igmpctl->im_vif;

    IF_DEBUG(DEBUG_MFC)
        logit(LOG_DEBUG, 0, "Cache miss, src %s, dst %s, iif %d",
              inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), iif);

    /* TODO: XXX: check whether the kernel generates cache miss for the
     * LAN scoped addresses
     */
    if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
        return; /* Don't create routing entries for the LAN scoped addresses */

    /* TODO: check if correct in case the source is one of my addresses */
    /* If I am the DR for this source, create (S,G) and add the register_vif
     * to the oifs.
     */
    if ((uvifs[iif].uv_flags & VIFF_DR)
        && (find_vif_direct_local(source) == iif)) {
        mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE);
        if (mrtentry_ptr == (mrtentry_t *)NULL)
            return;
        mrtentry_ptr->flags &= ~MRTF_NEW;
        /* set reg_vif_num as outgoing interface ONLY if I am not the RP */
        if (mrtentry_ptr->group->rpaddr != my_cand_rp_address)
            VIFM_SET(reg_vif_num, mrtentry_ptr->joined_oifs);
        change_interfaces(mrtentry_ptr,
                          mrtentry_ptr->incoming,
                          mrtentry_ptr->joined_oifs,
                          mrtentry_ptr->pruned_oifs,
                          mrtentry_ptr->leaves,
                          mrtentry_ptr->asserted_oifs, 0);
    }
    else {
        mrtentry_ptr = find_route(source, group,
                                  MRTF_SG | MRTF_WC | MRTF_PMBR,
                                  DONT_CREATE);
        if (mrtentry_ptr == (mrtentry_t *)NULL)
            return;
    }

    /* TODO: if there are too many cache miss for the same (S,G), install
     * negative cache entry in the kernel (oif==NULL) to prevent too
     * many upcalls.
     */

    if (mrtentry_ptr->incoming == iif) {
        if (!VIFM_ISEMPTY(mrtentry_ptr->oifs)) {
            if (mrtentry_ptr->flags & MRTF_SG) {
                /* TODO: check that the RPbit is not set? */
                /* TODO: XXX: TIMER implem. dependency! */
                if (mrtentry_ptr->timer < PIM_DATA_TIMEOUT)
                    SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
                if (!(mrtentry_ptr->flags & MRTF_SPT)) {
                    if ((mrtentry_rp = mrtentry_ptr->group->grp_route) ==
                        (mrtentry_t *)NULL)
                        mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
                    if (mrtentry_rp != (mrtentry_t *)NULL) {
                        /* Check if the (S,G) iif is different from
                         * the (*,G) or (*,*,RP) iif
                         */
                        if ((mrtentry_ptr->incoming != mrtentry_rp->incoming)
                            || (mrtentry_ptr->upstream != mrtentry_rp->upstream)) {
                            mrtentry_ptr->flags |= MRTF_SPT;
                            mrtentry_ptr->flags &= ~MRTF_RP;
                        }
                    }
                }
            }
            if (mrtentry_ptr->flags & MRTF_PMBR)
                rp_addr = mrtentry_ptr->source->address;
            else
                rp_addr = mrtentry_ptr->group->rpaddr;
            mfc_source = source;
#ifdef KERNEL_MFC_WC_G
            if (mrtentry_ptr->flags & (MRTF_WC | MRTF_PMBR))
                if (!(mrtentry_ptr->flags & MRTF_MFC_CLONE_SG))
                    mfc_source = INADDR_ANY_N;
#endif /* KERNEL_MFC_WC_G */
            add_kernel_cache(mrtentry_ptr, mfc_source, group, MFC_MOVE_FORCE);
#ifdef SCOPED_ACL
            APPLY_SCOPE(group,mrtentry_ptr);
#endif
            k_chg_mfc(igmp_socket, mfc_source, group, iif, mrtentry_ptr->oifs,
                      rp_addr);
            /* TODO: XXX: No need for RSRR message, because nothing has
             * changed.
             */
        }

        return; /* iif match */
    }

    /* The iif doesn't match */
    if (mrtentry_ptr->flags & MRTF_SG) {
        if (mrtentry_ptr->flags & MRTF_SPT)
            /* Arrived on wrong interface */
            return;
        if ((mrtentry_rp = mrtentry_ptr->group->grp_route) ==
            (mrtentry_t *)NULL)
            mrtentry_rp =
                mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
        if (mrtentry_rp != (mrtentry_t *)NULL) {
            if (mrtentry_rp->incoming == iif) {
                /* Forward on (*,G) or (*,*,RP) */
#ifdef KERNEL_MFC_WC_G
                if (!(mrtentry_rp->flags & MRTF_MFC_CLONE_SG))
                    mfc_source = INADDR_ANY_N;
#endif /* KERNEL_MFC_WC_G */
                add_kernel_cache(mrtentry_rp, mfc_source, group, 0);
/* marian: not sure if we are going to reach here for our scoped traffic */
#ifdef SCOPED_ACL
                APPLY_SCOPE(group,mrtentry_ptr);
#endif
                k_chg_mfc(igmp_socket, mfc_source, group, iif,
                          mrtentry_rp->oifs, mrtentry_ptr->group->rpaddr);
#ifdef RSRR
                rsrr_cache_send(mrtentry_rp, RSRR_NOTIFICATION_OK);
#endif /* RSRR */
            }
        }

        return;
    }
}
Пример #26
0
static mrtentry_t *create_mrtentry(srcentry_t *src, grpentry_t *grp, u_int16 flags)
{
    mrtentry_t *node;
    mrtentry_t *grp_insert, *src_insert; /* pointers to insert */
    u_int32 source;
    u_int32 group;

    if (flags & MRTF_SG) {
	/* (S,G) entry */
	source = src->address;
	group  = grp->group;

	if (search_grpmrtlink(grp, source, &grp_insert) == TRUE)
	    return grp_insert;

	if (search_srcmrtlink(src, group, &src_insert) == TRUE) {
	    /* Hmmm, search_grpmrtlink() didn't find the entry, but
	     * search_srcmrtlink() did find it!  Shouldn't happen.  Panic! */
	    logit(LOG_ERR, 0, "MRT inconsistency for src %s and grp %s\n",
		  inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)));

	    /* not reached but to make lint happy */
	    return NULL;
	}

	/* Create and insert in group mrtlink and source mrtlink chains. */
	node = alloc_mrtentry(src, grp);
	if (!node)
	    return NULL;

	/* node has to be insert right after grp_insert in the grp
	 * mrtlink chain and right after src_insert in the src mrtlink
	 * chain */
	insert_grpmrtlink(node, grp_insert, grp);
	insert_srcmrtlink(node, src_insert, src);
	node->flags |= MRTF_SG;

	return node;
    }

    if (flags & MRTF_WC) {
	/* (*,G) entry */
	if (grp->grp_route)
	    return grp->grp_route;

	node = alloc_mrtentry(src, grp);
	if (!node)
	    return NULL;

	grp->grp_route = node;
	node->flags |= (MRTF_WC | MRTF_RP);

	return node;
    }

    if (flags & MRTF_PMBR) {
	/* (*,*,RP) entry */
	if (src->mrtlink)
	    return src->mrtlink;

	node = alloc_mrtentry(src, grp);
	if (!node)
	    return NULL;

	src->mrtlink = node;
	node->flags |= (MRTF_PMBR | MRTF_RP);

	return node;
    }

    return NULL;
}
Пример #27
0
/*
 * Process an incoming route report message.
 */
void
accept_report(u_int32_t src, u_int32_t dst, char *p, int datalen,
              u_int32_t level)
{
    vifi_t vifi;
    register int width, i, nrt = 0;
    int metric;
    u_int32_t mask;
    u_int32_t origin;
    struct newrt rt[4096];

    if ((vifi = find_vif(src, dst)) == NO_VIF) {
        logit(LOG_INFO, 0,
              "ignoring route report from non-neighbor %s", inet_fmt(src, s1));
        return;
    }

    if (!update_neighbor(vifi, src, DVMRP_REPORT, NULL, 0, level))
        return;

    if (datalen > 2*4096) {
        logit(LOG_INFO, 0,
              "ignoring oversize (%d bytes) route report from %s",
              datalen, inet_fmt(src, s1));
        return;
    }

    while (datalen > 0) {	/* Loop through per-mask lists. */

        if (datalen < 3) {
            logit(LOG_WARNING, 0,
                  "received truncated route report from %s",
                  inet_fmt(src, s1));
            return;
        }
        ((u_char *)&mask)[0] = 0xff;
        width = 1;
        if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
        if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
        if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
        if (!inet_valid_mask(ntohl(mask))) {
            logit(LOG_WARNING, 0,
                  "%s reports bogus netmask 0x%08x (%s)",
                  inet_fmt(src, s1), ntohl(mask), inet_fmt(mask, s2));
            return;
        }
        datalen -= 3;

        do {			/* Loop through (origin, metric) pairs */
            if (datalen < width + 1) {
                logit(LOG_WARNING, 0,
                      "received truncated route report from %s",
                      inet_fmt(src, s1));
                return;
            }
            origin = 0;
            for (i = 0; i < width; ++i)
                ((char *)&origin)[i] = *p++;
            metric = *p++;
            datalen -= width + 1;
            rt[nrt].mask   = mask;
            rt[nrt].origin = origin;
            rt[nrt].metric = (metric & 0x7f);
            ++nrt;
        } while (!(metric & 0x80));
    }

    qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
    start_route_updates();
    /*
     * If the last entry is default, change mask from 0xff000000 to 0
     */
    if (rt[nrt-1].origin == 0)
        rt[nrt-1].mask = 0;

    logit(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
          inet_fmt(src, s1), inet_fmt(dst, s2));
    for (i = 0; i < nrt; ++i) {
        if (i != 0 && rt[i].origin == rt[i-1].origin &&
                rt[i].mask == rt[i-1].mask) {
            logit(LOG_WARNING, 0, "%s reports duplicate route for %s",
                  inet_fmt(src, s1), inet_fmts(rt[i].origin, rt[i].mask, s2));
            continue;
        }
        update_route(rt[i].origin, rt[i].mask, rt[i].metric,
                     src, vifi);
    }

    if (routes_changed && !delay_change_reports)
        report_to_all_neighbors(CHANGED_ROUTES);
}
Пример #28
0
/*
 * Process a route report for a single origin, creating or updating the
 * corresponding routing table entry if necessary.  'src' is either the
 * address of a neighboring router from which the report arrived, or zero
 * to indicate a change of status of one of our own interfaces.
 */
void
update_route(u_int32_t origin, u_int32_t mask, u_int metric, u_int32_t src,
             vifi_t vifi)
{
    register struct rtentry *r;
    u_int adj_metric;

    /*
     * Compute an adjusted metric, taking into account the cost of the
     * subnet or tunnel over which the report arrived, and normalizing
     * all unreachable/poisoned metrics into a single value.
     */
    if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) {
        logit(LOG_WARNING, 0,
              "%s reports out-of-range metric %u for origin %s",
              inet_fmt(src, s1), metric, inet_fmts(origin, mask, s2));
        return;
    }
    adj_metric = metric + uvifs[vifi].uv_metric;
    if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE;

    /*
     * Look up the reported origin in the routing table.
     */
    if (!find_route(origin, mask)) {
        /*
         * Not found.
         * Don't create a new entry if the report says it's unreachable,
         * or if the reported origin and mask are invalid.
         */
        if (adj_metric == UNREACHABLE) {
            return;
        }
        if (src != 0 && !inet_valid_subnet(origin, mask)) {
            logit(LOG_WARNING, 0,
                  "%s reports an invalid origin (%s) and/or mask (%08x)",
                  inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
            return;
        }

        /*
         * OK, create the new routing entry.  'rtp' will be left pointing
         * to the new entry.
         */
        create_route(origin, mask);

        /*
         * Now "steal away" any sources that belong under this route
         * by deleting any cache entries they might have created
         * and allowing the kernel to re-request them.
         */
        steal_sources(rtp);

        rtp->rt_metric = UNREACHABLE;	/* temporary; updated below */
    }

    /*
     * We now have a routing entry for the reported origin.  Update it?
     */
    r = rtp;
    if (r->rt_metric == UNREACHABLE) {
        /*
         * The routing entry is for a formerly-unreachable or new origin.
         * If the report claims reachability, update the entry to use
         * the reported route.
         */
        if (adj_metric == UNREACHABLE)
            return;

        r->rt_parent   = vifi;
        init_children_and_leaves(r, vifi);

        r->rt_gateway  = src;
        r->rt_timer    = 0;
        r->rt_metric   = adj_metric;
        r->rt_flags   |= RTF_CHANGED;
        routes_changed = TRUE;
        update_table_entry(r);
    }
    else if (src == r->rt_gateway) {
        /*
         * The report has come either from the interface directly-connected
         * to the origin subnet (src and r->rt_gateway both equal zero) or
         * from the gateway we have chosen as the best first-hop gateway back
         * towards the origin (src and r->rt_gateway not equal zero).  Reset
         * the route timer and, if the reported metric has changed, update
         * our entry accordingly.
         */
        r->rt_timer = 0;
        if (adj_metric == r->rt_metric)
            return;

        if (adj_metric == UNREACHABLE) {
            del_table_entry(r, 0, DEL_ALL_ROUTES);
            r->rt_timer = ROUTE_EXPIRE_TIME;
        }
        else if (adj_metric < r->rt_metric) {
            if (init_children_and_leaves(r, vifi)) {
                update_table_entry(r);
            }
        }
        r->rt_metric   = adj_metric;
        r->rt_flags   |= RTF_CHANGED;
        routes_changed = TRUE;
    }
    else if (src == 0 ||
             (r->rt_gateway != 0 &&
              (adj_metric < r->rt_metric ||
               (adj_metric == r->rt_metric &&
                (ntohl(src) < ntohl(r->rt_gateway) ||
                 r->rt_timer >= ROUTE_SWITCH_TIME))))) {
        /*
         * The report is for an origin we consider reachable; the report
         * comes either from one of our own interfaces or from a gateway
         * other than the one we have chosen as the best first-hop gateway
         * back towards the origin.  If the source of the update is one of
         * our own interfaces, or if the origin is not a directly-connected
         * subnet and the reported metric for that origin is better than
         * what our routing entry says, update the entry to use the new
         * gateway and metric.  We also switch gateways if the reported
         * metric is the same as the one in the route entry and the gateway
         * associated with the route entry has not been heard from recently,
         * or if the metric is the same but the reporting gateway has a lower
         * IP address than the gateway associated with the route entry.
         * Did you get all that?
         */
        if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
            /*
             * XXX Why do we do this if we are just changing the metric?
             */
            r->rt_parent = vifi;
            if (init_children_and_leaves(r, vifi)) {
                update_table_entry(r);
            }
        }
        r->rt_gateway  = src;
        r->rt_timer    = 0;
        r->rt_metric   = adj_metric;
        r->rt_flags   |= RTF_CHANGED;
        routes_changed = TRUE;
    }
    else if (vifi != r->rt_parent) {
        /*
         * The report came from a vif other than the route's parent vif.
         * Update the children and leaf info, if necessary.
         */
        if (VIFM_ISSET(vifi, r->rt_children)) {
            /*
             * Vif is a child vif for this route.
             */
            if (metric  < r->rt_metric ||
                    (metric == r->rt_metric &&
                     ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) {
                /*
                 * Neighbor has lower metric to origin (or has same metric
                 * and lower IP address) -- it becomes the dominant router,
                 * and vif is no longer a child for me.
                 */
                VIFM_CLR(vifi, r->rt_children);
                VIFM_CLR(vifi, r->rt_leaves);
                r->rt_dominants   [vifi] = src;
                r->rt_subordinates[vifi] = 0;
                r->rt_leaf_timers [vifi] = 0;
                update_table_entry(r);
            }
            else if (metric > UNREACHABLE) {	/* "poisoned reverse" */
                /*
                 * Neighbor considers this vif to be on path to route's
                 * origin; if no subordinate recorded, record this neighbor
                 * as subordinate and clear the leaf flag.
                 */
                if (r->rt_subordinates[vifi] == 0) {
                    VIFM_CLR(vifi, r->rt_leaves);
                    r->rt_subordinates[vifi] = src;
                    r->rt_leaf_timers [vifi] = 0;
                    update_table_entry(r);
                }
            }
            else if (src == r->rt_subordinates[vifi]) {
                /*
                 * Current subordinate no longer considers this vif to be on
                 * path to route's origin; it is no longer a subordinate
                 * router, and we set the leaf confirmation timer to give
                 * us time to hear from other subordinates.
                 */
                r->rt_subordinates[vifi] = 0;
                if (uvifs[vifi].uv_neighbors == NULL ||
                        uvifs[vifi].uv_neighbors->al_next == NULL) {
                    VIFM_SET(vifi, r->rt_leaves);
                    update_table_entry(r);
                }
                else {
                    r->rt_leaf_timers [vifi] = LEAF_CONFIRMATION_TIME;
                    r->rt_flags |= RTF_LEAF_TIMING;
                }
            }

        }
        else if (src == r->rt_dominants[vifi] &&
                 (metric  > r->rt_metric ||
                  (metric == r->rt_metric &&
                   ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) {
            /*
             * Current dominant no longer has a lower metric to origin
             * (or same metric and lower IP address); we adopt the vif
             * as our own child.
             */
            VIFM_SET(vifi, r->rt_children);
            r->rt_dominants  [vifi] = 0;
            if (metric > UNREACHABLE) {
                r->rt_subordinates[vifi] = src;
            }
            else if (uvifs[vifi].uv_neighbors == NULL ||
                     uvifs[vifi].uv_neighbors->al_next == NULL) {
                VIFM_SET(vifi, r->rt_leaves);
            }
            else {
                r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
                r->rt_flags |= RTF_LEAF_TIMING;
            }
            update_table_entry(r);
        }
    }
}
Пример #29
0
Файл: route.c Проект: F0rth/pimd
/*
 * Set the iif, upstream router, preference and metric for the route
 * toward the source. Return TRUE is the route was found, othewise FALSE.
 * If srctype==PIM_IIF_SOURCE and if the source is directly connected
 * then the "upstream" is set to NULL. If srcentry==PIM_IIF_RP, then
 * "upstream" in case of directly connected "source" will be that "source"
 * (if it is also PIM router).,
 */
int set_incoming(srcentry_t *srcentry_ptr, int srctype)
{
    struct rpfctl rpfc;
    u_int32 source = srcentry_ptr->address;
    u_int32 neighbor_addr;
    struct uvif *v;
    pim_nbr_entry_t *n;

    /* Preference will be 0 if directly connected */
    srcentry_ptr->metric = 0;
    srcentry_ptr->preference = 0;

    if ((srcentry_ptr->incoming = local_address(source)) != NO_VIF) {
        /* The source is a local address */
        /* TODO: set the upstream to myself? */
        srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
        return (TRUE);
    }

    if ((srcentry_ptr->incoming = find_vif_direct(source)) != NO_VIF) {
        /* The source is directly connected. Check whether we are
         * looking for real source or RP
         */
        if (srctype == PIM_IIF_SOURCE) {
            srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
            return (TRUE);
        } else {
            /* PIM_IIF_RP */
            neighbor_addr = source;
        }
    } else {
        /* TODO: probably need to check the case if the iif is disabled */
        /* Use the lastest resource: the kernel unicast routing table */
        k_req_incoming(source, &rpfc);
        if ((rpfc.iif == NO_VIF) ||
            rpfc.rpfneighbor.s_addr == INADDR_ANY_N) {
            /* couldn't find a route */
            IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF)
                logit(LOG_DEBUG, 0, "NO ROUTE found for %s",
                      inet_fmt(source, s1, sizeof(s1)));
            return FALSE;
        }
        srcentry_ptr->incoming = rpfc.iif;
        neighbor_addr = rpfc.rpfneighbor.s_addr;
        /* set the preference for sources that aren't directly connected. */
        v = &uvifs[srcentry_ptr->incoming];
        srcentry_ptr->preference = v->uv_local_pref;
        srcentry_ptr->metric = v->uv_local_metric;
    }

    /*
     * The upstream router must be a (PIM router) neighbor, otherwise we
     * are in big trouble ;-)
     */
    v = &uvifs[srcentry_ptr->incoming];
    for (n = v->uv_pim_neighbors; n != NULL; n = n->next) {
        if (ntohl(neighbor_addr) < ntohl(n->address))
            continue;
        if (neighbor_addr == n->address) {
            /*
             *The upstream router is found in the list of neighbors.
             * We are safe!
             */
            srcentry_ptr->upstream = n;
            IF_DEBUG(DEBUG_RPF)
                logit(LOG_DEBUG, 0,
                      "For src %s, iif is %d, next hop router is %s",
                      inet_fmt(source, s1, sizeof(s1)), srcentry_ptr->incoming,
                      inet_fmt(neighbor_addr, s2, sizeof(s2)));

            return TRUE;
        }
        else break;
    }

    /* TODO: control the number of messages! */
    logit(LOG_INFO, 0,
          "For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER",
          inet_fmt(source, s1, sizeof(s1)), srcentry_ptr->incoming,
          inet_fmt(neighbor_addr, s2, sizeof(s2)));
    srcentry_ptr->upstream = (pim_nbr_entry_t *)NULL;

    return FALSE;
}
Пример #30
0
Файл: route.c Проект: F0rth/pimd
/*
 * TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where
 * we have source-specific Join/Prune.
 */
void add_leaf(vifi_t vifi, u_int32 source __attribute__((unused)), u_int32 group)
{
    mrtentry_t *mrtentry_ptr;
    mrtentry_t *mrtentry_srcs;
    vifbitmap_t old_oifs;
    vifbitmap_t new_oifs;
    vifbitmap_t new_leaves;

    if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
        return; /* Don't create routing entries for the LAN scoped addresses */

    /*
     * XXX: only if I am a DR, the IGMP Join should result in creating
     * a PIM MRT state.
     * XXX: Each router must know if it has local members, i.e., whether
     * it is a last-hop router as well. This info is needed so it will
     * know whether is allowed to initiate a SPT switch by sending
     * a PIM (S,G) Join to the high datarate source.
     * However, if a non-DR last-hop router has not received
     * a PIM Join, it should not create a PIM state, otherwise later
     * this state may incorrectly trigger PIM joins.
     * There is a design flow in pimd, so without making major changes
     * the best we can do is that the non-DR last-hop router will
     * record the local members only after it receives PIM Join from the DR
     * (i.e.  after the second or third IGMP Join by the local member).
     * The downside is that a last-hop router may delay the initiation
     * of the SPT switch. Sigh...
     */
    if (uvifs[vifi].uv_flags & VIFF_DR)
        mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE);
    else
        mrtentry_ptr = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE);

    if (mrtentry_ptr == (mrtentry_t *)NULL)
        return;

    IF_DEBUG(DEBUG_MRT)
        logit(LOG_DEBUG, 0, "Adding vif %d for group %s", vifi,
              inet_fmt(group, s1, sizeof(s1)));

    if (VIFM_ISSET(vifi, mrtentry_ptr->leaves))
        return;     /* Already a leaf */
    calc_oifs(mrtentry_ptr, &old_oifs);
    VIFM_COPY(mrtentry_ptr->leaves, new_leaves);
    VIFM_SET(vifi, new_leaves);    /* Add the leaf */
    change_interfaces(mrtentry_ptr,
                      mrtentry_ptr->incoming,
                      mrtentry_ptr->joined_oifs,
                      mrtentry_ptr->pruned_oifs,
                      new_leaves,
                      mrtentry_ptr->asserted_oifs, 0);
    calc_oifs(mrtentry_ptr, &new_oifs);

    /* Only if I am the DR for that subnet, eventually initiate a Join */
    if (!(uvifs[vifi].uv_flags & VIFF_DR))
        return;

    if ((mrtentry_ptr->flags & MRTF_NEW)
        || (VIFM_ISEMPTY(old_oifs) && (!VIFM_ISEMPTY(new_oifs)))) {
        /* A new created entry or the oifs have changed
         * from NULL to non-NULL.
         */
        mrtentry_ptr->flags &= ~MRTF_NEW;
        FIRE_TIMER(mrtentry_ptr->jp_timer); /* Timeout the Join/Prune timer */
        /* TODO: explicitly call the function below?
           send_pim_join_prune(mrtentry_ptr->upstream->vifi,
           mrtentry_ptr->upstream,
           PIM_JOIN_PRUNE_HOLDTIME);
        */
    }

    /* Check all (S,G) entries and set the inherited "leaf" flag.
     * TODO: XXX: This won't work for IGMPv3, because there we don't know
     * whether the (S,G) leaf oif was inherited from the (*,G) entry or
     * was created by source specific IGMP join.
     */
    for (mrtentry_srcs = mrtentry_ptr->group->mrtlink;
         mrtentry_srcs != (mrtentry_t *)NULL;
         mrtentry_srcs = mrtentry_srcs->grpnext) {
        VIFM_COPY(mrtentry_srcs->leaves, new_leaves);
        VIFM_SET(vifi, new_leaves);
        change_interfaces(mrtentry_srcs,
                          mrtentry_srcs->incoming,
                          mrtentry_srcs->joined_oifs,
                          mrtentry_srcs->pruned_oifs,
                          new_leaves,
                          mrtentry_srcs->asserted_oifs, 0);
    }
}