# This is the design of LDPD Daemon for zMPLS 
# COPYRIGHT(C) Pranjal Kumar Dutta 
# 2002-2006

LDPD Functional Specification
==============================


                           +------------+  ldp add/del/update  +-------+ 
         LDPD CLI          | zMPLS      |--------------------->|Frd Eng|  
            |              +------------+                      +-------+ 
    +----------------+           ^ rt add/del/update from zebra
    | VTY Module     |           | if add/del/up/down from zebra
    +----------------+           |             
     execute_command             |             
           |                     V lsp add/del/update to zebra
    +-----------------+    +------------------+
    | Command Module  |    | ldp_zclient      |
    | (command.c)     |    |                  |
    +-----------------+    +------------------+
       |      |               |     |      |
+-----------+ |               |     |      |
|ldpd params| |               |     |      |
+-----------+ |        if add/del   |      |
              |             up/dn   |   rt add/del from zebra     
    +-----------------+       |     |      |
    | LDP Interface   |-------|     |      v 
    | (lo,eth0 etc)   |             |   +------------------+  
    +-----------------+             |   | LDP Route L3/FEC |
            |                       |   +------------------+
       enable/disable ldp           |      ^ invokes callbacks on rt events
            |                       |      |
            |            LSP add/del|      | Registers callbacks for rt events
            |            next hop change   |
            |                       |    +------------------+
            |                       +----| LDP Lib          |
            |                            +------------------+
            |                            /local fec add/del events generates
            |                           / label advertise/withdraw
            |                          /                                       
 add/start/del/stop hello_mgr         / remote bind add/del request to lib 
            |        +------------------+                     +----------+
            |        | ldp msg processor|\<---label req/ret-->| Label Mgr|
            |        +------------------+ \                   +----------+
            |        /            |        |
            |       /     generate events/ |  
            |      /      accepts events   |
            |     /            +-----+     |
            |    /             | FSM |     | ^
            |   /              +-----+\    | |
            |  /             changes state | peer specific msg to process
    +------------+                   +----------+  
    | Hello Mgr  |--add/del peers--->|  Peers   |   
    +------------+                   +----------+   
                |                         |            
        hello snd/rcv             ldp session messages snd/rcv
                |                         |

         
               +------------------------------+
               | ldp_packet.h/c               |
               |                              |
               |                              |
               +------------------------------+
               +------------------------------+
               |  ldp_network                 |
               +------------------------------+
                              |
                              |
               +------------------------------+
               | Socket Layer Communication   |
               |  poll/select                 |
               +------------------------------+
           udp_socket                  tcp_socket
                |                         |
     UDP hello Packets send/rcv       TCP Session Packets send/rcv

============================================================================

Pseudocode for LDP Daemon Initialization

             Starts as File  ldp_main.c
                                |
                                v
                              main()
                                |
                                v       
                       openzlog for ldpd
                                |
                                v
                         ldp_master_init()
                                |
                                v
                       Extract Command Line Arguments
                                |
                                v
                       Create the Master Thread;
                                |
                                v
                       Do General System Initializations
                      (srand_init, signal_init, cmd_init, vty_init,memory_init.)
                                |
                                v
                            ldp_init()
------------------------------------------------------------------------------
# This block is contains details within ldp_init()..
                                |
                 1. Initialize vty communication for external world. LDP can 
                    accept command directly through this facility.
                            ldp_vty_init()
                 2. Create ldp server socket. External world connects to this
                    ldp server socket for communication.
                            ldp_socket(NULL,lm->port)
                 3. Initialize IPC with ZebraD which is the MPLS controller/
                    arbiter. ZebraD maintains all the LSPs obtained from ldpd
                    and writed into ILM,NHLFE and FEC tables in forwarding
                    within the kernel via Netlink Sockets. 
                            ldp_zebra_init()   
                    ----------------------------------------------------------
                    # This block describes the ldp_zebra_init()..
                    1. Initialize the zclient for ldpd for ZebdaD
                    2. Register callbacks for interface_add/del with zclient
                    3. Register callbacks for interface Address Add/Del with 
                       zclient
                    4. Register lsp callbacks with zclient. zebra_ipv4_add(..)
                       zebra_ipv4_del(..).
                    5. Register Interface UP/DOWN callbacks with zclient.
                    6. Do interface related init ..if_init().
                    #end of ldp_zebra_init()
                    ----------------------------------------------------------  
                 4. Initialize the Debug Facility of ldpd. 
                            ldp_debug_init()
                 5. Initialize packet dump facilty of ldpd
                            ldp_dump_init()
                 6. Initialize the Label Manager. Late this to be moved to 
                    ZebraD so that both RSVP and LDP can share it.
                    ldp_label_mgr_init()
                 7. Initialize the LDP route Database. This database will
                    later contain routes received from zebra.
                    ldp_route_init().. Later will be moved to Zebra.
                 8. Initialize Label Information Base LIB for L2FECs, 
                    L3FECs(IP Routes)
                           ldp_lib_init().
                    LIB will contain L2/L3 FEC to Label Mapping. (received
                    from neigbours + egress FECs )
                 8. prefix_list_init(), prefix_list_add_hook,
                    prefix_list_delete_hook
                 9. ldp_snmp_init().
                 
                    # End of ldp_init() 
------------------------------------------------------------------------------
                                |
                                v
                            Sort the CLI Commands
                            (sort_node ())
                                |
                                v 
                           Parse Config File (ldpd.conf)
                                |
                                v
                          Turn into Daemon Mode
                                |
                                v
                          Create Process ID File(pid_output)
                                |
                                v
                          Make ldp vty socket
                                |
                                v
                          Print Banner that LDP started
                                |
                                v
                          Start the never ending FSM here :-)
                          and loop around fetching threads
    
The Functional Module Design
=============================

1.The Virtual Terminal Interface ldp_vty.h/c
   ===========================================
  This module exports the CLI facility for configuring the ldpd. We    
  follow the Industry standard CLI interface for configuring ldpd.
  (Cisco like).

  1.1 R1(config)# ip prefix-list <num> seq <num> permit <paddr/mask>
      - Configures a prefix-list to be used by ldpd

  1.2 R1(config)# route-map <name> <num> (deny|permit)
      - Configures a route-map to be used by ldpd

  1.3 R1(config-route-map)# match ip address prefix-list <plist_num>
    
  1.4 R1(config-route-map)# match ip next-hop prefix-list <plist_num>
 
  1.5  R1(config)# interface eth0
       R1(confog-if)# mpls ip
       - Enables LDP on this interface.

  1.6  R1(config)# mpls remote-ldp destination 2.2.2.2
       - Enables Targetted LDP session with 2.2.2.2
  
  1.7  R1(config)# mpls ldp neighbor 2.2.2.2 md5-passwword 0 p55717
       - Enables TCP MD5 Password protection with the neigbor.
  
  1.8  R1(config)# mpls ldp export-policy route-map xyz 
       - The filter for outgoing label requests.
       - Filter for outgoing label bindings.
 
  1.9  R1(config)# mpls ldp import-policy route-map xyx
       - Incoming label requests filter.
       - Filter for incoming label bindings.

  1.10  R1(config)# mpls ldp egress-policy route-map
       - Filters FECs to to be adverstised as egress

  1.11  R1(config)# mpls router-id lo


  Example:
 R1(config)# ip prefix-list 10 seq 1 permit 2.2.2.2/32
 R1(config)# route-map fec1 10 deny
 R1(config-route-map)# match ip address prefix-list 10
 R1(config-route-map)# match ip next-hop prefix-list 10
 R1(config-route-map)# exit
 R1(config)# mpls ldp import-policy route-map fec1



The LDP Main Module ldpd.h/c
=============================

This module is the central glueing entity of the LDP Stack.

ldpd implements:
 downstream unsolicited for IPV4/IPV6 Host/Prefix FECs, L2 FECs (PWEs).
 downstream on demand for CR-LSPs (Setup by CR-LDP).
 liberal retention mode.
 ordered control for IPV4/IPV6 Host/Prefix FECs.
 independent control for L2 FECs (PWEs).   

#define LDP_ADJ_TYPE_LINK	0
#define LDP_ADJ_TYPE_TARG	1

The central structure is :

struct ldp
{
   char      *name;                 /* Name of the LDP Instance*/
   u_int16_t ver    ;              /* Vserion of this LDP Implementation.*/
   struct ldp_id id;       /* ldp_id as per RFC 3036.*/   
 
   u_int16_t cflags;               /* Configuration Flags for optional params.*/
   #define LDP_CFLAG_HOPCOUNT		        (1 << 0)
   #define LDP_CFLAG_LOOPDETECT  		(1 << 1)
   #define LDP_CFLAG_TCP_AUTH		        (1 << 2)
   #define LDP_CFLAG_CONFIG_SEQNUM		(1 << 3)
   #define LDP_CFLAG_TRANSPORT_ADDR_LOOPBACK	(1 << 4)
   #define LDP_CFLAG_GRACEFUL_RESTART	        (1 << 5)   

   /* LDP Session Specific Parameters */
   u_char pvlim;		   /* Path Vector Limit for loop detection.*/

   /* LDP Graceful Restart Parameters */
   u_int16_t graceful_reconnect_time;
   u_int16_t graceful_recovery_time;
      
   /* Timer Values..when initialized fill with default values.
      Configuarble from CLI.*/
   u_int16_t hello_holdtime_link;
   u_int16_t hello_holdtime_targ;
   u_int16_t session_holdtime_link;
   u_int16_t session_holdtime_targ;

   /*Subsystem Hooks.*/
   
   /* Pointer to the global list of configured Interfaces. All IP interfaces
      including the loopback interface (s). The list of hello managers
      are organized within each interface. The link hello are attached per
      link. The targetted hello managers are attached to the loopback
      interface*/
    struct list *iflist;
    /* Hook for Address List.*/
    void *addr_obj;  
    /* LDP Label Manager. Later will be shifted to zebrad */
    void *label_mgr;

    /* Handle for the LDP Label Information Base. */
    void *lib_obj;

    /* The Sessons with the peers are controlled by struct peer which are 
       organized in the form of AVL Tree for faster search of existing peers
     */   
    void *peer_obj;
    u_int32_t msg_id;   /* Current Message ID.*/
         
    /* Sockets for TCP Server*/
    int srv_sock;     /* Used by ldp_hello for network comm.*/
    struct zlog *log;   /* Log for ldpd.*/
};

/* Holder for ldp's statistics information.*/
struct ldp_statistics
{
   u_int32_t hello_in;	
   u_int32_t hello_out;     
   u_int32_t init_in;
   u_int32_t init_out;	
   u_int32_t keepalive_in;
   u_int32_t keepalive_out;
   u_int32_t addr_in;	
   u_int32_t addr_out;	
   u_int32_t addr_withdraw_in;
   u_int32_t addr_withdraw_out; */
   u_int32_t labelmap_in;  	
   u_int32_t labelmap_out;
   u_int32_t labelwithdraw_in;
   u_int32_t labelwithdraw_out;
   u_int32_t notify_in;
   u_int32_t notify_out;
   u_int32_t labelreq_in;
   u_int32_t labelreq_out;
   u_int32_t label_abort_req_in;
   u_int32_t label_abort_req_out;
   u_int32_t label_rel_in; 
   u_int32_t label_rel_out;
};

The default parameters used by ldp

#define LDP_HELLO_HOLDTIME        15
#define LDP_SESSION_KEEPALIVETIME 30

hello interval = 5 seconds
keepalive interval = 10 seconds 

PUBLIC API
===========

void ldp_init (void)
Input  : None
Output : None
Synopsis : This method initializes the ldpd and all its submodules.
           This is called only once during ldpd initialization.
Callers  : main () in ldp_main.c


int
ldp_stats_print_vty (struct vty *vty,
                     struct ldp_statistics *stats)
Input : vty   = Pointer to the vty object.
      : stats = Pointer to ldp_statistics object.
Output: Returns 0.
Synopsis : This method prints the ldp packet stats into
           vty.




LDP Hello Manager Module ldp_hellomgr.h/c
==========================================
This module handles the LDP discovery protocol. It receives hello message events from ldp_packet module and sends hello messages to ldp_packet module.


/* This struct hold the adjacencies discovered by hellomgr.
   These are added to specific interface on which it was 
   received. The hello_adjs are organized in AVL tree with
   ldp_id as key. I don't anticipate more then 20 hello_adj
   though physical links, but for targetted session over
   loopback interface I may have 80-100 hello adjs. So 
   I have considered keeping them in AVL tree as addition/del
   of hello_adjs are rare compare to lookups. hello_adjs are 
   maintained internall by hellomgr and is not visible to any
   other module*/

struct hello_adj
{
   struct ldp_id     id;              /* Key for the hello adjacency.*/
   int               type;            /* Adjacency Type LDP_ADJ_LINK 
                                         or LDP_ADJ_TARG*/              
   struct interface  *ifp;            /* back_ptr to associated if.*/
   struct peer       *peer;           /* The peer associated with hello
                                        adjacency.*/
   struct sockunion  trans_addr;      /* Transport Addr if received.*/ 
   u_int32_t         config_seqnum;   /* Config Seq Num if received.*/
   u_int16_t         v_hello_holdtime;/* Hello Holdtime Value.*/ 
   struct thread     *t_hello_holdtimer;/* Hello Holdtimer thread.*/
};

struct hellomgr
{
   struct ldp 	    *ldp; /* Parent LDP Instance.*/ 
   struct in_addr     transport_addr;
   u_int32_t          config_seqnum;
  
   struct list        *iflist;/*List of interfaces enabled for hello.*/ 
   struct avl_table   *target_avl;/* AVL tree of targets configured */
   int                ttl;        /* TTL of the Hello Packets */
   time_t             uptime;     /* Last time Hello Mgr is up/down.*/
   time_t             readtime;   /* Last Time Hello Msg was read. */
   time_t             writetime;  /* Last time Hello Msg was sent. */

   struct zlog        *log;       /* Log */

   u_int32_t          v_hello_time;
   int                hello_sock; /* Socket for Hello.*/
   struct stream      *ibuf;      /* Input stream buffer.*/
   struct stream_fifo *obuf;      /* Output stream buffer.*/
                                 
   struct thread      *t_read;    /* Read/Write Threads.*/
   struct thread      *t_write;   /* Do */
   struct thread      *t_hello_timer; /*only one hello timer for all */ 
   u_int32_t          hello_in;   /* Hello Msg Statistics.*/
   u_int32_t          hello_out;  /* Do */
};

Abstractions
============

Private :
=========
struct hello_adj *
hello_adj_new(void)
Input : None
Output: Returns pointer to struct hello_adj.
Synopsis : This method allocates a hello_adj object

void
hello_adj_free (struct hello_adj *adj)
Input   : adj = Pointer to struct hello_ifadj.
Output  : None
Synopsis: Frees up the hello_adj object


int
hello_adj_add (struct ldp_id     *id,
               struct hello_info *info,
               struct interface  *iif)
Input : id   = Pointer to struct ldp_id.
      : info = Pointer to struct hello_info.
      : iif  = Pointer to struct interface.
Output: Returns 0 if success, else returns -1.
Synopsis : This API adds a new hello_ifadj object
           to the iif with parameters from hello_info
- Create a hello_ifadj object = hellomgr_ifadj_create().
- Initialize hello_ifadj with all relevant parameters from
  info. Start the hello_ifadj->t_hello_holdtimer.
- Add the hello_ifadj to the avl_table.
- Lookup if the peer corresponding to ldp_id exist.
  ldp_peer_lookup_by_id (struct ldp_id *)
- If found then hook the peer into hello_if_adj->peer.
  Add the hello_ifadj to the peer.
  ldp_peer_add_ifadj (struct peer        *peer,
                      struct hello_ifadj *adj)
  and return.
- If not found create a peer.
  ldp_peer_add (struct hello_ifadj *).
  Hook the peer to hello_ifadj->peer = peer. 

struct hello_ifadj *
hello_ifadj_lookup (struct ldp_id    *id,
                    struct interface *iif)
Input : id  = Pointer to struct ldp_id
      : iif = Pointer to struct interface.
Output: This method returns if the iif has hello_ifadj
        with the input keys. 

void
hello_ifadj_del (struct hello_ifadj *ifadj)
Input: ifadj = Pointer to struct hello_ifadj
Output: None
Synopsis : This method deletes the hello_adj from its interface. 

hellomgr_ifadj_holdtimer_expired


struct hellomgr *
hellomgr_new (void)
Input  : None
Output : Returns pointer to struct hellomgr.
Synopsis : This internal methid allocates an object of type struct hellomgr.

void
hellomgr_free (struct hellomgr *)
Input : Pointer to object of type struct hellomgr
Output: None
Synopsis : This method frees up an object of type struct hellomgr.


Public :
=========

void ldp_hellomgr_init  only


void ldp_hellomgr_rcv_hello (struct hello_info *info
                            struct ldp_id     *id,
                            struct interface  *iif)
Input : info   = hello msg info
        ldp_id = ldp_id from the Hello Message PDU.
        iif    = Interface through which hello was received 
Output: None
This API follows "Hello Message Procedures" as defined in section 3.5.2.1 in RFC 3036.

- Calls hello_check_errors (struct hello_info *). If no error proceed   
  else return.
- Check if hello_ifadj exist with id and iif.
  hello_ifadj_lookup (struct ldp_id    *id,
                     struct interface *iif).
- If found, check if any parameters like transport_addr, config_seqnum 
  etc is changed from the already stored info. 
  If yes update those info in hello_adj. 
  Check if the adjacency is being used by peer.
  hello_adj == hello_adj->peer->adj_in_use. 
  If yes, update those changed info in hello_adj->peer.
  ldp_peer_ifadj_update(struct peer *,
                        struct hello_adj *adj).
  Restart the hello_ifadj_restart_holdtimer (struct hello_adj *)
  and return.

- If the peer is not using the hello_adj then simply update the info   
  in hello_adj, restart the hello_adj->hello_timer and return.
  If no parameter got changed then simply restart the.
  
- If hello_adj not found the  add a new hello_adj.
  hellomgr_add_ifadj  (struct hello_info *info,
                       struct interface  *iif)


  Check if it has peer already for the ldp_id. 
  ldp_peer_lookup_by_id (struct ldp_id *). 
- If yes then check if the peer has adjacency with the interface.    
  ldp_peer_adj_exist (struct hello_ifadj *). If yes go to next step
  else add adjacency.
  ldp_peer_add_ifadj (struct peer      *peer,
                      struct interface *ifp). 
                                
- Start the hello holdtimer .
  hello_ifadj_restart_holdtimer (struct hello_ifadj *),
   and return;                        

  void ldp_hellomgr_add_if   (struct interface *if);
  Input : if = Pointer to struct interface.
  Output: None
  Synopsis : This method enables link level LDP to/fro interface.
  - Add the interface to hellomgr->iflist.
  - Initialize the hello_adj avl_table and hook into in ifp->info.
  - Join the interface to all routers Mcast address "224.0.0.1" for 
    accepting ldp hellos.
  

  void ldp_hellomgr_del_if   (struct interface *if);
  - Disconnect the interface from the Mcast address "224.0.0.1".
  - Parse all the hello_adj and delete them from corresponding peer.
    If peer->hello_adj_list count = 0, then tear the peer session
    and delete the peer. 
  - Delete the interface from hellmgr->iflist.

  int ldp_hellomgr_has_if (struct interface *ifp)
  Input : ifp = Pointer to struct interface.
  Output: Returns 1 if hellomgr has the interface, else
          returns 0.
  Synopsis : This method checks with hellomgr if an interface
             is enabled for LDP (by command "mpls ip").
  - Parse hellomgr->iflist. Ifindex matches return 1, else
    returns 0.

void
ldp_hellomgr_sock_err (void)
Input :  None
Output:  None
Synopsis: This method traps a hellomgr->hello_sock error.
- Closes the socket, ldp_network_tcp_udp_close (hellomgr->sock).
- Starts a new socket. ldp_network_udp_open (void) and get the
  handle into hellomgr->hello_sock.
- Return.

int
ldp_hellomgr_has_targ (struct in_addr *addr)
Input : This method checks if the ldpd has remote
        peers with the input addr.
Output :If the target is found then return 1 , else
        returns 0.
Synopsis : This method looks up  the target is configured
           in hello_mgr

void
ldp_hellomgr_add_targ (struct in_addr *addr)
Input : addr = Address of a remote peer.
Output: None
Synopsis : This method adds a new target to hellomgr.
- Checks if the targ exist ldp_hello_mgr_lookup_targ
- If yes return, if not proceed.
- Adds a new targ to hellomgr->targ_avl.
- Return

void
ldp_hellomgr_del_targ (struct in_addr *addr)
 

7. ldp_hellomgr_start ();
   This API Starts hello mgr
-  hellomgr_bcast_hello ();
-  start ldp->hellomgr->t_hello_timer.

Private :

8. hellomgr_snd_hello_if   (struct interface *if);

9. hellomgr_snd_hello_targ (struct in_addr   *targ_addr);

10. hello_mgr_bcast_hello ();
- This API broadcasts hello to all ldp enabled interfaces and remote targets..
- For each interface in ldp_hellomgr->iflist
  {
     ldp_hellomgr_snd_if_hello (struct interface *);
  }
- For each targ in ldp_hellomgr->targ_val
  {
     ldp_hellomgr_snd_targ_hello (struct in_addr *);
  }
- Start ldp_hellomgr->t_hello_timer.


11.void hello_timer_expired ();

This API is the thread function that fires every hello_mgr->hello_int. It sends
hello messages for all enabled links and remote targets.
- hellomgr_bcast_hello ();
- Restart ldp->hellomgr->t_hello_timer.


12.int hello_info_check_errors (struct hello_info *);
This method checks if hello is acceptable. Returns 1 if yes, else returns 0.


LDP Peer Module ldp_peer.h/c
=============================
This module is the repository of all peers discovered
by ldp_hellomgr. It hides all the inner details on how
peers are stored and all peer related processing.

/* ATM session parameters if peer is ATM LSR */
struct peer_atm_params
{
   u_int16_t              flags;
#define MERGE_NOT_SUPPORTED		(1 << 0)
#define VP_MERGE_SUPPORTED		(1 << 1)
#define VC_MERGE_SUPPORTED		(1 << 2)
#define VC_VP_MERGE_SUPPORTED		(1 << 3)
#define VC_BIDIRECTIONAL		(1 << 4)
   u_char                 num;
   struct atm_label_range *atm_range;
};

/* FR session parameters if peer is FR LSR.*/
struct peer_fr_params
{
   u_int16_t              flags;
#define MERGE_NOT_SUPPORTED	(1 << 0)
#define MERGE_SUPPORTED		(1 << 1)
   u_char                 num;
   struct fr_label_range  *fr_range;
};

It defines the data structure to identify a peer.

struct peer
{
   char *name;	         /* Description of the peer */
   struct ldp       *ldp;  /* Backpointer to ldp instance.*/
   u_char		  type;  /* Type of session*/
#define LDP_PEER_TYPE_LINK    		0
#define LDP_PEER_TYPE_TARG			1

   struct ldp_id    ldp_id;   /* ldp_id of the peer.*/
   struct list      *adj_list;/* List of interfaces through 
                                     which the peer adj is discovered*/ 
   struct hello_ifadj *ifadj; /* hello_ifadj to peer in use from the
                                 above  list ..for su_local*/
   struct sockunion su_local; /* Local addr to be used in session */
   struct sockunion su_remote;/* Remote Addr to be used in sess peer.*/
    

   int              status;   /*Status of connection to the peer
#define LDP_FSM_STATE_IDLE			0
#define LDP_FSM_STATE_CONNECT_ACTIVE	1
#define LDP_FSM_STATE_CONNECT_PASSIVE	2
#define LDP_FSM_STATE_INITIALIZED		3
#define LDP_FSM_STATE_OPEN_SENT		4
#define LDP_FSM_STATE_OPEN_RECEIVED		5
#define LDP_FSM_STATE_OPERATIONAL		6

   u_int32_t        cflags;   /* Optional config parameters.*/
#define PEER_CFLAG_PASSWORD			(1 << 0)
#define PEER_CFLAG_CONFIGSEQNUM		(1 << 1)
#define PEER_CFLAG_GRACEFUL_RESTART		(1 << 3) 
#define PEER_CFLAG_CONNECT_MODE_PASSIVE 	(1 << 4)
#define PEER_CFLAG_CONNECT_MODE_ACTIVE	(1 << 5)
#define PEER_CFLAG_SHUTDOWN			(1 << 6)
#define PEER_CFLAG_DISTMODE_DOD		(1 << 7)
#define PEER_CFLAG_LOOP_DETECTION		(1 << 8)
#define PEER_CFLAG_ATM_SESSION		(1 << 9)
#define PEER_CFLAG_FR_SESSION		      (1 << 10)
    
   char          *password;    /* Password for TCP signature */
   u_int32_t     config_seqnum;/* Config seqnum if present in hellos.*/ 
   u_char        pvlim;        /* Path vector limit from peer.*/
   u_int16_t     max_pdu_len;  /* Max PDU Accepted by this peer.*/ 
   int           ttl;	       /* TTL of TCP Connection to peer */

   union 
   {
      struct peer_atm_params	atm_params;
      struct peer_fr_params   fr_params;
   } opt_params; 	    /* ATM/FR Session Related Optional Parameters */

#define peer_atm_params_t opt_params.atm_params;
#define peer_fr_params_t  opt_params.fr_params;

   struct avl_table   *addrlist_avl; /* Addr List from peer.*/
   struct lib         *lib_snd;      /* label-map sent to peer.*/
   struct lib         *lib_rcv;      /* label-map received from peer.*/  
   struct list        *label_req_list;/* Label request sent to this
                                          peer and pending reply */
   int                session_sock;  /* Sockethandle used in session.*/          
   struct stream      *ibuf;         /* Packet receive buffer.*/
   struct stream_fifo *obuf;         /* Packet send buffer list.*/

   
   time_t             uptime;		 /* Last session Up/Down time */
   time_t             readtime;      /* Last session read time */
   time_t             resettime;		/* Last session reset time */
         
   /* Timer values maintained for Peer */
   u_int32_t v_hello_holdtime;
   u_int32_t v_session_holdtime;
   u_int32_t v_start_timer;
   u_int32_t v_connect_timer;
   
   /* Threads. */
   struct thread *t_read;
   struct thread *t_write;
   struct thread *t_hello_holdtimer;
   struct thread *t_start;
   struct thread *t_connect;
   struct thread *t_keepalive_timer;
   struct thread *t_session_holdtimer;
   struct thread *t_graceful_restart;
   struct thread *t_graceful_stale;
   
   /* Statistics Field. */
   struct ldp_statistics stats;    	
};

Peer organization
=================
The size of the deployments ranges from less than 20 Label Switching Routers (LSRs) to over 1000 LSRs. Eight out of the 11 deployments use LDP in the edge and the core, two on the edge only and one in the core only. Sessions exist to peers discovered via both the basic and the extended discovery mechanisms. In half the cases, more than one adja- cency (and as many as four adjacencies) are maintained per session. The average number of LDP sessions on an LSR ranges from under 10 to just over 80. The responses are spread as follows: under 10: 4 responses, 20-50: 4 responses, over 80: 1 response. 
The above section is from draft "Experience with the LDP Protocol".

I would consider maximum 128 peers in worst case that I would need to 
handle.In that if I use a hash table with the ldpid as key through Bob Jenkin's hash, I might get perfect hasing with O(1) lookup time. If I use AVL tree I might do worst case lookup in O(log 2^7) = 7 lookups.
Peer addition/deletion is rare process than peer lookup in LDP. So rebalancing AVL tree won't be much of an issue.
I think I would keep the peers in avl tree , because for hash everytime
I lookup, I need to compute the hash key which is apart from O(1) time.
Another reason for not using hash table is the key len (ldpid) is 48
bits which may be distributed in any fashion. So we may or may not
have hash collisions due to its unpredictable pattern. 


Private APIs
============
struct peer * peer_create (void)
Input : None
Output: returns a newly created peer object.
Synopsis : This method creates a peer object.
Callers  : ldp_peer_add

void peer_free (struct peer *peer)
Input : Pointer to struct peer.
Output: None
Synopsis : This method frees a peer object.
Callers  : ldp_peer_delete

Public API:
===========
void
ldp_peer_ifadj_add (struct peer *peer,
                    struct hello_ifadj *ifadj)
Input : peer  = pointer to struct peer
      : ifadj = pointer to struct hello_ifadj
Output: None
Synopsis : This method adds the new hello_adj
           to the peer.

void
ldp_peer_ifadj_delete (struct peer *peer,
                       struct hello_ifadj *ifadj)
Input : peer = Pointer to struct peer.
      : ifadj = pointer to struct hello_ifadj.
Output: None
Synopsis : This method deletes an existing
           hello_adj to the peer.

void
ldp_peer_ifadj_switch (struct peer *peer,
                       struct hello_ifadj *ifadj)
Input : peer = Pointer to struct peer.
      : ifadj= Pointer to struct hello_ifadj.
Output: None.
Synopsis : This method switches its hello_adj to
           the one given in input.
- Check if peer->ifadj_inuse == ifadj. If yes 
  do nothing and return. Else go to next step. 
- Make sanity check if peer->ifadj_list has this
  adjacency. If no then do nothing and return. Else
  proceed.
- Set peer->if_adj_inuse = ifadj.
- Check if any session params are different than 
  the earlier ones. If not do nothing and return.
  Else update the session params and proceed.
- Restart the ldp_session.
  ldp_session_restart (peer)
- Return.



void
ldp_peer_ifadj_update (struct peer *peer,
                       struct hello_ifadj *ifadj)
Input : peer  = Pointer to struct peer.
      : ifadj = Pointer to struct hello_ifadj.
Output: None
Synopsis: This method notifies an event when
          one of its ifadj is updated by hellomgr.
- Check if the ifadj is currently in use. If not
  return. Else proceed.
- Restart the session.
  if (LDP_PEER_STATE = LDP_FSM_SATE_OPERATIONAL)
     ldp_fsm_restart (struct peer *);

 


struct peer *ldp_peer_add (struct hello_ifadj *ifadj)
Input : ifadj = pointer to struct hello_ifadj
Output: returns the peer added.
Synopsis : This method adds a peer discovered by the 
            ifadj.
- peer_create (void)
- initialiaze the peer parameters such as 
  su_local, su_remote etc after referring to
  ifadj->trans_adr/config_seqnum etc.
- Add the hello_ifadj to the peer.
  ldp_peer_add_ifadj (struct peer        *peer,
                      struct hello_ifadj *ifadj);
- Start the peer
  ldp_session_start (struct peer *peer).  

 
struct peer *
ldp_peer_lookup_by_addr (struct in_addr *addr)
Input: addr = IPV4_address for the peer
Output: Returns the peer if found, else NULL
Synopsis : This method looks up the peer by its
           addr (32-bit id).
 
struct peer *
ldp_peer_lookup_by_id (struct ldp_id *id)
Input    : id = ldpid of the peer.
Output   : Returns the peer if found, else NULL
Synopsis : This method looks up the peer by its
           ldpid.

void
ldp_peer_print_vty (struct vty *vty, 
                    struct peer *peer)
Input : vty = Pointer to struct vty.
      : peer = Pointer to struct peer.
Output: None
Synopsis : This method prints info of the peer specified in input
           into vty.

void 
ldp_peer_print_vty_all (struct vty *vty)
Input : vty = Pointer to vty object where to print
Output: None
Synopsis : This method prints info of all peers
           into vty.



/*--------------------------------------------------
 * MACROs for this module.
 *-------------------------------------------------*/
#define LDP_PEER_STATE   (peer->state)
                   

******************************************************************************
ldp_zmpls.h/c module
====================
This module provides abstractions for all communication with zmpls daemon.
ldpd interacts with zmpls for getting routing updates, interface updates,
interface address updates as well as provides lsp updates.                  

public APIs:

void    ldp_zmpls_init (void)
Input : None
Output: None
Synopsis : Initializes zclient interface with zmpls daemon. 





******************************************************************************


  
2.LDP Network Module ldp_network.h/c
===================================
This module provides all the network services required by the ldpd
with platform independent APIs. For porting to other platforms would
require to adapt the magics done by these APIs as per the platform.

The abstractions/APIs are as follows:

2.1 int ldp_network_udp_open (unsigned short port)
    Input : Port Number on which to open the udp facility.
    Output: Returns the socket handle.
    Synopsis : This method opens facilty for HELLO message 
               communication to/from external world and 
               returns the socket handle.
    - Opens a UDP socket.
    - Bind the socket to port 646. Don't bind to any address
      because it it to be used for both link hellos (mcast)
      as well as targetted hellos (ucast).
    - Return the socket handle.

2.2 Add two versions of the following API- one for IPV4 and other for 
    IPV6.

    int ldp_network_tcp_srv_open (unsigned int port)
    Input : port = The port on which to bind the server.
    Output: returns the socket handle.
    Synopsis : This opens the TCP Server Socket at port 646
               (one only in the ldpd) for accepting incoming  
                tcp session requests to ldpd.
    - Open a TCP Socket.
    - Bind the socket to port. Don't bind to any address as this 
      same socket is to be used for targetted sessions as well as link 
      level sessions. 
    - Listens to 3 incoming connections in non-blocking I/O mode. 
    - Add the thread to accept incoming connections.
      thread_add_read (lm->master, ldp_srv_read, ldp, sock_handle);
    - Returns the socket handle that was opened.  

2.3 int ldp_network_tcp_cli_open (int              *sock,
                                  char             *ifname,
                                  struct sockunion *su_remote,
                                  unsigned short   port_remote)

         Input : sock  = Pointer to TCP Client handle to be returned.
                 ifname = Name of the interface where to bind the Client to.
                 su_remote = IPV4/IPV6 address the remote point.
                 port_remote = Port where to connect the client to.
 
         Output: Returns the socket handle for the TCP Client. 
         Synopsis : Opens a handle for tcp communication between local
                    addr as client and remote addr as TCP server.

         -Binds the tcp socket with the local_address/any port.
         -Connects the socket to sock_addr->addr = remote_addr
          and sock_addr->port = remote_port in non-blocking mode.
         -Returns the sock_handle (the caller hooks it into 
                           peer->session_sock).

2.4 void ldp_network_tcp_udp_close (int sock_handle)
    Input : sock_handle
    Output: None
    Synopsis : This API closes the TCP or UDP socket connected to
               the input sock_handle.    
    
2.5 int ldp_network_if_add_to_allrouters_mgrp (int           sock_handle,
                                          struct prefix *p,
                                          unsigned int  ifindex)
    Input : sock_handle = Socket Handle.
          : p		= Pointer to struct prefix.
          : ifindex	= Interface Index.
    Output: Returns 0 if successful, else retuns -1.
    Synopsis : This method makes a interface listen to all routers mcast 
               address "224.0.0.1". This is used by Hello Manager to listen
               to link Hellos from peers.

2.6 int ldp_network_if_leave_allrouters_mgrp (int           sock_handle,
                                              struct prefix *p,
                                              unsigned in   ifindex)
   NOTE : Just Opposite to aboveruct  


LDP Packet Module (ldp_packet.h/c)
==================================
This module handles all packet send/receive to/from ldp_network
module.

It interacts checks the sanity of HELLO messages received and interacts with ldp_hellomgr module for all hello message events

It interacts with ldp_peer module for all peer lookups.

It interacts checks sanity of LDP Session messages and interects with ldp_session module for all peer specific session message events

It interacts with ldpd for all global related info.


/* Following are internal formats of all message infos.*/
struct hello_info
{
};

struct init_info
{
};

struct keepalive_info
{
};

struct addr_info
{
};

struct addr_withdraw_info
{
};

struct label_map_info
{
};

struct label_req_info
{
};

struct label_abort_req_info
{
};

struct label_withdraw_info
{
};

struct label_rel_info
{
};

struct notify_info
{
};

/* Prototypes for sending packets*/

ldp_packet_snd_hello_link (struct hello_info *,
                           struct interface *,
                           struct hellomgr *);

ldp_packet_snd_hello_targ (struct hello_info *,
                           struct in_addr *,
                           struct hellomgr *);

ldp_packet_snd_init (struct init_info *,
                     struct peer *);
  
ldp_packet_snd_keepalive (struct keepalive_msg_info *,
                          struct peer *);

ldp_packet_snd_addr (struct addr_msg_info *,
                     struct peer *);

ldp_packet_snd_addr_withdraw (struct addr_withdraw_msg_info *,
                              struct peer *);

ldp_packet_snd_label_map (struct label_map_msg_info *,
                          struct peer *);

ldp_packet_snd_label_req (struct label_req_msg_info *,
                          struct peer *);

ldp_packet_snd_label_abort_req (struct label_abort_req_msg_info *,
                                struct peer *);

ldp_packet_snd_label_rel (struct label_rel_msg_info *,
                          struct peer *);

ldp_packet_snd_label_withdraw (struct label_withdraw_msg_info *,
                               struct peer *);

ldp_packet_snd_notify (struct notify_msg_info *,
                       struct peer *);

/* Prototypes for receiving session messages.*/
The receive routines decode the messages and their TLVs and convert all info
into the internal formats. It checks for the validity of peers and then
pass on to the ldp_msgev module (Message Events module).

ldp_packet_rcv_hello (struct stream *,
                      u_int16_t   size);

ldp_packet_rcv_init (struct stream *s,
                     u_int16_t	   size);

ldp_packet_rcv_keepalive (struct stream *s,
                          u_int16_t     size);

ldp_packet_rcv_addr (struct stream *s,
                     u_int16_t     size);

ldp_packet_rcv_addr_withdraw (struct stream *s,
                              u_int16_t     size);

ldp_packet_rcv_label_map (struct stream *s,
                          u_int16_t     size);

ldp_packet_rcv_label_req (struct stream *s,
                          u_int16_t     size);

ldp_packet_rcv_label_abort_req (struct stream *s,
                                u_int16_t     size);

ldp_packet_rcv_label_rel (struct stream *s,
                          u_int16_t size);

ldp_packet_rcv_label_withdraw (struct stream *s,
                               u_int16_t size);

ldp_packet_rcv_notify (struct stream *s,
                       u_int16_t size);



Private APIs:

int ldp_read_hello_packet   (struct hellomgr  *mgr,
                             struct interface *iif,
                             struct sockunion *su_src,
                             struct sockunion *su_dst)

Input : mgr    = Pointer to struct hellomgr.
        iif    = Pointer to struct interface.
        su_src = Pointer to struct sockunion.
        su_dst = Pointer to struct sockunion.
Output : Returns number of bytes read.
Synopsis : This function reads a hello packet from mgr->hello_sock
           and puts into mgr->ibuf. Futher it extracts the control
           info associated with the packet such as incoming interface
           source ipv4/v6 addr and dst ipv4/ipv6 addr.


int ldp_read_peer_packet (struct peer *peer)
Input : peer = Pointer to struct peer.
Output: Returns number of bytes read.
Synopsis : This function reads a packet from peer->session_sock and 
           inserts into peer->ibuf.


ldp_pdu_encode_hdr (struct stream *s,
                    u_int16_t *ver,
                    u_int16_t *len,
                    struct ldp_id *id)
Input: s = pointer to the stream.
       ver = For retuning ver field.
       len = For returning length field.
       id =  For returning ldp_id.   

ldp_pdu_decode_hdr (struct stream *s,
                    u_int16_t *ver,
                    u_int16_t *len,
                    struct ldp_id *id) 

ldp_pdu_check_err  (struct stream *) 

ldp_pdu_add_packet (struct stream *pdu,
                    struct stream *packet)


On the receiving side, it extracts the packets from relevant 
sockets (ldpd->srv_sock, hellomgr->hello_sock, peer->session_sock)
when notified about packet arrival (by thread_excute() when poll() returns true for the socket). It decodes the MSG/TLVs and after extracting the info from packets it delivers to the proper module for 
further processing.


4.1 ldp_srv_read (struct thread *thread)
    Input   : thread = The thread for which this is called.
    Output  : None
    Synopsis: This method reads Server events on ldpd->srv_sock.
    - thread arg = ldpd
      thread fd =  ldpd->srv_sock
    - Reads the event from ldpd->sock.
      Check if it is any accept event. If no return.
    - Extract from where the connection is from and 
      check that peer exists. ldp_peer_lookup_by_addr 
      (struct in_addr *). If Peer not found, return.
      Else proceed.
   -  Check that LDP_PEER_STATE(peer) == CONNECT_PASSIVE.
      If no return. If yes, notify that a incoming
      connection is received. 
      ldp_session_accept (struct peer *,
                          int sock_handle)
   -  Return.
 

4.2 ldp_hello_read (struct thread *)
    Input : thread = The thread for which this is called.
    Output: None
    Synopsis : This method reads hello messages from network.
    - thread arg = hellomgr
    - thead val  = hellomgr->hello_sock
    - Check if its any socket error event. If yes, then notify
      hellomgr about it. ldp_hellomgr_sock_err () and return.
    - If packet event then read the packets from hellomgr->ibuf.
    - Extract the interface on which the packet is received.
      ldp_packet_hello_get_ctrl_info (struct stream *s, 
                                      struct interface *iif,
                                      struct sockunion *su_src, 
                                      struct sockunion *su_dst)
   
    - Check the pdu for errors ldp_pdu_check_err (struct stream *)
      If not OK return.
    - Extract the hello msg info into struct hello_info. Notify the
      receipt of hello to hellomgr. If it is link hello (dst is mcast)
      then pass the iif , else pass NULL. Pass su_remote for both 
      link as well as targetted hellos.
 
      ldp_hellomgr_rcv_hello (struct hello_info *, 
                              struct ldp_id *,
                              struct interface *iif,
                              struct su *su_remote);
    - Start the thread again.(Read thread should be always on). 

4.3 ldp_hello_write (struct thread *) 
    Input : thread = The thread for which this is called.
    Output: None
    Synopsis : This method writes hello messages to network.
    - thread arg = hellomgr
    - thread val = hellomgr->hello_sock 
    - Writes hello messages from hello_mgr->obuf.

4.4 ldp_peer_read (struct thread *)
    Input : thread = The thread for which this is called.
    Output: None
    Synopsis : This method reads session messages from peers.
    - thread arg = peer
    - As its a non-blocking I/O check if the status of peer
      is CONNECT_ACTIVE. 
      LDP_PEER_STATE (peer) == CONNECT_ACTIVE. If yes proceed
      next else jump to "Make sanity check on PDU..".
    - ldp_session_connect_check (peer)
    - Make sanity check on PDU ldp_pdu_check_err (stream *s)
    - Check that the pdu->ldpid = peer->ldpid. If not
      return (and send notification).
    - Extract packets from the pdu one by one.
    - Deliver the individual packets to ldp_session module
      for further handling.
    - Start the thread again. (Read thread has to be always on).

4.5 ldp_peer_write (struct thread *)
    Input : thread = The thread for which this is called.
    Output: None
    Synopsis: This method writes session messages to peer.
    - threac arg = peer
    - thread cal = peer->session_sock
    - Parses the packets from peer->obuf.
    - Make a PDU by clubbing all packets
      ldp_pdu_add_packet (struct stream *pdu, 
                          struct stream *packet)

    - Send the stream containing the pdu to network


LDP TLV Module ldp_tlv.h/c
===========================

This module provides the set of libraries for decoding and encoding 
all types of TLVs supported by LDP. The info from a TLV is internally
represented with tlv_TLVNAME_info format.



APIs would be of types ldp_tlv_decode_TLVNAME and ldp_tlv_encode_TLVNAME


LDP Finite State Machine Module ldp_fsm.h/c
===========================================
This module handles the finite state machine of peer LDP sessions.

This module interacts with ldp_peer module and ldp_sessions module.

It receives internal events from ldp_peer module.Internal events are generated by ldp_peer module due to change in peer state due
to configuration or hellomgr notification etc. 


It receives external events from ldp_session_module. The external
events are mostly due to receipt of external events such as 
messages from the peer and/or tcp connection events.

Both external or internal event handlers are:

ldp_fsm... sort of commands.


APIs
====
Public:

void
ldp_fsm_start_active  (struct peer *)
Callers : ldp_session_start

- Checks with fsm and finds the next state = CONNECT_ACTIVE 
  and handler = ldp_session_connect_active(struct peer *)

void
ldp_fsm_start_passive 
callers : ldp_session_start

-Checks with fsm and finds the next state = CONNECT_PASSIVE
 and handler = ldp_session_connect_passive (struct peer *).

                           
        
LDP Session Manager Module ldp_session.h/c
==========================================
This module handles the LDP sessions related to peers. It interacts with
ldp_peer module for manipulating the peer, ldp_fsm module for state machine 
of peer and ldp_packet module for receiving/sending packets.

APIs
====

 1. void ldp_session_accept (struct peer *peer,
                             int sock_handle)
    Input : peer = Pointer to peer from which the tcp request came.
            sock_handle = session handle for this peer.
    Output : None
    Synopsis : This method receives a tcp connection request from 
               ldp_packet module for this peer in CONNECT_PASSIVE
               state. It passes the sock_handle because in this mode
               the handle is allocated only when the connection is 
               accepted.
    Callers : ldp_srv_read thread in (..) in ldp_packet.c

    - Add the sock_handle to peer->session_sock.
    - Set ldpd->state = INITIALIZED.
    - Wait for the peer to actively initialize the session.
    - Return.

 2. void ldp_session_connect_active (struct peer *peer)
    Input :   peer = Pointer to struct peer.
    Output:   None
    Synopsis: This method make a connection to the peer actively.
    Callers : 

    - Calls ldp_network_tcp_cli_open (&ldpd->su,
                                      &peer->su)
    - Assign the handle returned into peer->session_sock.
    - Set peer->state = CONNECT_ACTIVE.
    - Return

 3. void ldp_session_connect_passive (struct peer *peer)
    Input : peer = Pointer to struct peer.
    Output: None
    Synopsis : This method waits for a connection from a peer 
               passively.
    Callers  :
    - Set peer->state = CONNECT_PASSIVE. We don't have to do anything 
      because ldpd->srv_sock does all the wait work.
 
 4. ldp_session_connect_active_complete (struct peer *)
    Input : peer = Pointer to the struct peer.
    Output: None 
    Synopsis : This method is called when a prior ldp_session_conect
               has been accepted.
    
    Callers  : ldp_peer_read in ldp_packet.c
    - Now it's time to start the LDP Session.
    - Creates LDP INIT Message.
    - Send the message ldp_packet_snd_init (struct init_info *info,
                                            struct peer *peer)

 5. void ldp_connect_check (struct peer *peer)
    Input : peer = Pointer to struct peer.
    Output: None
    Synopsis : This checks whether connection is established
               in peer->session_sock 
    - Switch off read/write threads of the peer.
      thread_del_read  (peer->t_read)
      thread_del_write (peer->t_write)
    - Check the sockopt SO_ERROR
    - If returns < 0
      thread_add_event (peer, TCP_fatal_error) and return.
    - If return 0
      thread_add_event (peer, TCP_connection_open) and return.
    - Else thread_add_event (peer, TCP_connection_open_failed) and return.
   

 6. void ldp_session_err (struct peer *peer)
    Input: peer = Pointer to the struct peer.
    Output : None
    Synopsis : This event notifies an error in the socket communication
    - (TBD)

 7. ldp_session_start (struct peer *peer)
    Input : peer = Pointer to the struct peer.
    Output: None
    Synopsis : This is the starting point of LDP Finite State Machine
               for a Peer.
    - Check if the ldp_peer_is_master (struct peer *peer). 
    - If its master then wait in passive mode.
      ldp_session_connect_passive (peer).
    - Else do an active connect.
      ldp_session_connect_active (peer).    


External events handling in session module:

This module also handles events specific to messages received from peer.
This module manipulates the peer state machine due to external triggers.
Further this module takes help of ldp_packet module if any message needs
to be sent to peer. These events are generated by ldp_packet module after
doing necessary checks.

void ldp_session_init_from_peer (struct init_info *,
                                 struct peer *);
This API follows the "Initialization Message Procedures" as defined in section
3.5.3.1 in RFC 3036.

void ldp_session_keepalive_from_peer (struct keepalive_info *,
                                      struct peer *);
This API follows the "Keepalive Message Procedures" as defined in section 
3.5.4.1 in RFC 3036.

void ldp_session_addr_from_peer (struct addr_info *,
                                 struct peer *);
This API follows the "Address Message Procedures" as defined in section 
3.5.5.1 in RFC 3036. 

void ldp_session_addr_withdraw_from_peer (struct addr_withdraw_info *,
                                          struct peer *);
This API follows the "Address Withdraw Message Procedures" as defined in 
section 3.5.6.1 in RFC 3036.

void ldp_session_label_map_from_peer (struct label_map_info *,
                                      struct peer *);
This API follows the "Label Mapping Message Procedures" as defined in 
section 3.5.7.1 in RFC 3036.

void ldp_session_label_req_from_peer (struct label_req_info *,
                                      struct peer *);
This API follows the "Label Request Message Procedures" as defined in 
section 3.5.8.1 in RFC 3036.

void ldp_session_label_abort_req_from_peer (struct label_abort_req_info *,
                                            struct peer *);
This API follows the "Label Abort Request Message Procedures" as defined in 
section 3.5.9.1 in RFC 3036.

void ldp_session_label_rel_from_peer (struct label_rel_info *,
                                      struct peer *);
This API follows the "Label Release Message Procedures" as defined in section
3.5.11.1 in RFC 3036.

void ldp_session_label_withdraw_from_peer (struct label_withdraw_info *,
                                           struct peer *);
This API follows the "Label Withdraw Message Procedures" as defined in section
3.5.10.1 in RFC 3036.

void ldp_session_notify_from_peer (struct notify_info *,
                                   strut peer *);
This API follows the "Notification Message Procedures" as defined in section
3.5.1.1 in RFC 3036.




LDP Routing Module ldp_route.h/c
=================================
This module is the routing interface for LDP. It receives route add/del
events via zclient (ldp_zebra) from zmpls daemon and installs all the 
FIB Routes. By keeping the FIB in ldpd we intend to speed up route look up.

This module provides facility for callbacks on route add/del events.

Other modules can register with this module for specific events with their
desired callbacks. When the specific route event occurs thsi module notifies
other modules through callbacks.

APIs
====
void ldp_route_init ();

ldp_route_add ();

ldp_route_delete ();

ldp_route_changed_event ();  


Design of RFC 3478 - Graceful Restart Mechanism for Label Distribution Protocol.
=============

zMPLS needs to support NSF for ldpd restart.


The RFC 3478 refers to states that is to be preserved across restart 
is as below:

"The mechanism makes minimalistic assumptions on what has to be preserved across restart - the mechanism assumes that only the actual MPLS forwarding state has to be preserved. Clearly this is the minimum amount of state that has to be preserved across the restart in order not to perturb the LSPs traversing a restarting LSR. The mechanism does not require any of the LDP-related states to be preserved across the restart." 

The architecture of zMPLS itself can provide the NSF capability.
ldpd runs in its own virtual memory. When ldpd restarts zmpls still functions properly with the LSPs installed by ldpd and also the 
forwarding engine in kernel remains intact with the lsps installed by ldpd. 

if zmpls restarts and ldpd remains intact then ,ldpd will not be able
to update the interim lps updates tillthe kernel FIB till zmpls comes up. Still fowarding continues in kernel. Once zmpls comes up it updates
the lsps from kernel and further connects to ldpd/rsvpd for lsp updation. Then it does a cross check with "what I have", "what you have" and updates its lsp database,

The GR capability
==================

ldpd.h/c
========
The GR capability is divided into 2. ldpd can work as GR_HELPER mode
as well as NSF mode. We introduce 2 new flags in struct ldp->cflags.

#define LDP_CFLAG_GR_HELPER
#define LDP_CFLAG_GR_NSF

Both the options are configurable from CLI.
"ldp enable graceful-restart (nsf|helper)"

I need to see how this CLI fits in Cisco standard CLI and need to align if required.

Need the following parameters in struct ldp:

struct ldp->check_restart_time = Non standard param. This is the time
                                  for which ldpd waits zmpls to respond 
                                  with preserved lsps if any to take
                                  decision whether it is restarting. 

struct ldp->ft_reconnect_time = Time within which the ldpd restarts and 
                             reconnects to the peers. 
struct ldp->ft_recovery_time  = Time after sending init within which I  
                             want peers to sync up its FECs/LSPs.Else
                             I delete them. If I am restarting I should
                             send this time info to peers in INIT msg.
                             This is my forwarding state holding timer.

struct ldp->check_restart_timer = When this timer expires, start 
                                   sending hellos and in all subsequent
                                   sessions send recovery_time = 0; 

struct ldp->t_ft_recovery_timer = 


ldp->check_restart_timer handler (ldp_check_restart_timer_expired)

{
  start ldp_start_hellomgr ();
  set ldpd->state = NO_RESTART;
}
  
ldp_peer.h/c
=============

Add the following members to struct peer

struct peer->ft_reconnect_time   =  Time within which peer promises to 
                                    reconnect after restart.

struct peer->ft_recovery_time    =  Time for which the peer promises to
                                    retain the forwarding after sending 
                                    INIT message. So we need to sync up
                                    before this time.

struct peer->t_ft_reconnect_timer=  If this peer is restarting,then
                                    wait for this peer to be connected.

struct peer->t_ft_recovery_timer =  This peer wants to recover within
                                    this time. So need to send all FEC
                                    updates within this time. This is
                                    peer's forwarding state holding
                                    timer.

Following flags are added to struct peer->cflags
#define PEER_CFLAG_GR_HELPER = If peer is only helper. 
#define PEER_CFLAG_GR_NSF    = If peer is restart capable.

ldp_tlv.h/c
===========

The FT (Fault Tolerant) TLV is added to this module. This TLV SHOULD be sent ONLY in LDP Initialization Message.

#define LDP_TLV_FT

/* Holder to carry information extracted from FT TLV.*/
struct ldp_tlv_ft_info
{
   u_char l   ;                 /*The l bit*/
   u_int16_t  ft_reconnect_time;
   u_int16_t  ft_recovery_time;
};

APIs
=====
ldp_tlv_encode_ft (struct stream *s,
                   struct ldp_tlv_ft_info *);

ldp_tlv_decode_ft (struct stream *s,
                   struct ldp_tlv_ft_info *);

ldp_packet.h/c
==============

Following new CASE has been added to ldp_packet_rcv_init method (For receiving and processing initialization message) as

void
ldp_packet_rcv_init (struct stream *s,
                     struct init_info *)
{
   ...
   CASE LDP_FT_TLV:
      ldp_tlv_decode_ft (..);

   ...
} 

ALGORITHMS
=================================
CASE 1 : When ldpd is restarting

After ldpd starts check with zmpls daemon if it has stored any FEC/LSP in it.

ldpd_check_restart
        |
if (ldp_restart_capable)
        |
    if res = LDP_CFLAG_GR_NSF-----------No 
        |                               |
       Yes                        ldp->state = ACTIVE
        |                               |
ldp_zebra_get_fec_backup ()       ldp_hellomgr_start() 
start ldpd->check_restart_timer         |
        |                            <snip>
        .
        .
 zmpls_get_fec_backup event (Reply to earlier request)
        |
 stop ldpd->check_restart_timer
        |
        |---------------------------------+
        |                                 |
        |                                 |
        v                                 v
No lsp is given by zmpls          fecs preserved by zmpls
        |                                 |
ldpd->state = ACTIVE              add the fecs to ldp_lib
        |                                 |
        |                                 | 
ldp_hellomgr_start()                      |
        |                                 | 
     <snip>                               |
                                          v
                            Mark all FEC entries in all as stale.
                            (ldp_fec_select_and_mark_stale (ldpd->lib)
                                          |
                                          v
                                ldp->state = RESATRTING
                                          |
                                          |
                                          v
                                 ldp_hellomgr_start ()
                                          |
                                          |
                                          .
                                          .
                            Peer is discovered event
                                    (ldp_peer_add) 
                                          .
                                          |
                                     ldp_session_rcv_init
                                    (struct init_info,
                                     struct peer)
                                          |
                                          |
                                          v
                          if (ldp_session_is_ft (init_info)&&----+      
                              ldp->state = RECOVERING)           |
                                          |                      | 
                                         Yes                    No
                                          |                      |
                                          v                      | 
                          if (ldp_fib_peer_exist (ldp_lib))------|
                                          |                      | 
                                         Yes               Send INIT
                                          |           recovery_time = 0
                                          |
                                          v 
                          so send all INIT messages with
                          recovery_time = peer->ft_recovery_time
                          start peer->t_ft_recovery_timer.  


Event:
 
ldp_session_rcv_label_map (struct peer *)
                   |
                   v
 if (peer->state == RECOVERING)
 {
    fec_entry = ldp_peer_lib_lookup (fec, label)  

    if (!fec)
    {
       if (fec_entry->outlabel == label)
       { 
          fec_entry_clean_stale (fec_entry); 
          if (fec_entry-
          ldp_session_snd_label_map_to_all_peers ()
       }
    }
 }
       
Timer Handler
=============
1. Handler for ldp->t_ft_reconnect_timer is:

ldpd_ft_reconnect_timer_expired()
{
   For each entry in ldp_lib
   {
     if ((peer = ldp_peer_lookup (fec_entry->peer)== NULL)
     {
        /* If the peer is not initailized yet then delete the FECs.*/
        For each fec_entry in peer
           ldp_lib_delete_fec (fec_entry);   
     }            
}

2. Handler for ldp->t_ft_recovery_timer is:

ldpd_ft_recovery_time_expired()
{
  For each peer in lib
  {
     For each fec entry in this peer
     {
        if (fec_entry->state == STALE)
        {
           fec_entry_delete (fec_entry);
           ldp_snd_label_rel (peer, fec);
        }
     }
  }
  ldpd->state = ACTIVE;
}        

 
CASE 2 : When ldpd's neigbor is restarting
==========================================

Two events trigger graceful restart

ldp_session_hello_holdtimer_expired (struct peer *)
               or,
ldp_session_keepalivetimer_expired  (struct peer *)

In both the events:
                 |
           if (ldp_peer_is_gr_capable (struct peer *))----------
                 |                                             |
                Yes                                            No
                 |                                             |
                 v                                             v
           Stop peer->t_hello_holdtimer       ldp_peer_shutdown (peer)
           Stop peer->t_session_holdtimer   
           Start peer->t_ft_reconnect_timer
                 |
           peer->state = RECONNECTING
                 |
           For each fec_entry in peer
                 |
            peer_lib_mark_all_stale (peer)
                 |
                 v
     If (peer_is_active (peer))
                 |
                 v
     peer->state = PASSIVE_CONNECT--No
                 |                   | 
                yes                  |
                 v                   v
     ldp_connect_passive (peer)  ldp_connect_active (peer)


Event: ldp_session_rcv_init (struct peer *, struct init_info *)
                  |
                  v
             if(peer->state == RECONNECTING)
             {
                if(init->recovery_time ==0)
                   ldp_peer_lib_delete (peer);
                else
                {     
                   peer->state = RECOVERING;
                   Start peer->t_ft_recovery_timer;
                }
             } 
                           



Timer Handler
=============

peer->t_ft_reconnect_timer handler is 

peer_ft_reconnect_timer_expired (peer)
{
   ldp_peer_delete (struct peer *);
   ldp_peer_lib_delete (struct peer *);
}