Implementing an extension for free Diameter Souheil Ben
Implementing an extension for free. Diameter Souheil Ben Ayed (Keio) Sebastien Decugis (NICT) WIDE AAA-WG Free. Diameter Extension
Free. Diameter Extension Tutorial Goal : Introduce on writing an Extension for free. Diameter p Tutorial based on “test_app” extension Tutorial includes: p Writing an Extension p Configuring an extension for free. Diameter start writing an extension Add object definition to Dictionary Manage diameter messages and AVPs Manage sessions Add Extension to free. Diameter Add/edit CMAKE configuration files Add Extension to be loaded. Build/test Souheil Ben Ayed, Sebastien Decugis March 10, 2010 2
Steps : writing an Extension for free. Diameter 1. Start writing your extension 2. Add new objects to Dictionary 3. 4. Create Request/Response messages, send message … Add AVPs to message, set AVP Data, search for AVPs … Manage Sessions 6. Application object , commands objects , AVPs objects, rules … Add application to be announced (CER/CEA exchange) Manage Messages and AVPs 5. Includes, Entry point function, Cleanup callback function Create new session, store/retrieve session state, destroy session Add your extension to free. Diameter Edit free. Diameter configuration, Cmake configuration Souheil Ben Ayed, Sebastien Decugis March 10, 2010 3
Writing an extension Start writing an extension Adding objects to dictionary Manage Messages and AVPs Manage Sessions Souheil Ben Ayed, Sebastien Decugis March 10, 2010 4
Start writing your extension #include <free. Diameter/extension. h> Extension header file: pfree. Diameter API static int ta_entry(char * conffile); EXTENSION_ENTRY("test_app", ta_entry); Define the entry point /* Entry point */ static int ta_entry(char * conffile) { TRACE_ENTRY("%p", conffile); return 0; } Entry point called /* Cleanup callback*/ void fd_ext_fini(void) { return ; /* Extension is terminated */ } Function called when Souheil Ben Ayed, Sebastien Decugis when loading the extension the free. Diameter daemon exits March 10, 2010 5
Add Objects to the Dictionary /* A simple object: the test application */ struct dict_object * ta_appli = NULL; struct dict_application_data appdata = { /*application_id =*/ 999999, /* application_name =*/ "Test application" }; ret = fd_dict_new( dict, /* the dictionary we are adding into */ DICT_APPLICATION, &appdata, NULL, /* parent: optional (vendor in this case) */ &ta_appli ); /* Don’t forget to check the value of ret … */ Souheil Ben Ayed, Sebastien Decugis Object reference The data of the new object The new application is defined in “dict” upon success. March 10, 2010 6
Search in Dictionary (fd_dict_search) - 1 The function fd_dict_search is : p p Look for an application, command, AVP, vendor object… Check if an object is in the dictionary. int fd_dict_search ( struct dictionary * dict, enum dict_object_type, int criteria, void * what, struct dict_object **result, int retval ); dict : Target dictionary type : Type of object that is looking for: DICT_APPLICATION, DICT_AVP, … p criteria: How to search for the object: APPLICATION_BY_NAME, AVP_BY_CODE, … p what : value of the criteria to match p p Souheil Ben Ayed, Sebastien Decugis March 10, 2010 7
Search in Dictionary (fd_dict_search) - 2 To search for an object: Creates a dict_object : where the object will be store in. What is the type of the object : DICT_APPLICATION Choose your criteria for searching (+the value for this criteria): APPLICATION_BY_NAME Now we are ready to search for an object corresponding to this criteria in the dictionary. struct dict_object * appli, * avp_username; command_code_t code = 268; fd_dict_search(dict, DICT_APPLICATION, APPLICATION_BY_NAME, " Test application", &appli, ENOENT); fd_dict_search(dict, DICT_AVP, AVP_BY_CODE, &code, &avp_username, ENOENT); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 8
Register application for advertising To register an application to be advertized in CER/CEA exchanges. int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct ); Example: struct dict_object * ta_appli = NULL; struct dict_object * ta_vendor = NULL; application_id_t appli_id = 999999; /*search Application object by application ID*/ fd_dict_search(fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_ID, &appli_id, & ta_appli, ENOENT); /*search vendor object*/ fd_dict_search(fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_OF_APPLICATION, &ta_appli, & ta_vendor, ENOENT); /* Advertise the support for the test application in the peer */ fd_disp_app_support ( ta_appli, ta_vendor, 1, 0 ) ; Souheil Ben Ayed, Sebastien Decugis March 10, 2010 9
Register a callback function - 1 This callback will be called when a message matching criteria is received by free. Diameter daemon. To match criteria. APP ID, Command code, AVP code, … And give the value to match. p Example: Command code criteria (DISP_HOW_CC). And for messages with: Application Id = 5, Command code = 268 Souheil Ben Ayed, Sebastien Decugis struct disp_when { struct dict_object *app; struct dict_object *command; struct dict_object *avp; struct dict_object *value; }; enum disp_how { DISP_HOW_ANY = 1, DISP_HOW_APPID, DISP_HOW_CC, DISP_HOW_AVP_ENUMVAL }; March 10, 2010 10
Register a callback function - 2 To register a callback function : int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, enum disp_action *), enum disp_how how, struct disp_when * when, struct disp_hdl ** handle ); Example: /* int ta_tr_cb(struct msg **, struct avp *, struct session *, enum disp_action *); */ static struct disp_hdl * ta_hdl_tr = NULL; /* handler for Test-Request req cb */ struct disp_when data; data. app = ta_appli; data. command = ta_cmd_r; fd_disp_register( ta_tr_cb, DISP_HOW_CC, &data, &ta_hdl_tr ) ; Souheil Ben Ayed, Sebastien Decugis March 10, 2010 11
“test_app” extension entry point Souheil Ben Ayed, Sebastien Decugis March 10, 2010 12
Manage Diameter Messages A message object is made of a header and 0 or more AVPs. Structure of message header: struct msg_hdr { uint 8_t msg_version; uint 32_t msg_length; uint 8_t msg_flags; command_code_t msg_code; application_id_t msg_appl; uint 32_t msg_hbhid; uint 32_t msg_eteid; }; Dump a message Message AVP Grp. AVP AVP /*Dump the content of message object recursively*/ void fd_msg_dump_walk ( int level, msg_or_avp *obj ); /*Dump only the content of message object itself */ void fd_msg_dump_one ( int level, msg_or_avp *obj ); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 13
New request Diameter Message fd_msg_new creates a new empty Diameter message from a request command template. int fd_msg_new ( struct dict_object * model, int flags, struct msg ** msg ); model flags msg : corresponding to an object from dictionary. : options to create message ( combination of MSGFL_*) : the new created message Example : struct msg * req; struct dict_object * ta_cmd_r; command_code_t code = 257; /*Search request command object by command code “ 257” */ fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_CODE_R, & code, &ta_cmd_r); /*Create new request message with command code “ 257” and an end-to-end Id*/ fd_msg_new( ta_cmd_r, MSGFL_ALLOC_ETEID, &req ); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 14
New response Diameter Message fd_msg_new_answer_from_req creates an empty answer message corresponding to a request. Int fd_msg_new_answer_from_req ( struct dictionary * dict, struct msg ** msg, int flag ); R flag cleared Command code, application id, hop-by-hop id and end-to-end id are added in the new message. The session Id AVP is copied if present in request. fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ); Or creates a new empty response message (with answer command model /CMD_BY_CODE_A). CMD_BY_CODE_A fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_CODE_A, & code, &ta_cmd_a); /*Create new request message with command code “ 257” and an end-to-end Id*/ fd_msg_new( ta_cmd_a, NULL, &ans ); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 15
Send Diameter message Both request and response messages are sent on network using fd_msg_send function. When sending message, a callback function may be specified for receiving the answer message. int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data ); Example: /*send answer message */ fd_msg_send( &ans, NULL ); /*send a request message with answer callback */ fd_msg_send( &req, ta_cb_ans, sdata); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 16
AVPs are part of a message structure. Some AVPs can contain other AVPs: AVP header structure struct avp_hdr { avp_code_t avp_code; uint 8_t avp_flags; uint 32_t avp_len; vendor_id_t avp_vendor; union avp_value * avp_value; }; Grouped AVPs AVP value union avp_value { struct { uint 8_t *data; /*bytes buffer*/ size_t len; } os; int 32_t i 32; /* integer 32 */ int 64_t i 64; /* integer 64 */ uint 32_t u 32; /* unsigned 32 */ uint 64_t u 64; /* unsigned 64 */ float f 32; /* float 32 */ double f 64; /* float 64 */ }; Souheil Ben Ayed, Sebastien Decugis March 10, 2010 17
Create AVP, set value and add to message-1 fd_msg_avp_new creates a new AVP. int fd_msg_avp_new ( struct dict_object * model, int flags, struct avp ** avp ); fd_msg_avp_setvalue set AVP value. int fd_msg_avp_setvalue ( struct avp *avp, union avp_value *value ); To add an AVP to a message or an AVP to an other AVP: int fd_msg_avp_add ( msg_or_avp * reference, enum msg_brw_dir dir, struct avp *avp); p reference: a message or AVP object p dir : location where to insert this AVP MSG_BRW_FIRST_CHILD, MSG_BRW_LAST_CHILD, MSG_BRW_NEXT, MSG_BRW_PREV, … p avp: an AVP to insert. Souheil Ben Ayed, Sebastien Decugis March 10, 2010 18
Create AVP, set value and add to message-2 strcut avp * avp; struct msg * req; int randval; unsigned char * username; union avp_value val; struct dict_object * ta_user_name, *ta_avp; /* Set the User-Name AVP if needed*/ … { fd_msg_avp_new ( ta_user_name, 0, &avp ); val. os. data = (unsigned char *)(user_name); val. os. len = strlen(user_name); fd_msg_avp_setvalue( avp, &val ); fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ); } /* Set the Test-AVP */ { } fd_msg_avp_new ( ta_avp, 0, &avp ); val. i 32 = mi->randval; fd_msg_avp_setvalue( avp, &val ); fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 19
Others functions To add Origin-Host AVP and Origin-Realm AVP: AVP int fd_msg_add_origin ( struct msg * msg, int osi ); If osi is set add the Origin-State-Id AVP at the end of the message. To add Result-Code AVP int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id ); If optavp is provided, a Failed AVP will be added to the message with the optavp content inside it. To search an AVP in a message: int fd_msg_search_avp ( struct msg * msg, struct dict_object * what, struct avp ** avp ); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 20
Retrieve AVP header and get AVP value With fd_msg_avp_hdr we can retrieve the header of an AVP. p From AVP header we can get stored AVP value. (stored value depends on value type) struct avp * avp; struct dict_object * ta_avp; struct avp_hdr * hdr; … fd_msg_search_avp ( *msg, ta_avp, &avp); if (avp) { fd_msg_avp_hdr( avp, &hdr ); printf("%x (%s) ", hdr->avp_value->i 32, (hdr->avp_value->i 32 == mi->randval) ? "Ok" : "PROBLEM"); } else { printf("no_Test-AVP "); } Souheil Ben Ayed, Sebastien Decugis March 10, 2010 21
Receive message (server side) Souheil Ben Ayed, Sebastien Decugis March 10, 2010 22
Manage Sessions -1 Only one session object for each session-Id AVP. { To associate a state with a session struct session int eyec; object we must first register a handler for sessions. }; Souheil Ben Ayed, Sebastien Decugis char *sid; uint 32_t hash; struct fd_list chain_h struct timespec timeout; struct fd_list expire; pthread_mutex_t stlock; struct fd_list states; int msg_cnt; March 10, 2010 23
Manage Sessions -2 To create a session object : fd_sess_new. int fd_sess_new ( struct session ** session, char * diam. Id, char * opt, size_t optlen ); A Session-Id string is generated. opt : is optional string to be concatenated to the identifier. fd_sess_destroy data. destroys a session and all associated int fd_sess_destroy ( struct session ** session ); Destroying a session is equivalent to a session timeout expired. Souheil Ben Ayed, Sebastien Decugis March 10, 2010 24
Manage Sessions -3 We can retrieve a session object from a Session-Id string. int fd_sess_getsid ( struct session * session, char ** sid ); Retrieve the session identifier of a session object. int fd_sess_fromsid ( char * sid, size_t len, struct session ** session, int * new); Modify the timeout for a session object. int fd_sess_settimeout( struct session * session, const struct timespec * timeout ); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 25
Session handler To associate a state with a Session-Id we must first create a handler for sessions. int fd_sess_handler_create( struct session_handler ** handler, void (*cleanup)(char * sid, session_state * state)) handler : the handler for sessions. cleanup : a callback function that must be called when the session with associated data is destroyed. This session handler should be destroyed at the cleanup callback. int fd_sess_handler_destroy( struct session_handler ** handler) Souheil Ben Ayed, Sebastien Decugis March 10, 2010 26
Save/Retrieve session’s state To store a state with a session: fd_sess_state_store int fd_sess_state_store( struct session_handler * handler, struct session * session, session_state ** state); To retrieve the saved state for a session: fd_sess_state_retrieve int fd_sess_state_retrieve( struct session_handler * handler, struct session * session, session_state ** state); Retrieving stored state implies disassociating the state with the session. Use fd_sess_state_store to associate the new state with the session. Souheil Ben Ayed, Sebastien Decugis March 10, 2010 27
Using sessions and session handler - 1 static struct session_handler * ta_cli_reg = NULL; /*session handler*/ struct session *sess ; fd_sess_handler_create(&ta_cli_reg, free); …. /* Create a new session */ fd_sess_new( &sess, fd_g_config->cnf_diamid, "app_test", 8 ); /* Session-Id */ { char * sid; fd_sess_getsid ( sess, &sid ); fd_msg_avp_new ( ta_sess_id, 0, &avp ); val. os. data = sid; val. os. len = strlen(sid); fd_msg_avp_setvalue( avp, &val ); fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ); } /* Store the value of mi in the session */ fd_sess_state_store ( ta_cli_reg, sess, &mi ); Souheil Ben Ayed, Sebastien Decugis March 10, 2010 28
Using sessions and session handler - 2 /* Search the session, retrieve its data */ { int new; fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &sess, &new); fd_sess_state_retrieve( ta_cli_reg, sess, &mi ); } … void fd_ext_fini( void) { … (void) fd_sess_handler_destroy(&ta_cli_reg); … }; Souheil Ben Ayed, Sebastien Decugis March 10, 2010 29
Send/Receive message ( client side) Souheil Ben Ayed, Sebastien Decugis March 10, 2010 30
Add an extension to free. Diameter Add Extension Add/edit CMAKE configuration files Add Extension to be loaded. Build/test Souheil Ben Ayed, Sebastien Decugis March 10, 2010 31
Add your Extension Make sure that you have Cmake installed. 1) Add your extension to free. Diameter extensions. Add the extension to be built with free. Diameter 2) (free. Diameter_pathextensionsCMake. List. txt) # Create an option “BUILD_TEST_APP” set to ON OPTION(BUILD_TEST_APP "Build test_app. fdx? (Test application)" ON) #If the “BUILD_TEST_APP” is set add the extension directory to be built IF (BUILD_TEST_APP) SUBDIRS (test_app) ENDIF (BUILD_TEST_APP) Souheil Ben Ayed, Sebastien Decugis March 10, 2010 32
Create a CMake. File for your extension 3) Add a CMake. List. txt file to the extension. p Example : (CMake. List. txt for test_app) # The Test Diameter Application extension PROJECT("Test Diameter Application" C) # Parser files BISON_FILE(ta_conf. y) FLEX_FILE(ta_conf. l) SET_SOURCE_FILES_PROPERTIES(lex. ta_conf. c ta_conf. tab. c PROPERTIES COMPILE_FLAGS "-I ${CMAKE_CURRENT_SOURCE_DIR}") # List of source files SET( APP_TEST_SRC test_app. h test_app. c lex. ta_conf. c ta_conf. tab. h ta_sig. c ta_dict. c ta_cli. c ta_serv. c ) # Compile as a module FD_ADD_EXTENSION(test_app ${APP_TEST_SRC}) Souheil Ben Ayed, Sebastien Decugis March 10, 2010 33
Add extension to be loaded and build 4) Add extension to be loaded by free. Diameter daemon, (free. Diameter configuration file) # Extension without configuration file Load. Extension = "extensions/test_app. fdx"; # Extension with a configuration file Load. Extension = "extensions/test_app. fdx": " extensions/test_app. conf"; 5) Then generate Makefiles and Build: cmake command or cmake-gui Souheil Ben Ayed, Sebastien Decugis March 10, 2010 34
Questions ? ? ? Next >>> Demonstration Souheil Ben Ayed, Sebastien Decugis March 10, 2010 35
- Slides: 35