From c580a00aac271a524e5a75b35f4b91c174ed227b Mon Sep 17 00:00:00 2001 From: michele papalini Date: Thu, 23 Feb 2017 17:01:34 +0100 Subject: Initial commit: sb-forwarder, metis. Change-Id: I65ee3c851a6901929ef4417ad80d34bca0dce445 Signed-off-by: michele papalini --- .../metis/platforms/linux/test/.gitignore | 2 + .../platforms/linux/test/test_metis_GenericEther.c | 566 +++++++++++++++++++++ .../metis/platforms/linux/test/test_metis_System.c | 148 ++++++ 3 files changed, 716 insertions(+) create mode 100644 metis/ccnx/forwarder/metis/platforms/linux/test/.gitignore create mode 100644 metis/ccnx/forwarder/metis/platforms/linux/test/test_metis_GenericEther.c create mode 100644 metis/ccnx/forwarder/metis/platforms/linux/test/test_metis_System.c (limited to 'metis/ccnx/forwarder/metis/platforms/linux/test') diff --git a/metis/ccnx/forwarder/metis/platforms/linux/test/.gitignore b/metis/ccnx/forwarder/metis/platforms/linux/test/.gitignore new file mode 100644 index 00000000..44d3cf6d --- /dev/null +++ b/metis/ccnx/forwarder/metis/platforms/linux/test/.gitignore @@ -0,0 +1,2 @@ +test_metis_GenericEther +test_metis_System diff --git a/metis/ccnx/forwarder/metis/platforms/linux/test/test_metis_GenericEther.c b/metis/ccnx/forwarder/metis/platforms/linux/test/test_metis_GenericEther.c new file mode 100644 index 00000000..aedc5363 --- /dev/null +++ b/metis/ccnx/forwarder/metis/platforms/linux/test/test_metis_GenericEther.c @@ -0,0 +1,566 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metis_GenericEther.c" + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +/* + * This is no longer gobally exported, so reproduce here for tests + */ +typedef struct __attribute__ ((__packed__)) metis_tlv_fixed_header { + uint8_t version; + uint8_t packetType; + uint16_t payloadLength; + uint16_t reserved; + uint16_t headerLength; +} _MetisTlvFixedHeaderV0; + +static char * +getInterfaceName(void) +{ + // Lookup the MAC address of an interface that is up, then ask for it. Don't use loopback. + struct ifaddrs *ifaddr; + int failure = getifaddrs(&ifaddr); + assertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno)); + + char *ifname = NULL; + + struct ifaddrs *next; + for (next = ifaddr; next != NULL && ifname == NULL; next = next->ifa_next) { + if ((next->ifa_addr == NULL) || ((next->ifa_flags & IFF_UP) == 0)) { + continue; + } + + if (next->ifa_flags & IFF_LOOPBACK) { + continue; + } + + if (next->ifa_addr->sa_family == AF_PACKET) { + ifname = strdup(next->ifa_name); + } + } + freeifaddrs(ifaddr); + return ifname; +} + +static char *interfaceName = NULL; + +// ===================================== + + +LONGBOW_TEST_RUNNER(linux_Ethernet) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +/* + * If we cannot open a raw socket, we cannot run any of these tests. + */ +static bool +_checkForRawAbility(void) +{ + bool success = false; + uint16_t ethertype = 0x0801; + int fd = socket(AF_PACKET, SOCK_RAW, htons(ethertype)); + if (fd > 0) { + success = true; + close(fd); + } + + return success; +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(linux_Ethernet) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + if (_checkForRawAbility()) { + interfaceName = getInterfaceName(); + return LONGBOW_STATUS_SUCCEEDED; + } + + fprintf(stderr, "%s failed to open an AF_PACKET SOCK_RAW socket, cannot execute tests\n", __func__); + // exit here with autoconf SKIP code until LongBow exits that way for skipped tests + exit(77); + return LONGBOW_STATUS_SETUP_SKIPTESTS; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(linux_Ethernet) +{ + free(interfaceName); + + return LONGBOW_STATUS_SUCCEEDED; +} + +static uint8_t * +createEtherFrame(uint32_t frameLength) +{ + uint8_t *frame = parcMemory_AllocateAndClear(frameLength); + + for (int i = 0; i < frameLength; i++) { + frame[i] = i * frameLength; + } + + // Create a proper header + size_t messageLength = frameLength - ETHER_HDR_LEN; + size_t payloadLength = messageLength - metisTlv_FixedHeaderLength(); + + _MetisTlvFixedHeaderV0 *fixedHeader = (_MetisTlvFixedHeaderV0 *) (frame + ETHER_HDR_LEN); + fixedHeader->version = 0; + fixedHeader->packetType = 1; + fixedHeader->payloadLength = payloadLength; + fixedHeader->headerLength = 0; + + return frame; +} + +static PARCBuffer * +createInterestFrame(size_t extrabytes) +{ + size_t totalLength = sizeof(metisTestDataV0_EncodedInterest) + extrabytes + ETHER_HDR_LEN; + uint8_t *frame = createEtherFrame(totalLength); + + memcpy(frame + ETHER_HDR_LEN, metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest)); + + PARCBuffer *buffer = parcBuffer_Allocate(totalLength); + parcBuffer_PutArray(buffer, totalLength, frame); + parcBuffer_Flip(buffer); + parcMemory_Deallocate((void **) &frame); + + return buffer; +} + +// ================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisGenericEther_Create); + LONGBOW_RUN_TEST_CASE(Global, metisGenericEther_Create_BadEtherType); + LONGBOW_RUN_TEST_CASE(Global, metisGenericEther_Release); + LONGBOW_RUN_TEST_CASE(Global, metisGenericEther_GetDescriptor); + LONGBOW_RUN_TEST_CASE(Global, metisGenericEther_ReadNextFrame); + LONGBOW_RUN_TEST_CASE(Global, metisGenericEther_ReadNextFrame_WithPadding); + LONGBOW_RUN_TEST_CASE(Global, metisGenericEther_SendFrame); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisGenericEther_Create) +{ + uint16_t ethertype = 0x0801; + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisGenericEther *ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + + assertNotNull(ether, "Got null ether"); + assertTrue(ether->ethertype == ethertype, "Wrong ethertype, got %x expected %x", ether->ethertype, ethertype); + assertTrue(ether->etherSocket > 0, "Invalid etherSocket, got %d", ether->etherSocket); + + metisGenericEther_Release(ðer); +} + +LONGBOW_TEST_CASE(Global, metisGenericEther_Create_BadEtherType) +{ + uint16_t ethertype = 0x0000; + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisGenericEther *ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + + assertNull(ether, "Should have gotten NULL for bad ethertype"); +} + + +LONGBOW_TEST_CASE(Global, metisGenericEther_Release) +{ + uint16_t ethertype = 0x0801; + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisGenericEther *ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + metisGenericEther_Release(ðer); + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after release"); + assertNull(ether, "release did not null the pointer"); +} + +LONGBOW_TEST_CASE(Global, metisGenericEther_GetDescriptor) +{ + uint16_t ethertype = 0x0801; + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisGenericEther *ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + int fd = metisGenericEther_GetDescriptor(ether); + assertTrue(fd == ether->etherSocket, "Returned wrong descriptor"); + metisGenericEther_Release(ðer); +} + +static void +assertFrameEquals(uint8_t *frame, PARCEventBuffer *test, size_t caplen) +{ + assertTrue(parcEventBuffer_GetLength(test) == caplen, "Wrong length, got %zu expected %zu", parcEventBuffer_GetLength(test), caplen); + + uint8_t *linear = parcEventBuffer_Pullup(test, -1); + assertTrue(memcmp(linear, frame, caplen) == 0, "Buffers do not compare"); +} + +LONGBOW_TEST_CASE(Global, metisGenericEther_ReadNextFrame) +{ + uint16_t ethertype = 0x0801; + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisGenericEther *ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + + // swap out the PF_PACKET socket for a socket pair + close(ether->etherSocket); + + int fd[2]; + socketpair(PF_LOCAL, SOCK_DGRAM, 0, fd); + + int localSocket = fd[0]; + ether->etherSocket = fd[1]; + _linuxEthernet_SetNonBlocking(ether); + + size_t length_a = 129; + uint8_t *frame_a = createEtherFrame(length_a); + + size_t length_b = 777; + uint8_t *frame_b = createEtherFrame(length_b); + + ssize_t nwritten = write(localSocket, frame_a, length_a); + assertTrue(nwritten == length_a, "Error on write, expected %zu got %zd", length_a, nwritten); + + nwritten = write(localSocket, frame_b, length_b); + assertTrue(nwritten == length_b, "Error on write, expected %zu got %zd", length_b, nwritten); + + + // wait for it to become available + struct pollfd pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = ether->etherSocket; + pfd.events = POLLIN | POLLERR; + + poll(&pfd, 1, 10); + + // Something is ready to read + + bool success; + + PARCEventBuffer *output = parcEventBuffer_Create(); + + success = metisGenericEther_ReadNextFrame(ether, output); + assertTrue(success, "Failed to read frame A"); + assertFrameEquals(frame_a, output, length_a); + + // clear the buffer before next packet + parcEventBuffer_Read(output, NULL, -1); + + success = metisGenericEther_ReadNextFrame(ether, output); + assertTrue(success, "Failed to read frame B"); + assertFrameEquals(frame_b, output, length_b); + + close(localSocket); + + parcMemory_Deallocate((void **) &frame_a); + parcMemory_Deallocate((void **) &frame_b); + parcEventBuffer_Destroy(&output); + metisGenericEther_Release(ðer); +} + +LONGBOW_TEST_CASE(Global, metisGenericEther_ReadNextFrame_WithPadding) +{ + uint16_t ethertype = 0x0801; + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisGenericEther *ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + + // swap out the PF_PACKET socket for a socket pair + close(ether->etherSocket); + + int fd[2]; + socketpair(PF_LOCAL, SOCK_DGRAM, 0, fd); + + int localSocket = fd[0]; + ether->etherSocket = fd[1]; + _linuxEthernet_SetNonBlocking(ether); + + ssize_t nwritten = write(localSocket, metisTestDataV1_InterestWithEthernetPadding, sizeof(metisTestDataV1_InterestWithEthernetPadding)); + assertTrue(nwritten == sizeof(metisTestDataV1_InterestWithEthernetPadding), + "Error on write, expected %zu got %zd", + sizeof(metisTestDataV1_InterestWithEthernetPadding), nwritten); + + // wait for it to become available + struct pollfd pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = ether->etherSocket; + pfd.events = POLLIN | POLLERR; + + poll(&pfd, 1, 10); + + // Something is ready to read + + bool success; + + PARCEventBuffer *output = parcEventBuffer_Create(); + + success = metisGenericEther_ReadNextFrame(ether, output); + assertTrue(success, "Failed to read frame A"); + assertFrameEquals(metisTestDataV1_InterestWithEthernetPaddingStripped, output, sizeof(metisTestDataV1_InterestWithEthernetPaddingStripped)); + + close(localSocket); + + parcEventBuffer_Destroy(&output); + metisGenericEther_Release(ðer); +} + +LONGBOW_TEST_CASE(Global, metisGenericEther_SendFrame) +{ + char *interfaceName = getInterfaceName(); + uint16_t ethertype = 0x0801; + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisGenericEther *ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + + PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create(); + char dataBuffer[1024 * 1024]; + parcEventBuffer_Append(parcEventBuffer, dataBuffer, 16); + + bool result = metisGenericEther_SendFrame(ether, parcEventBuffer); + assertTrue(result, "metisGenericEther_Sendframe failed to send smallest packet"); + + parcEventBuffer_Append(parcEventBuffer, dataBuffer, 1024 * 1024); + + result = metisGenericEther_SendFrame(ether, parcEventBuffer); + assertFalse(result, "metisGenericEther_Sendframe should have failed to send packet larger than our MTU"); + + parcEventBuffer_Destroy(&parcEventBuffer); + + metisGenericEther_Release(ðer); + + free(interfaceName); +} + +// ================================================================== + +typedef struct test_data { + MetisGenericEther *ether; +} TestData; + +static void +commonSetup(const LongBowTestCase *testCase, const char *device, uint16_t ethertype) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + data->ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + + longBowTestCase_SetClipBoardData(testCase, data); +} + +static void +commonTeardown(const LongBowTestCase *testCase) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + metisGenericEther_Release(&data->ether); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _linuxEthernet_SetInterfaceIndex); + LONGBOW_RUN_TEST_CASE(Local, _linuxEthernet_SetInterfaceAddress); + LONGBOW_RUN_TEST_CASE(Local, _linuxEthernet_Bind); + LONGBOW_RUN_TEST_CASE(Local, _linuxEthernet_SetNonBlocking); + LONGBOW_RUN_TEST_CASE(Local, _linuxEthernet_SetupSocket); + LONGBOW_RUN_TEST_CASE(Local, _linuxEthernet_TrimBuffer_Length_OK); + LONGBOW_RUN_TEST_CASE(Local, _linuxEthernet_TrimBuffer_Length_Trim); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + commonSetup(testCase, interfaceName, 0x0801); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + commonTeardown(testCase); + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, _linuxEthernet_SetInterfaceIndex) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, _linuxEthernet_Bind) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, _linuxEthernet_SetNonBlocking) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, _linuxEthernet_SetupSocket) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, _linuxEthernet_SetInterfaceAddress) +{ + PARCBuffer *addr = NULL; + char ifname[1024]; + + // Lookup the MAC address of the interface we chose back in the fixture setup + struct ifaddrs *ifaddr; + int failure = getifaddrs(&ifaddr); + assertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno)); + + struct ifaddrs *next; + for (next = ifaddr; next != NULL && addr == NULL; next = next->ifa_next) { + if (strcmp(interfaceName, next->ifa_name) == 0) { + if (next->ifa_addr->sa_family == AF_PACKET) { + strcpy(ifname, next->ifa_name); + + struct sockaddr_ll *addr_ll = (struct sockaddr_ll *) next->ifa_addr; + + switch (addr_ll->sll_hatype) { + // list of the ARP hatypes we can extract a MAC address from + case ARPHRD_ETHER: + // fallthrough + case ARPHRD_IEEE802: { + addr = parcBuffer_Allocate(addr_ll->sll_halen); + parcBuffer_PutArray(addr, addr_ll->sll_halen, (uint8_t *) addr_ll->sll_addr); + parcBuffer_Flip(addr); + break; + } + default: + break; + } + } + } + } + freeifaddrs(ifaddr); + + if (addr) { + uint16_t ethertype = 0x0801; + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisGenericEther *ether = metisGenericEther_Create(metis, interfaceName, ethertype); + metisForwarder_Destroy(&metis); + + assertTrue(parcBuffer_Equals(addr, ether->macAddress), "Addresses do not match") + { + parcBuffer_Display(addr, 0); + parcBuffer_Display(ether->macAddress, 0); + } + + parcBuffer_Release(&addr); + metisGenericEther_Release(ðer); + } +} + +static void +trimBufferTest(const LongBowTestCase *testCase, size_t extraBytes) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + PARCEventBuffer *buffer = parcEventBuffer_Create(); + + PARCBuffer *frameBuffer = createInterestFrame(extraBytes); + size_t expectedSize = parcBuffer_Remaining(frameBuffer) - extraBytes; + + parcEventBuffer_Append(buffer, parcBuffer_Overlay(frameBuffer, 0), parcBuffer_Remaining(frameBuffer)); + + _linuxEthernet_TrimBuffer(data->ether, buffer); + + assertTrue(parcEventBuffer_GetLength(buffer) == expectedSize, + "Buffer incorrect size got %zu expected %zu", + parcEventBuffer_GetLength(buffer), expectedSize); + + parcBuffer_Release(&frameBuffer); + parcEventBuffer_Destroy(&buffer); +} + +LONGBOW_TEST_CASE(Local, _linuxEthernet_TrimBuffer_Length_OK) +{ + trimBufferTest(testCase, 0); +} + +LONGBOW_TEST_CASE(Local, _linuxEthernet_TrimBuffer_Length_Trim) +{ + trimBufferTest(testCase, 4); +} + + +// ================================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(linux_Ethernet); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/platforms/linux/test/test_metis_System.c b/metis/ccnx/forwarder/metis/platforms/linux/test/test_metis_System.c new file mode 100644 index 00000000..d65d2e2f --- /dev/null +++ b/metis/ccnx/forwarder/metis/platforms/linux/test/test_metis_System.c @@ -0,0 +1,148 @@ +/* + * 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. + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../metis_System.c" + +#include +#include +#include + +// Include the generic tests of MetisSystem +#include "../../test/testrig_metis_System.c" + +LONGBOW_TEST_RUNNER(linux_Interface) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + + // these are defined in testrig_metis_System.c + LONGBOW_RUN_TEST_FIXTURE(PublicApi); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(linux_Interface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(linux_Interface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisSystem_Interfaces); + LONGBOW_RUN_TEST_CASE(Global, metisSystem_InterfaceMTU); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisSystem_Interfaces) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + CPIInterfaceSet *set = metisSystem_Interfaces(metis); + assertNotNull(set, "metisSystem_Interfaces return null set"); + + // XXX we need some sort of validation test. e.g. open a socket, then ioctl to + // XXX get the interface name, then verify its in the list. + + size_t length = cpiInterfaceSet_Length(set); + assertTrue(length > 0, "metisSystem_Interfaces returned no interfaces"); + + for (size_t i = 0; i < length; i++) { + CPIInterface *iface = cpiInterfaceSet_GetByOrdinalIndex(set, i); + printf("Interface Index %u\n", cpiInterface_GetInterfaceIndex(iface)); + const CPIAddressList *list = cpiInterface_GetAddresses(iface); + PARCJSONArray *json = cpiAddressList_ToJson(list); + char *str = parcJSONArray_ToString(json); + printf("%s\n", str); + parcMemory_Deallocate((void **) &str); + parcJSONArray_Release(&json); + } + + cpiInterfaceSet_Destroy(&set); + metisForwarder_Destroy(&metis); +} + +// returns a strdup() of the interface name, use free(3) +static char * +_pickInterfaceName(MetisForwarder *metis) +{ + char *ifname = NULL; + + CPIInterfaceSet *set = metisSystem_Interfaces(metis); + size_t length = cpiInterfaceSet_Length(set); + assertTrue(length > 0, "metisSystem_Interfaces returned no interfaces"); + + for (size_t i = 0; i < length; i++) { + CPIInterface *iface = cpiInterfaceSet_GetByOrdinalIndex(set, i); + const CPIAddressList *addressList = cpiInterface_GetAddresses(iface); + + size_t length = cpiAddressList_Length(addressList); + for (size_t i = 0; i < length && !ifname; i++) { + const CPIAddress *a = cpiAddressList_GetItem(addressList, i); + if (cpiAddress_GetType(a) == cpiAddressType_LINK) { + ifname = strdup(cpiInterface_GetName(iface)); + } + } + } + + cpiInterfaceSet_Destroy(&set); + return ifname; +} + +LONGBOW_TEST_CASE(Global, metisSystem_InterfaceMTU) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + + char *deviceName = _pickInterfaceName(metis); + unsigned mtu = metisSystem_InterfaceMtu(metis, deviceName); + + assertTrue(mtu > 0, "Did not get mtu for interface %s", deviceName); + free(deviceName); + metisForwarder_Destroy(&metis); +} + +// ================================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(linux_Interface); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} -- cgit 1.2.3-korg