Skip to content
This repository was archived by the owner on Apr 13, 2019. It is now read-only.

Add support for "remove route" in Metis config/control #7

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 121 additions & 3 deletions ccnx/forwarder/metis/config/metisControl_RemoveRoute.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#include <LongBow/runtime.h>

Expand Down Expand Up @@ -92,18 +93,135 @@ metisControlRemoveRoute_HelpCreate(MetisControlState *state)
return metisCommandOps_Create(state, _commandRemoveRouteHelp, NULL, _metisControlRemoveRoute_HelpExecute, metisCommandOps_Destroy);
}

/**
* Return true if string is purely an integer
*/
static bool
_isNumber(const char *string)
{
size_t len = strlen(string);
for (size_t i = 0; i < len; i++) {
if (!isdigit(string[i])) {
return false;
}
}
return true;
}

/**
* A symbolic name must be at least 1 character and must begin with an alpha.
* The remainder must be an alphanum.
*/
static bool
_validateSymbolicName(const char *symbolic)
{
bool success = false;
size_t len = strlen(symbolic);
if (len > 0) {
if (isalpha(symbolic[0])) {
success = true;
for (size_t i = 1; i < len; i++) {
if (!isalnum(symbolic[i])) {
success = false;
break;
}
}
}
}
return success;
}

// ====================================================

static MetisCommandReturn
_metisControlRemoveRoute_HelpExecute(MetisCommandParser *parser, MetisCommandOps *ops, PARCList *args)
{
printf("%s help not implemented (case 149)", ops->command);
printf("commands:\n");
printf(" remove route <symbolic | connid> <prefix>\n");
printf("\n");
printf(" symbolic: The optional symbolic name for an exgress\n");
printf(" connid: The optional egress connection id (see 'help list connections')\n");
printf(" prefix: The CCNx name as a URI (e.g. lci:/foo/bar)\n");
printf("\n");
printf("Examples:\n");
printf(" remove route 25 lci:/foo/bar\n");
printf(" removes route to prefix '/foo/bar' on egress connection index 25\n");
printf(" remove route tun3 lci:/foo/bar\n");
printf(" removes route to prefix '/foo/bar' on egress connection 'tun3'\n");
printf("\n");

return MetisCommandReturn_Success;
}

static MetisCommandReturn
_metisControlRemoveRoute_Execute(MetisCommandParser *parser, MetisCommandOps *ops, PARCList *args)
{
printf("%s not implemented (case 149)", ops->command);
return MetisCommandReturn_Failure;
MetisControlState *state = ops->closure;

if (parcList_Size(args) != 4) {
_metisControlRemoveRoute_HelpExecute(parser, ops, args);
return MetisCommandReturn_Failure;
}

const char *symbolicOrConnid = parcList_GetAtIndex(args, 2);

if (_validateSymbolicName(symbolicOrConnid) || _isNumber(symbolicOrConnid)) {

const char *prefixString = parcList_GetAtIndex(args, 3);
CCNxName *prefix = ccnxName_CreateFromCString(prefixString);
if (prefix == NULL) {
printf("ERROR: could not parse prefix '%s'\n", prefixString);
return MetisCommandReturn_Failure;
}

char *protocolTypeAsString = "static";

CPINameRouteProtocolType protocolType = cpiNameRouteProtocolType_FromString(protocolTypeAsString);
CPINameRouteType routeType = cpiNameRouteType_LONGEST_MATCH;
CPIAddress *nexthop = NULL;

struct timeval *lifetime = NULL;

CPIRouteEntry *route = NULL;

if (_isNumber(symbolicOrConnid)) {
unsigned connid = (unsigned) strtold(symbolicOrConnid, NULL);
route = cpiRouteEntry_Create(prefix, connid, nexthop, protocolType, routeType, lifetime, 0);
} else {
route = cpiRouteEntry_CreateSymbolic(prefix, symbolicOrConnid, protocolType, routeType, lifetime, 0);
}

CCNxControl *addRouteRequest = ccnxControl_CreateRemoveRouteRequest(route);

cpiRouteEntry_Destroy(&route);

if (metisControlState_GetDebug(state)) {
char *str = parcJSON_ToString(ccnxControl_GetJson(addRouteRequest));
printf("request: %s\n", str);
parcMemory_Deallocate((void **) &str);
}

CCNxMetaMessage *message = ccnxMetaMessage_CreateFromControl(addRouteRequest);
CCNxMetaMessage *rawResponse = metisControlState_WriteRead(state, message);
ccnxMetaMessage_Release(&message);

ccnxControl_Release(&addRouteRequest);

CCNxControl *response = ccnxMetaMessage_GetControl(rawResponse);

if (metisControlState_GetDebug(state)) {
char *str = parcJSON_ToString(ccnxControl_GetJson(response));
printf("response: %s\n", str);
parcMemory_Deallocate((void **) &str);
}

ccnxMetaMessage_Release(&rawResponse);

return MetisCommandReturn_Success;
}
else {
printf("ERROR: Invalid symbolic or connid. Symbolic name must begin with an alpha followed by alphanum. connid must be an integer\n");
return MetisCommandReturn_Failure;
}

}
42 changes: 38 additions & 4 deletions ccnx/forwarder/metis/config/metis_Configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,18 +278,52 @@ metisConfiguration_ProcessRegisterPrefix(MetisConfiguration *config, CCNxControl
return response;
}

static bool
_symbolicUnregisterPrefix(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__,
"Remove route resolve name '%s' to connid %u",
symbolic, ifidx);
}

success = metisForwarder_RemoveRoute(config->metis, route);
} else {
if (metisLogger_IsLoggable(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning)) {
metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Warning, __func__,
"Remove route symbolic name '%s' could not be resolved", symbolic);
}
// this is a failure
}
return success;
}

static CCNxControl *
metisConfiguration_ProcessUnregisterPrefix(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
{
CPIRouteEntry *route = cpiForwarding_RouteFromControlMessage(control);

if (cpiRouteEntry_GetInterfaceIndex(route) == CPI_CURRENT_INTERFACE) {
// We want to use the ingress interface
cpiRouteEntry_SetInterfaceIndex(route, ingressId);
bool success = false;

// if it has a symbolic name set the interface index
if (cpiRouteEntry_GetSymbolicName(route) != NULL) {
success = _symbolicUnregisterPrefix(config, route);
} else {
if (cpiRouteEntry_GetInterfaceIndex(route) == CPI_CURRENT_INTERFACE) {
// We want to use the ingress interface
cpiRouteEntry_SetInterfaceIndex(route, ingressId);
}
success = metisForwarder_RemoveRoute(config->metis, route);
}

CCNxControl *response = NULL;
if (metisForwarder_RemoveRoute(config->metis, route)) {
if (success) {
response = _createAck(config, control, ingressId);
} else {
response = _createNack(config, control, ingressId);
Expand Down
47 changes: 43 additions & 4 deletions ccnx/forwarder/metis/config/test/test_metisControl_RemoveRoute.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,11 @@ LONGBOW_TEST_CASE(Global, metisControlRemoveRoute_Create)

LONGBOW_TEST_FIXTURE(Local)
{
LONGBOW_RUN_TEST_CASE(Local, metisControl_RemoveRoute_Execute_WrongArgCount);
LONGBOW_RUN_TEST_CASE(Local, metisControl_RemoveRoute_Execute_BadPrefix);
LONGBOW_RUN_TEST_CASE(Local, metisControl_RemoveRoute_Execute_Good);

LONGBOW_RUN_TEST_CASE(Local, metisControl_Help_RemoveRoute_Execute);
LONGBOW_RUN_TEST_CASE(Local, metisControl_RemoveRoute_Execute);
}

LONGBOW_TEST_FIXTURE_SETUP(Local)
Expand All @@ -137,15 +140,51 @@ LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
return LONGBOW_STATUS_SUCCEEDED;
}

static MetisCommandReturn
testRemoveRoute(const LongBowTestCase *testCase, int argc, const char *prefix, char *nexthop)
{
TestData *data = longBowTestCase_GetClipBoardData(testCase);
metisControlState_SetDebug(data->state, true);

const char *argv[] = { "remove", "route", nexthop, prefix };
PARCList *args = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
parcList_AddAll(args, argc, (void **) &argv[0]);

MetisCommandOps *ops = metisControlRemoveRoute_Create(data->state);

MetisCommandReturn result = ops->execute(data->state->parser, ops, args);
metisCommandOps_Destroy(&ops);
parcList_Release(&args);
return result;
}

LONGBOW_TEST_CASE(Local, metisControl_Help_RemoveRoute_Execute)
{
testHelpExecute(testCase, &metisControlRemoveRoute_HelpCreate, __func__, MetisCommandReturn_Success);
}

LONGBOW_TEST_CASE(Local, metisControl_RemoveRoute_Execute)
LONGBOW_TEST_CASE(Local, metisControl_RemoveRoute_Execute_WrongArgCount)
{
MetisCommandReturn result = testRemoveRoute(testCase, 3, "lci:/foo", "100");

assertTrue(result == MetisCommandReturn_Failure,
"metisControl_AddRoute with wrong argc should return %d, got %d", MetisCommandReturn_Failure, result);
}

LONGBOW_TEST_CASE(Local, metisControl_RemoveRoute_Execute_BadPrefix)
{
MetisCommandReturn result = testRemoveRoute(testCase, 4, "blah", "100");

assertTrue(result == MetisCommandReturn_Failure,
"metisControl_AddRoute with bad prefix should return %d, got %d", MetisCommandReturn_Failure, result);
}

LONGBOW_TEST_CASE(Local, metisControl_RemoveRoute_Execute_Good)
{
// Change to success once function implemented (case 157)
testHelpExecute(testCase, &metisControlRemoveRoute_Create, __func__, MetisCommandReturn_Failure);
MetisCommandReturn result = testRemoveRoute(testCase, 4, "lci:/foo", "100");

assertTrue(result == MetisCommandReturn_Success,
"metisControl_RemoveRoute should return %d, got %d", MetisCommandReturn_Success, result);
}

int
Expand Down
23 changes: 22 additions & 1 deletion ccnx/forwarder/metis/processor/metis_FIB.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
#include <parc/algol/parc_Memory.h>
#include <parc/algol/parc_TreeRedBlack.h>

#include <parc/concurrent/parc_RWLock.h>

#include <LongBow/runtime.h>

// =====================================================
Expand Down Expand Up @@ -110,6 +112,8 @@ struct metis_fib {
// KEY = tlvName, VALUE = FibEntry
PARCHashCodeTable *tableByName;

PARCRWLock *fibLock;

// KEY = tlvName. We use a tree for the keys because that
// has the same average insert and remove time. The tree
// is only used by GetEntries, which in turn is used by things
Expand Down Expand Up @@ -143,6 +147,8 @@ metisFIB_Create(MetisLogger *logger)
_hashTableFunction_FibEntryDestroyer,
initialSize);

fib->fibLock = parcRWLock_Create();

fib->tableOfKeys =
parcTreeRedBlack_Create(metisHashTableFunction_TlvNameCompare, NULL, NULL, NULL, NULL, NULL);

Expand Down Expand Up @@ -173,6 +179,7 @@ metisFIB_Destroy(MetisFIB **fibPtr)
metisLogger_Release(&fib->logger);
parcTreeRedBlack_Destroy(&fib->tableOfKeys);
parcHashCodeTable_Destroy(&fib->tableByName);
parcRWLock_Release(&fib->fibLock);
parcMemory_Deallocate((void **) &fib);
*fibPtr = NULL;
}
Expand All @@ -189,6 +196,7 @@ metisFIB_Match(MetisFIB *fib, const MetisMessage *interestMessage)
MetisFibEntry *longestMatchingFibEntry = NULL;

// because the FIB table is sparse, we need to scan all the name segments in order.
parcRWLock_ReadLock(fib->fibLock);
for (size_t i = 0; i < metisTlvName_SegmentCount(tlvName); i++) {
MetisTlvName *prefixName = metisTlvName_Slice(tlvName, i + 1);
MetisFibEntry *fibEntry = parcHashCodeTable_Get(fib->tableByName, prefixName);
Expand All @@ -203,6 +211,7 @@ metisFIB_Match(MetisFIB *fib, const MetisMessage *interestMessage)
}
metisTlvName_Release(&prefixName);
}
parcRWLock_Unlock(fib->fibLock);

if (longestMatchingFibEntry != NULL) {
// this returns a reference counted copy of the next hops
Expand All @@ -224,10 +233,12 @@ metisFIB_AddOrUpdate(MetisFIB *fib, CPIRouteEntry *route)
unsigned interfaceIndex = cpiRouteEntry_GetInterfaceIndex(route);
MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);

parcRWLock_WriteLock(fib->fibLock);
MetisFibEntry *fibEntry = parcHashCodeTable_Get(fib->tableByName, tlvName);
if (fibEntry == NULL) {
fibEntry = _metisFIB_CreateFibEntry(fib, tlvName);
}
parcRWLock_Unlock(fib->fibLock);

metisFibEntry_AddNexthop(fibEntry, interfaceIndex);

Expand All @@ -249,6 +260,7 @@ metisFIB_Remove(MetisFIB *fib, CPIRouteEntry *route)
unsigned interfaceIndex = cpiRouteEntry_GetInterfaceIndex(route);
MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);

parcRWLock_WriteLock(fib->fibLock);
MetisFibEntry *fibEntry = parcHashCodeTable_Get(fib->tableByName, tlvName);
if (fibEntry != NULL) {
metisFibEntry_RemoveNexthop(fibEntry, interfaceIndex);
Expand All @@ -261,6 +273,7 @@ metisFIB_Remove(MetisFIB *fib, CPIRouteEntry *route)
routeRemoved = true;
}
}
parcRWLock_Unlock(fib->fibLock);

metisTlvName_Release(&tlvName);
return routeRemoved;
Expand All @@ -270,7 +283,11 @@ size_t
metisFIB_Length(const MetisFIB *fib)
{
assertNotNull(fib, "Parameter fib must be non-null");
return parcHashCodeTable_Length(fib->tableByName);
size_t length;
parcRWLock_ReadLock(fib->fibLock);
length = parcHashCodeTable_Length(fib->tableByName);
parcRWLock_Unlock(fib->fibLock);
return length;
}

MetisFibEntryList *
Expand All @@ -279,11 +296,13 @@ metisFIB_GetEntries(const MetisFIB *fib)
assertNotNull(fib, "Parameter fib must be non-null");
MetisFibEntryList *list = metisFibEntryList_Create();

parcRWLock_ReadLock(fib->fibLock);
PARCArrayList *values = parcTreeRedBlack_Values(fib->tableOfKeys);
for (size_t i = 0; i < parcArrayList_Size(values); i++) {
MetisFibEntry *original = (MetisFibEntry *) parcArrayList_Get(values, i);
metisFibEntryList_Append(list, original);
}
parcRWLock_Unlock(fib->fibLock);
parcArrayList_Destroy(&values);
return list;
}
Expand All @@ -296,11 +315,13 @@ metisFIB_RemoveConnectionIdFromRoutes(MetisFIB *fib, unsigned connectionId)
// NB: This is very inefficient. We need a reverse-index from connectionId to FibEntry (case 814)

// Walk the entire tree and remove the connection id from every entry.
parcRWLock_WriteLock(fib->fibLock);
PARCArrayList *values = parcTreeRedBlack_Values(fib->tableOfKeys);
for (size_t i = 0; i < parcArrayList_Size(values); i++) {
MetisFibEntry *original = (MetisFibEntry *) parcArrayList_Get(values, i);
metisFibEntry_RemoveNexthop(original, connectionId);
}
parcRWLock_Unlock(fib->fibLock);
parcArrayList_Destroy(&values);
}

Expand Down
Loading