void delete_grpentry(grpentry_t *grp) { mrtentry_t *node; mrtentry_t *next; if (!grp) return; /* TODO: XXX: the first entry is unused and always there */ grp->prev->next = grp->next; if (grp->next) grp->next->prev = grp->prev; if (grp->grp_route) { if (grp->grp_route->flags & MRTF_KERNEL_CACHE) delete_mrtentry_all_kernel_cache(grp->grp_route); FREE_MRTENTRY(grp->grp_route); } /* Delete from the rp_grp_entry chain */ if (grp->active_rp_grp) { if (grp->rpnext) grp->rpnext->rpprev = grp->rpprev; if (grp->rpprev) grp->rpprev->rpnext = grp->rpnext; else grp->active_rp_grp->grplink = grp->rpnext; } for (node = grp->mrtlink; node; node = next) { next = node->grpnext; if (node->flags & MRTF_KERNEL_CACHE) /* Delete the kernel cache first */ delete_mrtentry_all_kernel_cache(node); if (node->srcprev) { node->srcprev->srcnext = node->srcnext; } else { node->source->mrtlink = node->srcnext; if (!node->srcnext) { /* Delete the srcentry if this was the last routing entry */ delete_srcentry(node->source); } } if (node->srcnext) node->srcnext->srcprev = node->srcprev; FREE_MRTENTRY(node); } free(grp); }
mrtentry_t *switch_shortest_path(u_int32 source, u_int32 group) { mrtentry_t *mrtentry_ptr; /* TODO: XXX: prepare and send immediately the (S,G) join? */ if ((mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE)) != (mrtentry_t *)NULL) { if (mrtentry_ptr->flags & MRTF_NEW) { mrtentry_ptr->flags &= ~MRTF_NEW; } else if (mrtentry_ptr->flags & MRTF_RP) { /* (S,G)RPbit with iif toward RP. Reset to (S,G) with iif * toward S. Delete the kernel cache (if any), because * change_interfaces() will reset it with iif toward S * and no data will arrive from RP before the switch * really occurs. */ mrtentry_ptr->flags &= ~MRTF_RP; mrtentry_ptr->incoming = mrtentry_ptr->source->incoming; mrtentry_ptr->upstream = mrtentry_ptr->source->upstream; delete_mrtentry_all_kernel_cache(mrtentry_ptr); change_interfaces(mrtentry_ptr, mrtentry_ptr->incoming, mrtentry_ptr->joined_oifs, mrtentry_ptr->pruned_oifs, mrtentry_ptr->leaves, mrtentry_ptr->asserted_oifs, 0); } SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT); FIRE_TIMER(mrtentry_ptr->jp_timer); } return mrtentry_ptr; }
void delete_srcentry(srcentry_t *src) { mrtentry_t *node; mrtentry_t *next; if (!src) return; /* TODO: XXX: the first entry is unused and always there */ src->prev->next = src->next; if (src->next) src->next->prev = src->prev; for (node = src->mrtlink; node; node = next) { next = node->srcnext; if (node->flags & MRTF_KERNEL_CACHE) /* Delete the kernel cache first */ delete_mrtentry_all_kernel_cache(node); if (node->grpprev) { node->grpprev->grpnext = node->grpnext; } else { node->group->mrtlink = node->grpnext; if (!node->grpnext && !node->group->grp_route) /* Delete the group entry if it has no (*,G) routing entry */ delete_grpentry(node->group); } if (node->grpnext) node->grpnext->grpprev = node->grpprev; FREE_MRTENTRY(node); } free(src); }
void delete_mrtentry(mrtentry_t *mrt) { grpentry_t *grp; mrtentry_t *mrt_wc; mrtentry_t *mrt_rp; if (!mrt) return; /* Delete the kernel cache first */ if (mrt->flags & MRTF_KERNEL_CACHE) delete_mrtentry_all_kernel_cache(mrt); #ifdef RSRR /* Tell the reservation daemon */ rsrr_cache_clean(mrt); #endif /* RSRR */ if (mrt->flags & MRTF_PMBR) { /* (*,*,RP) mrtentry */ mrt->source->mrtlink = NULL; } else if (mrt->flags & MRTF_SG) { /* (S,G) mrtentry */ /* Delete from the grpentry MRT chain */ if (mrt->grpprev) { mrt->grpprev->grpnext = mrt->grpnext; } else { mrt->group->mrtlink = mrt->grpnext; if (!mrt->grpnext) { /* All (S,G) MRT entries are gone. Allow creating (*,G) MFC entries. */ mrt_rp = mrt->group->active_rp_grp->rp->rpentry->mrtlink; mrt_wc = mrt->group->grp_route; if (mrt_rp) mrt_rp->flags &= ~MRTF_MFC_CLONE_SG; if (mrt_wc) mrt_wc->flags &= ~MRTF_MFC_CLONE_SG; else /* Delete the group entry if it has no (*,G) routing entry */ delete_grpentry(mrt->group); } } if (mrt->grpnext) mrt->grpnext->grpprev = mrt->grpprev; /* Delete from the srcentry MRT chain */ if (mrt->srcprev) { mrt->srcprev->srcnext = mrt->srcnext; } else { mrt->source->mrtlink = mrt->srcnext; if (!mrt->srcnext) /* Delete the srcentry if this was the last routing entry */ delete_srcentry(mrt->source); } if (mrt->srcnext) mrt->srcnext->srcprev = mrt->srcprev; } else { /* This mrtentry should be (*,G) */ grp = mrt->group; grp->grp_route = NULL; /* Delete the group entry if it has no (S,G) entries */ if (!grp->mrtlink) delete_grpentry(grp); } FREE_MRTENTRY(mrt); }
/* * Set the iif, join/prune/leaves/asserted interfaces. Calculate and * set the oifs. * Return 1 if oifs change from NULL to not-NULL. * Return -1 if oifs change from non-NULL to NULL * else return 0 * If the iif change or if the oifs change from NULL to non-NULL * or vice-versa, then schedule that mrtentry join/prune timer to * timeout immediately. */ int change_interfaces(mrtentry_t *mrtentry_ptr, vifi_t new_iif, vifbitmap_t new_joined_oifs_, vifbitmap_t new_pruned_oifs, vifbitmap_t new_leaves_, vifbitmap_t new_asserted_oifs, u_int16 flags) { vifbitmap_t new_joined_oifs; /* The oifs for that particular mrtentry */ vifbitmap_t old_joined_oifs; vifbitmap_t old_pruned_oifs; vifbitmap_t old_leaves; vifbitmap_t new_leaves; vifbitmap_t old_asserted_oifs; vifbitmap_t new_real_oifs; /* The result oifs */ vifbitmap_t old_real_oifs; vifi_t old_iif; rpentry_t *rpentry_ptr; cand_rp_t *cand_rp_ptr; kernel_cache_t *kernel_cache_ptr; rp_grp_entry_t *rp_grp_entry_ptr; grpentry_t *grpentry_ptr; mrtentry_t *mrtentry_srcs; mrtentry_t *mrtentry_wc; mrtentry_t *mrtentry_rp; int delete_mrtentry_flag; int return_value; int fire_timer_flag; if (mrtentry_ptr == (mrtentry_t *)NULL) return 0; VIFM_COPY(new_joined_oifs_, new_joined_oifs); VIFM_COPY(new_leaves_, new_leaves); old_iif = mrtentry_ptr->incoming; VIFM_COPY(mrtentry_ptr->joined_oifs, old_joined_oifs); VIFM_COPY(mrtentry_ptr->leaves, old_leaves); VIFM_COPY(mrtentry_ptr->pruned_oifs, old_pruned_oifs); VIFM_COPY(mrtentry_ptr->asserted_oifs, old_asserted_oifs); VIFM_COPY(mrtentry_ptr->oifs, old_real_oifs); mrtentry_ptr->incoming = new_iif; VIFM_COPY(new_joined_oifs, mrtentry_ptr->joined_oifs); VIFM_COPY(new_pruned_oifs, mrtentry_ptr->pruned_oifs); VIFM_COPY(new_leaves, mrtentry_ptr->leaves); VIFM_COPY(new_asserted_oifs, mrtentry_ptr->asserted_oifs); calc_oifs(mrtentry_ptr, &new_real_oifs); if (VIFM_ISEMPTY(old_real_oifs)) { if (VIFM_ISEMPTY(new_real_oifs)) return_value = 0; else return_value = 1; } else { if (VIFM_ISEMPTY(new_real_oifs)) return_value = -1; else return_value = 0; } if ((VIFM_SAME(new_real_oifs, old_real_oifs)) && (new_iif == old_iif) && !(flags & MFC_UPDATE_FORCE)) return 0; /* Nothing to change */ if ((return_value != 0) || (new_iif != old_iif) || (flags & MFC_UPDATE_FORCE)) FIRE_TIMER(mrtentry_ptr->jp_timer); VIFM_COPY(new_real_oifs, mrtentry_ptr->oifs); if (mrtentry_ptr->flags & MRTF_PMBR) { /* (*,*,RP) entry */ rpentry_ptr = mrtentry_ptr->source; if (rpentry_ptr == (rpentry_t *)NULL) return (0); /* Shoudn't happen */ rpentry_ptr->incoming = new_iif; cand_rp_ptr = rpentry_ptr->cand_rp; if (VIFM_ISEMPTY(new_real_oifs)) { delete_mrtentry_flag = TRUE; } else { delete_mrtentry_flag = FALSE; #ifdef RSRR rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK); #endif /* RSRR */ } if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE) { /* Update the kernel MFC entries */ if (delete_mrtentry_flag == TRUE) /* XXX: no need to send RSRR message. Will do it when * delete the mrtentry. */ for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != (kernel_cache_t *)NULL; kernel_cache_ptr = kernel_cache_ptr->next) delete_mrtentry_all_kernel_cache(mrtentry_ptr); else { for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != (kernel_cache_t *)NULL; kernel_cache_ptr = kernel_cache_ptr->next) /* here mrtentry_ptr->source->address is the RP address */ k_chg_mfc(igmp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group, new_iif, new_real_oifs, mrtentry_ptr->source->address); } } /* * Update all (*,G) entries associated with this RP. * The particular (*,G) outgoing are not changed, but the change * in the (*,*,RP) oifs may have affect the real oifs. */ fire_timer_flag = FALSE; for (rp_grp_entry_ptr = cand_rp_ptr->rp_grp_next; rp_grp_entry_ptr != (rp_grp_entry_t *)NULL; rp_grp_entry_ptr = rp_grp_entry_ptr->rp_grp_next) { for (grpentry_ptr = rp_grp_entry_ptr->grplink; grpentry_ptr != (grpentry_t *)NULL; grpentry_ptr = grpentry_ptr->rpnext) { if (grpentry_ptr->grp_route != (mrtentry_t *)NULL) { if (change_interfaces(grpentry_ptr->grp_route, new_iif, grpentry_ptr->grp_route->joined_oifs, grpentry_ptr->grp_route->pruned_oifs, grpentry_ptr->grp_route->leaves, grpentry_ptr->grp_route->asserted_oifs, flags)) fire_timer_flag = TRUE; } else { /* Change all (S,G) entries if no (*,G) */ for (mrtentry_srcs = grpentry_ptr->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) { if (mrtentry_srcs->flags & MRTF_RP) { if (change_interfaces(mrtentry_srcs, new_iif, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, flags)) fire_timer_flag = TRUE; } else { if (change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, flags)) fire_timer_flag = TRUE; } } } } } if (fire_timer_flag == TRUE) FIRE_TIMER(mrtentry_ptr->jp_timer); if (delete_mrtentry_flag == TRUE) { /* TODO: XXX: trigger a Prune message? Don't delete now, it will * be automatically timed out. If want to delete now, don't * reference to it anymore! delete_mrtentry(mrtentry_ptr); */ } return return_value; /* (*,*,RP) */ } if (mrtentry_ptr->flags & MRTF_WC) { /* (*,G) entry */ if (VIFM_ISEMPTY(new_real_oifs)) delete_mrtentry_flag = TRUE; else { delete_mrtentry_flag = FALSE; #ifdef RSRR rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK); #endif /* RSRR */ } if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE) { if (delete_mrtentry_flag == TRUE) delete_mrtentry_all_kernel_cache(mrtentry_ptr); else { for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != (kernel_cache_t *)NULL; kernel_cache_ptr = kernel_cache_ptr->next) k_chg_mfc(igmp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group, new_iif, new_real_oifs, mrtentry_ptr->group->rpaddr); } } /* Update all (S,G) entries for this group. * For the (S,G)RPbit entries the iif is the iif toward the RP; * The particular (S,G) oifs are not changed, but the change in the * (*,G) oifs may affect the real oifs. */ fire_timer_flag = FALSE; for (mrtentry_srcs = mrtentry_ptr->group->mrtlink; mrtentry_srcs != (mrtentry_t *)NULL; mrtentry_srcs = mrtentry_srcs->grpnext) { if (mrtentry_srcs->flags & MRTF_RP) { if (change_interfaces(mrtentry_srcs, new_iif, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, flags)) fire_timer_flag = TRUE; } else { if (change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming, mrtentry_srcs->joined_oifs, mrtentry_srcs->pruned_oifs, mrtentry_srcs->leaves, mrtentry_srcs->asserted_oifs, flags)) fire_timer_flag = TRUE; } } if (fire_timer_flag == TRUE) FIRE_TIMER(mrtentry_ptr->jp_timer); if (delete_mrtentry_flag == TRUE) { /* TODO: XXX: the oifs are NULL. Send a Prune message? */ } return return_value; /* (*,G) */ } if (mrtentry_ptr->flags & MRTF_SG) { /* (S,G) entry */ #ifdef KERNEL_MFC_WC_G vifbitmap_t tmp_oifs; mrtentry_t *mrtentry_tmp; #endif /* KERNEL_MFC_WC_G */ mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink; mrtentry_wc = mrtentry_ptr->group->grp_route; #ifdef KERNEL_MFC_WC_G /* Check whether (*,*,RP) or (*,G) have different (iif,oifs) from * the (S,G). If "yes", then forbid creating (*,G) MFC. */ for (mrtentry_tmp = mrtentry_rp; 1; mrtentry_tmp = mrtentry_wc) { for ( ; 1; ) { if (mrtentry_tmp == (mrtentry_t *)NULL) break; if (mrtentry_tmp->flags & MRTF_MFC_CLONE_SG) break; if (mrtentry_tmp->incoming != mrtentry_ptr->incoming) { delete_single_kernel_cache_addr(mrtentry_tmp, INADDR_ANY_N, mrtentry_ptr->group->group); mrtentry_tmp->flags |= MRTF_MFC_CLONE_SG; break; } calc_oifs(mrtentry_tmp, &tmp_oifs); if (!(VIFM_SAME(new_real_oifs, tmp_oifs))) mrtentry_tmp->flags |= MRTF_MFC_CLONE_SG; break; } if (mrtentry_tmp == mrtentry_wc) break; } #endif /* KERNEL_MFC_WC_G */ if (VIFM_ISEMPTY(new_real_oifs)) delete_mrtentry_flag = TRUE; else { delete_mrtentry_flag = FALSE; #ifdef RSRR rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK); #endif /* RSRR */ } if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE) { if (delete_mrtentry_flag == TRUE) delete_mrtentry_all_kernel_cache(mrtentry_ptr); else { k_chg_mfc(igmp_socket, mrtentry_ptr->source->address, mrtentry_ptr->group->group, new_iif, new_real_oifs, mrtentry_ptr->group->rpaddr); } } if (old_iif != new_iif) { if (new_iif == mrtentry_ptr->source->incoming) { /* For example, if this was (S,G)RPbit with iif toward the RP, * and now switch to the Shortest Path. * The setup of MRTF_SPT flag must be * done by the external calling function (triggered only * by receiving of a data from the source.) */ mrtentry_ptr->flags &= ~MRTF_RP; /* TODO: XXX: delete? Check again where will be the best * place to set it. mrtentry_ptr->flags |= MRTF_SPT; */ } if (((mrtentry_wc != (mrtentry_t *)NULL) && (mrtentry_wc->incoming == new_iif)) || ((mrtentry_rp != (mrtentry_t *)NULL) && (mrtentry_rp->incoming == new_iif))) { /* If the new iif points toward the RP, reset the SPT flag. * (PIM-SM-spec-10.ps pp. 11, 2.10, last sentence of first * paragraph. */ /* TODO: XXX: check again! */ mrtentry_ptr->flags &= ~MRTF_SPT; mrtentry_ptr->flags |= MRTF_RP; } } /* TODO: XXX: if this is (S,G)RPbit entry and the oifs==(*,G)oifs, * then delete the (S,G) entry?? The same if we have (*,*,RP) ? */ if (delete_mrtentry_flag == TRUE) { /* TODO: XXX: the oifs are NULL. Send a Prune message ? */ } /* TODO: XXX: have the feeling something is missing.... */ return return_value; /* (S,G) */ } return return_value; }