/* * 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 // 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 ERROR(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}; /******************************************************************************/ #include 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; /* Install hook on Face events to onConnectionAdded */ // see. config/configuration.c /* Install hook for signalization processing. See : * - io/hicnListener.c * - src/core/connection.{c,h} */ ERROR((*mapme), "MapMe"); return true; ERR_MALLOC: return false; } /****************************************************************************** * TFIB ******************************************************************************/ #define INVALID_SEQ 0 #define INIT_SEQ 1 typedef struct { uint32_t seq; PARCHashMap *nexthops; /* Update/Notification heuristic */ Ticks lastAckedUpdate; // XXX This is only for producer !!! } MapMeTFIB; static MapMeTFIB *mapMeTFIB_Create() { MapMeTFIB *tfib; tfib = malloc(sizeof(MapMeTFIB)); if (!tfib) goto ERR_MALLOC; tfib->seq = 0; 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_address_t ip_address; nameBitvector_ToIPAddress(bv, &ip_address); /* The name length will be equal to ip address' prefix length */ return hicn_prefix_create_from_ip_address(&ip_address, 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) { ERROR(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) { ERROR(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) { ERROR(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) { // XXX 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) { INFO(mapme, "[MAP-Me] Sending MAP-Me packet"); 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_onConnectionAdded(const MapMe *mapme, const Connection *conn_added) { /* bool ret; */ 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); } } /*------------------------------------------------------------------------------ * 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); 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; fibEntry = fibEntry_Create(name, fwdStrategy); fibEntry_AddNexthopByConnectionId(fibEntry, conn_in_id); mapMe_CreateTFIB(fibEntry); TFIB(fibEntry)->seq = seq; // INIT_SEQ; fib_Add(fib, fibEntry); return true; // with proper seq, we are done } 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_AddNexthopByConnectionId(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_AddNexthopByConnectionId(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_Interest); FIB *fib = forwarder_getFib(mapme->forwarder); FibEntry *fibEntry = fib_Contains(fib, name); 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 *msgBuffer) { uint8_t next_header = messageHandler_NextHeaderType(msgBuffer); const uint8_t *icmp_ptr; if (next_header == IPPROTO_ICMP) { icmp_ptr = msgBuffer + IPV4_HDRLEN; } else if (next_header == IPPROTO_ICMPV6) { icmp_ptr = msgBuffer + IPV6_HDRLEN; } else { return false; } uint8_t type = ((_icmp_header_t *)icmp_ptr)->type; uint8_t code = ((_icmp_header_t *)icmp_ptr)->code; if (HICN_IS_MAPME(type, code)) return true; 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); // XXX Dispatch message dependenging on type 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: printf("E:Unknown message\n"); break; } } #endif /* WITH_MAPME */