/* * @(#) $Id: rsvp_LLkern.c,v 4.16 1998/04/24 20:15:50 lindell Exp $ */ /************************ rsvp_LLkern.c ***************************** * * * Link-layer-dependent adaptation layer (LLDAL) routines * * for interfacing to a "kernel" traffic control mechanism. * * This supports QoS over passive media such as leased lines or * * (today's) shared LAN media. * * * * * *********************************************************************/ /**************************************************************************** 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) 1996 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" #include "rsvp_TCif.h" #if defined LABEL #include "rsvp_label.h" #endif /* * External declarations */ int Compute_Path_Props(Session *, RSB *, FiltSpecStar *, SENDER_TSPEC *, ADSPEC **, int *); int Is_B_Police(Session *, RSB *); Object_header * copy_object(Object_header *); int match_filter(FILTER_SPEC *, FILTER_SPEC *); int Compare_Flowspecs(FLOWSPEC *, FLOWSPEC *); FLOWSPEC * LUB_of_Flowspecs(FLOWSPEC *, FLOWSPEC *); int Compare_Tspecs(SENDER_TSPEC *, SENDER_TSPEC *); void send_confirm(Session *, RSB *); int find_fstar(FILTER_SPEC *, FiltSpecStar *); FiltSpecStar * Get_FiltSpecStar(int); char * fmt_flowspec(FLOWSPEC *); char * fmt_tspec(SENDER_TSPEC *); char * cnv_flags(char *, u_char); /* * Forward declarations */ TCSB * locate_TCSB(Session *, int, FiltSpecStar *, style_t); #ifdef LABEL TCSB * locate_label_TCSB(Session *, int, Label*, style_t); #endif /* * RSBs4_sameLL(rp1, rp2): Predicate true if two RSBs map into * the same link layer reservation block. */ #define RSBs4_sameLL(rp1, rp2) ((rp1->rs_OIf == rp2->rs_OIf) && \ ( Style_is_Shared(rp1->rs_style) || \ match_filter(rp1->rs_filter0, rp2->rs_filter0))) /* Call-back routines. * * External references to the core-RSVP routines that do 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. */ extern int Complete_NewFlow(Session *, RSB *, int); extern int Complete_ModFlowspec(Session *, RSB *, int); extern int Complete_ModFilter(Session *, RSB *, int); extern int Complete_DelFlow(Session *, RSB *, int); /** extern int Complete_Advertise(Session *, PSB *, int); **/ /** extern int Complete_BugDump(Session *, int); **/ /* * Forward declarations: LLDAL Interface Routines */ void KernTC_if_init(int OIf); int KernTC_NewFlow(Session *, RSB *); int KernTC_ModFlowspec(Session *, RSB *); int KernTC_ModFilter(Session *, RSB *); int KernTC_DelFlow(Session *, RSB *); int KernTC_Advertise(int, Session *, PSB *); int KernTC_GetInfo(Session *, RSB *); int KernTC_BugDump(int OIf, Session *); /* * Forward declarations: Internal Routines */ int Kernel_SetFilters(Session *, TCSB *, FiltSpecStar *); #ifdef LABEL int Kernel_SetLabel(Session *, TCSB *, RSB *); #endif int Kernel_Merge(Session *, RSB *, FLOWSPEC **, FiltSpecStar **); int Kernel_Return_Spec(Session *, RSB *, FLOWSPEC *); int union_filtstar(FiltSpecStar *, FiltSpecStar **); TCSB * make_TCSB(Session *, int, int); TCSB * trade_TCSB(Session *, TCSB *, int); void kill_TCSB(Session *, TCSB *); void log_K(int, Session *, TCSB *); /* * Initialize transfer vector for a given interface */ void KernTC_if_init(int OIf) { if_vec[OIf].if_LLifv.LL_NewFlow_p = &KernTC_NewFlow; if_vec[OIf].if_LLifv.LL_ModFlowspec_p = &KernTC_ModFlowspec; if_vec[OIf].if_LLifv.LL_ModFilter_p = &KernTC_ModFilter; if_vec[OIf].if_LLifv.LL_DelFlow_p = &KernTC_DelFlow; if_vec[OIf].if_LLifv.LL_Advertise_p = &KernTC_Advertise; if_vec[OIf].if_LLifv.LL_GetInfo_p = &KernTC_GetInfo; if_vec[OIf].if_LLifv.LL_BugDump_p = &KernTC_BugDump; #ifdef SCHEDULE TC_init(OIf); #endif /* SCHEDULE */ } /* * KernTC_NewFlow(Session, active RSB [=> Interface, NextHop, * FiltSpecList, Flowspec, Style) * * Add a new flow reservation request. RSB is used as a parameter * list to pass (interface, NHOP, style, flowspec, filter_spec_list). */ int KernTC_NewFlow(Session *destp, RSB *rp) { TCSB *kp = NULL; FLOWSPEC *Fwd_specp = NULL; SENDER_TSPEC Path_Te; ADSPEC *adspecp = NULL; int TC_kflags = 0, s_count; u_long handle; /* Assume memory error */ rsvp_errno = Set_Errno( RSVP_Err_RSVP_SYS_ERROR, RSVP_Erv_MEMORY); /* Compute Branch_Merge flag from RSBs [This might be better * be done in core RSVP]. */ TC_kflags |= Is_B_Police(destp, rp); /* Find out if there is already a matching reservation in * place for different NHOPs: search for a TCSB matching * (OI, session, [filter_spec_list (distinct style)]). */ #ifdef LABEL if(rp->rs_label) kp = locate_label_TCSB(destp,rp->rs_OIf, rp->rs_label, rp->rs_style); else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #endif if (!kp) { /* This is first reservation. Build TCSB, send flowspec, * filter_spec_list, etc. to traffic control, and if there * is no error, fill in TCSB. */ kp = make_TCSB(destp, rp->rs_OIf, rp->rs_fcount); if (!kp) goto TC_add_error; /* Compute path properties -- * Path_Te = sum of sender Tspecs, * [composed] Adspecs (for Guaranteed Service Slack Calc) * Entry_Police and Merge_Police flags -- * from PSBs that match this request. * * Note: this calculation will generally be independent of * the particular next hop, so it could be done in core RSVP. * However, there is at least a theoretical possibility of * further routing in the link layer driver, in which case * the selection of matching PSBs can only be done in the * LLDAL. Therefore, we execute it in the LLDAL (although * code currently defined in rsvp_resv.c). */ s_count = Compute_Path_Props(destp, rp, rp->rs_filtstar, &Path_Te, &adspecp, &TC_kflags); assert(s_count > 0); /* Caller checked: there are matching senders*/ #ifdef SCHEDULE if(if_vec[kp->tcs_OIf].if_up) /* Hack to allow some CBQed and non CBQed iface*/ { handle = TC_AddFlowspec(kp->tcs_OIf, rp->rs_spec, &Path_Te, adspecp, TC_kflags, &Fwd_specp); kp->tcs_rhandle = handle; } #endif if (IsDebug(DEBUG_ALL)) { char out[80]; log_K(LOGEV_TC_addflow, destp, kp); if (IsDebug(DEBUG_EVENTS)) { strncpy(out, fmt_tspec(&Path_Te), 80); log(LOG_DEBUG, 0, " flowspec= %s Tspec=%s\n", fmt_flowspec(rp->rs_spec), out); } } if (handle == TC_ERROR) /* Failed. rsvp_errno is set. */ goto TC_add_error; if (Fwd_specp) { /* An updated flowspec was returned. Pass * it back to the core. */ if (Kernel_Return_Spec(destp, rp, Fwd_specp) == LLDAL_RC_ERROR) goto TC_add_error; } #ifdef LABEL if(rp->rs_label != NULL) { if (Kernel_SetLabel(destp, kp, rp) == LLDAL_RC_ERROR) goto TC_add_error; /* add label to label_table via routing socket */ if (Add_label_to_route(destp, rp) < 0) { goto TC_add_error; } } else { /* Copy filter spec list into TCSB and install filters * in traffic control. */ if (Kernel_SetFilters(destp, kp, rp->rs_filtstar) == LLDAL_RC_ERROR) goto TC_add_error; /* Error; rsvp_errno set */ } #else /* Copy filter spec list into TCSB and install filters * in traffic control. */ if (Kernel_SetFilters(destp, kp, rp->rs_filtstar) == LLDAL_RC_ERROR) goto TC_add_error; /* Error; rsvp_errno set */ #endif /* Flowspec and filter spec(s) installed OK. Set * TCSB and return. */ kp->tcs_spec = copy_spec(rp->rs_spec); kp->tcs_tspec = copy_tspec(&Path_Te); kp->tcs_kflags = TC_kflags; if (!kp->tcs_spec || !kp->tcs_tspec) goto TC_add_error; /* out of memory */ return(LLDAL_RC_OK); } /* A reservation is already in place. Change it if necessary. * For simplicity (and at the cost of some efficiency) just use * LL_ModFlowspec. */ if (adspecp) free(adspecp); /* (KernTC_ModFlowspec will recompute */ /* * Note: we could avoid calling KernTC_ModFlowspec if new * flowspec LEQ against tcs_spec, and we could avoid calling * KernTC_ModFilter if new filter spec list is identical to * that in the TCSB. Leave those optimizations for later. */ return(KernTC_ModFlowspec(destp, rp)); TC_add_error: /* * Error cases: release resources and free TCSB as necessary. */ if (kp && kp->tcs_rhandle && kp->tcs_rhandle != TC_ERROR) { #ifdef SCHEDULE if(if_vec[kp->tcs_OIf].if_up) /* Hack to allow some CBQed and non CBQed iface*/ { TC_DelFlowspec(kp->tcs_OIf, kp->tcs_rhandle); } #endif if (IsDebug(DEBUG_ALL)) { log_K(LOGEV_TC_delflow, destp, kp); if (IsDebug(DEBUG_EVENTS)) log(LOG_DEBUG, 0, " flowspec= %s\n", fmt_flowspec(rp->rs_spec)); } } if (kp) kill_TCSB(destp, kp); if (adspecp) free(adspecp); return(LLDAL_RC_ERROR); } /* * KernTC_ModFlowspec(Session, active RSB) * * Modify an existing reservation because a component flowspec, * sender Tspec, or Adspec has changed. RSB *rp specifies NHOP, OIf, * OIf, and (for Distinct) the filter spec. */ int KernTC_ModFlowspec(Session *destp, RSB *rp) { TCSB *kp; FLOWSPEC *TC_specp, *Fwd_specp; FiltSpecStar *TC_FiltSp; SENDER_TSPEC Path_Te; ADSPEC *adspecp; int TC_kflags = 0; u_long rc; /* Scan RSBs and merge: * flowspecs -> TC_specp * filter specs -> TC_FiltSp. */ rc = Kernel_Merge(destp, rp, &TC_specp, &TC_FiltSp); if (rc != LLDAL_RC_OK) return(rc); assert(TC_specp && TC_FiltSp); /* Compute path properties -- Path_Te = sum of sender Tspecs, * [composed] Adspecs, Entry_Police and Merge_Police flags -- * from PSBs that match this request. */ if (Compute_Path_Props(destp, rp, TC_FiltSp, &Path_Te, &adspecp, &TC_kflags) == 0) return(LLDAL_RC_OK); /* ??? Can this ever happen? */ /* Compute Branch_Merge flag from RSBs [This might better * be done in core RSVP? Or in Kernel_Merge?] */ TC_kflags |= Is_B_Police(destp, rp); /* Find matching TCSB for reservation in place; match * (OI, session, [filter_spec_list (distinct style)]). * * XXX we could be cleverer, save A(TCSB) in RSB (except * this makes problems if we have to trade TCSBs!) */ #ifdef LABEL if(rp->rs_label) kp = locate_label_TCSB(destp,rp->rs_OIf, rp->rs_label, rp->rs_style); else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #endif assert(kp); /* Record merged flag in TCSB */ kp->tcs_flags &= ~TCF_MERGED; if (rp->rs_flags & RSB_FLAG_MERGED) kp->tcs_flags |= TCF_MERGED; /* * If TC_Flowspec, Path_Te, or police flags have changed, * modify reservation. */ if (Compare_Flowspecs(TC_specp, kp->tcs_spec) != SPECS_EQL || Compare_Tspecs(&Path_Te, kp->tcs_tspec) != SPECS_EQL || TC_kflags != kp->tcs_kflags) { #ifdef SCHEDULE if(if_vec[kp->tcs_OIf].if_up) /* Hack to allow some CBQed and non CBQed iface*/ { rc = TC_ModFlowspec(kp->tcs_OIf, kp->tcs_rhandle, TC_specp, &Path_Te, adspecp, TC_kflags, &Fwd_specp); } #endif if (IsDebug(DEBUG_ALL)) { log_K(LOGEV_TC_modflow, destp, kp); if (IsDebug(DEBUG_EVENTS)) { char out[80]; strncpy(out, fmt_tspec(kp->tcs_tspec), 80); log(LOG_DEBUG, 0, " Old: flowspec=%s Tspec=%s\n", fmt_flowspec(kp->tcs_spec), out); strncpy(out, fmt_tspec(&Path_Te), 80); log(LOG_DEBUG, 0, " New: flowspec=%s Tspec=%s\n", fmt_flowspec(TC_specp), out); } } if (rc == TC_ERROR) /* Failed. rsvp_errno is set. */ return(LLDAL_RC_ERROR); } /* Set filters if necessary, too. */ #ifdef LABEL if(rp->rs_label == NULL) { if ((rc = Kernel_SetFilters(destp, kp, TC_FiltSp)) == LLDAL_RC_ERROR) goto TC_mod_error; /* Error; rsvp_errno set */ } #else rc = Kernel_SetFilters(destp, kp, TC_FiltSp); if (rc == LLDAL_RC_ERROR) goto TC_mod_error; #endif /* * Since TC calls succeeded, update TCSB now. */ free(kp->tcs_spec); kp->tcs_spec = copy_spec(TC_specp); if (kp->tcs_tspec) free(kp->tcs_tspec); kp->tcs_tspec = copy_tspec(&Path_Te); kp->tcs_kflags = TC_kflags; if (!kp->tcs_spec || !kp->tcs_tspec) { rsvp_errno = Set_Errno( RSVP_Err_RSVP_SYS_ERROR, RSVP_Erv_MEMORY); rc = LLDAL_RC_ERROR; } TC_mod_error: free(TC_FiltSp); free(TC_specp); if (adspecp) free(adspecp); return(rc); } /* * KernTC_ModFilter(Session *, active RSB *) * * Modify the filter spec list for an existing reservation */ int KernTC_ModFilter(Session *destp, RSB *rp) { FiltSpecStar *TC_FiltSp; FLOWSPEC *TC_specp; TCSB *kp; int rc; #ifdef LABEL if(rp->rs_label) kp = locate_label_TCSB(destp,rp->rs_OIf, rp->rs_label, rp->rs_style); else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #endif if (!kp) return(LLDAL_RC_OK); rc = Kernel_Merge(destp, rp, &TC_specp, &TC_FiltSp); if (rc != LLDAL_RC_OK) return(rc); return(Kernel_SetFilters(destp, kp, TC_FiltSp)); } /* * KernTC_DelFlow(Session, active RSB) * * Active RSB has been deleted; update Kernel TC state to correspond. * * FF (distinct style) case is a little tricky: the RSB parameter must * specify the filter spec to define the flow to be deleted; yet this * RSB must not itself appear in the list of current RSBs. */ int KernTC_DelFlow(Session *destp, RSB *rp) { TCSB *kp; FLOWSPEC *TC_specp; FiltSpecStar *TC_FiltSp; u_long rc = TC_OK; #if defined LABEL LabelTableEntryPtr ltentry; #endif /* Find matching TCSB for reservation in place; match * (OI, session, [filter_spec_list (distinct style)]). */ #ifdef LABEL if(rp->rs_label) kp = locate_label_TCSB(destp,rp->rs_OIf, rp->rs_label, rp->rs_style); else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #endif if (!kp) return(LLDAL_RC_OK); rc = Kernel_Merge(destp, rp, &TC_specp, &TC_FiltSp); assert(rc == LLDAL_RC_OK); /* Record merged flag in TCSB */ kp->tcs_flags &= ~TCF_MERGED; if (rp->rs_flags & RSB_FLAG_MERGED) kp->tcs_flags |= TCF_MERGED; /* * If there are no matching RSBs now, simply kill the reservation */ if (!TC_specp) { if (IsDebug(DEBUG_ALL)) { log_K(LOGEV_TC_delflow, destp, kp); if (IsDebug(DEBUG_EVENTS)) log(LOG_DEBUG, 0, " flowspec= %s\n", fmt_flowspec(kp->tcs_spec)); } #ifdef SCHEDULE if(if_vec[kp->tcs_OIf].if_up) /* Hack to allow some CBQed and non CBQed iface*/ { TC_DelFlowspec(kp->tcs_OIf, kp->tcs_rhandle); } #if defined (LABEL) if(rp->rs_label) { ltentry = (LabelTableEntryPtr)malloc(sizeof(LabelTableEntry)); ltentry->lteNewLabel = 0; ltentry->lteLabel = rp->rs_label->label_obj; 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->lteSourceLtpProtocol = destp->d_session->sess4_prot; ltentry->lteSource = rp->rs_filtstar->fst_p->fst_filtp->filt4_srcaddr.s_addr; ltentry->lteSourceLtpPort = rp->rs_filtstar->fst_p->fst_filtp->filt4_srcport; } 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){ return -1; } else { Free_Label(rp->label_ifname,rp->rs_label->label_obj); rp->rs_label = NULL; } } #endif /* LABEL */ #endif kill_TCSB(destp, kp); if (TC_FiltSp) free(TC_FiltSp); return(LLDAL_RC_OK); } /* * Else recompute everything and update reservation */ return(KernTC_ModFlowspec(destp, rp)); } /* * KernTC_Advertise(Session, PSB) * * Pass Adspec (pt'd to by PSB) to traffic control, to be updated. * */ int KernTC_Advertise(int OI, Session *destp, PSB *psbp) { psbp->ps_newadspec = TC_Advertise(OI, psbp->ps_adspec, (int) psbp->ps_flags&PSBF_NonRSVP); return(LLDAL_RC_OK); } /* * KernTC_GetInfo(Session, RSB, item#) * * This is an exercise in information-hiding. Given (dummy) RSB defining * reservation, return pointers to objects containing useful effective * values as determined by the link layer: Tspec, flowspec, and filtspec*. * Flowspec and filtspecstar pointers are returned in the normal * places, while the Tspec is returned in rs_oldspec. * Also, the RSB_MERGED_FLAG is set 0/1. */ int KernTC_GetInfo(Session *destp, RSB *rp) { TCSB *kp; Fobject *copy_obj2Fobj(Object_header *); #ifdef LABEL if(rp->rs_label) kp = locate_label_TCSB(destp,rp->rs_OIf, rp->rs_label, rp->rs_style); else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #else kp = locate_TCSB(destp, rp->rs_OIf, rp->rs_filtstar, rp->rs_style); #endif if (!kp || rp->rs_UnkObjList) return(LLDAL_RC_ERROR); rp->rs_spec = kp->tcs_spec; rp->rs_filtstar = kp->tcs_filtstar; rp->rs_oldspec = (FLOWSPEC *) kp->tcs_tspec; rp->rs_flags &= ~RSB_FLAG_MERGED; if (kp->tcs_flags & TCF_MERGED) rp->rs_flags |= RSB_FLAG_MERGED; return(LLDAL_RC_OK); } /* * KernTC_BugDump(OIf, session) */ int KernTC_BugDump(int OIf, Session *destp) { TCSB *kp; void dump_filtstar(FiltSpecStar *, FLOWSPEC *); for (kp = (TCSB *) destp->d_LLB_listv[OIf]; kp != NULL; kp = kp->tcs_next) { if (IsNumAPI(OIf)) log(LOG_DEBUG, 0, " Kernel reservation: API Rhandle %x\n", kp->tcs_rhandle); else { log(LOG_DEBUG, 0, " Kernel reservation: Iface %d (%s) Rhandle %x \n", OIf, net_if_print(&GET_IF(OIf)), kp->tcs_rhandle); dump_filtstar(kp->tcs_filtstar, kp->tcs_spec); } } return(LLDAL_RC_OK); } /******************************************************************* * Auxiliary Routines * *******************************************************************/ /* * Kernel_SetFilters() * * Make FILTER_SPEC* in TCSB agree with given filter spec list * (empty for WF); call TC as necessary. If it fails, returns * -1; if there is a change, returns +1; else returns 0; */ int Kernel_SetFilters(Session *destp, TCSB *kp, FiltSpecStar *TC_FiltSp) { FiltSpecStar *filtssp; /* Empty filt* for WF */ int i, j, rc; /* Special case: insert "wildcard filter" for WF */ filtssp = kp->tcs_filtstar; if (TC_FiltSp->fst_count == 0) { #ifdef SCHEDULE if(if_vec[kp->tcs_OIf].if_up) /* Hack to allow some CBQed and non CBQed iface*/ { rc = TC_AddFilter(kp->tcs_OIf, kp->tcs_rhandle, destp, NULL); } #endif if (IsDebug(DEBUG_ALL)) { log_K(LOGEV_TC_addfilt, destp, kp); if (IsDebug(DEBUG_EVENTS)) log(LOG_DEBUG, 0, " WF Filter, Fhandle=%d\n", rc); } if (rc == TC_ERROR) return(LLDAL_RC_ERROR); } /* * 1. Delete any filter specs in TCSB that are not in *TC_FiltSp. */ for (i= 0; i < filtssp->fst_count; i++) { if (filtssp->fst_Filtp(i)&& find_fstar(filtssp->fst_Filtp(i), TC_FiltSp) < 0) { #ifdef SCHEDULE if(if_vec[kp->tcs_OIf].if_up) /* Hack to allow some CBQed and non CBQed iface*/ { rc = TC_DelFilter(kp->tcs_OIf, filtssp->fst_p[i].Fhandle); } #endif if (IsDebug(DEBUG_ALL)) { log_K(LOGEV_TC_delfilt, destp, kp); if (IsDebug(DEBUG_EVENTS)) log(LOG_DEBUG, 0, " Fhandle= %d\n", filtssp->fst_p[i].Fhandle); } if (rc == TC_ERROR) return(LLDAL_RC_ERROR); filtssp->fst_p[i].Fhandle = 0; free(filtssp->fst_Filtp(i)); filtssp->fst_Filtp(i) = NULL; } } /* * 2. Add to TCSB any filter specs in TC_Filtstar but not in TCSB. */ for (j= 0; j < TC_FiltSp->fst_count; j++) { FILTER_SPEC *filtp = TC_FiltSp->fst_Filtp(j); if (find_fstar(filtp, filtssp)<0) { i = find_fstar(NULL, filtssp); if (i < 0) { /* Damn... FiltSpecStar area needs to grow! */ kp = trade_TCSB(destp, kp, kp->tcs_filtstar->fst_size+16); if (!kp) goto Mem_setf_error; i = find_fstar(NULL, kp->tcs_filtstar); assert(i >= 0); filtssp = kp->tcs_filtstar; } #ifdef SCHEDULE if(if_vec[kp->tcs_OIf].if_up) /* Hack to allow some CBQed and non CBQed iface*/ { rc = TC_AddFilter(kp->tcs_OIf, kp->tcs_rhandle, destp, filtp); } #endif if (IsDebug(DEBUG_ALL)) { log_K(LOGEV_TC_addfilt, destp, kp); if (IsDebug(DEBUG_EVENTS)) log(LOG_DEBUG, 0, " Filter= %s Fhandle=%d\n", fmt_filtspec(filtp), rc); } if (rc == TC_ERROR) return(LLDAL_RC_ERROR); assert(filtssp->fst_count <= filtssp->fst_size); filtssp->fst_p[i].Fhandle = rc; filtssp->fst_Filtp(i) = copy_filter(filtp); } } return(LLDAL_RC_OK); Mem_setf_error: rsvp_errno = Set_Errno( RSVP_Err_RSVP_SYS_ERROR, RSVP_Erv_MEMORY); return(LLDAL_RC_ERROR); } #ifdef LABEL int Kernel_SetLabel(Session *destp, TCSB *kp, RSB *rp) { /* sets a label in the TCSB. This works only for FF reservations at the moment and has to be extended for SE and if possible for WF */ int rc; kp->tcs_label = rp->rs_label; #ifdef SCHEDULE if(if_vec[kp->tcs_OIf].if_up) /* Hack to allow some CBQed and non CBQed iface*/ { rc = TC_AddLabel(kp->tcs_OIf, kp->tcs_rhandle, destp, rp); } #endif if (IsDebug(DEBUG_ALL)) { log_K(LOGEV_TC_addlabel, destp, kp); if (IsDebug(DEBUG_EVENTS)) log(LOG_DEBUG, 0, "Label= %ld Lhandle=%d\n",rp->rs_label->label_obj, rc); } if (rc == TC_ERROR) return(LLDAL_RC_ERROR); return(LLDAL_RC_OK); } #endif /* Consider the set of RSB's matching SESSION and OI from the * active RSB. If the style is distinct, the Filterspec_list * in the RSB must also be matched. Merge them to compute * and return pointers to: * * o TC_spec, (copy of) effective TC flowspec to be installed * * o TC_FiltS, (copy of) union of FILTER_SPEC*'s in the set. * * It also sets MERGED flag on/off in active RSB, and returns * LLDAL_RC_OK or LLDAL_RC_ERROR. */ int Kernel_Merge(Session *destp, RSB *rp, FLOWSPEC **TC_specpp, FiltSpecStar **TC_FiltSpp) { RSB *trp; int cmp; FLOWSPEC *specp = NULL; int count = 0; *TC_specpp = NULL; *TC_FiltSpp = NULL; for (trp = destp->d_RSB_list; trp != NULL; trp = trp->rs_next) { if (!RSBs4_sameLL(trp, rp)) continue; count++; cmp = Compare_Flowspecs(trp->rs_spec, specp); switch (cmp) { case SPEC1_GTR: specp = trp->rs_spec; break; case SPECS_USELUB: specp = LUB_of_Flowspecs(trp->rs_spec, specp); break; case SPECS_INCOMPAT: rsvp_errno = Set_Errno( RSVP_Err_TC_ERROR, RSVP_Erv_Conflict_Serv); return(LLDAL_RC_ERROR); default: break; } if (union_filtstar(trp->rs_filtstar, TC_FiltSpp) < 0) goto Mem_merge_error; } *TC_specpp = copy_spec(specp); if ((!*TC_specpp) && specp) goto Mem_merge_error; rp->rs_flags &= ~RSB_FLAG_MERGED; if (count > 1) rp->rs_flags |= RSB_FLAG_MERGED; return(LLDAL_RC_OK); Mem_merge_error: rsvp_errno = Set_Errno( RSVP_Err_RSVP_SYS_ERROR, RSVP_Erv_MEMORY); return(LLDAL_RC_ERROR); } /* * TC_Newflow or TC_ModFlow returned a new flowspec, attach it to * the first matching RSB (same OI, filter spec). */ int Kernel_Return_Spec(Session *destp, RSB *rp, FLOWSPEC *Fwd_specp) { RSB *trp; int rc = LLDAL_RC_OK; for (trp = destp->d_RSB_list; trp != NULL; trp = trp->rs_next) { if (!RSBs4_sameLL(trp, rp)) continue; if (trp->rs_fwd_spec) free(trp->rs_fwd_spec); trp->rs_fwd_spec = copy_spec(Fwd_specp); if (!trp->rs_fwd_spec) rc = LLDAL_RC_ERROR; break; } free(Fwd_specp); return(rc); } /************************************************************************* * * Utility routines * *************************************************************************/ TCSB * locate_TCSB( Session *destp, int out_if, FiltSpecStar *filtssp, style_t style) { TCSB *kp; if (Style_is_Shared(style)) return((TCSB *)destp->d_LLB_listv[out_if]); for (kp = (TCSB *)destp->d_LLB_listv[out_if]; kp != NULL; kp = kp->tcs_next) { if (match_filter(filtssp->fst_filtp0, kp->tcs_filtstar->fst_filtp0)) break; } return(kp); } #ifdef LABEL TCSB * locate_label_TCSB( Session *destp, int out_if, Label *label, style_t style) { TCSB *kp; if (Style_is_Shared(style)) return((TCSB *)destp->d_LLB_listv[out_if]); for (kp = (TCSB *)destp->d_LLB_listv[out_if]; kp != NULL; kp = kp->tcs_next) { if (label->label_obj == kp->tcs_label->label_obj) break; } return(kp); } #endif /* Make TCSB control block with 'nhandles' empty filter * spec slots. */ TCSB * make_TCSB(Session *destp, int out_if, int nhandles) { TCSB *kp; int size; /* Allocate TCSB with contiguous FiltSpecStar area. Clear all. */ size = SizeofFiltSpecStar(nhandles) + sizeof(TCSB); kp = (TCSB *) malloc(size); if (!kp) { Log_Mem_Full("TCresv1"); return(NULL); } memset((char *)kp, 0, size); kp->tcs_filtstar = (FiltSpecStar *)((char *) kp + sizeof(TCSB)); kp->tcs_next = (TCSB *)destp->d_LLB_listv[out_if]; destp->d_LLB_listv[out_if] = (void *)kp; /*** kp->tcs_OIf = if_vec[out_if].if_index; ***/ kp->tcs_OIf = out_if; kp->tcs_filtstar->fst_count = 0; kp->tcs_filtstar->fst_size = nhandles; return(kp); } /* Expand an existing TCSB control block with space for nhandle * filter handles. */ TCSB * trade_TCSB(Session *destp, TCSB *kp, int nhandles) { TCSB *nkp; int n = kp->tcs_filtstar->fst_size; nkp = make_TCSB(destp, kp->tcs_OIf, nhandles); if (!nkp) { Log_Mem_Full("TCresv1"); return(NULL); } memcpy(nkp, kp, sizeof(TCSB)); nkp->tcs_filtstar = (FiltSpecStar *)((char *) nkp + sizeof(TCSB)); memcpy( (char *) nkp->tcs_filtstar, (char *) kp->tcs_filtstar, SizeofFiltSpecStar(n)); nkp->tcs_filtstar->fst_size = nhandles; free(kp); return(nkp); } /* * kill_TCSB(): Delete kernel reservation block */ void kill_TCSB(Session *destp, TCSB *kp) { TCSB **kpp; FiltSpecStar *filtssp; int i, OIf = kp->tcs_OIf; if (!kp) return; /* Unlink and delete kp */ for (kpp = (TCSB **)&destp->d_LLB_listv[OIf]; (*kpp) != NULL && (*kpp) != kp; kpp = &((*kpp)->tcs_next)); if (*kpp != NULL) *kpp = kp->tcs_next; free(kp->tcs_spec); if (kp->tcs_tspec) free(kp->tcs_tspec); filtssp = kp->tcs_filtstar; for (i=0; i < filtssp->fst_count; i++) if (filtssp->fst_Filtp(i)) free(filtssp->fst_Filtp(i)); free((char *)kp); } /**#define INIT_FST_COUNT 100 **/ #define INIT_FST_COUNT 1 /* for testing XXX */ /* Add new FiltSpecStar to union. Return -1 if error, else 0. */ int union_filtstar(FiltSpecStar *newfsp, FiltSpecStar **fspp) { FiltSpecStar *fsp = *fspp, *nfsp; int i, j; if (fsp == NULL) { /* First time... malloc an area. */ fsp = Get_FiltSpecStar(INIT_FST_COUNT); if (!fsp) return(-1); } for (i= 0; i < newfsp->fst_count; i++) { FILTER_SPEC *filtp = newfsp->fst_Filtp(i); for (j = 0; j < fsp->fst_count; j++) { if (match_filter(filtp, fsp->fst_Filtp(j))) break; } if (j == fsp->fst_count) { /* Add new filter to union */ if (fsp->fst_count >= fsp->fst_size) { nfsp = Get_FiltSpecStar(2*fsp->fst_count); if (!nfsp) return(-1); memcpy(nfsp, fsp, sizeof(FiltSpecStar) + (fsp->fst_count-1)*sizeof(FILTER_SPEC *)); nfsp->fst_size = 2*fsp->fst_count; free(fsp); fsp = nfsp; } fsp->fst_p[fsp->fst_count++].fst_filtp = filtp; } } *fspp = fsp; return(0); } void log_K(int evtype, Session *destp, TCSB *kp) { char *flgstr = cnv_flags("?????BME", kp->tcs_kflags); log_event(evtype, if_vec[kp->tcs_OIf].if_name, destp->d_session, " Flg=%s =>handle=%d\n", flgstr, kp->tcs_rhandle); }