/** * 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; }
/* * 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__ */ } }
/* * 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); } } } }
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); } }
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); } }
/* * 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; }
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); }
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; } }
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); }
/* * 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"); }
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; }
/** * 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; }
/* * 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; }
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; }
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; //根据所得到的时间,采取相应的操作*/ }
/* * 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"); } }
/* * 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; }
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)); } }
/* * 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))); }
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); } }
/* * 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))); } }
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; }
/* * 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); }
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; }
/* * 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; } }
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; }
/* * 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); }
/* * 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); } } }
/* * 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; }
/* * 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); } }