static bool _symbolicRegisterPrefix(MetisConfiguration *config, CPIRouteEntry *route) { bool success = false; const char *symbolic = cpiRouteEntry_GetSymbolicName(route); unsigned ifidx = metisSymbolicNameTable_Get(config->symbolicNameTable, symbolic); if (ifidx != UINT32_MAX) { cpiRouteEntry_SetInterfaceIndex(route, ifidx); if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug)) { metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__, "Add route resolve name '%s' to connid %u", symbolic, ifidx); } success = metisForwarder_AddOrUpdateRoute(config->metis, route); } else { if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning)) { metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning, __func__, "Add route symbolic name '%s' could not be resolved", symbolic); } // this is a failure } return success; }
/** * Reads from the socket to fill in the work buffer * * Reads one or more packets from the socket to the work buffer It will append to the work buffer. * The BFP socket is non-blocking. The BPF interface may return multiple packets in one read * that need to be parsed as in _darwinEthernet_ReadWorkBuffer(). * * @param [in] ether The Darwin ethernet interface * * @retval true We added something to the work buffer * @retval false Nothing was read * * Example: * @code * <#example#> * @endcode */ static bool _darwinEthernet_ReadSocket(MetisGenericEther *ether) { bool success = false; if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "%s reading fd %d bufferLength %u", __func__, ether->etherSocket, ether->etherBufferLength); } // The buffer we're reading must be exactly ether->etherBufferLength // TODO: Fix the parcEventBuffer_ReadFromFileDescriptor call to reserve that space so it's all there. uint8_t tempBuffer[ether->etherBufferLength]; ssize_t read_length = read(ether->etherSocket, tempBuffer, ether->etherBufferLength); if (read_length > 0) { parcEventBuffer_Append(ether->workBuffer, tempBuffer, read_length); if (read_length > 0) { if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "%s read %zd bytes from fd %d", __func__, read_length, ether->etherSocket); } success = true; } } return success; }
static bool _metisConfiguration_AddConnectionEthernet(MetisConfiguration *config, CPIConnectionEthernet *etherConn, CPIAddress *linkAddress, MetisListenerOps *listenerOps) { bool success = false; const char *symbolic = cpiConnectionEthernet_GetSymbolicName(etherConn); if (!metisSymbolicNameTable_Exists(config->symbolicNameTable, symbolic)) { const CPIAddress *remote = cpiConnectionEthernet_GetPeerLinkAddress(etherConn); MetisAddressPair *pair = metisAddressPair_Create(linkAddress, remote); MetisGenericEther *ether = metisEtherListener_GetGenericEtherFromListener(listenerOps); if (ether) { MetisIoOperations *ops = metisEtherConnection_Create(config->metis, ether, pair); if (ops) { MetisConnection *conn = metisConnection_Create(ops); assertNotNull(conn, "Failed to create connection"); metisConnectionTable_Add(metisForwarder_GetConnectionTable(config->metis), conn); metisSymbolicNameTable_Add(config->symbolicNameTable, symbolic, metisConnection_GetConnectionId(conn)); success = true; if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug)) { char *peerAddressString = cpiAddress_ToString(remote); metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__, "Add connection %s on %s to %s, connid %u", symbolic, cpiConnectionEthernet_GetInterfaceName(etherConn), peerAddressString, metisConnection_GetConnectionId(conn)); parcMemory_Deallocate((void **) &peerAddressString); } } } else { metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__, "Could not get MetisGenericEther for listener %p", listenerOps); } metisAddressPair_Release(&pair); } else { if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning)) { const CPIAddress *remote = cpiConnectionEthernet_GetPeerLinkAddress(etherConn); char *peerAddressString = cpiAddress_ToString(remote); metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning, __func__, "Add connection %s on %s to %s failed, symbolic name exists", symbolic, cpiConnectionEthernet_GetInterfaceName(etherConn), peerAddressString); parcMemory_Deallocate((void **) &peerAddressString); } } return success; }
static void _conn_eventcb(PARCEventQueue *event, PARCEventQueueEventType events, void *ioOpsVoid) { MetisIoOperations *ops = (MetisIoOperations *) ioOpsVoid; _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops); if (events & PARCEventQueueEventType_Connected) { if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__, "Connection %u is connected", stream->id); } // if the stream was closed, do not transition to an UP state if (!stream->isClosed) { _setConnectionState(stream, true); } } else if (events & PARCEventQueueEventType_EOF) { if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__, "connid %u closed.", stream->id); } parcEventQueue_Disable(stream->bufferEventVector, PARCEventType_Read); _setConnectionState(stream, false); if (!stream->isClosed) { stream->isClosed = true; // this will cause the connection manager to destroy the connection later metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionClosed, stream->id)); } } else if (events & PARCEventQueueEventType_Error) { if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Error)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Error, __func__, "Got an error on the connection %u: %s", stream->id, strerror(errno)); } parcEventQueue_Disable(stream->bufferEventVector, PARCEventType_Read | PARCEventType_Write); _setConnectionState(stream, false); if (!stream->isClosed) { stream->isClosed = true; // this will cause the connection manager to destroy the connection later metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionClosed, stream->id)); } } /* None of the other events can happen here, since we haven't enabled * timeouts */ }
// 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)) { // what should we do about extending the lifetime? (case 819) _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; } // it's an old entry, remove it metisMatchingRulesTable_RemoveFromBest(pit->table, interestMessage); } _metisPIT_StoreInTable(pit, interestMessage); return MetisPITVerdict_Forward; }
MetisGenericEther * metisGenericEther_Create(MetisForwarder *metis, const char *deviceName, uint16_t etherType) { assertNotNull(metis, "Parameter metis must be non-null"); // The Darwin generic ether allows a NULL device name, it is used in the unit tests. MetisGenericEther *ether = NULL; if (metisEthernet_IsValidEthertype(etherType)) { ether = parcObject_CreateInstance(MetisGenericEther); ether->ethertype = etherType; ether->logger = metisLogger_Acquire(metisForwarder_GetLogger(metis)); ether->etherSocket = -1; // invalid valid ether->workBuffer = parcEventBuffer_Create(); ether->macAddress = NULL; ether->mtu = metisSystem_InterfaceMtu(metis, deviceName); _darwinEthernet_SetInterfaceAddress(ether, deviceName); bool success = _darwinEthernet_SetupReceive(ether, deviceName); if (success) { if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) { char *str = parcBuffer_ToHexString(ether->macAddress); metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__, "GenericEther %p created on device %s (%s) for ethertype 0x%04x fd %d bufferLength %u mtu %u", (void *) ether, deviceName, str, etherType, ether->etherSocket, ether->etherBufferLength, ether->mtu); parcMemory_Deallocate((void **) &str); } } else { if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Error)) { metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Error, __func__, "GenericEther failed to created on device %s for ethertype 0x%04x", deviceName, etherType); } // this will also null ether metisGenericEther_Release(ðer); } assertTrue(ether->etherBufferLength < 65536, "Buffer length way too big, expected less than 65536 got %u", ether->etherBufferLength); } else { if (metisLogger_IsLoggable(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Error)) { metisLogger_Log(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Error, __func__, "GenericEther failed to created on device %s for ethertype 0x%04x, invalid ethertype", deviceName, etherType); } } return ether; }
static MetisMessage * _metisLRUContentStore_MatchInterest(MetisContentStoreInterface *storeImpl, MetisMessage *interest) { MetisMessage *result = NULL; _MetisLRUContentStore *store = (_MetisLRUContentStore *) metisContentStoreInterface_GetPrivateData(storeImpl); assertNotNull(store, "Parameter store must be non-null"); assertNotNull(interest, "Parameter interestMessage must be non-null"); assertTrue(metisMessage_GetType(interest) == MetisMessagePacketType_Interest, "Parameter interestMessage must be an Interest"); // This will do the most restrictive lookup. // a) If the interest has a ContentObjectHash restriction, it will look only in the ByNameAndObjectHash table. // b) If it has a KeyId, it will look only in the ByNameAndKeyId table. // c) otherwise, it looks only in the ByName table. PARCHashCodeTable *table; if (metisMessage_HasContentObjectHash(interest)) { table = store->storageByNameAndObjectHashHash; } else if (metisMessage_HasKeyId(interest)) { table = store->indexByNameAndKeyIdHash; } else { table = store->indexByNameHash; } MetisContentStoreEntry *storeEntry = parcHashCodeTable_Get(table, interest); if (storeEntry) { metisContentStoreEntry_MoveToHead(storeEntry); result = metisContentStoreEntry_GetMessage(storeEntry); store->stats.countHits++; if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) { metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__, "LRUContentStore %p matched interest %p (hits %" PRIu64 ", misses %" PRIu64 ")", (void *) store, (void *) interest, store->stats.countHits, store->stats.countMisses); } } else { store->stats.countMisses++; if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) { metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__, "LRUContentStore %p missed interest %p (hits %" PRIu64 ", misses %" PRIu64 ")", (void *) store, (void *) interest, store->stats.countHits, store->stats.countMisses); } } return result; }
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; }
static void _metisStreamConnection_DestroyOperations(MetisIoOperations **opsPtr) { assertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer"); assertNotNull(*opsPtr, "Parameter opsPtr must dereference to non-null pointer"); MetisIoOperations *ops = *opsPtr; assertNotNull(metisIoOperations_GetClosure(ops), "ops->context must not be null"); _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops); parcEventQueue_Destroy(&stream->bufferEventVector); metisAddressPair_Release(&stream->addressPair); if (!stream->isClosed) { stream->isClosed = true; metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionClosed, stream->id)); } metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionDestroyed, stream->id)); if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__, "StreamConnection %p destroyed", (void *) stream); } metisLogger_Release(&stream->logger); parcMemory_Deallocate((void **) &stream); parcMemory_Deallocate((void **) &ops); *opsPtr = NULL; }
void metisConfiguration_Receive(MetisConfiguration *config, MetisMessage *message) { assertNotNull(config, "Parameter config must be non-null"); assertNotNull(message, "Parameter message must be non-null"); assertTrue(metisMessage_GetType(message) == MetisMessagePacketType_Control, "Message must be type CPI, expected %02x got %02x", MetisMessagePacketType_Control, metisMessage_GetType(message)); CCNxControl *control = metisMessage_CreateControlMessage(message); unsigned ingressId = metisMessage_GetIngressConnectionId(message); if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug)) { char *str = parcJSON_ToCompactString(ccnxControl_GetJson(control)); metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__, "%s received %s\n", __func__, str); parcMemory_Deallocate((void **) &str); } CCNxControl *response = _processControl(config, control, ingressId); metisConfiguration_SendResponse(config, response, ingressId); ccnxControl_Release(&response); ccnxControl_Release(&control); metisMessage_Release(&message); }
bool metisTlvSkeleton_Parse(MetisTlvSkeleton *opaque, uint8_t *packet, MetisLogger *logger) { // do not assert invariants here. Parse will setup the invariants. _InternalSkeleton *skeleton = (_InternalSkeleton *) opaque; uint8_t version = packet[0]; switch (version) { case 0: _initialize(skeleton, &MetisTlvSchemaV0_Ops, packet, logger); return MetisTlvSchemaV0_Ops.parse(opaque); case 1: _initialize(skeleton, &MetisTlvSchemaV1_Ops, packet, logger); return MetisTlvSchemaV1_Ops.parse(opaque); default: if (metisLogger_IsLoggable(logger, MetisLoggerFacility_Message, PARCLogLevel_Warning)) { metisLogger_Log(logger, MetisLoggerFacility_Message, PARCLogLevel_Warning, __func__, "Parsing unknown packet version %u", version); } break; } return false; }
bool metisHopByHopFragmenter_Send(MetisHopByHopFragmenter *fragmenter, MetisMessage *message) { bool success = false; // If the packet will fit in the MTU without fragmentation, do not use fragmentation if (metisMessage_Length(message) > fragmenter->mtu) { success = _sendFragments(fragmenter, message); } else { MetisMessage *copy = metisMessage_Acquire(message); success = parcRingBuffer1x1_Put(fragmenter->sendQueue, copy); if (!success) { metisMessage_Release(©); metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__, "Failed to add message %p to send queue", (void *) message); } else { if (metisLogger_IsLoggable(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { metisLogger_Log(fragmenter->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "Add message %p to send queue", (void *) message); } } } return success; }
/** * @function metisStreamConnection_Send * @abstract Non-destructive send of the message. * @discussion * Send uses metisMessage_CopyToStreamBuffer, which is a non-destructive write. * The send may fail if there's no buffer space in the output queue. * * @param dummy is ignored. A stream has only one peer. * @return <#return#> */ static bool _metisStreamConnection_Send(MetisIoOperations *ops, const CPIAddress *dummy, MetisMessage *message) { assertNotNull(ops, "Parameter ops must be non-null"); assertNotNull(message, "Parameter message must be non-null"); _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops); bool success = false; if (stream->isUp) { PARCEventBuffer *buffer = parcEventBuffer_GetQueueBufferOutput(stream->bufferEventVector); size_t buffer_backlog = parcEventBuffer_GetLength(buffer); parcEventBuffer_Destroy(&buffer); if (buffer_backlog < OUTPUT_QUEUE_BYTES) { if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "connid %u Writing %zu bytes to buffer with backlog %zu bytes", stream->id, metisMessage_Length(message), buffer_backlog); } int failure = metisMessage_Write(stream->bufferEventVector, message); if (failure == 0) { success = true; } } else { if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__, "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE", stream->id, buffer_backlog); } } } else { if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Error)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Error, __func__, "connid %u tried to send to down connection (isUp %d isClosed %d)", stream->id, stream->isUp, stream->isClosed); } } return success; }
static void _evictByStorePolicy(_MetisLRUContentStore *store, uint64_t currentTimeInMetisTicks) { // We need to make room. Here's the plan: // 1) Check to see if anything has expired. If so, remove it and we're done. If not, // 2) Check to see if anything has exceeded it's recommended cache time. If so, remove it and we're done. If not, // 3) Remove the least recently used item. MetisContentStoreEntry *entry = metisTimeOrderedList_GetOldest(store->indexByExpirationTime); if (entry && metisContentStoreEntry_HasExpiryTimeTicks(entry) && (currentTimeInMetisTicks > metisContentStoreEntry_GetExpiryTimeTicks(entry))) { // Found an expired entry. Remove it, and we're done. store->stats.countExpiryEvictions++; if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) { metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__, "ContentStore %p evict message %p by ExpiryTime (ExpiryTime evictions %" PRIu64 ")", (void *) store, (void *) metisContentStoreEntry_GetMessage(entry), store->stats.countExpiryEvictions); } _metisLRUContentStore_PurgeStoreEntry(store, entry); } else { // Check for entries that have exceeded RCT entry = metisTimeOrderedList_GetOldest(store->indexByRecommendedCacheTime); if (entry && metisContentStoreEntry_HasRecommendedCacheTimeTicks(entry) && (currentTimeInMetisTicks > metisContentStoreEntry_GetRecommendedCacheTimeTicks(entry))) { // Found an entry passed it's RCT. Remove it, and we're done. store->stats.countRCTEvictions++; if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) { metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__, "ContentStore %p evict message %p by RCT (RCT evictions %" PRIu64 ")", (void *) store, (void *) metisContentStoreEntry_GetMessage(entry), store->stats.countRCTEvictions); } _metisLRUContentStore_PurgeStoreEntry(store, entry); } else { store->stats.countLruEvictions++; _metisLRUContentStore_RemoveLeastUsed(store); } } }
MetisConfigurationFile * metisConfigurationFile_Create(MetisForwarder *metis, const char *filename) { assertNotNull(metis, "Parameter metis must be non-null"); assertNotNull(filename, "Parameter filename must be non-null"); MetisConfigurationFile *configFile = parcObject_CreateInstance(MetisConfigurationFile); if (configFile) { configFile->linesRead = 0; configFile->metis = metis; configFile->filename = parcMemory_StringDuplicate(filename, strlen(filename)); assertNotNull(configFile->filename, "Could not copy string '%s'", filename); // setup the control state for the command parser configFile->controlState = metisControlState_Create(configFile, _writeRead); // we do not register Help commands metisControlState_RegisterCommand(configFile->controlState, metisControlRoot_Create(configFile->controlState)); // open the file and make sure we can read it configFile->fh = fopen(configFile->filename, "r"); if (configFile->fh) { if (metisLogger_IsLoggable(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug)) { metisLogger_Log(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Debug, __func__, "Open config file %s", configFile->filename); } } else { if (metisLogger_IsLoggable(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Error)) { metisLogger_Log(metisForwarder_GetLogger(metis), MetisLoggerFacility_Config, PARCLogLevel_Error, __func__, "Could not open config file %s: (%d) %s", configFile->filename, errno, strerror(errno)); } // failure cleanup the object -- this nulls it so final return null be NULL metisConfigurationFile_Release(&configFile); } } return configFile; }
/** * Parses the work buffer to extract packets * * The work buffer should be filled in with a set of tuples (bh_hdrlen, frame, pad). * The pad extends each packet out to BPF_WORDALIGN. * * If the CCNxMessage PacketLength says it is larger than the read capture length (caplen), * then this is an invalid packet and it will be discarded. This error will result in a * ReadWorkBufferResult_TryAgain condition. * * struct bpf_hdr { * struct BPF_TIMEVAL bh_tstamp; // time stamp * bpf_u_int32 bh_caplen; // length of captured portion * bpf_u_int32 bh_datalen; // original length of packet * u_short bh_hdrlen; // length of bpf header (this struct plus alignment padding) * } * * @param [in] ether An allocated Darwin ethernet. * @param [in] readbuffer A user-provided read buffer. * * @retval ReadWorkBufferResult_Ok A frame was moved from workbuffer to readbuffer * @retval ReadWorkBufferResult_Empty There's not enough bytes in the workbuffer * @retval ReadWorkBufferResult_TryAgain (likely discard) caused this call to fail, but you should try again * * Example: * @code * <#example#> * @endcode */ static _ReadWorkBufferResult _darwinEthernet_ReadWorkBuffer(MetisGenericEther *ether, PARCEventBuffer *readbuffer) { _ReadWorkBufferResult result = ReadWorkBufferResult_Empty; // Make sure we have linear memory for the BPF header struct bpf_hdr *bpfHeader = (struct bpf_hdr *) parcEventBuffer_Pullup(ether->workBuffer, sizeof(struct bpf_hdr)); // make sure we have enough bytes to process the frame // bpfHeader may be NULL if there are not sizeof(struct bpf_hdr) bytes available. if (bpfHeader && parcEventBuffer_GetLength(ether->workBuffer) >= bpfHeader->bh_hdrlen + bpfHeader->bh_caplen) { // (0) Save the needed fields from the bpf header // (1) pop off the bpf header // (2) move the iovec from work buffer to readBuffer. // (3) remove any BPF_WORDALIGN padding to the start of the next packet // (0) Save the needed fields from the bpf header uint16_t hdrlen = bpfHeader->bh_hdrlen; uint32_t caplen = bpfHeader->bh_caplen; // (1) pop off the bpf header parcEventBuffer_Read(ether->workBuffer, NULL, hdrlen); // (1a) Determine the packet length from the fixed header and only transfer that many bytes uint16_t packetlen = _getFrameLengthFromWorkBuffer(ether); if (packetlen <= caplen) { // (2) move the iovec from work buffer to readBuffer. parcEventBuffer_ReadIntoBuffer(ether->workBuffer, readbuffer, packetlen); // (2a) drain off any trailer (i.e. FCS) parcEventBuffer_Read(ether->workBuffer, NULL, caplen - packetlen); result = ReadWorkBufferResult_Ok; } else { if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning)) { metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__, "%s reading fd %d discard packetlen %u greater than caplen %u", __func__, ether->etherSocket, packetlen, caplen); } // discard all of caplen parcEventBuffer_Read(ether->workBuffer, NULL, caplen); // tell the caller that this read failed, but they could try again. result = ReadWorkBufferResult_TryAgain; } // (3) remove any BPF_WORDALIGN padding to the start of the next packet size_t alignedLength = BPF_WORDALIGN(hdrlen + caplen); size_t pad = alignedLength - hdrlen - caplen; parcEventBuffer_Read(ether->workBuffer, NULL, pad); } return result; }
void metisTlvSkeleton_SetFragmentPayload(MetisTlvSkeleton *opaque, size_t offset, size_t length) { _InternalSkeleton *skeleton = (_InternalSkeleton *) opaque; skeleton->array[INDEX_FRAGMENTPAYLOAD].offset = offset; skeleton->array[INDEX_FRAGMENTPAYLOAD].length = length; if (metisLogger_IsLoggable(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug)) { metisLogger_Log(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug, __func__, "Set fragment payload extent {%u, %u}", offset, length); } }
void metisTlvSkeleton_SetCPI(MetisTlvSkeleton *opaque, size_t offset, size_t length) { _InternalSkeleton *skeleton = (_InternalSkeleton *) opaque; skeleton->array[INDEX_CPI].offset = offset; skeleton->array[INDEX_CPI].length = length; if (metisLogger_IsLoggable(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug)) { metisLogger_Log(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug, __func__, "Set cpi extent {%u, %u}", offset, length); } }
/** * @function single_read * @abstract Read at most 1 message from the network * @discussion * If a complete message is ready on the input buffer, will allocate and return it. * * This function manipulates the stream->nextMessageLength. (1) Initializes with nextMessageLength = 0, * which means we have not started parsing a packet. (2) After reading a FixedHeader, set nextMessageLength * to the total length of the message. (3) After reading nextMessageLength bytes, return the outputBuffer * and reset nextMessageLength to 0. * * @param input is the PARCEventBuffer to read * @param stream is the related stream state for the input * @return true if there's more to read after this message. */ static MetisMessage * _single_read(PARCEventBuffer *input, _MetisStreamState *stream) { size_t bytesAvailable = parcEventBuffer_GetLength(input); assertTrue(bytesAvailable >= metisTlv_FixedHeaderLength(), "Called with too short an input: %zu", bytesAvailable); if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "connid %u read %zu bytes", stream->id, bytesAvailable); } if (stream->nextMessageLength == 0) { _startNewMessage(stream, input, bytesAvailable); } // This is not an ELSE statement. We can both start a new message then // check if there's enough bytes to read the whole thing. if (bytesAvailable >= stream->nextMessageLength) { MetisMessage *message = _readMessage(stream, metisForwarder_GetTicks(stream->metis), input); if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "connid %u msg_length %zu read_length %zu, resetting parser", stream->id, stream->nextMessageLength, bytesAvailable); } // now reset message length for next packet stream->nextMessageLength = 0; return message; } return NULL; }
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); }
MetisIoOperations * metisStreamConnection_OpenConnection(MetisForwarder *metis, MetisAddressPair *pair, bool isLocal) { assertNotNull(metis, "Parameter metis must be non-null"); assertNotNull(pair, "Parameter pair must be non-null"); // if there's an error on the bind or connect, will return NULL PARCEventQueue *bufferEventVector = metisDispatcher_StreamBufferConnect(metisForwarder_GetDispatcher(metis), pair); if (bufferEventVector == NULL) { // error opening connection return NULL; } _MetisStreamState *stream = parcMemory_AllocateAndClear(sizeof(_MetisStreamState)); assertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_MetisStreamState)); stream->metis = metis; stream->logger = metisLogger_Acquire(metisForwarder_GetLogger(metis)); stream->fd = parcEventQueue_GetFileDescriptor(bufferEventVector); stream->bufferEventVector = bufferEventVector; stream->id = metisForwarder_GetNextConnectionId(metis); stream->addressPair = pair; stream->isClosed = false; // allocate a connection MetisIoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(MetisIoOperations)); assertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MetisIoOperations)); memcpy(io_ops, &_template, sizeof(MetisIoOperations)); io_ops->closure = stream; parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL, _conn_eventcb, (void *) io_ops); parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read); // we start in DOWN state, until remote side answers metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionCreate, stream->id)); _setConnectionState(stream, false); if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info)) { char *pair_str = metisAddressPair_ToString(pair); metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Info, __func__, "StreamConnection %p connect for address pair %s", (void *) stream, pair_str); free(pair_str); } return io_ops; }
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); }
bool metisTlvSkeleton_UpdateHopLimit(MetisTlvSkeleton *opaque, uint8_t hoplimit) { _InternalSkeleton *skeleton = (_InternalSkeleton *) opaque; bool updated = false; if (!metisTlvExtent_Equals(&skeleton->array[INDEX_HOPLIMIT], &metisTlvExtent_NotFound)) { if (skeleton->array[INDEX_HOPLIMIT].length == 1) { updated = true; uint8_t *value = skeleton->packet + skeleton->array[INDEX_HOPLIMIT].offset; *value = hoplimit; if (metisLogger_IsLoggable(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug)) { metisLogger_Log(skeleton->logger, MetisLoggerFacility_Message, PARCLogLevel_Debug, __func__, "set hoplimit %u", hoplimit); } } } return updated; }
MetisContentStoreInterface * metisLRUContentStore_Create(MetisContentStoreConfig *config, MetisLogger *logger) { MetisContentStoreInterface *storeImpl = NULL; assertNotNull(logger, "MetisLRUContentStore requires a non-NULL logger"); storeImpl = parcObject_CreateAndClearInstance(MetisContentStoreInterface); if (storeImpl != NULL) { storeImpl->_privateData = parcObject_CreateAndClearInstance(_MetisLRUContentStore); if (_metisLRUContentStore_Init(storeImpl->_privateData, config, logger)) { storeImpl->putContent = &_metisLRUContentStore_PutContent; storeImpl->removeContent = &_metisLRUContentStore_RemoveContent; storeImpl->matchInterest = &_metisLRUContentStore_MatchInterest; storeImpl->getObjectCount = &_metisLRUContentStore_GetObjectCount; storeImpl->getObjectCapacity = &_metisLRUContentStore_GetObjectCapacity; storeImpl->log = &_metisLRUContentStore_Log; storeImpl->acquire = &_metisLRUContentStore_Acquire; storeImpl->release = &_metisLRUContentStore_Release; // Initialize from the config passed to us. _metisLRUContentStore_SetObjectCapacity(storeImpl, config->objectCapacity); if (metisLogger_IsLoggable(logger, MetisLoggerFacility_Processor, PARCLogLevel_Info)) { metisLogger_Log(logger, MetisLoggerFacility_Processor, PARCLogLevel_Info, __func__, "LRUContentStore %p created with capacity %zu", (void *) storeImpl, metisContentStoreInterface_GetObjectCapacity(storeImpl)); } } } else { parcObject_Release((void **) &storeImpl); } return storeImpl; }
/* * Reading a BPF packet will include the BPF header. Frame may include the FCS. */ bool metisGenericEther_ReadNextFrame(MetisGenericEther *ether, PARCEventBuffer *readbuffer) { assertNotNull(ether, "Parameter ether must be non-null"); assertNotNull(readbuffer, "Parameter readbuffer must be non-null"); bool success = false; if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "Workbuffer length %zu", __func__, parcEventBuffer_GetLength(ether->workBuffer)); } // Do we already have something in our work buffer? If not, try to read something. if (parcEventBuffer_GetLength(ether->workBuffer) == 0) { _darwinEthernet_ReadSocket(ether); } success = _darwinEthernet_WorkBufferToReadBuffer(ether, readbuffer); return success; }
static void _metisGenericEther_Destroy(MetisGenericEther **etherPtr) { MetisGenericEther *ether = *etherPtr; if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "GenericEther %p destroyed", (void *) ether); } if (ether->etherSocket > 0) { close(ether->etherSocket); } if (ether->macAddress) { parcBuffer_Release(ðer->macAddress); } metisLogger_Release(ðer->logger); parcEventBuffer_Destroy(ðer->workBuffer); }
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); // 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)); } }
MetisIoOperations * metisStreamConnection_AcceptConnection(MetisForwarder *metis, int fd, MetisAddressPair *pair, bool isLocal) { _MetisStreamState *stream = parcMemory_AllocateAndClear(sizeof(_MetisStreamState)); assertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_MetisStreamState)); MetisDispatcher *dispatcher = metisForwarder_GetDispatcher(metis); PARCEventScheduler *eventBase = metisDispatcher_GetEventScheduler(dispatcher); stream->bufferEventVector = parcEventQueue_Create(eventBase, fd, PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks); stream->metis = metis; stream->logger = metisLogger_Acquire(metisForwarder_GetLogger(metis)); stream->fd = fd; stream->id = metisForwarder_GetNextConnectionId(metis); stream->addressPair = pair; stream->isClosed = false; // allocate a connection MetisIoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(MetisIoOperations)); assertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MetisIoOperations)); memcpy(io_ops, &_template, sizeof(MetisIoOperations)); io_ops->closure = stream; parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL, _conn_eventcb, (void *) io_ops); parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read); metisMessenger_Send(metisForwarder_GetMessenger(stream->metis), metisMissive_Create(MetisMissiveType_ConnectionCreate, stream->id)); // As we are acceting a connection, we begin in the UP state _setConnectionState(stream, true); if (metisLogger_IsLoggable(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug)) { char *pair_str = metisAddressPair_ToString(pair); metisLogger_Log(stream->logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "StreamConnection %p accept for address pair %s", (void *) stream, pair_str); free(pair_str); } return io_ops; }
static void _logProcessCreateTunnelMessage(MetisConfiguration *config, CPIInterfaceIPTunnel *iptun, PARCLogLevel logLevel, const char *message) { if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Info)) { const CPIAddress *source = cpiInterfaceIPTunnel_GetSourceAddress(iptun); const CPIAddress *destination = cpiInterfaceIPTunnel_GetDestinationAddress(iptun); const char *symbolicName = cpiInterfaceIPTunnel_GetSymbolicName(iptun); char *sourceString = cpiAddress_ToString(source); char *remoteString = cpiAddress_ToString(destination); metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Info, __func__, "Add connection %s on %s to %s: %s", symbolicName, sourceString, remoteString, message); parcMemory_Deallocate((void **) &sourceString); parcMemory_Deallocate((void **) &remoteString); } }
static bool _metisLRUContentStore_RemoveLeastUsed(_MetisLRUContentStore *store) { bool result = false; if (store->objectCount > 0) { MetisLruListEntry *lruEntry = metisLruList_PopTail(store->lru); MetisContentStoreEntry *storeEntry = (MetisContentStoreEntry *) metisLruList_EntryGetData(lruEntry); if (metisLogger_IsLoggable(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug)) { metisLogger_Log(store->logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug, __func__, "ContentStore %p evict message %p by LRU (LRU evictions %" PRIu64 ")", (void *) store, (void *) metisContentStoreEntry_GetMessage(storeEntry), store->stats.countLruEvictions); } _metisLRUContentStore_PurgeStoreEntry(store, storeEntry); result = true; } return result; }