/* * @(#) $Id: rsvp_resv.c,v 4.62 1998/09/25 00:28:50 lindell Exp $ */ /************************ rsvp_resv.c ******************************* * * * Routines to receive, process, and send Resv and ResvTear * * messages. * * * * * *********************************************************************/ /**************************************************************************** RSVPD -- ReSerVation Protocol Daemon USC Information Sciences Institute Marina del Rey, California Original Version: Shai Herzog, Nov. 1993. Current Version: Steven Berson & Bob Braden, may 1996. Copyright (c) 1998 by the University of Southern California All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation in source and binary forms for any purpose and without fee is hereby granted, provided that both the above copyright notice and this permission notice appear in all copies, and that any documentation, advertising materials, and other materials related to such distribution and use acknowledge that the software was developed in part by the University of Southern California, Information Sciences Institute. The name of the University may not be used to endorse or promote products derived from this software without specific prior written permission. THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Other copyrights might apply to parts of this software and are so noted when applicable. ********************************************************************/ #include "rsvp_daemon.h" #ifdef LABEL #include #include #include "rsvp_label.h" #endif /* Define some global objects * */ STYLE Style_Obj; CONFIRM Confirm_Obj; /* The following globals are used in merging reservations across * different PSB's for the same PHOP. */ static FLOWSPEC *max_specp; static RSB *confRSBp; static Fobject *UnkObjL_perPHOP; #ifdef LABEL extern int cbqfd; extern Label * new_label_obj(u_char); extern u_int32_t Get_Label(int); extern int Free_Label(char *, u_int32_t); #endif /* External declarations */ Session *locate_session(SESSION *); Session *locate_session_p(SESSION *); struct packet *new_packet_area(packet_area *); int match_filter(FILTER_SPEC *, FILTER_SPEC *); int Compare_Flowspecs(FLOWSPEC *, FLOWSPEC *); FLOWSPEC *LUB_of_Flowspecs(FLOWSPEC *, FLOWSPEC *); FLOWSPEC *GLB_of_Flowspecs(FLOWSPEC *, FLOWSPEC *); int addTspec2sum(SENDER_TSPEC *, SENDER_TSPEC *); int Compare_Tspecs(SENDER_TSPEC *, SENDER_TSPEC *); u_int32_t Compute_R(TIME_VALUES *), Compute_TTD(TIME_VALUES *); int match_scope(SCOPE *, SCOPE *); int form_scope_union(Session *); void scope_catf(SCOPE **, FILTER_SPEC *); void rsvp_resv_err(int, int, int, FiltSpecStar *, struct packet *); void rsvp_RSB_err(Session *, RSB *, int, int); Object_header *copy_object(Object_header *); void api_RESV_EVENT_upcall(Session *, RSB *); int send_pkt_out_if(int, RSVP_HOP *, struct packet *); void send_confirm(Session *, RSB *); void clear_scope_union(Session *); char *fmt_flowspec(FLOWSPEC *); char *fmt_tspec(SENDER_TSPEC *); char *cnv_flags(char *, u_char); void FQkill(Fobject **); void merge_UnkObjL2(Fobject **, Fobject **, int); int match_policy(POLICY_DATA *, POLICY_DATA *); /* Link-layer Call-back routines. * These core-RSVP routines perform processing that must * follow completion of a corresponding LLDAL call. * This is because LLDAL calls may invoke link-layer control * functions that will not complete immediately, and avoids * internal threading of rsvpd. When an LLDAL call is * asynchronous, it will return an immediate code indicating * that, and then the LLDAL will invoke the call-back routine * with the real return code when the function does complete. */ int Complete_NewFlow(Session *, RSB *, int); int Complete_ModFlowspec(Session *, RSB *, int); int Complete_ModFilter(Session *, RSB *, int); int Complete_DelFlow(Session *, RSB *, int); /* Forward declarations */ int accept_resv(int, struct packet *); int accept_resv_tear(int, struct packet *); int flow_reservation(Session *, struct packet *, int, FLOWSPEC *, FiltSpecStar *); void resv_tear_PSB(Session *, PSB *, style_t, FILTER_SPEC *, struct packet *); void delete_resv4PSB(Session *, PSB *); static void send_resv_out(PSB *, struct packet *); void common_resv_header(struct packet *, Session *); void common_resv_tear_header(struct packet *, Session *); RSB * make_RSB(Session *, int count); int enlarge_RSB_filtstar(RSB *); RSB * locate_RSB(Session *, RSVP_HOP *, FiltSpecStar *, style_t); RSB * RSB_match_path(Session *, PSB *); int kill_RSB(Session *, RSB *); void kill_newRSB(Session *, RSB *); int kill_RSB1(Session *, RSB *, int); void resv_update_ttd(RSB *, u_int32_t); int resv_refresh(Session *, int); int resv_refresh_TimeOut(Session *); int resv_refresh_PSB(Session *, PSB *, struct packet *, int); void PSB_update_LL(Session *, PSB *); FiltSpecStar * Get_FiltSpecStar(int); int find_fstar(FILTER_SPEC *, FiltSpecStar *); int match_filt2star(FILTER_SPEC *, FiltSpecStar *); int set_need_scope(Session *); int Styles_are_compat(style_t, style_t); int IsRoutePSB2nhop(Session *, PSB *, RSVP_HOP *); int is_scope_needed(Session *, PSB *); void process_dummy_rtear(struct packet *); void coalesce_filtstar(FiltSpecStar *); int sameas_last_spec(FLOWSPEC **, FLOWSPEC *); void process_dummy_rtear(struct packet *pkt); void map2FiltStar(struct packet *, FiltSpecStar *); #ifdef LABEL void set_label(Label **,PSB *); void print_labels(Label *); #endif /* * Common routines used by link-layer adaptation modules */ int Is_B_Police(Session *, RSB *); int Compute_Path_Props(Session *, RSB *, FiltSpecStar *, SENDER_TSPEC *, ADSPEC **, int *); #define PSBmaps2RSB(destp, sp, rp) \ (IsRoutePSB2nhop(destp,sp,&rp->rs_rsvp_nhop) \ && (Style_is_Wildcard(rp->rs_style) \ || match_filt2star(sp->ps_templ, rp->rs_filtstar))) /* * accept_resv(): Process incoming Resv message, which is in host * byte order. It may be real packet from remote node or internal * packet from local API. * * pkt struct includes: * pkt_data -> packet buffer * pkt_map -> map of objects in packet * pkt_ttl = TTL with which it arrived (if not UDP) * pkt_flags & PKTFLG_USE_UDP: was it encapsulated? * * This routine does the common checking and then calls * flow_reservation() for each distinct flow descriptor packed * into the message. * */ int accept_resv( int vif, /* Phyint on which Resv msg arrived */ struct packet *pkt) { int out_vif; Session *destp; int i, rc; int need_refresh = 0; style_t style; FiltSpecStar filtss, *filtssp; FLOWSPEC *specp; RSB *rp; assert(pkt->pkt_order == BO_HOST); style = Style(pkt); /* Determine Outgoing Interface OI. * * The logical outgoing interface OI is taken from the LIH in * the NHOP object (non-RSVP cloud may cause packet to appear on * another interface). */ out_vif = IsHopAPI(pkt->rsvp_nhop) ? api_num : hop_lih(pkt->rsvp_nhop); Incr_ifstats(out_vif, rsvpstat_msgs_in[RSVP_RESV]); /* Check that INTEGRITY was included if it is required. */ if ((IF_FLAGS(out_vif)&IF_FLAG_Intgrty) && pkt->pkt_map->rsvp_integrity == NULL) return PKT_ERR_INTEGRITY; /* Look for path state. If it does not exist, send * "No path info" ResvErr msg. If there is confusion about * zero DstPorts, send "Conflicting Dest ports" error. */ destp = locate_session_p(pkt->rsvp_sess); if (!destp) { rsvp_resv_err(RSVP_Err_NO_PATH, 0, 0, (FiltSpecStar *) -1 /*all*/, pkt); return(-1); } else if ((int)destp == -1) { rsvp_resv_err(RSVP_Err_BAD_DSTPORT, 0, 0, (FiltSpecStar *) -1 /*all*/, pkt); return(-1); } /* * Check for incompatible styles, and if found, reject message * with a "Conflicting style" error. * Note: We use the strictest interpretation of conflicting * styles: every RSB in a node must use the same style. * Since the two directions of data flow through a node are * independent and never their reservations are not merged, * this is stronger than necessary. But the less strict test * would require deciding which RSB's cannot be merged together, * which would require nested loops over PSBs and RSBs. * */ for (rp = destp->d_RSB_list; rp != NULL; rp = rp->rs_next) { if (!Styles_are_compat(rp->rs_style, style)) { rsvp_resv_err(RSVP_Err_BAD_STYLE, 0, 0, (FiltSpecStar *) -1 /*all*/, pkt); return(-1); } } /* Process the flow descriptor list to make reservations, * depending upon the style. Filtss is a filter spec list. */ switch (style) { case STYLE_WF: if (!pkt->rsvp_scope) Incr_ifstats(out_vif, rsvpstat_no_inscope); specp = spec_of(FlowDesc_of(pkt, 0)); rc = flow_reservation(destp, pkt, out_vif, specp, NULL); break; case STYLE_FF: /* Style FF: execute independently for each flow * descriptor in the message. */ rc = -1; filtss.fst_count = 1; for (i = 0; i < pkt->rsvp_nflwd; i++) { int trc; filtss.fst_Filtp(0) = filter_of(FlowDesc_of(pkt, i)); filtss.fst_Filt_TTD(0) = 0; #ifdef LABEL if((FlowDesc_of(pkt, i))->rsvp_label){ filtss.fst_Labelp(0) = (FlowDesc_of(pkt,i))->rsvp_label; #ifdef DEBUG print_labels(filtss.fst_Labelp(0)); #endif } else filtss.fst_Labelp(0) = NULL; #endif specp = spec_of(FlowDesc_of(pkt, i)); trc = flow_reservation(destp, pkt, out_vif, specp, &filtss); rc = MAX(trc, rc); } break; case STYLE_SE: /* Obtain storage and construct FILTER_SPEC*, i.e., * list of FILTER_SPECs, dynamically. */ filtssp = Get_FiltSpecStar(pkt->rsvp_nflwd); if (!filtssp) { Log_Mem_Full("Resv1"); return(-1); } map2FiltStar(pkt, filtssp); specp = spec_of(FlowDesc_of(pkt, 0)); rc = flow_reservation(destp, pkt, out_vif, specp, filtssp); free(filtssp); break; default: rsvp_resv_err(RSVP_Err_UNKNOWN_STYLE, 0, 0, (FiltSpecStar *) -1 /*all*/, pkt); break; } if (rc < 0) return(-1); else if (rc > 0) need_refresh = 1; /* * If any resv succeeded and refresh timer has not * been started, start it now. */ if (destp->d_RSB_list && (Compute_R(&destp->d_timevalr) == 0)) add_to_timer((char *) destp, TIMEV_RESV, destp->d_Rtimor); /* If the refresh_needed flag is now on, execute * resv_refresh to send immediate refresh through every * interface noted in d_r_incifs. */ dump_ds(need_refresh); if (need_refresh) resv_refresh(destp, 0); return(0); } /* * flow_reservation(): Process a given flow descriptor within a Resv * msg, by finding or creating an RSB. But if an error is found, * create no RSB, send ResvErr message, and return. * * Returns: -1 for error * 1 OK, refresh needed * 0 OK, no refresh */ int flow_reservation( Session *destp, /* Session */ Resv_pkt *pkt, /* Packet itself */ int out_vif, /* True Outgoing interface */ FLOWSPEC *specp, /* Flowspec */ FiltSpecStar *filtssp) /* FILTER_SPEC* or NULL(WF) */ { RSB *rp; PSB *sp; FILTER_SPEC *filtp; int NeworMod = 0; int new_RSB = 0; int sender_cnt, i, rc, nfilt; u_int32_t time2die; style_t style = Style(pkt); #ifdef LABEL PSB *lpsb; static int lflag = 1; static LabelTableEntryPtr ltentry; #endif nfilt = (Style_is_Wildcard(style))? 0 : filtssp->fst_count; /* Check the path state, as follows. * * 1. Locate the set of PSBs (senders) that route to OI and * whose SENDER_TEMPLATES match *filtssp. * * Count these PSBs, and add OI to a bit vector of * incoming interfaces for immediate refresh. */ sender_cnt = 0; for (sp = destp->d_PSB_list ; sp != NULL; sp = sp->ps_next) { if (!IsRoutePSB2nhop(destp, sp, pkt->pkt_map->rsvp_hop)) continue; i = find_fstar(sp->ps_templ, filtssp); if (i >= 0) { if (!Style_is_Wildcard(style)) filtssp->fst_Filt_TTD(i) = 1; sender_cnt++; bmp_set(&(destp->d_r_incifs), sp->ps_in_if); lpsb = sp; } } if (sender_cnt == 0) { /* If this set is empty, build and send an error message * specifying "No Sender Information", and continue with * the next flow descriptor in the Resv message. * * XXX We are using permissive interpretation for SE: OK * if ANY of its FILTER_SPECs matches a sender. */ rsvp_resv_err(RSVP_Err_NO_SENDER, 0, 0, filtssp, pkt); return(-1); } /* Else delete from Filtss any FILTER_SPECs that match no PSB, */ else if (sender_cnt < nfilt) coalesce_filtstar(filtssp); /* * o Find or create a reservation state block (RSB) for * (SESSION, NHOP). If the style is distinct, Filtss is also * used in the selection. Call this the "active RSB". * * o Start or restart the cleanup timer on the active RSB, or, * in the case of SE style, on each FILTER_SPEC of the RSB * that also appears in Filtss. */ time2die = Compute_TTD(pkt->pkt_map->rsvp_timev); rp = locate_RSB(destp, pkt->pkt_map->rsvp_hop, filtssp, style); if (!rp) { rp = make_RSB(destp, nfilt); if (!rp) { Log_Mem_Full("Resv3"); return(-1); } new_RSB = 1; /* Active RSB is new: * 1. Set NHOP, OI, and style from message. * 2. Copy FILTER_SPEC* into the RSB. * 3. Copy the FLOWSPEC and any SCOPE object into RSB. * 4. Set NeworMod flag on. */ rp->rs_nhop = *pkt->rsvp_nhop; if(session_multicast(destp->d_session)) rp->label_nhop = destp->d_session->sess4_addr.s_addr; else #ifdef TUNNEL dst.sin_len = sizeof(dst); dst.sin_family = AF_INET; dst.sin_addr.s_addr = pkt->rsvp_nhop->hop4_addr.s_addr; rp->label_nhop = get_nhop(dst); #else rp->label_nhop = pkt->rsvp_nhop->hop4_addr.s_addr; #endif printf("%x \n",rp->label_nhop); rp->rs_OIf = out_vif; rp->rs_style = Style(pkt); for (i = 0; i < nfilt; i++) { filtp = copy_filter(filtssp->fst_Filtp(i)); if (!filtp && (filtssp->fst_Filtp(i))) { kill_newRSB(destp, rp); Log_Mem_Full("Resv5"); return(-1); } rp->rs_Filtp(i) = filtp; rp->rs_Filt_TTD(i) = time2die; rp->rs_fcount++; } rp->rs_spec = copy_spec(specp); if (!rp->rs_spec) { kill_newRSB(destp, rp); Log_Mem_Full("Resv4"); return(-1); } if (pkt->pkt_map->rsvp_scope_list) { rp->rs_scope= copy_scope(pkt->pkt_map->rsvp_scope_list); if (!rp->rs_scope) { kill_newRSB(destp, rp); Log_Mem_Full("Resv6"); return(-1); } } #ifdef LABEL /* * Copies label stack into RSB */ if (!Style_is_Wildcard(style)){ if(lpsb->ps_label_req != NULL) { if (filtssp->fst_Labelp(0)!= NULL) { rp->rs_label = (Label*)copy_object((Object_header *) filtssp->fst_Labelp(0)); /* Removed by SAS 12/29/99 lpsb->ps_label_out[in_vif] = rp->rs_label; */ rp->rs_labelout = rp->rs_label->label_obj; } strcpy(rp->label_ifname,if_vec[lpsb->ps_in_if].if_name); #ifdef EDGE if(lpsb->as_label_ident == 1) { rp->action_flag = LTE_PUSH; } else if(lpsb->as_label_ident == 0) { set_label(&(rp->rs_label),lpsb); rp->action_flag = LTE_POP; } else if(lpsb->as_label_ident == 2) { set_label(&(rp->rs_label),lpsb); rp->action_flag = LTE_SWAP; } #else if(strcmp(if_vec[lpsb->ps_in_if].if_name,"API")) { set_label(&(rp->rs_label),lpsb); } if(pkt->rsvp_nhop->hop4_addr.s_addr == 0) { ltentry = (LabelTableEntryPtr)malloc(sizeof(LabelTableEntry)); ltentry->lteNewLabel = 0; ltentry->lteLabel = rp->rs_label->label_obj; ltentry->lteFlags = LTE_POP; if(destp->d_session->sess_header.obj_ctype == ctype_SESSION_lsp_tunv4) { ltentry->lteDest = destp->d_session->sesslsp_addr.s_addr; ltentry->lteDestLtpPort = 0; ltentry->lteDestLtpProtocol = 0; ltentry->lteSourceLtpPort = 0; ltentry->lteSourceLtpProtocol = 0; ltentry->lteSource = 0; } else { ltentry->lteDest = destp->d_session->sess4_addr.s_addr; ltentry->lteDestLtpPort = destp->d_session->sess4_port; ltentry->lteDestLtpProtocol = destp->d_session->sess4_prot; ltentry->lteSourceLtpPort = filtp->filt4_srcport; ltentry->lteSourceLtpProtocol = destp->d_session->sess4_prot; ltentry->lteSource = filtp->filt4_srcaddr.s_addr; } ltentry->lteDestLtpPad = 0; ltentry->lteSourceLtpPad = 0; ltentry->lteNextHopAddr = rp->label_nhop; ltentry->lteCoS = 0; /* Not supported so far */ ltentry->lteStatsOut = 0; /* Not supported so far */ strcpy((rp->label_ifname),"\0"); if(pass_msg_2_rtsock(ltentry, NULL, LABEL_ADD) < 0) { rsvp_resv_err(RSVP_Err_NO_LABEL, 0 , 0, filtssp, pkt); return -1; } } #endif } } #endif clear_scope_union(destp); /* Set to recompute scope union */ NeworMod = 1; /* Pass new flow to link layer */ rc = LL_NewFlow(rp->rs_OIf, destp, rp); if (rc != LLDAL_RC_LATER) /* synchronous */ Complete_NewFlow(destp, rp, rc); if (rc == LLDAL_RC_ERROR) return(-1); } /* If the active RSB is not new, check whether Filtss from the * message contains FILTER_SPECs that are not in the RSB; if * so, add the new FILTER_SPECs and then invoke LL_ModFilter. * Also update timeout on each filter. * Note that we allow the order to change, requiring an N*N search. */ else { int NewFilter = 0; for (i= 0; i < nfilt; i++) { FILTER_SPEC *nu_filtp = filtssp->fst_Filtp(i); int j; j = find_fstar(nu_filtp, rp->rs_filtstar); if (j < 0) { j = find_fstar(NULL, rp->rs_filtstar); if (j < 0) { if (!enlarge_RSB_filtstar(rp)) { Log_Mem_Full("Resv7"); return(-1); } j = find_fstar(NULL, rp->rs_filtstar); } rp->rs_Filtp(j) = copy_filter(nu_filtp); NewFilter = 1; } rp->rs_Filt_TTD(j) = time2die; } if (NewFilter) { NeworMod = 1; rc = LL_ModFilter(rp->rs_OIf, destp, rp); if (rc != LLDAL_RC_LATER) /* synchronous */ Complete_ModFilter(destp, rp, rc); if (rc == LLDAL_RC_ERROR) return(-1); } } /* Free any old list of unknown objects, and save any new list. */ FQkill(&rp->rs_UnkObjList); rp->rs_UnkObjList = pkt->pkt_map->rsvp_UnkObjList; pkt->pkt_map->rsvp_UnkObjList = NULL; resv_update_ttd(rp, time2die); /* * If the message contained a RESV_CONFIRM object, copy it * into the RSB and turn on the NeworMod flag. */ if (pkt->pkt_map->rsvp_confirm) { rp->rs_confirm = (CONFIRM *) copy_object( (Object_header *) pkt->pkt_map->rsvp_confirm); NeworMod = 1; } if (!new_RSB) { /* * If active RSB is not new, check whether STYLE, FLOWSPEC, * or SCOPE objects have changed; if so, copy changed * object into RSB and turn on the NeworMod flag. */ #ifdef LABEL if((rp->rs_label) && (lflag == 0)) { if(pass_msg_2_rtsock(ltentry, NULL, LABEL_ADD) < 0) { lflag = 0; rsvp_resv_err(RSVP_Err_NO_LABEL, 0 , 0, filtssp, pkt); return(-1); } } else lflag = 1; #endif if (rp->rs_style != style) { rp->rs_style = style; NeworMod = 1; } if (Compare_Flowspecs(specp, rp->rs_spec) != SPECS_EQL) { /* If flowspec has changed, keep old one in case * Admission Control fails, and pass new one * to link layer. */ rp->rs_oldspec = rp->rs_spec; rp->rs_spec = copy_spec(specp); rc = LL_ModFlowspec(rp->rs_OIf, destp, rp); if (rc != LLDAL_RC_LATER) /* synchronous */ Complete_ModFlowspec(destp, rp, rc); if (rc == LLDAL_RC_ERROR) return(-1); NeworMod = 1; } if ((pkt->pkt_map->rsvp_scope_list) && !match_scope(rp->rs_scope, pkt->pkt_map->rsvp_scope_list)){ clear_scope_union(destp); /* Recompute scope union */ if (rp->rs_scope) free(rp->rs_scope); rp->rs_scope = copy_scope(pkt->pkt_map->rsvp_scope_list); NeworMod = 1; } } return(NeworMod); } int Complete_NewFlow(Session *destp, RSB *rp, int rc) { if (rc == LLDAL_RC_ERROR) { /* * Admission Control failed for new RSB. Send * error msg using side-effect variable rsvp_errno * and delete RSB. */ rsvp_RSB_err(destp, rp, Get_Errcode(rsvp_errno), Get_Errval(rsvp_errno) /* , 0 XXX */); kill_newRSB(destp, rp); return(-1); } /* If resv state (may have) changed and not API, * do RESV_EVENT upcall now. */ if (!IsHopAPI(&rp->rs_nhop)) api_RESV_EVENT_upcall(destp, rp); return(0); } int Complete_ModFlowspec(Session *destp, RSB *rp, int rc) { if (rc == LLDAL_RC_ERROR) { /* * Admission Control failed for existing RSB. Send * error msg using side-effect variable rsvp_errno * and restore previous flowspec. Delete any * confirmation object. */ rsvp_RSB_err(destp, rp, Get_Errcode(rsvp_errno), Get_Errval(rsvp_errno) /* , ERROR_SPECF_InPlace XXX */); if (rp->rs_oldspec) { free((char *) rp->rs_spec); rp->rs_spec = rp->rs_oldspec; rp->rs_oldspec = NULL; } if (rp->rs_confirm) free(rp->rs_confirm); rp->rs_confirm = NULL; return(-1); } else if (rp->rs_oldspec) { free((char *) rp->rs_oldspec); rp->rs_oldspec = NULL; } /* If resv state (may have) changed and network reservation, * do RESV_EVENT upcall now. */ if (!IsHopAPI(&rp->rs_nhop)) api_RESV_EVENT_upcall(destp, rp); return(0); } int Complete_ModFilter(Session *destp, RSB *rp, int rc) { if (rc == LLDAL_RC_ERROR) { rsvp_RSB_err(destp, rp, Get_Errcode(rsvp_errno), Get_Errval(rsvp_errno) /* , ERROR_SPECF_InPlace XXX */); return(-1); } /* If resv state (may have) changed and not API, * do RESV_EVENT upcall now. */ if (!IsHopAPI(&rp->rs_nhop)) api_RESV_EVENT_upcall(destp, rp); return(0); } int Complete_DelFlow(Session *destp, RSB *rp, int rc) { /* If resv state (may have) changed and not from API, * do RESV_EVENT upcall now. * Mark as teardown by deleting flowspec. */ if (!IsHopAPI(&rp->rs_nhop)) { free(rp->rs_spec); rp->rs_spec = NULL; api_RESV_EVENT_upcall(destp, rp); } return(0); } /* * accept_resv_tear(): Process an incoming ResvTear message */ int accept_resv_tear( int in_if, /* Alleged outgoing iface (IGNORED) */ struct packet *pkt) { Session *destp; PSB *sp; RSB *rp; FiltSpecStar filtss; packet_area data; struct packet *outpkt; int out_vif; style_t style = Style(pkt); int Refresh_Needed; int m_size = (char *) &pkt->pkt_map->rsvp_list - (char *) pkt->pkt_map; int i, j, nmatch, rc; RSVP_HOP *nhopp; #ifdef LABEL LabelTableEntryPtr ltentry; int label_rem_flag = 0; u_int32_t label_array[256]; #endif /* The logical outgoing interface OI is taken from the LIH in * the NHOP object. */ /* Changed by Mohit from * out_vif = hop_lih(pkt->rsvp_nhop); */ out_vif = IsHopAPI(pkt->rsvp_nhop) ? api_num : hop_lih(pkt->rsvp_nhop); nhopp = pkt->pkt_map->rsvp_hop; Incr_ifstats(out_vif, rsvpstat_msgs_in[RSVP_RESV_TEAR]); /* Check that INTEGRITY was included if it is required. */ if ((IF_FLAGS(out_vif)&IF_FLAG_Intgrty) && pkt->pkt_map->rsvp_integrity == NULL) return PKT_ERR_INTEGRITY; destp = locate_session(pkt->rsvp_sess); if (!destp) return(0); /* Check that styles match. Send BAD_STYLE error if not, * and ignore ResvTear message [THIS CASE NOT IN SPEC] */ if ((rp = destp->d_RSB_list) && (rp->rs_style != style)) { rsvp_resv_err(RSVP_Err_BAD_STYLE, 0, 0, (FiltSpecStar *) -1 /*all*/, pkt); return(0); } /* Process the flow descriptor list in the ResvTear message to * tear down local reservation state in style-dependent manner. */ if (!Style_is_Shared(style)) { /* FF */ filtss.fst_count = 1; for (i = 0; i < pkt->rsvp_nflwd; i++) { filtss.fst_filtp0 = filter_of(FlowDesc_of(pkt, i)); rp = locate_RSB(destp, nhopp, &filtss, style); #ifdef LABEL if(rp) if(nhopp->hop4_addr.s_addr ==0) if(rp->rs_label) { label_rem_flag = 1; (FlowDesc_of(pkt,i))->rsvp_label = rp->rs_label; label_array[i] = rp->rs_label->label_obj; ltentry = (LabelTableEntryPtr)malloc(sizeof(LabelTableEntry)); ltentry->lteNewLabel = 0; ltentry->lteLabel = rp->rs_label->label_obj; ltentry->lteFlags = LTE_POP; if(destp->d_session->sess_header.obj_ctype == ctype_SESSION_lsp_tunv4) { ltentry->lteDest = destp->d_session->sesslsp_addr.s_addr; ltentry->lteDestLtpPort = 0; ltentry->lteDestLtpProtocol = 0; ltentry->lteSourceLtpPort = 0; ltentry->lteSourceLtpProtocol = 0; ltentry->lteSource = 0; } else { ltentry->lteDest = destp->d_session->sess4_addr.s_addr; ltentry->lteDestLtpPort = destp->d_session->sess4_port; ltentry->lteDestLtpProtocol = destp->d_session->sess4_prot; ltentry->lteSourceLtpPort = filtss.fst_filtp0->filt4_srcport; ltentry->lteSourceLtpProtocol = destp->d_session->sess4_prot; ltentry->lteSource = filtss.fst_filtp0->filt4_srcaddr.s_addr; } ltentry->lteDestLtpPad = 0; ltentry->lteSourceLtpPad = 0; ltentry->lteNextHopAddr = rp->label_nhop; ltentry->lteCoS = 0; /* Not supported so far */ if(pass_msg_2_rtsock(ltentry, "\0", LABEL_DELETE)<0){ rsvp_resv_err(RSVP_Err_NO_LABEL, 0 , 0, NULL, pkt); return -1; } else rp->rs_label = NULL; } #endif /* LABEL */ Refresh_Needed |= kill_RSB(destp, rp); } } else { /* WF or SE */ rp = locate_RSB(destp, nhopp, NULL, style); if (!rp) return(0); /* * Mark filter specs to be torn down */ for (i=0; i < pkt->rsvp_nflwd; i++) { for (j= 0; j < rp->rs_fcount; j++) { if (match_filter( filter_of(FlowDesc_of(pkt, i)), rp->rs_Filtp(j))) { free(rp->rs_Filtp(j)); rp->rs_Filt_TTD(j) = 0; } } } /* Squeeze out marked filter spec entries. If filters * are all gone, delete RSB and update LL; else just * update LL. */ coalesce_filtstar(rp->rs_filtstar); if (rp->rs_fcount == 0) Refresh_Needed |= kill_RSB(destp, rp); else { rc = LL_ModFilter(rp->rs_OIf, destp, rp); if (rc != LLDAL_RC_LATER) Complete_ModFilter(destp, rp, rc); if (rc == LLDAL_RC_ERROR) return(-1); } } /* Create ResvTear msg template. Copy into map everything * up to flow descriptor list. Make a separate copy of the * HOP object, since we will change it when we send Tear msg(s). */ outpkt = new_packet_area(&data); memcpy((char*) outpkt->pkt_map, (char *) pkt->pkt_map, m_size); outpkt->pkt_map->rsvp_hop = (RSVP_HOP *) copy_object((Object_header *)nhopp); outpkt->pkt_map->rsvp_UnkObjList = pkt->pkt_map->rsvp_UnkObjList; outpkt->rsvp_scope = NULL; outpkt->rsvp_nflwd = 0; /* Forward ResvTear messages to all PHOPs whose PSBs route * to the RSB that has been deleted. Include a particular * sender only if there are no other RSBs that were merged * with the deleted RSB. * * Select each PSB whose OutInterface_list includes the * outgoing interface OI (more strictly, that routes to NHOP). * For distinct style, SENDER_TEMPLATE must also match a * filter spec in the received ResvTear. * * This logic assumes that PSBs are ordered by phop address. */ nmatch = 0; for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next) { if (IsHopAPI(&sp->ps_phop)) continue; if (!IsRoutePSB2nhop(destp, sp, nhopp)) continue; if (Style_is_Wildcard(style)) { nmatch++; resv_tear_PSB(destp, sp, Style(pkt), NULL, outpkt); } else { for (j = 0; j < pkt->rsvp_nflwd; j++) { if (match_filter(sp->ps_templ, filter_of(FlowDesc_of(pkt, j)))) { nmatch++; /* Do PSB-specific processing to build * flow descriptor list in outpkt, if * appropriate. */ resv_tear_PSB(destp, sp, Style(pkt), filter_of(FlowDesc_of(pkt,j)), outpkt); #ifdef LABEL (FlowDesc_of(outpkt,j))->rsvp_label = (FlowDesc_of(pkt,j))->rsvp_label; if(!session_multicast(destp->d_session)) { sp->ps_label_out[in_if] = NULL; if(label_rem_flag) Free_Label(if_vec[sp->ps_in_if].if_name, label_array[j]); } #endif } } } /* If the next PSB is for a different PHOP or the last * PSB has been processed, forward any ResvTear message * that has been built. */ if (sp->ps_next == NULL || !hop_addr_eq(&sp->ps_next->ps_phop,&sp->ps_phop)) { if (outpkt->rsvp_nflwd) send_resv_out(sp, outpkt); outpkt->rsvp_nflwd = 0; } } /* If any PSB's were found in the preceding step, and if the * Resv_Refresh_Needed flag is now on, execute the RESV REFRESH * sequence. resv_tear_PSB has set bits for incoming * interfaces to be refreshed. */ if (nmatch > 0 && (Refresh_Needed)) resv_refresh(destp, 0); free(outpkt->pkt_map->rsvp_hop); dump_ds(1); /* Log state change */ return(0); } /* Do PSB-specific processing to create Resv_Tear message: build flow * descriptor list in outpkt. */ void resv_tear_PSB( Session *destp, PSB *sp, style_t style, FILTER_SPEC *filtp, /* NULL for wildcard */ struct packet *outpkt) { FlowDesc *outflwdp; PSB *BSBp, *tsp; /* Delete last FLOWSPEC sent to this PSB, and blockade state. */ tsp = (Style_is_Wildcard(style))? sp->ps_1stphop: sp; if (tsp->ps_resv_spec) { free(tsp->ps_resv_spec); tsp->ps_resv_spec = NULL; } BSBp = tsp; if (BSBp->ps_BSB_Qb) { free(BSBp->ps_BSB_Qb); BSBp->ps_BSB_Qb = NULL; BSBp->ps_BSB_Tb = 0; } /* - Search for an RSB (for any outgoing interface) to which the * PSB routes and whose FILTER_SPEC matches the PSB. * * - If an RSB is found, set to send a Resv refresh message to * it, and return. */ if (RSB_match_path(destp, sp)) { bmp_set(&(destp->d_r_incifs), sp->ps_in_if); return; } /* - Otherwise, add filter spec to the new ResvTear message * being built. We omit flowspec, as the protocol spec allows. */ outflwdp = FlowDesc_of(outpkt, outpkt->rsvp_nflwd); outflwdp->rsvp_specp = NULL; if (!Style_is_Wildcard(style) || outpkt->rsvp_nflwd == 0) { outflwdp->rsvp_filtp = filtp; outpkt->rsvp_nflwd++; } } /* * Resv refresh timeout has occurred. Refresh all Resv state for * given session. */ int resv_refresh_TimeOut(Session *destp) { PSB *sp; /* Clear last_FLOWSPEC pointers in all PSBs, and then * call common routine resv_refresh(). */ for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next) { if (sp->ps_resv_spec) free(sp->ps_resv_spec); sp->ps_resv_spec = NULL; } return resv_refresh(destp, 0); } /* * resv_refresh(): Sends refresh Resv refresh message(s). * * Spec says resv refreshes are to be sent to specific PHOPs, or * to all PHOPs. This implementation cuts a corner, by sending * resv refreshes to specific incoming interfaces, selected by * bits in d_r_incifs; no bits => all. * * Parameter IsResvErr is 1 if entered from processing ResvErr. * * Returns: 0 if timer should be rescheduled, else -1. */ int resv_refresh(Session *destp, int IsResvErr) { struct packet *pkt; packet_area data; PSB *sp; RSB *rp; style_t style; /* Time out any expired state for this Session, and if it's * all gone, return -1 => cancel refresh timer. */ cleanup_resv_state(destp); /* Create an output message containing INTEGRITY, * SESSION, RSVP_HOP, and TIME_VALUES objects. */ pkt = new_packet_area(&data); common_resv_header(pkt, destp); /* * Determine style for these reservations from the first * RSB for the session, and move the STYLE object into * the proto-message. */ rp = destp->d_RSB_list; if (!rp) return(-1); style = rp->rs_style; pkt->pkt_map->rsvp_style = &Style_Obj; Init_Object(&Style_Obj,STYLE,STYLE_CTYPE); Style_of(pkt)->style_word = style; /* If style is wildcard, form union of SCOPE lists from RSB's, * with local senders deleted. Call this scope_union. */ if (Style_is_Wildcard(style)) form_scope_union(destp); /* Initialize globals. Then select each sender PSB for desired * incinf and call resv_refresh_PSB() to add its contribution * to merged (& packed) Resv refresh message. For last PSB * for same PHOP, resv_refresh_PSB sends resulting Resv. */ pkt->rsvp_nflwd = 0; max_specp = NULL; confRSBp = NULL; UnkObjL_perPHOP = NULL; for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next) { /* * Ignore senders whose incoming interfaces are not needed now. */ if (!bmp_zero(&(destp->d_r_incifs))&& !bmp_tst(&(destp->d_r_incifs), sp->ps_in_if)) continue; resv_refresh_PSB(destp, sp, pkt, IsResvErr); } pkt->rsvp_nflwd = 0; bmp_rst(&(destp->d_r_incifs)); if (confRSBp) { free(confRSBp->rs_confirm); confRSBp->rs_confirm = NULL; } return(0); } /* * resv_refresh_PSB(): Process one PSB to generate Resv refresh * message for its PHOP. If this is last PSB for PHOP, * send the Resv message. */ int resv_refresh_PSB( Session *destp, PSB *sp, struct packet *pkt, int IsResvErr) { RSB *rp; PSB *BSBp; FlowDesc *flwdp; FLOWSPEC *fwd_specp; style_t style = Style(pkt); int B_Merge = 0; int i, n_match, cmp; packet_map *mapp = pkt->pkt_map; int Need_Scope = 0; Fobject *UnkObjectL; #ifdef LABEL Label *rp_label; #endif BSBp = (Style_is_Wildcard(style))? sp->ps_1stphop: sp; n_match = 0; UnkObjectL = NULL; /* * 1. Select all RSBs whose Filter_spec_lists match the * SENDER_TEMPLATE object and whose OI appears in the * OutInterface_list of the PSB * (i.e., to which the given PSB will route). */ for (rp = destp->d_RSB_list; rp != NULL; rp = rp->rs_next) { if (!PSBmaps2RSB(destp, sp, rp)) continue; /* If sender in PSB is API, then: * (a) If RSB has a CONFIRM object, then create and send * a ResvConf message containing the object, delete it. * (b) Continue with next RSB. */ #ifdef LABEL if(rp->rs_label) rp_label = rp->rs_label; else rp_label = NULL; #ifndef CAIRN if(rp->action_flag == LTE_PUSH) rp_label = NULL; #endif #endif if (IsHopAPI(&sp->ps_phop)) { if (rp->rs_confirm) { send_confirm(destp, rp); rp->rs_confirm = NULL; } continue; } /* * 2. (If the B_Merge flag is off then) ignore a blockaded * RSB, as follows. * * Select BSBs that match this RSB. If any of * these BSBs has a Qb that is not strictly larger * than TC_Flowspec, then this RSB is blockaded; * continue processing with the next RSB. */ fwd_specp = (rp->rs_fwd_spec)? rp->rs_fwd_spec: rp->rs_spec; if (BSBp->ps_BSB_Qb && LT(BSBp->ps_BSB_Tb, time_now)) { /* Blockade state has timed out; delete it. */ free(BSBp->ps_BSB_Qb); BSBp->ps_BSB_Qb = NULL; BSBp->ps_BSB_Tb = 0; } if ((BSBp->ps_BSB_Qb) && Compare_Flowspecs(BSBp->ps_BSB_Qb, fwd_specp)!=SPEC1_GTR) { Incr_ifstats(BSBp->ps_in_if, rsvpstat_blockade_ev); continue; } n_match++; /* * 3. Merge the flowspecs from this set of RSBs. * Maintain RSB seen so far that has largest flowspec * in confRSBp, for sending a confirm message. */ cmp = Compare_Flowspecs(fwd_specp, max_specp); assert(cmp != SPECS_INCOMPAT); if (cmp == SPEC1_GTR) { max_specp = fwd_specp; if (confRSBp && !IsHopAPI(&rp->rs_nhop)) send_confirm(destp, confRSBp); confRSBp = NULL; if (rp->rs_confirm) confRSBp = rp; } else { if (cmp == SPECS_USELUB) max_specp = LUB_of_Flowspecs(rp->rs_spec, max_specp); if (rp->rs_confirm) send_confirm(destp, rp); } /* * Also merge the lists of unknown objects, if any. */ #define MAKE_COPY 1 merge_UnkObjL2(&rp->rs_UnkObjList, &UnkObjectL, MAKE_COPY); } if (IsHopAPI(&sp->ps_phop)) return(0); /* However, if steps 1 and 2 result in finding that all * RSBs matching this PSB are blockaded, then: * - If this Resv REFRESH sequence was invoked from * accept_resv_err(), then return to the latter. * - Otherwise, turn on the B_Merge flag and restart at * step 1 (actually, second copy of code): */ if (n_match == 0) { if (IsResvErr) return(0); B_Merge = 1; /* (isn't really used) */ max_specp = NULL; for (rp = destp->d_RSB_list; rp != NULL; rp = rp->rs_next) { if (!PSBmaps2RSB(destp, sp, rp)) continue; /* * 3. Merge the flowspecs from this set of * RSBs, as follows. * * Compute the GLB over the Flowspec objects * of this set of RSBs. * While computing the GLB, delete any * RESV_CONFIRM objects. */ n_match++; max_specp = GLB_of_Flowspecs(rp->rs_spec, max_specp); assert(max_specp); /* These flowspecs must be OK */ if (rp->rs_confirm) { free(rp->rs_confirm); rp->rs_confirm = NULL; } confRSBp = NULL; merge_UnkObjL2(&rp->rs_UnkObjList, &UnkObjectL, MAKE_COPY); } } /* * All matching RSB's have been processed. If there * were some, do style-dependent processing: * o Distinct style (FF): Pack flow descriptor into pkt. * o Shared style (SE,WF): continue to merge. */ if (n_match) { flwdp = FlowDesc_of(pkt, pkt->rsvp_nflwd); assert(max_specp); switch (style) { case STYLE_WF: flwdp->rsvp_specp = max_specp; flwdp->rsvp_filtp = NULL; pkt->rsvp_nflwd = 1; /* * If this sender has scope bit on, add this * sender host to the outgoing SCOPE list. */ if (sp->ps_flags & PSBF_InScope) scope_catf(&mapp->rsvp_scope_list, sp->ps_templ); break; case STYLE_FF: if (!confRSBp && sameas_last_spec(&sp->ps_resv_spec, max_specp)) { max_specp = NULL; FQkill(&UnkObjectL); break; } flwdp->rsvp_specp = max_specp; max_specp = NULL; /* To merge filter specs, simply use sender template, */ flwdp->rsvp_filtp = sp->ps_templ; #ifdef LABEL if(rp_label) flwdp->rsvp_label = rp_label; else flwdp->rsvp_label = NULL; #endif pkt->rsvp_nflwd++; /* Test nflwd for overflow XXX */ break; case STYLE_SE: (FlowDesc_of(pkt, 0))->rsvp_specp = max_specp; flwdp->rsvp_filtp = sp->ps_templ; pkt->rsvp_nflwd++; /* Test nflwd for overflow XXX */ break; } } merge_UnkObjL2(&UnkObjectL, &UnkObjL_perPHOP, !MAKE_COPY); /* * Senders are ordered by phop address. Return if next PSB has * the same PHOP, else finish up message and send it. */ if (sp->ps_next && hop_addr_eq(&sp->ps_next->ps_phop,&sp->ps_phop)) { return(0); } /* If there are no flow descriptors, or if new flowspec is same * as last sent for this PSB, the filter spec list did not change, * and there is no confirmation request, return without sending. */ if (pkt->rsvp_nflwd == 0 || ( Style_is_Shared(style) && !confRSBp && sameas_last_spec(&BSBp->ps_resv_spec, max_specp) )){ FQkill(&UnkObjL_perPHOP); pkt->rsvp_nflwd = 0; return(0); } pkt->pkt_map->rsvp_UnkObjList = UnkObjL_perPHOP; UnkObjL_perPHOP = NULL; /* * If a RESV_CONFIRM object was saved earlier, put a ptr * to it in the new Resv message. */ if (confRSBp) mapp->rsvp_confirm = confRSBp->rs_confirm; /* If the style is wildcard, decide whether a SCOPE object * must be sent. */ if (Style_is_Wildcard(style)) Need_Scope = is_scope_needed(destp, sp); /* * Send Resv message (unless there is an empty scope list) * Must first make copy of filter spec objects and set their * class (because they were SENDER_TEMPLATEs); then free copies. */ if (!Need_Scope || mapp->rsvp_scope_list) { for (i= 0; i < pkt->rsvp_nflwd; i++) { flwdp = FlowDesc_of(pkt, i); if (flwdp->rsvp_filtp) { flwdp->rsvp_filtp= copy_filter(flwdp->rsvp_filtp); Obj_Class(flwdp->rsvp_filtp)= class_FILTER_SPEC; } } send_resv_out(sp, pkt); for (i= 0; i < pkt->rsvp_nflwd; i++) { flwdp = FlowDesc_of(pkt, i); if (flwdp->rsvp_filtp) free(flwdp->rsvp_filtp); } } else /* Was not sent because scope list was empty */ Incr_ifstats(sp->ps_in_if, rsvpstat_no_outscope); /* * Free storage and re-initialize pkt for next PHOP */ for (i= 0; i < pkt->rsvp_nflwd; i++) { flwdp = FlowDesc_of(pkt, i); flwdp->rsvp_specp = NULL; } pkt->rsvp_nflwd = 0; if (mapp->rsvp_scope_list) { free(mapp->rsvp_scope_list); mapp->rsvp_scope_list = NULL; } max_specp = NULL; FQkill(&pkt->pkt_map->rsvp_UnkObjList); return(0); } /* Compare new resv refresh flowspec for particular sender/phop * with the last one sent. If they are equal, return 1, else * save new one and return 0. */ int sameas_last_spec(FLOWSPEC **last_specpp, FLOWSPEC *newspecp) { if (*last_specpp && Compare_Flowspecs(*last_specpp, newspecp) == SPECS_EQL) return(1); if (*last_specpp) free(*last_specpp); *last_specpp = copy_spec(newspecp); return(0); } #ifdef ISI_TEST #define MAX_RTEAR_PACK 2 /* XXX (For testing!) ***/ #else #define MAX_RTEAR_PACK MAX_FLWDS #endif /* * cleanup_resv_state(): For given session, kill all expired reservations. * For consistency, we kill a reservation by constructing and * processing a dummy RESV_TEAR message. */ int cleanup_resv_state(Session *destp) { packet_area data; struct packet *pkt = NULL; RSB *rp, *rpn; FlowDesc *flwdp; int i; rpn = destp->d_RSB_list; /* Next RSB */ while (rpn) { rp = rpn; rpn = rpn->rs_next; if (!LT(rp->rs_ttd, time_now)) continue; Incr_ifstats(rp->rs_OIf, rsvpstat_resv_timeout); /* Found timed-out RSB. Fake teardown message for it. */ if (pkt == NULL) { pkt = new_packet_area(&data); common_resv_tear_header(pkt, destp); } Style_of(pkt)->style_word = rp->rs_style; *pkt->rsvp_nhop = rp->rs_rsvp_nhop; if (Style_is_Wildcard(rp->rs_style)) { flwdp = FlowDesc_of(pkt, 0); flwdp->rsvp_filtp = NULL; flwdp->rsvp_specp = NULL; pkt->rsvp_nflwd = 1; } else { for (i= 0; i < rp->rs_fcount; i++) { if (LT(rp->rs_Filt_TTD(i), time_now)) { /* * Individual filter has timed out. * If packet is full, process dummy pkt and * start again. Add filter to dummy pkt. */ if (pkt->rsvp_nflwd >= MAX_RTEAR_PACK) { process_dummy_rtear(pkt); pkt->rsvp_nflwd = 0; } flwdp = FlowDesc_of(pkt, pkt->rsvp_nflwd); flwdp->rsvp_filtp = copy_filter(rp->rs_Filtp(i)); flwdp->rsvp_specp = NULL; pkt->rsvp_nflwd++; } } } if (Style_is_Shared(rp->rs_style) || rpn == NULL || !hop_addr_eq(&rpn->rs_nhop, &rp->rs_nhop)) { /* A little optimization: if a set of FF-style * reservations time out at the same time, try * (but not hard) to packet teardowns into same * RTear. Works if order of RSB list is right. */ if (pkt->rsvp_nflwd) { process_dummy_rtear(pkt); pkt->rsvp_nflwd = 0; } } } return(0); } void process_dummy_rtear(struct packet *pkt) { int i; if (!pkt) return; accept_resv_tear(-1, pkt); for (i= 0; i < pkt->rsvp_nflwd; i++) { if (spec_of(FlowDesc_of(pkt, i))) free(spec_of(FlowDesc_of(pkt, i))); if (filter_of(FlowDesc_of(pkt, i))) free(filter_of(FlowDesc_of(pkt, i))); } } /* * delete_resv4PSB(): Delete reservations corresponding to given PSB, * which is already deleted from session list. Called from * kill_PSB(). */ void delete_resv4PSB(Session *destp, PSB *psbp) { RSB *rp, *rpn; int j, rc; /* * Find each RSB that matches this PSB */ for (rp = destp->d_RSB_list; rp != NULL; rp = rpn) { rpn = rp->rs_next; if (!PSBmaps2RSB(destp, psbp, rp)) continue; if (!Style_is_Shared(rp->rs_style)) { #ifdef LABEL if (!session_multicast(destp->d_session)) { if(rp->rs_label) Free_Label(if_vec[psbp->ps_in_if].if_name, rp->rs_label->label_obj); } #endif kill_RSB(destp, rp); /* Style FF: delete RSB and update link layer. */ } else if (Style_is_Wildcard(rp->rs_style)) { PSB *sp; /* * Wildcard (WF) style => If there is another * matching PSB, update link layer and continue * with next RSB; else, delete RSB & update LL. */ for (sp = destp->d_PSB_list; sp; sp = sp->ps_next) { if (sp != psbp && IsRoutePSB2nhop(destp,sp,&rp->rs_rsvp_nhop)) break; } if (sp) { rc = LL_ModFlowspec(rp->rs_OIf, destp, rp); if (rc != LLDAL_RC_LATER) /* synchronous */ Complete_ModFlowspec(destp, rp, rc); continue; } else kill_RSB(destp, rp); } else { /* Else SE style. Delete matching filter specs. * If filters all gone, delete RSB & update LL. */ for (j= 0; j < rp->rs_fcount; j++) { if (match_filter(psbp->ps_templ, rp->rs_Filtp(j))){ free(rp->rs_Filtp(j)); rp->rs_Filt_TTD(j) = 0; } } coalesce_filtstar(rp->rs_filtstar); if (rp->rs_fcount == 0) kill_RSB(destp, rp); else { rc = LL_ModFilter(rp->rs_OIf, destp, rp); if (rc != LLDAL_RC_LATER) Complete_ModFilter(destp, rp, rc); } } } } /* Update link-layer reservation with respect to given PSB, which * is new or changed. */ void PSB_update_LL(Session *destp, PSB *psbp) { RSB *rp; bitmap out_vifs; int rc; bmp_rst(&out_vifs); /* None seen yet */ for (rp = destp->d_RSB_list; rp != NULL; rp = rp->rs_next) { /* * Search for first RSB for given OI that PSB * routes to and whose Filter_spec_list includes * a FILTER_SPEC matching the SENDER_TEMPLATE. * Using this as the 'active RB', update traffic * control on that OI. Use bit mask out_vifs to * process only one RSB per distinct OI. */ if (!PSBmaps2RSB(destp, psbp, rp)) continue; if (bmp_tst(&out_vifs, rp->rs_OIf)) continue; bmp_set(&out_vifs, rp->rs_OIf); /* ignore later RSBs */ /* * Update traffic control. In unlikely event * that admission Control fails, send ResvErr msg */ rc = LL_ModFlowspec(rp->rs_OIf, destp, rp); if (rc != LLDAL_RC_LATER) /* synchronous */ Complete_ModFlowspec(destp, rp, rc); } } /* * IsRoutePSB2nhop(): Return 1 if sender defined by PSB can * route to specified next hop. */ int IsRoutePSB2nhop(Session *destp, PSB *psbp, RSVP_HOP *hopp) { /* * If Resv came from network, it cannot match LocalOnly PSB. */ if (!IsHopAPI(hopp)) { if (psbp->ps_flags & PSBF_LocalOnly) return(0); else if (bmp_tst(&(psbp->ps_outif_list), hop_lih(hopp))) return(1); } else { /* Resv came from API. OK if: * * dest is unicast, or * * incoming interface matches recv interface, or * * PSB not LocalOnly and not from API and routes to OI. */ if (IF_UNICAST(psbp->ps_in_if) == hop_lih(hopp)) return(1); else if (!session_multicast(destp->d_session)) return(1); else if (!(psbp->ps_flags & PSBF_LocalOnly) && !IsHopAPI(&psbp->ps_phop) && bmp_tst(&(psbp->ps_outif_list), hop_lih(hopp))) return(1); } return(0); } /* Search for (any) RSB that matches the given PSB */ RSB * RSB_match_path(Session *destp, PSB *psbp) { RSB *rp; for (rp = destp->d_RSB_list; rp; rp = rp->rs_next) { if (PSBmaps2RSB(destp, psbp, rp)) break; } return(rp); } /* * Return pointer to RSB for (SESSION, NHOP, [FILTER_SPEC *]), * or NULL if none is found. */ RSB * locate_RSB(Session *destp, RSVP_HOP *nhopp, FiltSpecStar *filtssp, style_t style) { RSB *rp; for (rp = destp->d_RSB_list; rp != NULL; rp = rp->rs_next) { if (!hop_eq(nhopp,&rp->rs_nhop)) continue; if (Style_is_Shared(style) || match_filter(filtssp->fst_filtp0, rp->rs_filter0)) break; } return(rp); } RSB * make_RSB( Session *destp, int count) { int n; RSB *rp; n = SizeofFiltSpecStar(1) + sizeof(RSB); rp = (RSB *) malloc(n); if (!rp) return(NULL); memset((char *)rp, 0, n); #ifndef LPM rp->rs_next = destp->d_RSB_list; destp->d_RSB_list = rp; #endif /* Intially, a one-slot FiltSpecStar is allocated contiguous to * RSB. But if count>1, enlarge it by malloc. */ rp->rs_filtstar = (FiltSpecStar *)((char *) rp + sizeof(RSB)); rp->rs_filtstar->fst_size = 1; rp->rs_filtstar->fst_count = 0; while (rp->rs_filtstar->fst_size < count) { if (!enlarge_RSB_filtstar(rp)) { if (rp->rs_filtstar->fst_size > 1) free(rp->rs_filtstar); free(rp); return(NULL); } } return(rp); } /* Enlarge filtspecstar of given RSB. Malloc a new area. */ int enlarge_RSB_filtstar(RSB *rp) { int orig_size = rp->rs_filtstar->fst_size; int new_size = orig_size+4; int L = SizeofFiltSpecStar(new_size); FiltSpecStar *fsp = malloc(L); if (!fsp) return(0); memset((char *)fsp, 0, L); memcpy((char *)fsp, (char *)rp->rs_filtstar, SizeofFiltSpecStar(orig_size)); fsp->fst_size = new_size; if (orig_size > 1) free(rp->rs_filtstar); rp->rs_filtstar = fsp; return(1); } /* kill_RSB(): Delete specified reservation request element RSB and adjust * TC reservation state accordingly. */ int kill_RSB(Session *destp, RSB *rp) { if (!rp) return 0; return (kill_RSB1(destp, rp, 1)); } /* kill_newRSB(): Delete specified RSB that was in process of being * created, but not yet reflected in TC reservation. */ void kill_newRSB(Session *destp, RSB *rp) { kill_RSB1(destp, rp, 0); } /* Common inner routine for kill_[new]RSB() * Returns Refresh_Needed */ int kill_RSB1(Session *destp, RSB *rp, int isold) { RSB **rpp; int i; int Refresh_Needed = 0; #ifdef LABEL LabelTableEntryPtr ltentry; int label_rem_flag = 0; #endif /* Delete RSB from list, and then call LL_DelFlow to make * make LL reservation consistent with reduced set of RSBs * (unless RSB was new). * Note: Deleting a reservation request cannot increase the * kernel flowspec. In the unlikely event that this results * in an Admission Control failure, we just ignore it; the * original reservation will stay in place. */ for (rpp = &destp->d_RSB_list; (*rpp) != NULL && (*rpp) != rp; rpp = &((*rpp)->rs_next)); if (*rpp != NULL) *rpp = rp->rs_next; if (isold) { int rc; /* Note: for FF style, have not yet deleted filter spec */ rc = LL_DelFlow(rp->rs_OIf, destp, rp); if (rc != LLDAL_RC_LATER) Complete_DelFlow(destp, rp, 0); Refresh_Needed = 1; } #ifdef LABEL if(rp) if(rp->rs_label) { ltentry = (LabelTableEntryPtr)malloc(sizeof(LabelTableEntry)); ltentry->lteNewLabel = 0; ltentry->lteLabel = rp->rs_label->label_obj; ltentry->lteFlags = LTE_POP; if(destp->d_session->sess_header.obj_ctype == ctype_SESSION_lsp_tunv4) { ltentry->lteDest = destp->d_session->sesslsp_addr.s_addr; ltentry->lteDestLtpPort = 0; ltentry->lteDestLtpProtocol = 0; ltentry->lteSourceLtpPort = 0; ltentry->lteSourceLtpProtocol = 0; ltentry->lteSource = 0; } else { ltentry->lteDest = destp->d_session->sess4_addr.s_addr; ltentry->lteDestLtpPort = destp->d_session->sess4_port; ltentry->lteDestLtpProtocol = destp->d_session->sess4_prot; ltentry->lteSourceLtpPort = rp->rs_filtstar->fst_p->fst_filtp->filt4_srcport; ltentry->lteSourceLtpProtocol = destp->d_session->sess4_prot; ltentry->lteSource = rp->rs_filtstar->fst_p->fst_filtp->filt4_srcaddr.s_addr; } ltentry->lteDestLtpPad = 0; ltentry->lteSourceLtpPad = 0; ltentry->lteNextHopAddr = rp->label_nhop; ltentry->lteCoS = 0; /* Not supported so far */ if(pass_msg_2_rtsock(ltentry, "\0", LABEL_DELETE)<0){ rsvp_resv_err(RSVP_Err_NO_LABEL, 0 , 0, NULL, NULL); return -1; free(rp->rs_label); } } #endif /* LABEL */ /* If this was last RSB for session, delete Resv refresh timer */ if (destp->d_RSB_list == NULL) { del_from_timer((char *) destp, TIMEV_RESV); destp->d_timevalr.timev_R = 0; } /* Free everything in sight... */ if (rp->rs_spec) free(rp->rs_spec); for (i=0; i < rp->rs_fcount; i++) if (rp->rs_Filtp(i)) free(rp->rs_Filtp(i)); if (rp->rs_filtstar->fst_size > 1) free(rp->rs_filtstar); if (rp->rs_fwd_spec) free(rp->rs_fwd_spec); if (rp->rs_scope) { free(rp->rs_scope); clear_scope_union(destp); /* Set to recompute scope union */ } if (rp->rs_confirm) free(rp->rs_confirm); FQkill(&rp->rs_UnkObjList); free((char *)rp); return(Refresh_Needed); } /* Update RSB time-to-die from MIN of ttd's of filter specs. */ void resv_update_ttd(RSB *rp, u_int32_t ttd) { int j; for (j= 0; j < rp->rs_fcount; j++) ttd = MIN(ttd, rp->rs_Filt_TTD(j)); rp->rs_ttd = ttd; } /* Buy storage and initialize FILTER_SPEC* structure with n slots. */ FiltSpecStar * Get_FiltSpecStar(int n) { FiltSpecStar *filtssp; int len = SizeofFiltSpecStar(n); filtssp = (FiltSpecStar *) malloc(len); if (filtssp) { memset((char *)filtssp, 0, len); filtssp->fst_size = n; } return(filtssp); } /* Return index in FILTER_SPEC* vector of filter matching *filtp, * or -1. But if filtp = NULL, look for empty slot. If can't find * one, try to expand; if that fails, return -1. */ int find_fstar( FILTER_SPEC *filtp, FiltSpecStar *filtssp) { int i; if (!filtssp) return 0; /* Wildcard */ if (!filtp) { for (i= 0; i < filtssp->fst_count; i++) { if (filtssp->fst_Filtp(i) == NULL) return(i); } /* * Empty slot not found. Get next slot if available. */ if (filtssp->fst_count < filtssp->fst_size) return(filtssp->fst_count++); return(-1); } for (i= 0; i < filtssp->fst_count; i++) { if (match_filter(filtp, filtssp->fst_Filtp(i))) return(i); } return(-1); } /* Return 1 if FILTER_SPEC matches a filter in FILTER_SPEC*, else 0. * */ int match_filt2star(FILTER_SPEC *filtp, FiltSpecStar *fssp) { int i; for (i= 0; i < fssp->fst_count; i++) { if ((fssp->fst_Filtp(i)) && match_filter(filtp, fssp->fst_Filtp(i))) return(1); } return(0); } /* Coalesce (RSB) FILTER SPEC list, removing entries whose TTD is zero. */ void coalesce_filtstar(FiltSpecStar *filtssp) { int i, j; i = 0; for (j= 0; j < filtssp->fst_count; j++) { if (filtssp->fst_Filt_TTD(j)) { filtssp->fst_Filtp(i) = filtssp->fst_Filtp(j); filtssp->fst_Filt_TTD(i++) = filtssp->fst_Filt_TTD(j); } } filtssp->fst_count = i; } void map2FiltStar(struct packet *pkt, FiltSpecStar *filtssp) { int i; filtssp->fst_count = pkt->rsvp_nflwd; for (i=0; i < pkt->rsvp_nflwd; i++) { filtssp->fst_Filtp(i) = filter_of(FlowDesc_of(pkt, i)); filtssp->fst_Filt_TTD(i) = 0; } } /* * Decide whether a SCOPE object is needed in WF Resv refresh message * to given PHOP P for which there is path state. * * A SCOPE object is needed for phop P with path state if: * there is an RSB R to which data from P is routed, AND * o R has a SCOPE list, OR * o There path state for a PHOP P' != P, such that data * form P' is also routed to R */ int is_scope_needed(Session *destp, PSB *psbp) { RSB *rp; PSB *sp; /* For each RSB R... */ for (rp = destp->d_RSB_list; rp != NULL; rp = rp->rs_next) { if (!IsRoutePSB2nhop(destp, psbp, &rp->rs_rsvp_nhop)) continue; /* If RSB has SCOPE list, return True. Otherwise, * scan list of PSBs for those that route to R. * If PSB has PHOP != P, then return true. */ if (rp->rs_scope) return(1); for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next) { if (!IsRoutePSB2nhop(destp, sp, &rp->rs_rsvp_nhop)) continue; if (hop_addr_eq(&sp->ps_phop, &psbp->ps_phop)) return(1); } } return(0); } /* * common_resv_header(): Fill in common header fields for Resv msg */ void common_resv_header(struct packet *pkt, Session *destp) { static RSVP_HOP hop; packet_map *mapp = pkt->pkt_map; mapp->rsvp_msgtype = RSVP_RESV; mapp->rsvp_session = destp->d_session; mapp->rsvp_timev = &destp->d_timevalr; mapp->rsvp_hop = &hop; mapp->rsvp_dpolicy = NULL; pkt->rsvp_nflwd = 0; switch(Obj_CType(destp->d_session)) { case ctype_SESSION_ipv4: case ctype_SESSION_ipv4GPI: case ctype_SESSION_lsp_tunv4: Init_Object(&hop,RSVP_HOP,RSVP_HOP_ipv4); break; #ifdef USE_IPV6 case ctype_SESSION_ipv6: case ctype_SESSION_ipv6GPI: Init_Object(&hop,RSVP_HOP,RSVP_HOP_ipv6); break; #endif /* USE_IPV6 */ default: Init_Object(&hop,NULL,NULL); break; } } /* * common_resv_tear_header(): Fill in common header fields for Resv_Tear */ void common_resv_tear_header(struct packet *pkt, Session *destp) { static RSVP_HOP hop; packet_map *mapp = pkt->pkt_map; mapp->rsvp_msgtype = RSVP_RESV_TEAR; mapp->rsvp_session = destp->d_session; mapp->rsvp_hop = &hop; mapp->rsvp_style = &Style_Obj; Init_Object(&Style_Obj,STYLE,STYLE_CTYPE); mapp->rsvp_nlist = 0; switch(Obj_CType(destp->d_session)) { case ctype_SESSION_ipv4: case ctype_SESSION_ipv4GPI: case ctype_SESSION_lsp_tunv4: Init_Object(&hop,RSVP_HOP,RSVP_HOP_ipv4); break; #ifdef USE_IPV6 case ctype_SESSION_ipv6: case ctype_SESSION_ipv6GPI: Init_Object(&hop,RSVP_HOP,RSVP_HOP_ipv6); break; #endif /* USE_IPV6 */ default: Init_Object(&hop,NULL,NULL); break; } } /* * send_resv_out(): Send out Resv message to specified address. */ static void send_resv_out( PSB *psbp, struct packet *pkt) { int outif = psbp->ps_in_if; FORCE_HOST_ORDER(pkt); if (outif == -1) { switch(Obj_CType(&psbp->ps_rsvp_phop)) { case ctype_RSVP_HOP_ipv4: outif = local_v4; break; #ifdef USE_IPV6 case ctype_RSVP_HOP_ipv6: outif = local_v6; break; #endif /* USE_IPV6 */ default: return; } } hop_if_assign(pkt->rsvp_nhop,&GET_IF(outif), hop_lih(&psbp->ps_rsvp_phop)); send_pkt_out_if(IF_UNICAST(outif), &psbp->ps_rsvp_phop, pkt); } int Styles_are_compat(style_t st1, style_t st2) { if (st1 == st2) return 1; else return 0; } /* Compute B_Police flag for given 'active' RSB. * * Scan all RSB's matching SESSION (and Filter spec list, if * distinct style) for all OI different from active RSB. * Return the TC_B_Police flag if RSB's flowspec is smaller * than, or incomparable to, any FLOWSPEC in those RSBs. */ int Is_B_Police(Session *destp, RSB *rp) { RSB *trp; int rc; for (trp = destp->d_RSB_list; trp != NULL; trp = trp->rs_next) { if (trp->rs_OIf == rp->rs_OIf) continue; if ( !Style_is_Shared(rp->rs_style) && !match_filter(trp->rs_filter0, rp->rs_filter0)) continue; rc = Compare_Flowspecs(trp->rs_spec, rp->rs_spec); if (rc == SPEC1_GTR || rc == SPECS_INCOMPAT) return(TCF_B_POLICE); } return(0); } /* * Compute reservation properties from path state for reservation * for given NHOP, OI, and filter spec list. * * o Locate the set of PSBs (senders) that map to this NHOP and * FiltSpecList, and return count of these PSBs. * * o Compute Path_Te as the sum of the SENDER_TSPEC objects * * o Compute Path_Adspec. Note: we use the *first* adspec. * Since Guaranteed service only makes sense for distinct * style, this should be OK. * * o Set TC_E_Police flag if any of these PSBs have their * E-Police flag on. Set TC_M_Police flag on if it * is a shared style and there is more than one PSB * in the set. */ int Compute_Path_Props(Session *destp, RSB *rp, FiltSpecStar *filtpp, SENDER_TSPEC *Path_Tep, ADSPEC **Path_Adspp, int *flagp) { PSB *sp; int sender_cnt = 0; Init_Object(Path_Tep, SENDER_TSPEC, SENDER_TSPEC_CTYPE); sender_cnt = 0; *Path_Adspp = NULL; for (sp = destp->d_PSB_list ; sp != NULL; sp = sp->ps_next) { if (!IsRoutePSB2nhop(destp,sp,&rp->rs_rsvp_nhop) || ( !Style_is_Wildcard(rp->rs_style) && !match_filt2star(sp->ps_templ, filtpp))) continue; sender_cnt++; addTspec2sum(sp->ps_tspec, Path_Tep); if (sp->ps_flags & PSBF_E_Police || (IF_FLAGS((int)sp->ps_in_if) & IF_FLAG_Police)) *flagp |= TCF_E_POLICE; if (*Path_Adspp == NULL) *Path_Adspp = copy_adspec(sp->ps_adspec); } if (sender_cnt > 1) *flagp |= TCF_M_POLICE; return(sender_cnt); } #ifdef LABEL #define LABEL_LEN 4 #define MAX_SCOPE_LEN 65536 /* * Adds a new label to the end of the label stack */ void set_label(Label ** labelppp, PSB *psb) { int N, L, ctype, addrsize; Label *labelpp, *new_labelpp; ctype = ctype_Label; addrsize = 4; labelpp = *labelppp; if (!labelpp) { /* First time... set up object * We use the object length field to keep track of * the number of entries at present. The size of * malloc'd area is nearest power of 2 that is >= * this len, but at least INIT_SCOPE_LEN. */ labelpp = new_label_obj(ctype); if (!labelpp) return; /* some manipulation not to be done now */ /* Obj_Length(labelpp) = sizeof(Object_header);*/ } else { if (Obj_CType(labelpp) != ctype) return; } /* Compute size of existing area */ #ifdef 0 L = Obj_Length(labelpp); for (N = LABEL_LEN; N < MAX_SCOPE_LEN; N += 4) if (N >= L) break; if (L + addrsize > N) { /* Overflow. Malloc a new object area of double size, * copy into it, and free original one. */ new_labelpp = (Label *) malloc(L + addrsize); if (!new_labelpp) { /* XXX ?? */ return; } memset(new_labelpp, 0, L + addrsize); memcpy(new_labelpp, labelpp, 4); Obj_Length(new_labelpp) += addrsize; if(Obj_Length(new_labelpp) > 8) memcpy(((char *)(new_labelpp) + 8), ((char *)(labelpp)+4), L-4); labelpp = new_labelpp; } #endif #ifdef CAIRN labelpp->label_obj = (u_int32_t)0; #else if(psb->ps_label_in) labelpp->label_obj = psb->ps_label_in->label_obj; else labelpp->label_obj = Get_Label(psb->ps_in_if); #endif *labelppp = labelpp; } /* * Debug function to print label stack on each node */ void print_labels(Label *labelstack) { int n, length; length = Obj_Length(labelstack); log(LOG_DEBUG, 0, "Labelstack on this node :\n"); for (n = 4; n < length; n += 4) log(LOG_DEBUG, 0, " %d \n", *(u_long *)((char *)labelstack + n)); } #endif