/* * Initialize the children and leaf bits for route 'r', along with the * associated dominant, subordinate, and leaf timing data structures. * Return TRUE if this changes the value of either the children or * leaf bitmaps for 'r'. */ static int init_children_and_leaves(struct rtentry *r, vifi_t parent) { register vifi_t vifi; register struct uvif *v; vifbitmap_t old_children, old_leaves; VIFM_COPY(r->rt_children, old_children); VIFM_COPY(r->rt_leaves, old_leaves ); VIFM_CLRALL(r->rt_children); VIFM_CLRALL(r->rt_leaves); r->rt_flags &= ~RTF_LEAF_TIMING; for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { r->rt_dominants [vifi] = 0; r->rt_subordinates[vifi] = 0; if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { VIFM_SET(vifi, r->rt_children); if (v->uv_neighbors == NULL) { VIFM_SET(vifi, r->rt_leaves); r->rt_leaf_timers[vifi] = 0; } else { r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; r->rt_flags |= RTF_LEAF_TIMING; } } else { r->rt_leaf_timers[vifi] = 0; } } return (!VIFM_SAME(r->rt_children, old_children) || !VIFM_SAME(r->rt_leaves, old_leaves)); }
/* * 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; }