aboutsummaryrefslogtreecommitdiffstats
path: root/metis/ccnx/forwarder/metis/config/metis_Configuration.c
diff options
context:
space:
mode:
Diffstat (limited to 'metis/ccnx/forwarder/metis/config/metis_Configuration.c')
-rw-r--r--metis/ccnx/forwarder/metis/config/metis_Configuration.c936
1 files changed, 936 insertions, 0 deletions
diff --git a/metis/ccnx/forwarder/metis/config/metis_Configuration.c b/metis/ccnx/forwarder/metis/config/metis_Configuration.c
new file mode 100644
index 00000000..3703c6ef
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/config/metis_Configuration.c
@@ -0,0 +1,936 @@
+/*
+ * 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.
+ */
+
+/**
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_String.h>
+
+#include <ccnx/api/control/cpi_InterfaceSet.h>
+#include <ccnx/api/control/cpi_ConnectionEthernet.h>
+#include <ccnx/api/control/cpi_Listener.h>
+#include <ccnx/api/control/controlPlaneInterface.h>
+#include <ccnx/api/control/cpi_InterfaceIPTunnel.h>
+#include <ccnx/api/control/cpi_InterfaceIPTunnelList.h>
+#include <ccnx/api/control/cpi_ForwardingStrategy.h>
+
+#include <ccnx/forwarder/metis/config/metis_CommandLineInterface.h>
+#include <ccnx/forwarder/metis/config/metis_SymbolicNameTable.h>
+#include <ccnx/forwarder/metis/config/metis_ConfigurationListeners.h>
+
+#include <ccnx/forwarder/metis/core/metis_Forwarder.h>
+#include <ccnx/forwarder/metis/core/metis_System.h>
+#include <ccnx/forwarder/metis/core/metis_ConnectionTable.h>
+#include <ccnx/forwarder/metis/core/metis_Connection.h>
+
+#include <ccnx/forwarder/metis/io/metis_TcpTunnel.h>
+#include <ccnx/forwarder/metis/io/metis_UdpTunnel.h>
+#include <ccnx/forwarder/metis/io/metis_UdpConnection.h>
+#include <ccnx/forwarder/metis/io/metis_EtherListener.h>
+#include <ccnx/forwarder/metis/io/metis_EtherConnection.h>
+
+#include <ccnx/forwarder/metis/metis_About.h>
+
+#define ETHERTYPE 0x0801
+
+struct metis_configuration {
+ MetisForwarder *metis;
+ MetisLogger *logger;
+ MetisCommandLineInterface *cli;
+
+ size_t maximumContentObjectStoreSize;
+
+ // map from prefix to strategy
+ PARCHashMap *strategy_map;
+
+ // translates between a symblic name and a connection id
+ MetisSymbolicNameTable *symbolicNameTable;
+};
+
+
+// ========================================================================================
+
+MetisConfiguration *
+metisConfiguration_Create(MetisForwarder *metis)
+{
+ assertNotNull(metis, "Parameter metis must be non-null");
+ MetisConfiguration *config = parcMemory_AllocateAndClear(sizeof(MetisConfiguration));
+ assertNotNull(config, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MetisConfiguration));
+ config->metis = metis;
+ config->logger = metisLogger_Acquire(metisForwarder_GetLogger(metis));
+ config->cli = NULL;
+ config->maximumContentObjectStoreSize = 100000;
+ config->strategy_map = parcHashMap_Create();
+ config->symbolicNameTable = metisSymbolicNameTable_Create();
+
+ return config;
+}
+
+void
+metisConfiguration_Destroy(MetisConfiguration **configPtr)
+{
+ assertNotNull(configPtr, "Parameter must be non-null double poitner");
+ assertNotNull(*configPtr, "Parameter must dereference to non-null pointer");
+
+ MetisConfiguration *config = *configPtr;
+ metisLogger_Release(&config->logger);
+ if (config->cli != NULL) {
+ metisCommandLineInterface_Destroy(&config->cli);
+ }
+ parcHashMap_Release(&(config->strategy_map));
+ metisSymbolicNameTable_Destroy(&config->symbolicNameTable);
+ parcMemory_Deallocate((void **) &config);
+ *configPtr = NULL;
+}
+
+void
+metisConfiguration_StartCLI(MetisConfiguration *config, uint16_t port)
+{
+ assertNull(config->cli, "You cannot start more than one CLI");
+ config->cli = metisCommandLineInterface_Create(config->metis, port);
+ metisCommandLineInterface_Start(config->cli);
+}
+
+PARCJSON *
+metisConfiguration_GetVersion(MetisConfiguration *config)
+{
+ PARCJSON *fwd = parcJSON_Create();
+ parcJSON_AddString(fwd, "NAME", metisAbout_Name());
+ parcJSON_AddString(fwd, "COPYRIGHT", metisAbout_MiniNotice());
+ parcJSON_AddString(fwd, "VERSION", metisAbout_Version());
+ return fwd;
+}
+
+static void
+metisConfiguration_SendResponse(MetisConfiguration *config, CCNxControl *response, unsigned egressId)
+{
+ PARCBuffer *responseBuffer = metisTlv_EncodeControlPlaneInformation(response);
+ MetisMessage *tlvEncodedResponse = metisMessage_CreateFromParcBuffer(responseBuffer, 0, metisForwarder_GetTicks(config->metis), metisForwarder_GetLogger(config->metis));
+
+ parcBuffer_Release(&responseBuffer);
+
+ MetisConnectionTable *connectionTable = metisForwarder_GetConnectionTable(config->metis);
+ const MetisConnection *conn = metisConnectionTable_FindById(connectionTable, egressId);
+ assertNotNull(conn, "Got null connection for control message we just received");
+
+ metisConnection_Send(conn, tlvEncodedResponse);
+ metisMessage_Release(&tlvEncodedResponse);
+}
+
+static CCNxControl *
+_createNack(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ PARCJSON *json = ccnxControl_GetJson(control);
+
+ PARCJSON *jsonNack = cpiAcks_CreateNack(json);
+
+ CCNxControl *response = ccnxControl_CreateCPIRequest(jsonNack);
+ parcJSON_Release(&jsonNack);
+ return response;
+}
+
+static CCNxControl *
+_createAck(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ PARCJSON *json = ccnxControl_GetJson(control);
+ PARCJSON *jsonAck = cpiAcks_CreateAck(json);
+
+ CCNxControl *response = ccnxControl_CreateCPIRequest(jsonAck);
+ parcJSON_Release(&jsonAck);
+ return response;
+}
+
+
+static CCNxControl *
+metisConfiguration_ProcessForwarderVersion(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ PARCJSON *fwd = metisConfiguration_GetVersion(config);
+
+ // this process of getting to a MetisMesage needs streamlining
+
+ CCNxControl *response = cpi_CreateResponse(request, fwd);
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessInterfaceList(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ CPIInterfaceSet *set = metisSystem_Interfaces(config->metis);
+ PARCJSON *setJson = cpiInterfaceSet_ToJson(set);
+
+ CCNxControl *response = cpi_CreateResponse(request, setJson);
+ parcJSON_Release(&setJson);
+ cpiInterfaceSet_Destroy(&set);
+ return response;
+}
+
+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;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessRegisterPrefix(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ CPIRouteEntry *route = cpiForwarding_RouteFromControlMessage(control);
+
+ bool success = false;
+
+ // if it has a symbolic name set the interface index
+ if (cpiRouteEntry_GetSymbolicName(route) != NULL) {
+ success = _symbolicRegisterPrefix(config, route);
+ } else {
+ if (cpiRouteEntry_GetInterfaceIndex(route) == CPI_CURRENT_INTERFACE) {
+ // We want to use the ingress interface
+ cpiRouteEntry_SetInterfaceIndex(route, ingressId);
+ }
+ success = metisForwarder_AddOrUpdateRoute(config->metis, route);
+ }
+
+ CCNxControl *response;
+ if (success) {
+ response = _createAck(config, control, ingressId);
+ } else {
+ response = _createNack(config, control, ingressId);
+ }
+
+ cpiRouteEntry_Destroy(&route);
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessUnregisterPrefix(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ CPIRouteEntry *route = cpiForwarding_RouteFromControlMessage(control);
+
+ bool success = false;
+
+ if (cpiRouteEntry_GetSymbolicName(route) != NULL) {
+ const char *symbolic = cpiRouteEntry_GetSymbolicName(route);
+ unsigned ifidx = metisSymbolicNameTable_Get(config->symbolicNameTable, symbolic);
+ if (ifidx != UINT32_MAX) {
+ cpiRouteEntry_SetInterfaceIndex(route, ifidx);
+ success = metisForwarder_RemoveRoute(config->metis, route);
+ } else {
+ // this is a failure
+ success = false;
+ }
+ } 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;
+ if (success) {
+ response = _createAck(config, control, ingressId);
+ } else {
+ response = _createNack(config, control, ingressId);
+ }
+
+ cpiRouteEntry_Destroy(&route);
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessRegistrationList(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ MetisFibEntryList *fibList = metisForwarder_GetFibEntries(config->metis);
+
+ CPIRouteEntryList *routeEntryList = cpiRouteEntryList_Create();
+ for (size_t i = 0; i < metisFibEntryList_Length(fibList); i++) {
+ const MetisFibEntry *fibEntry = metisFibEntryList_Get(fibList, i);
+ MetisTlvName *prefix = metisFibEntry_GetPrefix(fibEntry);
+ const MetisNumberSet *nexthops = metisFibEntry_GetNexthops(fibEntry);
+
+ for (int j = 0; j < metisNumberSet_Length(nexthops); j++) {
+ CPIRouteEntry *route = cpiRouteEntry_Create(metisTlvName_ToCCNxName(prefix),
+ metisNumberSet_GetItem(nexthops, j),
+ NULL,
+ cpiNameRouteProtocolType_STATIC,
+ cpiNameRouteType_LONGEST_MATCH,
+ NULL, // lifetime
+ 1); // cost
+ cpiRouteEntryList_Append(routeEntryList, route);
+ }
+
+ metisTlvName_Release(&prefix);
+ }
+ PARCJSON *entryListJson = cpiRouteEntryList_ToJson(routeEntryList);
+ CCNxControl *response = cpi_CreateResponse(request, entryListJson);
+ parcJSON_Release(&entryListJson);
+ cpiRouteEntryList_Destroy(&routeEntryList);
+ metisFibEntryList_Destroy(&fibList);
+ return response;
+}
+
+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);
+ }
+}
+
+/**
+ * Add an IP-based tunnel.
+ *
+ * The call cal fail if the symbolic name is a duplicate. It could also fail if there's an problem creating
+ * the local side of the tunnel (i.e. the local socket address is not usable).
+ *
+ * @return true Tunnel added
+ * @return false Tunnel not added (an error)
+ */
+static CCNxControl *
+metisConfiguration_ProcessCreateTunnel(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ bool success = false;
+
+ CPIInterfaceIPTunnel *iptun = cpiLinks_CreateIPTunnelFromControlMessage(control);
+
+ const char *symbolicName = cpiInterfaceIPTunnel_GetSymbolicName(iptun);
+
+ if (!metisSymbolicNameTable_Exists(config->symbolicNameTable, symbolicName)) {
+ const CPIAddress *source = cpiInterfaceIPTunnel_GetSourceAddress(iptun);
+ const CPIAddress *destination = cpiInterfaceIPTunnel_GetDestinationAddress(iptun);
+
+ MetisIoOperations *ops = NULL;
+ switch (cpiInterfaceIPTunnel_GetTunnelType(iptun)) {
+ case IPTUN_TCP:
+ ops = metisTcpTunnel_Create(config->metis, source, destination);
+ break;
+ case IPTUN_UDP:
+ ops = metisUdpTunnel_Create(config->metis, source, destination);
+ break;
+ case IPTUN_GRE:
+ metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
+ "Unsupported tunnel protocol: GRE");
+ break;
+ default:
+ metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
+ "Unsupported tunnel protocol: %d",
+ cpiInterfaceIPTunnel_GetTunnelType(iptun));
+ break;
+ }
+
+
+ if (ops != NULL) {
+ MetisConnection *conn = metisConnection_Create(ops);
+
+ const char *suffix = "wldr";
+ size_t suffix_len = 4;
+ size_t name_len = strlen(symbolicName);
+ if (suffix_len < name_len && (strncmp(symbolicName + name_len - suffix_len, suffix, suffix_len) == 0)) {
+ printf("WARNING: WLDR initialized with legacy code. please use the command set wldr <on|off> <connId>\n");
+ printf("see metis_control help for more information\n");
+ metisConnection_EnableWldr(conn);
+ }
+
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(config->metis), conn);
+ metisSymbolicNameTable_Add(config->symbolicNameTable, symbolicName, metisConnection_GetConnectionId(conn));
+
+ success = true;
+
+ _logProcessCreateTunnelMessage(config, iptun, PARCLogLevel_Info, "success");
+ } else {
+ _logProcessCreateTunnelMessage(config, iptun, PARCLogLevel_Warning, "failed, could not create IoOperations");
+ }
+ } else {
+ _logProcessCreateTunnelMessage(config, iptun, PARCLogLevel_Warning, "failed, symbolic name exists");
+ }
+
+ // send the ACK or NACK
+ CCNxControl *response;
+ if (success) {
+ response = _createAck(config, control, ingressId);
+ } else {
+ response = _createNack(config, control, ingressId);
+ }
+
+ cpiInterfaceIPTunnel_Release(&iptun);
+
+ return response;
+}
+
+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 CCNxControl *
+metisConfiguration_ProcessAddConnectionEthernet(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ bool success = false;
+
+ CPIConnectionEthernet *etherConn = cpiConnectionEthernet_FromControl(control);
+ assertNotNull(etherConn, "Control message did not parse to CPIConnectionEthernet");
+
+ if (cpiConnectionEthernet_GetEthertype(etherConn) == ETHERTYPE) {
+ CPIAddress *linkAddress = metisSystem_GetMacAddressByName(config->metis, cpiConnectionEthernet_GetInterfaceName(etherConn));
+ if (linkAddress != NULL) {
+ MetisListenerSet *listenerSet = metisForwarder_GetListenerSet(config->metis);
+ MetisListenerOps *listenerOps = metisListenerSet_Find(listenerSet, METIS_ENCAP_ETHER, linkAddress);
+
+ if (listenerOps) {
+ // Now add the connection
+ success = _metisConfiguration_AddConnectionEthernet(config, etherConn, linkAddress, listenerOps);
+ } else {
+ char *str = cpiAddress_ToString(linkAddress);
+ metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
+ "Could not find listener for interface '%s' addr %s ethertype 0x%04x",
+ cpiConnectionEthernet_GetInterfaceName(etherConn),
+ str,
+ cpiConnectionEthernet_GetEthertype(etherConn));
+ parcMemory_Deallocate((void **) &str);
+ }
+
+
+ cpiAddress_Destroy(&linkAddress);
+ } else {
+ metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
+ "Could not resolve interface '%s' to a MAC address",
+ cpiConnectionEthernet_GetInterfaceName(etherConn));
+ }
+ } else {
+ metisLogger_Log(config->logger, MetisLoggerFacility_Config, PARCLogLevel_Error, __func__,
+ "Control message asked for ethertype %04x, only %04x supported",
+ cpiConnectionEthernet_GetEthertype(etherConn), ETHERTYPE);
+ }
+
+ CCNxControl *response;
+ if (success) {
+ response = _createAck(config, control, ingressId);
+ } else {
+ response = _createNack(config, control, ingressId);
+ }
+
+ cpiConnectionEthernet_Release(&etherConn);
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessRemoveConnectionEthernet(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ printf("%s not implemented\n", __func__);
+ return _createNack(config, control, ingressId);
+}
+
+
+static CCNxControl *
+metisConfiguration_ProcessRemoveTunnel(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ CPIInterfaceIPTunnel *iptun = cpiLinks_CreateIPTunnelFromControlMessage(control);
+ const char *symbolic = cpiInterfaceIPTunnel_GetSymbolicName(iptun);
+ unsigned ifidx = metisSymbolicNameTable_Get(config->symbolicNameTable, symbolic);
+ if (ifidx != UINT32_MAX) {
+ //remove connection from the FIB
+ metisForwarder_RemoveConnectionIdFromRoutes(config->metis, ifidx);
+ MetisConnectionTable *table = metisForwarder_GetConnectionTable(config->metis);
+ //remove connection from connection table
+ metisConnectionTable_RemoveById(table, ifidx);
+ //remove connection from symbolicNameTable
+ metisSymbolicNameTable_Remove(config->symbolicNameTable, symbolic);
+ //and ... this is it!
+ CCNxControl *response = _createAck(config, control, ingressId);
+ cpiInterfaceIPTunnel_Release(&iptun);
+ return response;
+ } else {
+ CCNxControl *response = _createNack(config, control, ingressId);
+ cpiInterfaceIPTunnel_Release(&iptun);
+ return response;
+ }
+}
+
+static CCNxControl *
+metisConfiguration_ProcessConnectionList(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ CPIConnectionList *tunnelList = cpiConnectionList_Create();
+
+ MetisConnectionTable *table = metisForwarder_GetConnectionTable(config->metis);
+ MetisConnectionList *connList = metisConnectionTable_GetEntries(table);
+
+ for (size_t i = 0; i < metisConnectionList_Length(connList); i++) {
+ // Don't release original, we're not storing it
+ MetisConnection *original = metisConnectionList_Get(connList, i);
+ const MetisAddressPair *addressPair = metisConnection_GetAddressPair(original);
+ CPIAddress *localAddress = cpiAddress_Copy(metisAddressPair_GetLocal(addressPair));
+ CPIAddress *remoteAddress = cpiAddress_Copy(metisAddressPair_GetRemote(addressPair));
+
+ CPIConnectionType type = metisIoOperations_GetConnectionType(metisConnection_GetIoOperations(original));
+
+ CPIConnection *cpiConn = cpiConnection_Create(metisConnection_GetConnectionId(original),
+ localAddress,
+ remoteAddress,
+ type);
+
+ cpiConnection_SetState(cpiConn, metisConnection_IsUp(original) ? CPI_IFACE_UP : CPI_IFACE_DOWN);
+ cpiConnectionList_Append(tunnelList, cpiConn);
+ }
+
+ PARCJSON *connectListJson = cpiConnectionList_ToJson(tunnelList);
+ CCNxControl *response = cpi_CreateResponse(request, connectListJson);
+ parcJSON_Release(&connectListJson);
+ cpiConnectionList_Destroy(&tunnelList);
+ metisConnectionList_Destroy(&connList);
+
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessCacheStoreOn(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ bool success = false;
+
+ metisForwarder_SetChacheStoreFlag(config->metis, true);
+ if (metisForwarder_GetChacheStoreFlag(config->metis)) {
+ success = true;
+ }
+
+ CCNxControl *response;
+ if (success) {
+ response = _createAck(config, request, ingressId);
+ } else {
+ response = _createNack(config, request, ingressId);
+ }
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessCacheStoreOff(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ bool success = false;
+
+ metisForwarder_SetChacheStoreFlag(config->metis, false);
+ if (!metisForwarder_GetChacheStoreFlag(config->metis)) {
+ success = true;
+ }
+
+ CCNxControl *response;
+ if (success) {
+ response = _createAck(config, request, ingressId);
+ } else {
+ response = _createNack(config, request, ingressId);
+ }
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessCacheServeOn(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ bool success = true;
+
+ metisForwarder_SetChacheServeFlag(config->metis, true);
+ if (metisForwarder_GetChacheServeFlag(config->metis)) {
+ success = true;
+ }
+
+ CCNxControl *response;
+ if (success) {
+ response = _createAck(config, request, ingressId);
+ } else {
+ response = _createNack(config, request, ingressId);
+ }
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessCacheServeOff(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ bool success = true;
+
+ metisForwarder_SetChacheServeFlag(config->metis, false);
+ if (!metisForwarder_GetChacheServeFlag(config->metis)) {
+ success = true;
+ }
+
+
+ CCNxControl *response;
+ if (success) {
+ response = _createAck(config, request, ingressId);
+ } else {
+ response = _createNack(config, request, ingressId);
+ }
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_ProcessCacheClear(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ metisForwarder_ClearCache(config->metis);
+
+ CCNxControl *response = _createAck(config, request, ingressId);
+
+ return response;
+}
+
+
+size_t
+metisConfiguration_GetObjectStoreSize(MetisConfiguration *config)
+{
+ return config->maximumContentObjectStoreSize;
+}
+
+static CCNxControl *
+metisConfiguration_SetForwarginStrategy(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ CPIForwardingStrategy *fwdStrategy = cpiForwarding_ForwardingStrategyFromControlMessage(request);
+
+ const CCNxName *prefix = cpiForwardingStrategy_GetPrefix(fwdStrategy);
+ const char *strategy = cpiForwardingStrategy_GetStrategy(fwdStrategy);
+ const char *existingFwdStrategy = metisConfiguration_GetForwarginStrategy(config, prefix);
+
+ if ((existingFwdStrategy == NULL) || (strcmp(strategy, existingFwdStrategy) != 0)) {
+ PARCString *fwdStrategy = parcString_Create(strategy);
+ parcHashMap_Put(config->strategy_map, prefix, fwdStrategy);
+ metisForwarder_SetStrategy(config->metis, (CCNxName *) prefix, (char *) strategy);
+ }
+
+ cpiForwardingStrategy_Destroy(&fwdStrategy);
+ CCNxControl *response = _createAck(config, request, ingressId);
+ return response;
+}
+
+static CCNxControl *
+metisConfiguration_SetWldr(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ CPIManageWldr *cpiWldr = cpiLinks_ManageWldrFromControlMessage(request);
+
+ const char * connId = cpiManageWldr_GetConnection(cpiWldr);
+ bool active = cpiManageWldr_IsActive(cpiWldr);
+
+ bool success = false;
+ unsigned ifidx = metisSymbolicNameTable_Get(config->symbolicNameTable, connId);
+ if (ifidx != UINT32_MAX) {
+ MetisConnectionTable *table = metisForwarder_GetConnectionTable(config->metis);
+ MetisConnection *conn = (MetisConnection *) metisConnectionTable_FindById(table, ifidx);
+ if(conn == NULL){
+ success = false;
+ } else {
+ if(active){
+ metisConnection_EnableWldr(conn);
+ } else {
+ metisConnection_DisableWldr(conn);
+ }
+ success = true;
+ }
+ } else {
+ success = false;
+ }
+
+ CCNxControl *response;
+ if(success){
+ response = _createAck(config, request, ingressId);
+ } else {
+ response = _createNack(config, request, ingressId);
+ }
+
+ cpiManageWldr_Destroy(&cpiWldr);
+ return response;
+}
+
+const char *
+metisConfiguration_GetForwarginStrategy(MetisConfiguration *config, const CCNxName *prefix)
+{
+ const PARCString *val = parcHashMap_Get(config->strategy_map, prefix);
+ if (val == NULL) {
+ return NULL;
+ } else {
+ return (const char *) parcString_ToString(val);
+ }
+}
+
+void
+metisConfiguration_SetObjectStoreSize(MetisConfiguration *config, size_t maximumObjectCount)
+{
+ config->maximumContentObjectStoreSize = maximumObjectCount;
+
+ metisForwarder_SetContentObjectStoreSize(config->metis, config->maximumContentObjectStoreSize);
+}
+
+MetisForwarder *
+metisConfiguration_GetForwarder(const MetisConfiguration *config)
+{
+ return config->metis;
+}
+
+MetisLogger *
+metisConfiguration_GetLogger(const MetisConfiguration *config)
+{
+ return config->logger;
+}
+
+// ===========================
+// Main functions that deal with receiving commands, executing them, and sending ACK/NACK
+
+static CCNxControl *
+metisConfiguration_DispatchCommandOldStyle(MetisConfiguration *config, CCNxControl *control, unsigned ingressId)
+{
+ CCNxControl *response = NULL;
+ switch (cpi_GetMessageOperation(control)) {
+ case CPI_FORWARDER_VERSION:
+ response = metisConfiguration_ProcessForwarderVersion(config, control, ingressId);
+ break;
+
+ case CPI_INTERFACE_LIST:
+ response = metisConfiguration_ProcessInterfaceList(config, control, ingressId);
+ break;
+
+ case CPI_PREFIX_REGISTRATION_LIST:
+ response = metisConfiguration_ProcessRegistrationList(config, control, ingressId);
+ break;
+
+ case CPI_REGISTER_PREFIX:
+ response = metisConfiguration_ProcessRegisterPrefix(config, control, ingressId);
+ break;
+
+ case CPI_UNREGISTER_PREFIX:
+ response = metisConfiguration_ProcessUnregisterPrefix(config, control, ingressId);
+ break;
+
+ case CPI_CREATE_TUNNEL:
+ response = metisConfiguration_ProcessCreateTunnel(config, control, ingressId);
+ break;
+
+ case CPI_REMOVE_TUNNEL:
+ response = metisConfiguration_ProcessRemoveTunnel(config, control, ingressId);
+ break;
+
+ case CPI_CONNECTION_LIST:
+ response = metisConfiguration_ProcessConnectionList(config, control, ingressId);
+ break;
+
+ case CPI_PAUSE:
+ break;
+
+ case CPI_CACHE_STORE_ON:
+ response = metisConfiguration_ProcessCacheStoreOn(config, control, ingressId);
+ break;
+
+ case CPI_CACHE_STORE_OFF:
+ response = metisConfiguration_ProcessCacheStoreOff(config, control, ingressId);
+ break;
+
+ case CPI_CACHE_SERVE_ON:
+ response = metisConfiguration_ProcessCacheServeOn(config, control, ingressId);
+ break;
+
+ case CPI_CACHE_SERVE_OFF:
+ response = metisConfiguration_ProcessCacheServeOff(config, control, ingressId);
+ break;
+
+ case CPI_CACHE_CLEAR:
+ response = metisConfiguration_ProcessCacheClear(config, control, ingressId);
+ break;
+
+ case CPI_SET_FORWARDING_STRATEGY:
+ response = metisConfiguration_SetForwarginStrategy(config, control, ingressId);
+ break;
+
+ case CPI_SET_WLDR:
+ response = metisConfiguration_SetWldr(config, control, ingressId);
+ break;
+
+ default:
+ break;
+ }
+
+ return response;
+}
+
+static CCNxControl *
+_processControl(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ CCNxControl *response = NULL;
+
+ switch (cpi_GetMessageType(request)) {
+ case CPI_REQUEST: {
+ if (cpiConnectionEthernet_IsAddMessage(request)) {
+ response = metisConfiguration_ProcessAddConnectionEthernet(config, request, ingressId);
+ } else if (cpiConnectionEthernet_IsRemoveMessage(request)) {
+ response = metisConfiguration_ProcessRemoveConnectionEthernet(config, request, ingressId);
+ } else if (cpiListener_IsAddMessage(request)) {
+ bool success = metisConfigurationListeners_Add(config, request, ingressId);
+ if (success) {
+ response = _createAck(config, request, ingressId);
+ } else {
+ response = _createNack(config, request, ingressId);
+ }
+ } else if (cpiListener_IsRemoveMessage(request)) {
+ bool success = metisConfigurationListeners_Remove(config, request, ingressId);
+ if (success) {
+ response = _createAck(config, request, ingressId);
+ } else {
+ response = _createNack(config, request, ingressId);
+ }
+ } else {
+ response = metisConfiguration_DispatchCommandOldStyle(config, request, ingressId);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ assertNotNull(response, "Got null CCNxControl response");
+ return response;
+}
+
+CCNxControl *
+metisConfiguration_ReceiveControl(MetisConfiguration *config, CCNxControl *request, unsigned ingressId)
+{
+ assertNotNull(config, "Parameter config must be non-null");
+ assertNotNull(request, "Parameter request must be non-null");
+
+ CCNxControl *response = _processControl(config, request, ingressId);
+ return response;
+}
+
+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);
+}
+
+