From 5fca7ef4838c6a8aede8a5e338940804e8e363f7 Mon Sep 17 00:00:00 2001 From: Jordan Augé Date: Mon, 28 Oct 2019 15:44:42 +0100 Subject: [HICN-363] Fix memory leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7617becdb520f20caca341be11fbb8c1054de021 Signed-off-by: Jordan Augé --- hicn-light/src/hicn/config/configuration.c | 8 +- hicn-light/src/hicn/config/symbolicNameTable.c | 2 +- hicn-light/src/hicn/core/CMakeLists.txt | 6 +- hicn-light/src/hicn/core/forwarder.c | 62 +- hicn-light/src/hicn/core/mapMe.c | 883 ---------------------- hicn-light/src/hicn/core/mapMe.h | 98 --- hicn-light/src/hicn/core/mapme.c | 888 +++++++++++++++++++++++ hicn-light/src/hicn/core/mapme.h | 104 +++ hicn-light/src/hicn/core/messageHandler.h | 6 +- hicn-light/src/hicn/io/hicnListener.c | 2 +- hicn-light/src/hicn/io/listenerSet.c | 2 +- hicn-light/src/hicn/io/streamConnection.c | 1 + hicn-light/src/hicn/io/udpListener.c | 9 +- hicn-light/src/hicn/processor/fibEntry.c | 7 +- hicn-light/src/hicn/processor/messageProcessor.c | 1 + hicn-light/src/hicn/socket/api.c | 45 +- hicn-light/src/hicn/strategies/loadBalancer.c | 13 + 17 files changed, 1105 insertions(+), 1032 deletions(-) delete mode 100644 hicn-light/src/hicn/core/mapMe.c delete mode 100644 hicn-light/src/hicn/core/mapMe.h create mode 100644 hicn-light/src/hicn/core/mapme.c create mode 100644 hicn-light/src/hicn/core/mapme.h (limited to 'hicn-light') diff --git a/hicn-light/src/hicn/config/configuration.c b/hicn-light/src/hicn/config/configuration.c index 4771c4073..c10b01c30 100644 --- a/hicn-light/src/hicn/config/configuration.c +++ b/hicn-light/src/hicn/config/configuration.c @@ -44,7 +44,7 @@ #include #include #ifdef WITH_MAPME -#include +#include #endif /* WITH_MAPME */ #include @@ -498,8 +498,8 @@ struct iovec *configuration_ProcessRemoveListener(Configuration *config, ConnectionTable *connTable = forwarder_GetConnectionTable(config->forwarder); ListenerOps *listenerOps = listenerSet_FindById(listenerSet, listenerId); if (listenerOps) { - ConnectionList *connectionList =connectionTable_GetEntries(connTable); - for (size_t i =0; i < connectionList_Length(connectionList); i++) { + ConnectionList *connectionList = connectionTable_GetEntries(connTable); + for (size_t i = 0; i < connectionList_Length(connectionList); i++) { Connection *connection = connectionList_Get(connectionList, i); const AddressPair *addressPair = connection_GetAddressPair(connection); const Address *address = addressPair_GetLocal(addressPair); @@ -514,6 +514,7 @@ struct iovec *configuration_ProcessRemoveListener(Configuration *config, symbolicNameTable_Remove(config->symbolicNameTable, symbolicConnection); } } + connectionList_Destroy(&connectionList); // remove listener listenerSet_RemoveById(listenerSet, listenerId); success = true; @@ -1391,6 +1392,7 @@ void configuration_ReceiveCommand(Configuration *config, command_id command, switch (command) { case LIST_CONNECTIONS: case LIST_ROUTES: // case LIST_INTERFACES: case ETC...: + case LIST_LISTENERS: parcMemory_Deallocate( &response[1] .iov_base); // deallocate payload only if generated at fwd side diff --git a/hicn-light/src/hicn/config/symbolicNameTable.c b/hicn-light/src/hicn/config/symbolicNameTable.c index 723039fae..e5ae81d3e 100644 --- a/hicn-light/src/hicn/config/symbolicNameTable.c +++ b/hicn-light/src/hicn/config/symbolicNameTable.c @@ -74,7 +74,7 @@ SymbolicNameTable *symbolicNameTable_Create(void) { void symbolicNameTable_Destroy(SymbolicNameTable **tablePtr) { SymbolicNameTable *table = *tablePtr; parcHashCodeTable_Destroy(&table->symbolicNameTable); - // parcHashCodeTable_Destroy(&table->indexToNameTable); + parcHashCodeTable_Destroy(&table->indexToNameTable); parcMemory_Deallocate((void **)&table); *tablePtr = NULL; } diff --git a/hicn-light/src/hicn/core/CMakeLists.txt b/hicn-light/src/hicn/core/CMakeLists.txt index c6e000524..5e2b696d7 100644 --- a/hicn-light/src/hicn/core/CMakeLists.txt +++ b/hicn-light/src/hicn/core/CMakeLists.txt @@ -28,7 +28,7 @@ list(APPEND HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.h ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.h ${CMAKE_CURRENT_SOURCE_DIR}/system.h - ${CMAKE_CURRENT_SOURCE_DIR}/mapMe.h + ${CMAKE_CURRENT_SOURCE_DIR}/mapme.h ${CMAKE_CURRENT_SOURCE_DIR}/wldr.h ${CMAKE_CURRENT_SOURCE_DIR}/messageHandler.h ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.h @@ -46,7 +46,7 @@ list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/message.c ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.c ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.c - ${CMAKE_CURRENT_SOURCE_DIR}/mapMe.c + ${CMAKE_CURRENT_SOURCE_DIR}/mapme.c ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.c ${CMAKE_CURRENT_SOURCE_DIR}/name.c @@ -59,4 +59,4 @@ set(TO_INSTALL_HEADER_FILES ${TO_INSTALL_HEADER_FILES} ${HEADER_FILES} PARENT_SCOPE -) \ No newline at end of file +) diff --git a/hicn-light/src/hicn/core/forwarder.c b/hicn-light/src/hicn/core/forwarder.c index c9527bb49..66551b0ec 100644 --- a/hicn-light/src/hicn/core/forwarder.c +++ b/hicn-light/src/hicn/core/forwarder.c @@ -52,7 +52,7 @@ #include #include #ifdef WITH_MAPME -#include +#include #endif /* WITH_MAPME */ #include #include @@ -197,10 +197,19 @@ Forwarder *forwarder_Create(Logger *logger) { dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_usr1); #endif -#if !defined(__APPLE__) && !defined(_WIN32) && defined(PUNTING) +#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \ + defined(PUNTING) forwarder->hicnSocketHelper = hicn_create(); - if (forwarder->hicnSocketHelper == NULL) return NULL; + if (!forwarder->hicnSocketHelper) + goto ERR_SOCKET; #endif /* __APPLE__ */ + +#ifdef WITH_MAPME + if (!(mapme_create(&forwarder->mapme, forwarder))) + goto ERR_MAPME; +#endif /* WITH_MAPME */ + + /* ignore child */ #ifndef _WIN32 signal(SIGCHLD, SIG_IGN); @@ -220,10 +229,6 @@ Forwarder *forwarder_Create(Logger *logger) { wtnow_timeout.tv_sec = 0; wtnow_timeout.tv_usec = 50000; // 20 Hz keepalive -#ifdef WITH_MAPME - if (!(mapMe_Init(&forwarder->mapme, forwarder))) return NULL; -#endif /* WITH_MAPME */ - PARCEventScheduler *base = dispatcher_GetEventScheduler(forwarder->dispatcher); forwarder->keepalive_event = parcEventTimer_Create( @@ -231,6 +236,39 @@ Forwarder *forwarder_Create(Logger *logger) { parcEventTimer_Start(forwarder->keepalive_event, &wtnow_timeout); return forwarder; + +#ifdef WITH_MAPME +ERR_MAPME: +#endif /* WITH_MAPME */ +#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \ + defined(PUNTING) + hicn_free(forwarder->hicnSocketHelper); +ERR_SOCKET: +#endif + listenerSet_Destroy(&(forwarder->listenerSet)); + connectionManager_Destroy(&(forwarder->connectionManager)); + connectionTable_Destroy(&(forwarder->connectionTable)); + messageProcessor_Destroy(&(forwarder->processor)); + configuration_Destroy(&(forwarder->config)); + messenger_Destroy(&(forwarder->messenger)); + + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_int)); + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_term)); +#ifndef _WIN32 + dispatcher_DestroySignalEvent(forwarder->dispatcher, + &(forwarder->signal_usr1)); +#endif + + parcClock_Release(&forwarder->clock); + logger_Release(&forwarder->logger); + + // do the dispatcher last + dispatcher_Destroy(&(forwarder->dispatcher)); + + parcMemory_Deallocate((void **)&forwarder); + return NULL; } void forwarder_Destroy(Forwarder **ptr) { @@ -239,7 +277,7 @@ void forwarder_Destroy(Forwarder **ptr) { Forwarder *forwarder = *ptr; #if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && \ defined(PUNTING) - hicn_destroy(); + hicn_free(forwarder->hicnSocketHelper); #endif parcEventTimer_Destroy(&(forwarder->keepalive_event)); @@ -252,6 +290,10 @@ void forwarder_Destroy(Forwarder **ptr) { // the messenger is used by many of the other pieces, so destroy it last messenger_Destroy(&(forwarder->messenger)); +#ifdef WITH_MAPME + mapme_free(forwarder->mapme); +#endif /* WITH_MAPME */ + dispatcher_DestroySignalEvent(forwarder->dispatcher, &(forwarder->signal_int)); dispatcher_DestroySignalEvent(forwarder->dispatcher, @@ -532,13 +574,13 @@ void forwarder_onConnectionEvent(Forwarder *forwarder, const Connection *conn, c #ifdef WITH_POLICY messageProcessor_onConnectionEvent(forwarder->processor, conn, event); #else - mapMe_onConnectionEvent(forwarder->mapme, conn, event); + mapme_onConnectionEvent(forwarder->mapme, conn, event); #endif /* WITH_POLICY */ } void forwarder_ProcessMapMe(Forwarder *forwarder, const uint8_t *msgBuffer, unsigned conn_id) { - mapMe_Process(forwarder->mapme, msgBuffer, conn_id); + mapme_Process(forwarder->mapme, msgBuffer, conn_id); } MapMe * diff --git a/hicn-light/src/hicn/core/mapMe.c b/hicn-light/src/hicn/core/mapMe.c deleted file mode 100644 index 2b621387b..000000000 --- a/hicn-light/src/hicn/core/mapMe.c +++ /dev/null @@ -1,883 +0,0 @@ -/* - * 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 mapMe.c - * @brief MAP-Me : AnchorLess Producer Mobility Management. - */ - -#ifdef WITH_MAPME - -#include -#include -#include // printf - -#include -#include -#include -#include -#include -#include // packet types -#include -#include -#include - -#include -#include -#include -#include - -#define MS2NS(x) x * 1000000 -#define T2NS(x) forwarder_TicksToNanos(x) - -#define MAPME_DEFAULT_TU 5000 /* ms */ -#define MAPME_DEFAULT_RETX 500 /* ms */ -#define MAX_RETX 3 - -#define NOT_A_NOTIFICATION false -#define NO_INGRESS 0 -#define TIMER_NO_REPEAT false - -#define DO_DISCOVERY 1 -#define MAPME_INVALID_DICOVERY_SEQ -1 - -#define LOG_FACILITY LoggerFacility_Core - -#define LOG(mapme, log_level, fmt, ...) \ - do { \ - Logger *logger = forwarder_GetLogger(mapme->forwarder); \ - if (logger_IsLoggable(logger, LOG_FACILITY, log_level)) { \ - logger_Log(logger, LOG_FACILITY, log_level, __func__, fmt, \ - ##__VA_ARGS__); \ - } \ - } while (0) - -#define WARN(mapme, fmt, ...) \ - LOG(mapme, PARCLogLevel_Warning, fmt, ##__VA_ARGS__) -#define ERR(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Error, fmt, ##__VA_ARGS__) -#define INFO(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Info, fmt, ##__VA_ARGS__) -#define DEBUG(mapme, fmt, ...) \ - LOG(mapme, PARCLogLevel_Debug, fmt, ##__VA_ARGS__) - -/** - * MAP-Me state data structure - */ -struct mapme { - uint32_t retx; /* ms */ - uint32_t Tu; /* ms */ - bool removeFibEntries; - - Forwarder *forwarder; -}; - -static MapMe MapMeDefault = {.retx = MAPME_DEFAULT_RETX, - .Tu = MAPME_DEFAULT_TU, - .removeFibEntries = false}; - -/******************************************************************************/ - -bool mapMe_Init(MapMe **mapme, Forwarder *forwarder) { - *mapme = malloc(sizeof(MapMe)); - if (!mapme) goto ERR_MALLOC; - - /* Internal state : set default values */ - memcpy(*mapme, &MapMeDefault, sizeof(MapMe)); - - (*mapme)->forwarder = forwarder; - - /* As there is no face table and no related events, we need to install hooks - * in various places in the forwarder, where both control commands and - * signalization are processed. - */ - - return true; - -ERR_MALLOC: - return false; -} - -/****************************************************************************** - * TFIB - ******************************************************************************/ - -#define INVALID_SEQ 0 -#define INIT_SEQ 0 - -typedef struct { - uint32_t seq; - PARCHashMap *nexthops; - /* Update/Notification heuristic */ - Ticks lastAckedUpdate; -} MapMeTFIB; - -static MapMeTFIB *mapMeTFIB_Create() { - MapMeTFIB *tfib; - tfib = malloc(sizeof(MapMeTFIB)); - if (!tfib) goto ERR_MALLOC; - tfib->seq = INIT_SEQ; - tfib->lastAckedUpdate = 0; - tfib->nexthops = parcHashMap_Create(); - if (!tfib->nexthops) goto ERR_HASHMAP; - - return tfib; - -ERR_HASHMAP: - free(tfib); -ERR_MALLOC: - return NULL; -} - -void mapMeTFIB_Release(MapMeTFIB **tfibPtr) { - MapMeTFIB *tfib = *tfibPtr; - parcHashMap_Release(&tfib->nexthops); - free(tfib); - *tfibPtr = NULL; -} - -/** - * @function mapMe_CreateTFIB - * @abstract Associate a new TFIB entry to a FIB entry. - * @param [in] - Pointer to the FIB entry. - * @return Boolean indicating the success of the operation. - */ -static void mapMe_CreateTFIB(FibEntry *fibEntry) { - MapMeTFIB *tfib; - - /* Make sure we don't already have an associated TFIB entry */ - tfib = fibEntry_getUserData(fibEntry); - // assertNull(tfib); - - tfib = mapMeTFIB_Create(); - fibEntry_setUserData(fibEntry, tfib, (void (*)(void **))mapMeTFIB_Release); -} - -#define TFIB(fibEntry) ((MapMeTFIB *)fibEntry_getUserData(fibEntry)) - -static const PARCEventTimer *mapMeTFIB_Get(const MapMeTFIB *tfib, - unsigned conn_id) { - const PARCEventTimer *timer; - const PARCBuffer *buffer; - PARCUnsigned *cid = parcUnsigned_Create(conn_id); - buffer = parcHashMap_Get(tfib->nexthops, cid); - if (!buffer) return NULL; - PARCByteArray *array = parcBuffer_Array(buffer); - timer = *((PARCEventTimer **)parcByteArray_Array(array)); - parcUnsigned_Release(&cid); - return timer; -} - -static void mapMeTFIB_Put(MapMeTFIB *tfib, unsigned conn_id, - const PARCEventTimer *timer) { - /* NOTE: Timers are not objects (the only class not being an object in - * fact), and as such, we cannot use them as values for the HashMap. - * Just like for unsigned we needed the PARC wrapper. - * There is no wrapper for pointers, so we use Arrays, which has an ubly - * syntax... - */ - PARCUnsigned *cid = parcUnsigned_Create(conn_id); - PARCBuffer *buffer = - parcBuffer_CreateFromArray(&timer, sizeof(PARCEventTimer *)); - parcHashMap_Put(tfib->nexthops, cid, buffer); - parcUnsigned_Release(&cid); - parcBuffer_Release(&buffer); -} - -static void mapMeTFIB_Remove(MapMeTFIB *tfib, unsigned conn_id) { - // Who releases the timer ? - PARCUnsigned *cid = parcUnsigned_Create(conn_id); - parcHashMap_Remove(tfib->nexthops, cid); - parcUnsigned_Release(&cid); -} - -static PARCIterator *mapMeTFIB_CreateKeyIterator(const MapMeTFIB *tfib) { - return parcHashMap_CreateKeyIterator(tfib->nexthops); -} - -int hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix) { - NameBitvector *bv = name_GetContentName(name); - ip_prefix_t ip_prefix; - nameBitvector_ToIPAddress(bv, &ip_prefix); - - /* The name length will be equal to ip address' prefix length */ - return hicn_prefix_create_from_ip_prefix(&ip_prefix, prefix); -} - -static Message *mapMe_createMessage(const MapMe *mapme, const Name *name, - mapme_params_t *params) { - Ticks now = forwarder_GetTicks(mapme->forwarder); - Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder)); - - INFO(mapme, "[MAP-Me] CreateMessage type=%d seq=%d", params->type, - params->seq); - - size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN - : HICN_MAPME_V4_HDRLEN; - uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size); - - hicn_prefix_t prefix; - int rc = hicn_prefix_from_name(name, &prefix); - if (rc < 0) { - ERR(mapme, "[MAP-Me] Failed to create lib's name"); - goto ERR_NAME; - } - - INFO(mapme, "[MAP-Me] Creating MAP-Me packet"); - size_t len = hicn_mapme_create_packet(icmp_pkt, &prefix, params); - if (len == 0) { - ERR(mapme, "[MAP-Me] Failed to create mapme packet through lib"); - goto ERR_CREATE; - } - - // hicn_packet_dump(icmp_pkt, MAPME_HDRLEN); - - return message_CreateFromByteArray(NO_INGRESS, icmp_pkt, - MessagePacketType_Interest, now, logger); - -ERR_CREATE: -ERR_NAME: - return NULL; -} - -static Message *mapMe_createAckMessage(const MapMe *mapme, - const uint8_t *msgBuffer, - const mapme_params_t *params) { - Ticks now = forwarder_GetTicks(mapme->forwarder); - Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder)); - - size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN - : HICN_MAPME_V4_HDRLEN; - uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size); - memcpy(icmp_pkt, msgBuffer, size); - - size_t len = hicn_mapme_create_ack(icmp_pkt, params); - if (len != size) { - ERR(mapme, "[MAP-Me] Failed to create mapme ack packet through lib"); - return NULL; - } - - return message_CreateFromByteArray( - NO_INGRESS, icmp_pkt, MessagePacketType_ContentObject, now, logger); -} - -struct setFacePendingArgs { - const MapMe *mapme; - const Name *name; - FibEntry *fibEntry; - unsigned conn_id; - bool send; - bool is_first; - uint32_t num_retx; -}; - -static bool mapMe_setFacePending(const MapMe *mapme, const Name *name, - FibEntry *fibEntry, unsigned conn_id, - bool send, bool is_first, uint32_t num_retx); - -static void mapMe_setFacePendingCallback(int fd, PARCEventType which_event, - void *data) { - struct setFacePendingArgs *args = (struct setFacePendingArgs *)data; - - parcAssertTrue(which_event & PARCEventType_Timeout, - "Event incorrect, expecting %X set, got %X", - PARCEventType_Timeout, which_event); - - INFO(args->mapme, "Timeout during retransmission. Re-sending"); - mapMe_setFacePending(args->mapme, args->name, args->fibEntry, args->conn_id, - args->send, args->is_first, args->num_retx); -} - -/** - * @brief Update/Notification heuristic: - * - * NOTE: IN are currently disabled until the proper placeholder is agreed in the - * interest header. - */ -static hicn_mapme_type_t mapMe_getTypeFromHeuristic(const MapMe *mapme, - FibEntry *fibEntry) { -#if 0 /* interplay of IU/IN */ - if (TFIB(fibEntry)->lastAckedUpdate == 0) { - return UPDATE; - } else { - Ticks interval = now - TFIB(fibEntry)->lastAckedUpdate; - return (T2NS(interval) > MS2NS(mapme->Tu)) ? UPDATE : NOTIFICATION; - } -#else /* Always send IU */ - return UPDATE; -#endif -} - -static bool mapMe_setFacePending(const MapMe *mapme, const Name *name, - FibEntry *fibEntry, unsigned conn_id, - bool send, bool is_first, uint32_t num_retx) { - int rc; - - INFO(mapme, "[MAP-Me] SetFacePending connection=%d prefix=XX retx=%d", - conn_id, num_retx); - - /* NOTE: if the face is pending an we receive an IN, maybe we should not - * cancel the timer - */ - Dispatcher *dispatcher = forwarder_GetDispatcher(mapme->forwarder); - PARCEventTimer *timer; - - // NOTE - // - at producer, send always true, we always send something reliably so we - // set the timer. - // - in the network, we always forward an IU, and never an IN - if (is_first || send) { - mapme_params_t params = { - .protocol = IPPROTO_IPV6, - .type = is_first ? mapMe_getTypeFromHeuristic(mapme, fibEntry) : UPDATE, - .seq = TFIB(fibEntry)->seq}; - Message *special_interest = mapMe_createMessage(mapme, name, ¶ms); - if (!special_interest) { - INFO(mapme, "[MAP-Me] Could not create special interest"); - return false; - } - - const ConnectionTable *table = - forwarder_GetConnectionTable(mapme->forwarder); - const Connection *conn = - connectionTable_FindById((ConnectionTable *)table, conn_id); - if (conn) { - const Name * name = message_GetName(special_interest); - char * name_str = name_ToString(name); - INFO(mapme, "[MAP-Me] Sending MAP-Me packet name=%s seq=%d conn=%d", - name_str, params.seq, conn_id); - free(name_str); - connection_ReSend(conn, special_interest, NOT_A_NOTIFICATION); - } else { - INFO(mapme, "[MAP-Me] Stopped retransmissions as face went down"); - } - - if (num_retx < MAX_RETX) { - INFO(mapme, "[MAP-Me] - Scheduling retransmission\n"); - /* Schedule retransmission */ - struct setFacePendingArgs *args = - malloc(sizeof(struct setFacePendingArgs)); - if (!args) goto ERR_MALLOC; - args->mapme = mapme; - args->name = name; - args->fibEntry = fibEntry; - args->conn_id = conn_id; - args->send = send; - args->is_first = is_first; - args->num_retx = num_retx + 1; - - timer = dispatcher_CreateTimer(dispatcher, TIMER_NO_REPEAT, - mapMe_setFacePendingCallback, args); - struct timeval timeout = {mapme->retx / 1000, - (mapme->retx % 1000) * 1000}; - rc = parcEventTimer_Start(timer, &timeout); - if (rc < 0) goto ERR_TIMER; - } else { - INFO(mapme, "[MAP-Me] Last retransmission."); - timer = NULL; - } - } else { - INFO(mapme, "[MAP-Me] - not forwarding as send is False"); - timer = NULL; - } - - PARCEventTimer *oldTimer = - (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_id); - if (oldTimer) { - INFO(mapme, "[MAP-Me] - Found old timer, would need to cancel !"); - // parcEventTimer_Stop(oldTimer); - } - INFO(mapme, "[MAP-Me] - Putting new timer in TFIB"); - if (timer) mapMeTFIB_Put(TFIB(fibEntry), conn_id, timer); - - return true; - -ERR_MALLOC: -ERR_TIMER: - return false; -} - -/*------------------------------------------------------------------------------ - * Event handling - *----------------------------------------------------------------------------*/ - -/* - * Return true if we have at least one local connection as next hop - */ -static bool mapMe_hasLocalNextHops(const MapMe *mapme, - const FibEntry *fibEntry) { - const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry); - const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder); - - for (size_t j = 0; j < fibEntry_NexthopCount(fibEntry); j++) { - /* Retrieve Nexthop #j */ - unsigned conn_id = numberSet_GetItem(nexthops, j); - const Connection *conn = - connectionTable_FindById((ConnectionTable *)table, conn_id); - - /* Ignore non-local connections */ - if (!connection_IsLocal(conn)) continue; - /* We don't need to test against conn_added since we don't - * expect it to have any entry in the FIB */ - - return true; - } - return false; -} - -/* - * Callback called everytime a new connection is created by the control protocol - */ -void mapMe_onConnectionEvent(const MapMe *mapme, const Connection *conn_added, connection_event_t event) { - switch(event) { - case CONNECTION_EVENT_CREATE: - case CONNECTION_EVENT_SET_UP: - { - FibEntryList *fiblist; - - /* Ignore local connections corresponding to applications for now */ - if (connection_IsLocal(conn_added)) - return; - - unsigned conn_added_id = connection_GetConnectionId(conn_added); - INFO(mapme, "[MAP-Me] New connection %d", conn_added_id); - - /* - * Iterate on FIB to find locally served prefix - * Ideally, we want to avoid a FIB scan everytime a face is added/removed - */ - fiblist = forwarder_GetFibEntries(mapme->forwarder); - for (size_t i = 0; i < fibEntryList_Length(fiblist); i++) { - FibEntry *fibEntry = (FibEntry *)fibEntryList_Get(fiblist, i); - const Name *name = fibEntry_GetPrefix(fibEntry); - - /* Skip entries that have no local connection as next hop */ - if (!mapMe_hasLocalNextHops(mapme, fibEntry)) - continue; - - /* This entry corresponds to a locally served prefix, set - * Special Interest */ - if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */ - mapMe_CreateTFIB(fibEntry); - TFIB(fibEntry)->seq++; - - char *name_str = name_ToString(name); - INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str, - conn_added_id); - free(name_str); - - mapMe_setFacePending(mapme, name, fibEntry, conn_added_id, true, true, 0); - } - break; - } - case CONNECTION_EVENT_DELETE: - case CONNECTION_EVENT_SET_DOWN: - case CONNECTION_EVENT_UPDATE: - break; - } -} - -#ifdef WITH_POLICY -void mapMe_onPolicyUpdate(const MapMe *mapme, const Connection *conn_selected, FibEntry * fibEntry) -{ - /* Ignore local connections corresponding to applications for now */ - if (connection_IsLocal(conn_selected)) - return; - - unsigned conn_selected_id = connection_GetConnectionId(conn_selected); - INFO(mapme, "[MAP-Me] New connection %d", conn_selected_id); - - const Name *name = fibEntry_GetPrefix(fibEntry); - - /* Skip entries that have no local connection as next hop */ - if (!mapMe_hasLocalNextHops(mapme, fibEntry)) - return; - - /* This entry corresponds to a locally served prefix, set - * Special Interest */ - if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */ - mapMe_CreateTFIB(fibEntry); - TFIB(fibEntry)->seq++; - - char *name_str = name_ToString(name); - INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str, - conn_selected_id); - free(name_str); - - mapMe_setFacePending(mapme, name, fibEntry, conn_selected_id, true, true, 0); -} -#endif /* WITH_POLICY */ - -/*------------------------------------------------------------------------------ - * Special Interest handling - *----------------------------------------------------------------------------*/ - -/** - * @discussion This function is way too long and should be cut out - */ -static bool mapMe_onSpecialInterest(const MapMe *mapme, - const uint8_t *msgBuffer, - unsigned conn_in_id, hicn_prefix_t *prefix, - mapme_params_t *params) { - const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder); - /* The cast is needed since connectionTable_FindById miss the - * const qualifier for the first parameter */ - const Connection *conn_in = - connectionTable_FindById((ConnectionTable *)table, conn_in_id); - seq_t fibSeq, seq = params->seq; - bool send = (params->type == UPDATE); - bool rv; - - Name *name = name_CreateFromPacket(msgBuffer, MessagePacketType_Interest); - name_setLen(name, prefix->len); - char *name_str = name_ToString(name); - INFO(mapme, - "[MAP-Me] Ack'ed Special Interest on connection %d - prefix=%s type=XX " - "seq=%d", - conn_in_id, name_str, seq); - free(name_str); - - /* - * Immediately send an acknowledgement back on the ingress connection - * We always ack, even duplicates. - */ - Message *ack = mapMe_createAckMessage(mapme, msgBuffer, params); - if (!ack) goto ERR_ACK_CREATE; - rv = connection_ReSend(conn_in, ack, NOT_A_NOTIFICATION); - if (!rv) goto ERR_ACK_SEND; - message_Release(&ack); - - /* EPM on FIB */ - /* only the processor has access to the FIB */ - FIB *fib = forwarder_getFib(mapme->forwarder); - - FibEntry *fibEntry = fib_Contains(fib, name); - if (!fibEntry) { - INFO(mapme, - "[MAP-Me] - Re-creating FIB entry with next hop on connection %d", - conn_in_id); - /* - * This might happen for a node hosting a producer which has moved. - * Destroying the face has led to removing all corresponding FIB - * entries. In that case, we need to correctly restore the FIB entries. - */ - strategy_type fwdStrategy = LAST_STRATEGY_VALUE; - - /* - * It might also be due to the announcement of a more specific prefix. In - * that case we need to perform a FIB lookup to find the next hops to which - * the message should be propagated. - */ -#ifdef WITH_POLICY - fibEntry = fibEntry_Create(name, fwdStrategy, mapme->forwarder); -#else - fibEntry = fibEntry_Create(name, fwdStrategy); -#endif /* WITH_POLICY */ - FibEntry *lpm = fib_MatchName(fib, name); - mapMe_CreateTFIB(fibEntry); - fib_Add(fib, fibEntry); - if (!lpm) { - TFIB(fibEntry)->seq = seq; - fibEntry_AddNexthop(fibEntry, conn_in_id); - return true; - } - - /* - * We make a clone of the FIB entry (zero'ing the sequence number ?) with - * the more specific name, and proceed as usual. Worst case we clone the - * default route... - */ - const NumberSet *lpm_nexthops = fibEntry_GetNexthops(lpm); - for (size_t i = 0; i < numberSet_Length(lpm_nexthops); i++) { - fibEntry_AddNexthop(fibEntry, numberSet_GetItem(lpm_nexthops, i)); - } - - } else if (!TFIB(fibEntry)) { - /* Create TFIB associated to FIB entry */ - INFO(mapme, - "[MAP-Me] - Creating TFIB entry with default sequence number"); - mapMe_CreateTFIB(fibEntry); - } - - fibSeq = TFIB(fibEntry)->seq; - if (seq > fibSeq) { - INFO(mapme, - "[MAP-Me] - Higher sequence number than FIB %d, updating seq and " - "next hops", - fibSeq); - /* This has to be done first to allow processing SpecialInterestAck's */ - TFIB(fibEntry)->seq = seq; - - /* Reliably forward the IU on all prevHops */ - INFO(mapme, "[MAP-Me] - (1/3) processing prev hops"); - if (params->type == UPDATE) { - PARCIterator *iterator = mapMeTFIB_CreateKeyIterator(TFIB(fibEntry)); - while (parcIterator_HasNext(iterator)) { - PARCUnsigned *cid = parcIterator_Next(iterator); - unsigned conn_id = parcUnsigned_GetUnsigned(cid); - INFO(mapme, "[MAP-Me] - Re-sending IU to pending connection %d", - conn_id); - mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, - conn_id, false, false, 0); - } - parcIterator_Release(&iterator); - } - - /* nextHops -> prevHops - * - * We add to the list of pendingUpdates the current next hops, and - * eventually forward them an IU too. - * - * Exception: nextHops -> nextHops - * Because of retransmission issues, it is possible that a second interest - * (with same of higher sequence number) is receive from a next-hop - * interface. In that case, the face remains a next hop. - */ - const NumberSet *nexthops_old = fibEntry_GetNexthops(fibEntry); - - /* We make a copy to be able to send IU _after_ updating next hops */ - NumberSet *nexthops = numberSet_Create(); - numberSet_AddSet(nexthops, nexthops_old); - - /* We are considering : * -> nextHops - * - * If inFace was a previous hop, we need to cancel the timer and remove - * the entry. Also, the face should be added to next hops. - * - * Optimization : nextHops -> nextHops - * - no next hop to add - * - we know that inFace was not a previous hop since it was a next hop and - * this forms a partition. No need for a search - */ - - INFO(mapme, "[MAP-Me] - (3/3) next hops ~~> prev hops"); - PARCEventTimer *oldTimer = - (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_in_id); - if (oldTimer) { - /* This happens if we receive an IU while we are still sending - * one in the other direction - */ - INFO(mapme, "[MAP-Me] - Canceled pending timer"); - parcEventTimer_Stop(oldTimer); - mapMeTFIB_Remove(TFIB(fibEntry), conn_in_id); - } - - /* Remove all next hops */ - for (size_t k = 0; k < numberSet_Length(nexthops_old); k++) { - unsigned conn_id = numberSet_GetItem(nexthops_old, k); - INFO(mapme, "[MAP-Me] - Replaced next hops by connection %d", conn_id); - fibEntry_RemoveNexthopByConnectionId(fibEntry, conn_id); - } - fibEntry_AddNexthop(fibEntry, conn_in_id); - - INFO(mapme, "[MAP-Me] - (2/3) processing next hops"); - bool complete = true; - for (size_t k = 0; k < numberSet_Length(nexthops); k++) { - unsigned conn_id = numberSet_GetItem(nexthops, k); - INFO(mapme, " - Next hop connection %d", conn_id); - if (conn_id == conn_in_id) { - INFO(mapme, " . Ignored this next hop since equal to ingress face"); - continue; - } - - INFO(mapme, "[MAP-Me] - Sending IU on current next hop connection %d", - conn_id); - mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, - conn_id, send, false, 0); - complete = false; - } - - /* - * The update is completed when the IU could not be sent to any - * other next hop. - */ - if (complete) INFO(mapme, "[MAP-Me] - Update completed !"); - - numberSet_Release(&nexthops); - - } else if (seq == fibSeq) { - /* - * Multipath, multihoming, multiple producers or duplicate interest - * - * In all cases, we assume the propagation was already done when the first - * interest with the same sequence number was received, so we stop here - * - * It might happen that the previous AP has still a connection to the - * producer and that we received back our own IU. In that case, we just - * need to Ack and ignore it. - */ - if (mapMe_hasLocalNextHops(mapme, fibEntry)) { - INFO(mapme, "[MAP-Me] - Received original interest... Update complete"); - return true; - } - - INFO(mapme, "[MAP-Me] - Adding multipath next hop on connection %d", - conn_in_id); - fibEntry_AddNexthop(fibEntry, conn_in_id); - - } else { // seq < fibSeq - /* - * Face is propagating outdated information, we can just - * consider it as a prevHops. Send the special interest backwards with - * the new sequence number to reconciliate this outdated part of the - * arborescence. - */ - INFO( - mapme, - "[MAP-Me] - Update interest %d -> %d sent backwards on connection %d", - seq, fibSeq, conn_in_id); - mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, - conn_in_id, send, false, 0); - } - - return true; - -ERR_ACK_SEND: - message_Release(&ack); -ERR_ACK_CREATE: - return false; -} - -void mapMe_onSpecialInterestAck(const MapMe *mapme, const uint8_t *msgBuffer, - unsigned conn_in_id, hicn_prefix_t *prefix, - mapme_params_t *params) { - INFO(mapme, "[MAP-Me] Receive IU/IN Ack on connection %d", conn_in_id); - - const Name * name = - name_CreateFromPacket(msgBuffer, MessagePacketType_ContentObject); - name_setLen((Name*) name, prefix->len); - char * name_str = name_ToString(name); - INFO(mapme, "[MAP-Me] Received ack for name prefix=%s seq=%d on conn id=%d", - name_str, params->seq, conn_in_id); - free(name_str); - - FIB *fib = forwarder_getFib(mapme->forwarder); - FibEntry *fibEntry = fib_Contains(fib, name); - if (!fibEntry) { - return; - } - parcAssertNotNull(fibEntry, - "No corresponding FIB entry for name contained in IU Ack"); - - /* Test if the latest pending update has been ack'ed, otherwise just ignore */ - seq_t seq = params->seq; - if (seq != INVALID_SEQ) { - seq_t fibSeq = TFIB(fibEntry)->seq; - - if (seq < fibSeq) { - INFO(mapme, - "[MAP-Me] - Ignored special interest Ack with seq=%u, expected %u", - seq, fibSeq); - return; - } - } - - /* - * Ignore the Ack if no TFIB is present, or it has no corresponding entry - * with the ingress face. - * Note: previously, we were creating the TFIB entry - */ - if (!TFIB(fibEntry)) { - INFO(mapme, "[MAP-Me] - Ignored ACK for prefix with no TFIB entry"); - return; - } - - PARCEventTimer *timer = - (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_in_id); - if (!timer) { - INFO(mapme, - "[MAP-Me] - Ignored ACK for prefix not having the Connection in " - "TFIB entry. Possible duplicate ?"); - return; - } - - /* Stop timer and remove entry from TFIB */ - parcEventTimer_Stop(timer); - mapMeTFIB_Remove(TFIB(fibEntry), conn_in_id); - - INFO(mapme, "[MAP-Me] - Removing TFIB entry for ack on connection %d", - conn_in_id); - - /* We need to update the timestamp only for IU Acks, not for IN Acks */ - if (params->type == UPDATE_ACK) { - INFO(mapme, "[MAP-Me] - Updating LastAckedUpdate"); - TFIB(fibEntry)->lastAckedUpdate = forwarder_GetTicks(mapme->forwarder); - } -} - -/*----------------------------------------------------------------------------- - * Overloaded functions - *----------------------------------------------------------------------------*/ - -/* - * @abstract returns where to forward a normal interests(nexthops) defined by - * mapme, it also set the sequnence number properly if needed - */ - -/****************************************************************************** - * Public functions (exposed in the .h) - ******************************************************************************/ - -/* - * Returns true iif the message corresponds to a MAP-Me packet - */ -bool mapMe_isMapMe(const uint8_t *packet) { - hicn_mapme_header_t * mapme = (hicn_mapme_header_t*)packet; - - switch(HICN_IP_VERSION(packet)) { - case 4: - if (mapme->v4.ip.protocol != IPPROTO_ICMP) - return false; - return HICN_IS_MAPME(mapme->v4.icmp_rd.type, mapme->v4.icmp_rd.code); - case 6: - if (mapme->v6.ip.nxt != IPPROTO_ICMPV6) - return false; - return HICN_IS_MAPME(mapme->v6.icmp_rd.type, mapme->v6.icmp_rd.code); - default: - return false; - } -} - -/** - * @discussion The exact type of the MapMe message is determined after - * reception. In hICN, Interest Update and Notifications look like regular - * Interest packets, and are first punted from the normal path by the forwarder, - * then treated as such in the Listener to reach this function. Acknowledgements - * are received as Content (Data) packets and will land here too. - * - * This function is in charge of abstracting the low-level implementation of - * MAP-Me (eg. ICMP packets) and return higher level messages that can be - * processed by MAP-Me core. - */ -void mapMe_Process(const MapMe *mapme, const uint8_t *msgBuffer, - unsigned conn_id) { - hicn_prefix_t prefix; - mapme_params_t params; - hicn_mapme_parse_packet(msgBuffer, &prefix, ¶ms); - - switch (params.type) { - case UPDATE: - case NOTIFICATION: - mapMe_onSpecialInterest(mapme, msgBuffer, conn_id, &prefix, ¶ms); - break; - case UPDATE_ACK: - case NOTIFICATION_ACK: - mapMe_onSpecialInterestAck(mapme, msgBuffer, conn_id, &prefix, ¶ms); - break; - default: - ERR(mapme, "[MAP-Me] Unknown message"); - break; - } -} - -#endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/core/mapMe.h b/hicn-light/src/hicn/core/mapMe.h deleted file mode 100644 index 7ea90d299..000000000 --- a/hicn-light/src/hicn/core/mapMe.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 mapMe.h - * @brief MAP-Me : AnchorLess Producer Mobility Management - */ - -#ifndef mapMe_h -#define mapMe_h - -#ifdef WITH_MAPME - -#include -#include - -#include -#include -#include -#include - -struct mapme; -typedef struct mapme MapMe; - -/** - * @function MapMe_Init - * @abstract Initializes MAP-Me state in the forwarder. - * @return bool - Boolean informing about the success of MAP-Me initialization. - */ -bool mapMe_Init(MapMe **mapme, Forwarder *Forwarder); - -/** - * @function messageHandler_isMapMe - * @abstract Identifies MAP-Me messages - * @discussion This function can be used by the forwarder to dispatch MAP-Me - * message to the appropriate processing function. Ideally this would be - * done through hooks defined in the Init function. - * @param [in] msgBuffer - The buffer to match - * @return A boolean indicating whether message is a MAP-Me control message. - */ -bool mapMe_isMapMe(const uint8_t *msgBuffer); - -/** - * @function mapMe_handleMapMeMessage - * @abstract Process a MAP-Me message. - * @param [in] mapme - Pointer to the MAP-Me data structure. - * @param [in] message - MAP-Me buffer - * @param [in] conn_id - Ingress connection id - */ -void mapMe_Process(const MapMe *mapme, const uint8_t *msgBuffer, - unsigned conn_id); - -/** - * @function mapMe_onConnectionEvent - * @abstract Callback following the addition of the face though the control - * protocol. - * @discussion This callback triggers the sending of control packets by MAP-Me. - * @param [in] mapme - Pointer to the MAP-Me data structure. - * @param [in] conn - The newly added connection. - * @param [in] event - Connection event - */ -void mapMe_onConnectionEvent(const MapMe *mapme, const Connection *conn, connection_event_t event); - -#ifdef WITH_POLICY - -/** - * @function mapMe_onPolicyUpdate - */ -void mapMe_onPolicyUpdate(const MapMe *mapme, const Connection *conn_added, FibEntry * fibEntry); -#endif /* WITH_POLICY */ - -/** - * @function mapMe_getNextHops - * @abstract return the nexthops to forward interests defined by mapme, it - * covers also the case where local discovery mechanisms are trriggered. - */ -NumberSet *mapMe_getNextHops(const MapMe *mapme, FibEntry *fibEntry, - const Message *interest); - -hicn_mapme_type_t mapMe_PktType_To_LibHicnPktType(MessagePacketType type); - -MessagePacketType mapMe_LibHicnPktType_To_PktType(hicn_mapme_type_t type); - -#endif /* WITH_MAPME */ - -#endif // mapMe_h diff --git a/hicn-light/src/hicn/core/mapme.c b/hicn-light/src/hicn/core/mapme.c new file mode 100644 index 000000000..94ada3afa --- /dev/null +++ b/hicn-light/src/hicn/core/mapme.c @@ -0,0 +1,888 @@ +/* + * 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 mapme.c + * @brief MAP-Me : AnchorLess Producer Mobility Management. + */ + +#ifdef WITH_MAPME + +#include +#include +#include // printf + +#include +#include +#include +#include +#include +#include // packet types +#include +#include +#include + +#include +#include +#include +#include + +#define MS2NS(x) x * 1000000 +#define T2NS(x) forwarder_TicksToNanos(x) + +#define MAPME_DEFAULT_TU 5000 /* ms */ +#define MAPME_DEFAULT_RETX 500 /* ms */ +#define MAX_RETX 3 + +#define NOT_A_NOTIFICATION false +#define NO_INGRESS 0 +#define TIMER_NO_REPEAT false + +#define DO_DISCOVERY 1 +#define MAPME_INVALID_DICOVERY_SEQ -1 + +#define LOG_FACILITY LoggerFacility_Core + +#define LOG(mapme, log_level, fmt, ...) \ + do { \ + Logger *logger = forwarder_GetLogger(mapme->forwarder); \ + if (logger_IsLoggable(logger, LOG_FACILITY, log_level)) { \ + logger_Log(logger, LOG_FACILITY, log_level, __func__, fmt, \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define WARN(mapme, fmt, ...) \ + LOG(mapme, PARCLogLevel_Warning, fmt, ##__VA_ARGS__) +#define ERR(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Error, fmt, ##__VA_ARGS__) +#define INFO(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Info, fmt, ##__VA_ARGS__) +#define DEBUG(mapme, fmt, ...) \ + LOG(mapme, PARCLogLevel_Debug, fmt, ##__VA_ARGS__) + +/** + * MAP-Me state data structure + */ +struct mapme { + uint32_t retx; /* ms */ + uint32_t Tu; /* ms */ + bool removeFibEntries; + + Forwarder *forwarder; +}; + +static MapMe MapMeDefault = {.retx = MAPME_DEFAULT_RETX, + .Tu = MAPME_DEFAULT_TU, + .removeFibEntries = false}; + +/******************************************************************************/ + +bool mapme_create(MapMe **mapme, Forwarder *forwarder) { + *mapme = malloc(sizeof(MapMe)); + if (!mapme) goto ERR_MALLOC; + + /* Internal state : set default values */ + memcpy(*mapme, &MapMeDefault, sizeof(MapMe)); + + (*mapme)->forwarder = forwarder; + + /* As there is no face table and no related events, we need to install hooks + * in various places in the forwarder, where both control commands and + * signalization are processed. + */ + + return true; + +ERR_MALLOC: + return false; +} + +void mapme_free(MapMe *mapme) +{ + free(mapme); +} + +/****************************************************************************** + * TFIB + ******************************************************************************/ + +#define INVALID_SEQ 0 +#define INIT_SEQ 0 + +typedef struct { + uint32_t seq; + PARCHashMap *nexthops; + /* Update/Notification heuristic */ + Ticks lastAckedUpdate; +} MapMeTFIB; + +static MapMeTFIB *mapmeTFIB_Create() { + MapMeTFIB *tfib; + tfib = malloc(sizeof(MapMeTFIB)); + if (!tfib) goto ERR_MALLOC; + tfib->seq = INIT_SEQ; + tfib->lastAckedUpdate = 0; + tfib->nexthops = parcHashMap_Create(); + if (!tfib->nexthops) goto ERR_HASHMAP; + + return tfib; + +ERR_HASHMAP: + free(tfib); +ERR_MALLOC: + return NULL; +} + +void mapmeTFIB_Release(MapMeTFIB **tfibPtr) { + MapMeTFIB *tfib = *tfibPtr; + parcHashMap_Release(&tfib->nexthops); + free(tfib); + *tfibPtr = NULL; +} + +/** + * @function mapme_CreateTFIB + * @abstract Associate a new TFIB entry to a FIB entry. + * @param [in] - Pointer to the FIB entry. + * @return Boolean indicating the success of the operation. + */ +static void mapme_CreateTFIB(FibEntry *fibEntry) { + MapMeTFIB *tfib; + + /* Make sure we don't already have an associated TFIB entry */ + tfib = fibEntry_getUserData(fibEntry); + // assertNull(tfib); + + tfib = mapmeTFIB_Create(); + fibEntry_setUserData(fibEntry, tfib, (void (*)(void **))mapmeTFIB_Release); +} + +#define TFIB(fibEntry) ((MapMeTFIB *)fibEntry_getUserData(fibEntry)) + +static const PARCEventTimer *mapmeTFIB_Get(const MapMeTFIB *tfib, + unsigned conn_id) { + const PARCEventTimer *timer; + const PARCBuffer *buffer; + PARCUnsigned *cid = parcUnsigned_Create(conn_id); + buffer = parcHashMap_Get(tfib->nexthops, cid); + if (!buffer) return NULL; + PARCByteArray *array = parcBuffer_Array(buffer); + timer = *((PARCEventTimer **)parcByteArray_Array(array)); + parcUnsigned_Release(&cid); + return timer; +} + +static void mapmeTFIB_Put(MapMeTFIB *tfib, unsigned conn_id, + const PARCEventTimer *timer) { + /* NOTE: Timers are not objects (the only class not being an object in + * fact), and as such, we cannot use them as values for the HashMap. + * Just like for unsigned we needed the PARC wrapper. + * There is no wrapper for pointers, so we use Arrays, which has an ubly + * syntax... + */ + PARCUnsigned *cid = parcUnsigned_Create(conn_id); + PARCBuffer *buffer = + parcBuffer_CreateFromArray(&timer, sizeof(PARCEventTimer *)); + parcHashMap_Put(tfib->nexthops, cid, buffer); + parcUnsigned_Release(&cid); + parcBuffer_Release(&buffer); +} + +static void mapmeTFIB_Remove(MapMeTFIB *tfib, unsigned conn_id) { + // Who releases the timer ? + PARCUnsigned *cid = parcUnsigned_Create(conn_id); + parcHashMap_Remove(tfib->nexthops, cid); + parcUnsigned_Release(&cid); +} + +static PARCIterator *mapmeTFIB_CreateKeyIterator(const MapMeTFIB *tfib) { + return parcHashMap_CreateKeyIterator(tfib->nexthops); +} + +int hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix) { + NameBitvector *bv = name_GetContentName(name); + ip_prefix_t ip_prefix; + nameBitvector_ToIPAddress(bv, &ip_prefix); + + /* The name length will be equal to ip address' prefix length */ + return hicn_prefix_create_from_ip_prefix(&ip_prefix, prefix); +} + +static Message *mapme_createMessage(const MapMe *mapme, const Name *name, + mapme_params_t *params) { + Ticks now = forwarder_GetTicks(mapme->forwarder); + Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder)); + + INFO(mapme, "[MAP-Me] CreateMessage type=%d seq=%d", params->type, + params->seq); + + size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN + : HICN_MAPME_V4_HDRLEN; + uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size); + + hicn_prefix_t prefix; + int rc = hicn_prefix_from_name(name, &prefix); + if (rc < 0) { + ERR(mapme, "[MAP-Me] Failed to create lib's name"); + goto ERR_NAME; + } + + INFO(mapme, "[MAP-Me] Creating MAP-Me packet"); + size_t len = hicn_mapme_create_packet(icmp_pkt, &prefix, params); + if (len == 0) { + ERR(mapme, "[MAP-Me] Failed to create mapme packet through lib"); + goto ERR_CREATE; + } + + // hicn_packet_dump(icmp_pkt, MAPME_HDRLEN); + + return message_CreateFromByteArray(NO_INGRESS, icmp_pkt, + MessagePacketType_Interest, now, logger); + +ERR_CREATE: +ERR_NAME: + return NULL; +} + +static Message *mapme_createAckMessage(const MapMe *mapme, + const uint8_t *msgBuffer, + const mapme_params_t *params) { + Ticks now = forwarder_GetTicks(mapme->forwarder); + Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder)); + + size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN + : HICN_MAPME_V4_HDRLEN; + uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size); + memcpy(icmp_pkt, msgBuffer, size); + + size_t len = hicn_mapme_create_ack(icmp_pkt, params); + if (len != size) { + ERR(mapme, "[MAP-Me] Failed to create mapme ack packet through lib"); + return NULL; + } + + return message_CreateFromByteArray( + NO_INGRESS, icmp_pkt, MessagePacketType_ContentObject, now, logger); +} + +struct setFacePendingArgs { + const MapMe *mapme; + const Name *name; + FibEntry *fibEntry; + unsigned conn_id; + bool send; + bool is_first; + uint32_t num_retx; +}; + +static bool mapme_setFacePending(const MapMe *mapme, const Name *name, + FibEntry *fibEntry, unsigned conn_id, + bool send, bool is_first, uint32_t num_retx); + +static void mapme_setFacePendingCallback(int fd, PARCEventType which_event, + void *data) { + struct setFacePendingArgs *args = (struct setFacePendingArgs *)data; + + parcAssertTrue(which_event & PARCEventType_Timeout, + "Event incorrect, expecting %X set, got %X", + PARCEventType_Timeout, which_event); + + INFO(args->mapme, "Timeout during retransmission. Re-sending"); + mapme_setFacePending(args->mapme, args->name, args->fibEntry, args->conn_id, + args->send, args->is_first, args->num_retx); +} + +/** + * @brief Update/Notification heuristic: + * + * NOTE: IN are currently disabled until the proper placeholder is agreed in the + * interest header. + */ +static hicn_mapme_type_t mapme_getTypeFromHeuristic(const MapMe *mapme, + FibEntry *fibEntry) { +#if 0 /* interplay of IU/IN */ + if (TFIB(fibEntry)->lastAckedUpdate == 0) { + return UPDATE; + } else { + Ticks interval = now - TFIB(fibEntry)->lastAckedUpdate; + return (T2NS(interval) > MS2NS(mapme->Tu)) ? UPDATE : NOTIFICATION; + } +#else /* Always send IU */ + return UPDATE; +#endif +} + +static bool mapme_setFacePending(const MapMe *mapme, const Name *name, + FibEntry *fibEntry, unsigned conn_id, + bool send, bool is_first, uint32_t num_retx) { + int rc; + + INFO(mapme, "[MAP-Me] SetFacePending connection=%d prefix=XX retx=%d", + conn_id, num_retx); + + /* NOTE: if the face is pending an we receive an IN, maybe we should not + * cancel the timer + */ + Dispatcher *dispatcher = forwarder_GetDispatcher(mapme->forwarder); + PARCEventTimer *timer; + + // NOTE + // - at producer, send always true, we always send something reliably so we + // set the timer. + // - in the network, we always forward an IU, and never an IN + if (is_first || send) { + mapme_params_t params = { + .protocol = IPPROTO_IPV6, + .type = is_first ? mapme_getTypeFromHeuristic(mapme, fibEntry) : UPDATE, + .seq = TFIB(fibEntry)->seq}; + Message *special_interest = mapme_createMessage(mapme, name, ¶ms); + if (!special_interest) { + INFO(mapme, "[MAP-Me] Could not create special interest"); + return false; + } + + const ConnectionTable *table = + forwarder_GetConnectionTable(mapme->forwarder); + const Connection *conn = + connectionTable_FindById((ConnectionTable *)table, conn_id); + if (conn) { + const Name * name = message_GetName(special_interest); + char * name_str = name_ToString(name); + INFO(mapme, "[MAP-Me] Sending MAP-Me packet name=%s seq=%d conn=%d", + name_str, params.seq, conn_id); + free(name_str); + connection_ReSend(conn, special_interest, NOT_A_NOTIFICATION); + } else { + INFO(mapme, "[MAP-Me] Stopped retransmissions as face went down"); + } + + if (num_retx < MAX_RETX) { + INFO(mapme, "[MAP-Me] - Scheduling retransmission\n"); + /* Schedule retransmission */ + struct setFacePendingArgs *args = + malloc(sizeof(struct setFacePendingArgs)); + if (!args) goto ERR_MALLOC; + args->mapme = mapme; + args->name = name; + args->fibEntry = fibEntry; + args->conn_id = conn_id; + args->send = send; + args->is_first = is_first; + args->num_retx = num_retx + 1; + + timer = dispatcher_CreateTimer(dispatcher, TIMER_NO_REPEAT, + mapme_setFacePendingCallback, args); + struct timeval timeout = {mapme->retx / 1000, + (mapme->retx % 1000) * 1000}; + rc = parcEventTimer_Start(timer, &timeout); + if (rc < 0) goto ERR_TIMER; + } else { + INFO(mapme, "[MAP-Me] Last retransmission."); + timer = NULL; + } + } else { + INFO(mapme, "[MAP-Me] - not forwarding as send is False"); + timer = NULL; + } + + PARCEventTimer *oldTimer = + (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_id); + if (oldTimer) { + INFO(mapme, "[MAP-Me] - Found old timer, would need to cancel !"); + // parcEventTimer_Stop(oldTimer); + } + INFO(mapme, "[MAP-Me] - Putting new timer in TFIB"); + if (timer) mapmeTFIB_Put(TFIB(fibEntry), conn_id, timer); + + return true; + +ERR_MALLOC: +ERR_TIMER: + return false; +} + +/*------------------------------------------------------------------------------ + * Event handling + *----------------------------------------------------------------------------*/ + +/* + * Return true if we have at least one local connection as next hop + */ +static bool mapme_hasLocalNextHops(const MapMe *mapme, + const FibEntry *fibEntry) { + const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry); + const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder); + + for (size_t j = 0; j < fibEntry_NexthopCount(fibEntry); j++) { + /* Retrieve Nexthop #j */ + unsigned conn_id = numberSet_GetItem(nexthops, j); + const Connection *conn = + connectionTable_FindById((ConnectionTable *)table, conn_id); + + /* Ignore non-local connections */ + if (!connection_IsLocal(conn)) continue; + /* We don't need to test against conn_added since we don't + * expect it to have any entry in the FIB */ + + return true; + } + return false; +} + +/* + * Callback called everytime a new connection is created by the control protocol + */ +void mapme_onConnectionEvent(const MapMe *mapme, const Connection *conn_added, connection_event_t event) { + switch(event) { + case CONNECTION_EVENT_CREATE: + case CONNECTION_EVENT_SET_UP: + { + FibEntryList *fiblist; + + /* Ignore local connections corresponding to applications for now */ + if (connection_IsLocal(conn_added)) + return; + + unsigned conn_added_id = connection_GetConnectionId(conn_added); + INFO(mapme, "[MAP-Me] New connection %d", conn_added_id); + + /* + * Iterate on FIB to find locally served prefix + * Ideally, we want to avoid a FIB scan everytime a face is added/removed + */ + fiblist = forwarder_GetFibEntries(mapme->forwarder); + for (size_t i = 0; i < fibEntryList_Length(fiblist); i++) { + FibEntry *fibEntry = (FibEntry *)fibEntryList_Get(fiblist, i); + const Name *name = fibEntry_GetPrefix(fibEntry); + + /* Skip entries that have no local connection as next hop */ + if (!mapme_hasLocalNextHops(mapme, fibEntry)) + continue; + + /* This entry corresponds to a locally served prefix, set + * Special Interest */ + if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */ + mapme_CreateTFIB(fibEntry); + TFIB(fibEntry)->seq++; + + char *name_str = name_ToString(name); + INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str, + conn_added_id); + free(name_str); + + mapme_setFacePending(mapme, name, fibEntry, conn_added_id, true, true, 0); + } + break; + } + case CONNECTION_EVENT_DELETE: + case CONNECTION_EVENT_SET_DOWN: + case CONNECTION_EVENT_UPDATE: + break; + } +} + +#ifdef WITH_POLICY +void mapme_onPolicyUpdate(const MapMe *mapme, const Connection *conn_selected, FibEntry * fibEntry) +{ + /* Ignore local connections corresponding to applications for now */ + if (connection_IsLocal(conn_selected)) + return; + + unsigned conn_selected_id = connection_GetConnectionId(conn_selected); + INFO(mapme, "[MAP-Me] New connection %d", conn_selected_id); + + const Name *name = fibEntry_GetPrefix(fibEntry); + + /* Skip entries that have no local connection as next hop */ + if (!mapme_hasLocalNextHops(mapme, fibEntry)) + return; + + /* This entry corresponds to a locally served prefix, set + * Special Interest */ + if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */ + mapme_CreateTFIB(fibEntry); + TFIB(fibEntry)->seq++; + + char *name_str = name_ToString(name); + INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str, + conn_selected_id); + free(name_str); + + mapme_setFacePending(mapme, name, fibEntry, conn_selected_id, true, true, 0); +} +#endif /* WITH_POLICY */ + +/*------------------------------------------------------------------------------ + * Special Interest handling + *----------------------------------------------------------------------------*/ + +/** + * @discussion This function is way too long and should be cut out + */ +static bool mapme_onSpecialInterest(const MapMe *mapme, + const uint8_t *msgBuffer, + unsigned conn_in_id, hicn_prefix_t *prefix, + mapme_params_t *params) { + const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder); + /* The cast is needed since connectionTable_FindById miss the + * const qualifier for the first parameter */ + const Connection *conn_in = + connectionTable_FindById((ConnectionTable *)table, conn_in_id); + seq_t fibSeq, seq = params->seq; + bool send = (params->type == UPDATE); + bool rv; + + Name *name = name_CreateFromPacket(msgBuffer, MessagePacketType_Interest); + name_setLen(name, prefix->len); + char *name_str = name_ToString(name); + INFO(mapme, + "[MAP-Me] Ack'ed Special Interest on connection %d - prefix=%s type=XX " + "seq=%d", + conn_in_id, name_str, seq); + free(name_str); + + /* + * Immediately send an acknowledgement back on the ingress connection + * We always ack, even duplicates. + */ + Message *ack = mapme_createAckMessage(mapme, msgBuffer, params); + if (!ack) goto ERR_ACK_CREATE; + rv = connection_ReSend(conn_in, ack, NOT_A_NOTIFICATION); + if (!rv) goto ERR_ACK_SEND; + message_Release(&ack); + + /* EPM on FIB */ + /* only the processor has access to the FIB */ + FIB *fib = forwarder_getFib(mapme->forwarder); + + FibEntry *fibEntry = fib_Contains(fib, name); + if (!fibEntry) { + INFO(mapme, + "[MAP-Me] - Re-creating FIB entry with next hop on connection %d", + conn_in_id); + /* + * This might happen for a node hosting a producer which has moved. + * Destroying the face has led to removing all corresponding FIB + * entries. In that case, we need to correctly restore the FIB entries. + */ + strategy_type fwdStrategy = LAST_STRATEGY_VALUE; + + /* + * It might also be due to the announcement of a more specific prefix. In + * that case we need to perform a FIB lookup to find the next hops to which + * the message should be propagated. + */ +#ifdef WITH_POLICY + fibEntry = fibEntry_Create(name, fwdStrategy, mapme->forwarder); +#else + fibEntry = fibEntry_Create(name, fwdStrategy); +#endif /* WITH_POLICY */ + FibEntry *lpm = fib_MatchName(fib, name); + mapme_CreateTFIB(fibEntry); + fib_Add(fib, fibEntry); + if (!lpm) { + TFIB(fibEntry)->seq = seq; + fibEntry_AddNexthop(fibEntry, conn_in_id); + return true; + } + + /* + * We make a clone of the FIB entry (zero'ing the sequence number ?) with + * the more specific name, and proceed as usual. Worst case we clone the + * default route... + */ + const NumberSet *lpm_nexthops = fibEntry_GetNexthops(lpm); + for (size_t i = 0; i < numberSet_Length(lpm_nexthops); i++) { + fibEntry_AddNexthop(fibEntry, numberSet_GetItem(lpm_nexthops, i)); + } + + } else if (!TFIB(fibEntry)) { + /* Create TFIB associated to FIB entry */ + INFO(mapme, + "[MAP-Me] - Creating TFIB entry with default sequence number"); + mapme_CreateTFIB(fibEntry); + } + + fibSeq = TFIB(fibEntry)->seq; + if (seq > fibSeq) { + INFO(mapme, + "[MAP-Me] - Higher sequence number than FIB %d, updating seq and " + "next hops", + fibSeq); + /* This has to be done first to allow processing SpecialInterestAck's */ + TFIB(fibEntry)->seq = seq; + + /* Reliably forward the IU on all prevHops */ + INFO(mapme, "[MAP-Me] - (1/3) processing prev hops"); + if (params->type == UPDATE) { + PARCIterator *iterator = mapmeTFIB_CreateKeyIterator(TFIB(fibEntry)); + while (parcIterator_HasNext(iterator)) { + PARCUnsigned *cid = parcIterator_Next(iterator); + unsigned conn_id = parcUnsigned_GetUnsigned(cid); + INFO(mapme, "[MAP-Me] - Re-sending IU to pending connection %d", + conn_id); + mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, + conn_id, false, false, 0); + } + parcIterator_Release(&iterator); + } + + /* nextHops -> prevHops + * + * We add to the list of pendingUpdates the current next hops, and + * eventually forward them an IU too. + * + * Exception: nextHops -> nextHops + * Because of retransmission issues, it is possible that a second interest + * (with same of higher sequence number) is receive from a next-hop + * interface. In that case, the face remains a next hop. + */ + const NumberSet *nexthops_old = fibEntry_GetNexthops(fibEntry); + + /* We make a copy to be able to send IU _after_ updating next hops */ + NumberSet *nexthops = numberSet_Create(); + numberSet_AddSet(nexthops, nexthops_old); + + /* We are considering : * -> nextHops + * + * If inFace was a previous hop, we need to cancel the timer and remove + * the entry. Also, the face should be added to next hops. + * + * Optimization : nextHops -> nextHops + * - no next hop to add + * - we know that inFace was not a previous hop since it was a next hop and + * this forms a partition. No need for a search + */ + + INFO(mapme, "[MAP-Me] - (3/3) next hops ~~> prev hops"); + PARCEventTimer *oldTimer = + (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_in_id); + if (oldTimer) { + /* This happens if we receive an IU while we are still sending + * one in the other direction + */ + INFO(mapme, "[MAP-Me] - Canceled pending timer"); + parcEventTimer_Stop(oldTimer); + mapmeTFIB_Remove(TFIB(fibEntry), conn_in_id); + } + + /* Remove all next hops */ + for (size_t k = 0; k < numberSet_Length(nexthops_old); k++) { + unsigned conn_id = numberSet_GetItem(nexthops_old, k); + INFO(mapme, "[MAP-Me] - Replaced next hops by connection %d", conn_id); + fibEntry_RemoveNexthopByConnectionId(fibEntry, conn_id); + } + fibEntry_AddNexthop(fibEntry, conn_in_id); + + INFO(mapme, "[MAP-Me] - (2/3) processing next hops"); + bool complete = true; + for (size_t k = 0; k < numberSet_Length(nexthops); k++) { + unsigned conn_id = numberSet_GetItem(nexthops, k); + INFO(mapme, " - Next hop connection %d", conn_id); + if (conn_id == conn_in_id) { + INFO(mapme, " . Ignored this next hop since equal to ingress face"); + continue; + } + + INFO(mapme, "[MAP-Me] - Sending IU on current next hop connection %d", + conn_id); + mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, + conn_id, send, false, 0); + complete = false; + } + + /* + * The update is completed when the IU could not be sent to any + * other next hop. + */ + if (complete) INFO(mapme, "[MAP-Me] - Update completed !"); + + numberSet_Release(&nexthops); + + } else if (seq == fibSeq) { + /* + * Multipath, multihoming, multiple producers or duplicate interest + * + * In all cases, we assume the propagation was already done when the first + * interest with the same sequence number was received, so we stop here + * + * It might happen that the previous AP has still a connection to the + * producer and that we received back our own IU. In that case, we just + * need to Ack and ignore it. + */ + if (mapme_hasLocalNextHops(mapme, fibEntry)) { + INFO(mapme, "[MAP-Me] - Received original interest... Update complete"); + return true; + } + + INFO(mapme, "[MAP-Me] - Adding multipath next hop on connection %d", + conn_in_id); + fibEntry_AddNexthop(fibEntry, conn_in_id); + + } else { // seq < fibSeq + /* + * Face is propagating outdated information, we can just + * consider it as a prevHops. Send the special interest backwards with + * the new sequence number to reconciliate this outdated part of the + * arborescence. + */ + INFO( + mapme, + "[MAP-Me] - Update interest %d -> %d sent backwards on connection %d", + seq, fibSeq, conn_in_id); + mapme_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry, + conn_in_id, send, false, 0); + } + + return true; + +ERR_ACK_SEND: + message_Release(&ack); +ERR_ACK_CREATE: + return false; +} + +void mapme_onSpecialInterestAck(const MapMe *mapme, const uint8_t *msgBuffer, + unsigned conn_in_id, hicn_prefix_t *prefix, + mapme_params_t *params) { + INFO(mapme, "[MAP-Me] Receive IU/IN Ack on connection %d", conn_in_id); + + const Name * name = + name_CreateFromPacket(msgBuffer, MessagePacketType_ContentObject); + name_setLen((Name*) name, prefix->len); + char * name_str = name_ToString(name); + INFO(mapme, "[MAP-Me] Received ack for name prefix=%s seq=%d on conn id=%d", + name_str, params->seq, conn_in_id); + free(name_str); + + FIB *fib = forwarder_getFib(mapme->forwarder); + FibEntry *fibEntry = fib_Contains(fib, name); + if (!fibEntry) { + return; + } + parcAssertNotNull(fibEntry, + "No corresponding FIB entry for name contained in IU Ack"); + + /* Test if the latest pending update has been ack'ed, otherwise just ignore */ + seq_t seq = params->seq; + if (seq != INVALID_SEQ) { + seq_t fibSeq = TFIB(fibEntry)->seq; + + if (seq < fibSeq) { + INFO(mapme, + "[MAP-Me] - Ignored special interest Ack with seq=%u, expected %u", + seq, fibSeq); + return; + } + } + + /* + * Ignore the Ack if no TFIB is present, or it has no corresponding entry + * with the ingress face. + * Note: previously, we were creating the TFIB entry + */ + if (!TFIB(fibEntry)) { + INFO(mapme, "[MAP-Me] - Ignored ACK for prefix with no TFIB entry"); + return; + } + + PARCEventTimer *timer = + (PARCEventTimer *)mapmeTFIB_Get(TFIB(fibEntry), conn_in_id); + if (!timer) { + INFO(mapme, + "[MAP-Me] - Ignored ACK for prefix not having the Connection in " + "TFIB entry. Possible duplicate ?"); + return; + } + + /* Stop timer and remove entry from TFIB */ + parcEventTimer_Stop(timer); + mapmeTFIB_Remove(TFIB(fibEntry), conn_in_id); + + INFO(mapme, "[MAP-Me] - Removing TFIB entry for ack on connection %d", + conn_in_id); + + /* We need to update the timestamp only for IU Acks, not for IN Acks */ + if (params->type == UPDATE_ACK) { + INFO(mapme, "[MAP-Me] - Updating LastAckedUpdate"); + TFIB(fibEntry)->lastAckedUpdate = forwarder_GetTicks(mapme->forwarder); + } +} + +/*----------------------------------------------------------------------------- + * Overloaded functions + *----------------------------------------------------------------------------*/ + +/* + * @abstract returns where to forward a normal interests(nexthops) defined by + * mapme, it also set the sequnence number properly if needed + */ + +/****************************************************************************** + * Public functions (exposed in the .h) + ******************************************************************************/ + +/* + * Returns true iif the message corresponds to a MAP-Me packet + */ +bool mapme_isMapMe(const uint8_t *packet) { + hicn_mapme_header_t * mapme = (hicn_mapme_header_t*)packet; + + switch(HICN_IP_VERSION(packet)) { + case 4: + if (mapme->v4.ip.protocol != IPPROTO_ICMP) + return false; + return HICN_IS_MAPME(mapme->v4.icmp_rd.type, mapme->v4.icmp_rd.code); + case 6: + if (mapme->v6.ip.nxt != IPPROTO_ICMPV6) + return false; + return HICN_IS_MAPME(mapme->v6.icmp_rd.type, mapme->v6.icmp_rd.code); + default: + return false; + } +} + +/** + * @discussion The exact type of the MapMe message is determined after + * reception. In hICN, Interest Update and Notifications look like regular + * Interest packets, and are first punted from the normal path by the forwarder, + * then treated as such in the Listener to reach this function. Acknowledgements + * are received as Content (Data) packets and will land here too. + * + * This function is in charge of abstracting the low-level implementation of + * MAP-Me (eg. ICMP packets) and return higher level messages that can be + * processed by MAP-Me core. + */ +void mapme_Process(const MapMe *mapme, const uint8_t *msgBuffer, + unsigned conn_id) { + hicn_prefix_t prefix; + mapme_params_t params; + hicn_mapme_parse_packet(msgBuffer, &prefix, ¶ms); + + switch (params.type) { + case UPDATE: + case NOTIFICATION: + mapme_onSpecialInterest(mapme, msgBuffer, conn_id, &prefix, ¶ms); + break; + case UPDATE_ACK: + case NOTIFICATION_ACK: + mapme_onSpecialInterestAck(mapme, msgBuffer, conn_id, &prefix, ¶ms); + break; + default: + ERR(mapme, "[MAP-Me] Unknown message"); + break; + } +} + +#endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/core/mapme.h b/hicn-light/src/hicn/core/mapme.h new file mode 100644 index 000000000..5888ccd21 --- /dev/null +++ b/hicn-light/src/hicn/core/mapme.h @@ -0,0 +1,104 @@ +/* + * 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 mapme.h + * @brief MAP-Me : AnchorLess Producer Mobility Management + */ + +#ifndef mapme_h +#define mapme_h + +#ifdef WITH_MAPME + +#include +#include + +#include +#include +#include +#include + +struct mapme; +typedef struct mapme MapMe; + +/** + * @function mapme_create + * @abstract Initializes MAP-Me state in the forwarder. + * @return bool - Boolean informing about the success of MAP-Me initialization. + */ +bool mapme_create(MapMe **mapme, Forwarder *Forwarder); + +/** + * @function mapme_free + * @abstract Free MAP-Me state in the forwarder. + */ +void mapme_free(MapMe *mapme); + +/** + * @function messageHandler_isMapMe + * @abstract Identifies MAP-Me messages + * @discussion This function can be used by the forwarder to dispatch MAP-Me + * message to the appropriate processing function. Ideally this would be + * done through hooks defined in the Init function. + * @param [in] msgBuffer - The buffer to match + * @return A boolean indicating whether message is a MAP-Me control message. + */ +bool mapme_isMapMe(const uint8_t *msgBuffer); + +/** + * @function mapme_handleMapMeMessage + * @abstract Process a MAP-Me message. + * @param [in] mapme - Pointer to the MAP-Me data structure. + * @param [in] message - MAP-Me buffer + * @param [in] conn_id - Ingress connection id + */ +void mapme_Process(const MapMe *mapme, const uint8_t *msgBuffer, + unsigned conn_id); + +/** + * @function mapme_onConnectionEvent + * @abstract Callback following the addition of the face though the control + * protocol. + * @discussion This callback triggers the sending of control packets by MAP-Me. + * @param [in] mapme - Pointer to the MAP-Me data structure. + * @param [in] conn - The newly added connection. + * @param [in] event - Connection event + */ +void mapme_onConnectionEvent(const MapMe *mapme, const Connection *conn, connection_event_t event); + +#ifdef WITH_POLICY + +/** + * @function mapme_onPolicyUpdate + */ +void mapme_onPolicyUpdate(const MapMe *mapme, const Connection *conn_added, FibEntry * fibEntry); +#endif /* WITH_POLICY */ + +/** + * @function mapme_getNextHops + * @abstract return the nexthops to forward interests defined by mapme, it + * covers also the case where local discovery mechanisms are trriggered. + */ +NumberSet *mapme_getNextHops(const MapMe *mapme, FibEntry *fibEntry, + const Message *interest); + +hicn_mapme_type_t mapme_PktType_To_LibHicnPktType(MessagePacketType type); + +MessagePacketType mapme_LibHicnPktType_To_PktType(hicn_mapme_type_t type); + +#endif /* WITH_MAPME */ + +#endif // mapme_h diff --git a/hicn-light/src/hicn/core/messageHandler.h b/hicn-light/src/hicn/core/messageHandler.h index f1f91bc40..e2f0140e5 100644 --- a/hicn-light/src/hicn/core/messageHandler.h +++ b/hicn-light/src/hicn/core/messageHandler.h @@ -57,7 +57,7 @@ #include #ifdef WITH_MAPME -#include +#include #include #endif /* WITH_MAPME */ @@ -274,7 +274,7 @@ static inline bool messageHandler_handleHooks(Forwarder * forwarder, /* BEGIN Match */ #ifdef WITH_MAPME - bool is_mapme = mapMe_isMapMe(packet); + bool is_mapme = mapme_isMapMe(packet); is_matched |= is_mapme; #endif /* WITH_MAPME */ @@ -310,7 +310,7 @@ static inline bool messageHandler_handleHooks(Forwarder * forwarder, /* BEGIN Process */ #ifdef WITH_MAPME - if (mapMe_isMapMe(packet)) + if (mapme_isMapMe(packet)) forwarder_ProcessMapMe(forwarder, packet, conn_id); #endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/io/hicnListener.c b/hicn-light/src/hicn/io/hicnListener.c index a60c4dd12..5a47982ff 100644 --- a/hicn-light/src/hicn/io/hicnListener.c +++ b/hicn-light/src/hicn/io/hicnListener.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/hicn-light/src/hicn/io/listenerSet.c b/hicn-light/src/hicn/io/listenerSet.c index 45dbe887a..d69632287 100644 --- a/hicn-light/src/hicn/io/listenerSet.c +++ b/hicn-light/src/hicn/io/listenerSet.c @@ -175,7 +175,7 @@ void listenerSet_RemoveById(const ListenerSet *set, unsigned id) { ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i); parcAssertNotNull(ops, "Got null listener ops at index %zu", i); if (ops->getInterfaceIndex(ops) == id) { - parcArrayList_RemoveAtIndex(set->listOfListeners, i); + parcArrayList_RemoveAndDestroyAtIndex(set->listOfListeners, i); break; } } diff --git a/hicn-light/src/hicn/io/streamConnection.c b/hicn-light/src/hicn/io/streamConnection.c index 08ff728d6..4e2f9c37e 100644 --- a/hicn-light/src/hicn/io/streamConnection.c +++ b/hicn-light/src/hicn/io/streamConnection.c @@ -598,6 +598,7 @@ static void _conn_readcb(PARCEventQueue *event, PARCEventType type, // If received correctly the whole message, send to dispatcher if (message) { forwarder_ReceiveCommand(stream->forwarder, command, rx, stream->id); + parcMemory_Deallocate((void **)&rx); parcEventBuffer_Destroy(&message); } diff --git a/hicn-light/src/hicn/io/udpListener.c b/hicn-light/src/hicn/io/udpListener.c index f43756a11..e484dc2db 100644 --- a/hicn-light/src/hicn/io/udpListener.c +++ b/hicn-light/src/hicn/io/udpListener.c @@ -282,8 +282,13 @@ ListenerOps *udpListener_CreateInet(Forwarder *forwarder, char *listenerName, myerrno, strerror(myerrno)); parcMemory_Deallocate((void **)&str); } - + parcMemory_Deallocate((void **)&udp->listenerName); + parcMemory_Deallocate((void **)&udp->interfaceName); +#ifndef _WIN32 close(udp->udp_socket); +#else + closesocket(udp->udp_socket); +#endif addressDestroy(&udp->localAddress); logger_Release(&udp->logger); parcMemory_Deallocate((void **)&udp); @@ -304,6 +309,8 @@ static void udpListener_Destroy(UdpListener **listenerPtr) { "UdpListener %p destroyed", (void *)udp); } + parcMemory_Deallocate((void **)&udp->listenerName); + parcMemory_Deallocate((void **)&udp->interfaceName); #ifndef _WIN32 close(udp->udp_socket); #else diff --git a/hicn-light/src/hicn/processor/fibEntry.c b/hicn-light/src/hicn/processor/fibEntry.c index f12dd506b..28cf6b13c 100644 --- a/hicn-light/src/hicn/processor/fibEntry.c +++ b/hicn-light/src/hicn/processor/fibEntry.c @@ -42,7 +42,7 @@ #include #ifdef WITH_MAPME -#include +#include #endif /* WITH_MAPME */ #define ALPHA 0.5 @@ -149,6 +149,9 @@ void fibEntry_Release(FibEntry **fibEntryPtr) { fibEntry->userDataRelease(&fibEntry->userData); } #endif /* WITH_MAPME */ +#ifdef WITH_POLICY + numberSet_Release(&fibEntry->nexthops); +#endif /* WITH_POLICY */ parcMemory_Deallocate((void **)&fibEntry); } *fibEntryPtr = NULL; @@ -467,7 +470,7 @@ void fibEntry_ReconsiderPolicy(FibEntry *fibEntry) { fibEntry->previous_nexthop = nexthop; ConnectionTable * table = forwarder_GetConnectionTable(fibEntry->forwarder); const Connection * conn = connectionTable_FindById(table, nexthop); - mapMe_onPolicyUpdate(forwarder_getMapmeInstance(fibEntry->forwarder), conn, fibEntry); + mapme_onPolicyUpdate(forwarder_getMapmeInstance(fibEntry->forwarder), conn, fibEntry); } END: diff --git a/hicn-light/src/hicn/processor/messageProcessor.c b/hicn-light/src/hicn/processor/messageProcessor.c index 6598b9035..58220ac9c 100644 --- a/hicn-light/src/hicn/processor/messageProcessor.c +++ b/hicn-light/src/hicn/processor/messageProcessor.c @@ -403,6 +403,7 @@ void messageProcessor_onConnectionEvent(const MessageProcessor *processor, FibEntry *fibEntry = (FibEntry *)fibEntryList_Get(fiblist, i); fibEntry_ReconsiderPolicy(fibEntry); } + fibEntryList_Destroy(&fiblist); } #endif /* WITH_MAPME */ diff --git a/hicn-light/src/hicn/socket/api.c b/hicn-light/src/hicn/socket/api.c index a3d5a3cfe..34c0aae54 100644 --- a/hicn-light/src/hicn/socket/api.c +++ b/hicn-light/src/hicn/socket/api.c @@ -72,7 +72,8 @@ hicn_socket_helper_t *hicn_create() { } hicn->conf = malloc(sizeof(hicn_conf_t)); - if (hicn->conf < 0) goto ERR_CONF; + if (hicn->conf < 0) + goto ERR_CONF; memcpy(hicn->conf, &hicn_default_conf, sizeof(hicn_conf_t)); /* Initialize socket tree to empty */ @@ -126,64 +127,56 @@ ERR_MALLOC: void hicn_destroy() { int rc; + int ret = 0; uint16_t i; /* Restore default rules */ printf("Restoring default configuration.\n"); rc = ops.del_lo_prio_rule(NULL, AF_INET6, LOCAL_PRIORITY); - if (rc < 0) { - goto ERR; - } + if (rc < 0) + ret = -1; rc = ops.del_lo_prio_rule(NULL, AF_INET, LOCAL_PRIORITY); - if (rc < 0) { - goto ERR; - } + if (rc < 0) + ret = -1; rc = ops.add_lo_prio_rule(NULL, AF_INET6, 0); - if (rc < 0) { - goto ERR; - } + if (rc < 0) + ret = -1; rc = ops.add_lo_prio_rule(NULL, AF_INET, 0); - if (rc < 0) { - goto ERR; - } + if (rc < 0) + ret = -1; for (i = 0; i < rules_counter; i++) { if (strcmp(rules_to_remove[i].tun_name, "NONE") != 0) { rc = ops.del_rule(rules_to_remove[i].tun_name, rules_to_remove[i].address_family, rules_to_remove[i].table_id); - if (rc < 0) { - goto ERR; - } } else { rc = ops.del_prio_rule( &rules_to_remove[i].prefix, rules_to_remove[i].address_family, rules_to_remove[i].priority, rules_to_remove[i].table_id); - if (rc < 0) { - goto ERR; - } } + if (rc < 0) + ret = -1; } for (i = 0; i < routes_counter; i++) { rc = ops.del_out_route(routes_to_remove[i].remote_ip_address, routes_to_remove[i].address_family, routes_to_remove[i].table_id); - if (rc < 0) { - goto ERR; - } + if (rc < 0) + ret = -1; } -ERR: - if (rc < 0) printf("Unexpected exit. Some state may not be deleted.\n"); - return; + if (ret < 0) + printf("Unexpected exit. Some state may not be deleted.\n"); } void hicn_free(hicn_socket_helper_t *hicn) { - // close tun ? + hicn_destroy(); + free(hicn->conf); free(hicn); } diff --git a/hicn-light/src/hicn/strategies/loadBalancer.c b/hicn-light/src/hicn/strategies/loadBalancer.c index ca9d34289..e3f377791 100644 --- a/hicn-light/src/hicn/strategies/loadBalancer.c +++ b/hicn-light/src/hicn/strategies/loadBalancer.c @@ -323,6 +323,10 @@ static void _strategyLoadBalancer_RemoveNexthop(StrategyImpl *strategy, PARCUnsigned *cid = parcUnsigned_Create(connectionId); if (parcHashMap_Contains(lb->strategy_state, cid)) { + StrategyNexthopState *state = + (StrategyNexthopState *)parcHashMap_Get(lb->strategy_state, cid); + parcObject_Release((void**)&state); + parcHashMap_Remove(lb->strategy_state, cid); #ifndef WITH_POLICY numberSet_Remove(lb->nexthops, connectionId); @@ -341,6 +345,15 @@ static void _strategyLoadBalancer_ImplDestroy(StrategyImpl **strategyPtr) { StrategyImpl *impl = *strategyPtr; StrategyLoadBalancer *strategy = (StrategyLoadBalancer *)impl->context; + PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state); + while (parcIterator_HasNext(it)) { + PARCUnsigned *cid = parcIterator_Next(it); + StrategyNexthopState *state = + (StrategyNexthopState *)parcHashMap_Get(strategy->strategy_state, cid); + parcObject_Release((void**)&state); + } + parcIterator_Release(&it); + parcHashMap_Release(&(strategy->strategy_state)); #ifndef WITH_POLICY numberSet_Release(&(strategy->nexthops)); -- cgit 1.2.3-korg