/* * @(#) $Id: rsvp_path.c,v 4.50 1998/08/17 20:52:34 mtalwar Exp $ */ /************************ rsvp_path.c ******************************* * * * Routines to receive, process, and send Path and PathTear * * 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) 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_exroute.h" /* external declarations */ Session *make_session(SESSION *); Session *locate_session(SESSION *); Session *locate_session_p(SESSION *); int start_UDP_encap(); void api_PATH_EVENT_upcall(Session *); int send_pkt_out_vif(int, Session *, FILTER_SPEC *, struct packet *); void move_object(); int Compare_Tspecs(SENDER_TSPEC *, SENDER_TSPEC *); Object_header *copy_object(Object_header *); struct packet *new_packet_area(packet_area *); ADSPEC *TC_Advertise(int, ADSPEC *, int); int match_filter(FILTER_SPEC *, FILTER_SPEC *); u_int32_t Compute_TTD(TIME_VALUES *), Compute_R(TIME_VALUES *); char *bm_expand(); #ifndef HOST_ONLY void rsrr_send_rq(); #endif void delete_resv4PSB(); void PSB_update_LL(Session *, PSB *); int resv_refresh(Session *, int); void clear_scope_union(Session *); Fobject *FQrmv(Fobject **); void FQkill(Fobject **); int match_policy(POLICY_DATA *, POLICY_DATA *); #ifdef LABEL extern Label * new_label_obj(u_char); extern u_int32_t Get_Label(int); extern int Free_Label(char *, u_int32_t); extern int IsLabelEnabled(char *); #endif /* forward declarations */ int accept_path(int, struct packet *); int accept_path_tear(int, struct packet *); PSB *locate_PSB(Session *, SENDER_TEMPLATE *, int, RSVP_HOP *); static PSB *make_PSB(Session *, RSVP_HOP *, SENDER_TEMPLATE *); int kill_PSB(Session *, PSB *); PSB * Find_fPSB(Session *, SENDER_TEMPLATE *); void finish_path(Session *, PSB *); void multicast_path_tear(Session *, struct packet *); void common_path_header(Session *, struct packet *); int check_dstport_conflict(struct packet *); int path_refresh_common(Session *, PSB *, struct packet *); int path_refresh_PSB(Session *, PSB *); void send_path_out_vif(int, Session *, SENDER_TEMPLATE *, struct packet *); int tear_PSB(Session *, PSB *, struct packet *, Fobject *); extern int rsrr_route_query(void*,void *,net_addr *,net_addr *,int,int *,bitmap *); extern int bmptoif(bitmap *); void route_update(Session *, PSB *, int, bitmap); static int query_routing(Session *, PSB *, int *, bitmap *, int); static void unnotify_rsrr(PSB *, Session *); static net_addr src, dst; static net_addr *srcp = &src; /* static net_addr *dstp = &dst; */ #ifdef EX_ROUTE int comph_r(EXROUTE *ex_route, int in_vif); EXROUTE* pop_route(EXROUTE * route_list); u_long prefix_to_mask(int prefix); int hit_route(u_long target, u_long router, int prefix); #endif /* Defines for the switch function in accept_path */ #ifdef EX_ROUTE #define EX_ROUTE_ERR 0 #define EX_ROUTE_HOST 1 #define EX_ROUTE_NOHOST 2 #define EX_ROUTE_LAST 3 #endif /* * accept_path() This routine processes an incoming Path message, * to build/refresh path state. * * in_vif = incoming vif, or -1 if unknown (multicast UDP encap'd) */ int accept_path(int in_vif, struct packet *pkt) { u_int32_t ttd; Session *destp; PSB *psbp; RSB *rp; bitmap new_routes; int rr_vif = 0; SenderDesc *sdp = SenderDesc_of(pkt); FILTER_SPEC *filtp; Fobject *fop; int rv; #ifdef LABEL int vif; Labelreq *label_req; #endif bmp_rst(&new_routes); /* Check that INTEGRITY was included if it is required. */ if (in_vif >= 0 && (IF_FLAGS(IF_UNICAST(in_vif))&IF_FLAG_Intgrty) && pkt->pkt_map->rsvp_integrity == NULL) return PKT_ERR_INTEGRITY; /* * Find/build a Session block * * If (a PSB is found whose) session matches the * DestAddress and Protocol Id fields of the received * SESSION object, but the DstPorts differ and one is * zero, then build and send a "Conflicting Dst Port" * PathErr message, drop the Path message, and return. */ destp = locate_session_p(pkt->rsvp_sess); if ((int)destp == -1) { rsvp_path_err(in_vif, RSVP_Err_BAD_DSTPORT, 0, pkt); return(-1); } else if (destp == NULL) { destp = make_session(pkt->rsvp_sess); if (!destp) return(-1); } /* Search for a path state block (PSB) whose (session, * sender_template) pair matches the corresponding objects * in the message. For a multicast session, also match * IncInterface; for a unicast session, match PHOP address. */ psbp = IsHopAPI(pkt->rsvp_phop)? locate_PSB(destp, sdp->rsvp_stempl, -1, NULL) : session_multicast(destp->d_session)? locate_PSB(destp, sdp->rsvp_stempl, in_vif, NULL) : locate_PSB(destp, sdp->rsvp_stempl, -1, pkt->pkt_map->rsvp_hop); if (psbp == NULL) { /* * If there is no matching PSB, create a new PSB. */ psbp = make_PSB(destp, pkt->pkt_map->rsvp_hop, sdp->rsvp_stempl); if (!psbp) return(-1); /* * Copy contents of the SENDER_TEMPLATE, SENDER_TSPEC, * and PHOP (IP address and LIH) objects into * the PSB. */ psbp->ps_templ = copy_filter(sdp->rsvp_stempl); #ifdef LABEL psbp->ps_label_in = copy_label(sdp->rsvp_label); if(psbp->ps_label_in) log(LOG_DEBUG, 0, "Path Label: %d \n", psbp->ps_label_in->label_obj); for(vif = 0; vif < if_num; vif++) psbp->ps_label_out[vif] = NULL; #endif psbp->ps_tspec = copy_tspec(sdp->rsvp_stspec); Move_Object(pkt->pkt_map->rsvp_hop, &psbp->ps_rsvp_phop); psbp->ps_Frpolicy = pkt->pkt_map->rsvp_dpolicy; pkt->pkt_map->rsvp_dpolicy = NULL; #ifdef EX_ROUTE /* * In case of an EXROUTE object it will be stored in the PSB * and an error checking is performed */ if (pkt->pkt_map->rsvp_exroute != NULL){ if(Obj_Length(pkt->pkt_map->rsvp_exroute) != 0){ psbp->ps_router_list = (EXROUTE *) copy_object((Object_header *)pkt->pkt_map->rsvp_exroute); log(LOG_DEBUG, 0, "Route Object ????????!!!!!!!!!!!!\n"); switch(comph_r(psbp->ps_router_list, in_vif)){ case EX_ROUTE_ERR: log(LOG_DEBUG, 0, "ROUTE ERROR\n"); /* correct error code has to be specified when defined in draft */ rsvp_path_err(in_vif, RSVP_Err_BAD_ExRouteObj, 0, pkt); return -1; case EX_ROUTE_HOST: psbp->ps_router_list = pop_route(psbp->ps_router_list); break; case EX_ROUTE_NOHOST: break; } } } #endif #ifdef LABEL /* * Copies label request into PSB */ #ifdef EDGE if (pkt->pkt_map->rsvp_label != NULL) { psbp->ps_label_req = (Labelreq *)copy_object((Object_header *)pkt->pkt_map->rsvp_label); psbp->as_label_ident = 2; /*Set at intermediate if Egresswill be taken care in path_refreh_common */ } else { label_req = malloc(sizeof(Label)); Obj_Length(label_req) = 8; Obj_CType(label_req) = ctype_Labelreq; Obj_Class(label_req) = class_Label_Request; label_req->l3pid = 0x0800; psbp->ps_label_req = label_req; psbp->as_label_ident = 1 /*INGRESS */; } #else if (pkt->pkt_map->rsvp_label != NULL) psbp->ps_label_req = (Labelreq *)copy_object((Object_header *)pkt->pkt_map->rsvp_label); #endif /* EDGE */ #endif /* LABEL */ /* If the sender is from the local API, setBEL * OutInterface_List to the single interface whose * address matches the sender address, and make * IncInterface undefined. Otherwise, record iface * on which it arrived, and for multicast, turn on * Local_Only flag. */ if (IsHopAPI(pkt->rsvp_phop)) { psbp->ps_in_if = api_num; psbp->ps_originvif = (u_char) hop_lih(pkt->rsvp_phop); } else { psbp->ps_in_if = in_vif; if (session_multicast(destp->d_session)) { psbp->ps_flags |= PSBF_LocalOnly; } } /* If this is the first PSB for the session, start a * refresh timer. */ if (Compute_R(&destp->d_timevalp) == 0) add_to_timer((char *) destp, TIMEV_PATH, destp->d_Rtimop); /* Since new sender is added, must recompute scope union. */ clear_scope_union(destp); /* Turn on the Path_Refresh_Needed flag. If there * is WF path state, also send Resv refresh. */ psbp->ps_flags |= PSBF_Prefr_need; if ((rp = destp->d_RSB_list) != NULL && Style_is_Wildcard(rp->rs_style)) psbp->ps_flags |= PSBF_Rrefr_need; } else { /* Otherwise (there is a matching PSB): * * If a PSB is found with a matching sender host but the * SrcPorts differ and one of the SrcPorts is zero, then * build and send an "Conflicting Sender Port" PathErr * message, drop the Path message, and return. */ filtp = STempl_of(sdp); if (!match_filter((FILTER_SPEC *)filtp, psbp->ps_templ)){ rsvp_path_err(in_vif, RSVP_Err_BAD_SNDPORT, 0, pkt); return(-1); } /* If the PHOP IP address or the LIH differs between the * message and the PSB, copy the new value into the PSB * and turn on the Resv_Refresh_Needed flag. * If the sender Tspec differs, copy the new value into * the PSB and turn on the Path_Refresh_Needed flag. */ if (!IsHopAPI(&psbp->ps_phop) && !hop_eq(pkt->rsvp_phop,&psbp->ps_phop)) { Move_Object(pkt->pkt_map->rsvp_hop, &psbp->ps_rsvp_phop); psbp->ps_flags |= PSBF_Rrefr_need; } if (Compare_Tspecs(sdp->rsvp_stspec, psbp->ps_tspec) != SPECS_EQL) { free((char *) psbp->ps_tspec); psbp->ps_tspec = copy_tspec(sdp->rsvp_stspec); psbp->ps_flags |= PSBF_Prefr_need; } #ifdef LABEL psbp->ps_label_in = copy_label(sdp->rsvp_label); if(psbp->ps_label_in) log(LOG_DEBUG, 0, "Path Label: %d \n", psbp->ps_label_in->label_obj); #endif } /* Update the current PSB, as follows. * * - Start or restart the cleanup timer for the PSB. * * - Copy current Adspec into the PSB. * * - Copy E_Police flag from SESSION object into PSB. * * - Store the received TTL into the PSB. * If the received TTL differs from Send_TTL in the RSVP * common header, set the Non_RSVP flag on in the PSB. * * - Free any old unknown objects and save any new ones. * */ ttd = Compute_TTD(pkt->pkt_map->rsvp_timev); if (LT(psbp->ps_ttd, ttd)) /* Update sender time-to-die */ psbp->ps_ttd = ttd; if ((sdp->rsvp_adspec)) { if (psbp->ps_adspec) free((char *) psbp->ps_adspec); psbp->ps_adspec = copy_adspec(sdp->rsvp_adspec); } if (session_get_flags(pkt->rsvp_sess) & SESSFLG_E_Police) psbp->ps_flags |= PSBF_E_Police; psbp->ps_ip_ttl = pkt->pkt_ttl; /* Set/update IP TTL */ if (pkt->pkt_ttl != pkt->pkt_data->rsvp_snd_TTL) psbp->ps_flags |= PSBF_NonRSVP; FQkill(&psbp->ps_UnkObjList); psbp->ps_UnkObjList = pkt->pkt_map->rsvp_UnkObjList; pkt->pkt_map->rsvp_UnkObjList = NULL; /* If policy objects have changed (or order has chnaged), * free the old ones, save the new ones, and pass them * to policy control. */ for (fop= pkt->pkt_map->rsvp_dpolicy; fop; fop = fop->Fobj_next){ if (!match_policy((POLICY_DATA *) &fop->Fobj_objhdr, (POLICY_DATA *) &psbp->ps_Frpolicy->Fobj_objhdr)){ FQkill(&psbp->ps_Frpolicy); psbp->ps_Frpolicy = pkt->pkt_map->rsvp_dpolicy; pkt->pkt_map->rsvp_dpolicy = NULL; /* Call Policy Control */ break; } } /* * If packet arrived with UDP encapsulation, set flag bit. */ if (pkt->pkt_flags&PKTFLG_USE_UDP) psbp->ps_flags |= PSBF_UDP; /* Perform/Initiate route computation. Maybe it is * asynchronous... If not, update state now, using * incoming interface and outgoing link info, then * finish Path processing by doing any needed refreshes. */ rr_vif = in_vif; rv = query_routing(destp,psbp,&rr_vif,&new_routes, 1); if (rv == -1) { log(LOG_ERR,0,"error in query_routing"); return -1; } if (!rv) { /* synchronous reply */ route_update(destp, psbp, rr_vif, new_routes); finish_path(destp, psbp); } return(0); } /* Finish processing Path message after completion of perhaps * asynchronous route query. */ void finish_path(Session *destp, PSB *psbp) { dump_ds(psbp->ps_flags & PSBF_Prefr_need); if (psbp->ps_flags&PSBF_Prefr_need) { psbp->ps_flags &= ~PSBF_Prefr_need; /* * Path state is new or modified. * 1. If Path message came from a network interface, * make a Path Event upcall for each local * application for this session. * * 2. Generate immediate Path refresh for this PSB * * 3. Update traffic control to match (new?) path state. */ if (!IsHopAPI(&psbp->ps_phop)) api_PATH_EVENT_upcall(destp); path_refresh_PSB(destp, psbp); PSB_update_LL(destp, psbp); } /* If needed, generate immediate Resv refreshes for this * PSB. Send Resv refresh towards all senders using same * incoming interface (perhaps multiple PHOPs). */ if (psbp->ps_flags & PSBF_Rrefr_need) { psbp->ps_flags &= ~PSBF_Rrefr_need; bmp_set(&(destp->d_r_incifs), psbp->ps_in_if); resv_refresh(destp, 0); } } /* * accept_path_tear(): Processes an incoming PathTear message. */ int accept_path_tear(int in_vif, struct packet *pkt) { Session *destp; PSB *psbp; packet_area data; /* Packet area */ struct packet *new_pkt; SenderDesc *sdp = SenderDesc_of(pkt); /* Added by Mohit * Check that INTEGRITY was included if it is required. */ if (in_vif >= 0 && (IF_FLAGS(IF_UNICAST(in_vif))&IF_FLAG_Intgrty) && pkt->pkt_map->rsvp_integrity == NULL) return PKT_ERR_INTEGRITY; destp = locate_session(pkt->rsvp_sess); if (destp == NULL) { log_event(LOGEV_ignore, "PATH-TEAR", pkt->pkt_map->rsvp_session, "// No dest\n"); return(0); } /* Locate PSB for same: * [Multicast dest:] (session, sender, PHOP, in_if) * [Unicast dest:] (session, sender, PHOP) */ psbp = session_multicast(destp->d_session)? locate_PSB(destp, sdp->rsvp_stempl, in_vif,pkt->pkt_map->rsvp_hop): locate_PSB(destp, sdp->rsvp_stempl, -1, pkt->pkt_map->rsvp_hop); if (!psbp) return(0); if (pkt->pkt_ttl == 0) { Incr_ifstats(psbp->ps_in_if, rsvpstat_path_ttl0_in); return(0); } Incr_ifstats(psbp->ps_in_if, rsvpstat_msgs_in[RSVP_PATH_TEAR]); /* * If the PSB to be killed has the route change notification flag * set, and it's a multicast session, send a route query with * notification flag cleared to remove this route from notification * list in the multicast routing daemon. */ if (session_multicast(destp->d_session) && BIT_TST(psbp->ps_rsrr_flags, PSBF_RSRR_NOTIFY)) unnotify_rsrr(psbp, destp); new_pkt = new_packet_area(&data); tear_PSB(destp, psbp, new_pkt, pkt->pkt_map->rsvp_UnkObjList); return 0; } /* * path_refresh(): This routine is called upon refresh timeout, to * send Path refresh for all PSBs. */ int path_refresh(Session *destp) { packet_area data; /* Packet area */ struct packet *pkt; PSB *psbp; /* Time out expired path state. If it's all gone, return -1. */ if (cleanup_path_state(destp) < 0) return(-1); /* Build packet struct, map vector, and packet buffer, and * set up common part of Path msg in map. */ pkt = new_packet_area(&data); pkt->pkt_map->rsvp_msgtype = RSVP_PATH; common_path_header(destp, pkt); /* * For PSB, send refresh. */ for (psbp= destp->d_PSB_list; psbp; psbp = psbp->ps_next) { path_refresh_common(destp, psbp, pkt); } dump_ds(0); /* record state but not too often... */ return (0); } /* * path_refresh_PSB: This routine is called when path state is created * or modified, to do an immediate refresh for specified PSB. */ int path_refresh_PSB(Session *destp, PSB *psbp) { packet_area data; /* Packet area */ struct packet *pkt; /* Build packet struct, map vector, and packet buffer, and * set up common part of Path msg in map. */ pkt = new_packet_area(&data); pkt->pkt_map->rsvp_msgtype = RSVP_PATH; common_path_header(destp, pkt); path_refresh_common(destp, psbp, pkt); dump_ds(0); /* record state but not too often... */ return (0); } /* * This routine sends a path refresh for a particular sender, * i.e., a PSB. This routine may be entered by either the * expiration of the path refresh timer or directly as the result * of the (Path_)Refresh_Needed flag being turned on during the * processing of a received Path message. */ int path_refresh_common(Session *destp, PSB *psbp, struct packet *pkt) { SenderDesc *sdscp = SenderDesc_of(pkt); int vif; /* Compute the IP TTL for the Path message as one less than * the TTL value from the sender. However, if the result is * zero, return without sending the Path message. */ if ((pkt->pkt_ttl = psbp->ps_ip_ttl - 1) <= 0) { Incr_ifstats(psbp->ps_in_if, rsvpstat_path_ttl0_out); return(0); } /* Create a sender descriptor containing the SENDER_TEMPLATE, * SENDER_TSPEC, and POLICY_DATA objects, if present in the * PSB, and pack it into the Path message being built. */ sdscp->rsvp_stempl = psbp->ps_templ; sdscp->rsvp_stspec = psbp->ps_tspec; /* * Copy into Path msg map a pointer to list of unknown objects * to be forwarded. */ #ifdef EX_ROUTE pkt->pkt_map->rsvp_exroute = (EXROUTE *) copy_object((Object_header *)psbp->ps_router_list); #endif pkt->pkt_map->rsvp_UnkObjList = psbp->ps_UnkObjList; /* Send a copy of the Path message to each interface OI in * OutInterface_list. Before sending each copy: * 1. Pass any ADSPEC and SENDER_TSPEC objects present in the PSB * to the traffic control call TC_Advertise. Insert the * modified ADSPEC object that is returned into the Path * message. * 2. If the PSB has the E_Police flag on but interface OI is * incapable of policing, turn on the E_Police flag in the * message. * 3. Insert into the PHOP object the interface address and * the LIH for the interface. */ sdscp->rsvp_adspec = NULL; for (vif= 0; vif < if_num; vif++) { if (IsNumAPI(vif)) continue; if (IF_DOWN(vif)) continue; if (!bmp_tst(&(psbp->ps_outif_list), vif)) continue; #ifdef LABEL if(IsLabelEnabled(if_vec[vif].if_name)) { pkt->pkt_map->rsvp_label = (Labelreq *) copy_object((Object_header *)psbp->ps_label_req); } else { pkt->pkt_map->rsvp_label = NULL; psbp->as_label_ident = 0; } #endif pkt->pkt_map->rsvp_UnkObjList = psbp->ps_UnkObjList; #ifdef SCHEDULE if(if_vec[vif].if_up) /* hack to allow some CBQed and non-CBQed ifaces */ { if (psbp->ps_adspec) sdscp->rsvp_adspec = TC_Advertise(vif, psbp->ps_adspec, (int) psbp->ps_flags&PSBF_NonRSVP); } #endif /* SCHEDULE */ if ((psbp->ps_flags&PSBF_E_Police)&& if_vec[vif].if_up==0) session_set_flags(pkt->rsvp_sess, session_get_flags(pkt->rsvp_sess) | SESSFLG_E_Police); #ifdef LABEL if ((session_multicast(destp->d_session)) && (pkt->pkt_map->rsvp_label)) { if (psbp->ps_label_out[vif] == NULL) { psbp->ps_label_out[vif] = new_label_obj(ctype_Label); psbp->ps_label_out[vif]->label_obj = Get_Label(vif); } sdscp->rsvp_label = psbp->ps_label_out[vif]; } else sdscp->rsvp_label = NULL; #endif send_path_out_vif(vif, destp, STempl_of(sdscp), pkt); if (sdscp->rsvp_adspec) { free(sdscp->rsvp_adspec); sdscp->rsvp_adspec = NULL; } } return(0); } /* * locate_PSB() returns the PSB matching a (SESSION, SENDER_TEMPLATE) and * possibly in_vif and/or PHOP address. In_vif < 0 and NULL * PHOP address are wildcards. * */ PSB * locate_PSB(Session *destp, SENDER_TEMPLATE *filtp, int in_vif, RSVP_HOP *phop) { PSB *sp; for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next) { if (match_filter(filtp, sp->ps_templ)) { if ( (in_vif < 0 || in_vif == sp->ps_in_if) && (phop == NULL || hop_addr_eq(phop,&sp->ps_phop))) return sp; } } return (NULL); } /* * make_PSB(): Add a PSB data structure to a session */ PSB * make_PSB(Session *dst, RSVP_HOP *phop, SENDER_TEMPLATE *stemp) { PSB *psbp, **spp, *tsp; psbp = (PSB *) calloc(1, sizeof(PSB)); if (!psbp) { Log_Mem_Full("New sender"); return(NULL); } psbp->ps_ttd = time_now; psbp->ps_next = NULL; bmp_rst(&(psbp->ps_outif_list)); psbp->ps_rsrr_flags = 0; /* * Insert PSB in list in ascending order by sender IP address * within phop. */ for (spp = &dst->d_PSB_list; ; spp = &((*spp)->ps_next)){ if (!(*spp) || hop_addr_lt(phop,&(*spp)->ps_phop)) { /* First sender for this PHOP: insert it here and * set 1stphop field to point to itself. */ psbp->ps_next = *spp; *spp = psbp; psbp->ps_1stphop = psbp; return(psbp); } if (hop_addr_eq(phop,&(*spp)->ps_phop)) break; } /* * PHOP address already in list. */ if (filterspec_lt(stemp,(*spp)->ps_templ)){ /* * Special case: new sender is first (smallest) address */ psbp->ps_1stphop = psbp; /* pt to itself */ for (tsp = *spp; tsp ; tsp = tsp->ps_next) { if (!hop_addr_eq(phop,&tsp->ps_phop)) break; tsp->ps_1stphop = psbp; } } else { psbp->ps_1stphop = *spp; assert((*spp)->ps_1stphop == *spp); for (spp = &((*spp)->ps_next); *spp ; spp = &((*spp)->ps_next)){ if (hop_addr_lt(phop,&(*spp)->ps_phop) || filterspec_lt(stemp,(*spp)->ps_templ)) break; } } psbp->ps_next = *spp; *spp = psbp; return (psbp); } /* * kill_PSB(): This routine frees a PSB data structure. * Called from cleanup_path_state (when sender times out) or * from accept_path_tear. * It deletes any dependent reservation state, and if all path and * reservation state is gone, it deletes the session and returns -1. */ int kill_PSB(Session *destp, PSB *psbp) { PSB **spp, *sp, *fsp; int from_net; assert(destp); if (!psbp) return(0); /* * remove PSB from linked list */ for (spp = &destp->d_PSB_list; (*spp) != NULL; spp = &((*spp)->ps_next)) { if ((*spp)->ps_1stphop == (*spp)) fsp = *spp; if ((*spp) == psbp) break; } if (*spp != NULL) *spp = psbp->ps_next; /* If this was first PSB per phop, recompute 1stphop pointers. */ if (fsp == psbp) { for (sp = psbp->ps_next; sp; sp = sp->ps_next) { if (sp->ps_1stphop != psbp) break; sp->ps_1stphop = psbp->ps_next; } } delete_resv4PSB(destp, psbp); /* Delete any dangling reservations */ clear_scope_union(destp); /* Set to recompute scope union */ from_net = !IsHopAPI(&psbp->ps_phop); free((char *) psbp->ps_templ); if (psbp->ps_tspec) free((char *) psbp->ps_tspec); if (psbp->ps_adspec) free((char *) psbp->ps_adspec); if (psbp->ps_BSB_Qb) free((char *) psbp->ps_BSB_Qb); if (psbp->ps_resv_spec) free(psbp->ps_resv_spec); FQkill(&psbp->ps_UnkObjList); free((char *) psbp); /* delete the PSB block itself */ /* Send Path Event upcall to all matching apps, except local state*/ if (from_net) api_PATH_EVENT_upcall(destp); if (!destp->d_PSB_list && !destp->d_RSB_list) { kill_session(destp); return(-1); } return (0); } /* Locate "forwarding" PSB for specified session, sender. Forwarding * PSB is the PSB that is *not* marked LocalyOnly. Return addr of PSB * or NULL if there is none. */ PSB * Find_fPSB(Session *destp, SENDER_TEMPLATE *filtp) { PSB *sp; for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next){ if (match_filter(filtp, sp->ps_templ)) { if (!(sp->ps_flags&PSBF_LocalOnly)) return(sp); } } return(NULL); } /* * cleanup_path_state(): For given session, kill all expired path state. * Return 1 if something was killed, -1 if entire session * was killed, else 0. */ int cleanup_path_state(Session *destp) { PSB *psbp, *psbpx; packet_area data; /* Packet area */ struct packet *pkt = NULL; int rc, killed = 0; /* * For each expired PSB, forward PTear message to all * outgoing vifs and then kill PSB. */ for (psbp = destp->d_PSB_list; psbp; psbp = psbpx) { psbpx = psbp->ps_next; if (!LT(psbp->ps_ttd, time_now)) continue; killed = 1; Incr_ifstats(psbp->ps_in_if, rsvpstat_path_timeout); if (!pkt) pkt = new_packet_area(&data); rc = tear_PSB(destp, psbp, pkt, NULL); if (rc < 0) return -1; } return(killed); } /* * Delete a PSB: forward PTear message to all outgoing vifs and then kill * PSB. Common code for accept_path_tear() and cleanup_path_state(). * In the first case, specify list of unknown objects to be forwarded. */ int tear_PSB(Session *destp, PSB *psbp, struct packet *pkt, Fobject *fobjp) { SenderDesc *newsdp; int vif; /* * Generate PathTear message */ pkt->pkt_map->rsvp_msgtype = RSVP_PATH_TEAR; common_path_header(destp, pkt); newsdp = SenderDesc_of(pkt); newsdp->rsvp_stempl = psbp->ps_templ; /* Omit Sender_Tspec and Adspec. */ pkt->pkt_map->rsvp_UnkObjList = fobjp; /* * Send PathTear message to each outgoing vif. */ if (psbp->ps_ip_ttl > 0) { pkt->pkt_ttl = psbp->ps_ip_ttl - 1; for (vif = 0; vif < if_num; vif++) { if (IsNumAPI(vif)) continue; if (IF_DOWN(vif)) continue; if (bmp_tst(&(psbp->ps_outif_list), vif)) send_path_out_vif(vif, destp, STempl_of(newsdp), pkt); #ifdef LABEL if (session_multicast(destp->d_session)) { if (psbp->ps_label_out[vif] != NULL) Free_Label(if_vec[vif].if_name, psbp->ps_label_out[vif]->label_obj); } #endif } } return (kill_PSB(destp, psbp)); } void common_path_header(Session *destp, struct packet *pkt) { static RSVP_HOP hop; packet_map *mapp = pkt->pkt_map; mapp->rsvp_session = destp->d_session; if(pkt->pkt_map->rsvp_msgtype != RSVP_PATH_TEAR) { mapp->rsvp_timev = &destp->d_timevalp; } mapp->rsvp_hop = &hop; #ifdef EX_ROUTE mapp->rsvp_exroute = (EXROUTE *) copy_object((Object_header *)destp->d_PSB_list->ps_router_list); #endif pkt->rsvp_nflwd = 1; /* Exactly one sender */ switch(Obj_CType(destp->d_session)) { case ctype_SESSION_ipv4: case ctype_SESSION_ipv4GPI: case ctype_LSP_TUNNEL_IPv4: 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; } } void send_path_out_vif( int vif, Session *destp, SENDER_TEMPLATE *sdscp, struct packet *pkt) { assert(pkt->pkt_order == BO_HOST); /* * Previous-Hop address = addr of output interface. */ hop_if_assign(pkt->rsvp_phop,&GET_IF(vif),vif); send_pkt_out_vif(vif, destp, sdscp, pkt); } /* query_routing(): Initiate/perform route computation for sender. * Return 1 if asynchronous, else 0. * * If destination is multicast and mrouted is running (and raw I/O?? XXX) * then send RSRR message to mrouted requesting route for (S,G) and * return 1. For unicast routing, do synchronous lookup, set output * bitmap *bm, and return 0. For the API in a (possibly multihomed) * host, match S against our interfaces to generate *bm, and return 0. */ static int query_routing(Session *destp, PSB *psbp, int *in_vifp, bitmap *bmp, int note) { int i; u_char stype, ptype; int mcast; bmp_rst(bmp); #if defined LABEL #define TYPE_V4(x) ((x == ctype_SESSION_ipv4) || (x == ctype_SESSION_ipv4GPI) \ || (x == ctype_SESSION_lsp_tunv4) ) #else #define TYPE_V4(x) ((x == ctype_SESSION_ipv4) || (x == ctype_SESSION_ipv4GPI)) #endif #ifdef USE_IPV6 #define TYPE_V6(x) ((x == ctype_SESSION_ipv6) || (x == ctype_SESSION_ipv6GPI)) #endif /* USE_IPV6 */ stype = Obj_CType(&(destp->d_session->sess_header)); if (TYPE_V4(stype)) { #if defined LABEL /* first copy the session dest addr modify later if EX_ROUTE */ if(stype == ctype_SESSION_lsp_tunv4) { NET_SET_ADDR_IPv4(&dst, destp->d_session->sesslsp_addr); } else #endif NET_SET_ADDR_IPv4(&dst, destp->d_session->sess4_addr); #if defined EX_ROUTE if(psbp->ps_router_list) { dst.type = NET_ADDR_IPv4; NET_GET_ADDR_IPv4(&dst) = session_addr_exr(psbp->ps_router_list)->u.addr_ipv4; } #endif } #ifdef USE_IPV6 else if (TYPE_V6(stype)) { NET_SET_ADDR_IPv6(&dst, destp->d_session->sess6_addr); } #endif /* USE_IPV6 */ mcast = session_multicast(destp->d_session); /* Multicast session */ if (mcast) { ptype = Obj_CType(&(psbp->ps_templ->filt_header)); switch (ptype) { case ctype_SENDER_TEMPLATE_ipv4: NET_SET_ADDR_IPv4(&src, psbp->ps_templ->filt4_srcaddr); break; case ctype_SENDER_TEMPLATE_ipv4GPI: NET_SET_ADDR_IPv4(&src, psbp->ps_templ->filtgpi4_srcaddr); break; #if defined LABEL /* case ctype_SENDER_TEMPLATE_lspv4 NET_SET_ADDR_IPv4(&src, psbp->ps_templ->filtlsp4_saddr); break; */ #endif #ifdef USE_IPV6 case ctype_SENDER_TEMPLATE_ipv6: case ctype_SENDER_TEMPLATE_ipv6FL: NET_SET_ADDR_IPv6(&src, psbp->ps_templ->filt6_srcaddr); break; case ctype_SENDER_TEMPLATE_ipv6GPI: NET_SET_ADDR_IPv6(&src, psbp->ps_templ->filtgpi6_srcaddr); break; #endif /* USE_IPV6 */ default: /* shouldn't be here */ log(LOG_ERR,errno,"No such type"); break; } srcp = &src; } else srcp = 0; if (!mcast) { /* * Unicast case. */ if (session_if(destp->d_session) >= 0) { /* Unicast Path message destined to one of my * interfaces. That's it... */ return(0); } if ((TYPE_V4(stype) && !NoUnicast) #ifdef USE_IPV6 || (TYPE_V6(stype) && !NoUnicast) #endif /* USE_IPV6 */ ) { i = rsrr_route_query((void *)psbp, (void *)destp, srcp, &dst, note, in_vifp, bmp); if (i == -1) { log(LOG_ERR,errno,"Unicast route error"); return -1; } if (i > 0) /* (In case asynchronous) */ return(i); i = bmptoif(bmp); if (i == -1) { log(LOG_ERR,errno,"bmptoif failed"); return -1; } return(0); } } else if ((TYPE_V4(stype) && !NoV4Mroute) #ifdef USE_IPV6 || (TYPE_V6(stype) && !NoV6Mroute) #endif /* USE_IPV6 */ ) { /* * Multicast case: If there is an mrouted, send RSRR * route query and return 1 (asynch) unless route * notification is enabled for this PSB and PSB state * has not changed. */ #ifdef HOST_ONLY assert(0); #else /* * If we only intend to remove this route from the route change * notification list in the multicast routing daemon */ if (!note) return rsrr_route_query((void *)psbp, (void *)destp, srcp, &dst, note, in_vifp, bmp); if ((!BIT_TST(psbp->ps_rsrr_flags, PSBF_RSRR_NOTIFY) || psbp->ps_flags & PSBF_Prefr_need)) { i = rsrr_route_query((void *)psbp, (void *)destp, srcp, &dst, note, in_vifp, bmp); if (i > 0) return(i); /* Is asynchronous */ if (i == -1) { log(LOG_ERR,errno,"Multicast route failed"); return -1; } return 0; } else { *bmp = psbp->ps_outif_list; *in_vifp = psbp->ps_in_if; return(0); } #endif /* HOST_ONLY */ } if (IsHopAPI(&psbp->ps_phop)) { /* If sender is local API, s_originvif is outgoing interface; * set this as the only route. */ bmp_set(bmp, psbp->ps_originvif); *in_vifp = psbp->ps_in_if; return(0); } /* Else... assume we are a host with one interface. */ /* Peserve the actual interface if we know it; else assume interface 0. */ if (*in_vifp < 0) *in_vifp = 0; return(0); } /* route_update(): Update state after route computation. * May be called synchronously (called from * path_refresh_common()) or asyncronously (called * from rsrr_update()). */ void route_update(Session *destp, PSB *psbp, int in_vif, bitmap new_routes) { extern char s[]; int mcast = 0; PSB *fPSB = Find_fPSB(destp, psbp->ps_templ); if (!IsHopAPI(&psbp->ps_phop)) /* If it's from the network, send it to API, too */ bmp_set(&new_routes, api_num); /* Count Path messages. Note: Delayed until here * because may not have known incoming interface until * asynchronous return from RSRR told us. */ if (in_vif >= 0) Incr_ifstats(in_vif, rsvpstat_msgs_in[RSVP_PATH]); mcast = session_multicast(destp->d_session); if (IsHopAPI(&(psbp->ps_phop))) { /* If inc iface was unknown, assume routing result */ if (psbp->ps_in_if < 0) psbp->ps_in_if = in_vif; fPSB = psbp; } else if (mcast) { /* Multicast routing */ /* If inc iface was unknown, assume routing result */ if (psbp->ps_in_if < 0) psbp->ps_in_if = in_vif; /* If this Path msg arrived on an interface different from * what routing says but *psbp was the forwarding PSB, then * route has changed; make *psbp local-only. */ if (psbp->ps_in_if != in_vif && fPSB == psbp) { psbp->ps_flags |= PSBF_LocalOnly; bmp_rst(&(psbp->ps_outif_list)); fPSB = locate_PSB(destp, psbp->ps_templ, in_vif, NULL); } /* Else if Path msg arrived on correct routing interface but * this PSB is not forwarding PSB (it was local-only), swap * local-only designation with forwarding PSB. */ else if (psbp->ps_in_if == in_vif && fPSB != psbp) { if (fPSB) { psbp->ps_outif_list = fPSB->ps_outif_list; bmp_rst(&(fPSB->ps_outif_list)); fPSB->ps_flags |= PSBF_LocalOnly; } fPSB = psbp; psbp->ps_flags &= ~PSBF_LocalOnly; } } else { /* Unicast routing or no routing (end system) */ fPSB = psbp; } /* We know incoming interface and sender is not from API; if * pkt arrived with UDP encaps, mark incoming interface UDP. */ if (psbp->ps_flags & PSBF_UDP) { start_UDP_encap(in_vif); if_vec[IF_UNICAST(in_vif)].if_flags |= IF_FLAG_UseUDP; } /* If outgoing links have changed for existing PSB, set timer * to initiate local repair (=> path refresh). */ if (fPSB && !bmp_equ(&(fPSB->ps_outif_list), &new_routes)) { if (!bmp_zero(&(fPSB->ps_outif_list))){ if (IsDebug(DEBUG_RSRR)) { log(LOG_DEBUG, 0, "Outgoing vifs changed from %s\n", bm_expand(&(fPSB->ps_outif_list), s)); } add_to_timer((char *) destp, TIMEV_LocalRepair, LOCAL_REPAIR_W); } fPSB->ps_outif_list = new_routes; } } /* * Called when a PSB is going to be deleted, and it this PSB belongs to a * multicast session, while this PSB has the PSBF_RSRR_NOTIFY bit set. */ static void unnotify_rsrr(PSB *psbp, Session *ses) { int in_if = 0; bitmap bmp; if (BIT_TST(psbp->ps_rsrr_flags, PSBF_RSRR_NOTIFY)) query_routing(ses, psbp, &in_if, &bmp, 0); return; } #ifdef EX_ROUTE /* * It is checked if the message was sent the correct path and if * further processing is possible without any errors. */ int comph_r(EXROUTE *ex_route, int in_vif) { u_long target; u_long router; EX_ROUTE_IPv4 *ex_routep; int prefix; ex_routep = (EX_ROUTE_IPv4 *)(((char *)ex_route) + 4); router = (ex_routep->ipv4_addr2 << 16 ) | (ex_routep->ipv4_addr1); /* Draft wrong */ prefix = ex_routep->rprefix; if (strcmp(if_vec[in_vif].if_name, "API") != 0) { target = if_vec[in_vif].if_addr.u.inf.addr.u.addr_ipv4.s_addr; if (router == 0) /* No explicit route entry */ return EX_ROUTE_ERR; if (hit_route(target,router,prefix) == 1) /* Host is next hop in explicit route */ return EX_ROUTE_HOST ; else { if (ex_routep->l== 1) { /* L-Bit Set ?? */ if(unicast_route(session_addr_exr(ex_route)) != -1) /* Host is on route to next hop */ return EX_ROUTE_NOHOST; else return EX_ROUTE_HOST; } return EX_ROUTE_ERR; } return EX_ROUTE_ERR; } else { //pop_route(ex_route); if(unicast_route(session_addr_exr(ex_route)) != -1) /* Host is on route to next hop */ return EX_ROUTE_NOHOST; } return EX_ROUTE_ERR; } /* * pop_route deletes the first address in the EXROUTE objects and sets the * following addres on first place */ EXROUTE* pop_route(EXROUTE * route_list) { memcpy(((char *)route_list+4),((char *)route_list+12), (Obj_Length(route_list)-8)); if ((Obj_Length(route_list) -= 8) < 12) return NULL; return route_list; } /* * If a netmask is specified in the EXROUTE object, this function is used to determine * if this host belongs to the specified subnet. */ int hit_route(u_long target, u_long router, int prefix) { u_long netmask; if(prefix != 0){ netmask = prefix_to_mask(prefix); if((target & htonl(netmask)) == (router & htonl(netmask))) return 1; } if(target == router) return 1; return 0; } #endif