void delete_pim_neighbor(void *arg) {//删除一个邻居 struct pim_neighbor *myentry,*temp,*pimneighbor; vifi_t vif; myentry=arg; vif=find_vif_direct(myentry->address); if(vif==0) { return; } for(pimneighbor=myvifs[vif].neighbor;pimneighbor!=NULL;pimneighbor=pimneighbor->next) { if(pimneighbor->address==myentry->address) { if(myvifs[vif].neighbor->address==myentry->address) { myvifs[vif].neighbor=NULL; } temp->next=pimneighbor->next; break; } temp=pimneighbor; } log(LOG_INFO,"Holdtime=0,delete this neighbor"); refresh_mrt(vif,DEL_NEIGHBOR); }
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"); } }
int valid_packet(u_int32 src,char *packet,int length) {//检验包的校验和 源地址 接口等信息,确定该包是否有效,有效返回1,否则返回0 vifi_t vif; struct myvif *myv; if(inet_cksum((u_int16 *)packet,length)) { log(LOG_INFO,0,"Checking sum error!"); return 0; } vif=find_vif_direct(src); if(vif==0) { //log(LOG_INFO,"Source address error!Don't handle!"); return 0; } myv=&myvifs[vif]; if(myv->is_active==0) { log(LOG_INFO,"Interface is not active!"); return 0; } return 1; }
/* * 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; }
/* * Traceroute function which returns traceroute replies to the requesting * router. Also forwards the request to downstream routers. */ void accept_mtrace(u_int32 src, u_int32 dst, u_int32 group, char *data, u_int no, int datalen) { u_char type; mrtentry_t *mrt; struct tr_query *qry; struct tr_resp *resp; int vifi; char *p; u_int rcount; int errcode = TR_NO_ERR; int resptype; struct timeval tp; struct sioc_vif_req v_req; #if 0 /* TODO */ struct sioc_sg_req sg_req; #endif /* 0 */ u_int32 parent_address = INADDR_ANY; /* Remember qid across invocations */ static u_int32 oqid = 0; /* timestamp the request/response */ gettimeofday(&tp, 0); /* * Check if it is a query or a response */ if (datalen == QLEN) { type = QUERY; IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); } else if ((datalen - QLEN) % RLEN == 0) { type = RESP; IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); if (IN_MULTICAST(ntohl(dst))) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Dropping multicast response"); return; } } else { logit(LOG_WARNING, 0, "%s from %s to %s", "Non decipherable traceroute request recieved", inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2))); return; } qry = (struct tr_query *)data; /* * if it is a packet with all reports filled, drop it */ if ((rcount = (datalen - QLEN)/RLEN) == no) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "packet with all reports filled in"); return; } IF_DEBUG(DEBUG_TRACE) { logit(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), inet_fmt(qry->tr_dst, s3, sizeof(s3))); logit(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl, inet_fmt(qry->tr_raddr, s1, sizeof(s1))); logit(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid); } /* determine the routing table entry for this traceroute */ mrt = find_route(qry->tr_src, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE); IF_DEBUG(DEBUG_TRACE) { if (mrt != (mrtentry_t *)NULL) { if (mrt->upstream != (pim_nbr_entry_t *)NULL) parent_address = mrt->upstream->address; else parent_address = INADDR_ANY; logit(LOG_DEBUG, 0, "mrt parent vif: %d rtr: %s metric: %d", mrt->incoming, inet_fmt(parent_address, s1, sizeof(s1)), mrt->metric); /* TODO logit(LOG_DEBUG, 0, "mrt origin %s", RT_FMT(rt, s1)); */ } else { logit(LOG_DEBUG, 0, "...no route"); } } /* * Query type packet - check if rte exists * Check if the query destination is a vif connected to me. * and if so, whether I should start response back */ if (type == QUERY) { if (oqid == qry->tr_qid) { /* * If the multicast router is a member of the group being * queried, and the query is multicasted, then the router can * recieve multiple copies of the same query. If we have already * replied to this traceroute, just ignore it this time. * * This is not a total solution, but since if this fails you * only get N copies, N <= the number of interfaces on the router, * it is not fatal. */ IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "ignoring duplicate traceroute packet"); return; } if (mrt == (mrtentry_t *)NULL) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s", inet_fmt(qry->tr_src, s1, sizeof(s1))); if (IN_MULTICAST(ntohl(dst))) return; } vifi = find_vif_direct(qry->tr_dst); if (vifi == NO_VIF) { /* The traceroute destination is not on one of my subnet vifs. */ IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Destination %s not an interface", inet_fmt(qry->tr_dst, s1, sizeof(s1))); if (IN_MULTICAST(ntohl(dst))) return; errcode = TR_WRONG_IF; } else if (mrt != (mrtentry_t *)NULL && !VIFM_ISSET(vifi, mrt->oifs)) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s", inet_fmt(qry->tr_dst, s1, sizeof(s1)), inet_fmt(qry->tr_src, s2, sizeof(s2))); if (IN_MULTICAST(ntohl(dst))) return; errcode = TR_WRONG_IF; } } else { /* * determine which interface the packet came in on * RESP packets travel hop-by-hop so this either traversed * a tunnel or came from a directly attached mrouter. */ if ((vifi = find_vif_direct(src)) == NO_VIF) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Wrong interface for packet"); errcode = TR_WRONG_IF; } } /* Now that we've decided to send a response, save the qid */ oqid = qry->tr_qid; IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Sending traceroute response"); /* copy the packet to the sending buffer */ p = igmp_send_buf + IP_IGMP_HEADER_LEN + IGMP_MINLEN; bcopy(data, p, datalen); p += datalen; /* * If there is no room to insert our reply, coopt the previous hop * error indication to relay this fact. */ if (p + sizeof(struct tr_resp) > igmp_send_buf + SEND_BUF_SIZE) { resp = (struct tr_resp *)p - 1; resp->tr_rflags = TR_NO_SPACE; mrt = NULL; goto sendit; } /* * fill in initial response fields */ resp = (struct tr_resp *)p; memset(resp, 0, sizeof(struct tr_resp)); datalen += RLEN; resp->tr_qarr = htonl(((tp.tv_sec + JAN_1970) << 16) + ((tp.tv_usec << 10) / 15625)); resp->tr_rproto = PROTO_PIM; resp->tr_outaddr = (vifi == NO_VIF) ? dst : uvifs[vifi].uv_lcl_addr; resp->tr_fttl = (vifi == NO_VIF) ? 0 : uvifs[vifi].uv_threshold; resp->tr_rflags = errcode; /* * obtain # of packets out on interface */ v_req.vifi = vifi; if (vifi != NO_VIF && ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0) resp->tr_vifout = htonl(v_req.ocount); else resp->tr_vifout = 0xffffffff; /* * fill in scoping & pruning information */ /* TODO */ #if 0 if (mrt != (mrtentry_t *)NULL) for (gt = rt->rt_groups; gt; gt = gt->gt_next) { if (gt->gt_mcastgrp >= group) break; } else gt = NULL; if (gt && gt->gt_mcastgrp == group) { struct stable *st; for (st = gt->gt_srctbl; st; st = st->st_next) if (qry->tr_src == st->st_origin) break; sg_req.src.s_addr = qry->tr_src; sg_req.grp.s_addr = group; if (st && st->st_ctime != 0 && ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0) resp->tr_pktcnt = htonl(sg_req.pktcnt + st->st_savpkt); else resp->tr_pktcnt = htonl(st ? st->st_savpkt : 0xffffffff); if (VIFM_ISSET(vifi, gt->gt_scope)) resp->tr_rflags = TR_SCOPED; else if (gt->gt_prsent_timer) resp->tr_rflags = TR_PRUNED; else if (!VIFM_ISSET(vifi, gt->gt_grpmems)) if (VIFM_ISSET(vifi, rt->rt_children) && NBRM_ISSETMASK(uvifs[vifi].uv_nbrmap, rt->rt_subordinates)) /*XXX*/ resp->tr_rflags = TR_OPRUNED; else resp->tr_rflags = TR_NO_FWD; } else { if (scoped_addr(vifi, group)) resp->tr_rflags = TR_SCOPED; else if (rt && !VIFM_ISSET(vifi, rt->rt_children)) resp->tr_rflags = TR_NO_FWD; } #endif /* 0 */ /* * if no rte exists, set NO_RTE error */ if (mrt == (mrtentry_t *)NULL) { src = dst; /* the dst address of resp. pkt */ resp->tr_inaddr = 0; resp->tr_rflags = TR_NO_RTE; resp->tr_rmtaddr = 0; } else { /* get # of packets in on interface */ v_req.vifi = mrt->incoming; if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0) resp->tr_vifin = htonl(v_req.icount); else resp->tr_vifin = 0xffffffff; /* TODO MASK_TO_VAL(rt->rt_originmask, resp->tr_smask); */ src = uvifs[mrt->incoming].uv_lcl_addr; resp->tr_inaddr = src; if (mrt->upstream != (pim_nbr_entry_t *)NULL) parent_address = mrt->upstream->address; else parent_address = INADDR_ANY; resp->tr_rmtaddr = parent_address; if (!VIFM_ISSET(vifi, mrt->oifs)) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s", inet_fmt(qry->tr_dst, s1, sizeof(s1)), inet_fmt(qry->tr_src, s2, sizeof(s2))); resp->tr_rflags = TR_WRONG_IF; } #if 0 if (rt->rt_metric >= UNREACHABLE) { resp->tr_rflags = TR_NO_RTE; /* Hack to send reply directly */ rt = NULL; } #endif /* 0 */ } sendit: /* * if metric is 1 or no. of reports is 1, send response to requestor * else send to upstream router. If the upstream router can't handle * mtrace, set an error code and send to requestor anyway. */ IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no); if ((rcount + 1 == no) || (mrt == NULL) || (mrt->metric == 1)) { resptype = IGMP_MTRACE_RESP; dst = qry->tr_raddr; } else #if 0 /* TODO */ if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) { dst = qry->tr_raddr; resp->tr_rflags = TR_OLD_ROUTER; resptype = IGMP_MTRACE_RESP; } else { #endif /* 0 */ if (mrt->upstream != (pim_nbr_entry_t *)NULL) parent_address = mrt->upstream->address; else parent_address = INADDR_ANY; dst = parent_address; resptype = IGMP_MTRACE; #if 0 /* TODO */ } #endif if (IN_MULTICAST(ntohl(dst))) { /* * Send the reply on a known multicast capable vif. * If we don't have one, we can't source any multicasts anyway. */ if (phys_vif != -1) { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Sending reply to %s from %s", inet_fmt(dst, s1, sizeof(s1)), inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2, sizeof(s2))); k_set_ttl(igmp_socket, qry->tr_rttl); send_igmp(igmp_send_buf, uvifs[phys_vif].uv_lcl_addr, dst, resptype, no, group, datalen); k_set_ttl(igmp_socket, 1); } else logit(LOG_INFO, 0, "No enabled phyints -- %s", "dropping traceroute reply"); } else { IF_DEBUG(DEBUG_TRACE) logit(LOG_DEBUG, 0, "Sending %s to %s from %s", resptype == IGMP_MTRACE_RESP ? "reply" : "request on", inet_fmt(dst, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2))); send_igmp(igmp_send_buf, src, dst, resptype, no, group, datalen); } }
void receive_pim_graft_ack(u_int32 src,u_int32 dst,char *data,int length) {// vifi_t vif; char *mydata; struct pim_join_prune_header *graft_header; struct pim_join_prune_group *graft_group_header; u_int32 unicast_address; struct encode_group_address group_address; struct encode_source_address *source_address; int num_groups; int join_number; int i,j; struct mrt *mymrt; vif=find_vif_direct(src); if(vif==0) { return; } if(valid_packet(src,data,length)==0) { return; } mydata=data+sizeof(struct pim)+sizeof(struct encode_unicast_option); graft_header=(struct pim_join_prune_header *)mydata; unicast_address=graft_header->upstream; num_groups=graft_header->num_groups; if(num_groups==0) { return; } mydata=mydata+sizeof(struct pim_join_prune_header); for(i=0;i<num_groups;i++) { graft_group_header=(struct pim_join_prune_group *)mydata; mydata=mydata+sizeof(struct pim_join_prune_group); group_address=graft_group_header->group_address; join_number=graft_group_header->join_number; if(!IN_MULTICAST(ntohl(group_address.group_address))) { mydata=mydata+(join_number)*sizeof(struct encode_source_address); continue; } for(j=0;j<join_number;j++) { source_address=(struct encode_source_address *)mydata; if(!inet_valid_host(source_address->source_address)) { mydata=mydata+sizeof(struct encode_source_address); continue; } mymrt=find_sg(source_address->source_address,group_address.group_address); if(mymrt==NULL) {//没有该组播路由表项,则不处理 mydata=mydata+sizeof(struct encode_source_address); continue; } if(mymrt->graft_timer_id!=0) { log(LOG_INFO,"Receive PIM Graft ack from %s to %s,Graft success",inet_fmt(src,s1),inet_fmt(src,s2)); timer_clearTimer(mymrt->graft_timer_id); mymrt->graft_timer_id=0; } } } }
void receive_pim_graft(u_int32 src,u_int32 dst,char *data,int length) {// u_int32 unicast_address; struct encode_group_address group_address; struct encode_source_address *source_address; vifi_t vif; struct pim_neighbor neighbor; struct pim_join_prune_header *graft_header; struct pim_join_prune_group *graft_group_header; int i,j; int join_number; char *mydata,*temp; int num_groups; struct mrt *mymrt; temp=data; vif=find_vif_direct(src); if(vif==0) { return; } if(valid_packet(src,data,length)==0) { return; } mydata=data+sizeof(struct pim)+sizeof(struct encode_unicast_option); graft_header=(struct pim_join_prune_header *)mydata; unicast_address=graft_header->upstream; num_groups=graft_header->num_groups; if(num_groups==0) { return; } mydata=mydata+sizeof(struct pim_join_prune_header); for(i=0;i<num_groups;i++) { graft_group_header=(struct pim_join_prune_group *)mydata; mydata=mydata+sizeof(struct pim_join_prune_group); group_address=graft_group_header->group_address; join_number=ntohs(graft_group_header->join_number); if(!IN_MULTICAST(ntohl(group_address.group_address))) { mydata=mydata+(join_number)*sizeof(struct encode_source_address); continue; } for(j=0;j<join_number;j++) { source_address=(struct encode_source_address *)mydata; if(!inet_valid_host(source_address->source_address)) { mydata=mydata+sizeof(struct encode_source_address); continue; } log(LOG_INFO,"Receive Graft form %s for group %s,Forwarding data in this interface",inet_fmt(source_address->source_address,s1),inet_fmt(group_address.group_address,s2)); bcopy(temp,pim_send_buf+sizeof(struct ip),length); pimdm_output(pim_send_buf,myvifs[vif].address,src,PIM_GRAFT_ACK,length-sizeof(struct pim)); mymrt=find_sg(source_address->source_address,group_address.group_address); if(mymrt==NULL) {//没有该组播路由表项,则不处理 mydata=mydata+sizeof(struct encode_source_address); continue; } if(mymrt->prune_delay_timer_id[vif]!=0) { timer_clearTimer(mymrt->prune_delay_timer_id[vif]); mymrt->prune_delay_timer_id[vif]=0; } if(mymrt->outvif[vif]==0) { mymrt->outvif[vif]=1; change_mfc(igmpsocket,mymrt->source,mymrt->group,mymrt->incoming); //bcopy(data,pim_send_buf+sizeof(struct ip),length); } //pimdm_output(pim_send_buf,myvifs[vif].address,src,PIM_GRAFT_ACK,length-sizeof(struct pim)); } mydata=mydata+sizeof(struct encode_source_address); } }
void receive_assert(u_int32 src,u_int32 dst,char *data,int length) {// vifi_t vif; vifi_t *vifdata; u_int32 *unicast_address; struct encode_group_address *group_address; u_int32 source,group; struct mrt *mymrt; char *mydata; u_int32 *preference; u_int32 *metric; vif=find_vif_direct(src); if(vif==0) { return; } if(valid_packet(src,data,length)==0) { return; } mydata=data+sizeof(struct pim); group_address=(struct encode_group_address *)mydata; group=group_address->group_address; mydata=mydata+sizeof(struct encode_group_address)+sizeof(struct encode_unicast_option); unicast_address=(u_int32 *)mydata; source=*unicast_address; mydata=mydata+sizeof(u_int32); preference=(u_int32 *)mydata; mydata=mydata+sizeof(u_int32); metric=(u_int32 *)mydata; log(LOG_INFO,"Receive PIM Assert from %s to %s",inet_fmt(src,s1),inet_fmt(dst,s2)); mymrt=find_sg(source,group); if(mymrt==NULL) { return; } if(vif==mymrt->incoming) { if(source==mymrt->upstream) { return; } else { if(assert_compare(mymrt->preference,mymrt->metric,mymrt->upstream,*preference,*metric,source)==1) { return; } else { log(LOG_INFO,"PIM Assert!:Change upstream!"); mymrt->preference=*preference; mymrt->metric=*metric; mymrt->upstream=source; return; } } } else { if(mymrt->outvif[vif]==0) { return; } if(assert_compare(mymrt->preference,mymrt->metric,mymrt->upstream,*preference,*metric,source)==1) { pim_assert_output(source,group,vif,mymrt->preference,mymrt->metric); return; } else { vifdata=(vifi_t *)malloc(sizeof(vifi_t)); *vifdata=vif; mymrt->prune_delay_timer_id[vif]=timer_setTimer(PIM_ASSERT_TIMER,active_forward,vifdata); //changeinterface();将该接口置为不转发状态 } } }
void receive_join_prune(u_int32 src,u_int32 dst,char *data,int length) {//收到join或prune int unicast_address; struct encode_group_address group_address; struct encode_source_address *source_address; vifi_t vif; struct pim_neighbor neighbor; struct pim_join_prune_header *jp_header; struct pim_join_prune_group *jp_group_header; struct mrt *mymrt; char *mydata; int num_groups; int holdtime; int join_number; int prune_number; int i,j,k; vif=find_vif_direct(src); if(vif==0) { return; } if(valid_packet(src,data,length)==0) { return; } mydata=data+sizeof(struct pim)+sizeof(struct encode_unicast_option); jp_header=(struct pim_join_prune_header *)mydata; unicast_address=jp_header->upstream; num_groups=jp_header->num_groups; holdtime=jp_header->holdtime; if(num_groups==0) { return; } log(LOG_INFO,"Receive PIM Join/Prune from %s to %s",inet_fmt(src,s1),inet_fmt(dst,s2)); mydata=mydata+sizeof(struct pim_join_prune_header); log(LOG_INFO,"Receive Upstream interface:%s",inet_fmt(unicast_address,s1)); if((unicast_address!=myvifs[vif].address)&&(unicast_address!=INADDR_ANY_N)) { //我不是这条消息的接收者 //如果是join,如果此时我有延迟发送join消息的计划,则取消发送join的计划 //如果是prune,此时我还要接收的话,延迟一段时间后发送join消息 if(findneighbor(unicast_address,vif)==NULL) {//看接收方是不是我的PIM邻居 return; }log(LOG_INFO,"Num of groups:%d",num_groups); for(i=0;i<num_groups;i++) { jp_group_header=(struct pim_join_prune_group *)mydata; mydata=mydata+sizeof(struct pim_join_prune_group); group_address=jp_group_header->group_address; join_number=ntohs(jp_group_header->join_number); prune_number=ntohs(jp_group_header->prune_number); log(LOG_INFO,"Receive Group number:%d Join number:%d Prune number:%d",inet_fmt(group_address.group_address,s1),join_number,prune_number); if(!IN_MULTICAST(ntohl(group_address.group_address))) { mydata=mydata+(join_number+prune_number)*sizeof(struct encode_source_address); continue; } for(j=0;j<join_number;j++) { source_address=(struct encode_source_address *)mydata; log(LOG_INFO,"Receive Source_address:%s",inet_fmt(source_address->source_address,s1)); if(!inet_valid_host(source_address->source_address)) { mydata=mydata+sizeof(struct encode_source_address); continue; } mymrt=find_sg(source_address->source_address,group_address.group_address); if(mymrt==NULL) {//没有该组播路由表项,则不处理 mydata=mydata+sizeof(struct encode_source_address); continue; } if(mymrt->join_delay_timer_id!=0) {//如果有join延迟的话,取消置为0即可 log(LOG_INFO,"Join form %s for %s,Canceling delay join",inet_fmt(source_address->source_address,s1),inet_fmt(group_address.group_address,s2)); timer_clearTimer(mymrt->join_delay_timer_id); mymrt->join_delay_timer_id=0; } mydata=mydata+(join_number+prune_number)*sizeof(struct encode_source_address); } for(k=0;k<prune_number;k++) { source_address=(struct encode_source_address *)mydata; log(LOG_INFO,"Receive Source_address:%s",inet_fmt(source_address->source_address,s1)); if(!inet_valid_host(source_address->source_address)) { mydata=mydata+sizeof(struct encode_source_address); continue; } mymrt=find_sg(source_address->source_address,group_address.group_address); if(mymrt==NULL) {//路由表是空的情况下,不处理 mydata=mydata+sizeof(struct encode_source_address); continue; } if(mymrt->outnumber!=0) { if(mymrt->upstream!=mymrt->source) { log(LOG_INFO,"We are receiving Src %s Group %s,Scheduling and send Join",inet_fmt(source_address->source_address,s1),inet_fmt(group_address.group_address,s2)); schedule_join(mymrt,unicast_address); } mydata=mydata+sizeof(struct encode_source_address); continue; } mydata=mydata+(join_number+prune_number)*sizeof(struct encode_source_address); } } return; } else {//我是Join/Prune报文的接收方 //收到Join报文,取消我的延迟剪枝计时器 //收到Prune报文,回送Prune报文,启动计时器,超时后剪枝 log(LOG_INFO,"Num of groups:%d",num_groups); for(i=0;i<num_groups;i++) { jp_group_header=(struct pim_join_prune_group *)mydata; mydata=mydata+sizeof(struct pim_join_prune_group); group_address=jp_group_header->group_address; join_number=ntohs(jp_group_header->join_number); prune_number=ntohs(jp_group_header->prune_number); log(LOG_INFO,"Receive Group address:%s Join number:%d Prune number:%d",inet_fmt(group_address.group_address,s1),join_number,prune_number); if(!IN_MULTICAST(ntohl(group_address.group_address))) { mydata=mydata+(join_number+prune_number)*sizeof(struct encode_source_address); continue; } for(j=0;j<join_number;j++) { source_address=(struct encode_source_address *)mydata; log(LOG_INFO,"Join Message,Receive Source_address:%s",inet_fmt(source_address->source_address,s1)); if(!inet_valid_host(source_address->source_address)) { mydata=mydata+sizeof(struct encode_source_address); continue; } mymrt=find_sg(source_address->source_address,group_address.group_address); if(mymrt==NULL) {//没有该组播路由表项,则不处理 mydata=mydata+sizeof(struct encode_source_address); continue; } if(mymrt->prune_delay_timer_id[vif]!=0) {//如果有join延迟的话,取消置为0即可 log(LOG_INFO,"Join form %s for %s,Canceling delay prune",inet_fmt(source_address->source_address,s1),inet_fmt(group_address.group_address,s2)); timer_clearTimer(mymrt->prune_delay_timer_id[vif]); mymrt->prune_delay_timer_id[vif]=0; } mydata=mydata+(join_number+prune_number)*sizeof(struct encode_source_address); } for(k=0;k<prune_number;k++) { source_address=(struct encode_source_address *)mydata; log(LOG_INFO,"Prune message,Receive Source_address:%s",inet_fmt(source_address->source_address,s1)); if(!inet_valid_host(source_address->source_address)) { mydata=mydata+sizeof(struct encode_source_address); continue; } mymrt=find_sg(source_address->source_address,group_address.group_address); if(mymrt==NULL) {//路由表是空的情况下,不处理 mydata=mydata+sizeof(struct encode_source_address); continue; } if(mymrt->upstream!=mymrt->source) { log(LOG_INFO,"We are receiving Src %s Group %s,Scheduling and echo Prune",inet_fmt(source_address->source_address,s1),inet_fmt(group_address.group_address,s2)); bcopy(data,pim_send_buf+sizeof(struct ip),length); if(pimdm_output(pim_send_buf,myvifs[vif].address,allpimrouters,PIM_JOIN_PRUNE,length-sizeof(struct pim))!=1) { log(LOG_INFO,"Echo Prune Packet error!"); } schedule_prune(mymrt,vif,holdtime); } mydata=mydata+(join_number+prune_number)*sizeof(struct encode_source_address); } } } return; }