Design of RSVPD for zMPLS ========================== Schedules (Includes the schedules of LDPD) ========================================== Phase 1 ======== 1) Support of Path, Resv, Path Err, Resv Err, Path Tear and Resv Tear Messages. 2) Support of basic RSVP Signaling Objects and TE extensions-RSVP SESSION. SENDER_TEMPLATE, FILTER_SPEC objects (LSP_TUNNEL_IPV4 , LSP_TUNNEL_IPV6) ,and LRO and Label Objects, 3) Support of only best effort LSps without CSPF and without ERO. 4) Support of best effort LSPs without Resource Reservation. Phase 2 ========= 1) Support of CSPF and interaction with ISIS,OSPF in computing CSPF Paths. May be we need to add TE support in ISIS,OSPF. 2) Support of explicit Objects (ERO/RRO) in setting up explicit routed LSPs without Reservation.Support of SESSION_ATTRIBUTE, EXPLICIT_ROUTE and RECORD_ROUTE Phase 3 ========= 1) Development of Resource Manager and support of resource reservation 2) Signaling Reservation objects Phase 4 ======== 1) Integration of Diff serv or desiging new Diffserv code. 2) Support for Diff serv signaling in RSVP-TE Phase 5 ======== 1) Implementation of Diffserv-TE and RSVP Support. 2) RSVP Refresh Reduction Techniques. Phase 6 ======== 1) RSVP Graceful Restart Support. FUNCTIONAL SPECIFICATION ========================= Commands to be supported: 1) mpls router-id loopback <number> (from 0 to 65535) Must be configured. Action : 1) MPLS_NODE is added to lib/command.h with prompt "config-mpls# ". Config write is mpls_config_write. 2) Command "mpls" is added to CONFIG_NODE. This command will change the vty->node = MPLS_NODE and vty->index = rm->rsvp. 3) Command "router-id loopback x" is added to MPLS_NODE. 4) MPLS_NODE is added to default_commands in command.c (vty->nodeafter exit/quit from MPLS_NODE is CONFIG_NODE. 2) Interface ethx (interface node) mpls traffic-eng tunnels mpls traffic-eng refresh-interval <1..1000> (Default 30 seconds) mpls traffic-eng refresh-multiple <> (Default 3) mpls traffic-eng hello-interval <0...10000> ms (Default 5 seconds) mpls traffic-eng hello-persist <1-100> (Default 2) mpls traffic-eng hello-tolerance <1-100> (Default 3) mpls traffic-eng message-bundling (Default Disabled) mpls traffic-eng refresh-reduction (Default Disabled) Actions: INTERFACE_NODE already exists. So just add the commands and command handlers to INTERFACE_NODE. 3) rsvp set global preemption (rsvp node) ACTION : 1) RSVP_NODE is added in lib/command.h with prompt "config-rsvp# " rsvp_config_write () is added in rsvp_vty.c for writing config for this node. 2) "set global preemption" command is added to RSVP_NODE. 3) The exit/quit commands in lib/command.c is modified to have CONFIG_NODE as parent node for RSVP_NODE. 4) Default node commands are installed in RSVP_NODE. 4) show mpls rsvp parameters (en node) show mpls interfaces Action: As SHOW_NODE already exists so just add the commands. Configuring LSPs 5)ip explicit-path name xyz next-address 30.1.1.1 strict next-address 30.1.1.2 loose next-address 31.1.1.2 loose Actions : 1) A new node RSVP_IP_PATH_NODE is added to lib/command.h. Prompt "config-ip-path #". 2) Add command "ip explicit-path name [IFNAME]" to it. This command switches to vty->node RSVP_IP_PATH and vty->index = path_name. 3) Install commands "next address ..." to RSVP_IP_PATH_NODE. 4) Parent node of RSVP_IP_PATH is CONFIG_NODE. 5) Install defaults in RSVP_IP_PATH. 6)interface Tunnel4 tunnel mode mpls traffic-eng tunnel destination 10.1.1.2 tunnel mpls traffic-eng cspf tunnel mpls traffic-eng path-option 1 (explicit|dynamic) xyz (standby|) 7) access-list test permit tcp 20.1.1.1 0.0.0.255 any route-map shortcut permit 10 match ip address test set interface Tunnel 1 Functional Modules =================== The following blocks provide a very high level architecture of rsvpd. User Events | +----------------------------+ | VTY Module rsvp_vty.c | /----------+----------------------------+ / | +-------------------+/ +-----------------------------------+ | rsvp_if.c | | | | struct rsvp_if |<----------->| rsvpd.c(RSVP Daemon) | +-------------------+<----+ | | ^ | | | | | | | v | | rsvp_master-->threads | +-------------------+ | | | | | rsvp_lsp_fsm.c | | | struct rsvp | | LSP FSMs | | | |-------rsvp_tunnel_if(Ingr)| | Changes states of | | | | / \ | | LSPs on events | | | | rsvp_lsp rsvp_lsp | +-------------------+ | | | | | | | |-------rsvp_tunnel_if(Egr) | | | | |-------rsvp_tunnel)if (Trs)| v | +-----------------------------------+ +--------------------+ +--------^----------+ | rsvp_lsp.h/c | | | | struct rsvp_lsp | +---------v--------+ | +------------------+ | LSP State Machine | |rsvp_tunnel.h/c | | | rsvp_route.c | | struct rsvp_lsp | | | | +-------------^----+ | | | | |struct rsvp_tunnel| | | | rsvp_psb rsvp_rsb|<-> | | | | +---------------+ | Registers callbacks| |rsvp_lsp rsvp_lsp| +--------- | rsvp_zmpls.c |--> | with rsvp_softstate| | | | if_add/del/dn | | for LSP events | | |<---------->| route_add/del | +--------------------+ +------------------+ | addr add/del | ^ | lsp add/del | |rsvp_lsp callbacks +---------------+ | +--------------------+ +------------------------+ | rsvp_softstate.c | | rsvp_packet.c | | struct rsvp_psb | | RSVP Packet Processor | | struct rsvp_rsb |<---------| | | struct psb_info |create/delete/update | | struct rsb_info | psb/rsb | | | PSB/RSB Event Call | | | | backs | | | +--------------------+ | struct rsvp_msg_hdr | | struct rsvp_packet | | create/decode packets | +---------------------+ | reads/writes packets | | |decode/encode obj | | rsvp_obj.c |<--------| to network | | struct rsvp_obj_hdr | +------------------------+ | All obj/sub defns. | | | Insert/Decode Object| | +---------------------+ | +------------------------+ | rsvp_network.c | | Handles read/write to | | socket. Provides | | abstractions of network| +------------------------+ RSVP Main Module ================= rsvpd.h /* The Central Holder of RSVP Stack. This is as per Zebra Framework */ struct rsvp_master { /* RSVP Instance */ struct list *rsvp; /* RSVP Thread Master */ struct thread_master *master..; /* RSVP Start Time */ time_t start_time; } /* Container for statistics data */ struct rsvp_statistics { u_int32_t path_msg_in; u_int32_t path_msg_out; u_int32_t resv_msg_in; u_int32_t resv_msg_out; u_int32_t path_err_in; u_int32_t path_err_out; u_int32_t resv_err_in; u_int32_t resv_err_out; u_int32_t path_tear_in; u_int32_t path_tear_out; u_int32_t resv_tear_in; u_int32_t resv_tear_out; u_int32_t hello_in; u_int32_t hello_out; u_int32_t resv_conf_in; u_int32_t resv_conf_out; }; /* The Central RSVP Object is as follows: struct rsvp { /* RSVP Router ID */ struct in_addr router_id; /* Configured automatically */ struct in_addr router_id_static; /* Configured Manually */ /*---------------------------------------------------------------- * Following params RSVP global Configs. CLI can modify these. *---------------------------------------------------------------*/ int_32_t cflags; #HELLO; #REFRESH_REDUSCTION #AGGREGATION int v_hello_interval; /* Interval for Hellos */ int v_refresh_interval;/* Interval for refresh*/ int v_reopt_interval; /* Interval for reoptimize an existing LSP*/ int v_retry_interval; /* Interval for retrying a failed lsp */ u_int32_t v_retry_max; /* Maxumum retry that can be done in bringing up the LSP */ /* Zebra Interface List */ struct list *iflist; /*------------------------------------------------------------ * The following four objects are maintained by rsvp_softstate *-----------------------------------------------------------*/ /* Pointer to the current PSB/RSBs maintained by this daemon */ void *psbObj; /* Hook for psbObj in rsvp_softstate */ void *rsbObj; /* Hook for rsbObj in rsvp_softstate */ /* Pointer to hash lists of PSB/RSB interface as key */ void *psb_hash_if_as_key; void *rsb_hash_if_as_key; /*----------------------------------------------------------------- * Holder for all tunnels data structure. Tunnel Interface that is * configured would be maintained at this data structure by rsvpd.c * module. These are organized in a AVL tree. *----------------------------------------------------------------*/ void* tunnel_if_Obj; /*----------------------------------------------------------------- * Following are maintained by mpls_lsp module *----------------------------------------------------------------*/ /* Global Object handle for all MPLS LSPs in the Daemon */ void *lspObj; /* Hash of lsps with ifindex as key */ void *lsp_hash_if_as_key; /*----------------------------------------------------------------- * I/O Facilities for the daemon *----------------------------------------------------------------*/ /* Socket handle for Reading/Writing packets with external world */ int sock; struct thread *t_read; struct thread *t_write; /* Interfaces queued for reading and writing */ struct list *rsvp_if_write_q; char *name; /* Hook for Label Manager */ struct rsvp_label_mgr *label_mgr; /* Hook for Routing Table */ struct rsvp_rtable *rtable; /* Statistics Data */ struct rsvp_statistics statistics; }; /* This Data Structure Holds all info on a configured ingress Tunnel Interfaces. As they are virtual interfaces so needs to be maintained separately then "struct interface". The CLI gets a consistemt view of tunnel as an interface. An interface is NOT a LSP. It's a traffic trunk (RFC 2702). A Tunnel can have one or more LSPs. It will point to the LSP Objects. At present we don't support load balancing of of the Tunnel over multiple LSPs. So only one LSP would be active */ Tunnel Interaces are organized in a AVL tree and hooked into rsvp->tunnel_if_obj. */ struct rsvp_tunnel_if { /* The Tunnel Type */ int type; /* Tunnel Status */ int status; struct in_addr dst_addr; /* List of RSVP LSPs for this Tunnel, only one active*/ struct list *rsvp_lsp_list; }; /* This Data Structure Holds all info on a egress tunnel */ RSVP_PROTO_VERSION 1 RSVP_MSG_MAX_LEN 65535 RSVP_IP_PROTO 46 /* As per RFC 2205 */ RSVP_TUNNEL_TYPE_INGRESS 1 RSVP_TUNNEL_TYPE_EGRESS 2 RSVP_TUNNEL_TYPE_TRANSIT 3 RSVP Peer Structure ======================== This defines a RSVP peer/neighbor, This is used to contain all info on a RSVP neigbors. Note that a neighbor is different then interface (struct rsvp_if). Multiple neighbors can be accessed through the same rsvp_if if the interface connects to a broadcast/multi-access network such as a bridge. in RSVP, a rsvp_peer or neighborship is not formed explicitly. A peer is added by rsvp_softstate module when 1)A rsvp_path_msg is received that causes to add a "new" rsvp_psb from peer (as phop) and that phop doesn't exist in object that contains all the peers. This could be achieved by searching the global object of rsvp_peers with phop as key. If not found then create a rsvp_peer and initialize parameters as received from the message and increment rsvp_peer->ref_cnt by 1.If found then update the peer info received from the message and rsvp_peer->ref_cnt by 1. 2)Add a rsvp_psb to peer (as nhop)and that nhop doesn't exist in object that contains all the peers. This could be achieved by searching the global object of rsvp_peers with nhop as key. If found then increment the rsvp_peer->ref_cnt by 1. NOTE : We wouldn't have to take rsvp_rsb as consideration for a peer creation because a rsvp_rsb is considered valid ONLY when a corresponding rsvp_psb is established. In that case the rsvp_psb might have already installed the rsvp_peer. So a rsvp_peer is referred when we have either we have rsvp_psb(s) installed from the peer or we have rsvp_psb(s) installed to the peer. But this is not a valid case always. There could be certain situations where a rsvp_psb might be deleted due to path tear or path err, but the rsvp_rsb is not deleted because either resv_tear or path_tear is got lost.In that case we need to take care of rsvp_rsb also that would still be referring to teh rsvp_peer. 3) Add a "new" rsvp_rsb from peer(phop). Search the peers with phop as key. If not found create a new rsvp_peer and initialize to all parameters received in the rsvp_resv_msg. If found son't create but increment the rsvp_peer->ref_cnt 4)Do the same as 3 for rsvp_rsb->nhop. A peer is deleted by rsvp_softstate module when we 1) delete a rsvp_psb from and that is the last rsvp_psb that refers to the peer as phop. To implement this search the global rsvp_psb object with key as phop. If the peer not found then assert(0) as its not a valid condition. If found decrement the rsvp_peer->ref_cnt by 1 and check if that makes rsvp_peer->ref_cnt = 0. If yes, then ' delete rsvp_peer completely. 2) Repeat the same for rsvp_psb->nhop. Search peer with nhop as key and delete the peer if this was the last reference. 3) Delete a rsvp_rsb. Check the peer matching the rsvp_rsb->nhop. If the peer not found then do assert(0) because peer must exist. Decrement the rsvp_peer->ref_cnt by 1 and check if that makes rsvp_peer->ref_cnt = 0. If yes then delete the rsvp_peer. 4) Do the same as 3) for rsvp_psb->nhop. So what information should we keep in a rsvp_peer ? /* Struct that defines a rsvp peer. All peers are organized in a AVL Tree. Peer search has to be done for each path/resv message and so the search has to be efficient. Note that rsvp_peer doesn't mean that its is RSVP capable.*/ struct rsvp_peer { /* This is the total number of PSB or RSBs that references this peer as either next hop or previous hop. I think 2^32 is sufficient number for accomodating the total psb/rsbs */ u_int32_t ref_cnt; /* Capability/config flags. */ u_int32_t cflags; #define RSVP_PEER_CFLAG_RSVP(1 << 0) /* RSVP Capable Node. */ #define RSVP_PEER_CFLAG_GR (1 << 1) /* Graceful Restart Capable.*/ #define RSVP_PEER_CFLAG_RR (1 << 2) /* Refresh Reduction (RFC 2961)*/ #define RSVP_PEER_CFLAG_RD (1 << 3) /* RSP Reliable Delivery. */ /* Address of the peer. This is NOT the loopback address of the rsvp capable neigbor router, rather a IP interface address. A peer is nothing but a neighbor hop.*/ in_addr addr; /* Bundle Trigger Timer. This timer shouldn't be user configurable, but hardcoded in implementation. When this timer triggers all messages in the bundle_trigger_msg_queue are flushed with single bundle message. The timer is active only when this rsvp_peer is set for Refresh Reduction (RR) */ struct thread *t_bundle_trigger_msg_timer; /* Bundle Refresh Timer: This timer too shouldn't be user configurable. This timer flushes the bundle_refresh_msg_queue*/ struct thread *t_bundle_refresh_msg_timer; /* Messages enqueued for bundling to this peer. So whenever we have Trigger messages to send to a peer which is RFC 2961 capable we enqueue packets in this queue. The timer fires within some n seconds and sends all packets from the queue in the bundle */ struct list *bundle_trigger_msg_queue; /* Refresh messages enqueued for bundling in this queue. This queue is flushed when t_bundle_refresh_msg_timer fires. */ struct list *bundle_refresh_msg_queue; } rsvpd.c ========= /* The RSVP Tunnel APIs */ The following handler triggers a RSVP Tunnel Creation. rsvp_interface_tunnel_cmd | v (Create a new Tunnel Data Structure and put it in AVL Tree with Key as Tunnel Number) struct rsvp_tunnel_if *rsvp_create_tunnel_if(int num) | v Set the flag as "INCOMPLETE_CONFIG". rsvp_tunnel_if_set_config_incomplete(struct rsvp_if *); | v by default the Tunnel Interface is admin up. rsvp_tunnel_if_admin_up (struct rsvp_tunnel_if *); NOTE: The mimimum parameter for making a config complete is at least one path element and tunnel destination is configured. When a Tunnel mode parameters is put from CLI, then fill the corresponding param. in struct rsvp_tunnel_if and check if config is complete to start the tunnel. | v rsvp_tunnel_if_set_config_complete (struct rsvp_if *); | v rsvp_tunnel_if_is_config_complete (struct rsvp_if *); | v Then start the tunnel - rsvp_tunnel_if_start (struct rsvp_tunnel_if *); The following event happens when a Tunnel is started. rsvp_tunnel_if_start procedures ========================= 1) Check the tunnel path options and create rsvp_lsps (rsvp_lsp_create) one by one for each path in the 6 element array. Initialize parameters on each LSP. from the configured parameters in the rsvp_ip_path and rsvp_if_tunnel. rsvp_lsp has visibility only upto path_option and not the rsvp_if_tunnel. So all relevant parameters in rsvp_lsp will be set up at the time of creation by this procedure. 2) This in turn calls on the corresponding rsvp_lsp. rsvp_lsp_start(struct rsvp_ldp *). This starts RSVP Signaling for the lsp. rsvp_lsp_start event procedure ============================== 3) Check if the destination in the rsvp_if_tunnel is reachable by IGP routing. If yes, proceed. Else, set the LSPs flag as down due to NO_ROUTE and start retry_timer of the LSP. 4) Check if CSPF is set on the LSP. If yes, calculate CSPF and get the best source route. 5) If the parent rsvp_path_option is dynamic then take the CSPF path and compute ERO and proceed. If path is strict the compare the map of explicit path. If matches then take the path map into ERO and proceed. If no CSPF and dynamic then follow best effort path. 6) Create and initialize a rsvp_lsp corresponding to the path option and hook the handle into the rsvp_tunnel_if_path_option. Hook the corresponding rsvp_tunnel_if_path_option into rsvp_lsp->ingress_user_handle. Hook the rsvp_lsp into the global handle of ingress LSPs. 7) Install the corresponding PSB in softstate module(rsvp_softstate_create_psb) and send path message through the corresponding interface to the corresponding neighbor and return.Go to exit. rsvp_lsp_ingress_up() event procedure =========================== 1) This is called by RSVP LSP module if a rsvp_lsp that is ingress in this router is UP. The argument is the rsvp_ip_path_option_handle (rsvp_lsp->rsvp_ip_path_option_handle). This in turn invokes rsvp_tunnel_if_path_option_event (LSP_UP, struct rsvp_tunnel_if_path_option). 2) This handler looks up if active_path_option = 0. If yes, it sets path_option_number as active_path_option. If active_path is already set then do nothing. rsvp_lsp_ingress_down() event procedure ======================================= 1) Check if the down LSP is active at present. If yes go to step 2 2) Search for alternate UP lsp for active. rsvp_tunnel_if_path_option_set_active (struct rsvp_tunnel_if *). If no active path_option found having lsp up, then it sets the Tunnel as down. APIs for rsvp_tunnel_if ======================= struct rsvp_tunnel_if *rsvp_tunnel_if_create (int num); void RSVP_TUNNEL_IF_SET_INCOMPLETE (struct rsvp_tunnel_if *); /* MACROS. */ void RSVP_TUNNEL_IF_SET_COMPLETE (struct rsvp_tunnel_if *); /* MACROS. */ int rsvp_tunnel_if_is_config_complete (struct rsvp_tunnel_if *); int rsvp_tunnel_if_start (struct rsvp_tunnel_if *); int rsvp_tunnel_if_stop (struct rsvp_tunnel_if *); int rsvp_tunnel_if_restart (struct rsvp_tunnel_if *); int rsvp_tunnel_if_switch_lsp (struct rsvp_tunnel_if *, int path_option); void rsvp_tunnel_if_admin_up (struct rsvp_tunnel_if *); void rsvp_tunnel_if_admin_down (struct rsvp_tunnel_if *); void rsvp_tunnel_if_set_dst (struct rsvp_tunnel_if *, struct prefix *); void rsvp_tunnel_if_unset_dst (struct rsvp_tunnel_if *); void rsvp_tunnel_if_set_path (struct rsvp_tunnel_if *, int pathnum, type); void rsvp_tunnel_if_unset_path (struct rsvp_tunnel_if *, int pathnum); Timers The refresh timer per rsvp_if is fired for each hello interval. /* This API starts hello timer on this RSVP Interface */ rsvp_if_hello_start (struct rsvp_if *) { RSVP_THREAD_ON (rsvp_if, rsvp_hello_timer_expired); } rsvp_if_hello_stop (struct rsvp_if *) { RSVP_THREAD_OFF (rsvp_if->hello_timer); } rsvp_if_hello_restart (struct rsvp_if *) { RSVP_THREAD_OFF (rsvp_if->hello_timer); RSVP_THREAD_ON (rsvp_if->hello_timer); } void rsvp_if_hello_timer_expired (struct thread *) { The thread argument is struct rsvp_if *. Actions: 1.Send out Hello over the rsvp_if Call rsvp_packet_send_hello (struct rsvp_if *). It allocates a stream and call 2. 2. This in turn calls rsvp_packet_add_to_if (struct stream *s, struct rsvp_if *). This API adds the stream to rsvp_if->o_buf. 3. Enable RSVP WRITE Thread. RSVP_WRITE_ON (rsvp_if->fd, rsvp_packet_write, rsvp_if->obuf); 4. The packet will be written into the file descriptor maintained for the rsvp_if. rsvp_packet_write(struct thread *); The thread arg is struct rsvp_if The thread value is fd (struct rsvp_if->fd); rsvp_packet_delete_from_if (struct rsvp_if *); } RSVP LSP MODULE ================ This is the upper level module taht provides the abstraction of a MPLS LSP to the user. The CLI module interacts with this module. There are two levels of abstraction provided by this module- rsvp_tunnel and rsvp_lsp. Note that struct rsvp_tunnel here is different then the rsvp_tunnel_if defined in rsvpd.c. The reason is that rsvp_tunnel_if is administratively created with configuration info at the ingress LSR only. rsvp_tunnel is an abstraction that identifies any tunnel as per RFC 2702. And a Tunnel may have one or more LSPs. so rsvp_lsp is child of rsvp_tunnel. So the abstractions are organized in the following levels. struct rsvp_tunnel_if (config infos) | struct rsvp_tunnel (Dynamically created from the config info). / \ / \ rsvp_lsp rsvp_lsp | | struct psb struct psb So, the common output "show mpls traffic-emg tunne" shows all rsvp_tunnels. The RSVP LSPs are described by struct rsvp_lsp and is common for all types of LSPs. An LSP type can be ingress LSP, Transit LSP or can be an Egress LSP. PSB/RSBs are tightly coupled with LSP data structure "indirectly" as an active PSB and its corresponding RSB makes a LSP active. "Indirectly" means LSP has no clue abou interval PSB/RSB structs, but exchanges info through struct rsvp_psb_info/rsvp_rsb_info with rsvp_softstate module through callbacks. This is an event based module. RSVP Softstate module will generate events per PSB/RSB basis and this module will extract info for create/update/delete LSPs from the struct rsvp_psb_info/rsvp_rsb_info.Then this module will interact with LSP FSM for each event and do handle necessary action. This module further interacts with zMPLS daemon for add/del/modify LSP and add/del tunnels. rsvp_lsp.h =========== RSVP_LSP_TYPE_INGRESS RSVP_LSP_TYPE_EGRESS RSVP_LSP_TYPE_TRANSIT A RSVP TE-LSP goes through the following states. RSVP_LSP_STATUS_DOWN /* LSP is down due to signaling failure (Ingress) */ RSVP_LSP_STATUS_DOWN_RETRY_EXPIRED /* LSP is down because retry count reached max (Only for ingress) RSVP_LSP_STATUS_UP /* LSP is up and active, both PSB/RSB installed*/ RSVP_LSP_STATUS_PSB_ACTIVE /* Only PSB Installed */ RSVP_LSP_STATUS_MBB /* Make Before Break is going ON */ RSVP_LSP_STATUS_CSPF /* CSPF Computatation is going on (Only ingress) */ typedef enum { RSVP_LSP_STATUS_DOWN, RSVP_LSP_STATUS_DOWN_STANDBY, RSVP_LSP_STATUS_UP, RSVP_LSP_STATUS_.. ... }rsvp_lsp_status_t; /* The RSVP LSP Descriptor */ struct rsvp_lsp { /* The LSP Type, INGRESS, TRANSIT or EGRESS */ int type; rsvp_lsp_status_t status; /* Info extracted from PSB/RSB */ int l3pid; union { struct in_addr lsp_ipv4_src_addr; struct in6_addr lsp_ipv6_src_addr; }u1; #define lsp_ipv4_src_addr u1.lsp_ipv4_src_addr #define lsp_ipv6_src_addr u1.lsp_ipv6_src_addr union { struct in_addr lsp_ipv4_dst_addr; struct in6_addr lsp_ipv6_dst_addr; }u2; #define lsp_ipv4_dst_addr u2.lsp_ipv4_dst_addr #define lsp_ipv6_dst_addr u2.lsp_ipv6_dst_addr u_int16_t tunnel_id; u_int16_t lsp_id; union { u_int32_t lsp_ipv4_ext_tunnel_id; u_int32_t lsp_ipv6_ext_tunnel_id; }u3; #define lsp_ipv4_ext_tunnel_id u3.lsp_ipv4_ext_tunnel_id #define lsp_ipv6_ext_tunnel_id u3.lsp_ipv6_ext_tunnel_id /* Timer threads for this LSP. Take the values from struct rsvp */ struct thread *t_retry_timer;/* Active when lsp id down except DOWN_STANDBY state */ struct thread *t_reopt_timer; u_int32_t retry_count; /* The Upstream Interface and Label for this LSP */ int ifindex_up; u_int32_t label_up; /* Downstream Interface and Label received*/ int ifindex_dn; u_int32_t label_dn; time_t uptime; /* Hooks to PSB/RSBs for this LSP */ void *psb_handle; void *rsb_handle; }; rsvp_lsp structure organization : The rsvp_lsp structure is organized as a groups to the same src_addr. Each group further sparses the rsvp_lsps based on Tunnel IDs. The organization is made globally. Apart from that lsps are organized in hash list with if_index as key. struct rsvp_lsp *rsvp_lsp_create (); int rsvp_lsp_start (struct rsvp_lsp *); int rsvp_lsp_stop (struct rsvp_lsp *); int rsvp_lsp_reoptimize (struct rsvp_lsp *); void rsvp_lsp_event_handle (struct rsvp_lsp *, int event); Following APIs needed and Pseudocodes are as follows: These are timer handlers. rsvp_psb_expired (struct thread *) { thread argument is struct rsvp_lsp for which the rsvp_psb is timed out. Actions 1.delete the psb 2. 2.Send reservation error for psb } rsvp_rsb_expired (struct thread *) { thread argument in struct rsvp_lsp for which the rsvp_rsb is timed out. 1. delete the rsb 2. } RSVP_LSP_FSM module ==================== rsvp_lsp_fsm.h LSP Events rsvp_lsp_fsm.c ============== struct { int (*func)(); int next_state; } RSVP_LSP_FSM [RSVP_LSP_STATUS_MAX -1][RSVP_LSP_EVENTS_MAX-1] = { } MPLS Tunnel Module ================== mpls_tunnel.h ==================================== #define MAX_LSP_PER_TUNNEL 6 #define TUNNEL_NAME_LEN 128 typedef enum { RSVP_TUNNEL_INGRESS = 1, RSVP_TUNNEL_TRANSIT = 2, RSVP_TUNNEL_EGRESS = 3 } rsvp_tunnel_type_t; struct rsvp_tunnel { char name [TUNNEL_NAME_LEN]; rsvp_tunnel_type_t type; u_int132_t if_num; /* Interface numbers are type specific.*/ struct in_addr dst; /* Destination of the Tunnel.*/ u_char status_admin; u_char status_oper; u_char up_lsps; struct rsvp_lsp rsvp_lsp [MAX_LSP_PER_TUNNEL]; }; RSVP Tunnel Organization : rsvp_tunnels are organized as ingress, egress and transit tunnels. For ingress tunnels the sender_addr is fixed. The keys that signify diff tunnels are dst_addr, the tunnel number (inherited from rsvp_tunnel_if *). For egress tunnels the dst_addr are fixed (The LSR Router address). The search keys are sender_addr. For transit tunnels the keys the first level is src_addr, /* Tunnel Level Abstractions */ struct rsvp_tunnel * rvsp_tunnel_create (); int rsvp_tunnel_delete (struct rsvp_tunnel *); int rsvp_tunnel_add_lsp (struct rsvp_tunnel *, struct rsvp_lsp *); int rsvp_tunnel_delete_lsp (struct rsvp_tunnel *, struct rsvp_ldp *); int rsvp_tunnel_start (struct rsvp_tunnel *); int rsvp_tunnel_stop (struct rsvp_tunnel *); int rsvp_tunnel_dump_vty (struct rsvp_tunnel *); RSVP Interfaces ================ rsvp_if.h /* RSVP Interface is private data structure hooked into struct interface->data. RSVP Sessions with neighbors are mainatined by RSVP Interfaces. The RSVP Interface(struct interface->rsvp_if)is enabled when a physical interface is enabled administratively for RSVP from CLI. Basic criteria for making at active is that it should be at an IP interface, If IP is not configured then although RSVP is enabled , still keep the rsvp_if as INACTIVE. This data structure needs to be created during rsvp_if_init which is called suring stack initialization. If at least one valid session is found then we set session_exist flag to 1.Then we need to maintain hellos on that interface for maitenance/refresh of PSB/RSB. */ /*--------------------------------- * Status of RSVP on a Interface *--------------------------------*/ enum { RSVP_IF_DOWN = 0, /* Down due to parent struct interface is down. */ RSVP_IF_DOWN_NO_IP = 1, /* Down due to no IP is configured */ RSVP_IF_UP = 2 /* UP and ready for running RSVP Sessions */ }rsvp_if_status; struct rsvp_if { int status; /* Back Pointers */ struct rsvp *rsvp; struct interface *if; /* The Packet Queue for writing */ struct rsvp_packet_fifo *obuf; /* The Hello Timer Thread */ struct thread *t_hello_timer; /* Number of sessions (or LSPs) */ int session_nums; /* RSVP Interface specific statistics */ struct rsvp_statistics statistics; ... } Interface Events ================ RSVP_IF_DOWN RSVP_IF_UP RSVP_IF_ADD RSVP_IF_DEL rsvp_if.c ========= /* Handles events from interface layer. */ rsvp_if_event_handle (int event); RSVP Packet Processing Module ============================== The RSVP Packet Processing Module provides all packet processing utilities required by the Daemon. This module uses the utility services provided by rsvp_obj module for analyzing/creating a packet and futher interacts with rsvp_softstate module for updating/creating/deleting psb/rsb. This module interacts with rsvp_network module for sending/receiving packets. rsvp_packet.h /* RSVP Path Message to be supported in Phase 1 */ +--------------------------------------------------+ | RSVP Message Common Header | +--------------------------------------------------+ | SESSION OBJECT | +--------------------------------------------------+ | RSVP HOP | +--------------------------------------------------+ | Time Values | +--------------------------------------------------+ | Label Request | +--------------------------------------------------+ | Sender Template | +--------------------------------------------------+ | Sender Tspec | +--------------------------------------------------+ /* RSVP Resv Message to be supported in Phase 1 */ +---------------------------------------------------+ | RSVP Message Common Header | +---------------------------------------------------+ | RSVP Session | +---------------------------------------------------+ | RSVP_HOP | +---------------------------------------------------+ | TIME_VALUES | +---------------------------------------------------+ | STYLE | +---------------------------------------------------+ | Flow Descriptor List | +---------------------------------------------------+ /*----------------------------------- * The Generic RSVP Packet Descriptor * used only for sending packets. This is the * format in which rsvp_packet module * interacts with rsvp_network module *----------------------------------*/ struct rsvp_packet { int flag; #define RSVP_PACKET_IPHDR ( 1 << 0) /* If valid IP Header is included in the stream*/ #define RSVP_PACKET_RA ( 1 << 1) /* If Router Alert is to be set for this packet. */ struct rsvp_packet *next; /* Path messages always carry at upper levels.*/ struct ip ip_hdr; /* Pointer to data stream */ struct stream *s; /* Next hop of the RSVP Packet. */ struct in_addr dst; /* RSVP Packet Length */ u_int16_t length; }; /*------------------------------------ * RSVP Packet Queue Structure used for * sending packets. *-----------------------------------*/ struct rsvp_packet_fifo { unsigned long count; struct rsvp_packet *head; struct rsvp_packet *tail; }; /* The Header template for a RSVP Message */ struct rsvp_msg_hdr { u_char vers 4; u_char flags 4; rsvp_msg_type_t type; u_int16_t checksum; u_char send_ttl; u_char reserved; u_char rsvp_length; }; RSVP_MSG_TYPE_PATH 1 RSVP_MSG_TYPE_RESV 2 RSVP_MSG_TYPE_PATHERR 3 RSVP_MSG_TYPE_RESV_ERR 4 RSVP_MSG_TYPE_PATHTEAR 5 RSVP_MSG_TYPE_RESVTEAR 6 RSVP_MSG_TYPE_RESVCONF 7 typedef enum { RSVP_MSG_TYPE_PATH, RSVP_MSG_TYPE_RESV RSVP_MSG_TYPE_PATHERR, RSVP_MSG_TYPE_RESV_ERR RSVP_MSG_TYPE_PATHTEAR, RSVP_MSG_TYPE_RESVTEAR, RSVP_MSG_TYPE_RESVCONF, RSVP_MSG_TYPE_HELLO, /* RFC 2961 Extensions. */ RSVP_MSG_TYPE_BUNDLE }rsvp_msg_type_t; rsvp_packet.c ============= The RSVP Packet module is again divided into 2 layers. Set of APIs deal with only RSVP specific messages. This layer communicates a packet with the lower layer through struct rsvp_packet that contains the complete RSVP message/bundle message (RFC 2961). One basic assumption is : A. Path messages when received are manipulated in rsvp parameters only. IP Header remains intact (it's end to end). So neither path_msg nor ip_hdr is destroyed.Path message must be sent with ip src hdr same as in SENDER_TEMPLATE and dst_addr must be the same as in SESSION. B. Resv messages when received are stripped of ip header and then manipulated in rsvp parameters. So rsv_msg can't be destroyed, but ip_hdr is and a new ip_hdr is put when sending out the resv_msg. So path/resv msgs are never destroyed in transit . Path msg is destoyed in egress and resv msg in ingress ONLY. 1) NOTE : We process only MPLS-RSVP Path Messages. In phase 1 we are supporting on mandatory params. rsvp_packet_path_receive (struct rsvp_msg_hdr *, struct rsvp_packet *, struct rsvp_if *) { 1. If INTEGRITY Object is present immediately after common header. If integrity fails then drop the message. 2. When SESSION Object is found, Check if ctype == LSP_IPV4/LSP_IPV6 else return Path Err. extract the session_info like session_info->tunnel_id session_info->destination. rsvp_obj_decode_session (struct stream *s, size); 3. Look for SENDER_TEMPLATE and extract the info Check if C-TYPE is LSP_IPV4/LSP_IPV6. If not return path_err rsvp_obj_decode_sender_template (struct stream *s, size); 4. Lookup the PSB in alreay installed in system (that will determine whether its a refresh or trigger message. The key to search a PSB are those ones that doesn't change throughout the session. struct rsvp_psb *rsvp_softstate_lookup_psb (tunnel_id, lsp_id, source_addr, dst_addr); 5. If the PSB is not found then create a new PSB. struct rsvp_psb rsvp_softstate_install_psb (..) Fill all necessary parameters. Record rsvp_psb->phop from that obtained from the message and check that rsvp_peer with that addr exist. If yes.. Record the rsvp_psb->ifindex_up. Install Label Request Object. Install timer as per TIME Values. start the rsvp_psb->cleanup_timer. start the rsvp_psb->refresh_timer. 6. If existing PSB then reset the rsvp_psb->t_cleanup_timer. 7. Update the PSB with changed parameters if any. 8. Check if the destination of IP packet is itself. If yes, that means this is the egress of the session and match the dst_addr in SESSION is same as IP header dst addr(section 3.1.3 in RFC 2205).If yes then install RSB and initiate resv_message to the source else returns path error. If destination is self. Else go to 9. 9. If NO ERO present then check with routing the outgoing interface(ifp) and nhop. rsvp_route_lookup_ipv4 (struct rsvp_rtable, in_addr dst); If ERO is present then lookup the route based on dst ar ERO next hop. 9. Set the PHOP in the existing path message to the address of the interface (ifp->connected). 10.Send the packet to the next_hop and addr. rsvp_packet->dst_addr = nhop. add the packet to the rsvp_if. rsvp_packet_add_to_if (rsvp_packet, rsvp_if); 11. Start the thread rsvp_write. } 2) rsvp_packet_resv_receive (struct rsvp_packet *, int ifindex) { 1) Check for the matching rsvp_psb. If not found drop and free the packet memory. Else go to step 2. 2) Check if the rsvp_rsb pointed by the matched rsvp_psb exists. If yes go to 3) else go to 4. 3) Check if all rsb parameters are same as that of in resv msg. Else update it and reset the rsvp_rsb cleanout timer. 4) Check that ifindex == rsvp_psb->next_hop. If yes, the install rsb and start cleanout time. Else drop the message and free the buffer. 5) Don't destroy, rather send the same resv_msg with a new IP header with this node as src_addr and rsvp_psb->phop as dst_addr. rsvp_resv_msg_snd (struct rsvp_packet *, int rsvp_psb->phop); } 3) The lower below deals with all communication with RAW/IP layer and provides a generic interface to all packets through struct rsvp_packet and interacts with rsvp_network layer. 1. /* Generic Utilities for Creating and destroying a RSVP Packet used for sending */ rsvp_packet_new (size_t size); rsvp_packet_free (struct rsvp_packet *); 2. The generic Send and Receive Hnadles on RSVP Interfaces are as follows. These thread handlers are the lowest level APIs that interact at socket level through the APIs provided by rsvp_network module. Let's see what are the assumptions in RFC 2205/RFC 3209 in send/receive of RSVP messages. 1) At ingress IP src/dst fields would be filled by RSVP for path msgs. At transit IP src/dst fileds would remain same At egress/transit the IP src/dst fields would be decided based on phops in psbs for resv msgs So, IP_HDINCL option needs to be set on the socket used for RSVP. 1) At ingress when NO_CSPF and NO_ERO is used then path message ie sent via best effort path by looking up outgoing interface/next hop in routing table.For that rsvp needs routes from zebra and refer to rsvp->rtable. So the API needs to take src_addr, dst_addr, the rsvp specific packet in stream, next hop and outgoing ifindex. At ingress if CSPF/ERO is used then there is no direct lookup in the routing table. ERO already sets the nexthop and the first hop is the outgoing interface address (and if can be found). Second hop is the next hop. So the API is needed to take src_addr, dst_addr, stream, next hop and outgoing if. At transit, after receiving a path msg we need to preserve the IP Header. /* This returns a stream with ip header included.*/ struct stream *rsvp_packet_recv (rsvp->fd, struct interface *); rsvp_packet_send (struct stream *s, struct in_addr *src_addr, struct in_addr *dst_addr, struct rsvp_peer *next_hop, int ifindex); 2.1 rsvp_packet_read (struct thread *); Reads a packet from the rsvp->fd. The starting point of receive processing. 2.2 rsvp_packet_write (struct thread *); The Final point of packet writing. This is a thread function with THREAD_ARG as struct rsvp*. 2.2.1 This procedure gets rsvp->fd for writing and rsvp->rsvp_if_write_q, the queue of rsvp_if(s) which are enqueued for writing. 2.2.2 We get the 1st rsvp_if(s) and get the first packet its stream_fifo. The packet will be 2.2.3 If further packets in stream_fifo exists or another rsvp_if exists in rsvp->rsvp_if_write_q then we make the LDP_WRITE_ON. 2. Generic Utilities for adding and deleting s stream to/from struct rsvp_if and inserting msg_hdr /* Decoder of rsvp message header. This API extracts the RSVP Message Header from stream->getp and fills up the struct rsvp_msg_hdr passed on y the caller */ void rsvp_packet_decode_msg_hdr (struct stream *s, struct rsvp_msg_hdr *msg_hdr); /* Creator of the Msg Header. The message header is created at the the location of putp*/ void rsvp_packet_encode_msg_hdr (struct stream *s, u_char ver, u_char flags, rsvp_msg_type_t msg_type, u_int16_t checksum, u_char send_ttl, u_char reserved, u_int16_t length); /* This API computes the checksum of the RSVP Message that starts at msg_startp and ends at stream->putp. The reason of msg_startp is that when RSVP Message bundling is used later then one stream MAY contain multiple messages. The checksum value will be computed ans inserted into the checksu field in the message header*/ void rsvp_packet_encode_msg_checksum (struct stream *s, int msg_startp); /* This API calculates the length of the message from startp and stream->putp and inserts into the length field in msg_hdr */ void rsvp_packet_encode_msg_length (struct stream *s, int msg_startp); /* In the first version, I am going to send only mandatory params in each message. *. void rsvp_packet_encode_path_msg (struct stream *, struct session_info *; struct rsvp_hop_info *, struct rsvp_timevalues_info *, struct sender_template_info *, struct sender_tspec_info *); /* Adds/Deletes a RSVP Packet to/from rsvp_if->obuf */ void rsvp_packet_add_to_if (struct stream *s, struct rsvp_if *); rsvp_packet_del_from_if (struct rsvp_if *); 3. The message specific handlers called by the handlers in 1 for specific messages. /* The Generic Message Sender * Inputs : s = stream to send * src_addr = Source Address of the Packet * dst_addr = Destination Address of the Packet * */ rsvp_packet_send_msg (struct stream *s, struct in_addr *src_addr, struct in_addr *dst_addr, struct interface *rsvp_if); rsvp_packet_receive_path_msg (struct stream *s, struct rsvp_if *rsvp_if); /* rsvp_packet_send_resv_msg (struct rsvp_packet *rsvp_packet, struct rsvp_if *rsvp_if, struct in_addr *hop) rsvp_packet_receive_resv_msg (struct stream *s, struct rsvp_if *rsvp_if); rsvp_packet_send_path_err (struct stream *s, struct rsvp_intf_mgr *intf_mgr); rsvp_packet_receive_path_err (struct stream *s, struct rsvp_intf_mgr *intf_mgr); rsvp_packet_send_path_tear (struct stream *s, struct rsvp_intf_mgr *intf_mgr); 4. RSVP Message Parser rsvp_packet_decode_msg_hdr (struct stream *s, struct rsvp_msg_hdr *hdr) 4. RSVP network Module ======================= This module provides all interaction necessary for RSVPD communication with the network. This module sends/receives rsvp packets to/from network. This module provides services to the rsvp_packet module. So all APIs (abstractions) provided by this module is aligned with services required from rsvp_packet module. int rsvp_sock_init (void) { } 5. RSVP Object Processing Module ============================== This module is library for processing the following objects and class types. LSP_TUNNEL_IPV4 LSP_TUNNEL_IPV6 LABEL_REQUEST LABEL EXPLICIT_ROUTE RECORD_ROUTE SESSION_ATTRIBUTE C-types : SESSION, SENDER_TEMPLATE and FILTER_SPEC rsvp_obj.h RSVP_OBJ_LEN_MAX 65528 RSVP_OBJ_LEN_MIN 4 RSVP_CLASS_NULL 0 RSVP_CLASS_SESSION 1 RSVP_CLASS_SESSION_CTYPE_IPV4_UDP 1 RSVP_CLASS_SESSION_CTYPE_IPV6_UDP 2 /* RFC 3209 RSVP-TE Extensions */ RSVP_CLASS_SESSION_CTYPE_LSP_TUNNEL_IPV4 7 RSVP_CLASS_SESSION_CTYPE_LSP_TUNNEL_IPV6 8 RSVP_CLASS_RSVP_HOP 3 RSVP_CLASS_RSVP_HOP_CTYPE_IPV4 1 RSVP_CLASS_RSVP_HOP_CTYPE_IPV6 2 RSVP_CLASS_INTEGRITY 4 RSVP_CLASS_TIME_VALUES 5 RSVP_CLASS_TIME_VALUES_CTYPE 1 RSVP_CLASS_ERROR_SPEC 6 RSVP_CLASS_ERROR_SPEC_CTYPE_IPV4 1 RSVP_CLASS_ERROR_SPEC_CTYPE_IPV6 2 RSVP_CLASS_SCOPE 7 RSVP_CLASS_IPV4_SCOPE 1 RSVP_CLASS_IPV6_SCOPE 2 RSVP_CLASS_STYLE 8 RSVP_CLASS_STYLE_CTYPE_IPv4 1 RSVP_CLASS_STYLE_CTYPE_IPv6 2 RSVP_CLASS_FLOW_SPEC 9 RSVP_CLASS_FLOW_SPEC_CTYPE_RESV 1 RSVP_CLASS_FLOW_SPEC_CTYPE_INV_SERV 2 RSVP_CLASS_FILTER_SPEC 10 RSVP_CLASS_FILTER_SPEC_CTYPE_IPV4 1 RSVP_CLASS_FILTER_SPEC_CTYPE_IPV6 2 RSVP_CLASS_FILTER_SPEC_CTYPE_FLOW_LABEL 3 /* RFC 3209 RSVP-TE Extensions */ RSVP_CLASS_FILTER_SPEC_CTYPE_LSP_TUNNEL_IPV4 7 RSVP_CLASS_FILTER_SPEC_CTYPE_LSP_TUNNEL_IPV6 8 RSVP_CLASS_SENDER_TEMPLATE 11 RSVP_CLASS_SENDER_TEMPLATE_IPV4 1 RSVP_CLASS_SENDER_TEMPLATE_IPV6 2 RSVP_CLASS_SENDER_TEMPLATE_IPV6_FLOW_LABEL 3 /* RFC 3209 RSVP-TE Extensions */ RSVP_CLASS_SENDER_TEMPLATE_LSP_TUNNEL_IPV4 7 RSVP_CLASS_SENDER_TEMPLATE_LSP_TUNNEL_IPV6 8 RSVP_CLASS_SENDER_TSPEC 12 RSVP_CLASS_SENDER_TSPEC_CTYPE_INTSERV 2 RSVP_CLASS_ADSPEC 13 RSVP_CLASS_ADSPEC_INTSERV 2 RSVP_CLASS_POLICY_DATA 14 RSVP_CLASS_POLICY_DATA_CTYPE_GENERIC 1 RSVP_CLASS_RESV_CONFIRM 15 RSVP_CLASS_RESV_CONFIRM_CTYPE_IPV4 1 RSVP_CLASS_RESV_CONFIRM_CTYPE_IPV6 2 /* RFC 3206 RSVP-TE Objects */ RSVP_CLASS_LABEL 16 RSVP_CLASS_LABEL_CTYPE_GENERIC 1 RSVP_CLASS_LRO 19 RSVP_CLASS_LRO_CTYPE_GENERIC 1 RSVP_CLASS_LRO_CTYPE_ATM 2 RSVP_CLASS_LRO_CTYPE_FR 3 RSVP_CLASS_ERO 20 RSVP_CLASS_ERO_CTYPE_GENERIC 1 RSVP_CLASS_ERO_CTYPE_GENERIC_SUBOBJ_IPV4 1 RSVP_CLASS_ERO_CTYPE_GENERIC_SUBOBJ_IPV6 2 RSVP_CLASS_ERO_CTYPE_GENERIC_SUBOBJ_AS 3 RSVP_CLASS_RRO 21 RSVP_CLASS_RRO_CTYPE_GENERIC 1 /* RFC 3209 RSVP-TE Extensions */ RSVP_CLASS_HELLO 22 RSVP_CLASS_HELLO_CTYPE_REQUEST 1 RSVP_CLASS_HELLO_CTYPE_ACK 2 RSVP_CLASS_SESSION_ATTRIBUTE 207 RSVP_CLASS_SESSION_ATTRIBUTE_CTYPE_LSP_TUNNEL_RA 1 RSVP_CLASS_SESSION_ATTRIBUTE_CTYPE_LSP_TUNNEL 7 typedef enum { RSVP_CLASS_NULL, RSVP_CLASS_SESSION, RSVP_CLASS_RSVP_HOP, RSVP_CLASS_INTEGRITY, RSVP_CLASS_TIME_VALUES, RSVP_CLASS_ERROR_SPEC, RSVP_CLASS_SCOPE, RSVP_CLASS_STYLE, ...... }rsvp_class_type_t; struct rsvp_obj_hdr { u_int16_t length; rsvp_class_type_t class; u_char c_type; } struct rsvp_obj_ero_sub_hdr { }; struct rsvp_obj_rro_sub_hdr { } rsvp_obj.c /*--------------------------------------------- * Decodes the object header in stream->putp * and fills up struct rsvp_obj_hdr *--------------------------------------------*/ void rsvp_obj_decode_obj_hdr (struct stream *s, struct rsvp_obj_hdr); void rsvp_obj_insert_obj_hdr (struct stream *s, u_int16_t length, u_char class_num, u_char c_type); /*------------------------------------------- * This API calculates and inserts the length * field of the object into obj_hdr. obj_startp * is pointer to the start of the object. *------------------------------------------*/ void rsvp_obj_insert_obj_length (struct stream *s, int obj_startp); /*-------------------------------------------- * Object Builders. These all intern calls * rsvp_obj_insert_obj_hdr *-------------------------------------------*/ void rsvp_obj_insert_label (struct stream *s, u_int32_t label); void rsvp_obj_insert_label_request (struct stream *s, int l3pid); void rsvp_obj_insert_atm_label_request (struct stream *s, int l3pid, int flag_merge_capable, u_int16_t min_vpi, u_int16_t min_vci, u_int16_t max_vpi, u_int16_t max_vci); void rsvp_obj_insert_fr_label_request (struct stream *s, u_int16_t l3pid, int dli_, min_dlci, max_dlci); 6. RSVP Softstate Module (rsvp_state.h/c) ========================================= This module will handle the PSB (Path State Blocks) and RSB(Reservation State Blocks) and will generate events for RSVP LSP module . The rsvp_lsp module sits one layer above the rsvp_state module. This module has no clue about rsvp_lsp data structures as this module sits below the rsvp_lsp module. The rsvp_state module provides interface for callbacks registration to notofy various events w.r.t the states. The rsvp_lsp module registers callbacks with this module and thsi module notifies the rsvp_lsp module through the callbacks registered with it. This module sits one layer above the rsvp_packet layer. The packet layer job is limited to decoding/encoding path and resv messages as per the protocol specification and interact with rsvp_network layer to send and receive packets. The common language between rsvp_pacekts and rsvp_state module are the various infos defines in rsvp_state. The rsvp_state module requests the rsvp_packet layer through the same infos. rsvp_state.h ================= /* The various info to be kept in PSB/RSB */ enum { SESSION_INFO_LSP_TUNNEL_IPV4 = 1, SESSION_INFO_LSP_TUNNEL_IPV6 = 2 } rsvp_session_info_type_t; struct rsvp_lsp_tunnel_ipv4_info { struct in_addr end_point_addr; u_int16_t tunnel_id; struct u_int32_t ext_tunnel_id; }; struct rsvp_lsp_tunnel_ipv6_info { struct in6_addr end_point_addr; u_int32_t tunnel_id; u_int32_t ext_tunnel_id[4]; }; struct rsvp_session_info { int type; union { struct rsvp_lsp_tunnel_ipv4_info ipv4_lsp_info; struct rsvp_lsp_tunnel_ipv6_info ipv6_lsp_info; }u; #define ipv4_lsp_info u.ipv4_lsp_info #define ipv6_lsp_info u.ipv6_lsp_info }; typedef enum { LRO_INFO_TYPE_GEN = 1, LRO_INFO_TYPE_FR = 2, LRO_INFO_TYPE_ATM = 3 } lro_info_type_t; struct rsvp_lro_info_atm { u_char m; u_int16_t min_vpi; u_int16_t min_vci; u_int16_t max_vpi; u_int16_t max_vci; }; struct rsvp_lro_info_fr { int dlci_min; int dlci_max; }; struct rsvp_lro_info { int valid; int l3pid; int type; union { struct rsvp_lro_info_atm info_atm; struct rsvp_lro_info_fr info_fr; }u; #define info_atm u.info_atm #define info_fr u.info_fr }; .... /* The PSB and RSB descriptor. The state values are only for MPLS LSP TE Tunnels. These PSB/RSBs are sufficient only for maintaining LSP Tunnels */ struct rsvp_psb { /* Upstream Interface. For ingress LSP this would be 0 */ int if_index_phop; struct in_addr in_addr_phop; /* Backpointer to the downstream Interface. For Egress LSP this is 0 */ int if_index_nhop; struct in_addr in_addr_nhop; /* Parameters at PSB required to maintain mpls lsps */ void integrity_info; struct rsvp_session_info session_info; void time_values_info; void ero_info; struct rsvp_lro_info lro_info; void session_attribute_info; void policy_data_info; /* Sender descriptors */ void sender_template_info; void sender_tspec_info; void adspec_info; void rro_info; /* Timer that is fired when this psb times out. When hello or refresh is received on this PSB then we need to reset this timer. This timer is active only if this PSB is installed in Transit LSR */ struct thread *t_psb_expire_timer; /* Timer when fired initiates a PSB refresh message. This timer is active only when this PSB is installed at ingress LSR */ struct thread *t_psb_refresh_timer; /* Pointer to its RSB */ struct rsvp_rsb *rsb; } struct rsvp_rsb { /* The PSB Pointer */ struct rsvp_psb *psb; /* Parameters at RSB required to maintain mpls lsps */ void integrity_info; void session_info; void rsvp_hop_info; void time_values_info; void resv_confirm_info; void scope_info; void policy_data_info; void style_info; void flow_desc_list_info; void filter_spec_list_info; u_int32_t label_info; void rro_info; /* Timer that is fired when this rsb times out. When hello or refresh is received on this RSB then we need to reset this timer. This timer is active only if this RSB is in Transit LSR */ struct thread *t_rsb_expire_timer; /* Timer is fired after every RSB refresh Interval. This timer is active only if this RSB is installed in egress LSR */ struct thread *t_rsb_refresh_timer; } PSB/RSB Data Structure Organization: The keys for searching a PSB/RSB is Tunnel ID+ LSP ID per source - a psb is installed with SENDER_TEMPLATE and SESSION objects). So first the PSBs are organized in groups for s source in_addr (32bit). Although ideally 2^32 sources are possible (keys), in practice assumed in a core transit LSR there could be MAX 1000 senders. So we will keep senders in hash of size 1000 (10 bits hash mask) to have almost a "perfect hashing". I use Bob Jenkins jhash which is the most efficient hash to generate 32 bit keys from any arbitrary length of keys. Each hashed list per hash bucket is an "ordered" list with sender_addr as key. A per source specific PSB group will always have PSBs with a Unique Tunnel ID as Tunnel ID is specific to a source. PSB Groups are organized in a AVL tree. Assuming there could be 10000 (~ 2^13) Tunnels per source, so worst case search in a AVL tree will take 13 node touches in AVL tree. Each node of AVL tree will have PSBs with same session but diff sender template (lsp-id).So each AVL node will have an "ordered" linked list with ldp_id as key. Assuming that during MBB we can have 2 LSP-Ids so most of time the linked list will have 2 PSBs. So assuming that there could be in a transit LSR there could be 1000 sources, and 10000 tunnels per source, the worst case search will take lookup in 16 nodes. I guess for my phase 1 this would be OK :-). The same applies to rsvp_rsbs. Here the keys vare taken from SESSION object and FILTER_SPEC. Data structures used for PSB/RSB: #define RSVP_SENDER_HASH_SIZE (1 << 10) struct rsvp_sender_hash_entry { struct in_addr sender_addr; struct avl_table *session_avl; }; struct list *rsvp_sender_hash[SENDER_KEY_HASH_SIZE]; The hash-list contains entry of type struct rsvp_sender_hash_entry. The list is an ordered tree with sender_addr as key. Each node in avl_tree contains a list of rsvp_psb/rsbs that share the same session but different sender template. Maintenance of Softstates/Timers: ================================= Now we have done away with some basic organization of PSB/RSBs. RSB/PSB Cleanup timers: ======================= To deal with scalability we maintain only one garbage collection timer for cleaning up rsvp_psbs/rsvp_rsbs that times out. The cleanup timer of every PSB/RSB is decided by timevalues that it receives from its PHOP. We make the timer fire eveny 5 seconds. (min cleanup time is 5 seconds). Evertime it fires, the handler parses each PSB/RSB and checks if it exceeds its timeout interval. If yes, then it deletes the PSB/RSB and sends the corresponding path/resv error messages. As the timer needs to parse every PSB/RSB so for simplicity we add each psb/rsb into a cleanup list. Only transit/egress PSBs are in the list as we don't need to claenup the ingress PSB/RSBs, Similiary only igress/transit LSRs RSBs needs cleanup. rsvp->psb_cleanup_list rsvp->rsvp_cleanup_list RSB/PSB Refresh Timers ====================== The refresh timers are configured per RSVP interface. So we keep one timer per interface that refreshes all PSB/RSBs on that interface. This periodic timer at the node scans the RSB/PSBs to create new path/resv messages towards the originator of that message. rsvp_if->refresh_timer. So we need to also maintain the refresh_list per interface. This lists contain psb/rsbs for which it is the nexthop interface. rsvp->if->psb_refresh_list. rsvp->if->rsb_refresh_list. Whenever the timer fires, it parses through the lists and generates refresh message for each psb/rsb in the list. Callbacks Stuff =============== rsvp_softstate.c ================ APIs provided. ============= 1. struct rsvp_sender_hash_entry *rsvp_sender_hash_entry_create (void) It creates a rsvp_sender_hash_entry and returns the pointer. 2. int rsvp_sender_hash_bucket (struct in_addr *sender_addr) It returns a hash bucket for the input key as sender_addr; 3. int rsvp_sender_hash_bucket_lookup_sender_key (struct in_addr *sender_addr, int hash, struct rsvp_sender_hash_entry *entry, u_char create_flag); 3.1 It parses the list in the hash bucket of input arg "hash" with sender_addr as key. If the entry is found then its pointer is filled into input arg "entry" and returns 1. If not found and create_flag is not set then return 0. 3.2 If entry not found and create_flag is set to one then create a new one with rsvp_sender_hash_entry_create (). Fill the addr key in the entry and initialize the session_avl. Fill the entry pointer in input arg "entry' and return 2. 4. struct list* rsvp_session_avl_lookup_tunid_key (struct avl_table*session_avl, u_int16_t *tunnel_id) This API looks up a Session AVL Tree with tunnel_id as key and returns pointer to the rsvp_rsb/rsvp_psb list in the avl_node that matches the key. If not found is returns NULL. 5. struct list* rsvp_session_avl_create_tunid_key (struct avl_table *session_avl, u_int16_t *tunnel_id) This API creates a avl_node with list of rsb/psbs as data and returns the list of rsvp_psb/rsvp_rsbs beraing the same session_id but diff lsp_id. 6. void rsvp_session_avl_delete_tunid_key (struct avl_table *session_avl, u_int16_t *tunnel_id); This API deletes all rsvp_psb/rsvp_rsbs that matches the same tunnel_id but may have diff lsp_id. 7. void * rsvp_state_list_lookup_lspid_key (struct list *lspid_list, u_int16_t lsp_id) Returns pointer to the struct rsvp_psb or struct rsvp_rsb that matches the lsp_id. 8. static struct rsvp_psb *rsvp_state_psb_create (void) Creates an object of type struct rsvp_psb in heap and returns it. 9. static void rsvp_state_psb_free (struct rsvp_psb *) Frees an object of type struct rsvp_psb from heap. 10. static struct rsvp_rsb *rsvp_state_rsb_create (void) Creates an object of type struct rsvp_rsb in heap and returns it. 11. static void rsvp_state_rsb_free (struct rsvp_rsb *) Frees an object of type struct rsvp_rsb from heap and returns it. 12. int rsvp_state_psb_lookup_create (struct in_addr *sender_addr, struct u_int16_t *tunnel_id, struct u_int16_t *lsp_id, struct in_addr *dst_addr, struct rsvp_psb *psb); This API looks up a PSB with the input keys, if found an existing rsvp_psb then it fills its pointer to input arg psb and returns 1. If not found then it creates one and fills its pointer to input arg psb and returns 0. If creation fails then return -1. This API is invoked in a Transit/Egress LSR for the LSP (or PSB) when a path message is received. This API is used in a ingress LSR when a new psb needs to be created. The API does the following: The arguments required are sender_addr, tunnel_id, dest_addr, lsp_id and struct rsvp_psb 12.1 Get the hash bucket for the sender_addr as key. hash = rsvp_sender_hash_key (struct in_addr *sender_addr) 12.2 Lookup the hash list with the sender_addr. int rsvp_sender_hash_bucket_lookup_sender_key (struct in_addr *sender_addr, int hash, struct rsvp_state_sender_hash_entry entry *); if returns 0 then return from this API. If 1 then proceed to 5.3. If returns 2 then proceed to 5.4. 12.3. Do avl_find with the key as tunnel_id. If found go to 5.6. If not found and create_flag is not set then return from the API with 0. If create_flag is set then proceed. 12.4 Insert an entry avl_node with avl_insert (tunnel_id) . 12.5 Create a psb. rsvp_state psb_create (). Fill with relevant parameters. add to the list in avl_node. 12.6 Returns the rsvp_psb. 13. void rsvp_state_psb_delete (struct rsvp_psb *); This unhooks it from the hash/avl_tree. Then is unhooked from the the rsvp_if->refresh_list. Here the rsvp_if is the outgoing interface for next hop. The free it from heap. This API is used when a 2.1. A Path Tear message is received 2.2 The rsvp->clean_up_timer finds the a psb is aged out. 2.3 A Path Err Message is received. 14. struct rsvp_rsb *rsvp_state_rsb_create (struct in_addr *sender_addr, u_int16_t *tunnel_id, u_int16_t *lsp_id, struct in_addr *dst_addr) This is used to create a new RSB when a Resv Message is received. When a Resv message is received first it looks up the matching PSB by using rsvp_state_psb_lookup with the relevant keys. If not found then it is created. This allocates a struct rsvp_rsb and hooks into sender hash/session avl_tree. Further if this is transit or egress node then add to rsvp_if->rsb_refresh_list where struct rsvp_if is the outgoing if for the rsbp_rsb. Also add to rsv->rsb_cleanup_list if this node is ingress or transit for the LSP. 15. void rsvp_state_rsb_delete (struct rsvp_rsb *) This API unhooks the rsvp_rsb from the sender hash/avl_tree and futher unhooks from the rsvp_if->rsb_refresh_list and rsvp->rsb_cleanup_list. Then it frees the object from heap. This API is called when Path Tear/ Resv Tear/Resv Err message is received. Further this is called when the rsvp->rsb_cleanup_timer finds that the struct rsvp_rsb is timed out. 16. struct rsvp_rsb *rsvp_state_rsb_lookup (struct in_addr *sender_addr, u_int32_t *tunnel_id, u_int32_t *lsp_id, struct in_addr *dst_addr) This API looks up the struct rsvp_rsb that matches the inpt keys. This API is called to lookup when a Resv Err/Resv Tear Message is received. 17. void rsvp_state_psb_refresh (struct rsvp_psb *); This is called when rsvp_if->refresh_timer expires and it parses through the rsvp_if->psb_refresh_list. 18. void rsvp_state_rsb_refresh (struct rsvp_rsb *); This is called when rsvp_if->refresh_timer expires and it parses through rsvp_if->rsb_refresh_list. 19. void rsvp_state_psb_cleanup (struct rsvp_psb *) This is called from rsvp->cleanup_timer handler if a struct rsvp_psb is timed out. The API does the following. rsvp_state_psb_cleanup (struct rsvp_psb *) | v rsvp_packet_path_tear_send (...) in rsvp_packet.c | v rsvp_state_psb_delete (struct rsvp_psb *) | v rsvp_state_rsb_delete (struct rsvp_rsb *) where rsvp_rsb = rsvp_psb->rsb. 20. void rsvp_state_rsb_cleanup (struct rsvp_rsb *) This is called when rsvp_cleanup_timer handler if a struct rsvp_rsb is timed out. The API does the following: rsvp_state_rsb_cleanup (struct rsvp_rsb *) | v rsvp_packet_resv_tear_send (..) in rsvp_packet.c | v rsvp_state_rsb_delete (struct rsvp_rsb *); Callbacks library for softstates static struct rsvp_softstate_callback_info rsvp_softstate_cb_info [RSVP_SOFTSTATE_EVENTS_MAX][RSVP_SOFTSTATE_CLIENTS_MAX] rsvp_softstate_register_callback (int event, int (*fn)(void)); rsvp_softstate_deregister_callback (int event, int (*fn)(void)); rsvp_softstate_notification_callback (int event, struct rsvp_softstate_cb_info*); Callbacks Events RSVP_SOFTSTATE_EVENT_PSB_ADD /* New PSB Added */ RSVP_SOFTSTATE_EVENT_PSB_DEL /* Existing RSB Deleted */ RSVP_SOFTSTATE_EVENT_PSB_UPD /* Existing PSB Updated */ RSVP_SOFTSTATE_EVENT_RSB_ADD /* New RSB Added */ RSVP_SOFTSTATE_EVENT_RSB_DEL /* Existing RSB Deleted */ RSVP_SOFTSTATE_EVENT_RSB_UPD /* Existing RSB Updated */ /* Interface Specfific Hash. Add the PSBs in a hash list per if_index. This is needed to handle interface specific events The hash key is if_index and data is struct rsvp_psb/rsvp_rsb The interface specific hash objects will be hooked to struct rsvp*/ RSVP Zebra Module ================= This module interacts with the zMPLS daemon. 1) Gets all interface specific info and traps all interface events. 2) Gets IP addresses on the interfaces and all add/del ip addr events 3) Gets Routing Info. rsvp_zebra.h rsvp_zebra.c RSVP Refresh Reduction Extensions RFC 2961 =========================================== This extension categorizes RSVP messages into two types: trigger and refresh messages.Trigger messages are those RSVP messages that advertise state or any other information not previously transmitted. New Message RSVP_MSG_BUNDLE Rules: 1) Sent with IP address of the sending router to the neigbor. 2) Shouldn't be sent with Router Alert Option as its destined to next neighbor. /* RFC 2961 says no max size limit as IP will fragment, but in this implementation we limit it to 1500 bytes to respect standard MTU */ #define RSVP_BUNDLE_MSG_MAX_LEN 1500 #define RSVP_BUNDLE_TRIGGER_MSG_INTERVAL #define RSVP_BUNDLE_REFRESH_MSG_INTERVAL Bundle Header RSVP Bundle Message Processing ============================== rsvp_msg_bundle_rcv (struct rsvp_if) | | v if (rsvp_if->cflags & RSVP_CFLAG_RR)----no-->discard |yes | v if (Send_TTL in bundle header == IP TTL in IP Header)-- | | |yes No | | v Do nothing Set(rsvp_peer(phop)->cflags & RSVP_PEER_CFLAGS) | | v if(bundle_hdr->version == 1) && (rsvp_msg_bundle_checksum_error()) | | yes NO | | | discard rsvp_msg_bundle_decap(..) Decapsulate bundle and process individual messages | | call handler based on each message type MSG_ID Extension ================ New objects MESSAGE_ID MESSAGE_ID_ACK MESSAGE_ID_NACK