Commit cd071261 authored by Kevin Fox's avatar Kevin Fox

Make fragmenter loadable per-ethernet link instance

parent 274a2250
......@@ -5,13 +5,13 @@ configure_file(config.h.in config.h @ONLY)
if ( APPLE )
set(ATHENA_PLATFORM_MODULES
platform/darwin/athena_Ethernet.c
)
)
endif()
if( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" )
set(ATHENA_PLATFORM_MODULES
platform/linux/athena_Ethernet.c
)
)
endif()
set(ATHENA_SOURCE_FILES
......@@ -21,6 +21,7 @@ set(ATHENA_SOURCE_FILES
athenactl_About.c
athena_Control.c
athena_InterestControl.c
athena_EthernetFragmenter.c
athena_FIB.c
athena_ContentStore.c
athena_LRUContentStore.c
......@@ -28,16 +29,17 @@ set(ATHENA_SOURCE_FILES
athena_TransportLinkAdapter.c
athena_TransportLink.c
athena_TransportLinkModule.c
${ATHENA_PLATFORM_MODULES}
)
${ATHENA_PLATFORM_MODULES}
)
set(ATHENA_HEADER_FILES
athena.h
athena_About.h
athena_ContentStore.h
athena_ContentStoreInterface.h
athena_ContentStoreInterface.h
athena_Control.h
athena_Ethernet.h
athena_Ethernet.h
athena_EthernetFragmenter.h
athena_FIB.h
athena_InterestControl.h
athena_LRUContentStore.h
......@@ -47,7 +49,7 @@ set(ATHENA_HEADER_FILES
athena_TransportLinkModule.h
athenactl.h
athenactl_About.h
)
)
set(LIBATHENA_TCP_SOURCE_FILES
athena_TransportLinkModuleTCP.c
......@@ -61,8 +63,8 @@ set(LIBATHENA_ETH_SOURCE_FILES
athena_TransportLinkModuleETH.c
)
set(LIBATHENA_ETH1990_SOURCE_FILES
athena_TransportLinkModuleETH1990.c
set(LIBATHENA_ETHFRAGMENT_1990_SOURCE_FILES
athena_TransportLinkModuleETHFragmenter_1990.c
)
set(LIBATHENA_TEMPLATE_SOURCE_FILES
......@@ -90,7 +92,7 @@ source_group(Sources FILES ${ATHENA_SOURCE_FILES})
source_group(Sources FILES ${LIBATHENA_TCP_SOURCE_FILES})
source_group(Sources FILES ${LIBATHENA_UDP_SOURCE_FILES})
source_group(Sources FILES ${LIBATHENA_ETH_SOURCE_FILES})
source_group(Sources FILES ${LIBATHENA_ETH1990_SOURCE_FILES})
source_group(Sources FILES ${LIBATHENA_ETHFRAGMENT_1990_SOURCE_FILES})
source_group(Sources FILES ${LIBATHENA_TEMPLATE_SOURCE_FILES})
add_library(athena_ETH.shared SHARED ${LIBATHENA_ETH_SOURCE_FILES})
......@@ -100,12 +102,12 @@ set_target_properties(athena_ETH.shared PROPERTIES
VERSION 1.0
OUTPUT_NAME athena_ETH )
add_library(athena_ETH1990.shared SHARED ${LIBATHENA_ETH1990_SOURCE_FILES})
set_target_properties(athena_ETH1990.shared PROPERTIES
add_library(athena_ETHFragment_1990.shared SHARED ${LIBATHENA_ETHFRAGMENT_1990_SOURCE_FILES})
set_target_properties(athena_ETHFragment_1990.shared PROPERTIES
C_STANDARD 99
SOVERSION 1
VERSION 1.0
OUTPUT_NAME athena_ETH1990 )
OUTPUT_NAME athena_ETHFragment_1990 )
add_library(athena_TEMPLATE.shared SHARED ${LIBATHENA_TEMPLATE_SOURCE_FILES})
set_target_properties(athena_TEMPLATE.shared PROPERTIES
......@@ -119,7 +121,7 @@ set(athena_libraries
athena_TCP.shared
athena_UDP.shared
athena_ETH.shared
athena_ETH1990.shared
athena_ETHFragment_1990.shared
athena_TEMPLATE.shared
)
......@@ -133,9 +135,9 @@ add_subdirectory(command-line)
if ( UNIX )
execute_process(COMMAND whoami OUTPUT_VARIABLE USER
OUTPUT_STRIP_TRAILING_WHITESPACE)
OUTPUT_STRIP_TRAILING_WHITESPACE)
if ( ${USER} STREQUAL "root" )
add_subdirectory(platform/darwin/test)
add_subdirectory(platform/linux/test)
add_subdirectory(platform/darwin/test)
add_subdirectory(platform/linux/test)
endif()
endif()
/*
* Copyright (c) 2016, Xerox Corporation (Xerox)and Palo Alto Research Center (PARC)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Patent rights are not granted under this agreement. Patent rights are
* available under FRAND terms.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEROX or PARC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Kevin Fox, Palo Alto Research Center (Xerox PARC)
* @copyright 2016, Xerox Corporation (Xerox)and Palo Alto Research Center (PARC). All rights reserved.
*/
#include <config.h>
#include <LongBow/runtime.h>
#include <dlfcn.h>
#include <errno.h>
#include <net/ethernet.h>
#include <parc/algol/parc_Object.h>
#include <ccnx/forwarder/athena/athena_TransportLinkModule.h>
#include <ccnx/forwarder/athena/athena_EthernetFragmenter.h>
#include <ctype.h>
static const char *
_strtoupper(const char *string)
{
char *upperCaseString = parcMemory_StringDuplicate(string, strlen(string));
for (char *i = upperCaseString; *i; i++) {
*i = toupper(*i);
}
return upperCaseString;
}
#define LIBRARY_MODULE_PREFIX "libathena_ETHFragmenter_"
#ifdef __linux__
#define LIBRARY_MODULE_SUFFIX ".so"
#else // MacOS
#define LIBRARY_MODULE_SUFFIX ".dylib"
#endif
#define METHOD_PREFIX "athenaEthernetFragmenter_"
#define INIT_METHOD_SUFFIX "_Init"
static const char *
_nameToInitMethod(const char *name)
{
char *result = NULL;
assertNotNull(name, "name must not be null");
const char *module = _strtoupper(name);
PARCBufferComposer *composer = parcBufferComposer_Create();
if (composer != NULL) {
parcBufferComposer_Format(composer, "%s%s%s",
METHOD_PREFIX, module, INIT_METHOD_SUFFIX);
PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
parcBufferComposer_Release(&composer);
result = parcBuffer_ToString(tempBuffer);
parcBuffer_Release(&tempBuffer);
}
parcMemory_Deallocate(&module);
return result;
}
static const char *
_nameToLibrary(const char *name)
{
char *result = NULL;
assertNotNull(name, "module name must not be null");
const char *libraryName = _strtoupper(name);
PARCBufferComposer *composer = parcBufferComposer_Create();
if (composer != NULL) {
parcBufferComposer_Format(composer, "%s%s%s",
LIBRARY_MODULE_PREFIX, libraryName, LIBRARY_MODULE_SUFFIX);
PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
parcBufferComposer_Release(&composer);
result = parcBuffer_ToString(tempBuffer);
parcBuffer_Release(&tempBuffer);
}
parcMemory_Deallocate(&libraryName);
return result;
}
typedef AthenaEthernetFragmenter *(*ModuleInit)(AthenaEthernetFragmenter *);
static void
_destroy(AthenaEthernetFragmenter **athenaEthernetFragmenter)
{
if ((*athenaEthernetFragmenter)->fini) {
(*athenaEthernetFragmenter)->fini(*athenaEthernetFragmenter);
}
if ((*athenaEthernetFragmenter)->module) {
dlclose((*athenaEthernetFragmenter)->module);
}
}
parcObject_ExtendPARCObject(AthenaEthernetFragmenter, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
AthenaEthernetFragmenter *
athenaEthernetFragmenter_Create(const char *fragmenterName)
{
AthenaEthernetFragmenter *athenaEthernetFragmenter = parcObject_CreateAndClearInstance(AthenaEthernetFragmenter);
const char *moduleLibrary = _nameToLibrary(fragmenterName);
athenaEthernetFragmenter->module = dlopen(moduleLibrary, RTLD_NOW | RTLD_GLOBAL);
parcMemory_Deallocate(&moduleLibrary);
if (athenaEthernetFragmenter->module == NULL) {
athenaEthernetFragmenter_Release(&athenaEthernetFragmenter);
errno = ENOENT;
return NULL;
}
const char *initEntry = _nameToInitMethod(fragmenterName);
ModuleInit _init = dlsym(athenaEthernetFragmenter->module, initEntry);
parcMemory_Deallocate(&initEntry);
if (_init == NULL) {
athenaEthernetFragmenter_Release(&athenaEthernetFragmenter);
errno = EFAULT;
return NULL;
}
if (_init(athenaEthernetFragmenter) == NULL) {
athenaEthernetFragmenter_Release(&athenaEthernetFragmenter);
errno = ENODEV;
return NULL;
}
return athenaEthernetFragmenter;
}
parcObject_ImplementAcquire(athenaEthernetFragmenter, AthenaEthernetFragmenter);
parcObject_ImplementRelease(athenaEthernetFragmenter, AthenaEthernetFragmenter);
int
athenaEthernetFragmenter_Send(AthenaEthernetFragmenter *athenaEthernetFragmenter,
AthenaEthernet *athenaEthernet,
size_t mtu,
struct ether_header *header,
CCNxMetaMessage *ccnxMetaMessage)
{
if (athenaEthernetFragmenter && athenaEthernetFragmenter->send) {
return athenaEthernetFragmenter->send(athenaEthernetFragmenter, athenaEthernet, mtu, header, ccnxMetaMessage);
} else {
errno = ENOENT;
return -1;
}
return 0;
}
PARCBuffer *
athenaEthernetFragmenter_Receive(AthenaEthernetFragmenter *athenaEthernetFragmenter, PARCBuffer *wireFormatBuffer)
{
if (athenaEthernetFragmenter && athenaEthernetFragmenter->receive) {
return athenaEthernetFragmenter->receive(athenaEthernetFragmenter, wireFormatBuffer);
}
return wireFormatBuffer;
}
/*
* Copyright (c) 2016, Xerox Corporation (Xerox)and Palo Alto Research Center (PARC)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Patent rights are not granted under this agreement. Patent rights are
* available under FRAND terms.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEROX or PARC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Kevin Fox, Palo Alto Research Center (Xerox PARC)
* @copyright 2016, Xerox Corporation (Xerox)and Palo Alto Research Center (PARC). All rights reserved.
*/
#ifndef libathena_EthernetFragmenter
#define libathena_EthernetFragmenter
#include <parc/algol/parc_Deque.h>
#include <ccnx/forwarder/athena/athena_Ethernet.h>
typedef struct AthenaEthernetFragmenter AthenaEthernetFragmenter;
typedef int (AthenaEthernetFragmenter_Send)(AthenaEthernetFragmenter *athenaEthernetFragmenter,
AthenaEthernet *athenaEthernet,
size_t mtu, struct ether_header *etherHeader,
CCNxMetaMessage *ccnxMetaMessage);
typedef PARCBuffer *(AthenaEthernetFragmenter_Receive)(AthenaEthernetFragmenter *athenaEthernetFragmenter,
PARCBuffer *wireFormatBuffer);
typedef void (AthenaEthernetFragmenter_Fini)(AthenaEthernetFragmenter *athenaEthernetFragmenter);
//
// Private data for each fragmented connection
//
struct AthenaEthernetFragmenter {
void *module;
uint32_t sendSequenceNumber;
uint32_t receiveSequenceNumber;
PARCDeque *fragments;
AthenaEthernetFragmenter_Send *send;
AthenaEthernetFragmenter_Receive *receive;
AthenaEthernetFragmenter_Fini *fini;
};
typedef AthenaEthernetFragmenter *(AthenaEthernetFragmenter_Init)();
AthenaEthernetFragmenter *athenaEthernetFragmenter_Create(const char *fragmenterName);
AthenaEthernetFragmenter *athenaEthernetFragmenter_Acquire(const AthenaEthernetFragmenter *);
void athenaEthernetFragmenter_Release(AthenaEthernetFragmenter **);
int athenaEthernetFragmenter_Send(AthenaEthernetFragmenter *athenaEthernetFragmenter,
AthenaEthernet *athenaEthernet, size_t mtu,
struct ether_header *header, CCNxMetaMessage *ccnxMetaMessage);
PARCBuffer *athenaEthernetFragmenter_Receive(AthenaEthernetFragmenter *athenaEthernetFragmenter,
PARCBuffer *wireFormatBuffer);
#endif // libathena_EthernetFragmenter
......@@ -53,6 +53,7 @@
#include <ccnx/forwarder/athena/athena_TransportLinkModule.h>
#include <ccnx/forwarder/athena/athena_TransportLinkModuleETH.h>
#include <ccnx/forwarder/athena/athena_Ethernet.h>
#include <ccnx/forwarder/athena/athena_EthernetFragmenter.h>
#include <ccnx/common/codec/ccnxCodec_TlvPacket.h>
......@@ -83,8 +84,11 @@ typedef struct _ETHLinkData {
size_t send_ShortWrite;
} _stats;
AthenaEthernet *athenaEthernet;
AthenaEthernetFragmenter *fragmenter;
} _ETHLinkData;
typedef AthenaEthernetFragmenter *(*ModuleInit)(void);
static int
_stringToEtherAddr(struct ether_addr *address, const char *buffer)
{
......@@ -136,6 +140,9 @@ _ETHLinkData_Destroy(_ETHLinkData **linkData)
if ((*linkData)->multiplexTable) {
parcHashCodeTable_Destroy(&((*linkData)->multiplexTable));
}
if ((*linkData)->fragmenter) {
athenaEthernetFragmenter_Release(&((*linkData)->fragmenter));
}
parcMemory_Deallocate(linkData);
}
......@@ -186,27 +193,41 @@ _ETHSend(AthenaTransportLink *athenaTransportLink, CCNxMetaMessage *ccnxMetaMess
"sending deprecated version %d message\n", ccnxTlvDictionary_GetSchemaVersion(ccnxMetaMessage));
}
// Construct our header to prepend
// Construct the ethernet header to prepend
struct ether_header header;
memcpy(header.ether_shost, &(linkData->link.myAddress), ETHER_ADDR_LEN * sizeof(uint8_t));
memcpy(header.ether_dhost, &(linkData->link.peerAddress), ETHER_ADDR_LEN * sizeof(uint8_t));
header.ether_type = htons(athenaEthernet_GetEtherType(linkData->athenaEthernet));
// An iovec to contain the header and packet data
CCNxCodecNetworkBufferIoVec *iovec = athenaTransportLinkModule_GetMessageIoVector(ccnxMetaMessage);
// If we we're setup to fragment, and the message would exceed our MTU size,
// fragment it and send the messages out.
if ((ccnxCodecNetworkBufferIoVec_Length(iovec) + sizeof(struct ether_header)) > linkData->link.mtu) {
if (linkData->fragmenter) {
ccnxCodecNetworkBufferIoVec_Release(&iovec);
return athenaEthernetFragmenter_Send(linkData->fragmenter,
linkData->athenaEthernet,
linkData->link.mtu, &header,
ccnxMetaMessage);
} else {
errno = EMSGSIZE;
return -1;
}
}
// An iovec to contain the header and packet data for the trivial case
struct iovec iov[2];
struct iovec *array = iov;
int iovcnt = 2;
size_t messageLength = 0;
// If the iovec we're prepending to has more than one element, allocatedIovec holds the
// allocated IO vector of the right size that we must deallocate before returning.
struct iovec *allocatedIovec = NULL;
// Attach the header and populate the iovec
// Attach our ethernet header and populate the iovec
CCNxCodecNetworkBufferIoVec *iovec = athenaTransportLinkModule_GetMessageIoVector(ccnxMetaMessage);
iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec);
int iovcnt = ccnxCodecNetworkBufferIoVec_GetCount((CCNxCodecNetworkBufferIoVec *) iovec);
const struct iovec *networkBufferIovec = ccnxCodecNetworkBufferIoVec_GetArray((CCNxCodecNetworkBufferIoVec *) iovec);
// Trivial case, single iovec element.
......@@ -238,17 +259,6 @@ _ETHSend(AthenaTransportLink *athenaTransportLink, CCNxMetaMessage *ccnxMetaMess
}
iovcnt++; // increment for the header
if (linkData->link.mtu) {
if (messageLength > linkData->link.mtu) {
if (allocatedIovec != NULL) {
parcMemory_Deallocate(&allocatedIovec);
}
ccnxCodecNetworkBufferIoVec_Release(&iovec);
errno = EMSGSIZE;
return -1;
}
}
parcLog_Debug(athenaTransportLink_GetLogger(athenaTransportLink),
"sending message (size=%d)", messageLength);
......@@ -405,6 +415,11 @@ _demuxDelivery(AthenaTransportLink *athenaTransportLink, CCNxMetaMessage *ccnxMe
if (demuxLink == NULL) {
_ETHLinkData *newLinkData = _ETHLinkData_Create();
// Use the same fragmentation as our parent
if (linkData->fragmenter) {
newLinkData->fragmenter = athenaEthernetFragmenter_Acquire(linkData->fragmenter);
}
// We use our parents fd to send, and receive demux'd messages from our parent on our queue
newLinkData->athenaEthernet = athenaEthernet_Acquire(linkData->athenaEthernet);
newLinkData->queue = parcDeque_Create();
......@@ -469,6 +484,8 @@ _ETHReceiveMessage(AthenaTransportLink *athenaTransportLink, struct ether_addr *
PARCBuffer *wireFormatBuffer = parcBuffer_Slice(message);
parcBuffer_Release(&message);
wireFormatBuffer = athenaEthernetFragmenter_Receive(linkData->fragmenter, wireFormatBuffer);
if (wireFormatBuffer != NULL) {
// Construct, and return a ccnxMetaMessage from the wire format buffer.
parcBuffer_SetPosition(wireFormatBuffer, 0);
......@@ -701,6 +718,16 @@ _ETHOpenListener(AthenaTransportLinkModule *athenaTransportLinkModule, const cha
#define LINK_MTU_SIZE "mtu%3D"
#define SRC_LINK_SPECIFIER "src%3D"
#define ETH_LISTENER_FLAG "listener"
#define FRAGMENTER "fragmenter%3D"
static int
_parseFragmenterName(const char *token, char *name)
{
if (sscanf(token, "%*[^%%]%%3D%s", name) != 1) {
return -1;
}
return 0;
}
static int
_parseLinkName(const char *token, char *name)
......@@ -795,6 +822,8 @@ _ETHOpen(AthenaTransportLinkModule *athenaTransportLinkModule, PARCURI *connecti
bool isListener = false;
char *linkName = NULL;
char specifiedLinkName[MAXPATHLEN] = { 0 };
char *fragmenterName = NULL;
char specifiedFragmenterName[MAXPATHLEN] = { 0 };
size_t mtu = 0;
int forceLocal = 0;
......@@ -814,6 +843,19 @@ _ETHOpen(AthenaTransportLinkModule *athenaTransportLinkModule, PARCURI *connecti
continue;
}
if (strncasecmp(token, FRAGMENTER, strlen(FRAGMENTER)) == 0) {
if (_parseFragmenterName(token, specifiedFragmenterName) != 0) {
parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule),
"Improper fragmenter name specification (%s)", token);
parcMemory_Deallocate(&token);
errno = EINVAL;
return NULL;
}
fragmenterName = specifiedFragmenterName;
parcMemory_Deallocate(&token);
continue;
}
if (strncasecmp(token, SRC_LINK_SPECIFIER, strlen(SRC_LINK_SPECIFIER)) == 0) {
if (_parseSrc(athenaTransportLinkModule, token, &srcMAC) != 0) {
parcLog_Error(athenaTransportLinkModule_GetLogger(athenaTransportLinkModule),
......@@ -881,6 +923,11 @@ _ETHOpen(AthenaTransportLinkModule *athenaTransportLinkModule, PARCURI *connecti
}
}
if (result && fragmenterName) {
struct _ETHLinkData *linkData = athenaTransportLink_GetPrivateData(result);
linkData->fragmenter = athenaEthernetFragmenter_Create(fragmenterName);
}
// forced IsLocal/IsNotLocal, mainly for testing
if (result && forceLocal) {
athenaTransportLink_ForceLocal(result, forceLocal);
......
......@@ -12,7 +12,6 @@ set(TestsExpectedToPass
test_athena_TransportLinkModuleTCP
test_athena_TransportLinkModuleUDP
test_athena_TransportLinkModuleETH
test_athena_TransportLinkModuleETH1990
test_athena_TransportLinkModuleTEMPLATE
test_athena_ContentStore
test_athena_LRUContentStore
......
......@@ -67,6 +67,7 @@ LONGBOW_TEST_FIXTURE(Global)
{
LONGBOW_RUN_TEST_CASE(Global, athenaTransportLinkModuleETH_OpenClose);
LONGBOW_RUN_TEST_CASE(Global, athenaTransportLinkModuleETH_SendReceive);
LONGBOW_RUN_TEST_CASE(Global, athenaTransportLinkModuleETH_SendReceiveFragments);
}
LONGBOW_TEST_FIXTURE_SETUP(Global)
......@@ -330,6 +331,100 @@ LONGBOW_TEST_CASE(Global, athenaTransportLinkModuleETH_SendReceive)
athenaTransportLinkAdapter_Destroy(&athenaTransportLinkAdapter);
}
LONGBOW_TEST_CASE(Global, athenaTransportLinkModuleETH_SendReceiveFragments)
{
PARCURI *connectionURI;
char linkSpecificationURI[MAXPATHLEN];
char deviceMAC[NI_MAXHOST];
const char *result;
AthenaTransportLinkAdapter *athenaTransportLinkAdapter = athenaTransportLinkAdapter_Create(_removeLink, NULL);
assertNotNull(athenaTransportLinkAdapter, "athenaTransportLinkAdapter_Create returned NULL");
const char *device = _getInterfaceByName();
assertNotNull(device, "Could not find an available ethernet device");
struct ether_addr myAddress;
athenaEthernet_GetInterfaceMAC(device, &myAddress);
sprintf(deviceMAC, "%2.2hhx:%2.2hhx:%2.2hhx:%2.2hhx:%2.2hhx:%2.2hhx",
myAddress.ether_addr_octet[0], myAddress.ether_addr_octet[1],
myAddress.ether_addr_octet[2], myAddress.ether_addr_octet[3],
myAddress.ether_addr_octet[4], myAddress.ether_addr_octet[5]);
sprintf(linkSpecificationURI, "eth://%s/Listener/name=ETHListener/fragmenter=1990", device);
connectionURI = parcURI_Parse(linkSpecificationURI);
result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
// If we can't open a device (i.e. we're not root), the test can not continue.
if ((result == NULL) && (errno == EBADF)) {
parcURI_Release(&connectionURI);
athenaTransportLinkAdapter_Destroy(&athenaTransportLinkAdapter);
return;
}
assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
parcURI_Release(&connectionURI);
// Open a link we can send messages on
sprintf(linkSpecificationURI, "eth1990://%s/name=ETH_1/fragmenter=1990", device);
connectionURI = parcURI_Parse(linkSpecificationURI);
result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
parcURI_Release(&connectionURI);
free((void *) device);
// Enable debug logging after all instances are open
athenaTransportLinkAdapter_SetLogLevel(athenaTransportLinkAdapter, PARCLogLevel_Debug);
// Construct an interest
CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
CCNxMetaMessage *ccnxMetaMessage = ccnxInterest_CreateSimple(name);
ccnxName_Release(&name);
PARCBitVector *sendVector = parcBitVector_Create();
// Send the interest out on the link, this message will also be received by ourself
// since we're sending it to our own MAC destination.
int linkId = athenaTransportLinkAdapter_LinkNameToId(athenaTransportLinkAdapter, "ETH_1");
parcBitVector_Set(sendVector, linkId);
// Try to send a large (>mtu) message
size_t numberOfFragments = 4; // four is the maximum that MacOS will queue without a reader
size_t mtu = 1500;
size_t largePayloadSize = mtu * numberOfFragments;
char largePayload[largePayloadSize];
PARCBuffer *payload = parcBuffer_Wrap((void *)largePayload, largePayloadSize, 0, largePayloadSize);
ccnxInterest_SetPayload(ccnxMetaMessage, payload);
athena_EncodeMessage(ccnxMetaMessage);
PARCBitVector *resultVector = athenaTransportLinkAdapter_Send(athenaTransportLinkAdapter, ccnxMetaMessage, sendVector);
assertTrue(parcBitVector_NumberOfBitsSet(resultVector) == 1, "athenaTransportLinkAdapter_Send should have fragmented and sent a large message");
parcBuffer_Release(&payload);
parcBitVector_Release(&sendVector);
parcBitVector_Release(&resultVector);
ccnxMetaMessage_Release(&ccnxMetaMessage);
size_t iterations = numberOfFragments + 5;
// Receive the large message
do {
// Allow a context switch for the sends to complete
usleep(1000);
ccnxMetaMessage = athenaTransportLinkAdapter_Receive(athenaTransportLinkAdapter, &resultVector, 0);
} while (iterations-- && (ccnxMetaMessage == NULL));
assertNotNull(ccnxMetaMessage, "Could not reassemble fragmented message");
parcBitVector_Release(&resultVector);
ccnxMetaMessage_Release(&ccnxMetaMessage);
// Close one end of the connection
int closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "ETHListener");
assertTrue(closeResult == 0, "athenaTransportLinkAdapter_CloseByName failed (%s)", strerror(errno));
closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "ETH_1");
assertTrue(closeResult == 0, "athenaTransportLinkAdapter_CloseByName failed (%s)", strerror(errno));
athenaTransportLinkAdapter_Destroy(&athenaTransportLinkAdapter);
}
LONGBOW_TEST_FIXTURE(Local)
{
}
......
......@@ -29,7 +29,7 @@
* @copyright 2015, Xerox Corporation (Xerox)and Palo Alto Research Center (PARC). All rights reserved.
*/
#include <config.h>
#include "../athena_TransportLinkModuleETH1990.c"
#include "../athena_TransportLinkModuleETHFragmenter_1990.c"
#include <LongBow/unit-test.h>
#include <stdio.h>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment