aboutsummaryrefslogtreecommitdiffstats
path: root/ctrl/facemgr/src/api.c
diff options
context:
space:
mode:
authorJordan Augé <jordan.auge@cisco.com>2019-10-30 17:56:08 +0100
committerJordan Augé <jordan.auge@cisco.com>2019-10-31 13:41:47 +0100
commit95170bf3a69597b49238bb7ff396d41f6dc94f30 (patch)
tree2f9b565e84514d7ee25cfd874235dd25e9300a0f /ctrl/facemgr/src/api.c
parentfc6dfe9f7ee02834ae1e6f56e0aaee36ac3e88dd (diff)
[HICN-369] Implement reconciliation state machine in face manager incl. reattempts in case of errors
Change-Id: Ia4ecf621fbd513d9e29313d2aaa487aa65811183 Signed-off-by: Jordan Augé <jordan.auge@cisco.com>
Diffstat (limited to 'ctrl/facemgr/src/api.c')
-rw-r--r--ctrl/facemgr/src/api.c815
1 files changed, 551 insertions, 264 deletions
diff --git a/ctrl/facemgr/src/api.c b/ctrl/facemgr/src/api.c
index a1507bd70..19f211dbf 100644
--- a/ctrl/facemgr/src/api.c
+++ b/ctrl/facemgr/src/api.c
@@ -39,8 +39,8 @@
#endif /* __ANDROID__ */
#include <hicn/ctrl/face.h>
+#include <hicn/facemgr/facelet.h>
#include "common.h"
-#include "facelet.h"
#include "interface.h"
#include "util/map.h"
#include "util/set.h"
@@ -49,6 +49,7 @@
#define DEFAULT_PORT 9695
+#define DEFAULT_REATTEMPT_DELAY_MS 250
#define MAX_FDS 10
typedef struct {
@@ -149,6 +150,7 @@ struct facemgr_s {
#ifdef WITH_EXAMPLE_UPDOWN
interface_t * updown;
#endif
+ int timer_fd; /* Timer used for reattempts */
};
int
@@ -174,6 +176,8 @@ facemgr_initialize(facemgr_t * facemgr)
if (!facemgr->cfg)
goto ERR_CFG;
+ facemgr->timer_fd = 0;
+
return 0;
ERR_CFG:
@@ -194,6 +198,16 @@ facemgr_finalize(facemgr_t * facemgr)
int ret = 0;
int rc;
+ if (facemgr->timer_fd) {
+ rc = facemgr->callback(facemgr->callback_owner,
+ FACEMGR_CB_TYPE_UNREGISTER_TIMER, &facemgr->timer_fd);
+ if (rc < 0) {
+ ERROR("[facemgr_finalize] Error unregistering timer");
+ ret = -1;
+ }
+ facemgr->timer_fd = 0;
+ }
+
rc = interface_map_finalize(&facemgr->interface_map);
if (rc < 0) {
ERROR("[facemgr_finalize] Could not finalize interface_map");
@@ -226,6 +240,8 @@ facemgr_finalize(facemgr_t * facemgr)
ret = -1;
#endif /* __linux__ */
+ interface_unregister_all();
+
return ret;
}
@@ -265,12 +281,49 @@ facemgr_create_with_config(facemgr_cfg_t * cfg)
return facemgr;
}
+/*
+ * \brief Heuristics to determine face type based on name, until a better
+ * solution is found
+ */
+netdevice_type_t
+facemgr_get_netdevice_type(const facemgr_t * facemgr, const char * interface_name)
+{
+ if (strncmp(interface_name, "lo", 2) == 0) {
+ return NETDEVICE_TYPE_LOOPBACK;
+ }
+ if ((strncmp(interface_name, "eth", 3) == 0) ||
+ (strncmp(interface_name, "en", 2) == 0)) {
+ /* eth* en* enx* */
+ return NETDEVICE_TYPE_WIRED;
+ }
+ if (strncmp(interface_name, "wl", 2) == 0) {
+ /* wlan* wlp* wlx* */
+ return NETDEVICE_TYPE_WIFI;
+ }
+ if (strncmp(interface_name, "rmnet_ipa", 9) == 0) {
+ /* Qualcomm IPA driver */
+ return NETDEVICE_TYPE_UNDEFINED;
+ }
+ if ((strncmp(interface_name, "rmnet", 5) == 0) ||
+ (strncmp(interface_name, "rev_rmnet", 9) == 0) ||
+ (strncmp(interface_name, "ccmni", 5) == 0)) {
+ /*
+ * rmnet* (Qualcomm) ccmni* (MediaTek)
+ */
+ return NETDEVICE_TYPE_CELLULAR;
+ }
+ /* usb0 might be cellular (eg Zenfone2) */
+ /* what about tethering */
+ /* tun* dummy* ... */
+ /* bnet* pan* hci* for bluetooth */
+ return NETDEVICE_TYPE_UNDEFINED;
+}
+
int facemgr_callback(facemgr_t * facemgr, interface_cb_type_t type, void * data);
int
facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, void * cfg, interface_t ** pinterface)
{
- int fd;
char rand_name[RAND_NAME_LEN+1];
interface_t * interface;
@@ -291,10 +344,6 @@ facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * ty
}
interface_set_callback(interface, facemgr, facemgr_callback);
- fd = interface_initialize(interface, cfg);
- if (fd < 0)
- goto ERR_INIT;
-
interface_map_data_t * interface_map_data = malloc(sizeof(interface_map_data_t));
if (!interface_map_data)
goto ERR_MAP_DATA;
@@ -308,6 +357,15 @@ facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * ty
if (interface_map_add(&facemgr->interface_map, interface->name, interface_map_data) < 0)
goto ERR_MAP_ADD;
+ /*
+ * This should be called _after_ the interface_map is initialized otherwise
+ * it will be impossible to register fds from *_initialize
+ */
+ if (interface_initialize(interface, cfg) < 0) {
+ ERROR("[facemgr_create_interface] Error initializing interface");
+ goto ERR_INIT;
+ }
+
DEBUG("Interface %s created successfully.", name);
if (pinterface)
*pinterface = interface;
@@ -342,7 +400,13 @@ facemgr_delete_interface(facemgr_t * facemgr, interface_t * interface)
for (unsigned i = 0; i < interface_map_data->num_fds; i++) {
int fd = interface_map_data->fds[i];
- facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_UNREGISTER_FD, &fd);
+ fd_callback_data_t fd_callback_data = {
+ .fd = fd,
+ .owner = facemgr,
+ .callback = NULL,
+ .data = NULL,
+ };
+ facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_UNREGISTER_FD, &fd_callback_data);
if (rc < 0)
WARN("[facemgr_delete_interface] Error unregistering fd %d for interface", fd);
}
@@ -494,7 +558,7 @@ facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet)
}
netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
-#ifdef __ANDROID__
+//#ifdef __ANDROID__
/*
* In addition to netdevice, netdevice_type should be present to correctly
* apply rules
@@ -504,7 +568,7 @@ facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet)
ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet");
return -2;
}
-#endif /* __ANDROID__ */
+//#endif /* __ANDROID__ */
/* Ignore */
bool ignore;
@@ -578,11 +642,13 @@ facemgr_complement_facelet_au(facemgr_t * facemgr, facelet_t * facelet)
}
DEBUG("Querying android utility...");
- facelet_set_au_done(facelet);
/* /!\ Synchronous code here /!\ */
- if (facemgr_query_android_utility(facemgr, netdevice) < 0)
+ if (facemgr_query_android_utility(facemgr, netdevice) < 0) {
return -1;
+ }
+
+ facelet_set_au_done(facelet);
return 0;
}
#endif /* __ANDROID__ */
@@ -607,7 +673,7 @@ facemgr_complement_facelet_bj(facemgr_t * facemgr, facelet_t * facelet)
}
netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
-#ifdef __ANDROID__
+//#ifdef __ANDROID__
/*
* In addition to netdevice, netdevice_type should be present to correctly
* apply rules
@@ -617,7 +683,7 @@ facemgr_complement_facelet_bj(facemgr_t * facemgr, facelet_t * facelet)
ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice_type from facelet");
return -2;
}
-#endif /* __ANDROID__ */
+//#endif /* __ANDROID__ */
bool discovery;
if (facemgr_cfg_get_discovery(facemgr->cfg, &netdevice, netdevice_type,
@@ -679,7 +745,7 @@ facemgr_complement_facelet_manual(facemgr_t * facemgr, facelet_t * facelet)
}
netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
-#ifdef __ANDROID__
+//#ifdef __ANDROID__
/*
* In addition to netdevice, netdevice_type should be present to correctly
* apply rules
@@ -689,7 +755,7 @@ facemgr_complement_facelet_manual(facemgr_t * facemgr, facelet_t * facelet)
ERROR("[facemgr_complement_facelet_manual] Error retrieving netdevice_type from facelet");
return -2;
}
-#endif /* __ANDROID__ */
+//#endif /* __ANDROID__ */
int family = AF_UNSPEC;
if (facelet_has_family(facelet)) {
@@ -798,11 +864,22 @@ facemgr_complement_facelet(facemgr_t * facemgr, facelet_t * facelet)
if (!facelet_has_key(facelet))
return -2;
+#if 0
#ifdef __ANDROID__
rc = facemgr_complement_facelet_au(facemgr, facelet);
if (rc != -2)
return rc;
#endif /* __ANDROID__ */
+#endif
+ if (!facelet_has_netdevice_type(facelet)) {
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet] Error retrieving netdevice from facelet");
+ return -1;
+ }
+ facelet_set_netdevice_type(facelet, facemgr_get_netdevice_type(facemgr, netdevice.name));
+ }
/* We continue only if the current call was not applicable. In the current
* setting we have no interface that can be requested in parallel, and no
@@ -825,105 +902,279 @@ facemgr_complement_facelet(facemgr_t * facemgr, facelet_t * facelet)
return 0;
}
-/**
- * \brief Process facelet CREATE event
- * \param [in] facemgr - Pointer to the face manager instance
- * \param [in] facelet - Pointer to the facelet event to process
- * \return 0 if everything went correctly, or -1 in case of error.
- */
-int
-facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet)
+int facemgr_assign_face_type(facemgr_t * facemgr, facelet_t * facelet)
{
- /*
- * We create an interface locally, which does not means it should not exist
- * remotely. Once such codepath is enabled, the two facelets will have been
- * merged and we need to handle an eventual update on our side.
- *
- * In the same way, we need to check for the equivalence of face types etc.
- */
- int rc;
+ /* As key, netdevice and family should always be present */
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet");
+ return -1;
+ }
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+//#ifdef __ANDROID__
/*
- * If the facelet does not satisfy filters, we do not lose any information
- * but do not take any action to complement the face
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
*/
- rc = facemgr_facelet_satisfy_rules(facemgr, facelet);
- if (rc == -3) {
- facelet_set_status(facelet, FACELET_STATUS_IGNORED);
- /* Does not satisfy rules */
- return 0;
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet");
+ return -2;
}
+//#endif /* __ANDROID__ */
- // FIXME: we should complement a part of the facelet, so that we don't
- // necessarily keep this information if we get more locally. Or at least we
- // should remember that.
- if (rc == -2) {
- /*
- * We don't have equivalent for linux right now, heuristic is only used
- * at the end... might change.
- */
-#ifdef __ANDROID__
- /* Priority is given to information that complements a face */
- if (facemgr_complement_facelet_au(facemgr, facelet) < 0) {
- ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by rule application");
- return -1;
- }
- return 0;
-#endif /* __ANDROID__ */
+ facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+ if (facemgr_cfg_get_face_type(facemgr->cfg, &netdevice, netdevice_type, &face_type) < 0)
+ return rc;
+ facelet_set_face_type(facelet, face_type);
+ return 0;
+}
+
+/*
+ * This function performs one step of the state machine associated to the
+ * facelet, from initial creation, to synchronization with the forwarder.
+ *
+ * We assume the facelet is already present in the cache
+ */
+int
+facemgr_process_facelet(facemgr_t * facemgr, facelet_t * facelet)
+{
+ int rc;
+
+ switch(facelet_get_status(facelet)) {
+ case FACELET_STATUS_UNCERTAIN:
+ /*
+ * All new faces are marked UNCERTAIN. We need to check whether we
+ * have sufficient information to check rules, if not proceed,
+ * otherwise possibly mark the face as IGNORED. Otherwise, we verify
+ * the completeness of the information we have, and continue towards
+ * being able to mark the face as CREATE.
+ */
+ rc = facemgr_facelet_satisfy_rules(facemgr, facelet);
+ switch(rc) {
+ case -3:
+ /* Does not satisfy rules */
+ facelet_set_status(facelet, FACELET_STATUS_IGNORED);
+ return 0;
+
+ case -2:
+ /* Not enough information: AU in fact */
+ if (facemgr_complement_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_facelet] Error while attempting to complement face for fields required by face creation");
+ goto ERR;
+ }
+ return 0;
+
+ case 0:
+ /* Ok pass rules */
+ break;
+
+ default:
+ /* -1 - Error */
+ goto ERR;
+ }
+
+ if (facemgr_assign_face_type(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_facelet] Could not assign face type");
+ goto ERR;
+ }
+ facelet_set_status(facelet, FACELET_STATUS_INCOMPLETE);
+ /* Continue in case facelet satisfies rules */
+
+ case FACELET_STATUS_INCOMPLETE:
+ if (!facelet_validate_face(facelet)) {
+ /* We need additional information */
+ if (facemgr_complement_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_facelet] Error while attempting to complement face for fields required by face creation");
+ goto ERR;
+ }
+ }
+ if (!facelet_validate_face(facelet))
+ return 0;
+
+ facelet_set_status(facelet, FACELET_STATUS_CREATE);
+ /* Continue in case we need to proceed to creation */
+
+ case FACELET_STATUS_CREATE:
+ facelet_set_event(facelet, FACELET_EVENT_CREATE);
+ if (interface_on_event(facemgr->hl, facelet) < 0) {
+ ERROR("[facemgr_process_facelet] Failed to create face");
+ goto ERR;
+ }
+
+ /* This works assuming the call to hicn-light is blocking */
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ break;
+
+
+ case FACELET_STATUS_UPDATE:
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ if (interface_on_event(facemgr->hl, facelet) < 0) {
+ ERROR("[facemgr_process_facelet] Failed to update face");
+ goto ERR;
+ }
+
+ /* This works assuming the call to hicn-light is blocking */
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ break;
+
+ case FACELET_STATUS_DELETE:
+ facelet_set_event(facelet, FACELET_EVENT_DELETE);
+ if (interface_on_event(facemgr->hl, facelet) < 0) {
+ ERROR("[facemgr_process_facelet] Failed to delete face");
+ goto ERR;
+ }
+
+ /* This works assuming the call to hicn-light is blocking */
+ DEBUG("[facemgr_process_facelet] Cleaning cached data");
+ facelet_unset_local_addr(facelet);
+ facelet_unset_local_port(facelet);
+ facelet_unset_remote_addr(facelet);
+ facelet_unset_remote_port(facelet);
+ facelet_unset_bj_done(facelet);
+ //facelet_unset_au_done(facelet);
+
+ facelet_set_status(facelet, FACELET_STATUS_DELETED);
+ break;
+
+ case FACELET_STATUS_CLEAN:
+ case FACELET_STATUS_IGNORED:
+ case FACELET_STATUS_DELETED:
+ /* Nothing to do */
+ break;
+
+ case FACELET_STATUS_UNDEFINED:
+ case FACELET_STATUS_N:
+ ERROR("[facemgr_process_facelet] Unexpected facelet status");
+ goto ERR;
}
- if (rc < 0)
- return -1;
-// netdevice_t netdevice = NETDEVICE_EMPTY;
-// if (facelet_get_netdevice(facelet, &netdevice) < 0) {
-// ERROR("[facemgr_process_create] Error retrieving netdevice from facelet");
-// return -1;
-// }
-//
-// netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
-//#ifdef __ANDROID__
-// /*
-// * In addition to netdevice, netdevice_type should be present to correctly
-// * apply rules
-// */
-// if (facelet_get_netdevice_type(facelet, &netdevice_type) < 0) {
-// ERROR("[facemgr_process_create] Error retrieving netdevice_type from facelet");
-// return -2;
-// }
-//#endif /* __ANDROID__ */
+ facelet_set_status_error(facelet, false);
+ return 0;
+ERR:
+ facelet_set_status_error(facelet, true);
+ return -1;
+}
- char facelet_s[MAXSZ_FACELET];
- facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet);
- //DEBUG("---[ FACELET CREATE : %s ] ---", facelet_s);
+int
+facemgr_reattempt_timeout(facemgr_t * facemgr, int fd, void * data)
+{
+ bool has_error = false;
- /* Do we have enough information about the facelet ? */
- if (!facelet_validate_face(facelet)) {
- if (facemgr_complement_facelet(facemgr, facelet) < 0) {
- ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation");
- return -1;
+ assert(data == NULL);
+
+ /* Free all facelets from cache */
+ facelet_t ** facelet_array;
+ int n = facelet_cache_get_array(&facemgr->facelet_cache, &facelet_array);
+ if (n < 0) {
+ ERROR("[facemgr_reattempt_timeout] Could not retrieve facelets in cache");
+ } else {
+ for (unsigned i = 0; i < n; i++) {
+ facelet_t * facelet = facelet_array[i];
+
+ if (!facelet_get_status_error(facelet))
+ continue;
+
+ char buf[MAXSZ_FACELET];
+ facelet_snprintf(buf, MAXSZ_FACELET, facelet);
+ DEBUG("Reattempt to process failed facelet %s", buf);
+ if (facemgr_process_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_reattempt_timeout] Error processing facelet");
+ has_error = true;
+ continue;
+ }
+ facelet_set_status_error(facelet, false);
}
- // we should not stop after complement_manual but create a face if
- // possible... so we add a second validation
+ free(facelet_array);
}
- if (!facelet_validate_face(facelet))
+ if (has_error)
return 0;
- /*
- * Is the forwarder connected, and has the facelet cache already sync'ed the
- * remote faces ?
- */
- // TODO
+ DEBUG("Cancelling timer");
+ if (facemgr->callback(facemgr->callback_owner,
+ FACEMGR_CB_TYPE_UNREGISTER_TIMER, &facemgr->timer_fd) < 0) {
+ ERROR("[facemgr_reattempt_timeout] Error unregistering reattempt timer");
+ return -1;
+ }
+ facemgr->timer_fd = 0;
+ return 0;
+}
- /*
- * Actually create the face on the forwarder
- *
- * FIXME Currently hicn-light is hardcoded
- */
- if (interface_on_event(facemgr->hl, facelet) < 0)
+int
+facemgr_start_reattempts(facemgr_t * facemgr)
+{
+ if (facemgr->timer_fd > 0)
+ return 0;
+
+ timer_callback_data_t timer_callback = {
+ .delay_ms = DEFAULT_REATTEMPT_DELAY_MS,
+ .owner = facemgr,
+ .callback = (fd_callback_t)facemgr_reattempt_timeout,
+ .data = NULL,
+ };
+ facemgr->timer_fd = facemgr->callback(facemgr->callback_owner,
+ FACEMGR_CB_TYPE_REGISTER_TIMER, &timer_callback);
+ return (facemgr->timer_fd > 0);
+}
+
+/**
+ * \brief Process facelet CREATE event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ * -2 means we ignored the face purposedly
+ */
+int
+facemgr_process_facelet_create(facemgr_t * facemgr, facelet_t * facelet)
+{
+ switch(facelet_get_status(facelet)) {
+ case FACELET_STATUS_UNCERTAIN:
+ case FACELET_STATUS_INCOMPLETE:
+ case FACELET_STATUS_CREATE:
+ /* No change */
+ break;
+ case FACELET_STATUS_UPDATE:
+ case FACELET_STATUS_DELETE:
+ /*
+ * Unlikely. The face had been created and is planned to
+ * be deleted. Schedule for creation (we should have all
+ * needed information), but make sure to handle errors
+ * correctly if the face is still present.
+ * TODO What if some fields have been updated ?
+ */
+ facelet_set_status(facelet, FACELET_STATUS_CREATE);
+ break;
+ case FACELET_STATUS_CLEAN:
+ case FACELET_STATUS_IGNORED:
+ /*
+ * We should have nothing to do unless some fields have
+ * been updated.
+ */
+ break;
+
+ case FACELET_STATUS_DELETED:
+ /*
+ * Unless rules have changed, we only need to recover
+ * missing information, and proceed to face creation.
+ * Rule changes should be handled separately.
+ */
+ facelet_set_status(facelet, FACELET_STATUS_INCOMPLETE);
+ break;
+ case FACELET_STATUS_UNDEFINED:
+ case FACELET_STATUS_N:
+ ERROR("[facemgr_process_facelet_create] Unexpected facelet status");
+ return -1;
+ }
+
+ if (facemgr_process_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_facelet_create] Error processing facelet");
return -1;
- facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ }
+
return 0;
}
@@ -935,15 +1186,15 @@ facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet)
* -2 means we ignored the face purposedly
*/
int
-facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet)
+facemgr_process_facelet_get(facemgr_t * facemgr, facelet_t * facelet)
{
- facelet_set_status(facelet, FACELET_STATUS_CLEAN);
if (facelet_has_netdevice(facelet)) {
netdevice_t netdevice;
if (facelet_get_netdevice(facelet, &netdevice) < 0)
return -1;
if (!IS_VALID_NETDEVICE(netdevice))
return -2;
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
return facelet_cache_add(&facemgr->facelet_cache, facelet);
}
return -2;
@@ -954,146 +1205,38 @@ facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet)
* \param [in] facemgr - Pointer to the face manager instance
* \param [in] facelet - Pointer to the facelet event to process
* \return 0 if everything went correctly, or -1 in case of error.
+ * -2 means we ignored the face purposedly
*/
int
-facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet)
+facemgr_process_facelet_update(facemgr_t * facemgr, facelet_t * facelet)
{
- /* This is the most complex operation since we have the same problems as in
- * CREATE + the need to manage changes...
- *
- * This might eventually trigger a face deletion...
- */
-
- /*
- * Update in local does not mean the face should not be created remotely as
- * it might be the first time we have enough information to create it
- */
-
- char facelet_s[MAXSZ_FACELET];
- facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet);
- //DEBUG("---[ FACELET UPDATE : %s ] ---", facelet_s);
-
- /* Sets face type */
- if (!facelet_has_face_type(facelet)) {
-
- /* As key, netdevice and family should always be present */
- netdevice_t netdevice = NETDEVICE_EMPTY;
- int rc = facelet_get_netdevice(facelet, &netdevice);
- if (rc < 0) {
- ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet");
- return -1;
- }
-
- netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
-#ifdef __ANDROID__
- /*
- * In addition to netdevice, netdevice_type should be present to correctly
- * apply rules
- */
- rc = facelet_get_netdevice_type(facelet, &netdevice_type);
- if (rc < 0) {
- ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet");
- return -2;
- }
-#endif /* __ANDROID__ */
-
- facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED;
- if (facemgr_cfg_get_face_type(facemgr->cfg, &netdevice, netdevice_type, &face_type) < 0)
- return rc;
- facelet_set_face_type(facelet, face_type);
- }
-
- /* Process GET/UDPATE... */
- int rc;
switch(facelet_get_status(facelet)) {
- case FACELET_STATUS_UNDEFINED:
- ERROR("[facemgr_process_update] Unexpected facelet status");
- return -1;
-
- case FACELET_STATUS_DELETED:
- case FACELET_STATUS_NEW:
- /*
- * If the remote action should be a CREATE, then we need to check
- * whether we have enough information about the face...
- */
- if (!facelet_validate_face(facelet)) {
- if (facemgr_complement_facelet(facemgr, facelet) < 0) {
- ERROR("[facemgr_process_update] Error while attempting to complement face for fields required by face creation");
- return -1;
- }
- }
-
- rc = facemgr_facelet_satisfy_rules(facemgr, facelet);
- if (rc == -3) {
- facelet_set_status(facelet, FACELET_STATUS_IGNORED);
- /* Does not satisfy rules */
- return 0;
- }
-
- if (!facelet_validate_face(facelet))
- return 0;
-
- facelet_set_event(facelet, FACELET_EVENT_CREATE);
- interface_on_event(facemgr->hl, facelet);
-
- /* This works assuming the call to hicn-light is blocking */
- facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ case FACELET_STATUS_UNCERTAIN:
+ case FACELET_STATUS_INCOMPLETE:
+ case FACELET_STATUS_CREATE:
+ case FACELET_STATUS_UPDATE:
+ /* No change */
break;
-
case FACELET_STATUS_CLEAN:
- /* Nothing to do */
- break;
-
- case FACELET_STATUS_DIRTY:
- /*
- * For now we assume only local changes, and proceed to try and
- * update the hICN forwarder.
- *
- * In case of update, the face exists which means we should already
- * have enough information
- */
- if (!facelet_validate_face(facelet)) {
- if (facemgr_complement_facelet(facemgr, facelet) < 0) {
- ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation");
- return -1;
- }
- }
-
- rc = facemgr_facelet_satisfy_rules(facemgr, facelet);
- if (rc == -3) {
- facelet_set_status(facelet, FACELET_STATUS_IGNORED);
- /* Does not satisfy rules */
- return 0;
- }
-
- if (!facelet_validate_face(facelet))
- return 0;
-
- facelet_set_event(facelet, FACELET_EVENT_UPDATE);
- if (interface_on_event(facemgr->hl, facelet) < 0)
- return -1;
-
- /* This works assuming the call to hicn-light is blocking and we
- * have proceeded to all udpates */
- facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ facelet_set_status(facelet, FACELET_STATUS_UPDATE);
break;
-
- case FACELET_STATUS_CONFLICT:
- ERROR("[facemgr_process_update] Conflict resolution (not) yet implemented");
- return -1;
-
- case FACELET_STATUS_ERROR:
- ERROR("[facemgr_process_update] Case ERROR (not) yet implemented");
- break;
-
+ case FACELET_STATUS_DELETE:
+ case FACELET_STATUS_DELETED:
case FACELET_STATUS_IGNORED:
- ERROR("[facemgr_process_update] Case IGNORED (not) yet implemented");
+ /* Reconsider face creation in light of new information */
+ facelet_set_status(facelet, FACELET_STATUS_UNCERTAIN);
break;
-
+ case FACELET_STATUS_UNDEFINED:
case FACELET_STATUS_N:
- ERROR("[facemgr_process_update] Facelet in error");
+ ERROR("[facemgr_process_facelet_update] Unexpected facelet status");
return -1;
}
+
+ if (facemgr_process_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_facelet_update] Error processing facelet");
+ return -1;
+ }
+
return 0;
}
@@ -1102,34 +1245,47 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet)
* \param [in] facemgr - Pointer to the face manager instance
* \param [in] facelet - Pointer to the facelet event to process
* \return 0 if everything went correctly, or -1 in case of error.
+ * -2 means we ignored the face purposedly
*/
int
-facemgr_process_delete(facemgr_t * facemgr, facelet_t * facelet)
+facemgr_process_facelet_delete(facemgr_t * facemgr, facelet_t * facelet)
{
+ switch(facelet_get_status(facelet)) {
+ case FACELET_STATUS_UNCERTAIN:
+ case FACELET_STATUS_INCOMPLETE:
+ case FACELET_STATUS_CREATE:
+ facelet_unset_local_addr(facelet);
+ facelet_unset_local_port(facelet);
+ facelet_unset_remote_addr(facelet);
+ facelet_unset_remote_port(facelet);
+ facelet_unset_bj_done(facelet);
+ //facelet_unset_au_done(facelet);
+ facelet_set_status(facelet, FACELET_STATUS_DELETED);
+ break;
+ case FACELET_STATUS_UPDATE:
+ case FACELET_STATUS_CLEAN:
+ facelet_set_status(facelet, FACELET_STATUS_DELETE);
+ break;
+ case FACELET_STATUS_DELETE:
+ case FACELET_STATUS_IGNORED:
+ case FACELET_STATUS_DELETED:
+ /* Nothing to do */
+ DEBUG("%s\n", facelet_status_str[facelet_get_status(facelet)]);
+ break;
+ case FACELET_STATUS_UNDEFINED:
+ case FACELET_STATUS_N:
+ ERROR("[facemgr_process_facelet_delete] Unexpected facelet status");
+ return -1;
+ }
- DEBUG("[facemgr_process_delete] Deleting facelet on hicn-light");
- if (interface_on_event(facemgr->hl, facelet) < 0)
+ if (facemgr_process_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_facelet_delete] Error processing facelet");
return -1;
-
- /*
- * It might be tempting to cache old information, but for now we reset the
- * facelet state that might change (such as IP addresses etc).
- * netdevice, netdevice_type and admin_state should not be affected.
- */
- DEBUG("[facemgr_process_delete] Cleaning cached data");
- facelet_unset_local_addr(facelet);
- facelet_unset_local_port(facelet);
- facelet_unset_remote_addr(facelet);
- facelet_unset_remote_port(facelet);
-
- facelet_set_status(facelet, FACELET_STATUS_DELETED);
-
- facelet_unset_bj_done(facelet);
+ }
return 0;
}
-
/**
* \brief Process incoming events from interfaces
*
@@ -1147,37 +1303,41 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in)
char facelet_s[MAXSZ_FACELET];
facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet_in);
- //DEBUG("----------------------------------");
DEBUG("EVENT %s", facelet_s);
facelet_t ** cached_facelets = NULL;
int n = facelet_cache_lookup(&facemgr->facelet_cache, facelet_in, &cached_facelets);
if (n < 0) {
ERROR("[facemgr_on_event] Error during cache lookup");
- goto ERR;
+ free(facelet_in);
+ return -1;
}
if (n == 0) {
/* This is a new facelet... we expect a CREATE event. */
switch(facelet_get_event(facelet_in)) {
case FACELET_EVENT_CREATE:
+ facelet_set_status(facelet_in, FACELET_STATUS_UNCERTAIN);
if (facelet_cache_add(&facemgr->facelet_cache, facelet_in) < 0) {
ERROR("[facemgr_on_event] Error adding facelet to cache");
+ free(facelet_in);
+ free(cached_facelets);
return -1;
}
- //DEBUG("Facelet added to cache");
remove_facelet = false;
- if (facemgr_process_create(facemgr, facelet_in) < 0) {
- ERROR("[facemgr_on_event] Error processing CREATE event");
+ if (facemgr_process_facelet_create(facemgr, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error processing facelet CREATE event");
+ ret = -1;
goto ERR;
}
+
break;
case FACELET_EVENT_GET:
/* Insert new facelet in cached */
- rc = facemgr_process_get(facemgr, facelet_in);
+ rc = facemgr_process_facelet_get(facemgr, facelet_in);
if (rc == 0)
remove_facelet = false;
if (rc == -1) {
@@ -1227,10 +1387,12 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in)
ERROR("[facemgr_on_event] Error merging facelets");
continue;
}
- if (facemgr_process_create(facemgr, facelet) < 0) {
- ERROR("[facemgr_on_event] Error processing CREATE event");
+
+ if (facemgr_process_facelet_create(facemgr, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error processing facelet CREATE event");
ret = -1;
}
+
continue;
case FACELET_EVENT_GET: /* should be an INFORM message */
@@ -1245,8 +1407,8 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in)
ERROR("[facemgr_on_event] Error merging facelets");
continue;
}
- if (facemgr_process_update(facemgr, facelet) < 0) {
- ERROR("[facemgr_on_event] Error processing UPDATE event");
+ if (facemgr_process_facelet_update(facemgr, facelet) < 0) {
+ ERROR("[facemgr_on_event] Error processing facelet UPDATE event");
ret = -1;
}
continue;
@@ -1256,8 +1418,8 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in)
ERROR("[facemgr_on_event] Error merging facelets");
continue;
}
- if (facemgr_process_delete(facemgr, facelet) < 0) {
- ERROR("[facemgr_on_event] Error processing DELETE event");
+ if (facemgr_process_facelet_delete(facemgr, facelet) < 0) {
+ ERROR("[facemgr_on_event] Error processing facelet DELETE event");
ret = -1;
}
continue;
@@ -1268,7 +1430,6 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in)
}
}
- free(cached_facelets);
goto DUMP_CACHE;
ERR:
@@ -1283,9 +1444,14 @@ DUMP_CACHE:
DEBUG("----------------------------------");
#endif
+ free(cached_facelets);
+
if (remove_facelet)
facelet_free(facelet_in);
+ if (ret == -1)
+ facemgr_start_reattempts(facemgr);
+
return ret;
}
@@ -1294,18 +1460,62 @@ int facemgr_callback(facemgr_t * facemgr, interface_cb_type_t type, void * data)
switch(type) {
case INTERFACE_CB_TYPE_RAISE_EVENT:
return facemgr_on_event(facemgr, data);
+
case INTERFACE_CB_TYPE_REGISTER_FD:
+ {
+ /* Remember fd for further release */
+ fd_callback_data_t * fd_callback_data = data;
+ interface_t * interface = (interface_t*)(fd_callback_data->owner);
+
+ interface_map_data_t * interface_map_data = NULL;
+ if (interface_map_get(&facemgr->interface_map, interface->name, &interface_map_data) < 0) {
+ ERROR("[facemgr_callback] Error getting interface map data");
+ return -1;
+ }
+ if (!interface_map_data) {
+ ERROR("[facemgr_callback] No entry in interface map data");
+ return -1;
+ }
+ interface_map_data->fds[interface_map_data->num_fds++] = fd_callback_data->fd;
+
return facemgr->callback(facemgr->callback_owner,
FACEMGR_CB_TYPE_REGISTER_FD, data);
+ }
+
+ case INTERFACE_CB_TYPE_UNREGISTER_FD:
+ {
+ fd_callback_data_t * fd_callback_data = data;
+ interface_t * interface = (interface_t*)(fd_callback_data->owner);
+
+ interface_map_data_t * interface_map_data = NULL;
+ if (interface_map_get(&facemgr->interface_map, interface->name, &interface_map_data) < 0) {
+ ERROR("[facemgr_callback] Error getting interface map data");
+ return -1;
+ }
+ if (!interface_map_data) {
+ ERROR("[facemgr_callback] No entry in interface map data");
+ return -1;
+ }
+
+ for (unsigned i = 0; i < interface_map_data->num_fds; i++) {
+ if (interface_map_data->fds[i] == fd_callback_data->fd) {
+ interface_map_data->fds[i] = interface_map_data->fds[--interface_map_data->num_fds];
+ break;
+ }
+ }
+
+ return facemgr->callback(facemgr->callback_owner,
+ FACEMGR_CB_TYPE_UNREGISTER_FD, data);
+ }
+
case INTERFACE_CB_TYPE_REGISTER_TIMER:
return facemgr->callback(facemgr->callback_owner,
FACEMGR_CB_TYPE_REGISTER_TIMER, data);
+
case INTERFACE_CB_TYPE_UNREGISTER_TIMER:
return facemgr->callback(facemgr->callback_owner,
FACEMGR_CB_TYPE_UNREGISTER_TIMER, data);
- case INTERFACE_CB_TYPE_UNREGISTER_FD:
- return facemgr->callback(facemgr->callback_owner,
- FACEMGR_CB_TYPE_UNREGISTER_FD, data);
+
}
return -1;
}
@@ -1497,8 +1707,85 @@ facemgr_set_callback(facemgr_t * facemgr, void * callback_owner, facemgr_cb_t ca
facemgr->callback_owner = callback_owner;
}
-void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data)
+void facemgr_list_facelets(const facemgr_t * facemgr, facemgr_list_facelets_cb_t cb, void * user_data)
{
- //face_cache_iter(&facemgr->face_cache, cb, user_data);
- facelet_cache_dump(&facemgr->facelet_cache);
+ facelet_t ** facelet_array;
+ if (!cb)
+ return;
+ int n = facelet_cache_get_array(&facemgr->facelet_cache, &facelet_array);
+ if (n < 0) {
+ ERROR("[facemgr_list_facelets] Could not retrieve facelets in cache");
+ return;
+ }
+ for (unsigned i = 0; i < n; i++) {
+ facelet_t * facelet = facelet_array[i];
+ cb(facemgr, facelet, user_data);
+ }
+ free(facelet_array);
+}
+
+int
+facemgr_list_facelets_json(const facemgr_t * facemgr, char ** buffer)
+{
+ char * cur;
+ char * s;
+ int rc;
+
+ facelet_t ** facelet_array;
+ int n = facelet_cache_get_array(&facemgr->facelet_cache, &facelet_array);
+ if (n < 0) {
+ ERROR("[facemgr_list_facelets_json] Could not retrieve facelets in cache");
+ return -1;
+ }
+ /* This should be enough for JSON overhead, refine later */
+ size_t size = 2 * n * MAXSZ_FACELET;
+ *buffer = malloc(size);
+ if (!buffer) {
+ ERROR("[facemgr_list_facelets_json] Could not allocate JSON s");
+ free(facelet_array);
+ return -1;
+ }
+ s = *buffer;
+ cur = s;
+
+ rc = snprintf(cur, s + size - cur, "{\"facelets\": [\n");
+ if (rc < 0)
+ goto ERR;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ goto END;
+
+ for (unsigned i = 0; i < n; i++) {
+ facelet_t * facelet = facelet_array[i];
+
+ rc = facelet_snprintf_json(cur, s + size - cur, facelet, /* indent */ 1);
+ if (rc < 0)
+ goto ERR;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ goto END;
+
+ rc = snprintf(cur, s + size - cur, (i == n-1) ? "\n" : ",\n");
+ if (rc < 0)
+ goto ERR;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ goto END;
+ }
+ free(facelet_array);
+
+ rc = snprintf(cur, s + size - cur, "]}\n");
+ if (rc < 0)
+ goto ERR;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ goto END;
+
+END:
+ free(facelet_array);
+ return cur - s;
+
+ERR:
+ free(facelet_array);
+ return rc;
}