Commit 965be382 authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Started support for routing module

parent 42d561cf
......@@ -166,7 +166,6 @@ struct fd_peer { /* The "real" definition of the peer structure */
pthread_t p_ini_thr; /* Initiator thread for establishing a connection */
struct fd_list p_connparams; /* The list of connection attempts, see p_cnx.c */
};
/* connection context: socket and related information */
struct cnxctx *p_cnxctx;
......
......@@ -425,18 +425,67 @@ int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor,
/* Note: if we want to support capabilities updates, we'll have to add possibility to remove an app as well... */
/***************************************/
/* Routing module */
/***************************************/
/* This file contains the definitions of types and functions involved in the routing decisions in freeDiameter,
* and that can be called by extensions.
*
* Three different type of messages must be distinguished:
* - Messages received, and the peer is final recipient (IN messages)
* - Messages received, and the peer is not final recipient (FWD messages)
* - Message is locally generated (OUT messages)
*
* There are three global message queues (in queues.c) and also peers-specific queues (in struct fd_peer).
*
* (*) IN messages processing details:
* - the message is received from the remote peer, a FDEVP_CNX_MSG_RECV event is generated for the peer.
* - the PSM thread parses the buffer, does some verifications, handles non routable messages (fd_msg_is_routable)
* - routable messages are queued in the fd_g_incoming global queue.
* - a thread (routing-in) picks the message and takes the decision if it is handled locally or forwarded,
* based on local capabilities (registered by extensions).
* - If the message is handled locally, it is queued in fd_g_local.
* - Another thread (dispatch.c) will handle this message and pass it to registered callbacks (see fd_disp_register in libfreeDiameter.h).
*
* (*) FWD messages details:
* - The process is the same as for IN messages, until the routing-in threads makes its decision that the message is not handled locally.
* - All callbacks registered with fd_rt_fwd_register are called for the message (see bellow).
* - these callbacks will typically do proxying work. Note that adding the route-record is handled by the daemon.
* - Once all callbacks have been called, the message is queued in the global fd_g_outgoing queue.
* - The remaining processing is the same as for OUT messages, as described bellow.
*
* (*) OUT messages details:
* - The message are picked from fd_g_outgoing, as result of forwarding process or call to fd_msg_send.
* - The (routing-out) thread builds a list of possible destinations for the message.
* The logic to build this list is as follow:
* - create a list of all known peers in the "OPEN" state.
* - remove from that list all peers that are in a Route-Record AVP of the message, to avoid routing loops.
* - remove also all peers that have previously replied an error message for this message.
* - If the list is empty, create an error UNABLE_TO_DELIVER (note: should we trig dynamic discovery here???) and reply this.
* - Otherwise, call all callbacks registered by function fd_rt_out_register, with the list of peers and the message.
* - Order the resulting list of peers by score (see bellow), and sent the message to the peer with highest (positive) score.
* - in case the peer is no longer in the "OPEN" state, send the message to the second peer in the list.
* - if no peer is in OPEN state anymore, restart the process of creating the list.
* - The peer thread will handle the creation of the Hop-by-hop ID and sending the message.
*
* This part of the API (routing-api.h) provides the definitions of the rt_out_cb_t and rt_fwd_cb_t callbacks, and the
* functions to register and deregister these callbacks.
*/
/***************************************/
/* Events helpers */
/***************************************/
/* Events */
struct fd_event {
int code; /* codespace depends on the queue */
size_t size;
void *data;
};
/* Daemon's codespace: 1000->1999 */
/* Daemon's codespace: 1000->1999 (1500->1999 defined in fD.h) */
enum {
FDEV_TERMINATE = 1000 /* request to terminate */
,FDEV_DUMP_DICT /* Dump the content of the dictionary */
......
......@@ -1611,6 +1611,43 @@ void fd_sess_dump(int level, struct session * session);
void fd_sess_dump_hdl(int level, struct session_handler * handler);
/*============================================================*/
/* ROUTING */
/*============================================================*/
/* The following functions are helpers for the routing module.
The routing data is stored in the message it-self. */
/* Structure that contains the routing data for a message */
struct rt_data;
/* Following functions are helpers to create the routing data of a message */
int fd_rtd_init(struct rt_data ** rtd);
void fd_rtd_free(struct rt_data ** rtd);
/* Add a peer to the candidates list */
int fd_rtd_candidate_add(struct rt_data * rtd, char * peerid);
/* Remove a peer from the candidates (if it is found) */
void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */);
/* If a peer returned a protocol error for this message, save it so that we don't try to send it there again */
int fd_rtd_error_add(struct rt_data * rtd, char * sentto, uint8_t * origin, size_t originsz, uint32_t rcode);
/* Extract the list of valid candidates, and initialize their scores to 0 */
void fd_rtd_candidate_extract(struct rt_data * rtd, struct fd_list ** candidates);
/* The extracted list items have the following structure: */
struct rtd_candidate {
struct fd_list chain; /* link in the list returned by the previous fct */
char * diamid; /* the diameter Id of the peer */
int score; /* the current routing score for this peer, see fd_rt_out_register definition for details */
};
/* Reorder the list of peers */
int fd_rtd_candidate_reorder(struct fd_list * candidates);
/*============================================================*/
/* MESSAGES */
/*============================================================*/
......@@ -1958,8 +1995,8 @@ int fd_msg_anscb_get ( struct msg * msg, void (**anscb)(void *, struct msg
* 0 : ok
* EINVAL: a parameter is invalid
*/
int fd_msg_rt_associate( struct msg * msg, struct fd_list ** list );
int fd_msg_rt_get ( struct msg * msg, struct fd_list ** list );
int fd_msg_rt_associate( struct msg * msg, struct rt_data ** rtd );
int fd_msg_rt_get ( struct msg * msg, struct rt_data ** rtd );
/*
* FUNCTION: fd_msg_is_routable
......
......@@ -11,6 +11,7 @@ SET(LFD_SRC
lists.c
log.c
messages.c
rt_data.c
sessions.c
)
......
......@@ -86,7 +86,6 @@ void fd_list_move_end(struct fd_list * ref, struct fd_list * senti)
ref->prev = senti->prev;
senti->prev = senti;
senti->next = senti;
}
/* insert before a reference, checks done */
......
......@@ -117,7 +117,7 @@ struct msg {
uint8_t *msg_rawbuffer; /* data buffer that was received, saved during fd_msg_parse_buffer and freed in fd_msg_parse_dict */
int msg_routable; /* Is this a routable message? (0: undef, 1: routable, 2: non routable) */
struct msg *msg_query; /* the associated query if the message is a received answer */
struct fd_list *msg_rtlist; /* Routing list for the query */
struct rt_data *msg_rtdata; /* Routing list for the query */
struct {
void (*fct)(void *, struct msg **);
void * data;
......@@ -568,14 +568,8 @@ static int destroy_obj (struct msg_avp_chain * obj )
free(_M(obj)->msg_src_id);
}
if ((obj->type == MSG_MSG) && (_M(obj)->msg_rtlist != NULL)) {
while (! FD_IS_LIST_EMPTY(_M(obj)->msg_rtlist) ) {
struct fd_list * li = _M(obj)->msg_rtlist->next;
fd_list_unlink(li);
free(li);
}
free(_M(obj)->msg_rtlist);
if ((obj->type == MSG_MSG) && (_M(obj)->msg_rtdata != NULL)) {
fd_rtd_free(&_M(obj)->msg_rtdata);
}
/* free the object */
......@@ -1030,26 +1024,26 @@ int fd_msg_anscb_get( struct msg * msg, void (**anscb)(void *, struct msg **), v
}
/* Associate routing lists */
int fd_msg_rt_associate( struct msg * msg, struct fd_list ** list )
int fd_msg_rt_associate( struct msg * msg, struct rt_data ** rtd )
{
TRACE_ENTRY( "%p %p", msg, list );
TRACE_ENTRY( "%p %p", msg, rtd );
CHECK_PARAMS( CHECK_MSG(msg) && list );
CHECK_PARAMS( CHECK_MSG(msg) && rtd );
msg->msg_rtlist = *list;
*list = NULL;
msg->msg_rtdata = *rtd;
*rtd = NULL;
return 0;
}
int fd_msg_rt_get( struct msg * msg, struct fd_list ** list )
int fd_msg_rt_get( struct msg * msg, struct rt_data ** rtd )
{
TRACE_ENTRY( "%p %p", msg, list );
TRACE_ENTRY( "%p %p", msg, rtd );
CHECK_PARAMS( CHECK_MSG(msg) && list );
CHECK_PARAMS( CHECK_MSG(msg) && rtd );
*list = msg->msg_rtlist;
msg->msg_rtlist = NULL;
*rtd = msg->msg_rtdata;
msg->msg_rtdata = NULL;
return 0;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment