summaryrefslogtreecommitdiffstats
path: root/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c
diff options
context:
space:
mode:
Diffstat (limited to 'libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c')
-rw-r--r--libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c449
1 files changed, 449 insertions, 0 deletions
diff --git a/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c b/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c
new file mode 100644
index 00000000..469acd02
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/api/control/controlPlaneInterface.c
@@ -0,0 +1,449 @@
+/*
+ * 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.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * <#Abstract#>
+ *
+ * <#Discussion#>
+ *
+ * @author Marc Mosko
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+/**
+ * These comments describe the implementation of the protocol described in the header file.
+ *
+ * A Control Plane Information (CPI) message is a JSON object of this form:
+ * {
+ * "CPI_REQUEST" | "CPI_RESPONSE" :
+ * { "SEQUENCE" : <sequence number>,
+ * <operation> : <contents>
+ * }
+ * ["AUTHENTICATOR" : <TBD proof based on request/response, e.g. a crypto signature>]
+ * }
+ *
+ * {
+ * "CPI_ACK" :
+ * { "SEQUENCE" : <sequence number>,
+ * "RETURN" : "ACK" or "NACK",
+ * "REQUEST" : <original request JSON>
+ * [, "MESSAGE" : <optional message> ]
+ * }
+ * ["AUTHENTICATOR" : <TBD proof based on request/response, e.g. a crypto signature>]
+ * }
+ *
+ *
+ * { "REGISTER" :
+ * { "PREFIX" : <name URI string>,
+ * "INTERFACE" : <integer>,
+ * "FLAGS" : <integer>
+ * [, "LIFETIME" : [seconds, micro_seconds] ]
+ * }
+ * }
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include "controlPlaneInterface.h"
+#include "cpi_private.h"
+#include "cpi_NameRouteProtocolType.h"
+#include "cpi_Acks.h"
+#include <ccnx/api/control/cpi_ConnectionEthernet.h>
+
+static const char *cpiRequest = "CPI_REQUEST";
+static const char *cpiResponse = "CPI_RESPONSE";
+static const char *cpiPause = "CPI_PAUSE";
+static const char *cpiFlush = "CPI_FLUSH";
+
+// This is the unique sequence number used by all messages and its thread locks
+static pthread_mutex_t cpiNextSequenceNumberMutex = PTHREAD_MUTEX_INITIALIZER;
+static uint64_t cpiNextSequenceNumber = 1;
+
+const char *
+cpiRequest_GetJsonTag()
+{
+ return cpiRequest;
+}
+
+const char *
+cpiResponse_GetJsonTag()
+{
+ return cpiResponse;
+}
+
+const char *
+cpiSequence_GetJSONTag()
+{
+ return cpiSeqnum;
+}
+
+uint64_t
+cpi_GetNextSequenceNumber(void)
+{
+ uint64_t seqnum;
+
+ int result = pthread_mutex_lock(&cpiNextSequenceNumberMutex);
+ assertTrue(result == 0, "Got error from pthread_mutex_lock: %d", result);
+
+ seqnum = cpiNextSequenceNumber++;
+
+ result = pthread_mutex_unlock(&cpiNextSequenceNumberMutex);
+ assertTrue(result == 0, "Got error from pthread_mutex_unlock: %d", result);
+
+ return seqnum;
+}
+
+CpiOperation
+cpi_getCPIOperation2(const PARCJSON *json)
+{
+ PARCJSONValue *cpi_value = parcJSON_GetValueByName(json, cpiRequest);
+
+ if (cpi_value == NULL) {
+ cpi_value = parcJSON_GetValueByName(json, cpiResponse);
+ }
+ assertNotNull(cpi_value, "Could not get Request or response");
+
+ PARCJSON *cpi_json = parcJSONValue_GetJSON(cpi_value);
+
+ /*
+ * The JSON is defined as { REQUEST : { SEQUENCE: xxx, <OPERATION>: xxx } }
+ * so we want to get the key of the 2nd item (index 1) of the array of objects
+ * under the request
+ */
+
+ PARCJSONPair *item1Pair = parcJSON_GetPairByIndex(cpi_json, 1);
+ PARCBuffer *name = parcJSONPair_GetName(item1Pair);
+ const char *p = parcBuffer_Overlay(name, 0);
+
+ if (strncasecmp(p, cpiForwarding_AddRouteJsonTag(), strlen(cpiForwarding_AddRouteJsonTag())) == 0) {
+ return CPI_REGISTER_PREFIX;
+ }
+
+ if (strncasecmp(p, cpiForwarding_RemoveRouteJsonTag(), strlen(cpiForwarding_RemoveRouteJsonTag())) == 0) {
+ return CPI_UNREGISTER_PREFIX;
+ }
+
+ if (strncasecmp(p, cpiPause, strlen(cpiPause)) == 0) {
+ return CPI_PAUSE;
+ }
+
+ if (strncasecmp(p, cpiFlush, strlen(cpiFlush)) == 0) {
+ return CPI_FLUSH;
+ }
+
+ if (strncasecmp(p, cpiCancelFlow_CancelFlowJsonTag(), strlen(cpiCancelFlow_CancelFlowJsonTag())) == 0) {
+ return CPI_CANCEL_FLOW;
+ }
+
+ if (strncasecmp(p, cpiLinks_InterfaceListJsonTag(), strlen(cpiLinks_InterfaceListJsonTag())) == 0) {
+ return CPI_INTERFACE_LIST;
+ }
+
+ if (strncasecmp(p, cpiForwarding_RouteListJsonTag(), strlen(cpiForwarding_RouteListJsonTag())) == 0) {
+ return CPI_PREFIX_REGISTRATION_LIST;
+ }
+
+ if (strncasecmp(p, cpiLinks_CreateTunnelJsonTag(), strlen(cpiLinks_CreateTunnelJsonTag())) == 0) {
+ return CPI_CREATE_TUNNEL;
+ }
+
+ if (strncasecmp(p, cpiLinks_RemoveTunnelJsonTag(), strlen(cpiLinks_RemoveTunnelJsonTag())) == 0) {
+ return CPI_REMOVE_TUNNEL;
+ }
+
+ if (strncasecmp(p, cpiLinks_ConnectionListJsonTag(), strlen(cpiLinks_ConnectionListJsonTag())) == 0) {
+ return CPI_CONNECTION_LIST;
+ }
+
+ if (strncasecmp(p, cpiLinks_AddEtherConnectionJasonTag(), strlen(cpiLinks_AddEtherConnectionJasonTag())) == 0) {
+ return (CPI_ADD_ETHER_CONNECTION);
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheStoreOnJsonTag(), strlen(cpiManageChaces_CacheStoreOnJsonTag())) == 0) {
+ return CPI_CACHE_STORE_ON;
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheStoreOffJsonTag(), strlen(cpiManageChaces_CacheStoreOffJsonTag())) == 0) {
+ return CPI_CACHE_STORE_OFF;
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheServeOnJsonTag(), strlen(cpiManageChaces_CacheServeOnJsonTag())) == 0) {
+ return CPI_CACHE_SERVE_ON;
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheServeOffJsonTag(), strlen(cpiManageChaces_CacheServeOffJsonTag())) == 0) {
+ return CPI_CACHE_SERVE_OFF;
+ }
+
+ if (strncasecmp(p, cpiManageChaces_CacheClearJsonTag(), strlen(cpiManageChaces_CacheClearJsonTag())) == 0) {
+ return CPI_CACHE_CLEAR;
+ }
+
+ if (strncasecmp(p, cpiForwarding_SetStrategyJsonTag(), strlen(cpiForwarding_SetStrategyJsonTag())) == 0) {
+ return CPI_SET_FORWARDING_STRATEGY;
+ }
+
+ if (strncasecmp(p, cpiLinks_SetWldrJsonTag(), strlen(cpiLinks_SetWldrJsonTag())) == 0) {
+ return CPI_SET_WLDR;
+ }
+
+ if (strncasecmp(p, "AddConnEther", strlen("AddConnEther")) == 0) {
+ return CPI_ADD_CONNECTION_ETHERNET;
+ }
+
+ if (strncasecmp(p, "RemoveConnEther", strlen("RemoveConnEther")) == 0) {
+ return CPI_REMOVE_CONNECTION_ETHERNET;
+ }
+
+ if (strncasecmp(p, "AddListener", strlen("AddListener")) == 0) {
+ return CPI_ADD_LISTENER;
+ }
+
+ if (strncasecmp(p, "RemoveListener", strlen("RemoveListener")) == 0) {
+ return CPI_REMOVE_LISTENER;
+ }
+
+ trapIllegalValue(json, "Could not parse: %s\n", parcJSON_ToString(json));
+}
+
+/**
+ * Return the relevant operation from a REQUEST or a REPSONSE.
+ * Do not call on an ACK
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CpiOperation
+cpi_GetMessageOperation(CCNxControl *control)
+{
+ if (cpiConnectionEthernet_IsAddMessage(control)) {
+ return CPI_ADD_CONNECTION_ETHERNET;
+ }
+
+ if (cpiConnectionEthernet_IsRemoveMessage(control)) {
+ return CPI_REMOVE_CONNECTION_ETHERNET;
+ }
+
+ PARCJSON *json = ccnxControl_GetJson(control);
+
+ CpiOperation result = cpi_getCPIOperation2(json);
+ return result;
+}
+
+CpiMessageType
+controlPlaneInterface_GetCPIMessageType(PARCJSON *json)
+{
+ assertNotNull(json, "Invalid state, got NULL json from control message");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(json, cpiResponse);
+ if (value != NULL) {
+ return CPI_RESPONSE;
+ }
+
+ value = parcJSON_GetValueByName(json, cpiRequest);
+ if (value != NULL) {
+ return CPI_REQUEST;
+ }
+
+ value = parcJSON_GetValueByName(json, cpiAck);
+ if (value != NULL) {
+ return CPI_ACK;
+ }
+
+ trapIllegalValue(json, "Expected CpiMessageType, actual %s", parcJSON_ToString(json));
+}
+
+/**
+ * You should verify that it's a CPI message with cpi_IsCpiMessage() before using this.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CpiMessageType
+cpi_GetMessageType(const CCNxControl *control)
+{
+ PARCJSON *json = ccnxControl_GetJson(control);
+ CpiMessageType result = controlPlaneInterface_GetCPIMessageType(json);
+ return result;
+}
+
+/**
+ * Returns the inner operation JSON from the request.
+ *
+ * INPUT: "{ CPI_REQUEST: { SEQUENCE:number key: { operation } }}"
+ * OUTPUT: "{ key : { operation } }"
+ *
+ * Example return: "{ operation }"
+ * @param <#param1#>
+ * @return The inner json, do not destroy it
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSONPair *
+cpi_ParseRequest(PARCJSON *request)
+{
+ PARCJSONValue *value = parcJSON_GetValueByName(request, cpiRequest);
+ assertNotNull(value, "Could not find JSON key %s in %s", cpiRequest, parcJSON_ToString(request));
+ assertTrue(parcJSONValue_IsJSON(value), "cpiRequest is unexpected type");
+
+ PARCJSON *requestJson = parcJSONValue_GetJSON(value);
+ PARCJSONPair *result = parcJSON_GetPairByIndex(requestJson, 1);
+
+ return result;
+}
+
+CCNxControl *
+cpi_ForwarderVersion()
+{
+ return NULL;
+}
+
+uint64_t
+controlPlaneInterface_GetSequenceNumber(const PARCJSON *controlPlaneMessage)
+{
+ assertNotNull(controlPlaneMessage, "Invalid state, got NULL json from control message");
+
+ PARCJSONValue *value = parcJSON_GetValueByName(controlPlaneMessage, cpiRequest);
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(controlPlaneMessage, cpiResponse);
+ }
+ if (value == NULL) {
+ value = parcJSON_GetValueByName(controlPlaneMessage, cpiAck);
+ }
+
+ assertNotNull(value, "Could not get request or response");
+
+ PARCJSON *json = parcJSONValue_GetJSON(value);
+ value = parcJSON_GetValueByName(json, cpiSeqnum);
+ assertNotNull(value, "Could not retrieve key %s from CPI section", cpiSeqnum);
+
+ return parcJSONValue_GetInteger(value);
+}
+
+/**
+ * All CPI messages carry a sequence number.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t
+cpi_GetSequenceNumber(CCNxControl *control)
+{
+ PARCJSON *json = ccnxControl_GetJson(control);
+
+ return controlPlaneInterface_GetSequenceNumber(json);
+}
+
+PARCJSON *
+cpi_CreatePauseInputRequest(void)
+{
+ PARCJSON *operation = parcJSON_Create();
+ PARCJSON *result = cpi_CreateRequest(cpiPause, operation);
+ parcJSON_Release(&operation);
+
+ return result;
+}
+
+PARCJSON *
+cpi_CreateFlushRequest(void)
+{
+ PARCJSON *operation = parcJSON_Create();
+ PARCJSON *result = cpi_CreateRequest(cpiFlush, operation);
+ parcJSON_Release(&operation);
+
+ return result;
+}
+
+/**
+ * Given the inner operation member, wrap it in a Request with a sequence number
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCJSON *
+cpi_CreateRequest(const char *key, PARCJSON *operation)
+{
+ PARCJSON *result = parcJSON_Create();
+ PARCJSON *request = parcJSON_Create();
+
+ uint64_t seqnum = cpi_GetNextSequenceNumber();
+
+ parcJSON_AddInteger(request, cpiSeqnum, (int) seqnum);
+ parcJSON_AddObject(request, key, operation);
+ parcJSON_AddObject(result, cpiRequest, request);
+ parcJSON_Release(&request);
+
+ return result;
+}
+
+CCNxControl *
+cpi_CreateResponse(CCNxControl *request, PARCJSON *operation)
+{
+ PARCJSON *requestJson = ccnxControl_GetJson(request);
+
+ // use the same key as the request
+ uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(requestJson);
+
+ PARCJSONValue *value = parcJSON_GetValueByName(requestJson, cpiRequest);
+ assertNotNull(value, "Could not get request or response");
+ assertTrue(parcJSONValue_IsJSON(value), "cpiRequest should be a JSON object");
+
+ PARCJSON *operationJson = parcJSONValue_GetJSON(value);
+ PARCJSONPair *pair = parcJSON_GetPairByIndex(operationJson, 1);
+ const PARCBuffer *opKeyBuf = parcJSONPair_GetName(pair);
+ const char *opKey = parcBuffer_ToString(opKeyBuf);
+
+ PARCJSON *response = parcJSON_Create();
+ parcJSON_AddInteger(response, cpiSeqnum, (int) seqnum);
+ parcJSON_AddObject(response, opKey, operation);
+ parcMemory_Deallocate(&opKey);
+
+ PARCJSON *responseJson = parcJSON_Create();
+ parcJSON_AddObject(responseJson, cpiResponse, response);
+ parcJSON_Release(&response);
+
+ CCNxControl *result = ccnxControl_CreateCPIRequest(responseJson);
+
+ parcJSON_Release(&responseJson);
+
+ return result;
+}