aboutsummaryrefslogtreecommitdiffstats
path: root/metis/ccnx/forwarder/metis/processor/metis_StandardPIT.c
diff options
context:
space:
mode:
Diffstat (limited to 'metis/ccnx/forwarder/metis/processor/metis_StandardPIT.c')
-rw-r--r--metis/ccnx/forwarder/metis/processor/metis_StandardPIT.c326
1 files changed, 326 insertions, 0 deletions
diff --git a/metis/ccnx/forwarder/metis/processor/metis_StandardPIT.c b/metis/ccnx/forwarder/metis/processor/metis_StandardPIT.c
new file mode 100644
index 00000000..4c981f23
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/metis_StandardPIT.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+/**
+ * The pending interest table.
+ *
+ * Interest aggregation strategy:
+ * - The first Interest for a name is forwarded
+ * - A second Interest for a name from a different reverse path may be aggregated
+ * - A second Interest for a name from an existing Interest is forwarded
+ * - The Interest Lifetime is like a subscription time. A reverse path entry is removed once the lifetime
+ * is exceeded.
+ * - Whan an Interest arrives or is aggregated, the Lifetime for that reverse hop is extended. As a simplification,
+ * we only keep a single lifetime not per reverse hop.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <ccnx/forwarder/metis/processor/metis_PIT.h>
+#include <ccnx/forwarder/metis/processor/metis_MatchingRulesTable.h>
+
+#include <ccnx/forwarder/metis/core/metis_Ticks.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Hash.h>
+
+#include <ccnx/forwarder/metis/core/metis_Forwarder.h>
+
+#include <LongBow/runtime.h>
+
+struct metis_standard_pit;
+typedef struct metis_standard_pit MetisStandardPIT;
+
+struct metis_standard_pit {
+ MetisForwarder *metis;
+ MetisLogger *logger;
+
+ MetisMatchingRulesTable *table;
+
+ // counters to track how many of each type of Interest we get
+ unsigned insertCounterByName;
+ unsigned insertCounterByKeyId;
+ unsigned insertCounterByObjectHash;
+};
+
+static void _metisPIT_StoreInTable(MetisStandardPIT *pit, MetisMessage *interestMessage);
+
+static void
+_metisPIT_PitEntryDestroyer(void **dataPtr)
+{
+ metisPitEntry_Release((MetisPitEntry **) dataPtr);
+}
+
+static bool
+_metisPIT_IngressSetContains(MetisPitEntry *pitEntry, unsigned connectionId)
+{
+ const MetisNumberSet *set = metisPitEntry_GetIngressSet(pitEntry);
+ bool numberInSet = metisNumberSet_Contains(set, connectionId);
+ return numberInSet;
+}
+
+static MetisTicks
+_metisPIT_CalculateLifetime(MetisStandardPIT *pit, MetisMessage *interestMessage)
+{
+ uint64_t interestLifetimeTicks = 0;
+
+ if (metisMessage_HasInterestLifetime(interestMessage)) {
+ interestLifetimeTicks = metisMessage_GetInterestLifetimeTicks(interestMessage);
+ } else {
+ interestLifetimeTicks = metisForwarder_NanosToTicks(4000000000ULL);
+ }
+
+ MetisTicks expiryTime = metisForwarder_GetTicks(pit->metis) + interestLifetimeTicks;
+ return expiryTime;
+}
+
+static void
+_metisPIT_StoreInTable(MetisStandardPIT *pit, MetisMessage *interestMessage)
+{
+ MetisMessage *key = metisMessage_Acquire(interestMessage);
+
+ MetisTicks expiryTime = _metisPIT_CalculateLifetime(pit, interestMessage);
+
+ MetisPitEntry *pitEntry = metisPitEntry_Create(key, expiryTime, metisForwarder_GetTicks(pit->metis));
+ // this is done in metisPitEntry_Create
+ // metisPitEntry_AddIngressId(pitEntry, metisMessage_GetIngressConnectionId(interestMessage));
+
+ metisMatchingRulesTable_AddToBestTable(pit->table, key, pitEntry);
+
+ if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
+ metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
+ "Message %p added to PIT (expiry %" PRIu64 ") ingress %u",
+ (void *) interestMessage,
+ metisPitEntry_GetExpiryTime(pitEntry),
+ metisMessage_GetIngressConnectionId(interestMessage));
+ }
+}
+
+static void
+_metisPIT_ExtendLifetime(MetisStandardPIT *pit, MetisPitEntry *pitEntry, MetisMessage *interestMessage)
+{
+ MetisTicks expiryTime = _metisPIT_CalculateLifetime(pit, interestMessage);
+ metisPitEntry_SetExpiryTime(pitEntry, expiryTime);
+}
+
+// this appears to only be used in some unit tests
+__attribute__((unused))
+static void
+_metisPIT_AddEgressConnectionId(MetisPIT *generic, const MetisMessage *interestMessage, unsigned connectionId)
+{
+ assertNotNull(generic, "Parameter pit must be non-null");
+ assertNotNull(interestMessage, "Parameter interestMessage must be non-null");
+
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisPitEntry *entry = metisMatchingRulesTable_Get(pit->table, interestMessage);
+ if (entry) {
+ metisPitEntry_AddEgressId(entry, connectionId);
+ }
+}
+
+
+// ======================================================================
+// Interface API
+
+static void
+_metisStandardPIT_Destroy(MetisPIT **pitPtr)
+{
+ assertNotNull(pitPtr, "Parameter must be non-null double pointer");
+ assertNotNull(*pitPtr, "Parameter must dereference to non-null pointer");
+
+ MetisStandardPIT *pit = metisPIT_Closure(*pitPtr);
+
+ if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
+ metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
+ "PIT %p destroyed",
+ (void *) pit);
+ }
+
+ metisMatchingRulesTable_Destroy(&pit->table);
+ metisLogger_Release(&pit->logger);
+ parcMemory_Deallocate(pitPtr);
+}
+
+// There's a bit too much going on in this function, need to break it
+// apart for testability and style.
+static MetisPITVerdict
+_metisStandardPIT_ReceiveInterest(MetisPIT *generic, MetisMessage *interestMessage)
+{
+ assertNotNull(generic, "Parameter pit must be non-null");
+ assertNotNull(interestMessage, "Parameter interestMessage must be non-null");
+
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisPitEntry *pitEntry = metisMatchingRulesTable_Get(pit->table, interestMessage);
+
+ if (pitEntry) {
+ // has it expired?
+ MetisTicks now = metisForwarder_GetTicks(pit->metis);
+ if (now < metisPitEntry_GetExpiryTime(pitEntry)) {
+ _metisPIT_ExtendLifetime(pit, pitEntry, interestMessage);
+
+ // Is the reverse path already in the PIT entry?
+ if (_metisPIT_IngressSetContains(pitEntry, metisMessage_GetIngressConnectionId(interestMessage))) {
+ // It is already in the PIT entry, so this is a retransmission, so forward it.
+
+ if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
+ metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
+ "Message %p existing entry (expiry %" PRIu64 ") and reverse path, forwarding",
+ (void *) interestMessage,
+ metisPitEntry_GetExpiryTime(pitEntry));
+ }
+
+ return MetisPITVerdict_Forward;
+ }
+
+ // It is in the PIT but this is the first interest for the reverse path
+ metisPitEntry_AddIngressId(pitEntry, metisMessage_GetIngressConnectionId(interestMessage));
+
+ if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
+ metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
+ "Message %p existing entry (expiry %" PRIu64 ") and reverse path is new, aggregate",
+ (void *) interestMessage,
+ metisPitEntry_GetExpiryTime(pitEntry));
+ }
+
+ return MetisPITVerdict_Aggregate;
+ }
+ //this is a timeout....
+ MetisFibEntry *fibEntry = metisPitEntry_GetFibEntry(pitEntry);
+ if (fibEntry != NULL) {
+ metisFibEntry_OnTimeout(fibEntry, metisPitEntry_GetEgressSet(pitEntry));
+ }
+
+ // it's an old entry, remove it
+ metisMatchingRulesTable_RemoveFromBest(pit->table, interestMessage);
+ }
+
+ _metisPIT_StoreInTable(pit, interestMessage);
+
+ return MetisPITVerdict_Forward;
+}
+
+static MetisNumberSet *
+_metisStandardPIT_SatisfyInterest(MetisPIT *generic, const MetisMessage *objectMessage)
+{
+ assertNotNull(generic, "Parameter pit must be non-null");
+ assertNotNull(objectMessage, "Parameter objectMessage must be non-null");
+
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ // we need to look in all three tables to see if there's anything
+ // to satisy in each of them and take the union of the reverse path sets.
+
+ MetisNumberSet *ingressSetUnion = metisNumberSet_Create();
+
+ PARCArrayList *list = metisMatchingRulesTable_GetUnion(pit->table, objectMessage);
+ for (size_t i = 0; i < parcArrayList_Size(list); i++) {
+ MetisPitEntry *pitEntry = (MetisPitEntry *) parcArrayList_Get(list, i);
+
+ MetisFibEntry *fibEntry = metisPitEntry_GetFibEntry(pitEntry);
+ if (fibEntry != NULL) {
+ //this is a rough estimation of the residual RTT
+ MetisTicks rtt = metisForwarder_GetTicks(pit->metis) - metisPitEntry_GetCreationTime(pitEntry);
+ metisFibEntry_ReceiveObjectMessage(fibEntry, metisPitEntry_GetEgressSet(pitEntry), objectMessage, rtt); //need to implement RTT
+ }
+
+ // this is a reference counted return
+ const MetisNumberSet *ingressSet = metisPitEntry_GetIngressSet(pitEntry);
+ metisNumberSet_AddSet(ingressSetUnion, ingressSet);
+
+ // and remove it from the PIT. Key is a reference counted copy of the pit entry message
+ MetisMessage *key = metisPitEntry_GetMessage(pitEntry);
+ metisMatchingRulesTable_RemoveFromBest(pit->table, key);
+ metisMessage_Release(&key);
+ }
+ parcArrayList_Destroy(&list);
+
+ return ingressSetUnion;
+}
+
+static void
+_metisStandardPIT_RemoveInterest(MetisPIT *generic, const MetisMessage *interestMessage)
+{
+ assertNotNull(generic, "Parameter pit must be non-null");
+ assertNotNull(interestMessage, "Parameter interestMessage must be non-null");
+
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
+ metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
+ "Message %p removed from PIT",
+ (void *) interestMessage);
+ }
+
+ metisMatchingRulesTable_RemoveFromBest(pit->table, interestMessage);
+}
+
+static MetisPitEntry *
+_metisStandardPIT_GetPitEntry(const MetisPIT *generic, const MetisMessage *interestMessage)
+{
+ assertNotNull(generic, "Parameter pit must be non-null");
+ assertNotNull(interestMessage, "Parameter interestMessage must be non-null");
+
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisPitEntry *entry = metisMatchingRulesTable_Get(pit->table, interestMessage);
+ if (entry) {
+ return metisPitEntry_Acquire(entry);
+ }
+ return NULL;
+}
+
+
+// ======================================================================
+// Public API
+
+MetisPIT *
+metisStandardPIT_Create(MetisForwarder *metis)
+{
+ assertNotNull(metis, "Parameter must be non-null");
+
+ size_t allocation = sizeof(MetisPIT) + sizeof(MetisStandardPIT);
+
+ MetisPIT *generic = parcMemory_AllocateAndClear(allocation);
+ assertNotNull(generic, "parcMemory_AllocateAndClear(%zu) returned NULL", allocation);
+ generic->closure = (uint8_t *) generic + sizeof(MetisPIT);
+
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+ pit->metis = metis;
+ pit->logger = metisLogger_Acquire(metisForwarder_GetLogger(metis));
+ pit->table = metisMatchingRulesTable_Create(_metisPIT_PitEntryDestroyer);
+
+ if (metisLogger_IsLoggable(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) {
+ metisLogger_Log(pit->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__,
+ "PIT %p created",
+ (void *) pit);
+ }
+
+ generic->getPitEntry = _metisStandardPIT_GetPitEntry;
+ generic->receiveInterest = _metisStandardPIT_ReceiveInterest;
+ generic->release = _metisStandardPIT_Destroy;
+ generic->removeInterest = _metisStandardPIT_RemoveInterest;
+ generic->satisfyInterest = _metisStandardPIT_SatisfyInterest;
+
+ return generic;
+}
+