diff options
author | Alberto Compagno <acompagn+fdio@cisco.com> | 2019-11-15 08:58:23 +0000 |
---|---|---|
committer | Alberto Compagno <acompagn+fdio@cisco.com> | 2019-11-20 07:58:12 +0000 |
commit | 4eb89ea4dcad4c01664b5331745f4e9a38facbd2 (patch) | |
tree | f4c6935249f6461a03886ab89532e5563db1f75f /ctrl/libhicnctrl | |
parent | 40fde5ad542c30e59ac02639e29389085de89de5 (diff) |
[HICN-394] Add route commands add, list, del for the hicn-plugin
Signed-off-by: Alberto Compagno <acompagn+fdio@cisco.com>
Change-Id: I41641f6d27babaa1c413ecf2fe6eae0e499df97d
Diffstat (limited to 'ctrl/libhicnctrl')
-rw-r--r-- | ctrl/libhicnctrl/CMakeLists.txt | 16 | ||||
-rw-r--r-- | ctrl/libhicnctrl/includes/hicn/ctrl/api.h | 341 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/CMakeLists.txt | 61 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/api.c | 8 | ||||
-rw-r--r-- | ctrl/libhicnctrl/src/hicn_plugin_api.c | 1186 |
5 files changed, 1404 insertions, 208 deletions
diff --git a/ctrl/libhicnctrl/CMakeLists.txt b/ctrl/libhicnctrl/CMakeLists.txt index 960eb6743..43d120473 100644 --- a/ctrl/libhicnctrl/CMakeLists.txt +++ b/ctrl/libhicnctrl/CMakeLists.txt @@ -35,7 +35,11 @@ set(CMAKE_MACOSX_RPATH ON) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - find_package_wrapper(Libhicn REQUIRED) + if (BUILD_CTRL_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + find_package_wrapper(HicnPlugin REQUIRED) + else () + find_package_wrapper(Libhicn REQUIRED) + endif() set(HICNCTRL hicnctrl) set(LIBHICNCTRL hicnctrl) @@ -48,6 +52,16 @@ else() list(APPEND DEPENDENCIES ${LIBHICN_STATIC} ) + elseif (BUILD_CTRL_HICNPLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + set(HICN_INCLUDE_DIRS + ${HICN_INCLUDE_DIRS} + ${HICNPLUGIN_INCLUDE_DIRS}) + + set(HICN_LIBRARIES ${HICNPLUGIN_LIBRARIES}) + + list(APPEND DEPENDENCIES + hicn_plugin + ) else () set(HICN_LIBRARIES ${LIBHICN_SHARED}) list(APPEND DEPENDENCIES diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index c9c2f0da8..b6d2686b7 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h @@ -51,9 +51,9 @@ * NOTES: * * - Different extensions of the forwarder functionalities bring both new API - * calls, and new object attributes. While it is expected that the former will - * only raised NACK answers because of unsupported API calls, the latter will - * certainly trigger incompatibilities. It is expected that the forwarder + * calls, and new object attributes. While it is expected that the former + * will only raised NACK answers because of unsupported API calls, the latter + * will certainly trigger incompatibilities. It is expected that the forwarder * validates the message length and returns a NACK too. In that case, we * provide a set of defines to preserve backwards compatibility. At the * moment, those defines are : @@ -77,25 +77,30 @@ #define HOTFIXMARGIN 0 /* Helper for avoiding warnings about type-punning */ +#ifndef UNION_CAST #define UNION_CAST(x, destType) \ - (((union {__typeof__(x) a; destType b;})x).b) - + (((union { \ + __typeof__(x) a; \ + destType b; \ + })x) \ + .b) +#endif /****************************************************************************** * Message helper types and aliases ******************************************************************************/ #define foreach_command \ - _(UNDEFINED) \ - _(CREATE) \ - _(UPDATE) \ - _(DELETE) \ - _(LIST) \ - _(SET) \ - _(N) + _(UNDEFINED) \ + _(CREATE) \ + _(UPDATE) \ + _(DELETE) \ + _(LIST) \ + _(SET) \ + _(N) typedef enum { -#define _(x) ACTION_ ## x, -foreach_command +#define _(x) ACTION_##x, + foreach_command #undef _ } hc_action_t; @@ -115,33 +120,32 @@ typedef int (*data_callback_t)(struct hc_data_s *, void *); * \brief Holds the results of an hICN control request */ typedef struct hc_data_s { - size_t size; - size_t max_size_log; - size_t in_element_size; - size_t out_element_size; - u8 command_id; /**< Expected message type (should give element size) */ - u8 * buffer; - bool complete; - - /* Callbacks */ - data_callback_t complete_cb; // XXX int (*complete_cb)(struct hc_data_s * data); - void * complete_cb_data; - int ret; + size_t size; + size_t current; + size_t max_size_log; + size_t in_element_size; + size_t out_element_size; + u8 command_id; /**< Expected message type (should give element size) */ + u8 *buffer; + bool complete; + + /* Callbacks */ + data_callback_t complete_cb; // XXX int (*complete_cb)(struct hc_data_s * data); + void *complete_cb_data; + int ret; } hc_data_t; /** * Create a structure holding the results of an hICN control request. * \result The newly create data structure. */ -hc_data_t * -hc_data_create(size_t in_element_size, size_t out_element_size); +hc_data_t *hc_data_create(size_t in_element_size, size_t out_element_size); /** * Free a structure holding the results of an hICN control request. * \param [in] data - The data structure to free. */ -void -hc_data_free(hc_data_t * data); +void hc_data_free(hc_data_t *data); /** * \brief Adds many new results at the end of the data structure, eventually @@ -154,8 +158,7 @@ hc_data_free(hc_data_t * data); * NOTE: The size of the element should match the one declared at structure * initialization. */ -int -hc_data_push_many(hc_data_t * data, const void * elements, size_t count); +int hc_data_push_many(hc_data_t *data, const void *elements, size_t count); /** * \brief Adds a new result at the end of the data structure, eventually @@ -167,8 +170,7 @@ hc_data_push_many(hc_data_t * data, const void * elements, size_t count); * NOTE: The size of the element should match the one declared at structure * initialization. */ -int -hc_data_push(hc_data_t * data, const void * element); +int hc_data_push(hc_data_t *data, const void *element); /** * \brief Configure a callback (along with private data) to be called upon @@ -177,8 +179,7 @@ hc_data_push(hc_data_t * data, const void * element); * \param [in] cb - Callback function * \param [in] cb_data - Callback private data */ -int -hc_data_set_callback(hc_data_t * data, data_callback_t cb, void * cb_data); +int hc_data_set_callback(hc_data_t *data, data_callback_t cb, void *cb_data); /** * \brief Mark the data structure as complete. @@ -187,16 +188,14 @@ hc_data_set_callback(hc_data_t * data, data_callback_t cb, void * cb_data); * returned if the callback executed successfully, or if no callback were * defined. */ -int -hc_data_set_complete(hc_data_t * data); +int hc_data_set_complete(hc_data_t *data); /** * \brief Reset the data structure holding control data * \param [in] data - hICN control data * \return Error code */ -int -hc_data_reset(hc_data_t * data); +int hc_data_reset(hc_data_t *data); /** * \brief Find en element in the data structure @@ -242,33 +241,33 @@ typedef struct hc_sock_s hc_sock_t; * \param [in] url - The URL to connect to. * \return an hICN control socket */ -hc_sock_t * hc_sock_create_url(const char * url); +hc_sock_t *hc_sock_create_url(const char *url); /** * \brief Create an hICN control socket using the default connection type. * \return an hICN control socket */ -hc_sock_t * hc_sock_create(void); +hc_sock_t *hc_sock_create(void); /** * \brief Frees an hICN control socket * \param [in] s - hICN control socket */ -void hc_sock_free(hc_sock_t * s); +void hc_sock_free(hc_sock_t *s); /** * \brief Returns the next available sequence number to use for requests to the * API. * \param [in] s - hICN control socket */ -int hc_sock_get_next_seq(hc_sock_t * s); +int hc_sock_get_next_seq(hc_sock_t *s); /** * \brief Sets the socket as non-blocking * \param [in] s - hICN control socket * \return Error code */ -int hc_sock_set_nonblocking(hc_sock_t * s); +int hc_sock_set_nonblocking(hc_sock_t *s); /** * \brief Return the file descriptor associated to the hICN contorl sock @@ -276,14 +275,13 @@ int hc_sock_set_nonblocking(hc_sock_t * s); * \return The file descriptor (positive value), or a negative integer in case * of error */ -int hc_sock_get_fd(hc_sock_t * s); +int hc_sock_get_fd(hc_sock_t *s); /** * \brief Connect the socket * \return Error code */ -int -hc_sock_connect(hc_sock_t * s); +int hc_sock_connect(hc_sock_t *s); /** * \brief Return the offset and size of available buffer space @@ -292,7 +290,7 @@ hc_sock_connect(hc_sock_t * s); * \param [out] size - Remaining size * \return Error code */ -int hc_sock_get_available(hc_sock_t * s, u8 ** buffer, size_t * size); +int hc_sock_get_available(hc_sock_t *s, u8 **buffer, size_t *size); /** * \brief Write/read iexchance on the control socket (internal helper function) @@ -301,14 +299,14 @@ int hc_sock_get_available(hc_sock_t * s, u8 ** buffer, size_t * size); * \param [in] msglen - Length of the message to send * \return Error code */ -int hc_sock_send(hc_sock_t * s, hc_msg_t * msg, size_t msglen, int seq); +int hc_sock_send(hc_sock_t *s, hc_msg_t *msg, size_t msglen, int seq); /** * \brief Helper for reading socket contents * \param [in] s - hICN control socket * \return Error code */ -int hc_sock_recv(hc_sock_t * s); +int hc_sock_recv(hc_sock_t *s); /** * \brief Processing data received by socket @@ -317,21 +315,21 @@ int hc_sock_recv(hc_sock_t * s); * types, or NULL not to perform any translation. * \return Error code */ -int hc_sock_process(hc_sock_t * s, hc_data_t ** data); +int hc_sock_process(hc_sock_t *s, hc_data_t **data); /** * \brief Callback used in async mode when data is available on the socket * \param [in] s - hICN control socket * \return Error code */ -int hc_sock_callback(hc_sock_t * s, hc_data_t ** data); +int hc_sock_callback(hc_sock_t *s, hc_data_t **data); /** * \brief Reset the state of the sock (eg. to handle a reconnecton) * \param [in] s - hICN control socket * \return Error code */ -int hc_sock_reset(hc_sock_t * s); +int hc_sock_reset(hc_sock_t *s); /****************************************************************************** * Command-specific structures and functions @@ -391,54 +389,52 @@ int hc_sock_reset(hc_sock_t * s); #define MAXSZ_HC_ID_ 10 /* Number of digits for MAX_INT */ #define MAXSZ_HC_ID MAXSZ_HC_ID_ + NULLTERM - -#define foreach_type(TYPE, VAR, data) \ - for (TYPE * VAR = (TYPE*)data->buffer; \ - VAR < (TYPE*)(data->buffer + data->size * data->out_element_size); \ - VAR++) +#define foreach_type(TYPE, VAR, data) \ + for (TYPE *VAR = (TYPE *)data->buffer; \ + VAR < (TYPE *)(data->buffer + data->size * data->out_element_size); \ + VAR++) /** * New type is defined to reconciliate different enum for add and list. * Also, values not implemented have been removed for clarity. */ #define foreach_connection_type \ - _(UNDEFINED) \ - _(TCP) \ - _(UDP) \ - _(HICN) \ - _(N) + _(UNDEFINED) \ + _(TCP) \ + _(UDP) \ + _(HICN) \ + _(N) typedef enum { -#define _(x) CONNECTION_TYPE_ ## x, -foreach_connection_type +#define _(x) CONNECTION_TYPE_##x, + foreach_connection_type #undef _ } hc_connection_type_t; #define MAXSZ_HC_CONNECTION_TYPE_ 9 #define MAXSZ_HC_CONNECTION_TYPE MAXSZ_HC_CONNECTION_TYPE_ + NULLTERM + HOTFIXMARGIN -extern const char * connection_type_str[]; +extern const char *connection_type_str[]; -hc_connection_type_t -connection_type_from_str(const char * str); +hc_connection_type_t connection_type_from_str(const char *str); /* Same order as connection_state_t in hicn/core/connectionState.h */ #define foreach_connection_state \ - _(UNDEFINED) \ - _(DOWN) \ - _(UP) \ - _(N) + _(UNDEFINED) \ + _(DOWN) \ + _(UP) \ + _(N) typedef enum { -#define _(x) HC_CONNECTION_STATE_ ## x, -foreach_connection_state +#define _(x) HC_CONNECTION_STATE_##x, + foreach_connection_state #undef _ } hc_connection_state_t; #define MAXSZ_HC_CONNECTION_STATE_ 9 #define MAXSZ_HC_CONNECTION_STATE MAXSZ_HC_CONNECTION_STATE_ + NULLTERM -extern const char * connection_state_str[]; +extern const char *connection_state_str[]; typedef int (*HC_PARSE)(const u8 *, u8 *); @@ -448,34 +444,35 @@ typedef int (*HC_PARSE)(const u8 *, u8 *); // FIXME the listener should not require any port for hICN... typedef struct { - char name[SYMBOLIC_NAME_LEN]; /* K.w */ // XXX clarify what used for - char interface_name[INTERFACE_LEN]; /* Kr. */ - u32 id; - hc_connection_type_t type; /* .rw */ - int family; /* .rw */ - ip_address_t local_addr; /* .rw */ - u16 local_port; /* .rw */ + char name[SYMBOLIC_NAME_LEN]; /* K.w */ // XXX clarify what used for + char interface_name[INTERFACE_LEN]; /* Kr. */ + u32 id; + hc_connection_type_t type; /* .rw */ + int family; /* .rw */ + ip_address_t local_addr; /* .rw */ + u16 local_port; /* .rw */ } hc_listener_t; -int hc_listener_create(hc_sock_t * s, hc_listener_t * listener); +int hc_listener_create(hc_sock_t *s, hc_listener_t *listener); /* listener_found might eventually be allocated, and needs to be freed */ -int hc_listener_get(hc_sock_t * s, hc_listener_t * listener, - hc_listener_t ** listener_found); -int hc_listener_delete(hc_sock_t * s, hc_listener_t * listener); -int hc_listener_list(hc_sock_t * s, hc_data_t ** pdata); +int hc_listener_get(hc_sock_t *s, hc_listener_t *listener, + hc_listener_t **listener_found); +int hc_listener_delete(hc_sock_t *s, hc_listener_t *listener); +int hc_listener_list(hc_sock_t *s, hc_data_t **pdata); -int hc_listener_validate(const hc_listener_t * listener); -int hc_listener_cmp(const hc_listener_t * l1, const hc_listener_t * l2); -int hc_listener_parse(void * in, hc_listener_t * listener); +int hc_listener_validate(const hc_listener_t *listener); +int hc_listener_cmp(const hc_listener_t *l1, const hc_listener_t *l2); +int hc_listener_parse(void *in, hc_listener_t *listener); #define foreach_listener(VAR, data) foreach_type(hc_listener_t, VAR, data) -#define MAXSZ_HC_LISTENER_ INTERFACE_LEN + SPACE + MAXSZ_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ +#define MAXSZ_HC_LISTENER_ \ + INTERFACE_LEN + SPACE + MAXSZ_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ #define MAXSZ_HC_LISTENER MAXSZ_HC_LISTENER_ + NULLTERM GENERATE_FIND_HEADER(listener); -int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener); +int hc_listener_snprintf(char *s, size_t size, hc_listener_t *listener); /*----------------------------------------------------------------------------* * Connections @@ -487,16 +484,16 @@ int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener); * not itself used to create connections. */ typedef struct { - u32 id; /* Kr. */ - char name[SYMBOLIC_NAME_LEN]; /* K.w */ - char interface_name[INTERFACE_LEN]; /* Kr. */ - hc_connection_type_t type; /* .rw */ - int family; /* .rw */ - ip_address_t local_addr; /* .rw */ - u16 local_port; /* .rw */ - ip_address_t remote_addr; /* .rw */ - u16 remote_port; /* .rw */ - hc_connection_state_t admin_state; /* .rw */ + u32 id; /* Kr. */ + char name[SYMBOLIC_NAME_LEN]; /* K.w */ + char interface_name[INTERFACE_LEN]; /* Kr. */ + hc_connection_type_t type; /* .rw */ + int family; /* .rw */ + ip_address_t local_addr; /* .rw */ + u16 local_port; /* .rw */ + ip_address_t remote_addr; /* .rw */ + u16 remote_port; /* .rw */ + hc_connection_state_t admin_state; /* .rw */ #ifdef WITH_POLICY uint32_t priority; /* .rw */ policy_tags_t tags; /* .rw */ @@ -504,25 +501,24 @@ typedef struct { hc_connection_state_t state; /* .r. */ } hc_connection_t; - -int hc_connection_create(hc_sock_t * s, hc_connection_t * connection); +int hc_connection_create(hc_sock_t *s, hc_connection_t *connection); /* connection_found will be allocated, and must be freed */ -int hc_connection_get(hc_sock_t * s, hc_connection_t * connection, - hc_connection_t ** connection_found); -int hc_connection_update_by_id(hc_sock_t * s, int hc_connection_id, - hc_connection_t * connection); -int hc_connection_update(hc_sock_t * s, hc_connection_t * connection_current, - hc_connection_t * connection_updated); -int hc_connection_delete(hc_sock_t * s, hc_connection_t * connection); +int hc_connection_get(hc_sock_t *s, hc_connection_t *connection, + hc_connection_t **connection_found); +int hc_connection_update_by_id(hc_sock_t *s, int hc_connection_id, + hc_connection_t *connection); +int hc_connection_update(hc_sock_t *s, hc_connection_t *connection_current, + hc_connection_t *connection_updated); +int hc_connection_delete(hc_sock_t *s, hc_connection_t *connection); /* int hc_connection_remove_by_id(hc_sock_t * s, char * name); int hc_connection_remove_by_name(hc_sock_t * s, char * name); */ -int hc_connection_list(hc_sock_t * s, hc_data_t ** pdata); +int hc_connection_list(hc_sock_t *s, hc_data_t **pdata); -int hc_connection_validate(const hc_connection_t * connection); -int hc_connection_cmp(const hc_connection_t * c1, const hc_connection_t * c2); -int hc_connection_parse(void * in, hc_connection_t * connection); +int hc_connection_validate(const hc_connection_t *connection); +int hc_connection_cmp(const hc_connection_t *c1, const hc_connection_t *c2); +int hc_connection_parse(void *in, hc_connection_t *connection); int hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); #ifdef WITH_POLICY @@ -531,14 +527,15 @@ int hc_connection_set_priority(hc_sock_t * s, const char * conn_id_or_name, uint #define foreach_connection(VAR, data) foreach_type(hc_connection_t, VAR, data) -#define MAXSZ_HC_CONNECTION_ MAXSZ_HC_CONNECTION_STATE_ + \ - INTERFACE_LEN + SPACE + \ - 2 * MAXSZ_URL_ + MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) +#define MAXSZ_HC_CONNECTION_ \ + MAXSZ_HC_CONNECTION_STATE_ + INTERFACE_LEN + SPACE + 2 * MAXSZ_URL_ + \ + MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) #define MAXSZ_HC_CONNECTION MAXSZ_HC_CONNECTION_ + NULLTERM GENERATE_FIND_HEADER(connection); -int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection); +int hc_connection_snprintf(char *s, size_t size, + const hc_connection_t *connection); /*----------------------------------------------------------------------------* * Faces @@ -551,10 +548,10 @@ int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connec *----------------------------------------------------------------------------*/ typedef struct { - u8 id; - char name[SYMBOLIC_NAME_LEN]; - face_t face; // or embed ? - //face_id_t parent; /* Pointer from connection to listener */ + u8 id; + char name[SYMBOLIC_NAME_LEN]; + face_t face; // or embed ? + // face_id_t parent; /* Pointer from connection to listener */ } hc_face_t; /** @@ -565,11 +562,11 @@ typedef struct { * * The face parameters will be updated with the face ID. */ -int hc_face_create(hc_sock_t * s, hc_face_t * face); -int hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found); -int hc_face_delete(hc_sock_t * s, hc_face_t * face); -int hc_face_list(hc_sock_t * s, hc_data_t ** pdata); -int hc_face_list_async(hc_sock_t * s); //, hc_data_t ** pdata); +int hc_face_create(hc_sock_t *s, hc_face_t *face); +int hc_face_get(hc_sock_t *s, hc_face_t *face, hc_face_t **face_found); +int hc_face_delete(hc_sock_t *s, hc_face_t *face); +int hc_face_list(hc_sock_t *s, hc_data_t **pdata); +int hc_face_list_async(hc_sock_t *s); //, hc_data_t ** pdata); #define foreach_face(VAR, data) foreach_type(hc_face_t, VAR, data) @@ -582,21 +579,21 @@ int hc_face_list_async(hc_sock_t * s); //, hc_data_t ** pdata); #define MAXSZ_HC_FACE_ MAXSZ_FACE_ID_ + MAXSZ_FACE_NAME_ + MAXSZ_FACE_ + 5 + HOTFIXMARGIN #define MAXSZ_HC_FACE MAXSZ_HC_FACE_ + NULLTERM -int hc_face_snprintf(char * s, size_t size, hc_face_t * face); +int hc_face_snprintf(char *s, size_t size, hc_face_t *face); /*----------------------------------------------------------------------------* * Routes *----------------------------------------------------------------------------*/ typedef struct { - u8 face_id; /* Kr. */ - int family; /* Krw */ - ip_address_t remote_addr; /* krw */ - u8 len; /* krw */ - u16 cost; /* .rw */ + u8 face_id; /* Kr. */ + int family; /* Krw */ + ip_address_t remote_addr; /* krw */ + u8 len; /* krw */ + u16 cost; /* .rw */ } hc_route_t; -int hc_route_parse(void * in, hc_route_t * route); +int hc_route_parse(void *in, hc_route_t *route); int hc_route_create(hc_sock_t * s, hc_route_t * route); int hc_route_delete(hc_sock_t * s, hc_route_t * route); @@ -610,31 +607,32 @@ int hc_route_list_async(hc_sock_t * s); #define MAX_LEN 255 #define MAXSZ_LEN 3 -#define MAXSZ_HC_ROUTE_ MAXSZ_FACE_ID + 1 + MAXSZ_COST + 1 + MAXSZ_IP_ADDRESS + 1 + MAXSZ_LEN +#define MAXSZ_HC_ROUTE_ \ + MAXSZ_FACE_ID + 1 + MAXSZ_COST + 1 + MAXSZ_IP_ADDRESS + 1 + MAXSZ_LEN #define MAXSZ_HC_ROUTE MAXSZ_HC_ROUTE_ + NULLTERM -int hc_route_snprintf(char * s, size_t size, hc_route_t * route); - +int hc_route_snprintf(char *s, size_t size, hc_route_t *route); /*----------------------------------------------------------------------------* * Punting *----------------------------------------------------------------------------*/ typedef struct { - u8 face_id; /* Kr. */ // XXX listener id, could be NULL for all ? - int family; /* Krw */ - ip_address_t prefix; /* krw */ - u8 prefix_len; /* krw */ + u8 face_id; /* Kr. */ // XXX listener id, could be NULL for all ? + int family; /* Krw */ + ip_address_t prefix; /* krw */ + u8 prefix_len; /* krw */ } hc_punting_t; -int hc_punting_create(hc_sock_t * s, hc_punting_t * punting); -int hc_punting_get(hc_sock_t * s, hc_punting_t * punting, hc_punting_t ** punting_found); -int hc_punting_delete(hc_sock_t * s, hc_punting_t * punting); -int hc_punting_list(hc_sock_t * s, hc_data_t ** pdata); +int hc_punting_create(hc_sock_t *s, hc_punting_t *punting); +int hc_punting_get(hc_sock_t *s, hc_punting_t *punting, + hc_punting_t **punting_found); +int hc_punting_delete(hc_sock_t *s, hc_punting_t *punting); +int hc_punting_list(hc_sock_t *s, hc_data_t **pdata); -int hc_punting_validate(const hc_punting_t * punting); -int hc_punting_cmp(const hc_punting_t * c1, const hc_punting_t * c2); -int hc_punting_parse(void * in, hc_punting_t * punting); +int hc_punting_validate(const hc_punting_t *punting); +int hc_punting_cmp(const hc_punting_t *c1, const hc_punting_t *c2); +int hc_punting_parse(void *in, hc_punting_t *punting); #define foreach_punting(VAR, data) foreach_type(hc_punting_t, VAR, data) @@ -643,15 +641,14 @@ int hc_punting_parse(void * in, hc_punting_t * punting); GENERATE_FIND_HEADER(punting); -int hc_punting_snprintf(char * s, size_t size, hc_punting_t * punting); - +int hc_punting_snprintf(char *s, size_t size, hc_punting_t *punting); /*----------------------------------------------------------------------------* * Cache *----------------------------------------------------------------------------*/ -int hc_cache_set_store(hc_sock_t * s, int enabled); -int hc_cache_set_serve(hc_sock_t * s, int enabled); +int hc_cache_set_store(hc_sock_t *s, int enabled); +int hc_cache_set_serve(hc_sock_t *s, int enabled); /*----------------------------------------------------------------------------* * Strategy @@ -660,36 +657,36 @@ int hc_cache_set_serve(hc_sock_t * s, int enabled); #define MAXSZ_STRATEGY_NAME 255 typedef struct { - char name[MAXSZ_STRATEGY_NAME]; + char name[MAXSZ_STRATEGY_NAME]; } hc_strategy_t; -int hc_strategy_list(hc_sock_t * s, hc_data_t ** data); +int hc_strategy_list(hc_sock_t *s, hc_data_t **data); #define foreach_strategy(VAR, data) foreach_type(hc_strategy_t, VAR, data) #define MAXSZ_HC_STRATEGY_ MAXSZ_STRATEGY_NAME #define MAXSZ_HC_STRATEGY MAXSZ_HC_STRATEGY_ + NULLTERM -int hc_strategy_snprintf(char * s, size_t size, hc_strategy_t * strategy); +int hc_strategy_snprintf(char *s, size_t size, hc_strategy_t *strategy); // per prefix -int hc_strategy_set(hc_sock_t * s /* XXX */); +int hc_strategy_set(hc_sock_t *s /* XXX */); /*----------------------------------------------------------------------------* * WLDR *----------------------------------------------------------------------------*/ // per connection -int hc_wldr_set(hc_sock_t * s /* XXX */); +int hc_wldr_set(hc_sock_t *s /* XXX */); /*----------------------------------------------------------------------------* * MAP-Me *----------------------------------------------------------------------------*/ -int hc_mapme_set(hc_sock_t * s, int enabled); -int hc_mapme_set_discovery(hc_sock_t * s, int enabled); -int hc_mapme_set_timescale(hc_sock_t * s, double timescale); -int hc_mapme_set_retx(hc_sock_t * s, double timescale); +int hc_mapme_set(hc_sock_t *s, int enabled); +int hc_mapme_set_discovery(hc_sock_t *s, int enabled); +int hc_mapme_set_timescale(hc_sock_t *s, double timescale); +int hc_mapme_set_retx(hc_sock_t *s, double timescale); /*----------------------------------------------------------------------------* * Policies @@ -698,17 +695,17 @@ int hc_mapme_set_retx(hc_sock_t * s, double timescale); #ifdef WITH_POLICY typedef struct { - int family; /* Krw */ - ip_address_t remote_addr; /* krw */ - u8 len; /* krw */ - policy_t policy; /* .rw */ + int family; /* Krw */ + ip_address_t remote_addr; /* krw */ + u8 len; /* krw */ + policy_t policy; /* .rw */ } hc_policy_t; -int hc_policy_parse(void * in, hc_policy_t * policy); +int hc_policy_parse(void *in, hc_policy_t *policy); -int hc_policy_create(hc_sock_t * s, hc_policy_t * policy); -int hc_policy_delete(hc_sock_t * s, hc_policy_t * policy); -int hc_policy_list(hc_sock_t * s, hc_data_t ** pdata); +int hc_policy_create(hc_sock_t *s, hc_policy_t *policy); +int hc_policy_delete(hc_sock_t *s, hc_policy_t *policy); +int hc_policy_list(hc_sock_t *s, hc_data_t **pdata); #define foreach_policy(VAR, data) foreach_type(hc_policy_t, VAR, data) @@ -716,7 +713,7 @@ int hc_policy_list(hc_sock_t * s, hc_data_t ** pdata); #define MAXSZ_HC_POLICY_ 0 #define MAXSZ_HC_POLICY MAXSZ_HC_POLICY_ + NULLTERM -int hc_policy_snprintf(char * s, size_t size, hc_policy_t * policy); +int hc_policy_snprintf(char *s, size_t size, hc_policy_t *policy); #endif /* WITH_POLICY */ diff --git a/ctrl/libhicnctrl/src/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index ea63217dd..14c204dda 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -26,11 +26,22 @@ set(UTIL_HEADER_FILES ) set(SOURCE_FILES - api.c face.c route.c ) +if(BUILD_CTRL_HICNPLUGIN) + set(SOURCE_FILES + ${SOURCE_FILES} + hicn_plugin_api.c + ) +else () + set(SOURCE_FILES + ${SOURCE_FILES} + api.c + ) +endif() + set(LIBRARIES m ${HICN_LIBRARIES} @@ -42,43 +53,37 @@ set(INCLUDE_DIRS ${HICN_INCLUDE_DIRS} ) +# Android requires static libraries if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") - set(HICN_LIBRARIES ${LIBHICN_STATIC} log) - build_library(${LIBHICNCTRL} - STATIC - SOURCES ${SOURCE_FILES} - INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} - LINK_LIBRARIES ${LIBRARIES} - DEPENDS ${LIBHICN_STATIC} - COMPONENT ${LIBHICNCTRL_COMPONENT} - DEPENDS ${LIBHICN_STATIC} - INCLUDE_DIRS ${INCLUDE_DIRS} - INSTALL_ROOT_DIR hicn - DEFINITIONS ${COMPILER_DEFINITIONS} - ) + set(LIBRARIES ${LIBRARIES} ${LIBHICN_STATIC}) + set(LINK_TYPE STATIC) else () - build_library(${LIBHICNCTRL} - SHARED STATIC - SOURCES ${SOURCE_FILES} - INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} - LINK_LIBRARIES ${LIBRARIES} - DEPENDS ${LIBHICN_SHARED} - COMPONENT ${LIBHICNCTRL_COMPONENT} - DEPENDS ${LIBHICN_SHARED} - INCLUDE_DIRS ${INCLUDE_DIRS} - INSTALL_ROOT_DIR hicn - DEFINITIONS ${COMPILER_DEFINITIONS} - ) + set(LINK_TYPE SHARED STATIC) endif () +build_library(${LIBHICNCTRL} + ${LINK_TYPE} + SOURCES ${SOURCE_FILES} + INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} + LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${DEPENDENCIES} + COMPONENT ${LIBHICNCTRL_COMPONENT} + INCLUDE_DIRS ${INCLUDE_DIRS} + INSTALL_ROOT_DIR hicn + DEFINITIONS ${COMPILER_DEFINITIONS} +) + if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android" AND NOT COMPILE_FOR_IOS) + set(LIBRARIES ${LIBRARIES} ${LIBHICN_SHARED} ${LIBHICNCTRL_SHARED}) + list(APPEND DAEMON_SRC cli.c ) + build_executable(${HICNCTRL} SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${LIBHICNCTRL_SHARED} ${LIBHICN_SHARED} - DEPENDS ${LIBHICNCTRL_SHARED} ${LIBHICN_SHARED} + LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${LIBHICNCTRL_SHARED} COMPONENT ${LIBHICNCTRL_COMPONENT} INCLUDE_DIRS ${INCLUDE_DIRS} DEFINITIONS ${COMPILER_DEFINITIONS} diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 14ee69b53..5afecf7e6 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -91,7 +91,6 @@ struct hc_sock_s { hc_sock_request_t * hc_sock_request_create(int seq, hc_data_t * data, HC_PARSE parse) { - assert(seq >= 0); assert(data); hc_sock_request_t * request = malloc(sizeof(hc_sock_request_t)); @@ -851,11 +850,7 @@ hc_execute_command(hc_sock_t * s, hc_msg_t * msg, size_t msg_len, } int seq = hc_sock_get_next_seq(s); - if (seq < 0) { - ERROR("[hc_execute_command] Could not get next sequence number"); - goto ERR_SEQ; - } - + /* Create state used to process the request */ hc_sock_request_t * request = NULL; request = hc_sock_request_create(seq, data, params->parse); @@ -902,7 +897,6 @@ ERR_PROCESS: ERR_MAP: hc_sock_request_free(request); ERR_REQUEST: -ERR_SEQ: hc_data_free(data); ERR_DATA: return -1; diff --git a/ctrl/libhicnctrl/src/hicn_plugin_api.c b/ctrl/libhicnctrl/src/hicn_plugin_api.c new file mode 100644 index 000000000..7dbd88771 --- /dev/null +++ b/ctrl/libhicnctrl/src/hicn_plugin_api.c @@ -0,0 +1,1186 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file api.c + * \brief Implementation of hICN control library API + */ + +#include <assert.h> // assert +#include <fcntl.h> // fcntl +#include <math.h> // log2 +#include <stdbool.h> +#include <stdio.h> // snprintf +#include <string.h> // memmove, strcasecmp +#include <sys/socket.h> // socket +#include <unistd.h> // close, fcntl + +#include <hicn/ctrl/api.h> +#include <hicn/ctrl/commands.h> +#include <hicn/util/token.h> +#include <strings.h> +#include <vapi/hicn.api.vapi.h> +#include <hicn/util/log.h> +#include <hicn/util/map.h> + +#define APP_NAME "hicn_plugin" +#define MAX_OUTSTANDING_REQUESTS 4 +#define RESPONSE_QUEUE_SIZE 2 + +DEFINE_VAPI_MSG_IDS_HICN_API_JSON + +/* + * Internal state associated to a pending request + */ +typedef struct { + int seq; + // Reusing the buffer of data to hold both the unparsed response from the + // forwarder and the result of the parsing + hc_data_t *data; + /* Information used to process results */ + int size_in; + HC_PARSE parse; +} hc_sock_request_t; + +/** + * Messages to the forwarder might be multiplexed thanks to the seqNum fields in + * the header_control_message structure. The forwarder simply answers back the + * original sequence number. We maintain a map of such sequence number to + * outgoing queries so that replied can be demultiplexed and treated + * appropriately. + */ +TYPEDEF_MAP_H(hc_sock_map, int, hc_sock_request_t *); +TYPEDEF_MAP(hc_sock_map, int, hc_sock_request_t *, int_cmp, int_snprintf, + generic_snprintf); + +struct hc_sock_s { + vapi_ctx_t g_vapi_ctx_instance; + char *url; + int fd; + + size_t roff; /**< Read offset */ + size_t woff; /**< Write offset */ + u32 buffer[RECV_BUFLEN]; + /* Next sequence number to be used for requests */ + int seq; + + bool async; + hc_sock_map_t *map; +}; + +hc_sock_request_t *hc_sock_request_create(int seq, hc_data_t *data, + HC_PARSE parse) { + assert(data); + + hc_sock_request_t *request = malloc(sizeof(hc_sock_request_t)); + if (!request) return NULL; + request->seq = seq; + request->data = data; + request->parse = parse; + request->size_in = 0; + return request; +} + +void hc_sock_request_free(hc_sock_request_t *request) { free(request); } + +/****************************************************************************** + * Message helper types and aliases + ******************************************************************************/ + +#define foreach_hc_command \ + _(hicn_api_node_params_set) \ + _(hicn_api_node_params_set_reply) \ + _(hicn_api_node_params_get_reply) \ + _(hicn_api_node_stats_get_reply) \ + _(hicn_api_face_ip_add) \ + _(hicn_api_face_ip_add_reply) \ + _(hicn_api_face_ip_del) \ + _(hicn_api_face_ip_del_reply) \ + _(hicn_api_face_ip_params_get) \ + _(hicn_api_face_stats_details) \ + _(hicn_api_face_ip_params_get_reply) \ + _(hicn_api_route_nhops_add) \ + _(hicn_api_route_nhops_add_reply) \ + _(hicn_api_route_del) \ + _(hicn_api_route_del_reply) \ + _(hicn_api_route_nhop_del) \ + _(hicn_api_route_nhop_del_reply) \ + _(hicn_api_route_get) \ + _(hicn_api_route_get_reply) \ + _(hicn_api_routes_details) \ + _(hicn_api_strategies_get_reply) \ + _(hicn_api_strategy_get) \ + _(hicn_api_strategy_get_reply) \ + _(hicn_api_punting_add) \ + _(hicn_api_punting_add_reply) \ + _(hicn_api_punting_del) \ + _(hicn_api_punting_del_reply) + +typedef vapi_type_msg_header2_t hc_msg_header_t; + +typedef union { +#define _(a) vapi_payload_ ## a a; + foreach_hc_command +#undef _ +} hc_msg_payload_t; + +#define IS_DUMP_MSG(a) (a == vapi_msg_id_hicn_api_face_stats_dump || a == vapi_msg_id_hicn_api_routes_dump) + +typedef struct __attribute__ ((__packed__)) { + hc_msg_header_t hdr; + hc_msg_payload_t payload; +} hc_hicnp_t; + +typedef void (* NTOH)(void *msg); + +typedef struct __attribute__((__packed__)) { + hc_sock_t *s; + uint32_t ctx_msg; +} callback_ctx_t; + +typedef struct __attribute__((__packed__)) { + hc_hicnp_t * hicnp_msg; + vapi_cb_t callback; + callback_ctx_t *callback_ctx; + NTOH ntoh; +} hc_msg_s; + +/****************************************************************************** + * Control Data + ******************************************************************************/ + +hc_data_t *hc_data_create(size_t in_element_size, size_t out_element_size) { + hc_data_t *data = malloc(sizeof(hc_data_t)); + if (!data) goto ERR_MALLOC; + + /* FIXME Could be NULL thanks to realloc provided size is 0 */ + data->in_element_size = in_element_size; + data->out_element_size = out_element_size; + data->size = 0; + data->current = 0; + data->complete = false; + data->command_id = 0; // TODO this could also be a busy mark in the socket + /* No callback needed in blocking code for instance */ + data->complete_cb = NULL; + + return data; + +ERR_MALLOC: + return NULL; +} + +void hc_data_free(hc_data_t *data) { + if (data != NULL) { + if (data->buffer) free(data->buffer); + free(data); + } +} + +/****************************************************************************** + * Control socket + ******************************************************************************/ + +/** + * \brief Parse a connection URL into a sockaddr + * \param [in] url - URL + * \param [out] sa - Resulting struct sockaddr, expected zero'ed. + * \return 0 if parsing succeeded, a negative error value otherwise. + */ +int hc_sock_parse_url(const char *url, struct sockaddr *sa) { + // NOT IMPLEMENTED + return -1; +} + +hc_sock_t *hc_sock_create_url(const char *url) { + // NOT IMPLEMENTED + return NULL; +} + +hc_sock_t *hc_sock_create(void) { + hc_sock_t *s = malloc(sizeof(hc_sock_t)); + memset(s, 0, sizeof(hc_sock_t)); + + s->map = hc_sock_map_create(); + if (!s->map) goto ERR_MAP; + + //By default the socket is blocking -- not async + s->async = 0; + + return s; + +ERR_MAP: + free(s); + return NULL; +} + +void hc_sock_free(hc_sock_t *s) { + hc_sock_request_t **request_array = NULL; + int n = hc_sock_map_get_value_array(s->map, &request_array); + if (n < 0) { + ERROR("Could not retrieve pending request array for freeing up resources"); + } else { + for (unsigned i = 0; i < n; i++) { + hc_sock_request_t *request = request_array[i]; + hc_sock_request_free(request); + } + free(request_array); + } + + hc_sock_map_free(s->map); + if (s->url) free(s->url); + close(s->fd); + free(s); +} + +int hc_sock_get_next_seq(hc_sock_t *s) { + return vapi_gen_req_context(s->g_vapi_ctx_instance); +} + +int hc_sock_set_nonblocking(hc_sock_t *s) { + s->async = 1; + return 0; +} + +int hc_sock_get_fd(hc_sock_t *s) { return 1; } + +vapi_error_e vapi_cb(vapi_ctx_t ctx, void *callback_ctx, vapi_error_e error, bool is_last, void *payload) { + callback_ctx_t *ctx_call = (callback_ctx_t *)callback_ctx; + hc_sock_t *s = ctx_call->s; + + if ((s->woff != s->roff) && (s->woff % RECV_BUFLEN == 0)) { + ERROR("[hc_sock_process] No more space on the buffer to store responces"); + return -1; + } + + if (is_last) { + s->buffer[s->woff % RECV_BUFLEN] = ctx_call->ctx_msg; + s->woff++; + } + + if(!payload) + return 0; + + hc_sock_request_t *request = NULL; + if (hc_sock_map_get(s->map, ctx_call->ctx_msg, &request) < + 0) { + ERROR("[hc_sock_process] Error searching for matching request"); + return -1; + } + + if (request->data->current == request->data->size) { + if (request->data->size == 0){ + request->data->size = 1; + request->data->buffer = malloc(request->data->in_element_size * request->data->size); + } else { + void *tmp = + malloc(request->data->in_element_size * request->data->size * 2); + memcpy(tmp, request->data->buffer, request->data->current * request->data->in_element_size); + free(request->data->buffer); + request->data->size *= 2; + request->data->buffer = tmp; + } + } + memcpy(request->data->buffer + + request->data->current * request->data->in_element_size, + payload, request->data->in_element_size); + request->data->current++; + + return 0; +} + +int hc_sock_connect(hc_sock_t *s) { + if (s->g_vapi_ctx_instance == NULL) { + vapi_error_e rv = vapi_ctx_alloc(&s->g_vapi_ctx_instance); + rv = vapi_connect(s->g_vapi_ctx_instance, APP_NAME, NULL, + MAX_OUTSTANDING_REQUESTS, RESPONSE_QUEUE_SIZE, + s->async ? VAPI_MODE_NONBLOCKING : VAPI_MODE_BLOCKING, true); + if (rv != VAPI_OK) { + vapi_ctx_free(s->g_vapi_ctx_instance); + goto ERR_CONNECT; + } + printf("[hc_sock_connect] *connected %s ok", APP_NAME); + } else { + printf("connection %s keeping", APP_NAME); + } + + return 0; + +ERR_CONNECT: + ERROR("[hc_sock_connect] connection %s failes", APP_NAME); + return -1; +} + +int hc_sock_send(hc_sock_t *s, hc_msg_t *msg, size_t msglen, int seq) { + vapi_cb_t callback = ((hc_msg_s *)msg)->callback; + callback_ctx_t *callback_ctx = ((hc_msg_s *)msg)->callback_ctx; + + if (!msg || !callback) { + return VAPI_EINVAL; + } + if (vapi_is_nonblocking(s->g_vapi_ctx_instance) && vapi_requests_full(s->g_vapi_ctx_instance)) { + return VAPI_EAGAIN; + } + vapi_error_e rv; + if (VAPI_OK != (rv = vapi_producer_lock (s->g_vapi_ctx_instance))) { + return rv; + } + ((hc_msg_s *)msg)->hicnp_msg->hdr.context = seq; + callback_ctx->ctx_msg = seq; + vapi_msg_id_t msg_id = vapi_lookup_vapi_msg_id_t(s->g_vapi_ctx_instance, ((hc_msg_s *)msg)->hicnp_msg->hdr._vl_msg_id); + ((hc_msg_s *)msg)->ntoh(((hc_msg_s *)msg)->hicnp_msg); + if (IS_DUMP_MSG(msg_id)) { + if (VAPI_OK == (rv = vapi_send_with_control_ping (s->g_vapi_ctx_instance, ((hc_msg_s *)msg)->hicnp_msg, seq))) { + vapi_store_request(s->g_vapi_ctx_instance, seq, true, (vapi_cb_t)callback, callback_ctx); + } + } else { + if (VAPI_OK == (rv = vapi_send (s->g_vapi_ctx_instance, ((hc_msg_s *)msg)->hicnp_msg))) { + vapi_store_request(s->g_vapi_ctx_instance, seq, false, (vapi_cb_t)callback, callback_ctx); + } + } + + if (rv != VAPI_OK) { + if (VAPI_OK != vapi_producer_unlock (s->g_vapi_ctx_instance)) { + abort (); /* this really shouldn't happen */ + } + } + return rv; +} + +int hc_sock_get_available(hc_sock_t *s, u8 **buffer, size_t *size) { + // NOT IMPLEMENTED + return -1; +} + +int hc_sock_recv(hc_sock_t *s) { + vapi_error_e rv; + if (VAPI_OK != vapi_producer_unlock (s->g_vapi_ctx_instance)) { + abort (); /* this really shouldn't happen */ + } + if (vapi_is_nonblocking(s->g_vapi_ctx_instance)) { + rv = VAPI_OK; + } else { + rv = vapi_dispatch(s->g_vapi_ctx_instance); + } + + return rv; +} + +int hc_sock_process(hc_sock_t *s, hc_data_t **pdata) { + int err = 0; + int seq = s->buffer[s->roff % RECV_BUFLEN]; + + hc_sock_request_t *request = NULL; + if (hc_sock_map_get(s->map, seq, &request) < 0) { + ERROR("[hc_sock_process] Error searching for matching request"); + return -1; + } + if (!request) { + ERROR("[hc_sock_process] No request matching received sequence number"); + return -1; + } + + if (s->roff == s->woff) { + ERROR("[hc_sock_process] No data received for the corresponding request"); + return -1; + } + + err = request->parse((u8 *)request, NULL); + request->data->complete = 1; + s->roff++; + + if (pdata) *pdata = request->data; + + hc_sock_map_remove(s->map, seq, NULL); + hc_sock_request_free(request); + + return err; +} + +int hc_sock_callback(hc_sock_t *s, hc_data_t **pdata) { + hc_data_t *data = NULL; + + for (;;) { + int n = hc_sock_recv(s); + if (n == 0) { + goto ERR_EOF; + } + if (n < 0) { + switch (errno) { + case ECONNRESET: + case ENODEV: + /* Forwarder restarted */ + WARN("Forwarder likely restarted: not (yet) implemented"); + goto ERR; + case EWOULDBLOCK: + // DEBUG("Would block... stop reading from socket"); + goto END; + default: + perror("hc_sock_recv"); + goto ERR; + } + } + if (hc_sock_process(s, &data) < 0) { + goto ERR; + } + } +END: + if (pdata) + *pdata = data; + else + hc_data_free(data); + return 0; + +ERR: + hc_data_free(data); +ERR_EOF: + return -1; +} + +int hc_sock_reset(hc_sock_t *s) { + s->roff = s->woff = 0; + return 0; +} + +/****************************************************************************** + * Command-specific structures and functions + ******************************************************************************/ + +typedef int (*HC_PARSE)(const u8 *, u8 *); + +typedef struct { + hc_action_t cmd; + command_id cmd_id; + size_t size_in; + size_t size_out; + HC_PARSE parse; +} hc_command_params_t; + +int hc_execute_command(hc_sock_t *s, hc_msg_t *msg, size_t msg_len, + hc_command_params_t *params, hc_data_t **pdata, + bool async) { + if (async) assert(!pdata); + + /* Sanity check */ + switch (params->cmd) { + case ACTION_CREATE: + assert(params->size_in != 0); /* payload repeated */ + assert(params->size_out == 0); + //assert(params->parse == NULL); + break; + case ACTION_DELETE: + assert(params->size_in != 0); /* payload repeated */ + assert(params->size_out == 0); + //assert(params->parse == NULL); + break; + case ACTION_LIST: + assert(params->size_in != 0); + assert(params->size_out != 0); + //assert(params->parse != NULL); + break; + case ACTION_SET: + assert(params->size_in != 0); + assert(params->size_out == 0); + //assert(params->parse == NULL); + break; + default: + return -1; + } + + /* XXX data will at least store the result (complete) */ + hc_data_t *data = hc_data_create(params->size_in, params->size_out); + if (!data) { + ERROR("[hc_execute_command] Could not create data storage"); + goto ERR_DATA; + } + + int seq = hc_sock_get_next_seq(s); + + /* Create state used to process the request */ + hc_sock_request_t *request = NULL; + request = hc_sock_request_create(seq, data, params->parse); + if (!request) { + ERROR("[hc_execute_command] Could not create request state"); + goto ERR_REQUEST; + } + + /* Add state to map */ + if (hc_sock_map_add(s->map, seq, request) < 0) { + ERROR("[hc_execute_command] Error adding request state to map"); + goto ERR_MAP; + } + + if (hc_sock_send(s, msg, msg_len, seq) < 0) { + ERROR("[hc_execute_command] Error sending message"); + goto ERR_PROCESS; + } + + if (async) return 0; + + while (!data->complete) { + // CAN WE COLLAPSE THEM INTO A SINGLE COMMAND? Ideally the process would be + // done in the recv + /* + * As the socket is non blocking it might happen that we need to read + * several times before success... shall we alternate between blocking + * and non-blocking mode ? + */ + if (hc_sock_recv(s) < 0) continue; // break; + if (hc_sock_process(s, pdata) < 0) { + ERROR("[hc_execute_command] Error processing socket results"); + goto ERR_PROCESS; + } + } + + if (!pdata) hc_data_free(data); + + return 0; + +ERR_PROCESS: +ERR_MAP: + hc_sock_request_free(request); +ERR_REQUEST: + hc_data_free(data); +ERR_DATA: + return -1; +} + +/*----------------------------------------------------------------------------* + * Listeners + *----------------------------------------------------------------------------*/ + +/* LISTENER CREATE */ + +int _hc_listener_create(hc_sock_t *s, hc_listener_t *listener, bool async) { + // NOT IMPLEMENTED + return -1; +} + +int hc_listener_create(hc_sock_t *s, hc_listener_t *listener) { + // NOT IMPLEMENTED + return -1; +} + +int hc_listener_create_async(hc_sock_t *s, hc_listener_t *listener) { + // NOT IMPLEMENTED + return -1; +} + +/* LISTENER GET */ + +int hc_listener_get(hc_sock_t *s, hc_listener_t *listener, + hc_listener_t **listener_found) { + // NOT IMPLEMENTED + return -1; +} + +/* LISTENER DELETE */ + +int hc_listener_delete(hc_sock_t *s, hc_listener_t *listener) { + // NOT IMPLEMENTED + return -1; +} + +int hc_listener_delete_async(hc_sock_t *s, hc_listener_t *listener) { + // NOT IMPLEMENTED + return -1; +} + +/* LISTENER LIST */ +int hc_listener_list(hc_sock_t *s, hc_data_t **pdata) { + // NOT IMPLEMENTED + return -1; +} + +int hc_listener_list_async(hc_sock_t *s, hc_data_t **pdata) { + // NOT IMPLEMENTED + return -1; +} + +/* LISTENER VALIDATE */ + +int hc_listener_validate(const hc_listener_t *listener) { + // NOT IMPLEMENTED + return -1; +} + +/* LISTENER CMP */ + +int hc_listener_cmp(const hc_listener_t *l1, const hc_listener_t *l2) { + // NOT IMPLEMENTED + return -1; +} + +/* LISTENER PARSE */ + +int hc_listener_parse(void *in, hc_listener_t *listener) { + // NOT IMPLEMENTED + return -1; +} + +GENERATE_FIND(listener) + +/* LISTENER SNPRINTF */ + +/* /!\ Please update constants in header file upon changes */ +int hc_listener_snprintf(char *s, size_t size, hc_listener_t *listener) { + // NOT IMPLEMENTED + return -1; +} + +/*----------------------------------------------------------------------------* + * CONNECTION + *----------------------------------------------------------------------------*/ + +/* CONNECTION CREATE */ + +int hc_connection_create(hc_sock_t *s, hc_connection_t *connection) { + // NOT IMPLEMENTED + return -1; +} + +int hc_connection_create_async(hc_sock_t *s, hc_connection_t *connection) { + // NOT IMPLEMENTED + return -1; +} + +/* CONNECTION GET */ + +int hc_connection_get(hc_sock_t *s, hc_connection_t *connection, + hc_connection_t **connection_found) { + // NOT IMPLEMENTED + return -1; +} + +/* CONNECTION DELETE */ + +int hc_connection_delete(hc_sock_t *s, hc_connection_t *connection) { + // NOT IMPLEMENTED + return -1; +} + +int hc_connection_delete_async(hc_sock_t *s, hc_connection_t *connection) { + // NOT IMPLEMENTED + return -1; +} + +/* CONNECTION LIST */ + +int hc_connection_list(hc_sock_t *s, hc_data_t **pdata) { + // NOT IMPLEMENTED + return -1; +} + +int hc_connection_list_async(hc_sock_t *s, hc_data_t **pdata) { + // NOT IMPLEMENTED + return -1; +} + +/* CONNECTION VALIDATE */ + +int hc_connection_validate(const hc_connection_t *connection) { + // NOT IMPLEMENTED + return -1; +} + +/* CONNECTION CMP */ + +/* + * hICN light uses ports even for hICN connections, but their value is ignored. + * As connections are specific to hicn-light, we can safely use IP and ports for + * comparison independently of the face type. + */ +int hc_connection_cmp(const hc_connection_t *c1, const hc_connection_t *c2) { + // NOT IMPLEMENTED + return -1; +} + +/* CONNECTION PARSE */ + +int hc_connection_parse(void *in, hc_connection_t *connection) { + // NOT IMPLEMENTED + return -1; +} + +GENERATE_FIND(connection) + +/* CONNECTION SNPRINTF */ + +/* /!\ Please update constants in header file upon changes */ +int hc_connection_snprintf(char *s, size_t size, + const hc_connection_t *connection) { + // NOT IMPLEMENTED + return -1; +} + +/* CONNECTION SET ADMIN STATE */ + +int hc_connection_set_admin_state(hc_sock_t *s, const char *conn_id_or_name, + face_state_t state) { + // NOT IMPLEMENTED + return -1; +} + +int hc_connection_set_admin_state_async(hc_sock_t *s, + const char *conn_id_or_name, + face_state_t state) { + // NOT IMPLEMENTED + return -1; +} + +/*----------------------------------------------------------------------------* + * Routes + *----------------------------------------------------------------------------*/ + +/* ROUTE CREATE */ +int parse_route_create(uint8_t *src, uint8_t *dst) { + // No need to write anything on the dst, no data expected + + hc_sock_request_t *request = (hc_sock_request_t *)src; + vapi_payload_hicn_api_route_nhops_add_reply *reply = + (vapi_payload_hicn_api_route_nhops_add_reply *)request->data->buffer; + + int retval = reply->retval; + free(reply); + return retval; +} + +int _hc_route_create(hc_sock_t *s, hc_route_t *route, bool async) { + if (!IS_VALID_FAMILY(route->family)) return -1; + + hc_msg_s *msg = malloc(sizeof(hc_msg_s)); + vapi_msg_hicn_api_route_nhops_add *hicnp_msg; + hicnp_msg = vapi_alloc_hicn_api_route_nhops_add(s->g_vapi_ctx_instance); + msg->hicnp_msg = (hc_hicnp_t *)hicnp_msg; + msg->callback = &vapi_cb; + msg->callback_ctx = malloc(sizeof(callback_ctx_t)); + msg->callback_ctx->s = s; + msg->ntoh = (NTOH)&vapi_msg_hicn_api_route_nhops_add_hton; + + if (route->family == AF_INET) { + memcpy(&hicnp_msg->payload.prefix.address.un.ip4[0], &route->remote_addr.v4, 4); + } + else { + memcpy(&hicnp_msg->payload.prefix.address.un.ip6[0], &route->remote_addr.v6, 16); + } + hicnp_msg->payload.prefix.address.af = + route->family == AF_INET ? ADDRESS_IP4 : ADDRESS_IP6; + hicnp_msg->payload.prefix.len = route->len; + hicnp_msg->payload.face_ids[0] = route->face_id; + hicnp_msg->payload.n_faces = 1; + + hc_command_params_t params = { + .cmd = ACTION_CREATE, + .cmd_id = ADD_ROUTE, + .size_in = + sizeof(vapi_msg_hicn_api_route_nhops_add), + .size_out = 0, + .parse = (HC_PARSE)parse_route_create, + }; + + return hc_execute_command(s, (hc_msg_t *)msg, sizeof(msg), ¶ms, NULL, + async); +} + +int hc_route_create(hc_sock_t *s, hc_route_t *route) { + return _hc_route_create(s, route, false); +} + +int hc_route_create_async(hc_sock_t *s, hc_route_t *route) { + return _hc_route_create(s, route, true); +} + +/* ROUTE DELETE */ + +int parse_route_delete(uint8_t *src, uint8_t *dst) { + // No need to write anything on the dst, no data expected + + hc_sock_request_t *request = (hc_sock_request_t *)src; + vapi_payload_hicn_api_route_nhop_del_reply *reply = + (vapi_payload_hicn_api_route_nhop_del_reply *)request->data->buffer; + + int retval = reply->retval; + free(reply); + return retval; +} + +int _hc_route_delete(hc_sock_t *s, hc_route_t *route, bool async) { + if (!IS_VALID_FAMILY(route->family)) return -1; + + hc_msg_s *msg = malloc(sizeof(hc_msg_s)); + vapi_msg_hicn_api_route_nhop_del *hicnp_msg; + hicnp_msg = vapi_alloc_hicn_api_route_nhop_del(s->g_vapi_ctx_instance); + msg->hicnp_msg = (hc_hicnp_t *)hicnp_msg; + msg->callback = &vapi_cb; + msg->callback_ctx = malloc(sizeof(callback_ctx_t)); + msg->callback_ctx->s = s; + msg->ntoh = (NTOH)&vapi_msg_hicn_api_route_nhop_del_hton; + + memcpy(&hicnp_msg->payload.prefix.address.un.ip6[0], &route->remote_addr, 16); + hicnp_msg->payload.prefix.address.af = + route->family == AF_INET ? ADDRESS_IP4 : ADDRESS_IP6; + hicnp_msg->payload.prefix.len = route->len; + hicnp_msg->payload.faceid = route->face_id; + + hc_command_params_t params = { + .cmd = ACTION_DELETE, + .cmd_id = REMOVE_ROUTE, + .size_in = + sizeof(vapi_msg_hicn_api_route_nhop_del), + .size_out = 0, + .parse = (HC_PARSE)parse_route_delete, + }; + + return hc_execute_command(s, (hc_msg_t *)msg, sizeof(msg), ¶ms, NULL, + async); +} + +int hc_route_delete(hc_sock_t *s, hc_route_t *route) { + return _hc_route_delete(s, route, false); +} + +int hc_route_delete_async(hc_sock_t *s, hc_route_t *route) { + return _hc_route_delete(s, route, true); +} + +/* ROUTE LIST */ +int parse_route_list(uint8_t *src, uint8_t *dst) { + // No need to write anything on the dst, no data expected + + hc_sock_request_t *request = (hc_sock_request_t *)src; + + int size = 0; + for (int i = 0; i < request->data->current; i++) { + vapi_payload_hicn_api_routes_details *reply = + (vapi_payload_hicn_api_routes_details + *)(request->data->buffer + i * request->data->in_element_size); + size += reply->nfaces; + } + hc_route_t *output = malloc(sizeof(hc_route_t) * size); + + int cur = 0; + for (int j = 0; j < request->data->current; j++) { + vapi_payload_hicn_api_routes_details *reply = + (vapi_payload_hicn_api_routes_details + *)(request->data->buffer + j * request->data->in_element_size); + for (int i = 0; i < reply->nfaces; i++) { + output[cur].face_id = reply->faceids[i]; + output[cur].cost = 1; + output[cur].len = reply->prefix.len; + if (reply->prefix.address.af == ADDRESS_IP6) + { + memcpy(output[cur].remote_addr.v6.as_u8, reply->prefix.address.un.ip6, 16); + } + else + { + memcpy(output[cur].remote_addr.v4.as_u8, reply->prefix.address.un.ip4, 4); + } + output[cur].family = reply->prefix.address.af == ADDRESS_IP6? AF_INET6 : AF_INET; + cur++; + } + } + + free(request->data->buffer); + request->data->buffer = (void *)output; + request->data->size = size; + request->data->out_element_size = sizeof(hc_route_t); + return 0; +} + +int _hc_route_list(hc_sock_t *s, hc_data_t **pdata, bool async) { + hc_msg_s *msg = malloc(sizeof(hc_msg_s)); + vapi_msg_hicn_api_routes_dump *hicnp_msg; + hicnp_msg = vapi_alloc_hicn_api_routes_dump(s->g_vapi_ctx_instance); + msg->hicnp_msg = (hc_hicnp_t *)hicnp_msg; + msg->callback = &vapi_cb; + msg->callback_ctx = malloc(sizeof(callback_ctx_t)); + msg->callback_ctx->s = s; + msg->ntoh = (NTOH)&vapi_msg_hicn_api_routes_dump_hton; + + hc_command_params_t params = { + .cmd = ACTION_LIST, + .cmd_id = LIST_ROUTES, + .size_in = sizeof(vapi_msg_hicn_api_routes_details), + .size_out = sizeof(hc_route_t), + .parse = (HC_PARSE)parse_route_list, + }; + + return hc_execute_command(s, (hc_msg_t *)msg, sizeof(msg), ¶ms, pdata, + async); +} + +int hc_route_list(hc_sock_t *s, hc_data_t **pdata) { + return _hc_route_list(s, pdata, false); +} + +int hc_route_list_async(hc_sock_t *s) { + return _hc_route_list(s, NULL, true); +} + +/* ROUTE SNPRINTF */ + +/* /!\ Please update constants in header file upon changes */ +int hc_route_snprintf(char *s, size_t size, hc_route_t *route) { + /* interface cost prefix length */ + + char prefix[MAXSZ_IP_ADDRESS]; + int rc; + + rc = ip_address_snprintf(prefix, MAXSZ_IP_ADDRESS, &route->remote_addr, + route->family); + if (rc < 0) return rc; + + return snprintf(s, size, "%*d %*d %s %*d", MAXSZ_FACE_ID, route->face_id, + MAXSZ_COST, route->cost, prefix, MAXSZ_LEN, route->len); +} + +/*----------------------------------------------------------------------------* + * Face + * + * Face support is not directly available in hicn-light, but we can offer such + * an interface through a combination of listeners and connections. The code + * starts with some conversion functions between faces/listeners/connections. + * + * We also need to make sure that there always exist a (single) listener when a + * connection is created, and in the hICN face case, that there is a single + * connection attached to this listener. + * + *----------------------------------------------------------------------------*/ + +/* FACE -> LISTENER */ + +int hc_face_to_listener(const hc_face_t *face, hc_listener_t *listener) { + const face_t *f = &face->face; + + switch (f->type) { + case FACE_TYPE_HICN_LISTENER: + break; + case FACE_TYPE_TCP_LISTENER: + break; + case FACE_TYPE_UDP_LISTENER: + break; + default: + return -1; + } + return -1; /* XXX Not implemented */ +} + +/* LISTENER -> FACE */ + +int hc_listener_to_face(const hc_listener_t *listener, hc_face_t *face) { + return -1; /* XXX Not implemented */ +} + +/* FACE -> CONNECTION */ + +int hc_face_to_connection(const hc_face_t *face, hc_connection_t *connection, + bool generate_name) { + return 0; +} + +/* CONNECTION -> FACE */ + +int hc_connection_to_face(const hc_connection_t *connection, hc_face_t *face) { + return 0; +} + +/* CONNECTION -> LISTENER */ + +int hc_connection_to_local_listener(const hc_connection_t *connection, + hc_listener_t *listener) { + return 0; +} + +/* FACE CREATE */ + +int hc_face_create(hc_sock_t *s, hc_face_t *face) { return 0; } + +int hc_face_get(hc_sock_t *s, hc_face_t *face, hc_face_t **face_found) { + return 0; +} + +/* FACE DELETE */ + +int hc_face_delete(hc_sock_t *s, hc_face_t *face) { return 0; } + +/* FACE LIST */ + +int hc_face_list(hc_sock_t *s, hc_data_t **pdata) { return 0; } + +int hc_connection_parse_to_face(void *in, hc_face_t *face) { return 0; } + +int hc_face_list_async(hc_sock_t *s) //, hc_data_t ** pdata) +{ + return 0; +} + +/* /!\ Please update constants in header file upon changes */ +int hc_face_snprintf(char *s, size_t size, hc_face_t *face) { return 0; } + +int hc_face_set_admin_state( + hc_sock_t *s, const char *conn_id_or_name, // XXX wrong identifier + face_state_t admin_state) { + return 0; +} + +/*----------------------------------------------------------------------------* + * Punting + *----------------------------------------------------------------------------*/ + +int _hc_punting_create(hc_sock_t *s, hc_punting_t *punting, bool async) { + return 0; +} + +int hc_punting_create(hc_sock_t *s, hc_punting_t *punting) { + return _hc_punting_create(s, punting, false); +} + +int hc_punting_create_async(hc_sock_t *s, hc_punting_t *punting) { + return _hc_punting_create(s, punting, true); +} + +int hc_punting_get(hc_sock_t *s, hc_punting_t *punting, + hc_punting_t **punting_found) { + ERROR("hc_punting_get not (yet) implemented."); + return -1; +} + +int hc_punting_delete(hc_sock_t *s, hc_punting_t *punting) { + ERROR("hc_punting_delete not (yet) implemented."); + return -1; +} + +int hc_punting_list(hc_sock_t *s, hc_data_t **pdata) { + ERROR("hc_punting_list not (yet) implemented."); + return -1; +} + +int hc_punting_validate(const hc_punting_t *punting) { + if (!IS_VALID_FAMILY(punting->family)) return -1; + + /* + * We might use the zero value to add punting on all faces but this is not + * (yet) implemented + */ + if (punting->face_id == 0) { + ERROR("Punting on all faces is not (yet) implemented."); + return -1; + } + + return 0; +} + +int hc_punting_cmp(const hc_punting_t *p1, const hc_punting_t *p2) { + return ((p1->face_id == p2->face_id) && (p1->family == p2->family) && + (ip_address_cmp(&p1->prefix, &p2->prefix, p1->family) == 0) && + (p1->prefix_len == p2->prefix_len)) + ? 0 + : -1; +} + +int hc_punting_parse(void *in, hc_punting_t *punting) { + ERROR("hc_punting_parse not (yet) implemented."); + return -1; +} + +int hc_punting_snprintf(char *s, size_t size, hc_punting_t *punting) { + ERROR("hc_punting_snprintf not (yet) implemented."); + return -1; +} + +/*----------------------------------------------------------------------------* + * Cache + *----------------------------------------------------------------------------*/ + +int _hc_cache_set_store(hc_sock_t *s, int enabled, bool async) { + return 0; +} + +int hc_cache_set_store(hc_sock_t *s, int enabled) { + return _hc_cache_set_store(s, enabled, false); +} + +int hc_cache_set_store_async(hc_sock_t *s, int enabled) { + return _hc_cache_set_store(s, enabled, true); +} + +int _hc_cache_set_serve(hc_sock_t *s, int enabled, bool async) { + return 0; +} + +int hc_cache_set_serve(hc_sock_t *s, int enabled) { + return _hc_cache_set_serve(s, enabled, false); +} + +int hc_cache_set_serve_async(hc_sock_t *s, int enabled) { + return _hc_cache_set_serve(s, enabled, true); +} + +/*----------------------------------------------------------------------------* + * Strategy + *----------------------------------------------------------------------------*/ + +// per prefix +int hc_strategy_set(hc_sock_t *s /* XXX */) { return 0; } + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array)) + +int hc_strategy_list(hc_sock_t *s, hc_data_t **data) { + return 0; +} + +/* /!\ Please update constants in header file upon changes */ +int hc_strategy_snprintf(char *s, size_t size, hc_strategy_t *strategy) { + return snprintf(s, size, "%s", strategy->name); +} + +/*----------------------------------------------------------------------------* + * WLDR + *----------------------------------------------------------------------------*/ + +// per connection +int hc_wldr_set(hc_sock_t *s /* XXX */) { return 0; } + +/*----------------------------------------------------------------------------* + * MAP-Me + *----------------------------------------------------------------------------*/ + +int hc_mapme_set(hc_sock_t *s, int enabled) { return 0; } + +int hc_mapme_set_discovery(hc_sock_t *s, int enabled) { return 0; } + +int hc_mapme_set_timescale(hc_sock_t *s, double timescale) { return 0; } + +int hc_mapme_set_retx(hc_sock_t *s, double timescale) { return 0; } + +/* Useless function defined to prevent undefined reference */ +hc_connection_type_t +connection_type_from_str(const char * str) +{ + if (strcasecmp(str, "TCP") == 0) + return CONNECTION_TYPE_TCP; + else if (strcasecmp(str, "UDP") == 0) + return CONNECTION_TYPE_UDP; + else if (strcasecmp(str, "HICN") == 0) + return CONNECTION_TYPE_HICN; + else + return CONNECTION_TYPE_UNDEFINED; +} + +/*********************** Missing Symbol in vpp libraries *************************/ +u8 * +format_vl_api_address_union (u8 * s, va_list * args) +{ + return NULL; +} |