From e4b47afe317e2598f63221b0d961aa59884f2412 Mon Sep 17 00:00:00 2001 From: martinezric Date: Wed, 3 May 2023 14:39:11 +0200 Subject: [PATCH 1/7] PathComp Backend Adding Logs --- src/pathcomp/backend/pathComp_sp.c | 585 +-- src/pathcomp/backend/pathComp_tools.c | 6796 +++++++++++++------------ src/pathcomp/backend/pathComp_tools.h | 1242 ++--- 3 files changed, 4317 insertions(+), 4306 deletions(-) diff --git a/src/pathcomp/backend/pathComp_sp.c b/src/pathcomp/backend/pathComp_sp.c index 48231b591..252c1d614 100644 --- a/src/pathcomp/backend/pathComp_sp.c +++ b/src/pathcomp/backend/pathComp_sp.c @@ -1,291 +1,294 @@ -/* - * Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pathComp_log.h" -#include "pathComp_tools.h" -#include "pathComp_sp.h" - -// Global Variables -GList* contextSet; - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_sp.c - * @brief handling the Dijkstra algorithm - * - * @param pred - * @param g - * @param s - * @param mapNodes - * - * @author Ricardo Mart�nez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gint computation(struct pred_t* pred, struct graph_t* g, struct service_t* s, struct map_nodes_t* mapNodes) { - g_assert(pred); - g_assert(g); - g_assert(s); - - // Check the both ingress src and dst endpoints are in the graph - gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); - if (srcMapIndex == -1) { - DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); - return -1; - } - - gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); - if (dstMapIndex == -1) { - DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); - return -1; - } - - // Compute the shortest path - dijkstra(srcMapIndex, dstMapIndex, g, s, mapNodes, NULL, NULL, 0x00000000); - - // Check that a feasible solution in term of latency and bandwidth is found - gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); - struct map_t* dest_map = &mapNodes->map[map_dstIndex]; - if (!(dest_map->distance < INFINITY_COST)) { - DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); - return -1; - } - - DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); - // Check that the computed available bandwidth is larger than 0.0 - if (dest_map->avaiBandwidth <= (gfloat)0.0) { - DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); - return -1; - } - DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); - // Handle predecessors - build_predecessors(pred, s, mapNodes); - - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_sp.c - * @brief CSPF algorithm execution - * - * @param s - * @param path - * @param g - * - * @author Ricardo Mart�nez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void computation_shortest_path(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g) { - g_assert(s); - g_assert(path); - g_assert(g); - - // create map of devices / nodes to handle the path computation using the context - struct map_nodes_t *mapNodes = create_map_node(); - build_map_node(mapNodes, g); - - // predecessors to store the computed path - struct pred_t* predecessors = create_predecessors(); - - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); - struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); - - // SP computation - gint done = computation(predecessors, g, s, mapNodes); - if (done == -1) { - DEBUG_PC("NO PATH FOUND %s[%s] ---> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); - comp_route_connection_issue_handler(path, s); - g_free(mapNodes); g_free(predecessors); - return; - } - - // Construct the path from the computed predecessors - struct compRouteOutputItem_t* p = create_path_item(); - //print_predecessors(predecessors); - build_path(p, predecessors, s); - //DEBUG_PC ("Path is constructed"); - - gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); - struct map_t* dst_map = &mapNodes->map[indexDest]; - set_path_attributes(p, dst_map); - DEBUG_PC("Computed Path Avail Bw: %f, Path Cost: %f, latency: %f", p->availCap, p->cost, p->delay); - print_path(p); - - gboolean feasibleRoute = check_computed_path_feasability(s, p); - if (feasibleRoute == TRUE) { - DEBUG_PC("SP Feasible"); - print_path(p); - path->numPaths++; - - // Copy the serviceId - DEBUG_PC("contextId: %s", s->serviceId.contextId); - copy_service_id(&path->serviceId, &s->serviceId); - - // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) - for (gint i = 0; i < s->num_service_endpoints_id; i++) { - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); - struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); - copy_service_endpoint_id(oEp, iEp); - } - path->num_service_endpoints_id = s->num_service_endpoints_id; - - // Copy the computed path - struct path_t* targetedPath = &(path->paths[path->numPaths - 1]); - duplicate_path_t(p, targetedPath); - print_path_t(targetedPath); - g_free(predecessors); - g_free(p); - g_free(mapNodes); - return; - } - DEBUG_PC("SP FAILED!!!"); - comp_route_connection_issue_handler(path, s); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_sp.c - * @brief Iterates over the list of network connectivity service requests - * to compute their own paths fulfilling the constraints - * - * @param outputList - * - * @author Ricardo Mart�nez - * @date 2022 - */ -void sp_execution_services(struct compRouteOutputList_t* oPathList) { - g_assert(oPathList); - // Check at least there is a service to be processed - if (g_list_length(serviceList) == 0) { - DEBUG_PC("Lengtg requested serviceList is Empty..."); - return; - } - - DEBUG_PC("----- Starting the SP Computation ------"); - gint i = 0; - for (GList* listnode = g_list_first(serviceList); - listnode; - listnode = g_list_next(listnode), i++) { - //struct service_t* service = &(serviceList->services[i]); - struct service_t* service = (struct service_t*)(listnode->data); - - DEBUG_PC("Starting the Computation for ServiceId: %s [ContextId: %s]", service->serviceId.service_uuid, service->serviceId.contextId); - struct compRouteOutput_t* pathService = &(oPathList->compRouteConnection[i]); - // check endpoints of the service are different (PE devices/nodes are different) - if (same_src_dst_pe_nodeid(service) == 0) { - DEBUG_PC("PEs are the same... no path computation"); - comp_route_connection_issue_handler(pathService, service); - oPathList->numCompRouteConnList++; - continue; - } - - // get the graph associated to the contextId in the contextSet, if no then error - struct graph_t* g = get_graph_by_contextId(contextSet, service->serviceId.contextId); - if (g == NULL) { - DEBUG_PC("The targeted contextId is NOT in the ContextSet ... then NO graph"); - comp_route_connection_issue_handler(pathService, service); - oPathList->numCompRouteConnList++; - continue; - } - - computation_shortest_path(service, pathService, g); - oPathList->numCompRouteConnList++; - - // for each network connectivity service, a single computed path (out of the KCSP) is retuned - // If path is found, then the selected resources must be pre-assigned into the context information - if (pathService->noPathIssue == NO_PATH_CONS_ISSUE) { - continue; - } - struct path_t* path = &(pathService->paths[pathService->numPaths - 1]); - //allocate_graph_resources(path, service, g); // LGR: crashes in some cases with assymetric topos - //allocate_graph_reverse_resources(path, service, g); // LGR: crashes in some cases with assymetric topos - print_graph(g); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_sp.c - * @brief handles the path computation for the constrained shortest path - * - * @param compRouteOutput - * - * @author Ricardo Mart�nez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gint pathComp_sp_alg(struct compRouteOutputList_t* routeConnList) { - g_assert(routeConnList); - gint numSuccesPathComp = 0, numPathCompIntents = 0; - - DEBUG_PC("================================================================"); - DEBUG_PC("=========================== SP ========================="); - DEBUG_PC("================================================================"); - // increase the number of Path Comp. Intents - numPathCompIntents++; - gint http_code = HTTP_CODE_OK; - - // timestamp t0 - struct timeval t0; - gettimeofday(&t0, NULL); - - // Allocate memory for the context - contextSet = NULL; - // Build up the contextSet (>= 1) - build_contextSet(&contextSet); - print_contextSet(contextSet); -#if 1 - //Triggering the path computation for each specific network connectivity service - sp_execution_services(routeConnList); - - // -- timestamp t1 - struct timeval t1, delta; - gettimeofday(&t1, NULL); - delta.tv_sec = t1.tv_sec - t0.tv_sec; - delta.tv_usec = t1.tv_usec - t0.tv_usec; - delta = tv_adjust(delta); - - numSuccesPathComp++; - update_stats_path_comp(routeConnList, delta, numSuccesPathComp, numPathCompIntents); - print_path_connection_list(routeConnList); -#endif - - g_list_free_full(g_steal_pointer(&contextSet), (GDestroyNotify)destroy_context); - return http_code; -} - - +//////////////////////////////////////////////////////////////////////////////////////// +/** + * # Copyright 2022 Centre Tecnològic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es + * + * 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. + + * Author: CTTC/CERCA PONS RU Ricardo Martínez (ricardo.martinez@cttc.es) + */ + //////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathComp_log.h" +#include "pathComp_tools.h" +#include "pathComp_sp.h" + +// Global Variables +GList* contextSet; + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_sp.c + * @brief handling the Dijkstra algorithm + * + * @param pred + * @param g + * @param s + * @param mapNodes + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gint computation(struct pred_t* pred, struct graph_t* g, struct service_t* s, struct map_nodes_t* mapNodes) { + g_assert(pred); + g_assert(g); + g_assert(s); + + // Check the both ingress src and dst endpoints are in the graph + gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); + if (srcMapIndex == -1) { + DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); + return -1; + } + + gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); + if (dstMapIndex == -1) { + DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); + return -1; + } + + // Compute the shortest path + dijkstra(srcMapIndex, dstMapIndex, g, s, mapNodes, NULL, NULL, 0x00000000); + + // Check that a feasible solution in term of latency and bandwidth is found + gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); + struct map_t* dest_map = &mapNodes->map[map_dstIndex]; + if (!(dest_map->distance < INFINITY_COST)) { + DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); + return -1; + } + + DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); + // Check that the computed available bandwidth is larger than 0.0 + if (dest_map->avaiBandwidth <= (gfloat)0.0) { + DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); + return -1; + } + DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); + // Handle predecessors + build_predecessors(pred, s, mapNodes); + + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_sp.c + * @brief CSPF algorithm execution + * + * @param s + * @param path + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void computation_shortest_path(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g) { + g_assert(s); + g_assert(path); + g_assert(g); + + // create map of devices / nodes to handle the path computation using the context + struct map_nodes_t *mapNodes = create_map_node(); + build_map_node(mapNodes, g); + + // predecessors to store the computed path + struct pred_t* predecessors = create_predecessors(); + + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); + struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); + + // SP computation + gint done = computation(predecessors, g, s, mapNodes); + if (done == -1) { + DEBUG_PC("NO PATH FOUND %s[%s] ---> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); + comp_route_connection_issue_handler(path, s); + g_free(mapNodes); g_free(predecessors); + return; + } + + // Construct the path from the computed predecessors + struct compRouteOutputItem_t* p = create_path_item(); + //print_predecessors(predecessors); + build_path(p, predecessors, s); + //DEBUG_PC ("Path is constructed"); + + gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); + struct map_t* dst_map = &mapNodes->map[indexDest]; + set_path_attributes(p, dst_map); + DEBUG_PC("Computed Path Avail Bw: %f, Path Cost: %f, latency: %f", p->availCap, p->cost, p->delay); + print_path(p); + + gboolean feasibleRoute = check_computed_path_feasability(s, p); + if (feasibleRoute == TRUE) { + DEBUG_PC("SP Feasible"); + print_path(p); + path->numPaths++; + + // Copy the serviceId + DEBUG_PC("contextId: %s", s->serviceId.contextId); + copy_service_id(&path->serviceId, &s->serviceId); + + // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) + for (gint i = 0; i < s->num_service_endpoints_id; i++) { + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); + struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); + copy_service_endpoint_id(oEp, iEp); + } + path->num_service_endpoints_id = s->num_service_endpoints_id; + + // Copy the computed path + struct path_t* targetedPath = &(path->paths[path->numPaths - 1]); + duplicate_path_t(p, targetedPath); + print_path_t(targetedPath); + g_free(predecessors); + g_free(p); + g_free(mapNodes); + return; + } + DEBUG_PC("SP FAILED!!!"); + comp_route_connection_issue_handler(path, s); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_sp.c + * @brief Iterates over the list of network connectivity service requests + * to compute their own paths fulfilling the constraints + * + * @param outputList + * + * @author Ricardo Martínez + * @date 2022 + */ +void sp_execution_services(struct compRouteOutputList_t* oPathList) { + g_assert(oPathList); + // Check at least there is a service to be processed + if (g_list_length(serviceList) == 0) { + DEBUG_PC("Lengtg requested serviceList is Empty..."); + return; + } + + DEBUG_PC("----- Starting the SP Computation ------"); + gint i = 0; + for (GList* listnode = g_list_first(serviceList); + listnode; + listnode = g_list_next(listnode), i++) { + //struct service_t* service = &(serviceList->services[i]); + struct service_t* service = (struct service_t*)(listnode->data); + + DEBUG_PC("Starting the Computation for ServiceId: %s [ContextId: %s]", service->serviceId.service_uuid, service->serviceId.contextId); + struct compRouteOutput_t* pathService = &(oPathList->compRouteConnection[i]); + // check endpoints of the service are different (PE devices/nodes are different) + if (same_src_dst_pe_nodeid(service) == 0) { + DEBUG_PC("PEs are the same... no path computation"); + comp_route_connection_issue_handler(pathService, service); + oPathList->numCompRouteConnList++; + continue; + } + + // get the graph associated to the contextId in the contextSet, if no then error + struct graph_t* g = get_graph_by_contextId(contextSet, service->serviceId.contextId); + if (g == NULL) { + DEBUG_PC("The targeted contextId is NOT in the ContextSet ... then NO graph"); + comp_route_connection_issue_handler(pathService, service); + oPathList->numCompRouteConnList++; + continue; + } + + computation_shortest_path(service, pathService, g); + oPathList->numCompRouteConnList++; + + // for each network connectivity service, a single computed path (out of the KCSP) is retuned + // If path is found, then the selected resources must be pre-assigned into the context information + if (pathService->noPathIssue == NO_PATH_CONS_ISSUE) { + continue; + } + struct path_t* path = &(pathService->paths[pathService->numPaths - 1]); + allocate_graph_resources(path, service, g); + allocate_graph_reverse_resources(path, service, g); + print_graph(g); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_sp.c + * @brief handles the path computation for the constrained shortest path + * + * @param compRouteOutput + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gint pathComp_sp_alg(struct compRouteOutputList_t* routeConnList) { + g_assert(routeConnList); + gint numSuccesPathComp = 0, numPathCompIntents = 0; + + DEBUG_PC("================================================================"); + DEBUG_PC("=========================== SP ========================="); + DEBUG_PC("================================================================"); + // increase the number of Path Comp. Intents + numPathCompIntents++; + gint http_code = HTTP_CODE_OK; + + // timestamp t0 + struct timeval t0; + gettimeofday(&t0, NULL); + + // Allocate memory for the context + contextSet = NULL; + // Build up the contextSet (>= 1) + build_contextSet(&contextSet); + print_contextSet(contextSet); +#if 1 + //Triggering the path computation for each specific network connectivity service + sp_execution_services(routeConnList); + + // -- timestamp t1 + struct timeval t1, delta; + gettimeofday(&t1, NULL); + delta.tv_sec = t1.tv_sec - t0.tv_sec; + delta.tv_usec = t1.tv_usec - t0.tv_usec; + delta = tv_adjust(delta); + + numSuccesPathComp++; + update_stats_path_comp(routeConnList, delta, numSuccesPathComp, numPathCompIntents); + print_path_connection_list(routeConnList); +#endif + + g_list_free_full(g_steal_pointer(&contextSet), (GDestroyNotify)destroy_context); + return http_code; +} + + diff --git a/src/pathcomp/backend/pathComp_tools.c b/src/pathcomp/backend/pathComp_tools.c index e7b91ee9e..ab4a394f1 100644 --- a/src/pathcomp/backend/pathComp_tools.c +++ b/src/pathcomp/backend/pathComp_tools.c @@ -1,3397 +1,3401 @@ -/* - * Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pathComp_log.h" -#include "pathComp.h" -#include "pathComp_tools.h" - -gint numPathCompIntents = 0; // number of events triggering the path computation -//gint numSuccesPathComp = 0; // number of events resulting in succesfully path computations fulfilling the constraints -struct timeval total_path_comp_time; -gdouble totalReqBw = 0.0; -gdouble totalServedBw = 0.0; - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function for time processing - * - * @param a - * - * @author Ricardo Martínez - * @date 2022 - */ - //////////////////////////////////////////////////////////////////////////////////////// -struct timeval tv_adjust (struct timeval a) { - while (a.tv_usec >= 1000000) { - a.tv_usec -= 1000000; - a.tv_sec++; - } - while (a.tv_usec < 0) { - a.tv_usec += 1000000; - a.tv_sec--; - } - return a; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief friendly function to copy safely strings - * - * @param dst - * @param src - * - * @author Ricardo Martínez - * @date 2022 - */ - //////////////////////////////////////////////////////////////////////////////////////// -void duplicate_string(gchar* dst, gchar* src) { - g_assert(dst); g_assert(src); - strcpy(dst, src); - dst[strlen(dst)] = '\0'; - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to print the computed the path - * - * @param path - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void print_path (struct compRouteOutputItem_t *p) { - g_assert(p); - DEBUG_PC ("=========== COMPUTED PATH ======================="); - DEBUG_PC ("E2E Avail. Bw: %f, Latency: %f, Cost: %f, Consumed Power (in W): %f", p->availCap, p->delay, p->cost, p->power); - for (gint k = 0; k < p->numRouteElements; k++) { - DEBUG_PC ("%s[%s] --> %s[%s]", p->routeElement[k].aNodeId.nodeId, p->routeElement[k].aEndPointId, - p->routeElement[k].zNodeId.nodeId, p->routeElement[k].zEndPointId); - DEBUG_PC("\t linkId: %s", p->routeElement[k].linkId); - DEBUG_PC("\t aTopologyId: %s", p->routeElement[k].aTopologyId); - DEBUG_PC("\t zTopologyId: %s", p->routeElement[k].zTopologyId); - } - DEBUG_PC ("=================================================================="); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to print the output path formed by link Ids - * - * @param p - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_path_t(struct path_t* p) { - g_assert(p); - DEBUG_PC(" ============ COMPUTED OUTPUT PATH ================="); - DEBUG_PC("Path AvailBw: %f, Cost: %f, Latency: %f, Power: %f", p->path_capacity.value, - p->path_cost.cost_value, p->path_latency.fixed_latency, p->path_power.power); - DEBUG_PC("number of links of path %d", p->numPathLinks); - for (gint k = 0; k < p->numPathLinks; k++) { - DEBUG_PC("Link: %s", p->pathLinks[k].linkId); - for (gint l = 0; l < p->pathLinks[k].numLinkTopologies; l++) { - DEBUG_PC("end Link [%d] TopologyId: %s", l, p->pathLinks[k].linkTopologies[l].topologyId); - } - DEBUG_PC(" ContextId: %s", p->pathLinks[k].topologyId.contextId); - DEBUG_PC(" TopologyUUid: %s", p->pathLinks[k].topologyId.topology_uuid); - DEBUG_PC(" aDeviceId: %s", p->pathLinks[k].aDeviceId); - DEBUG_PC(" aEndpointId: %s", p->pathLinks[k].aEndPointId); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used allocate memory for struct path_t - * - * - * @author Ricardo Martínez - * @date 2022 - */ - //////////////////////////////////////////////////////////////////////////////////////// -struct path_t* create_path() { - struct path_t* p = g_malloc0(sizeof(struct path_t)); - if (p == NULL) { - DEBUG_PC("Memory allocation failure"); - exit(-1); - } - return(p); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Returns the char (36 bytes) format of a uuid - * - * @param uuid - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gchar* get_uuid_char(uuid_t uuid) { - gchar* uuidChar = g_malloc0(16); // uuid has 36 chars - if (uuidChar == NULL) { - DEBUG_PC("Memory Allocation failure"); - exit(-1); - } - uuid_unparse(uuid, (char *)uuidChar); - return uuidChar; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Makes a copy of the service identifier (including the context) - * - * @param o - * @param i - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void copy_service_id(struct serviceId_t* o, struct serviceId_t* i) { - g_assert(o); g_assert(i); - memcpy(o->contextId, i->contextId, sizeof(i->contextId)); - memcpy(o->service_uuid, i->service_uuid, sizeof(i->service_uuid)); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Makes a copy of the service endpoint identifier (including the topology (contect and topology id), device and endpoint (port)) - * - * @param oEp - * @param iEp - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void copy_service_endpoint_id(struct service_endpoints_id_t* oEp, struct service_endpoints_id_t* iEp) { - g_assert(oEp); g_assert(iEp); - - // copy topology information - memcpy(oEp->topology_id.contextId, iEp->topology_id.contextId, sizeof(iEp->topology_id.contextId)); - memcpy(oEp->topology_id.topology_uuid, iEp->topology_id.topology_uuid, sizeof(iEp->topology_id.topology_uuid)); - - // copy the endpoint - memcpy(oEp->device_uuid, iEp->device_uuid, sizeof(iEp->device_uuid)); - memcpy(oEp->endpoint_uuid, iEp->endpoint_uuid, sizeof(iEp->endpoint_uuid)); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief From the set of contexts, it is returned the graph associated to that context matching - * with the passed contextId. - * - * @param Set - * @param contextId - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct graph_t* get_graph_by_contextId(GList* set, gchar* contextId) { - g_assert(contextId); - - // iterate over the set of context. Pick the one matching with contextId, and return the graph. - // If not found, return NULL - struct graph_t* g = NULL; - for (GList *ln = g_list_first(set); - ln; - ln = g_list_next(ln)){ - struct context_t* context = (struct context_t*)(ln->data); - if (strcmp(context->contextId, contextId) == 0) { - g = &(context->g); - return g; - } - } - return NULL; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Process the service constraint and maps them into the path constraints - * to be fulfilled - * - * @param path_constraints - * @param s - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct path_constraints_t * get_path_constraints(struct service_t* s) { - g_assert(s); - - struct path_constraints_t* path_constraints = g_malloc0(sizeof(struct path_constraints_t)); - if (path_constraints == NULL) { - DEBUG_PC("Memory Allocation Failure"); - exit(-1); - } - - char* eptr; - for (gint i = 0; i < s->num_service_constraints; i++) { - struct constraint_t* constraint = &(s->constraints[i]);; - if (strncmp((const char*)constraint->constraint_type, "bandwidth", 9) == 0) { - path_constraints->bwConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); - path_constraints->bw = TRUE; - //DEBUG_PC("Path Constraint Bw: %f", path_constraints->bwConstraint); - } - if (strncmp((const char*)constraint->constraint_type, "cost", 4) == 0) { - path_constraints->costConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); - path_constraints->cost = TRUE; - //DEBUG_PC("Path Constraint Cost: %f", path_constraints->costConstraint); - } - if (strncmp((const char*)constraint->constraint_type, "latency", 7) == 0) { - path_constraints->latencyConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); - path_constraints->latency = TRUE; - //DEBUG_PC("Path Constraint Latency: %f", path_constraints->latencyConstraint); - } - if (strncmp((const char*)constraint->constraint_type, "energy", 6) == 0) { - path_constraints->energyConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); - path_constraints->energy = TRUE; - //DEBUG_PC("Path Constraint Energy: %f", path_constraints->energyConstraint); - } - } - return path_constraints; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Creates the predecessors to keep the computed path - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct pred_t * create_predecessors () { - struct pred_t *predecessors = g_malloc0 (sizeof (struct pred_t)); - if (predecessors == NULL) { - DEBUG_PC ("memory allocation failed\n"); - exit (-1); - } - return predecessors; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief create edge - * - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct edges_t* create_edge() { - struct edges_t* e = g_malloc0(sizeof(struct edges_t)); - if (e == NULL) { - DEBUG_PC("Memory allocation failed\n"); - exit(-1); - } - return e; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Prints the list of the predecessors for a given computed Shortest Path - * - * @param p - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void print_predecessors (struct pred_t *p) -{ - g_assert (p); - DEBUG_PC ("Number of Predecessors: %d", p->numPredComp); - for (gint i = 0; i < p->numPredComp; i++) { - struct pred_comp_t *pComp = &(p->predComp[i]); - DEBUG_PC ("deviceId: %s", pComp->v.nodeId); - struct edges_t *e = &(pComp->e); - DEBUG_PC("Edge[#%d] (linkId): %s", i, e->linkId); - DEBUG_PC ("\t %s[%s] ===>", e->aNodeId.nodeId, e->aEndPointId); - DEBUG_PC("\t %s[%s]", e->zNodeId.nodeId, e->zEndPointId); - DEBUG_PC("\t aTopologyId: %s", e->aTopologyId); - DEBUG_PC("\t zTopologyId: %s", e->zTopologyId); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Builds the list of predecessors for the request destination using the computed Shortest Path - * being stored in map - * - * @param p - * @param s - * @param map - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void build_predecessors (struct pred_t *p, struct service_t *s, struct map_nodes_t *map) { - g_assert (p); g_assert (s); g_assert (map); - - struct nodes_t *v = create_node(); - duplicate_string(v->nodeId, s->service_endpoints_id[1].device_uuid); - - struct edges_t *e = create_edge(); - get_edge_from_map_by_node (e, v, map); - - // Get u (being source of edge e) - struct nodes_t u; - duplicate_node_id (&e->aNodeId, &u); - - // Add to the predecessors list - struct pred_comp_t *pred = &(p->predComp[p->numPredComp]); - duplicate_node_id (&u, &pred->v); - struct edges_t *e1 = &(pred->e); - duplicate_edge (e1, e); - p->numPredComp++; - // Back-trace edges till reaching the srcPEId - struct nodes_t* srcNode = create_node(); - duplicate_string(srcNode->nodeId, s->service_endpoints_id[0].device_uuid); - - while (compare_node_id (&u, srcNode) != 0) { - duplicate_node_id (&u, v); - get_edge_from_map_by_node (e, v, map); - // Get the u (being source of edge e) - duplicate_node_id (&e->aNodeId, &u); - // Get the new predecessor - struct pred_comp_t *pred = &p->predComp[p->numPredComp]; - // Add to the predecessors list - duplicate_node_id (&u, &pred->v); - struct edges_t *e1 = &(pred->e); - duplicate_edge (e1, e); - p->numPredComp++; - } - print_predecessors (p); - g_free (e); g_free(v); g_free(srcNode); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief It creates a struct nodes_t - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct nodes_t * create_node () -{ - struct nodes_t *n = g_malloc0 (sizeof (struct nodes_t)); - if (n == NULL) { - DEBUG_PC ("memory allocation problem"); - exit (-1); - } - return n; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief It creates a routeElement_t - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct routeElement_t * create_routeElement () { - struct routeElement_t *rE = g_malloc0 (sizeof (struct routeElement_t)); - if (rE == NULL) { - DEBUG_PC ("memory allocation problem"); - exit (-1); - } - return rE; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief copy node ids - * - * @param src - * @param dst - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_node_id (struct nodes_t *src, struct nodes_t *dst) { - g_assert (src); - g_assert (dst); - //DEBUG_PC ("Duplicate nodeId for %s", src->nodeId); - strcpy (dst->nodeId, src->nodeId); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief compares a pair of node Ids - * - * @param a - * @param b - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint compare_node_id (struct nodes_t *a, struct nodes_t *b) { - g_assert (a); - g_assert (b); - return (memcmp (&a->nodeId, b->nodeId, strlen (b->nodeId))); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief duplicate two routeElement_t - * - * @param src - * @param dst - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_routeElement (struct routeElement_t *src, struct routeElement_t *dst) -{ - g_assert (src); - g_assert (dst); - - duplicate_node_id (&(src->aNodeId), &(dst->aNodeId)); - duplicate_node_id (&(src->zNodeId), &(dst->zNodeId)); - duplicate_string(dst->aEndPointId, src->aEndPointId); - duplicate_string(dst->zEndPointId, src->zEndPointId); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief duplicate two edges - * - * @param e1 (destination) - * @param e2 (source) - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_edge (struct edges_t *e1, struct edges_t *e2) { - g_assert (e1); g_assert (e2); - - duplicate_node_id (&e2->aNodeId, &e1->aNodeId); - duplicate_node_id (&e2->zNodeId, &e1->zNodeId); - //DEBUG_PC ("e->aNodeId: %s ---> e->zNodeId: %s", e1->aNodeId.nodeId, e1->zNodeId.nodeId); - duplicate_string(e1->aEndPointId, e2->aEndPointId); - duplicate_string(e1->zEndPointId, e2->zEndPointId); - duplicate_string(e1->linkId, e2->linkId); - duplicate_string(e1->interDomain_localId, e2->interDomain_localId); - duplicate_string(e1->interDomain_remoteId, e2->interDomain_remoteId); - duplicate_string(e1->aTopologyId, e2->aTopologyId); - duplicate_string(e1->zTopologyId, e2->zTopologyId); - - e1->unit = e2->unit; - memcpy(&e1->totalCap, &e2->totalCap, sizeof(gdouble)); - memcpy(&e1->availCap, &e2->availCap, sizeof(gdouble)); - - memcpy (&e1->cost, &e2->cost, sizeof (gdouble)); - memcpy (&e1->delay, &e2->delay, sizeof (gdouble)); - memcpy(&e1->energy, &e2->energy, sizeof(gdouble)); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Duplicate path - * - * @param a - original - * @param b - copy - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_path (struct compRouteOutputItem_t *a, struct compRouteOutputItem_t *b) { - g_assert (a); g_assert (b); - memcpy(&b->availCap, &a->availCap, sizeof (gdouble)); - memcpy(&b->cost, &a->cost, sizeof(gdouble)); - memcpy(&b->delay, &a->delay, sizeof (gdouble)); - memcpy(&b->power, &a->power, sizeof(gdouble)); - b->numRouteElements = a->numRouteElements; - for (gint k = 0; k < a->numRouteElements; k++) { - //DEBUG_PC ("aNodeId: %s // zNodeId: %s", a->routeElement[k].aNodeId.nodeId, a->routeElement[k].zNodeId.nodeId); - // aNodeId duplication - struct nodes_t *n1 = &(a->routeElement[k].aNodeId); - struct nodes_t *n2 = &(b->routeElement[k].aNodeId); - duplicate_node_id (n1, n2); - //zNodeId duplication - n1 = &(a->routeElement[k].zNodeId); - n2 = &(b->routeElement[k].zNodeId); - duplicate_node_id (n1, n2); - duplicate_string(b->routeElement[k].aEndPointId, a->routeElement[k].aEndPointId); - duplicate_string(b->routeElement[k].zEndPointId, a->routeElement[k].zEndPointId); - duplicate_string(b->routeElement[k].linkId, a->routeElement[k].linkId); - duplicate_string(b->routeElement[k].aTopologyId, a->routeElement[k].aTopologyId); - duplicate_string(b->routeElement[k].zTopologyId, a->routeElement[k].zTopologyId); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Duplicate path from compRouteOutputItem_t to path_t - * - * @param a - original - * @param b - copy - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_path_t(struct compRouteOutputItem_t* a, struct path_t* b) { - g_assert(a); g_assert(b); - - // transfer path characteristics ... - memcpy(&b->path_capacity.value, &a->availCap, sizeof(gdouble)); - memcpy(&b->path_cost.cost_value, &a->cost, sizeof(gdouble)); - memcpy(&b->path_latency.fixed_latency, &a->delay, sizeof(gdouble)); - memcpy(&b->path_power.power, &a->power, sizeof(gdouble)); - - b->numPathLinks = a->numRouteElements; - - for (gint k = 0; k < a->numRouteElements; k++) { - struct routeElement_t* rE = &(a->routeElement[k]); - struct pathLink_t* pL = &(b->pathLinks[k]); - - // copy the aDeviceId and aEndpointId, zDeviceId and zEndPointId - duplicate_string(pL->aDeviceId, rE->aNodeId.nodeId); - duplicate_string(pL->zDeviceId, rE->zNodeId.nodeId); - duplicate_string(pL->aEndPointId, rE->aEndPointId); - duplicate_string(pL->zEndPointId, rE->zEndPointId); - - duplicate_string(pL->topologyId.topology_uuid, rE->aTopologyId); - duplicate_string(pL->topologyId.contextId, rE->contextId); - - //copy the linkId - duplicate_string(pL->linkId, rE->linkId); - pL->numLinkTopologies++; - duplicate_string(pL->linkTopologies[pL->numLinkTopologies - 1].topologyId, rE->aTopologyId); - pL->numLinkTopologies++; - duplicate_string(pL->linkTopologies[pL->numLinkTopologies - 1].topologyId, rE->zTopologyId); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Return the index into mapN related nodeId - * - * @param nodeId - * @para mapN - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint get_map_index_by_nodeId (gchar *nodeId, struct map_nodes_t * mapN) { - gint i = 0; - for (i = 0; i < mapN->numMapNodes; i++) { - //DEBUG_PC ("i: %d; current: %s // targeted: %s", i, mapN->map[i].verticeId.nodeId, nodeId); - if (memcmp (mapN->map[i].verticeId.nodeId, nodeId, strlen (nodeId)) == 0) { - //DEBUG_PC ("Index: %d", i); - return i; - } - } - //DEBUG_PC ("Index: %d", index); - return -1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Get the edge e enabling reaching the computed v in mapNodes - * - * @param e - * @param v - * @param mapN - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void get_edge_from_map_by_node (struct edges_t *e, struct nodes_t* v, struct map_nodes_t *mapN) { - //DEBUG_PC ("Get the Edge into map from node v: %s", v.nodeId); - // Get the edge reaching the node v from mapNodes - gint map_vIndex = get_map_index_by_nodeId (v->nodeId, mapN); - //DEBUG_PC ("aNodeId: %s --> zNodeId: %s", mapN->map[map_vIndex].predecessor.aNodeId.nodeId, mapN->map[map_vIndex].predecessor.zNodeId.nodeId); - struct edges_t *te = &(mapN->map[map_vIndex].predecessor); - duplicate_edge (e, te); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Get the edge from the predecessors array for a given node n - * - * @param e - * @param n - * @param predecessors - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void get_edge_from_predecessors (struct edges_t *e, struct nodes_t* n, struct pred_t *predecessors) { - g_assert(predecessors); - DEBUG_PC ("Get edge outgoing node %s from predecessors list", n->nodeId); - //print_predecessors (predecessors); - for (gint i = 0; i < predecessors->numPredComp; i++) { - struct pred_comp_t *pred = &(predecessors->predComp[i]); - if (compare_node_id (n, &pred->v) == 0) { - // Add to the predecessors list - struct edges_t *te = &(pred->e); - DEBUG_PC("add e (linkId): %s", te->linkId); - duplicate_edge (e, te); - return; - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Construct the path using the predecessors list - * - * @param path - * @param predecessors - * @param s - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void build_path (struct compRouteOutputItem_t *p, struct pred_t *predecessors, struct service_t *s) { - // Get the source device Id of the network connectivity service - struct nodes_t *v = create_node(); - // Src Node of the Service set to v - duplicate_string(v->nodeId, s->service_endpoints_id[0].device_uuid); - - // Get the edge for v in predecessors - struct edges_t* e = create_edge(); - get_edge_from_predecessors (e, v, predecessors); - // Get the target for e - struct nodes_t u; - duplicate_node_id (&e->zNodeId, &u); - //DEBUG_PC ("u: %s", u.nodeId); - struct path_constraints_t* pathCons = get_path_constraints(s); - - // Add route element to the path being constructed - gint k = 0; - duplicate_node_id (&e->aNodeId, &p->routeElement[k].aNodeId); - duplicate_node_id (&e->zNodeId, &p->routeElement[k].zNodeId); - duplicate_string(p->routeElement[k].aEndPointId, e->aEndPointId); - duplicate_string(p->routeElement[k].zEndPointId, e->zEndPointId); - duplicate_string(p->routeElement[k].linkId, e->linkId); - duplicate_string(p->routeElement[k].aTopologyId, e->aTopologyId); - duplicate_string(p->routeElement[k].zTopologyId, e->zTopologyId); - duplicate_string(p->routeElement[k].contextId, s->serviceId.contextId); - p->numRouteElements++; - - // Get Dst Node of connectivity service - struct nodes_t* dst = create_node(); - duplicate_string(dst->nodeId, s->service_endpoints_id[1].device_uuid); - while (compare_node_id (&u, dst) != 0) { - k++; - p->numRouteElements++; - duplicate_node_id (&u, v); - get_edge_from_predecessors (e, v, predecessors); - // Get the target u - duplicate_node_id (&e->zNodeId, &u); - // Add route element to the path being constructed - duplicate_node_id (&e->aNodeId, &p->routeElement[k].aNodeId); - duplicate_node_id (&e->zNodeId, &p->routeElement[k].zNodeId); - duplicate_string(p->routeElement[k].aEndPointId, e->aEndPointId); - duplicate_string(p->routeElement[k].zEndPointId, e->zEndPointId); - duplicate_string(p->routeElement[k].linkId, e->linkId); - duplicate_string(p->routeElement[k].aTopologyId, e->aTopologyId); - duplicate_string(p->routeElement[k].zTopologyId, e->zTopologyId); - duplicate_string(p->routeElement[k].contextId, s->serviceId.contextId); - } - g_free(e); g_free(v); g_free(pathCons); - //DEBUG_PC ("Path is constructed"); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Print the graph for DEBUG_PCging purposes - * - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void print_graph (struct graph_t *g) { - g_assert(g); - DEBUG_PC ("================================================================"); - DEBUG_PC ("=========================== GRAPH =========================="); - DEBUG_PC ("================================================================"); - DEBUG_PC("Graph Num Vertices: %d", g->numVertices); - - for (gint i = 0; i < g->numVertices; i++) { - DEBUG_PC ("Head Vertice [%s]", g->vertices[i].verticeId.nodeId); - for (gint j = 0; j < g->vertices[i].numTargetedVertices; j++) - { - DEBUG_PC (" Tail Vertice: %s", g->vertices[i].targetedVertices[j].tVertice.nodeId); - for (gint k = 0; k < g->vertices[i].targetedVertices[j].numEdges; k++) - { - struct edges_t *e = &(g->vertices[i].targetedVertices[j].edges[k]); - DEBUG_PC ("%s(%s) --> %s(%s) [C: %f, Bw: %f b/s, Delay: %f ms]", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, - e->zEndPointId, e->cost, e->availCap, e->delay); - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Look for a given edge into the graph - * - * @param verticeIndex - * @param targetedVerticeIndex - * @param e - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint graph_edge_lookup (gint verticeIndex, gint targetedVerticeIndex, struct edges_t *e, struct graph_t *g) { - gint indexEdge = -1; - - for (gint j = 0; j < g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex].numEdges; j++) { - struct edges_t *e2 = &(g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex].edges[j]); - if ((compare_node_id (&e->aNodeId, &e2->aNodeId) == 0) && - (compare_node_id (&e->zNodeId, &e2->zNodeId) == 0) && - (strcmp (e->aEndPointId, e2->aEndPointId) == 0) && - (strcmp (e->zEndPointId, e2->zEndPointId) == 0) && - (strcmp(e->linkId, e2->linkId) == 0)) { - DEBUG_PC ("%s (%s) --> %s (%s) [linkId: %s] FOUND in the Graph at index: %d", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, - e->zEndPointId, e->linkId, j); - indexEdge = j; - return indexEdge; - } - } - return indexEdge; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Look for a given vertice within the graph using the nodeId - * - * @param nodeId - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint graph_vertice_lookup (gchar *nodeId, struct graph_t *g) -{ - gint index = -1; - //DEBUG_PC("Searching Node: %s", nodeId); - for (gint i = 0; i < g->numVertices; i++) { - //DEBUG_PC("Checked Graph Node: %s", g->vertices[i].verticeId.nodeId); - if (memcmp (g->vertices[i].verticeId.nodeId, nodeId, strlen (nodeId)) == 0) - { - index = i; - //DEBUG_PC ("%s is found in the graph vertice [%d]", nodeId, index); - break; - } - } - return (index); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Check if a nodeId is already considered into the set of targeted vertices from a given vertice - * - * @param nodeId - * @param vIndex - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint graph_targeted_vertice_lookup (gint vIndex, gchar *nodeId, struct graph_t *g) -{ - gint addedTargetedVerticeIndex = -1; - gint i = 0; - - if (g->vertices[vIndex].numTargetedVertices == 0) - { - return (addedTargetedVerticeIndex); - } - - for (i = 0; i < g->vertices[vIndex].numTargetedVertices; i++) - { - if (memcmp (g->vertices[vIndex].targetedVertices[i].tVertice.nodeId, nodeId, strlen (nodeId)) == 0) - { - DEBUG_PC ("Targeted %s reachable from %s", nodeId, g->vertices[vIndex].verticeId.nodeId); - addedTargetedVerticeIndex = i; - return (addedTargetedVerticeIndex); - } - } - // not found ... - return (addedTargetedVerticeIndex); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Check if a nodeId is already considered into the set of targeted vertices from a given vertice, if not to be added - * - * @param nodeId - * @param vIndex - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint graph_targeted_vertice_add (gint vIndex, gchar *nodeId, struct graph_t *g) -{ - gint addedTargetedVerticeIndex = -1; - gint i = 0; - - if (g->vertices[vIndex].numTargetedVertices == 0) - { - //DEBUG_PC ("targeted vertice %s being reachable from vertice %s", nodeId, g->vertices[vIndex].verticeId.nodeId); - addedTargetedVerticeIndex = 0; - return (addedTargetedVerticeIndex); - } - - for (i = 0; i < g->vertices[vIndex].numTargetedVertices; i++) - { - if (memcmp (g->vertices[vIndex].targetedVertices[i].tVertice.nodeId, nodeId, strlen (nodeId)) == 0) - { - //DEBUG_PC ("Targeted vertice %s is already considered in the reachable from vertice %s", nodeId, g->vertices[vIndex].verticeId.nodeId); - addedTargetedVerticeIndex = -1; - return (addedTargetedVerticeIndex); - } - } - // It is not found, next to be added at i position - addedTargetedVerticeIndex = i; - return (addedTargetedVerticeIndex); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Remove edge from the graph - * - * @param g - * @param e - * - * @author Ricardo Martínez - * @date 2022 - */ -void remove_edge_from_graph (struct graph_t *g, struct edges_t *e) { - // Find the ingress vertice into the graph - DEBUG_PC ("Removing from Graph %s[%s]) ---> %s[%s] (linkId: %s)", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, e->aEndPointId, e->linkId); - gint verticeIndex = -1; - verticeIndex = graph_vertice_lookup (e->aNodeId.nodeId, g); - if (verticeIndex == -1) { - DEBUG_PC ("Edge w/ %s is NOT in the Graph!!", e->aNodeId.nodeId); - return; - } - - // Find the targeted vertice from vertice Id - gint targetedVerticeIndex = -1; - targetedVerticeIndex = graph_targeted_vertice_lookup (verticeIndex, e->zNodeId.nodeId, g); - if (targetedVerticeIndex == -1) { - DEBUG_PC ("%s --> %s NOT in the Graph!!", e->aNodeId.nodeId, e->zNodeId.nodeId); - return; - } - //DEBUG_PC ("%s --> %s found in the Graph", e->aNodeId.nodeId, e->zNodeId.nodeId); - - // Get the edge position - gint edgeIndex = -1; - edgeIndex = graph_edge_lookup (verticeIndex, targetedVerticeIndex, e, g); - if (edgeIndex == -1) { - DEBUG_PC ("%s --> %s NOT in the Graph!!", e->aNodeId.nodeId, e->zNodeId.nodeId); - return; - } - - //DEBUG_PC ("%s --> %s FOUND in Graph w/ edgeIndex: %d", e->aNodeId.nodeId, e->zNodeId.nodeId, edgeIndex); - - // Remove the edge - //DEBUG_PC ("Start Removing %s --> %s from Graph", e->aNodeId.nodeId, e->zNodeId.nodeId); - struct targetNodes_t *v = &(g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex]); - for (gint j = edgeIndex; j < v->numEdges; j++) { - struct edges_t *e1 = &(v->edges[j]); - struct edges_t *e2 = &(v->edges[j+1]); - duplicate_edge (e1, e2); - } - v->numEdges --; - DEBUG_PC ("Number of Edges between %s and %s is %d", e->aNodeId.nodeId, e->zNodeId.nodeId, v->numEdges); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief create the pointer for keeping a set of the paths (struct compRouteOutput_t) - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct path_set_t * create_path_set () { - struct path_set_t * p = g_malloc0 (sizeof (struct path_set_t)); - if (p == NULL) { - DEBUG_PC ("Memory allocation problem"); - exit (-1); - } - return p; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Remove the path set - * - * @param p - * - * @author Ricardo Martínez - * @date 2021 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void remove_path_set(struct path_set_t* p) { - g_assert(p); g_free(p); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Create map of nodes to handle the path computation - * - * @param mapN - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void build_map_node (struct map_nodes_t *mapN, struct graph_t *g) { - //DEBUG_PC ("Construction of the Map of Nodes"); - for (gint i = 0; i < g->numVertices; i++) { - duplicate_node_id (&g->vertices[i].verticeId, &mapN->map[i].verticeId); - mapN->map[i].distance = INFINITY_COST; - mapN->map[i].avaiBandwidth = 0.0; - mapN->map[i].latency = INFINITY_COST; - mapN->map[i].power = INFINITY_COST; - mapN->numMapNodes++; - } - //DEBUG_PC ("mapNodes formed by %d Nodes", mapN->numMapNodes); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Allocate memory for path of struct compRouteOutputList_t * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct compRouteOutputList_t * create_route_list () { - struct compRouteOutputList_t *p = g_malloc0 (sizeof (struct compRouteOutputList_t)); - if (p == NULL) { - DEBUG_PC ("Memory Allocation Problem"); - exit (-1); - } - return p; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Copy all the attributes defining a path - * - * @param dst_path - * @param src_path - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void copy_path(struct path_t* dst_path, struct path_t* src_path) { - g_assert(dst_path); - g_assert(src_path); - - // Path capacity - dst_path->path_capacity.unit = src_path->path_capacity.unit; - memcpy(&dst_path->path_capacity.value, &src_path->path_capacity.value, sizeof(gdouble)); - - // Path latency - memcpy(&dst_path->path_latency.fixed_latency, &src_path->path_latency.fixed_latency, sizeof(gdouble)); - - // Path cost - duplicate_string(dst_path->path_cost.cost_name, src_path->path_cost.cost_name); - memcpy(&dst_path->path_cost.cost_value, &src_path->path_cost.cost_value, sizeof(gdouble)); - memcpy(&dst_path->path_cost.cost_algorithm, &src_path->path_cost.cost_algorithm, sizeof(gdouble)); - - // Path links - dst_path->numPathLinks = src_path->numPathLinks; - for (gint i = 0; i < dst_path->numPathLinks; i++) { - struct pathLink_t* dPathLink = &(dst_path->pathLinks[i]); - struct pathLink_t* sPathLink = &(src_path->pathLinks[i]); - - duplicate_string(dPathLink->linkId, sPathLink->linkId); - duplicate_string(dPathLink->aDeviceId, sPathLink->aDeviceId); - duplicate_string(dPathLink->zDeviceId, sPathLink->zDeviceId); - duplicate_string(dPathLink->aEndPointId, sPathLink->aEndPointId); - duplicate_string(dPathLink->zEndPointId, sPathLink->zEndPointId); - - duplicate_string(dPathLink->topologyId.contextId, sPathLink->topologyId.contextId); - duplicate_string(dPathLink->topologyId.topology_uuid, sPathLink->topologyId.topology_uuid); - - dPathLink->numLinkTopologies = sPathLink->numLinkTopologies; - for (gint j = 0; j < dPathLink->numLinkTopologies; j++) { - struct linkTopology_t* dLinkTop = &(dPathLink->linkTopologies[j]); - struct linkTopology_t* sLinkTop = &(sPathLink->linkTopologies[j]); - - duplicate_string(dLinkTop->topologyId, sLinkTop->topologyId); - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Duplicate the route output instance - * - * @param dst_ro - * @param src_ro - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_compRouteOuput(struct compRouteOutput_t* dst_ro, struct compRouteOutput_t* src_ro) { - g_assert(dst_ro); g_assert(src_ro); - - // Copy the serviceId - copy_service_id(&dst_ro->serviceId, &src_ro->serviceId); - dst_ro->num_service_endpoints_id = src_ro->num_service_endpoints_id; - - for (gint j = 0; j < dst_ro->num_service_endpoints_id; j++) { - struct service_endpoints_id_t* iEp = &(src_ro->service_endpoints_id[j]); - struct service_endpoints_id_t* oEp = &(dst_ro->service_endpoints_id[j]); - copy_service_endpoint_id(oEp, iEp); - } - - // Copy paths - dst_ro->numPaths = src_ro->numPaths; - for (gint j = 0; j < dst_ro->numPaths; j++) { - struct path_t* dst_path = &(dst_ro->paths[j]); - struct path_t* src_path = &(src_ro->paths[j]); - copy_path(dst_path, src_path); - } - // copy no path issue value - dst_ro->noPathIssue = src_ro->noPathIssue; - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Duplicate the computation route output list - * - * @param dst - * @param src - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_route_list(struct compRouteOutputList_t* dst, struct compRouteOutputList_t* src) { - g_assert(src); g_assert(dst); - - dst->numCompRouteConnList = src->numCompRouteConnList; - dst->compRouteOK = src->compRouteOK; - memcpy(&dst->compRouteConnAvBandwidth, &src->compRouteConnAvBandwidth, sizeof(gdouble)); - memcpy(&dst->compRouteConnAvPathLength, &src->compRouteConnAvPathLength, sizeof(gdouble)); - for (gint i = 0; i < src->numCompRouteConnList; i++) { - struct compRouteOutput_t* src_ro = &(src->compRouteConnection[i]); - struct compRouteOutput_t* dst_ro = &(dst->compRouteConnection[i]); - duplicate_compRouteOuput(dst_ro, src_ro); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Allocate memory for path of struct compRouteOutputItem_t * - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct compRouteOutputItem_t *create_path_item () { - struct compRouteOutputItem_t *p = g_malloc0 (sizeof (struct compRouteOutputItem_t)); - if (p == NULL) { - DEBUG_PC ("Memory Allocation Problem"); - exit (-1); - } - return p; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Sort the set of paths the AvailBw, Cost and Delay - * - * @params setP - * @params args - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void sort_path_set(struct path_set_t* setP, guint args) { - g_assert(setP); - // Sort the paths contained in setP by: - // 1st Criteria: The path cost (maybe bound to link distance) - // 2nd Criteria: The consumed path power - // 3nd Criteria: The path latency - // 3rd Criteria: The available Bw - float epsilon = 0.1; - - for (gint i = 0; i < setP->numPaths; i++) { - for (gint j = 0; j < (setP->numPaths - i - 1); j++) { - struct compRouteOutputItem_t* path1 = &setP->paths[j]; - struct compRouteOutputItem_t* path2 = &setP->paths[j + 1]; - struct compRouteOutputItem_t* pathTmp = create_path_item(); - //////////////////////// Criterias //////////////////////////////////////// - // 1st Criteria (Cost) - if (path2->cost < path1->cost) { - duplicate_path(path1, pathTmp); - duplicate_path(path2, path1); - duplicate_path(pathTmp, path2); - g_free(pathTmp); - continue; - } - if (path2->cost == path1->cost) { - // 2nd Criteria (Energy) - if (args & ENERGY_EFFICIENT_ARGUMENT) { - if (path2->power < path1->power) { - duplicate_path(path1, pathTmp); - duplicate_path(path2, path1); - duplicate_path(pathTmp, path2); - g_free(pathTmp); - continue; - } - else { // path1->power < path2->power - g_free(pathTmp); - continue; - } - } - else { // No enery efficient argument - // 3rd Criteria (latency) - if (path2->delay < path1->delay) { - duplicate_path(path1, pathTmp); - duplicate_path(path2, path1); - duplicate_path(pathTmp, path2); - g_free(pathTmp); - continue; - } - else if (path1->delay < path2->delay) { - g_free(pathTmp); - continue; - } - else { // path1->delay == path2->delay - // 4th Criteria (available bw) - if (path2->availCap > path1->availCap) { - duplicate_path(path1, pathTmp); - duplicate_path(path2, path1); - duplicate_path(pathTmp, path2); - g_free(pathTmp); - continue; - } - else { - g_free(pathTmp); - continue; - } - } - } - } - else { // path1->cost < path2->cost - g_free(pathTmp); - continue; - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Remove first element from the path sets - * - * @params setP - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void pop_front_path_set (struct path_set_t *setP) { - for (gint j = 0; j < setP->numPaths - 1; j++) { - struct compRouteOutputItem_t *path1 = &setP->paths[j]; - struct compRouteOutputItem_t *path2 = &setP->paths[j+1]; - duplicate_path (path2, path1); - } - setP->numPaths--; - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Add routeElement to the back of the path - * - * @param rE - * @param p - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void add_routeElement_path_back (struct routeElement_t *rE, struct compRouteOutputItem_t *p) { - //DEBUG_PC ("p->numRouteElements: %d", p->numRouteElements); - p->numRouteElements++; - gint index = p->numRouteElements - 1; - - struct nodes_t *pn = &(p->routeElement[index].aNodeId); - struct nodes_t *rEn = &(rE->aNodeId); - - // duplicate aNodeId - duplicate_node_id (rEn, pn); - pn = &(p->routeElement[index].zNodeId); - rEn = &(rE->zNodeId); - duplicate_node_id (rEn, pn); - duplicate_string(p->routeElement[index].aEndPointId, rE->aEndPointId); - duplicate_string(p->routeElement[index].zEndPointId, rE->zEndPointId); - duplicate_string(p->routeElement[index].linkId, rE->linkId); - duplicate_string(p->routeElement[index].aTopologyId, rE->aTopologyId); - duplicate_string(p->routeElement[index].zTopologyId, rE->zTopologyId); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief This function compares ap and rootPath. If all the links are equal between both ap and rootPath till the sN, then the link from sN to next node - * ap is returned - * - * @params ap - * @params p - * @params sN - * @params e - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gboolean matching_path_rootPath (struct compRouteOutputItem_t *ap, struct compRouteOutputItem_t *rootPath, struct nodes_t *sN, struct edges_t *e) { - gint j = 0; - gboolean ret = FALSE; - while ((j < ap->numRouteElements) && (j < rootPath->numRouteElements)) { - if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0) && - //(memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) != 0) && - (memcmp (sN->nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0)) { - duplicate_node_id (&ap->routeElement[j].aNodeId, &e->aNodeId); - duplicate_node_id (&ap->routeElement[j].zNodeId, &e->zNodeId); - duplicate_string(e->aEndPointId, ap->routeElement[j].aEndPointId); - duplicate_string(e->zEndPointId, ap->routeElement[j].zEndPointId); - duplicate_string(e->linkId, ap->routeElement[j].linkId); - return TRUE; - } - if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0) && - (memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) == 0)) { - j++; - continue; - } - - if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) != 0) || - (memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) != 0)) { - //DEBUG_PC ("ap and rootPath not in the same path"); - return ret; - } - } - return ret; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief This function is used to modify the graph to be used for running the subsequent SP computations acording to the YEN algorithm principles - * - * @params g - * @params A - * @params rootPath - * @params spurNode - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void modify_targeted_graph (struct graph_t *g, struct path_set_t *A, struct compRouteOutputItem_t * rootPath, struct nodes_t * spurNode) { - //DEBUG_PC ("Modify the Targeted graph according to the Yen algorithm principles"); - for (gint j = 0; j < A->numPaths; j++) { - struct compRouteOutputItem_t *ap = &A->paths[j]; - struct edges_t *e = create_edge(); - gboolean ret = FALSE; - ret = matching_path_rootPath (ap, rootPath, spurNode, e); - if (ret == TRUE) { - DEBUG_PC ("Removal %s[%s] --> %s[%s] from the graph", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, e->aEndPointId); - remove_edge_from_graph (g, e); - //DEBUG_PC ("Print Resulting Graph"); - print_graph (g); - g_free (e); - } - if (ret == FALSE) { - g_free (e); - continue; - } - } - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Supporting fucntion to Check if a nodeId is already in the items of a given GList - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint find_nodeId (gconstpointer data, gconstpointer userdata) -{ - /** check values */ - g_assert(data != NULL); - g_assert(userdata != NULL); - - struct nodeItem_t *SNodeId = (struct nodeItem_t *)data; - guchar * nodeId = (guchar *)userdata; - - //DEBUG_PC ("SNodeId (%s) nodeId (%s)", SNodeId->node.nodeId, nodeId); - - if (!memcmp(SNodeId->node.nodeId, nodeId, strlen (SNodeId->node.nodeId))) - { - return (0); - } - return -1; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Explores the link between u and v - * - * @param u - * @param v - * @param g - * @param s - * @param S - * @param Q - * @param mapNodes - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struct graph_t *g, - struct service_t *s, GList **S, GList **Q, struct map_nodes_t *mapNodes, - guint arg) { - g_assert(g); g_assert(s); g_assert(mapNodes); - - struct targetNodes_t *v = &(g->vertices[indexGraphU].targetedVertices[indexGraphV]); - DEBUG_PC("Explored Link %s => %s)", u->node.nodeId, v->tVertice.nodeId); - //DEBUG_PC("\t %s => %s", u->node.nodeId, v->tVertice.nodeId); - - // v already explored in S? then, discard it - GList *found = g_list_find_custom (*S, v->tVertice.nodeId, find_nodeId); - if (found != NULL) { - DEBUG_PC ("v (%s) in S, Discard", v->tVertice.nodeId); - return 0; - } - - // Get the set of constraints imposed by the service - struct path_constraints_t* path_constraints = get_path_constraints(s); - gdouble distance_through_u = INFINITY_COST ,latency_through_u = INFINITY_COST, power_through_u = INFINITY_COST; - gint i = 0, foundAvailBw = 0; - // BANDWIDTH requirement to be fulfilled on EDGE u->v - gdouble edgeAvailBw = 0.0, edgeTotalBw = 0.0; - for (i = 0; i < v->numEdges; i++) { - struct edges_t *e = &(v->edges[i]); - memcpy (&edgeAvailBw, &(e->availCap), sizeof (gdouble)); - memcpy(&edgeTotalBw, &(e->totalCap), sizeof(gdouble)); - DEBUG_PC("EDGE %s[%s] => %s[%s]", u->node.nodeId, e->aEndPointId, v->tVertice.nodeId, e->zEndPointId); - //DEBUG_PC ("\t %s[%s] =>", u->node.nodeId, e->aEndPointId); - //DEBUG_PC("\t => %s[%s]", v->tVertice.nodeId, e->zEndPointId); - DEBUG_PC("\t AvailBw: %f, TotalBw: %f", edgeAvailBw, edgeTotalBw); - // Check Service Bw constraint - if ((path_constraints->bw == TRUE) && (edgeAvailBw < path_constraints->bwConstraint)) - continue; - else { - foundAvailBw = 1; - break; - } - } - // BW constraint NOT MET, then DISCARD edge - if ((path_constraints->bw == TRUE) && (foundAvailBw == 0)) { - DEBUG_PC ("AvailBw: %f < path_constraint: %f -- Discard Edge", edgeAvailBw, path_constraints->bwConstraint); - g_free(path_constraints); - return 0; - } - - gint indexEdge = i; // get the index for the explored edge - // Update distance, latency and availBw through u to reach v - gint map_uIndex = get_map_index_by_nodeId (u->node.nodeId, mapNodes); - struct map_t *u_map = &mapNodes->map[map_uIndex]; - distance_through_u = u_map->distance + v->edges[indexEdge].cost; - latency_through_u = u_map->latency + v->edges[indexEdge].delay; - // Consumed power at v through u is the sum - // 1. Power from src to u - // 2. Power-idle at node u - // 3. power consumed over the edge between u and v, i.e. energy*usedBw - power_through_u = u_map->power + g->vertices[indexGraphU].power_idle + ((edgeTotalBw - edgeAvailBw + path_constraints->bwConstraint) * (v->edges[indexEdge].energy)); - gdouble availBw_through_u = 0.0; - - // ingress endpoint (u) is the src of the request - if (strcmp (u->node.nodeId, s->service_endpoints_id[0].device_uuid) == 0) { - //DEBUG_PC ("AvailBw %f on %s --> %s", edgeAvailBw, u->node.nodeId, v->tVertice.nodeId); - memcpy (&availBw_through_u, &edgeAvailBw, sizeof (gdouble)); - } - else { - // Get the minimum available bandwidth between the src-->u and the new added edge u-->v - //DEBUG_PC ("Current AvailBw: %f from src to %s", u_map->avaiBandwidth, u->node.nodeId); - //DEBUG_PC ("AvailBw: %f %s --> %s", edgeAvailBw, u->node.nodeId, v->tVertice.nodeId); - if (u_map->avaiBandwidth <= edgeAvailBw) { - memcpy (&availBw_through_u, &u_map->avaiBandwidth, sizeof (gdouble)); - } - else { - memcpy (&availBw_through_u, &edgeAvailBw, sizeof (gdouble)); - } - } - // Relax the link according to the pathCost, latency, and energy - gint map_vIndex = get_map_index_by_nodeId (v->tVertice.nodeId, mapNodes); - struct map_t *v_map = &mapNodes->map[map_vIndex]; - // If cost dist (u, v) > dist (src, v) relax the link - if (distance_through_u > v_map->distance) { - //DEBUG_PC ("dist(src, u) + dist(u, v): %f > dist (src, v): %f --> Discard Link", distance_through_u, v_map->distance); - return 0; - } - // If energy consumption optimization is requested - if (arg & ENERGY_EFFICIENT_ARGUMENT) { - if (distance_through_u == v_map->distance) { - if (power_through_u > v_map->power) { - DEBUG_PC("Energy (src -> u + u -> v: %f (Watts) >Energy (src, v): %f (Watts)--> DISCARD LINK", power_through_u, v_map->power); - return 0; - } - // same energy consumption, consider latency - if ((power_through_u == v_map->power) && (latency_through_u > v_map->latency)) { - return 0; - } - if ((power_through_u == v_map->power) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { - return 0; - } - } - } // No optimization, rely on latency and available e2e bandwidth - else { - // If dist (src, u) + dist (u, v) = current dist(src, v), then use the latency as discarding criteria - if ((distance_through_u == v_map->distance) && (latency_through_u > v_map->latency)) { - //DEBUG_PC ("dist(src, u) + dist(u,v) = current dist(src, v), but latency (src,u) + latency (u, v) > current latency (src, v)"); - return 0; - } - // If dist (src, u) + dist (u,v) == current dist(src, v) AND latency (src, u) + latency (u, v) == current latency (src, v), the available bandwidth is the criteria - if ((distance_through_u == v_map->distance) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { - return 0; - } - } - DEBUG_PC ("%s --> %s Relaxed", u->node.nodeId, v->tVertice.nodeId); - DEBUG_PC ("\t AvailBw: %f Mb/s, Cost: %f, Latency: %f ms, Energy: %f Watts", availBw_through_u, distance_through_u, latency_through_u, power_through_u); - - // Update Q list -- - struct nodeItem_t *nodeItem = g_malloc0 (sizeof (struct nodeItem_t)); - if (nodeItem == NULL) { - DEBUG_PC ("memory allocation failed\n"); - exit (-1); - } - nodeItem->distance = distance_through_u; - memcpy(&nodeItem->distance, &distance_through_u, sizeof(gdouble)); - memcpy(&nodeItem->latency, &latency_through_u, sizeof(gdouble)); - memcpy(&nodeItem->power, &power_through_u, sizeof(gdouble)); - duplicate_node_id (&v->tVertice, &nodeItem->node); - // add node to the Q list - if (arg & ENERGY_EFFICIENT_ARGUMENT) { - *Q = g_list_insert_sorted(*Q, nodeItem, sort_by_energy); - } - else - *Q = g_list_insert_sorted (*Q, nodeItem, sort_by_distance); - - // Update the mapNodes for the specific reached tv - v_map->distance = distance_through_u; - memcpy(&v_map->distance, &distance_through_u, sizeof(gdouble)); - memcpy (&v_map->avaiBandwidth, &availBw_through_u, sizeof (gdouble)); - memcpy (&v_map->latency, &latency_through_u, sizeof (gdouble)); - memcpy(&v_map->power, &power_through_u, sizeof(gdouble)); - // Duplicate the predecessor edge into the mapNodes - struct edges_t *e1 = &(v_map->predecessor); - struct edges_t *e2 = &(v->edges[indexEdge]); - duplicate_edge(e1, e2); - DEBUG_PC ("u->v Edge: %s(%s) --> %s(%s)", e2->aNodeId.nodeId, e2->aEndPointId, e2->zNodeId.nodeId, e2->zEndPointId); - //DEBUG_PC("v-pred aTopology: %s", e2->aTopologyId); - DEBUG_PC("v-pred zTopology: %s", e2->zTopologyId); - - // Check whether v is dstPEId - //DEBUG_PC ("Targeted dstId: %s", s->service_endpoints_id[1].device_uuid); - //DEBUG_PC ("nodeId added to the map: %s", v_map->verticeId.nodeId); - //DEBUG_PC ("Q Length: %d", g_list_length(*Q)); - g_free(path_constraints); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Check the feasability of a path wrt the constraints imposed by the request in terms of latency - * - * @param s - * @param p - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gboolean check_computed_path_feasability (struct service_t *s, struct compRouteOutputItem_t* p) { - float epsilon = 0.0000001; - struct path_constraints_t* pathCons = get_path_constraints(s); - gboolean ret = TRUE; - if (pathCons->latency == TRUE) { - if ((pathCons->latencyConstraint - p->delay > 0.0) || (fabs(pathCons->latencyConstraint - p->delay) < epsilon)) { - DEBUG_PC("Computed Path (latency: %f) is feasible wrt Connection Demand: %f", p->delay, pathCons->latencyConstraint); - } - else { - DEBUG_PC("Computed Path (latency: %f) is NOT feasible wrt Connection Demand: %f", p->delay, pathCons->latencyConstraint); - g_free(pathCons); - return FALSE; - } - } - // Other constraints... - g_free(pathCons); - return ret; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Sorting the GList Q items by distance - * - * @param a - * @param b - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint sort_by_distance (gconstpointer a, gconstpointer b) { - //DEBUG_PC ("sort by distance a and b"); - g_assert(a != NULL); - g_assert(b != NULL); - - //DEBUG_PC ("sort by distance a and b"); - struct nodeItem_t *node1 = (struct nodeItem_t *)a; - struct nodeItem_t *node2 = (struct nodeItem_t *)b; - g_assert (node1); - g_assert (node2); - - //DEBUG_PC ("a->distance %u; b->distance %u", node1->distance, node2->distance); - //DEBUG_PC("a->latency: %f; b->latency: %f", node1->latency, node2->latency); - //1st criteria, sorting by lowest distance - if (node1->distance > node2->distance) - return 1; - else if (node1->distance < node2->distance) - return 0; - if (node1->distance == node2->distance) { - if (node1->latency > node2->latency) - return 1; - else if (node1->latency <= node2->latency) - return 0; - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Sorting the GList Q items by distance - * - * @param a - * @param b - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gint sort_by_energy(gconstpointer a, gconstpointer b) { - g_assert(a != NULL); - g_assert(b != NULL); - - //DEBUG_PC ("sort by distance a and b"); - struct nodeItem_t* node1 = (struct nodeItem_t*)a; - struct nodeItem_t* node2 = (struct nodeItem_t*)b; - g_assert(node1); - g_assert(node2); - - //1st criteria: sorting by lowest distance - if (node1->distance > node2->distance) - return 1; - if (node1->distance < node2->distance) - return 0; - - // 2nd Criteria: sorting by the lowest energy - if (node1->power > node2->power) - return 1; - if (node1->power < node1->power) - return 0; - - // 3rd Criteria: by the latency - if (node1->latency > node2->latency) - return 1; - if (node1->latency <= node2->latency) - return 0; - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Allocate memory for graph - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct graph_t * create_graph () { - struct graph_t * g = g_malloc0 (sizeof (struct graph_t)); - if (g == NULL) { - DEBUG_PC ("Memory Allocation Problem"); - exit (-1); - } - return g; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Allocate memory for mapNodes - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct map_nodes_t * create_map_node () { - struct map_nodes_t * mN = g_malloc0 (sizeof (struct map_nodes_t)); - if (mN == NULL) { - DEBUG_PC ("Memory allocation failed"); - exit (-1); - } - return mN; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Look up for the service in the servieList bound to a serviceUUID - * - * @params serviceUUID - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct service_t* get_service_for_computed_path(gchar* serviceUUID) { - gint i = 0; - for(GList *listnode = g_list_first(serviceList); - listnode; - listnode = g_list_next(listnode), i++) { - struct service_t* s = (struct service_t*)(listnode->data); - if (strcmp(s->serviceId.service_uuid, serviceUUID) == 0) - return s; - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the service type - * - * @param type - * - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_service_type(guint type) { - switch (type) { - case SERVICE_TYPE_UNKNOWN: - DEBUG_PC("Service Type UNKNOWN"); - break; - case SERVICE_TYPE_L3NM: - DEBUG_PC("Service Type L3NM"); - break; - case SERVICE_TYPE_L2NM: - DEBUG_PC("Service Type L2NM"); - break; - case SERVICE_TYPE_TAPI: - DEBUG_PC("Service Type L2NM"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the port direction - * - * @param direction - * - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_link_port_direction(guint direction) { - switch (direction) { - case LINK_PORT_DIRECTION_BIDIRECTIONAL: - //DEBUG_PC("Bidirectional Port Direction"); - break; - case LINK_PORT_DIRECTION_INPUT: - //DEBUG_PC("Input Port Direction"); - break; - case LINK_PORT_DIRECTION_OUTPUT: - //DEBUG_PC("Output Port Direction"); - break; - case LINK_PORT_DIRECTION_UNKNOWN: - //DEBUG_PC("Unknown Port Direction"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the port termination direction - * - * @param direction - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_termination_direction(guint direction) { - switch (direction) { - case TERMINATION_DIRECTION_BIDIRECTIONAL: - //DEBUG_PC("Bidirectional Termination Direction"); - break; - case TERMINATION_DIRECTION_SINK: - //DEBUG_PC("Input Termination Direction"); - break; - case TERMINATION_DIRECTION_SOURCE: - //DEBUG_PC("Output Termination Direction"); - break; - case TERMINATION_DIRECTION_UNKNOWN: - //DEBUG_PC("Unknown Termination Direction"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the termination state - * - * @param state - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_termination_state(guint state) -{ - switch (state) { - case TERMINATION_STATE_CAN_NEVER_TERMINATE: - //DEBUG_PC("Can never Terminate"); - break; - case TERMINATION_STATE_NOT_TERMINATED: - DEBUG_PC("Not terminated"); - break; - case TERMINATION_STATE_TERMINATED_SERVER_TO_CLIENT_FLOW: - DEBUG_PC("Terminated server to client flow"); - break; - case TERMINATION_STATE_TERMINATED_CLIENT_TO_SERVER_FLOW: - DEBUG_PC("Terminated client to server flow"); - break; - case TERMINATION_STATE_TERMINATED_BIDIRECTIONAL: - //DEBUG_PC("Terminated bidirectional"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the capacity unit - * - * @param unit - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_capacity_unit(guint unit) { - - switch (unit) { - case CAPACITY_UNIT_TB: - DEBUG_PC("Unit in TB"); - break; - case CAPACITY_UNIT_TBPS: - DEBUG_PC("Unit in TB/s"); - break; - case CAPACITY_UNIT_GB: - DEBUG_PC("Unit in GB"); - break; - case CAPACITY_UNIT_GBPS: - DEBUG_PC("Unit in GB/s"); - break; - case CAPACITY_UNIT_MB: - DEBUG_PC("Unit in MB"); - break; - case CAPACITY_UNIT_MBPS: - //DEBUG_PC("Unit in MB/s"); - break; - case CAPACITY_UNIT_KB: - DEBUG_PC("Unit in KB"); - break; - case CAPACITY_UNIT_KBPS: - DEBUG_PC("Unit in KB/s"); - break; - case CAPACITY_UNIT_GHZ: - DEBUG_PC("Unit in GHz"); - break; - case CAPACITY_UNIT_MHZ: - DEBUG_PC("Unit in MHz"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the link forwarding direction - * - * @param linkFwDir - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_link_forwarding_direction(guint linkFwDir) { - switch (linkFwDir) { - case LINK_FORWARDING_DIRECTION_BIDIRECTIONAL: - DEBUG_PC("BIDIRECTIONAL LINK FORWARDING DIRECTION"); - break; - case LINK_FORWARDING_DIRECTION_UNIDIRECTIONAL: - DEBUG_PC("UNIDIRECTIONAL LINK FORWARDING DIRECTION"); - break; - case LINK_FORWARDING_DIRECTION_UNKNOWN: - DEBUG_PC("UNKNOWN LINK FORWARDING DIRECTION"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Search a specific contextUuid element into the contextSet - * - * @param contextUuid - * @param set - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct context_t* find_contextId_in_set(gchar* contextUuid, GList** set) { - //DEBUG_PC("Checking if contextId: %s in in the ContextSet??", contextUuid); - gint i = 0; - for (GList *ln = g_list_first(*set); - ln; - ln = g_list_next(ln)){ - struct context_t* c = (struct context_t*)(ln->data); - //DEBUG_PC("Context Item [%d] Id: %s", i, c->contextId); - if (strcmp(contextUuid, c->contextId) == 0) { - //DEBUG_PC("contextId: %s is FOUND in the ContextSet_List", contextUuid); - return c; - } - i++; - } - //DEBUG_PC("contextId: %s NOT FOUND in the ContextSet_List", contextUuid); - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Add a specific context uuid into the context set - * - * @param contextUuid - * @param set - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct context_t* add_contextId_in_set(gchar *contextUuid, GList** set) { - - struct context_t* c = g_malloc0(sizeof(struct context_t)); - if (c == NULL) { - DEBUG_PC("Memory Allocation Failure"); - exit(-1); - } - duplicate_string(c->contextId, contextUuid); - // Add the context into the context set - //DEBUG_PC("Adding ContextId: %s", contextUuid); - //DEBUG_PC(" (BEFORE ADDING) Context Set Length: %d", g_list_length(*set)); - *set = g_list_append(*set, c); - //DEBUG_PC(" (AFTER ADDING) Context Set Length: %d", g_list_length(*set)); - return c; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Find a vertex in a specific graph - * - * @param contextUuid - * @param set - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct vertices_t* find_vertex_in_graph_context(struct graph_t *g, gchar* deviceId) { - for (gint i = 0; i < g->numVertices; i++) { - struct vertices_t* v = &(g->vertices[i]); - if (strcmp(v->verticeId.nodeId, deviceId) == 0) { - return v; - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Adding a deviceId into a graph - * - * @param g - * @param deviceId - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct vertices_t* add_vertex_in_graph(struct graph_t* g, struct device_t *d) { - g->numVertices++; - struct vertices_t* v = &(g->vertices[g->numVertices - 1]); - duplicate_string(v->verticeId.nodeId, d->deviceId); - memcpy(&v->power_idle, &d->power_idle, sizeof(gdouble)); - return v; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Construct the graphs (vertices and edges) bound to every individual context - * - * @param cSet - * @param activeFlag - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void build_contextSet_deviceList(GList** cSet, gint activeFlag) { - // Check every device their endpoints - for (GList* listnode = g_list_first(deviceList); - listnode; - listnode = g_list_next(listnode)) { - struct device_t* d = (struct device_t*)(listnode->data); - //DEBUG_PC("Exploring DeviceId: %s", d->deviceId); - - if ((activeFlag == 1) && (d->operational_status != 2)) { - // it is only considered devices with operational status enabled, i.e., set to 2 - continue; - } - // Check the associated endPoints - for (gint j = 0; j < d->numEndPoints; j++) { - struct endPoint_t* eP = &(d->endPoints[j]); - // Get endPointId (topology, context, device Id and endpoint uuid) - struct endPointId_t* ePid = &(eP->endPointId); //end point id - //DEBUG_PC(" EndPointId: %s || Type: %s", eP->endPointId.endpoint_uuid, d->deviceType); - //DEBUG_PC(" TopologyId: %s || ContextId: %s", eP->endPointId.topology_id.topology_uuid, eP->endPointId.topology_id.contextId); - // Add contextId in ContextSet and the deviceId (+endpoint) into the vertex set - struct context_t *c = find_contextId_in_set(eP->endPointId.topology_id.contextId, cSet); - if (c == NULL) { - DEBUG_PC(" contextUuid: %s MUST BE ADDED to ContextSet", eP->endPointId.topology_id.contextId); - c = add_contextId_in_set(eP->endPointId.topology_id.contextId, cSet); - } - // Check if the deviceId and endPointUuid are already considered in the graph of the context c - struct vertices_t* v = find_vertex_in_graph_context(&c->g, d->deviceId); - if (v == NULL) { - //DEBUG_PC(" deviceId: %s MUST BE ADDED to the Context Graph", d->deviceId); - v = add_vertex_in_graph(&c->g, d); - } - } - } - //print_contextSet(cSet); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Determine whether a deviceId is in the targetNode list of a specific vertex v - * - * @param v - * @param deviceId - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct targetNodes_t* find_targeted_vertex_in_graph_context(struct vertices_t* v, gchar *deviceId) { - for (gint k = 0; k < v->numTargetedVertices; k++) { - struct targetNodes_t* w = &(v->targetedVertices[k]); - if (strcmp(w->tVertice.nodeId, deviceId) == 0) { - return w; - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Add a deviceId a targetNode of a specific vertex v - * - * @param v - * @param deviceId - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct targetNodes_t* add_targeted_vertex_in_graph_context(struct vertices_t* v, gchar* bDeviceId) { - v->numTargetedVertices++; - struct targetNodes_t* w = &(v->targetedVertices[v->numTargetedVertices - 1]); - duplicate_string(w->tVertice.nodeId, bDeviceId); - return w; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Returns the structure of a device endpoint bound to a specific deviceId and endPointId - * - * @param devId - * @param endPointUuid - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct endPoint_t* find_device_tied_endpoint(gchar* devId, gchar* endPointUuid) { - //DEBUG_PC("devId: %s ePId: %s", devId, endPointUuid); - for (GList* ln = g_list_first(deviceList); - ln; - ln = g_list_next(ln)) { - struct device_t* d = (struct device_t*)(ln->data); - if (strcmp(d->deviceId, devId) != 0) { - continue; - } - // Iterate over the endpoints tied to the deviceId - for (gint j = 0; j < d->numEndPoints; j++) { - struct endPoint_t* eP = &(d->endPoints[j]); - //DEBUG_PC("looked endPointId: %s", eP->endPointId.endpoint_uuid); - if (strcmp(eP->endPointId.endpoint_uuid, endPointUuid) == 0) { - return eP; - } - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Adding the edge/linnk in the targetedNodes w list - * - * @param w - * @param l - * @param activeFlag - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void add_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l, gint activeFlag) { - //DEBUG_PC("\t targetedVertex: %s", w->tVertice.nodeId); - - // Check if the activeFlag is 1. If YES, it is only added to the edges as long as the - // associated endPoint is in status ENABLED, i.e., with operational status set to 2 - // Get the endpoints (A and Z) of the link l (assumed P2P) - struct link_endpointId_t* aEndpointId = &(l->linkEndPointId[0]); - struct link_endpointId_t* zEndpointId = &(l->linkEndPointId[1]); - // Get the endPoint Information tied to the device bound to aEndPointId - struct endPoint_t* eP = find_device_tied_endpoint(aEndpointId->deviceId, aEndpointId->endPointId); - if (eP == NULL) { - DEBUG_PC("devId: %s endPointUuid: %s NOT in Device List!!--- Weird", aEndpointId->deviceId, aEndpointId->endPointId); - exit(-1); - } - // Check whether the port in that endPoint (eP) is Active upon the activeFlag being SET - if (activeFlag == 1) { - if (eP->operational_status != 2) // NOT ENABLED, then discard this link - return; - } - - // Add the edge into the graph - w->numEdges++; - struct edges_t* e = &(w->edges[w->numEdges - 1]); - // Copy the link Id UUID - duplicate_string(e->linkId, l->linkId); - duplicate_string(e->aNodeId.nodeId, aEndpointId->deviceId); - duplicate_string(e->aEndPointId, aEndpointId->endPointId); - duplicate_string(e->aTopologyId, aEndpointId->topology_id.topology_uuid); - duplicate_string(e->zNodeId.nodeId, zEndpointId->deviceId); - duplicate_string(e->zEndPointId, zEndpointId->endPointId); - duplicate_string(e->zTopologyId, zEndpointId->topology_id.topology_uuid); - - //Potential(total) and available capacity - e->unit = eP->potential_capacity.unit; - memcpy(&e->totalCap, &eP->potential_capacity.value, sizeof(gdouble)); - memcpy(&e->availCap, &eP->available_capacity.value, sizeof(gdouble)); - // Copy interdomain local/remote Ids - memcpy(e->interDomain_localId, eP->inter_domain_plug_in.inter_domain_plug_in_local_id, - strlen(eP->inter_domain_plug_in.inter_domain_plug_in_local_id)); - memcpy(e->interDomain_remoteId, eP->inter_domain_plug_in.inter_domain_plug_in_remote_id, - strlen(eP->inter_domain_plug_in.inter_domain_plug_in_remote_id)); - // cost value - memcpy(&e->cost, &l->cost_characteristics.cost_value, sizeof(gdouble)); - // latency ms - memcpy(&e->delay, &l->latency_characteristics.fixed_latency, sizeof(gdouble)); - // energy J/bits ~ power - memcpy(&e->energy, &eP->energyConsumption, sizeof(gfloat)); - - //DEBUG_PC("Edge - Total/Available Capacity: %f/%f; Cost: %f; Delay: %f, Energy: %f", eP->potential_capacity.value, eP->available_capacity.value, - // l->cost_characteristics.cost_value, l->latency_characteristics.fixed_latency, l->energy_link); - - //DEBUG_PC("Graph Edge - Total/Available Capacity: %f/%f; Cost: %f; Delay: %f, Energy: %f", e->totalCap, e->availCap, - // e->cost, e->delay, e->energy); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Searching a specific edge/link by the linkId(UUID) - * - * @param w - * @param l - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct edges_t* find_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l) { - for (gint i = 0; i < w->numEdges; i++) { - struct edges_t* e = &(w->edges[i]); - if (strcmp(e->linkId, l->linkId) == 0) { - return e; - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief supporting the construction of the graph per context using the explicit - * contents/info of the link list - * - * @param set - * @param activeFlag - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void build_contextSet_linklList(GList** set, gint activeFlag) { - // for each link in linkList: - // 1st- Retrieve endpoints A --> B feauture (context Id, device Id, endpoint Id) - // 2st - In the graph associated to the contextId, check wheter A (deviceId) is in the vertices list - // o No, this is weird ... exist - // o Yes, get the other link endpoint (i.e., B) and check whether it exists. If NOT add it, considering - // all the attributes; Otherwise, check whether the link is different from existing edges between A and B - gdouble epsilon = 0.1; - gint j = 0; - for (GList* ln = g_list_first(linkList); - ln; - ln = g_list_next(ln)) { - struct link_t* l = (struct link_t*)(ln->data); - j++; - - // link assumed to be P2P A --> B; i.e. 2 endPoints; 1st specifies A and 2nd specifie B - struct link_endpointId_t* aEndpointId = &(l->linkEndPointId[0]); - struct topology_id_t* topologyId = &(aEndpointId->topology_id); - // get the contextId - gchar contextUuid[UUID_CHAR_LENGTH]; - duplicate_string(contextUuid, topologyId->contextId); - DEBUG_PC("Link: %s in ContextId: %s", l->linkId, contextUuid); - - // Check first contextUuid exists in the cSet - //DEBUG_PC("Length of Context: %d", g_list_length(set)); - struct context_t* c = find_contextId_in_set(contextUuid, set); - if (c == NULL) { - DEBUG_PC("ContextId: %s does NOT exist... weird", contextUuid); - exit(-1); - } - - // get the device ID of A - gchar aDeviceId[UUID_CHAR_LENGTH]; - duplicate_string(aDeviceId, aEndpointId->deviceId); - - struct graph_t* g = &(c->g); // get the graph associated to the context c - struct vertices_t* v = find_vertex_in_graph_context(g, aDeviceId); - if (v == NULL) { - DEBUG_PC("%s NOT a VERTEX of contextId: %s ... WEIRD", aDeviceId, contextUuid); - exit(-1); - } - // get the bEndpointId - struct link_endpointId_t* bEndpointId = &(l->linkEndPointId[1]); - gchar bDeviceId[UUID_CHAR_LENGTH]; - duplicate_string(bDeviceId, bEndpointId->deviceId); - DEBUG_PC("[%d] -- Link: %s [%s ==> %s]", j-1, l->linkId, aDeviceId, bDeviceId); - // Check whether device B is in the targeted Vertices from A (i.e., v)? - // If not, add B in the targeted vertices B + create the edge and add it - // If B exist, check whether the explored link/edge is already in the list of edges - struct targetNodes_t* w = find_targeted_vertex_in_graph_context(v, bDeviceId); - if (w == NULL) { - DEBUG_PC("[%s] is PEER of [%s]", bDeviceId, v->verticeId.nodeId); - w = add_targeted_vertex_in_graph_context(v, bDeviceId); - add_edge_in_targetedVertice_set(w, l, activeFlag); - } - else { - // w exists, it is needed to check whether the edge (link) should be added - struct edges_t* e = find_edge_in_targetedVertice_set(w, l); - if (e == NULL) { - // Add the link into the list - add_edge_in_targetedVertice_set(w, l, activeFlag); - } - else { - DEBUG_PC("The link already exists ..."); - continue; - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Create the set of (distinct) contexts with the deviceList and linkList - * - * @param cSet - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void build_contextSet(GList** cSet) { - gint activeFlag = 0; // this means that all the devices/links (regardless they are active or not) are considered - - // devices are tied to contexts, i.e. depending on the contextId of the devices - build_contextSet_deviceList(cSet, activeFlag); - - DEBUG_PC("Length for the Context Set: %d", g_list_length(*cSet)); - - // Once the diverse contexts are created and the devices/endpoints asigned to the - // respective graph tied to each context, it is needed to create the edges - build_contextSet_linklList(cSet, activeFlag); - - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Create the set of (distinct) contexts with the deviceList and linkList with - * operational status active - * - * @param cSet - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void build_contextSet_active(GList** cSet) { - gint activeFlag = 1; // this means that all the devices (regardless they are active or not) are considered - - // devices are tied to contexts, i.e. depending on the contextId of the devices - build_contextSet_deviceList(cSet, activeFlag); - - DEBUG_PC("Length for the Context Set: %d", g_list_length(*cSet)); - - // Once the diverse contexts are created and the devices/endpoints asigned to the - // respective graph tied to each context, it is needed to create the edges - build_contextSet_linklList(cSet, activeFlag); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Print the contents of the ContextIds - * - * @param set - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_contextSet(GList* set) { - - DEBUG_PC("Printing the ContextSet w/ number of Elements: %d", g_list_length(set)); - - for (GList* ln = g_list_first(set); - ln; - ln = g_list_next(ln)) { - struct context_t* c = (struct context_t*)(ln->data); - DEBUG_PC("-------------------------------------------------------------"); - DEBUG_PC(" Context Id: %s", c->contextId); - DEBUG_PC("-------------------------------------------------------------"); - - struct graph_t* g = &(c->g); - for (gint j = 0; j < g->numVertices; j++) { - struct vertices_t* v = &(g->vertices[j]); - DEBUG_PC(" Head Device Id: %s", v->verticeId.nodeId); - for (gint k = 0; k < v->numTargetedVertices; k++) { - struct targetNodes_t* w = &(v->targetedVertices[k]); - DEBUG_PC(" [%d] --- Peer Device Id: %s", k, w->tVertice.nodeId); - for (gint l = 0; l < w->numEdges; l++) { - struct edges_t* e = &(w->edges[l]); - DEBUG_PC(" \t link Id: %s", e->linkId); - DEBUG_PC(" \t aEndPointId: %s", e->aEndPointId); - DEBUG_PC(" \t zEndPointId: %s", e->zEndPointId); - DEBUG_PC(" \t Available Capacity: %f, Latency: %f, Cost: %f", e->availCap, e->delay, e->cost); - DEBUG_PC(" \t aTopologyId: %s", e->aTopologyId); - DEBUG_PC(" \t zTopologyId: %s", e->zTopologyId); - } - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Check whether src and dst PE nodeId of the req are the same - * - * @param r - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint same_src_dst_pe_nodeid(struct service_t* s) -{ - // Check that source PE and dst PE are NOT the same, i.e., different ingress and egress endpoints (iEp, eEp) - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); - struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); - - gchar* iEpUUID = iEp->endpoint_uuid; - gchar* eEpUUID = eEp->endpoint_uuid; - gchar* iDevUUID = iEp->device_uuid; - gchar* eDevUUID = eEp->device_uuid; - - // Compare the device uuids - if (strcmp(iDevUUID, eDevUUID) != 0) { - DEBUG_PC("DIFFERENT --- iDevId: %s and eDevId: %s", iDevUUID, eDevUUID); - return 1; - } - // Compare the endpoints (ports) - if (strcmp(iEpUUID, eEpUUID) != 0) { - DEBUG_PC("DIFFERENT --- iEpUUID: %s and eEpUUID: %s", iEpUUID, eEpUUID); - return 1; - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Handles issues with the route computation - * - * @param route - * @param s - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void comp_route_connection_issue_handler (struct compRouteOutput_t *path, struct service_t *s) -{ - g_assert(path); g_assert(s); - - // Increase the number of computed routes/paths despite there was an issue to be reported - path->numPaths++; - // Copy the serviceId - copy_service_id(&(path->serviceId), &(s->serviceId)); - - // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) - for (gint i = 0; i < s->num_service_endpoints_id; i++) { - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); - struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); - copy_service_endpoint_id(oEp, iEp); - } - path->num_service_endpoints_id = s->num_service_endpoints_id; - path->noPathIssue = NO_PATH_CONS_ISSUE; - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief released the allocated memory fo compRouteOutputList_t - * - * @param ro - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void destroy_compRouteOutputList (struct compRouteOutputList_t *ro) -{ - g_assert (ro); - g_free (ro); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief creates a copy of the underlying graph - * - * @param originalGraph - * @param destGraph - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_graph (struct graph_t *originalGraph, struct graph_t *destGraph) { - g_assert (originalGraph); g_assert (destGraph); - - destGraph->numVertices = originalGraph->numVertices; - for (gint i = 0; i < originalGraph->numVertices; i++) { - struct vertices_t *oVertex = &(originalGraph->vertices[i]); - struct vertices_t *dVertex = &(destGraph->vertices[i]); - dVertex->numTargetedVertices = oVertex->numTargetedVertices; - duplicate_node_id (&oVertex->verticeId, &dVertex->verticeId); - memcpy(&dVertex->power_idle, &oVertex->power_idle, sizeof(gdouble)); - - for (gint j = 0; j < oVertex->numTargetedVertices; j++) { - struct targetNodes_t *oTargetedVertex = &(oVertex->targetedVertices[j]); - struct targetNodes_t *dTargetedVertex = &(dVertex->targetedVertices[j]); - duplicate_node_id (&oTargetedVertex->tVertice, &dTargetedVertex->tVertice); - dTargetedVertex->numEdges = oTargetedVertex->numEdges; - - for (gint k = 0; k < oTargetedVertex->numEdges; k++) { - struct edges_t *oEdge = &(oTargetedVertex->edges[k]); - struct edges_t *dEdge = &(dTargetedVertex->edges[k]); - duplicate_edge (dEdge, oEdge); - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to retrieve from the graph the edge instance associated to the - * pathLink (pL) - * - * @param pL - * @parma g - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct edges_t* get_edge_from_graph_by_linkId(struct pathLink_t* pL, struct graph_t* g) { - g_assert(pL); - g_assert(g); - - for (gint i = 0; i < g->numVertices; i++) { - struct vertices_t* v = &(g->vertices[i]); - for (gint j = 0; j < v->numTargetedVertices; j++) { - struct targetNodes_t* tv = &(v->targetedVertices[j]); - for (gint k = 0; k < tv->numEdges; k++) { - struct edges_t* e = &(tv->edges[k]); - if (strcmp(e->linkId, pL->linkId) == 0) { - return e; - } - } - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to retrieve from the graph the reverse edge (rev_e) associated to an edge (e) - * - * @param e - * @parma g - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct edges_t* get_reverse_edge_from_the_graph(struct edges_t* e, struct graph_t* g) { - g_assert(e); - g_assert(g); - - for (gint i = 0; i < g->numVertices; i++) { - struct vertices_t* v = &(g->vertices[i]); - // Check Route Element zNodeId with the v->verticeId - if (compare_node_id(&e->zNodeId, &v->verticeId) != 0) - continue; - // Check Route Element zNodeis with any of reachable targeted vertices from v - gboolean foundTargVert = FALSE; - gint indexTargVert = -1; - for (gint j = 0; j < v->numTargetedVertices; j++) { - struct targetNodes_t* tv = &(v->targetedVertices[j]); - if (compare_node_id(&e->aNodeId, &tv->tVertice) == 0) - { - foundTargVert = TRUE; - indexTargVert = j; - break; - } - } - if (foundTargVert == FALSE) { - continue; - } - - // The targeted vertice is found, then check matching with the endpoints - struct targetNodes_t* tv = &(v->targetedVertices[indexTargVert]); - for (gint k = 0; k < tv->numEdges; k++) { - struct edges_t* rev_e = &(tv->edges[k]); - if ((strcmp(rev_e->aEndPointId, e->zEndPointId) == 0) && - (strcmp(rev_e->zEndPointId, e->aEndPointId) == 0)) { - return rev_e; - } - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to reflect in the graph the assigned/allocated resources contained in the path p - * considering the needs (e.g., bandwidth) of service s - * - * @param p - * @param s - * @parma g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void allocate_graph_resources (struct path_t *p, struct service_t *s, struct graph_t *g) -{ - g_assert (p); g_assert (s); g_assert (g); - // Retrieve the requested bw by the service - struct path_constraints_t* pathCons = get_path_constraints(s); - - for (gint i = 0; i < p->numPathLinks; i++) { - struct pathLink_t* pL = &(p->pathLinks[i]); - // get the edge associated to the linkId in the graph - struct edges_t* e = get_edge_from_graph_by_linkId(pL, g); - if (e == NULL) { - DEBUG_PC("The linkId: %s is NOT found in the Graph!!!", pL->linkId); - exit(-1); - } - //Update the availBw in the edge - gdouble resBw = e->availCap - pathCons->bwConstraint; - DEBUG_PC("Updating the Avail Bw @ edge/link: %s", e->linkId); - DEBUG_PC("Initial avaiCap @ e/link: %f, demanded Bw: %f, resulting Avail Bw: %f", e->availCap, pathCons->bwConstraint, resBw); - memcpy(&e->availCap, &resBw, sizeof(gdouble)); - DEBUG_PC("Final e/link avail Bw: %f", e->availCap); - } - g_free(pathCons); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to reflect in the graph the assigned/allocated resources contained in the reverse direction of the path p - * considering the needs (e.g., bandwidth) of service s - * - * @param p - * @param s - * @parma g - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void allocate_graph_reverse_resources(struct path_t* p, struct service_t * s, struct graph_t* g) -{ - g_assert(p); g_assert(s); g_assert(g); - - struct path_constraints_t* pathCons = get_path_constraints(s); - for (gint i = 0; i < p->numPathLinks; i++) { - struct pathLink_t* pL = &(p->pathLinks[i]); - struct edges_t* e = get_edge_from_graph_by_linkId(pL, g); - if (e == NULL) { - DEBUG_PC("The linkId: %s is NOT found in the Graph!!!", pL->linkId); - exit(-1); - } - struct edges_t* rev_e = get_reverse_edge_from_the_graph(e, g); - if (rev_e == NULL) { - DEBUG_PC("the reverse edge of linkId: %s is NOT found in the Graph!!!", pL->linkId); - exit(-1); - } - //Update the availBw in the edge - gdouble resBw = rev_e->availCap - pathCons->bwConstraint; - DEBUG_PC("Updating the Avail Bw @ reverse edge/link: %s", rev_e->linkId); - DEBUG_PC("Initial avaiCap @ reverse edge e/link: %f, demanded Bw: %f, resulting Avail Bw: %f", rev_e->availCap, pathCons->bwConstraint, resBw); - memcpy(&rev_e->availCap, &resBw, sizeof(gdouble)); - DEBUG_PC("Final reverse edge e/link avail Bw: %f", rev_e->availCap); - } - g_free(pathCons); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to printall the computed paths for the requested network connectivity services - * - * @param routeList - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_path_connection_list(struct compRouteOutputList_t* routeList) { - g_assert(routeList); - for (gint i = 0; i < routeList->numCompRouteConnList; i++) { - DEBUG_PC("==================== Service instance: %d ===================", i); - struct compRouteOutput_t* rO = &(routeList->compRouteConnection[i]); - DEBUG_PC("num service endpoints: %d", rO->num_service_endpoints_id); - struct serviceId_t* s = &(rO->serviceId); - DEBUG_PC("ContextId: %s, ServiceId: %s", s->contextId, s->service_uuid); - DEBUG_PC("ingress - %s[%s]", rO->service_endpoints_id[0].device_uuid, - rO->service_endpoints_id[0].endpoint_uuid); - DEBUG_PC("egress - %s [%s]", rO->service_endpoints_id[1].device_uuid, - rO->service_endpoints_id[1].endpoint_uuid); - - if (rO->noPathIssue == NO_PATH_CONS_ISSUE) { - DEBUG_PC("NO PATH SUCCESSFULLY COMPUTED"); - continue; - } - // Path - DEBUG_PC("Number of paths: %d", rO->numPaths); - for (gint j = 0; j < rO->numPaths; j++) { - struct path_t* p = &(rO->paths[j]); - print_path_t(p); - } - } - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief update statistics for the path computation operations - * - * @param routeConnList - * @param d - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void update_stats_path_comp(struct compRouteOutputList_t* routeConnList, struct timeval d, gint numSuccesPathComp, gint numPathCompIntents) { - g_assert(routeConnList); - - total_path_comp_time.tv_sec = total_path_comp_time.tv_sec + d.tv_sec; - total_path_comp_time.tv_usec = total_path_comp_time.tv_usec + d.tv_usec; - total_path_comp_time = tv_adjust(total_path_comp_time); - - gdouble path_comp_time_msec = (((total_path_comp_time.tv_sec) * 1000) + ((total_path_comp_time.tv_usec) / 1000)); - gdouble av_alg_comp_time = ((path_comp_time_msec / numSuccesPathComp)); - DEBUG_PC("\t --- STATS PATH COMP ----"); - DEBUG_PC("Succesfully Comp: %d | Path Comp Requests: %d", numSuccesPathComp, numPathCompIntents); - DEBUG_PC("AV. PATH COMP ALG. TIME: %f ms", av_alg_comp_time); - - gint i = 0; - for (GList* listnode = g_list_first(serviceList); - listnode; - listnode = g_list_next(listnode), i++) { - struct service_t* s = (struct service_t*)(listnode->data); - char* eptr; - for (gint j = 0; j < s->num_service_constraints; j++) { - struct constraint_t* constraints = &(s->constraints[j]); - if (strncmp((const char*)(constraints->constraint_type), "bandwidth", 9) == 0) { - totalReqBw += (gdouble)(strtod((char*)constraints->constraint_value, &eptr)); - } - } - } - - for (gint k = 0; k < routeConnList->numCompRouteConnList; k++) { - struct compRouteOutput_t* rO = &(routeConnList->compRouteConnection[k]); - if (rO->noPathIssue == NO_PATH_CONS_ISSUE) { - continue; - } - // Get the requested service bw bound to that computed path - struct path_t* p = &(rO->paths[0]); - struct service_t* s = get_service_for_computed_path(rO->serviceId.service_uuid); - if (s == NULL) { - DEBUG_PC("Weird the service associated to a path is not found"); - exit(-1); - } - for (gint l = 0; l < s->num_service_constraints; l++) { - struct constraint_t* constraints = &(s->constraints[l]); - char* eptr; - if (strncmp((const char*)(constraints->constraint_type), "bandwidth", 9) == 0) { - totalServedBw += (gdouble)(strtod((char*)constraints->constraint_value, &eptr)); - } - } - } - gdouble avServedRatio = totalServedBw / totalReqBw; - DEBUG_PC("AV. Served Ratio: %f", avServedRatio); - gdouble avBlockedBwRatio = (gdouble)(1.0 - avServedRatio); - DEBUG_PC("AV. BBE: %f", avBlockedBwRatio); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate active service path - * - * @param actServPath - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_active_service_path(struct activeServPath_t* actServPath) { - g_assert(actServPath); - g_free(actServPath); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate active service - * - * @param actService - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_active_service(struct activeService_t* actService) { - g_assert(actService); - g_list_free_full(g_steal_pointer(&actService->activeServPath), (GDestroyNotify)destroy_active_service_path); - g_free(actService); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate a requested service - * - * @param s - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_requested_service(struct service_t* s) { - g_assert(s); - g_free(s); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate a device - * - * @param d - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_device(struct device_t* d) { - g_assert(d); - g_free(d); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate a link from the linkList - * - * @param d - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_link(struct link_t* l) { - g_assert(l); - g_free(l); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate a context from the contextSet - * - * @param d - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_context(struct context_t* c) { - g_assert(c); - g_free(c); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Excecution Dijkstra algorithm - * - * @param srcMapIndex - * @param dstMapIndex - * @param g - * @param s - * @param mapNodes - * @param SN - * @param RP - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void dijkstra(gint srcMapIndex, gint dstMapIndex, struct graph_t* g, struct service_t* s, - struct map_nodes_t* mapNodes, struct nodes_t* SN, struct compRouteOutputItem_t* RP, - guint arg) { - g_assert(s);g_assert(g); - - // Set params into mapNodes related to the source nodes of the request - mapNodes->map[srcMapIndex].distance = 0.0; - mapNodes->map[srcMapIndex].latency = 0.0; - mapNodes->map[srcMapIndex].avaiBandwidth = 0.0; - mapNodes->map[srcMapIndex].power = 0.0; - - // Initialize the set Q and S - GList *S = NULL, *Q = NULL; - gint indexVertice = -1; - - // Add the source into the Q - struct nodeItem_t* nodeItem = g_malloc0(sizeof(struct nodeItem_t)); - if (nodeItem == NULL) { - DEBUG_PC("memory allocation failed\n"); - exit(-1); - } - // initialize some nodeItem attributes - nodeItem->distance = 0.0; - nodeItem->latency = 0.0; - nodeItem->power = 0.0; - duplicate_node_id(&mapNodes->map[srcMapIndex].verticeId, &nodeItem->node); - - // Select the optimization process - if (arg & ENERGY_EFFICIENT_ARGUMENT) - Q = g_list_insert_sorted(Q, nodeItem, sort_by_energy); - // more "if" according to different optimization criteria ... - else - Q = g_list_insert_sorted(Q, nodeItem, sort_by_distance); - - // Check whether there is spurNode (SN) and rootPath (RP) - if (SN != NULL && RP != NULL) { - struct routeElement_t* re; - for (gint j = 0; j < RP->numRouteElements; j++) { - // Get the source and target Nodes of the routeElement within the rootPath - re = &RP->routeElement[j]; - DEBUG_PC("root Link: aNodeId: %s (%s) --> zNodeiId: %s (%s)", re->aNodeId.nodeId, re->aEndPointId, re->zNodeId.nodeId, re->zEndPointId); - - // if ingress of the root link (aNodeId) is the spurNode, then stops - if (compare_node_id(&re->aNodeId, SN) == 0) { - DEBUG_PC("root Link: aNodeId: %s and spurNode: %s -- stop exploring the rootPath (RP)", re->aNodeId.nodeId, SN->nodeId); - break; - } - // Extract from Q - GList* listnode = g_list_first(Q); - struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); - Q = g_list_remove(Q, node); - - //DEBUG_RL_RA ("Exploring node %s", node->node.nodeId); - indexVertice = graph_vertice_lookup(node->node.nodeId, g); - g_assert(indexVertice >= 0); - - // Get the indexTargetedVertice - gint indexTVertice = -1; - indexTVertice = graph_targeted_vertice_lookup(indexVertice, re->zNodeId.nodeId, g); - gint done = check_link(node, indexVertice, indexTVertice, g, s, &S, &Q, mapNodes, arg); - (void)done; - // Add to the S list - S = g_list_append(S, node); - } - // Check that the first node in Q set is SpurNode, otherwise something went wrong ... - if (compare_node_id(&re->aNodeId, SN) != 0) { - //DEBUG_PC ("root Link: aNodeId: %s is NOT the spurNode: %s -- something wrong", re->aNodeId.nodeId, SN->nodeId); - g_list_free_full(g_steal_pointer(&S), g_free); - g_list_free_full(g_steal_pointer(&Q), g_free); - return; - } - } - - while (g_list_length(Q) > 0) { - //Extract from Q set - GList* listnode = g_list_first(Q); - struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); - Q = g_list_remove(Q, node); - DEBUG_PC("Q length: %d", g_list_length(Q)); - DEBUG_PC("DeviceId: %s", node->node.nodeId); - - // visit all the links from u within the graph - indexVertice = graph_vertice_lookup(node->node.nodeId, g); - g_assert(indexVertice >= 0); - - // Check the targeted vertices from u - for (gint i = 0; i < g->vertices[indexVertice].numTargetedVertices; i++) { - gint done = check_link(node, indexVertice, i, g, s, &S, &Q, mapNodes, arg); - (void)done; - } - // Add node into the S Set - S = g_list_append(S, node); - //DEBUG_PC ("S length: %d", g_list_length (S)); - } - g_list_free_full(g_steal_pointer(&S), g_free); - g_list_free_full(g_steal_pointer(&Q), g_free); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief KSP computation using Dijkstra algorithm - * - * @param pred - * @param g - * @param s - * @param SN - * @param RP - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gint ksp_comp(struct pred_t* pred, struct graph_t* g, struct service_t* s, - struct nodes_t* SN, struct compRouteOutputItem_t* RP, - struct map_nodes_t* mapNodes, guint arg) { - g_assert(pred); g_assert(g); g_assert(s); - - DEBUG_PC("Source: %s -- Destination: %s", s->service_endpoints_id[0].device_uuid, s->service_endpoints_id[1].device_uuid); - - // Check the both ingress src and dst endpoints are in the graph - gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); - if (srcMapIndex == -1) { - DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); - return -1; - } - - gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); - if (dstMapIndex == -1) { - DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); - return -1; - } - - //DEBUG_PC("srcMapIndex: %d (node: %s)", srcMapIndex, mapNodes->map[srcMapIndex].verticeId.nodeId); - //DEBUG_PC("dstMapIndex: %d (node: %s)", dstMapIndex, mapNodes->map[dstMapIndex].verticeId.nodeId); - - // Compute the shortest path route - dijkstra(srcMapIndex, dstMapIndex, g, s, mapNodes, SN, RP, arg); - - // Check that a feasible solution in term of latency and bandwidth is found - gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); - struct map_t* dest_map = &mapNodes->map[map_dstIndex]; - if (!(dest_map->distance < INFINITY_COST)) { - DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); - return -1; - } - - DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); - // Check that the computed available bandwidth is larger than 0.0 - if (dest_map->avaiBandwidth <= (gfloat)0.0) { - DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); - return -1; - } - DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); - // Handle predecessors - build_predecessors(pred, s, mapNodes); - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief set the path parameters (e.g., latency, cost, power, ...) to an under-constructed - * path from the computed map vertex - * - * @param p - * @param mapV - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void set_path_attributes(struct compRouteOutputItem_t* p, struct map_t* mapV) { - g_assert(p); g_assert(mapV); - memcpy(&p->cost, &mapV->distance, sizeof(gdouble)); - memcpy(&p->availCap, &mapV->avaiBandwidth, sizeof(mapV->avaiBandwidth)); - memcpy(&p->delay, &mapV->latency, sizeof(mapV->latency)); - memcpy(&p->power, &mapV->power, sizeof(gdouble)); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief K-CSPF algorithm execution (YEN algorithm) - * - * @param s - * @param path - * @param g - * @param optimization_flag - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g, guint arg) { - g_assert(s); g_assert(path); g_assert(g); - - // create map of devices/nodes to handle the path computation using the context - struct map_nodes_t* mapNodes = create_map_node(); - build_map_node(mapNodes, g); - - // predecessors to store the computed path - struct pred_t* predecessors = create_predecessors(); - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); - struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); - - // Compute the 1st KSP path - gint done = ksp_comp(predecessors, g, s, NULL, NULL, mapNodes, arg); - if (done == -1) { - DEBUG_PC("NO PATH for %s[%s] --> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); - comp_route_connection_issue_handler(path, s); - g_free(mapNodes); g_free(predecessors); - return; - } - - // Construct the path from the computed predecessors - struct compRouteOutputItem_t* p = create_path_item(); - //print_predecessors(predecessors); - build_path(p, predecessors, s); - gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); - struct map_t* dst_map = &mapNodes->map[indexDest]; - // Get the delay and cost - set_path_attributes(p, dst_map); - - // Add the computed path, it may be a not feasible path, but at the end it is - // checked all the feasible paths, and select the first one - print_path(p); - - // Copy the serviceId - copy_service_id(&path->serviceId, &s->serviceId); - // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) - for (gint i = 0; i < s->num_service_endpoints_id; i++) { - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); - struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); - copy_service_endpoint_id(oEp, iEp); - } - path->num_service_endpoints_id = s->num_service_endpoints_id; - - DEBUG_PC("COMPUTE UP TO K Feasible Paths A[%d]", MAX_KSP_VALUE); - // Create A and B sets of paths to handle the YEN algorithm - struct path_set_t *A = create_path_set(), *B = create_path_set(); - // Add 1st Computed path into A->paths[0] - duplicate_path(p, &A->paths[0]); - A->numPaths++; - g_free(predecessors); g_free(p); - for (gint k = 1; k < MAX_KSP_VALUE; k++) { - DEBUG_PC("*************************** kth (%d) ***********************************", k); - struct compRouteOutputItem_t* p = create_path_item(); - duplicate_path(&A->paths[k - 1], p); - // The spurNode ranges from near-end node of the first link to the near-end of the last link forming the kth path - gint i = 0; - struct compRouteOutputItem_t* rootPath = create_path_item(); - for (i = 0; i < p->numRouteElements; i++) { - struct nodes_t *spurNode = create_node(), *nextSpurNode = create_node(); - struct routeElement_t* re = &(p->routeElement[i]); - // Create predecessors to store the computed path - struct pred_t* predecessors = create_predecessors(); - // Clear previous mapNodes, i.e. create it again - g_free(mapNodes); - mapNodes = create_map_node(); - build_map_node(mapNodes, g); - struct nodes_t* n = &re->aNodeId; - duplicate_node_id(n, spurNode); - n = &re->zNodeId; - duplicate_node_id(n, nextSpurNode); - DEBUG_PC("spurNode: %s --> nextSpurNode: %s", spurNode->nodeId, nextSpurNode->nodeId); - - // rootPath contains a set of links of A[k-1] from the source Node till the SpurNode -> NextSpurNode - // Example: A[k-1] = {L1, L2, L3, L4}, i.e. " Node_a -- L1 --> Node_b -- L2 --> Node_c -- L3 --> Node_d -- L4 --> Node_e " - // E.g., for the ith iteration if the spurNode = Node_c and NextSpurNode = Node_d; then rootPath = {L1, L2, L3} - add_routeElement_path_back(re, rootPath); - DEBUG_PC("\n"); - DEBUG_PC("^^^^^^^rootPath^^^^^^^"); - print_path(rootPath); - - // For all existing and computed paths p in A check if from the source to the NextSpurNode - // the set of links matches with those contained in the rootPath - // If YES, remove from the auxiliary graph the next link in p from NextSpurNode - // Otherwise do nothing - struct graph_t* gAux = create_graph(); - duplicate_graph(g, gAux); - // Modified graph - modify_targeted_graph(gAux, A, rootPath, spurNode); - - // Trigger the computation of the path from src to dst constrained to traverse all the links from src - // to spurNode contained into rootPath over the resulting graph - if (ksp_comp(predecessors, gAux, s, spurNode, rootPath, mapNodes, arg) == -1) { - DEBUG_PC("FAILED SP from %s via spurNode: %s to %s", iEp->device_uuid, spurNode->nodeId, eEp->device_uuid); - g_free(nextSpurNode); g_free(spurNode); - g_free(gAux); g_free(predecessors); - continue; - } - DEBUG_PC("SUCCESFUL SP from %s via spurNode: %s to %s", iEp->device_uuid, spurNode->nodeId, eEp->device_uuid); - // Create the node list from the predecessors - struct compRouteOutputItem_t* newKpath = create_path_item(); - build_path(newKpath, predecessors, s); - DEBUG_PC("new K (for k: %d) Path is built", k); - gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); - struct map_t* dst_map = &mapNodes->map[indexDest]; - set_path_attributes(newKpath, dst_map); - DEBUG_PC("New PATH (@ kth: %d) ADDED to B[%d] - {Path Cost: %f, e2e latency: %f, bw: %f, Power: %f ", k, B->numPaths, newKpath->cost, - newKpath->delay, newKpath->availCap, newKpath->power); - // Add the computed kth SP to the heap B - duplicate_path(newKpath, &B->paths[B->numPaths]); - B->numPaths++; - DEBUG_PC("Number of B paths: %d", B->numPaths); - - g_free(newKpath); g_free(nextSpurNode); g_free(spurNode); - g_free(gAux); g_free(predecessors); - } - // If B is empty then stops - if (B->numPaths == 0) { - DEBUG_PC("B does not have any path ... the stops kth computation"); - break; - } - - // Sort the potential B paths according to different optimization parameters - sort_path_set(B, arg); - // Add the lowest path into A[k] - DEBUG_PC("-------------------------------------------------------------"); - DEBUG_PC("Append SP for B[0] to A[%d] --- Cost: %f, Latency: %f, Power: %f", A->numPaths, B->paths[0].cost, - B->paths[0].delay, B->paths[0].power); - duplicate_path(&B->paths[0], &A->paths[A->numPaths]); - A->numPaths++; - DEBUG_PC("A Set size: %d", A->numPaths); - DEBUG_PC("-------------------------------------------------------------"); - - // Remove/Pop front element from the path set B (i.e. remove B[0]) - pop_front_path_set(B); - DEBUG_PC("B Set Size: %d", B->numPaths); - } - - // Copy the serviceId - copy_service_id(&path->serviceId, &s->serviceId); - // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) - for (gint m = 0; m < s->num_service_endpoints_id; m++) { - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[m]); - struct service_endpoints_id_t* oEp = &(s->service_endpoints_id[m]); - copy_service_endpoint_id(oEp, iEp); - } - - // Print all the paths i A - for (gint h = 0; h < A->numPaths; h++) { - DEBUG_PC("================== A[%d] =======================", h); - print_path(&A->paths[h]); - } - DEBUG_PC("Number of paths: %d", path->numPaths); - // For all the computed paths in A, pick the one being feasible wrt the service constraints - for (gint ksp = 0; ksp < A->numPaths; ksp++) { - if (ksp >= MAX_KSP_VALUE) { - DEBUG_PC("Number Requested paths (%d) REACHED - STOP", ksp); - break; - } - gdouble feasibleRoute = check_computed_path_feasability(s, &A->paths[ksp]); - if (feasibleRoute == TRUE) { - DEBUG_PC("A[%d] available: %f, pathCost: %f; latency: %f, Power: %f", ksp, A->paths[ksp].availCap, A->paths[ksp].cost, A->paths[ksp].delay, A->paths[ksp].power); - struct compRouteOutputItem_t* pathaux = &A->paths[ksp]; - path->numPaths++; - struct path_t* targetedPath = &path->paths[path->numPaths - 1]; - duplicate_path_t(pathaux, targetedPath); - print_path_t(targetedPath); - remove_path_set(A); - remove_path_set(B); - return; - } - } - remove_path_set(A); - remove_path_set(B); - // No paths found --> Issue - DEBUG_PC("K-SP failed!!!"); - comp_route_connection_issue_handler(path, s); - return; +//////////////////////////////////////////////////////////////////////////////////////// +/** + * # Copyright 2022 Centre Tecnològic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es + * + * 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. + + * Author: CTTC/CERCA PONS RU Ricardo Martínez (ricardo.martinez@cttc.es) + */ +///////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathComp_log.h" +#include "pathComp.h" +#include "pathComp_tools.h" + +gint numPathCompIntents = 0; // number of events triggering the path computation +//gint numSuccesPathComp = 0; // number of events resulting in succesfully path computations fulfilling the constraints +struct timeval total_path_comp_time; +gdouble totalReqBw = 0.0; +gdouble totalServedBw = 0.0; + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function for time processing + * + * @param a + * + * @author Ricardo Martínez + * @date 2022 + */ + //////////////////////////////////////////////////////////////////////////////////////// +struct timeval tv_adjust (struct timeval a) { + while (a.tv_usec >= 1000000) { + a.tv_usec -= 1000000; + a.tv_sec++; + } + while (a.tv_usec < 0) { + a.tv_usec += 1000000; + a.tv_sec--; + } + return a; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief friendly function to copy safely strings + * + * @param dst + * @param src + * + * @author Ricardo Martínez + * @date 2022 + */ + //////////////////////////////////////////////////////////////////////////////////////// +void duplicate_string(gchar* dst, gchar* src) { + g_assert(dst); g_assert(src); + strcpy(dst, src); + dst[strlen(dst)] = '\0'; + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to print the computed the path + * + * @param path + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void print_path (struct compRouteOutputItem_t *p) { + g_assert(p); + DEBUG_PC ("=========== COMPUTED PATH ======================="); + DEBUG_PC ("E2E Avail. Bw: %f, Latency: %f, Cost: %f, Consumed Power (in W): %f", p->availCap, p->delay, p->cost, p->power); + for (gint k = 0; k < p->numRouteElements; k++) { + DEBUG_PC ("%s[%s] --> %s[%s]", p->routeElement[k].aNodeId.nodeId, p->routeElement[k].aEndPointId, + p->routeElement[k].zNodeId.nodeId, p->routeElement[k].zEndPointId); + DEBUG_PC("\t linkId: %s", p->routeElement[k].linkId); + DEBUG_PC("\t aTopologyId: %s", p->routeElement[k].aTopologyId); + DEBUG_PC("\t zTopologyId: %s", p->routeElement[k].zTopologyId); + } + DEBUG_PC ("=================================================================="); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to print the output path formed by link Ids + * + * @param p + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_path_t(struct path_t* p) { + g_assert(p); + DEBUG_PC(" ============ COMPUTED OUTPUT PATH ================="); + DEBUG_PC("Path AvailBw: %f, Cost: %f, Latency: %f, Power: %f", p->path_capacity.value, + p->path_cost.cost_value, p->path_latency.fixed_latency, p->path_power.power); + DEBUG_PC("number of links of path %d", p->numPathLinks); + for (gint k = 0; k < p->numPathLinks; k++) { + DEBUG_PC("Link: %s", p->pathLinks[k].linkId); + for (gint l = 0; l < p->pathLinks[k].numLinkTopologies; l++) { + DEBUG_PC("end Link [%d] TopologyId: %s", l, p->pathLinks[k].linkTopologies[l].topologyId); + } + DEBUG_PC(" ContextId: %s", p->pathLinks[k].topologyId.contextId); + DEBUG_PC(" TopologyUUid: %s", p->pathLinks[k].topologyId.topology_uuid); + DEBUG_PC(" aDeviceId: %s", p->pathLinks[k].aDeviceId); + DEBUG_PC(" aEndpointId: %s", p->pathLinks[k].aEndPointId); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used allocate memory for struct path_t + * + * + * @author Ricardo Martínez + * @date 2022 + */ + //////////////////////////////////////////////////////////////////////////////////////// +struct path_t* create_path() { + struct path_t* p = g_malloc0(sizeof(struct path_t)); + if (p == NULL) { + DEBUG_PC("Memory allocation failure"); + exit(-1); + } + return(p); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Returns the char (36 bytes) format of a uuid + * + * @param uuid + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gchar* get_uuid_char(uuid_t uuid) { + gchar* uuidChar = g_malloc0(16); // uuid has 36 chars + if (uuidChar == NULL) { + DEBUG_PC("Memory Allocation failure"); + exit(-1); + } + uuid_unparse(uuid, (char *)uuidChar); + return uuidChar; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Makes a copy of the service identifier (including the context) + * + * @param o + * @param i + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void copy_service_id(struct serviceId_t* o, struct serviceId_t* i) { + g_assert(o); g_assert(i); + memcpy(o->contextId, i->contextId, sizeof(i->contextId)); + memcpy(o->service_uuid, i->service_uuid, sizeof(i->service_uuid)); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Makes a copy of the service endpoint identifier (including the topology (contect and topology id), device and endpoint (port)) + * + * @param oEp + * @param iEp + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void copy_service_endpoint_id(struct service_endpoints_id_t* oEp, struct service_endpoints_id_t* iEp) { + g_assert(oEp); g_assert(iEp); + + // copy topology information + memcpy(oEp->topology_id.contextId, iEp->topology_id.contextId, sizeof(iEp->topology_id.contextId)); + memcpy(oEp->topology_id.topology_uuid, iEp->topology_id.topology_uuid, sizeof(iEp->topology_id.topology_uuid)); + + // copy the endpoint + memcpy(oEp->device_uuid, iEp->device_uuid, sizeof(iEp->device_uuid)); + memcpy(oEp->endpoint_uuid, iEp->endpoint_uuid, sizeof(iEp->endpoint_uuid)); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief From the set of contexts, it is returned the graph associated to that context matching + * with the passed contextId. + * + * @param Set + * @param contextId + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct graph_t* get_graph_by_contextId(GList* set, gchar* contextId) { + g_assert(contextId); + + // iterate over the set of context. Pick the one matching with contextId, and return the graph. + // If not found, return NULL + struct graph_t* g = NULL; + for (GList *ln = g_list_first(set); + ln; + ln = g_list_next(ln)){ + struct context_t* context = (struct context_t*)(ln->data); + if (strcmp(context->contextId, contextId) == 0) { + g = &(context->g); + return g; + } + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Process the service constraint and maps them into the path constraints + * to be fulfilled + * + * @param path_constraints + * @param s + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct path_constraints_t * get_path_constraints(struct service_t* s) { + g_assert(s); + + struct path_constraints_t* path_constraints = g_malloc0(sizeof(struct path_constraints_t)); + if (path_constraints == NULL) { + DEBUG_PC("Memory Allocation Failure"); + exit(-1); + } + + char* eptr; + for (gint i = 0; i < s->num_service_constraints; i++) { + struct constraint_t* constraint = &(s->constraints[i]);; + if (strncmp((const char*)constraint->constraint_type, "bandwidth", 9) == 0) { + path_constraints->bwConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); + path_constraints->bw = TRUE; + //DEBUG_PC("Path Constraint Bw: %f", path_constraints->bwConstraint); + } + if (strncmp((const char*)constraint->constraint_type, "cost", 4) == 0) { + path_constraints->costConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); + path_constraints->cost = TRUE; + //DEBUG_PC("Path Constraint Cost: %f", path_constraints->costConstraint); + } + if (strncmp((const char*)constraint->constraint_type, "latency", 7) == 0) { + path_constraints->latencyConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); + path_constraints->latency = TRUE; + //DEBUG_PC("Path Constraint Latency: %f", path_constraints->latencyConstraint); + } + if (strncmp((const char*)constraint->constraint_type, "energy", 6) == 0) { + path_constraints->energyConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); + path_constraints->energy = TRUE; + //DEBUG_PC("Path Constraint Energy: %f", path_constraints->energyConstraint); + } + } + return path_constraints; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Creates the predecessors to keep the computed path + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct pred_t * create_predecessors () { + struct pred_t *predecessors = g_malloc0 (sizeof (struct pred_t)); + if (predecessors == NULL) { + DEBUG_PC ("memory allocation failed\n"); + exit (-1); + } + return predecessors; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief create edge + * + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct edges_t* create_edge() { + struct edges_t* e = g_malloc0(sizeof(struct edges_t)); + if (e == NULL) { + DEBUG_PC("Memory allocation failed\n"); + exit(-1); + } + return e; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Prints the list of the predecessors for a given computed Shortest Path + * + * @param p + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void print_predecessors (struct pred_t *p) +{ + g_assert (p); + DEBUG_PC ("Number of Predecessors: %d", p->numPredComp); + for (gint i = 0; i < p->numPredComp; i++) { + struct pred_comp_t *pComp = &(p->predComp[i]); + DEBUG_PC ("deviceId: %s", pComp->v.nodeId); + struct edges_t *e = &(pComp->e); + DEBUG_PC("Edge[#%d] (linkId): %s", i, e->linkId); + DEBUG_PC ("\t %s[%s] ===>", e->aNodeId.nodeId, e->aEndPointId); + DEBUG_PC("\t %s[%s]", e->zNodeId.nodeId, e->zEndPointId); + DEBUG_PC("\t aTopologyId: %s", e->aTopologyId); + DEBUG_PC("\t zTopologyId: %s", e->zTopologyId); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Builds the list of predecessors for the request destination using the computed Shortest Path + * being stored in map + * + * @param p + * @param s + * @param map + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void build_predecessors (struct pred_t *p, struct service_t *s, struct map_nodes_t *map) { + g_assert (p); g_assert (s); g_assert (map); + + struct nodes_t *v = create_node(); + duplicate_string(v->nodeId, s->service_endpoints_id[1].device_uuid); + + struct edges_t *e = create_edge(); + get_edge_from_map_by_node (e, v, map); + + // Get u (being source of edge e) + struct nodes_t u; + duplicate_node_id (&e->aNodeId, &u); + + // Add to the predecessors list + struct pred_comp_t *pred = &(p->predComp[p->numPredComp]); + duplicate_node_id (&u, &pred->v); + struct edges_t *e1 = &(pred->e); + duplicate_edge (e1, e); + p->numPredComp++; + // Back-trace edges till reaching the srcPEId + struct nodes_t* srcNode = create_node(); + duplicate_string(srcNode->nodeId, s->service_endpoints_id[0].device_uuid); + + while (compare_node_id (&u, srcNode) != 0) { + duplicate_node_id (&u, v); + get_edge_from_map_by_node (e, v, map); + // Get the u (being source of edge e) + duplicate_node_id (&e->aNodeId, &u); + // Get the new predecessor + struct pred_comp_t *pred = &p->predComp[p->numPredComp]; + // Add to the predecessors list + duplicate_node_id (&u, &pred->v); + struct edges_t *e1 = &(pred->e); + duplicate_edge (e1, e); + p->numPredComp++; + } + print_predecessors (p); + g_free (e); g_free(v); g_free(srcNode); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief It creates a struct nodes_t + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct nodes_t * create_node () +{ + struct nodes_t *n = g_malloc0 (sizeof (struct nodes_t)); + if (n == NULL) { + DEBUG_PC ("memory allocation problem"); + exit (-1); + } + return n; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief It creates a routeElement_t + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct routeElement_t * create_routeElement () { + struct routeElement_t *rE = g_malloc0 (sizeof (struct routeElement_t)); + if (rE == NULL) { + DEBUG_PC ("memory allocation problem"); + exit (-1); + } + return rE; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief copy node ids + * + * @param src + * @param dst + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_node_id (struct nodes_t *src, struct nodes_t *dst) { + g_assert (src); + g_assert (dst); + //DEBUG_PC ("Duplicate nodeId for %s", src->nodeId); + strcpy (dst->nodeId, src->nodeId); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief compares a pair of node Ids + * + * @param a + * @param b + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint compare_node_id (struct nodes_t *a, struct nodes_t *b) { + g_assert (a); + g_assert (b); + return (memcmp (&a->nodeId, b->nodeId, strlen (b->nodeId))); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief duplicate two routeElement_t + * + * @param src + * @param dst + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_routeElement (struct routeElement_t *src, struct routeElement_t *dst) +{ + g_assert (src); + g_assert (dst); + + duplicate_node_id (&(src->aNodeId), &(dst->aNodeId)); + duplicate_node_id (&(src->zNodeId), &(dst->zNodeId)); + duplicate_string(dst->aEndPointId, src->aEndPointId); + duplicate_string(dst->zEndPointId, src->zEndPointId); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief duplicate two edges + * + * @param e1 (destination) + * @param e2 (source) + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_edge (struct edges_t *e1, struct edges_t *e2) { + g_assert (e1); g_assert (e2); + + duplicate_node_id (&e2->aNodeId, &e1->aNodeId); + duplicate_node_id (&e2->zNodeId, &e1->zNodeId); + //DEBUG_PC ("e->aNodeId: %s ---> e->zNodeId: %s", e1->aNodeId.nodeId, e1->zNodeId.nodeId); + duplicate_string(e1->aEndPointId, e2->aEndPointId); + duplicate_string(e1->zEndPointId, e2->zEndPointId); + duplicate_string(e1->linkId, e2->linkId); + duplicate_string(e1->interDomain_localId, e2->interDomain_localId); + duplicate_string(e1->interDomain_remoteId, e2->interDomain_remoteId); + duplicate_string(e1->aTopologyId, e2->aTopologyId); + duplicate_string(e1->zTopologyId, e2->zTopologyId); + + e1->unit = e2->unit; + memcpy(&e1->totalCap, &e2->totalCap, sizeof(gdouble)); + memcpy(&e1->availCap, &e2->availCap, sizeof(gdouble)); + + memcpy (&e1->cost, &e2->cost, sizeof (gdouble)); + memcpy (&e1->delay, &e2->delay, sizeof (gdouble)); + memcpy(&e1->energy, &e2->energy, sizeof(gdouble)); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Duplicate path + * + * @param a - original + * @param b - copy + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_path (struct compRouteOutputItem_t *a, struct compRouteOutputItem_t *b) { + g_assert (a); g_assert (b); + memcpy(&b->availCap, &a->availCap, sizeof (gdouble)); + memcpy(&b->cost, &a->cost, sizeof(gdouble)); + memcpy(&b->delay, &a->delay, sizeof (gdouble)); + memcpy(&b->power, &a->power, sizeof(gdouble)); + b->numRouteElements = a->numRouteElements; + for (gint k = 0; k < a->numRouteElements; k++) { + //DEBUG_PC ("aNodeId: %s // zNodeId: %s", a->routeElement[k].aNodeId.nodeId, a->routeElement[k].zNodeId.nodeId); + // aNodeId duplication + struct nodes_t *n1 = &(a->routeElement[k].aNodeId); + struct nodes_t *n2 = &(b->routeElement[k].aNodeId); + duplicate_node_id (n1, n2); + //zNodeId duplication + n1 = &(a->routeElement[k].zNodeId); + n2 = &(b->routeElement[k].zNodeId); + duplicate_node_id (n1, n2); + duplicate_string(b->routeElement[k].aEndPointId, a->routeElement[k].aEndPointId); + duplicate_string(b->routeElement[k].zEndPointId, a->routeElement[k].zEndPointId); + duplicate_string(b->routeElement[k].linkId, a->routeElement[k].linkId); + duplicate_string(b->routeElement[k].aTopologyId, a->routeElement[k].aTopologyId); + duplicate_string(b->routeElement[k].zTopologyId, a->routeElement[k].zTopologyId); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Duplicate path from compRouteOutputItem_t to path_t + * + * @param a - original + * @param b - copy + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_path_t(struct compRouteOutputItem_t* a, struct path_t* b) { + g_assert(a); g_assert(b); + + // transfer path characteristics ... + memcpy(&b->path_capacity.value, &a->availCap, sizeof(gdouble)); + memcpy(&b->path_cost.cost_value, &a->cost, sizeof(gdouble)); + memcpy(&b->path_latency.fixed_latency, &a->delay, sizeof(gdouble)); + memcpy(&b->path_power.power, &a->power, sizeof(gdouble)); + + b->numPathLinks = a->numRouteElements; + + for (gint k = 0; k < a->numRouteElements; k++) { + struct routeElement_t* rE = &(a->routeElement[k]); + struct pathLink_t* pL = &(b->pathLinks[k]); + + // copy the aDeviceId and aEndpointId, zDeviceId and zEndPointId + duplicate_string(pL->aDeviceId, rE->aNodeId.nodeId); + duplicate_string(pL->zDeviceId, rE->zNodeId.nodeId); + duplicate_string(pL->aEndPointId, rE->aEndPointId); + duplicate_string(pL->zEndPointId, rE->zEndPointId); + + duplicate_string(pL->topologyId.topology_uuid, rE->aTopologyId); + duplicate_string(pL->topologyId.contextId, rE->contextId); + + //copy the linkId + duplicate_string(pL->linkId, rE->linkId); + pL->numLinkTopologies++; + duplicate_string(pL->linkTopologies[pL->numLinkTopologies - 1].topologyId, rE->aTopologyId); + pL->numLinkTopologies++; + duplicate_string(pL->linkTopologies[pL->numLinkTopologies - 1].topologyId, rE->zTopologyId); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Return the index into mapN related nodeId + * + * @param nodeId + * @para mapN + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint get_map_index_by_nodeId (gchar *nodeId, struct map_nodes_t * mapN) { + gint i = 0; + for (i = 0; i < mapN->numMapNodes; i++) { + //DEBUG_PC ("i: %d; current: %s // targeted: %s", i, mapN->map[i].verticeId.nodeId, nodeId); + if (memcmp (mapN->map[i].verticeId.nodeId, nodeId, strlen (nodeId)) == 0) { + //DEBUG_PC ("Index: %d", i); + return i; + } + } + //DEBUG_PC ("Index: %d", index); + return -1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Get the edge e enabling reaching the computed v in mapNodes + * + * @param e + * @param v + * @param mapN + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void get_edge_from_map_by_node (struct edges_t *e, struct nodes_t* v, struct map_nodes_t *mapN) { + //DEBUG_PC ("Get the Edge into map from node v: %s", v.nodeId); + // Get the edge reaching the node v from mapNodes + gint map_vIndex = get_map_index_by_nodeId (v->nodeId, mapN); + //DEBUG_PC ("aNodeId: %s --> zNodeId: %s", mapN->map[map_vIndex].predecessor.aNodeId.nodeId, mapN->map[map_vIndex].predecessor.zNodeId.nodeId); + struct edges_t *te = &(mapN->map[map_vIndex].predecessor); + duplicate_edge (e, te); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Get the edge from the predecessors array for a given node n + * + * @param e + * @param n + * @param predecessors + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void get_edge_from_predecessors (struct edges_t *e, struct nodes_t* n, struct pred_t *predecessors) { + g_assert(predecessors); + DEBUG_PC ("Get edge outgoing node %s from predecessors list", n->nodeId); + //print_predecessors (predecessors); + for (gint i = 0; i < predecessors->numPredComp; i++) { + struct pred_comp_t *pred = &(predecessors->predComp[i]); + if (compare_node_id (n, &pred->v) == 0) { + // Add to the predecessors list + struct edges_t *te = &(pred->e); + DEBUG_PC("add e (linkId): %s", te->linkId); + duplicate_edge (e, te); + return; + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Construct the path using the predecessors list + * + * @param path + * @param predecessors + * @param s + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void build_path (struct compRouteOutputItem_t *p, struct pred_t *predecessors, struct service_t *s) { + // Get the source device Id of the network connectivity service + struct nodes_t *v = create_node(); + // Src Node of the Service set to v + duplicate_string(v->nodeId, s->service_endpoints_id[0].device_uuid); + + // Get the edge for v in predecessors + struct edges_t* e = create_edge(); + get_edge_from_predecessors (e, v, predecessors); + // Get the target for e + struct nodes_t u; + duplicate_node_id (&e->zNodeId, &u); + //DEBUG_PC ("u: %s", u.nodeId); + struct path_constraints_t* pathCons = get_path_constraints(s); + + // Add route element to the path being constructed + gint k = 0; + duplicate_node_id (&e->aNodeId, &p->routeElement[k].aNodeId); + duplicate_node_id (&e->zNodeId, &p->routeElement[k].zNodeId); + duplicate_string(p->routeElement[k].aEndPointId, e->aEndPointId); + duplicate_string(p->routeElement[k].zEndPointId, e->zEndPointId); + duplicate_string(p->routeElement[k].linkId, e->linkId); + duplicate_string(p->routeElement[k].aTopologyId, e->aTopologyId); + duplicate_string(p->routeElement[k].zTopologyId, e->zTopologyId); + duplicate_string(p->routeElement[k].contextId, s->serviceId.contextId); + p->numRouteElements++; + + // Get Dst Node of connectivity service + struct nodes_t* dst = create_node(); + duplicate_string(dst->nodeId, s->service_endpoints_id[1].device_uuid); + while (compare_node_id (&u, dst) != 0) { + k++; + p->numRouteElements++; + duplicate_node_id (&u, v); + get_edge_from_predecessors (e, v, predecessors); + // Get the target u + duplicate_node_id (&e->zNodeId, &u); + // Add route element to the path being constructed + duplicate_node_id (&e->aNodeId, &p->routeElement[k].aNodeId); + duplicate_node_id (&e->zNodeId, &p->routeElement[k].zNodeId); + duplicate_string(p->routeElement[k].aEndPointId, e->aEndPointId); + duplicate_string(p->routeElement[k].zEndPointId, e->zEndPointId); + duplicate_string(p->routeElement[k].linkId, e->linkId); + duplicate_string(p->routeElement[k].aTopologyId, e->aTopologyId); + duplicate_string(p->routeElement[k].zTopologyId, e->zTopologyId); + duplicate_string(p->routeElement[k].contextId, s->serviceId.contextId); + } + g_free(e); g_free(v); g_free(pathCons); + //DEBUG_PC ("Path is constructed"); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Print the graph for DEBUG_PCging purposes + * + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void print_graph (struct graph_t *g) { + g_assert(g); + DEBUG_PC ("================================================================"); + DEBUG_PC ("=========================== GRAPH =========================="); + DEBUG_PC ("================================================================"); + DEBUG_PC("Graph Num Vertices: %d", g->numVertices); + + for (gint i = 0; i < g->numVertices; i++) { + DEBUG_PC ("Head Vertice [%s]", g->vertices[i].verticeId.nodeId); + for (gint j = 0; j < g->vertices[i].numTargetedVertices; j++) + { + DEBUG_PC (" Tail Vertice: %s", g->vertices[i].targetedVertices[j].tVertice.nodeId); + for (gint k = 0; k < g->vertices[i].targetedVertices[j].numEdges; k++) + { + struct edges_t *e = &(g->vertices[i].targetedVertices[j].edges[k]); + DEBUG_PC ("%s(%s) --> %s(%s) [C: %f, Bw: %f b/s, Delay: %f ms]", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, + e->zEndPointId, e->cost, e->availCap, e->delay); + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Look for a given edge into the graph + * + * @param verticeIndex + * @param targetedVerticeIndex + * @param e + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint graph_edge_lookup (gint verticeIndex, gint targetedVerticeIndex, struct edges_t *e, struct graph_t *g) { + gint indexEdge = -1; + + for (gint j = 0; j < g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex].numEdges; j++) { + struct edges_t *e2 = &(g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex].edges[j]); + if ((compare_node_id (&e->aNodeId, &e2->aNodeId) == 0) && + (compare_node_id (&e->zNodeId, &e2->zNodeId) == 0) && + (strcmp (e->aEndPointId, e2->aEndPointId) == 0) && + (strcmp (e->zEndPointId, e2->zEndPointId) == 0) && + (strcmp(e->linkId, e2->linkId) == 0)) { + DEBUG_PC ("%s (%s) --> %s (%s) [linkId: %s] FOUND in the Graph at index: %d", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, + e->zEndPointId, e->linkId, j); + indexEdge = j; + return indexEdge; + } + } + return indexEdge; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Look for a given vertice within the graph using the nodeId + * + * @param nodeId + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint graph_vertice_lookup (gchar *nodeId, struct graph_t *g) +{ + gint index = -1; + //DEBUG_PC("Searching Node: %s", nodeId); + for (gint i = 0; i < g->numVertices; i++) { + //DEBUG_PC("Checked Graph Node: %s", g->vertices[i].verticeId.nodeId); + if (memcmp (g->vertices[i].verticeId.nodeId, nodeId, strlen (nodeId)) == 0) + { + index = i; + //DEBUG_PC ("%s is found in the graph vertice [%d]", nodeId, index); + break; + } + } + return (index); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Check if a nodeId is already considered into the set of targeted vertices from a given vertice + * + * @param nodeId + * @param vIndex + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint graph_targeted_vertice_lookup (gint vIndex, gchar *nodeId, struct graph_t *g) +{ + gint addedTargetedVerticeIndex = -1; + gint i = 0; + + if (g->vertices[vIndex].numTargetedVertices == 0) + { + return (addedTargetedVerticeIndex); + } + + for (i = 0; i < g->vertices[vIndex].numTargetedVertices; i++) + { + if (memcmp (g->vertices[vIndex].targetedVertices[i].tVertice.nodeId, nodeId, strlen (nodeId)) == 0) + { + DEBUG_PC ("Targeted %s reachable from %s", nodeId, g->vertices[vIndex].verticeId.nodeId); + addedTargetedVerticeIndex = i; + return (addedTargetedVerticeIndex); + } + } + // not found ... + return (addedTargetedVerticeIndex); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Check if a nodeId is already considered into the set of targeted vertices from a given vertice, if not to be added + * + * @param nodeId + * @param vIndex + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint graph_targeted_vertice_add (gint vIndex, gchar *nodeId, struct graph_t *g) +{ + gint addedTargetedVerticeIndex = -1; + gint i = 0; + + if (g->vertices[vIndex].numTargetedVertices == 0) + { + //DEBUG_PC ("targeted vertice %s being reachable from vertice %s", nodeId, g->vertices[vIndex].verticeId.nodeId); + addedTargetedVerticeIndex = 0; + return (addedTargetedVerticeIndex); + } + + for (i = 0; i < g->vertices[vIndex].numTargetedVertices; i++) + { + if (memcmp (g->vertices[vIndex].targetedVertices[i].tVertice.nodeId, nodeId, strlen (nodeId)) == 0) + { + //DEBUG_PC ("Targeted vertice %s is already considered in the reachable from vertice %s", nodeId, g->vertices[vIndex].verticeId.nodeId); + addedTargetedVerticeIndex = -1; + return (addedTargetedVerticeIndex); + } + } + // It is not found, next to be added at i position + addedTargetedVerticeIndex = i; + return (addedTargetedVerticeIndex); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Remove edge from the graph + * + * @param g + * @param e + * + * @author Ricardo Martínez + * @date 2022 + */ +void remove_edge_from_graph (struct graph_t *g, struct edges_t *e) { + // Find the ingress vertice into the graph + DEBUG_PC ("Removing from Graph %s[%s]) ---> %s[%s] (linkId: %s)", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, e->aEndPointId, e->linkId); + gint verticeIndex = -1; + verticeIndex = graph_vertice_lookup (e->aNodeId.nodeId, g); + if (verticeIndex == -1) { + DEBUG_PC ("Edge w/ %s is NOT in the Graph!!", e->aNodeId.nodeId); + return; + } + + // Find the targeted vertice from vertice Id + gint targetedVerticeIndex = -1; + targetedVerticeIndex = graph_targeted_vertice_lookup (verticeIndex, e->zNodeId.nodeId, g); + if (targetedVerticeIndex == -1) { + DEBUG_PC ("%s --> %s NOT in the Graph!!", e->aNodeId.nodeId, e->zNodeId.nodeId); + return; + } + //DEBUG_PC ("%s --> %s found in the Graph", e->aNodeId.nodeId, e->zNodeId.nodeId); + + // Get the edge position + gint edgeIndex = -1; + edgeIndex = graph_edge_lookup (verticeIndex, targetedVerticeIndex, e, g); + if (edgeIndex == -1) { + DEBUG_PC ("%s --> %s NOT in the Graph!!", e->aNodeId.nodeId, e->zNodeId.nodeId); + return; + } + + //DEBUG_PC ("%s --> %s FOUND in Graph w/ edgeIndex: %d", e->aNodeId.nodeId, e->zNodeId.nodeId, edgeIndex); + + // Remove the edge + //DEBUG_PC ("Start Removing %s --> %s from Graph", e->aNodeId.nodeId, e->zNodeId.nodeId); + struct targetNodes_t *v = &(g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex]); + for (gint j = edgeIndex; j < v->numEdges; j++) { + struct edges_t *e1 = &(v->edges[j]); + struct edges_t *e2 = &(v->edges[j+1]); + duplicate_edge (e1, e2); + } + v->numEdges --; + DEBUG_PC ("Number of Edges between %s and %s is %d", e->aNodeId.nodeId, e->zNodeId.nodeId, v->numEdges); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief create the pointer for keeping a set of the paths (struct compRouteOutput_t) + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct path_set_t * create_path_set () { + struct path_set_t * p = g_malloc0 (sizeof (struct path_set_t)); + if (p == NULL) { + DEBUG_PC ("Memory allocation problem"); + exit (-1); + } + return p; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Remove the path set + * + * @param p + * + * @author Ricardo Martínez + * @date 2021 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void remove_path_set(struct path_set_t* p) { + g_assert(p); g_free(p); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Create map of nodes to handle the path computation + * + * @param mapN + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void build_map_node (struct map_nodes_t *mapN, struct graph_t *g) { + //DEBUG_PC ("Construction of the Map of Nodes"); + for (gint i = 0; i < g->numVertices; i++) { + duplicate_node_id (&g->vertices[i].verticeId, &mapN->map[i].verticeId); + mapN->map[i].distance = INFINITY_COST; + mapN->map[i].avaiBandwidth = 0.0; + mapN->map[i].latency = INFINITY_COST; + mapN->map[i].power = INFINITY_COST; + mapN->numMapNodes++; + } + //DEBUG_PC ("mapNodes formed by %d Nodes", mapN->numMapNodes); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Allocate memory for path of struct compRouteOutputList_t * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct compRouteOutputList_t * create_route_list () { + struct compRouteOutputList_t *p = g_malloc0 (sizeof (struct compRouteOutputList_t)); + if (p == NULL) { + DEBUG_PC ("Memory Allocation Problem"); + exit (-1); + } + return p; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Copy all the attributes defining a path + * + * @param dst_path + * @param src_path + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void copy_path(struct path_t* dst_path, struct path_t* src_path) { + g_assert(dst_path); + g_assert(src_path); + + // Path capacity + dst_path->path_capacity.unit = src_path->path_capacity.unit; + memcpy(&dst_path->path_capacity.value, &src_path->path_capacity.value, sizeof(gdouble)); + + // Path latency + memcpy(&dst_path->path_latency.fixed_latency, &src_path->path_latency.fixed_latency, sizeof(gdouble)); + + // Path cost + duplicate_string(dst_path->path_cost.cost_name, src_path->path_cost.cost_name); + memcpy(&dst_path->path_cost.cost_value, &src_path->path_cost.cost_value, sizeof(gdouble)); + memcpy(&dst_path->path_cost.cost_algorithm, &src_path->path_cost.cost_algorithm, sizeof(gdouble)); + + // Path links + dst_path->numPathLinks = src_path->numPathLinks; + for (gint i = 0; i < dst_path->numPathLinks; i++) { + struct pathLink_t* dPathLink = &(dst_path->pathLinks[i]); + struct pathLink_t* sPathLink = &(src_path->pathLinks[i]); + + duplicate_string(dPathLink->linkId, sPathLink->linkId); + duplicate_string(dPathLink->aDeviceId, sPathLink->aDeviceId); + duplicate_string(dPathLink->zDeviceId, sPathLink->zDeviceId); + duplicate_string(dPathLink->aEndPointId, sPathLink->aEndPointId); + duplicate_string(dPathLink->zEndPointId, sPathLink->zEndPointId); + + duplicate_string(dPathLink->topologyId.contextId, sPathLink->topologyId.contextId); + duplicate_string(dPathLink->topologyId.topology_uuid, sPathLink->topologyId.topology_uuid); + + dPathLink->numLinkTopologies = sPathLink->numLinkTopologies; + for (gint j = 0; j < dPathLink->numLinkTopologies; j++) { + struct linkTopology_t* dLinkTop = &(dPathLink->linkTopologies[j]); + struct linkTopology_t* sLinkTop = &(sPathLink->linkTopologies[j]); + + duplicate_string(dLinkTop->topologyId, sLinkTop->topologyId); + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Duplicate the route output instance + * + * @param dst_ro + * @param src_ro + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_compRouteOuput(struct compRouteOutput_t* dst_ro, struct compRouteOutput_t* src_ro) { + g_assert(dst_ro); g_assert(src_ro); + + // Copy the serviceId + copy_service_id(&dst_ro->serviceId, &src_ro->serviceId); + dst_ro->num_service_endpoints_id = src_ro->num_service_endpoints_id; + + for (gint j = 0; j < dst_ro->num_service_endpoints_id; j++) { + struct service_endpoints_id_t* iEp = &(src_ro->service_endpoints_id[j]); + struct service_endpoints_id_t* oEp = &(dst_ro->service_endpoints_id[j]); + copy_service_endpoint_id(oEp, iEp); + } + + // Copy paths + dst_ro->numPaths = src_ro->numPaths; + for (gint j = 0; j < dst_ro->numPaths; j++) { + struct path_t* dst_path = &(dst_ro->paths[j]); + struct path_t* src_path = &(src_ro->paths[j]); + copy_path(dst_path, src_path); + } + // copy no path issue value + dst_ro->noPathIssue = src_ro->noPathIssue; + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Duplicate the computation route output list + * + * @param dst + * @param src + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_route_list(struct compRouteOutputList_t* dst, struct compRouteOutputList_t* src) { + g_assert(src); g_assert(dst); + + dst->numCompRouteConnList = src->numCompRouteConnList; + dst->compRouteOK = src->compRouteOK; + memcpy(&dst->compRouteConnAvBandwidth, &src->compRouteConnAvBandwidth, sizeof(gdouble)); + memcpy(&dst->compRouteConnAvPathLength, &src->compRouteConnAvPathLength, sizeof(gdouble)); + for (gint i = 0; i < src->numCompRouteConnList; i++) { + struct compRouteOutput_t* src_ro = &(src->compRouteConnection[i]); + struct compRouteOutput_t* dst_ro = &(dst->compRouteConnection[i]); + duplicate_compRouteOuput(dst_ro, src_ro); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Allocate memory for path of struct compRouteOutputItem_t * + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct compRouteOutputItem_t *create_path_item () { + struct compRouteOutputItem_t *p = g_malloc0 (sizeof (struct compRouteOutputItem_t)); + if (p == NULL) { + DEBUG_PC ("Memory Allocation Problem"); + exit (-1); + } + return p; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Sort the set of paths the AvailBw, Cost and Delay + * + * @params setP + * @params args + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void sort_path_set(struct path_set_t* setP, guint args) { + g_assert(setP); + // Sort the paths contained in setP by: + // 1st Criteria: The path cost (maybe bound to link distance) + // 2nd Criteria: The consumed path power + // 3nd Criteria: The path latency + // 3rd Criteria: The available Bw + float epsilon = 0.1; + + for (gint i = 0; i < setP->numPaths; i++) { + for (gint j = 0; j < (setP->numPaths - i - 1); j++) { + struct compRouteOutputItem_t* path1 = &setP->paths[j]; + struct compRouteOutputItem_t* path2 = &setP->paths[j + 1]; + struct compRouteOutputItem_t* pathTmp = create_path_item(); + //////////////////////// Criterias //////////////////////////////////////// + // 1st Criteria (Cost) + if (path2->cost < path1->cost) { + duplicate_path(path1, pathTmp); + duplicate_path(path2, path1); + duplicate_path(pathTmp, path2); + g_free(pathTmp); + continue; + } + if (path2->cost == path1->cost) { + // 2nd Criteria (Energy) + if (args & ENERGY_EFFICIENT_ARGUMENT) { + if (path2->power < path1->power) { + duplicate_path(path1, pathTmp); + duplicate_path(path2, path1); + duplicate_path(pathTmp, path2); + g_free(pathTmp); + continue; + } + else { // path1->power < path2->power + g_free(pathTmp); + continue; + } + } + else { // No enery efficient argument + // 3rd Criteria (latency) + if (path2->delay < path1->delay) { + duplicate_path(path1, pathTmp); + duplicate_path(path2, path1); + duplicate_path(pathTmp, path2); + g_free(pathTmp); + continue; + } + else if (path1->delay < path2->delay) { + g_free(pathTmp); + continue; + } + else { // path1->delay == path2->delay + // 4th Criteria (available bw) + if (path2->availCap > path1->availCap) { + duplicate_path(path1, pathTmp); + duplicate_path(path2, path1); + duplicate_path(pathTmp, path2); + g_free(pathTmp); + continue; + } + else { + g_free(pathTmp); + continue; + } + } + } + } + else { // path1->cost < path2->cost + g_free(pathTmp); + continue; + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Remove first element from the path sets + * + * @params setP + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void pop_front_path_set (struct path_set_t *setP) { + for (gint j = 0; j < setP->numPaths - 1; j++) { + struct compRouteOutputItem_t *path1 = &setP->paths[j]; + struct compRouteOutputItem_t *path2 = &setP->paths[j+1]; + duplicate_path (path2, path1); + } + setP->numPaths--; + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Add routeElement to the back of the path + * + * @param rE + * @param p + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void add_routeElement_path_back (struct routeElement_t *rE, struct compRouteOutputItem_t *p) { + //DEBUG_PC ("p->numRouteElements: %d", p->numRouteElements); + p->numRouteElements++; + gint index = p->numRouteElements - 1; + + struct nodes_t *pn = &(p->routeElement[index].aNodeId); + struct nodes_t *rEn = &(rE->aNodeId); + + // duplicate aNodeId + duplicate_node_id (rEn, pn); + pn = &(p->routeElement[index].zNodeId); + rEn = &(rE->zNodeId); + duplicate_node_id (rEn, pn); + duplicate_string(p->routeElement[index].aEndPointId, rE->aEndPointId); + duplicate_string(p->routeElement[index].zEndPointId, rE->zEndPointId); + duplicate_string(p->routeElement[index].linkId, rE->linkId); + duplicate_string(p->routeElement[index].aTopologyId, rE->aTopologyId); + duplicate_string(p->routeElement[index].zTopologyId, rE->zTopologyId); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief This function compares ap and rootPath. If all the links are equal between both ap and rootPath till the sN, then the link from sN to next node + * ap is returned + * + * @params ap + * @params p + * @params sN + * @params e + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gboolean matching_path_rootPath (struct compRouteOutputItem_t *ap, struct compRouteOutputItem_t *rootPath, struct nodes_t *sN, struct edges_t *e) { + gint j = 0; + gboolean ret = FALSE; + while ((j < ap->numRouteElements) && (j < rootPath->numRouteElements)) { + if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0) && + //(memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) != 0) && + (memcmp (sN->nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0)) { + duplicate_node_id (&ap->routeElement[j].aNodeId, &e->aNodeId); + duplicate_node_id (&ap->routeElement[j].zNodeId, &e->zNodeId); + duplicate_string(e->aEndPointId, ap->routeElement[j].aEndPointId); + duplicate_string(e->zEndPointId, ap->routeElement[j].zEndPointId); + duplicate_string(e->linkId, ap->routeElement[j].linkId); + return TRUE; + } + if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0) && + (memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) == 0)) { + j++; + continue; + } + + if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) != 0) || + (memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) != 0)) { + //DEBUG_PC ("ap and rootPath not in the same path"); + return ret; + } + } + return ret; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief This function is used to modify the graph to be used for running the subsequent SP computations acording to the YEN algorithm principles + * + * @params g + * @params A + * @params rootPath + * @params spurNode + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void modify_targeted_graph (struct graph_t *g, struct path_set_t *A, struct compRouteOutputItem_t * rootPath, struct nodes_t * spurNode) { + //DEBUG_PC ("Modify the Targeted graph according to the Yen algorithm principles"); + for (gint j = 0; j < A->numPaths; j++) { + struct compRouteOutputItem_t *ap = &A->paths[j]; + struct edges_t *e = create_edge(); + gboolean ret = FALSE; + ret = matching_path_rootPath (ap, rootPath, spurNode, e); + if (ret == TRUE) { + DEBUG_PC ("Removal %s[%s] --> %s[%s] from the graph", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, e->aEndPointId); + remove_edge_from_graph (g, e); + //DEBUG_PC ("Print Resulting Graph"); + print_graph (g); + g_free (e); + } + if (ret == FALSE) { + g_free (e); + continue; + } + } + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Supporting fucntion to Check if a nodeId is already in the items of a given GList + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint find_nodeId (gconstpointer data, gconstpointer userdata) +{ + /** check values */ + g_assert(data != NULL); + g_assert(userdata != NULL); + + struct nodeItem_t *SNodeId = (struct nodeItem_t *)data; + guchar * nodeId = (guchar *)userdata; + + //DEBUG_PC ("SNodeId (%s) nodeId (%s)", SNodeId->node.nodeId, nodeId); + + if (!memcmp(SNodeId->node.nodeId, nodeId, strlen (SNodeId->node.nodeId))) + { + return (0); + } + return -1; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Explores the link between u and v + * + * @param u + * @param v + * @param g + * @param s + * @param S + * @param Q + * @param mapNodes + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struct graph_t *g, + struct service_t *s, GList **S, GList **Q, struct map_nodes_t *mapNodes, + guint arg) { + g_assert(g); g_assert(s); g_assert(mapNodes); + + struct targetNodes_t *v = &(g->vertices[indexGraphU].targetedVertices[indexGraphV]); + DEBUG_PC("Explored Link %s => %s)", u->node.nodeId, v->tVertice.nodeId); + //DEBUG_PC("\t %s => %s", u->node.nodeId, v->tVertice.nodeId); + + // v already explored in S? then, discard it + GList *found = g_list_find_custom (*S, v->tVertice.nodeId, find_nodeId); + if (found != NULL) { + DEBUG_PC ("v (%s) in S, Discard", v->tVertice.nodeId); + return 0; + } + + // Get the set of constraints imposed by the service + struct path_constraints_t* path_constraints = get_path_constraints(s); + gdouble distance_through_u = INFINITY_COST ,latency_through_u = INFINITY_COST, power_through_u = INFINITY_COST; + gint i = 0, foundAvailBw = 0; + // BANDWIDTH requirement to be fulfilled on EDGE u->v + gdouble edgeAvailBw = 0.0, edgeTotalBw = 0.0; + for (i = 0; i < v->numEdges; i++) { + struct edges_t *e = &(v->edges[i]); + memcpy (&edgeAvailBw, &(e->availCap), sizeof (gdouble)); + memcpy(&edgeTotalBw, &(e->totalCap), sizeof(gdouble)); + DEBUG_PC("EDGE %s[%s] => %s[%s]", u->node.nodeId, e->aEndPointId, v->tVertice.nodeId, e->zEndPointId); + //DEBUG_PC ("\t %s[%s] =>", u->node.nodeId, e->aEndPointId); + //DEBUG_PC("\t => %s[%s]", v->tVertice.nodeId, e->zEndPointId); + DEBUG_PC("\t AvailBw: %f, TotalBw: %f", edgeAvailBw, edgeTotalBw); + // Check Service Bw constraint + if ((path_constraints->bw == TRUE) && (edgeAvailBw < path_constraints->bwConstraint)) + continue; + else { + foundAvailBw = 1; + break; + } + } + // BW constraint NOT MET, then DISCARD edge + if ((path_constraints->bw == TRUE) && (foundAvailBw == 0)) { + DEBUG_PC ("AvailBw: %f < path_constraint: %f -- Discard Edge", edgeAvailBw, path_constraints->bwConstraint); + g_free(path_constraints); + return 0; + } + + gint indexEdge = i; // get the index for the explored edge + // Update distance, latency and availBw through u to reach v + gint map_uIndex = get_map_index_by_nodeId (u->node.nodeId, mapNodes); + struct map_t *u_map = &mapNodes->map[map_uIndex]; + distance_through_u = u_map->distance + v->edges[indexEdge].cost; + latency_through_u = u_map->latency + v->edges[indexEdge].delay; + // Consumed power at v through u is the sum + // 1. Power from src to u + // 2. Power-idle at node u + // 3. power consumed over the edge between u and v, i.e. energy*usedBw + power_through_u = u_map->power + g->vertices[indexGraphU].power_idle + ((edgeTotalBw - edgeAvailBw + path_constraints->bwConstraint) * (v->edges[indexEdge].energy)); + gdouble availBw_through_u = 0.0; + + // ingress endpoint (u) is the src of the request + if (strcmp (u->node.nodeId, s->service_endpoints_id[0].device_uuid) == 0) { + //DEBUG_PC ("AvailBw %f on %s --> %s", edgeAvailBw, u->node.nodeId, v->tVertice.nodeId); + memcpy (&availBw_through_u, &edgeAvailBw, sizeof (gdouble)); + } + else { + // Get the minimum available bandwidth between the src-->u and the new added edge u-->v + //DEBUG_PC ("Current AvailBw: %f from src to %s", u_map->avaiBandwidth, u->node.nodeId); + //DEBUG_PC ("AvailBw: %f %s --> %s", edgeAvailBw, u->node.nodeId, v->tVertice.nodeId); + if (u_map->avaiBandwidth <= edgeAvailBw) { + memcpy (&availBw_through_u, &u_map->avaiBandwidth, sizeof (gdouble)); + } + else { + memcpy (&availBw_through_u, &edgeAvailBw, sizeof (gdouble)); + } + } + // Relax the link according to the pathCost, latency, and energy + gint map_vIndex = get_map_index_by_nodeId (v->tVertice.nodeId, mapNodes); + struct map_t *v_map = &mapNodes->map[map_vIndex]; + // If cost dist (u, v) > dist (src, v) relax the link + if (distance_through_u > v_map->distance) { + //DEBUG_PC ("dist(src, u) + dist(u, v): %f > dist (src, v): %f --> Discard Link", distance_through_u, v_map->distance); + return 0; + } + // If energy consumption optimization is requested + if (arg & ENERGY_EFFICIENT_ARGUMENT) { + if (distance_through_u == v_map->distance) { + if (power_through_u > v_map->power) { + DEBUG_PC("Energy (src -> u + u -> v: %f (Watts) >Energy (src, v): %f (Watts)--> DISCARD LINK", power_through_u, v_map->power); + return 0; + } + // same energy consumption, consider latency + if ((power_through_u == v_map->power) && (latency_through_u > v_map->latency)) { + return 0; + } + if ((power_through_u == v_map->power) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { + return 0; + } + } + } // No optimization, rely on latency and available e2e bandwidth + else { + // If dist (src, u) + dist (u, v) = current dist(src, v), then use the latency as discarding criteria + if ((distance_through_u == v_map->distance) && (latency_through_u > v_map->latency)) { + //DEBUG_PC ("dist(src, u) + dist(u,v) = current dist(src, v), but latency (src,u) + latency (u, v) > current latency (src, v)"); + return 0; + } + // If dist (src, u) + dist (u,v) == current dist(src, v) AND latency (src, u) + latency (u, v) == current latency (src, v), the available bandwidth is the criteria + if ((distance_through_u == v_map->distance) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { + return 0; + } + } + DEBUG_PC ("%s --> %s Relaxed", u->node.nodeId, v->tVertice.nodeId); + DEBUG_PC ("\t AvailBw: %f Mb/s, Cost: %f, Latency: %f ms, Energy: %f Watts", availBw_through_u, distance_through_u, latency_through_u, power_through_u); + + // Update Q list -- + struct nodeItem_t *nodeItem = g_malloc0 (sizeof (struct nodeItem_t)); + if (nodeItem == NULL) { + DEBUG_PC ("memory allocation failed\n"); + exit (-1); + } + nodeItem->distance = distance_through_u; + memcpy(&nodeItem->distance, &distance_through_u, sizeof(gdouble)); + memcpy(&nodeItem->latency, &latency_through_u, sizeof(gdouble)); + memcpy(&nodeItem->power, &power_through_u, sizeof(gdouble)); + duplicate_node_id (&v->tVertice, &nodeItem->node); + // add node to the Q list + if (arg & ENERGY_EFFICIENT_ARGUMENT) { + *Q = g_list_insert_sorted(*Q, nodeItem, sort_by_energy); + } + else + *Q = g_list_insert_sorted (*Q, nodeItem, sort_by_distance); + + // Update the mapNodes for the specific reached tv + v_map->distance = distance_through_u; + memcpy(&v_map->distance, &distance_through_u, sizeof(gdouble)); + memcpy (&v_map->avaiBandwidth, &availBw_through_u, sizeof (gdouble)); + memcpy (&v_map->latency, &latency_through_u, sizeof (gdouble)); + memcpy(&v_map->power, &power_through_u, sizeof(gdouble)); + // Duplicate the predecessor edge into the mapNodes + struct edges_t *e1 = &(v_map->predecessor); + struct edges_t *e2 = &(v->edges[indexEdge]); + duplicate_edge(e1, e2); + DEBUG_PC ("u->v Edge: %s(%s) --> %s(%s)", e2->aNodeId.nodeId, e2->aEndPointId, e2->zNodeId.nodeId, e2->zEndPointId); + //DEBUG_PC("v-pred aTopology: %s", e2->aTopologyId); + DEBUG_PC("v-pred zTopology: %s", e2->zTopologyId); + + // Check whether v is dstPEId + //DEBUG_PC ("Targeted dstId: %s", s->service_endpoints_id[1].device_uuid); + //DEBUG_PC ("nodeId added to the map: %s", v_map->verticeId.nodeId); + //DEBUG_PC ("Q Length: %d", g_list_length(*Q)); + g_free(path_constraints); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Check the feasability of a path wrt the constraints imposed by the request in terms of latency + * + * @param s + * @param p + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gboolean check_computed_path_feasability (struct service_t *s, struct compRouteOutputItem_t* p) { + float epsilon = 0.0000001; + struct path_constraints_t* pathCons = get_path_constraints(s); + gboolean ret = TRUE; + if (pathCons->latency == TRUE) { + if ((pathCons->latencyConstraint - p->delay > 0.0) || (fabs(pathCons->latencyConstraint - p->delay) < epsilon)) { + DEBUG_PC("Computed Path (latency: %f) is feasible wrt Connection Demand: %f", p->delay, pathCons->latencyConstraint); + } + else { + DEBUG_PC("Computed Path (latency: %f) is NOT feasible wrt Connection Demand: %f", p->delay, pathCons->latencyConstraint); + g_free(pathCons); + return FALSE; + } + } + // Other constraints... + g_free(pathCons); + return ret; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Sorting the GList Q items by distance + * + * @param a + * @param b + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint sort_by_distance (gconstpointer a, gconstpointer b) { + //DEBUG_PC ("sort by distance a and b"); + g_assert(a != NULL); + g_assert(b != NULL); + + //DEBUG_PC ("sort by distance a and b"); + struct nodeItem_t *node1 = (struct nodeItem_t *)a; + struct nodeItem_t *node2 = (struct nodeItem_t *)b; + g_assert (node1); + g_assert (node2); + + //DEBUG_PC ("a->distance %u; b->distance %u", node1->distance, node2->distance); + //DEBUG_PC("a->latency: %f; b->latency: %f", node1->latency, node2->latency); + //1st criteria, sorting by lowest distance + if (node1->distance > node2->distance) + return 1; + else if (node1->distance < node2->distance) + return 0; + if (node1->distance == node2->distance) { + if (node1->latency > node2->latency) + return 1; + else if (node1->latency <= node2->latency) + return 0; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Sorting the GList Q items by distance + * + * @param a + * @param b + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gint sort_by_energy(gconstpointer a, gconstpointer b) { + g_assert(a != NULL); + g_assert(b != NULL); + + //DEBUG_PC ("sort by distance a and b"); + struct nodeItem_t* node1 = (struct nodeItem_t*)a; + struct nodeItem_t* node2 = (struct nodeItem_t*)b; + g_assert(node1); + g_assert(node2); + + //1st criteria: sorting by lowest distance + if (node1->distance > node2->distance) + return 1; + if (node1->distance < node2->distance) + return 0; + + // 2nd Criteria: sorting by the lowest energy + if (node1->power > node2->power) + return 1; + if (node1->power < node1->power) + return 0; + + // 3rd Criteria: by the latency + if (node1->latency > node2->latency) + return 1; + if (node1->latency <= node2->latency) + return 0; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Allocate memory for graph + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct graph_t * create_graph () { + struct graph_t * g = g_malloc0 (sizeof (struct graph_t)); + if (g == NULL) { + DEBUG_PC ("Memory Allocation Problem"); + exit (-1); + } + return g; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Allocate memory for mapNodes + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct map_nodes_t * create_map_node () { + struct map_nodes_t * mN = g_malloc0 (sizeof (struct map_nodes_t)); + if (mN == NULL) { + DEBUG_PC ("Memory allocation failed"); + exit (-1); + } + return mN; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Look up for the service in the servieList bound to a serviceUUID + * + * @params serviceUUID + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct service_t* get_service_for_computed_path(gchar* serviceUUID) { + gint i = 0; + for(GList *listnode = g_list_first(serviceList); + listnode; + listnode = g_list_next(listnode), i++) { + struct service_t* s = (struct service_t*)(listnode->data); + if (strcmp(s->serviceId.service_uuid, serviceUUID) == 0) + return s; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the service type + * + * @param type + * + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_service_type(guint type) { + switch (type) { + case SERVICE_TYPE_UNKNOWN: + DEBUG_PC("Service Type UNKNOWN"); + break; + case SERVICE_TYPE_L3NM: + DEBUG_PC("Service Type L3NM"); + break; + case SERVICE_TYPE_L2NM: + DEBUG_PC("Service Type L2NM"); + break; + case SERVICE_TYPE_TAPI: + DEBUG_PC("Service Type L2NM"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the port direction + * + * @param direction + * + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_link_port_direction(guint direction) { + switch (direction) { + case LINK_PORT_DIRECTION_BIDIRECTIONAL: + //DEBUG_PC("Bidirectional Port Direction"); + break; + case LINK_PORT_DIRECTION_INPUT: + //DEBUG_PC("Input Port Direction"); + break; + case LINK_PORT_DIRECTION_OUTPUT: + //DEBUG_PC("Output Port Direction"); + break; + case LINK_PORT_DIRECTION_UNKNOWN: + //DEBUG_PC("Unknown Port Direction"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the port termination direction + * + * @param direction + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_termination_direction(guint direction) { + switch (direction) { + case TERMINATION_DIRECTION_BIDIRECTIONAL: + //DEBUG_PC("Bidirectional Termination Direction"); + break; + case TERMINATION_DIRECTION_SINK: + //DEBUG_PC("Input Termination Direction"); + break; + case TERMINATION_DIRECTION_SOURCE: + //DEBUG_PC("Output Termination Direction"); + break; + case TERMINATION_DIRECTION_UNKNOWN: + //DEBUG_PC("Unknown Termination Direction"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the termination state + * + * @param state + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_termination_state(guint state) +{ + switch (state) { + case TERMINATION_STATE_CAN_NEVER_TERMINATE: + //DEBUG_PC("Can never Terminate"); + break; + case TERMINATION_STATE_NOT_TERMINATED: + DEBUG_PC("Not terminated"); + break; + case TERMINATION_STATE_TERMINATED_SERVER_TO_CLIENT_FLOW: + DEBUG_PC("Terminated server to client flow"); + break; + case TERMINATION_STATE_TERMINATED_CLIENT_TO_SERVER_FLOW: + DEBUG_PC("Terminated client to server flow"); + break; + case TERMINATION_STATE_TERMINATED_BIDIRECTIONAL: + //DEBUG_PC("Terminated bidirectional"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the capacity unit + * + * @param unit + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_capacity_unit(guint unit) { + + switch (unit) { + case CAPACITY_UNIT_TB: + DEBUG_PC("Unit in TB"); + break; + case CAPACITY_UNIT_TBPS: + DEBUG_PC("Unit in TB/s"); + break; + case CAPACITY_UNIT_GB: + DEBUG_PC("Unit in GB"); + break; + case CAPACITY_UNIT_GBPS: + DEBUG_PC("Unit in GB/s"); + break; + case CAPACITY_UNIT_MB: + DEBUG_PC("Unit in MB"); + break; + case CAPACITY_UNIT_MBPS: + //DEBUG_PC("Unit in MB/s"); + break; + case CAPACITY_UNIT_KB: + DEBUG_PC("Unit in KB"); + break; + case CAPACITY_UNIT_KBPS: + DEBUG_PC("Unit in KB/s"); + break; + case CAPACITY_UNIT_GHZ: + DEBUG_PC("Unit in GHz"); + break; + case CAPACITY_UNIT_MHZ: + DEBUG_PC("Unit in MHz"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the link forwarding direction + * + * @param linkFwDir + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_link_forwarding_direction(guint linkFwDir) { + switch (linkFwDir) { + case LINK_FORWARDING_DIRECTION_BIDIRECTIONAL: + DEBUG_PC("BIDIRECTIONAL LINK FORWARDING DIRECTION"); + break; + case LINK_FORWARDING_DIRECTION_UNIDIRECTIONAL: + DEBUG_PC("UNIDIRECTIONAL LINK FORWARDING DIRECTION"); + break; + case LINK_FORWARDING_DIRECTION_UNKNOWN: + DEBUG_PC("UNKNOWN LINK FORWARDING DIRECTION"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Search a specific contextUuid element into the contextSet + * + * @param contextUuid + * @param set + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct context_t* find_contextId_in_set(gchar* contextUuid, GList** set) { + //DEBUG_PC("Checking if contextId: %s in in the ContextSet??", contextUuid); + gint i = 0; + for (GList *ln = g_list_first(*set); + ln; + ln = g_list_next(ln)){ + struct context_t* c = (struct context_t*)(ln->data); + //DEBUG_PC("Context Item [%d] Id: %s", i, c->contextId); + if (strcmp(contextUuid, c->contextId) == 0) { + //DEBUG_PC("contextId: %s is FOUND in the ContextSet_List", contextUuid); + return c; + } + i++; + } + //DEBUG_PC("contextId: %s NOT FOUND in the ContextSet_List", contextUuid); + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Add a specific context uuid into the context set + * + * @param contextUuid + * @param set + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct context_t* add_contextId_in_set(gchar *contextUuid, GList** set) { + + struct context_t* c = g_malloc0(sizeof(struct context_t)); + if (c == NULL) { + DEBUG_PC("Memory Allocation Failure"); + exit(-1); + } + duplicate_string(c->contextId, contextUuid); + // Add the context into the context set + //DEBUG_PC("Adding ContextId: %s", contextUuid); + //DEBUG_PC(" (BEFORE ADDING) Context Set Length: %d", g_list_length(*set)); + *set = g_list_append(*set, c); + //DEBUG_PC(" (AFTER ADDING) Context Set Length: %d", g_list_length(*set)); + return c; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Find a vertex in a specific graph + * + * @param contextUuid + * @param set + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct vertices_t* find_vertex_in_graph_context(struct graph_t *g, gchar* deviceId) { + for (gint i = 0; i < g->numVertices; i++) { + struct vertices_t* v = &(g->vertices[i]); + if (strcmp(v->verticeId.nodeId, deviceId) == 0) { + return v; + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Adding a deviceId into a graph + * + * @param g + * @param deviceId + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct vertices_t* add_vertex_in_graph(struct graph_t* g, struct device_t *d) { + g->numVertices++; + struct vertices_t* v = &(g->vertices[g->numVertices - 1]); + duplicate_string(v->verticeId.nodeId, d->deviceId); + memcpy(&v->power_idle, &d->power_idle, sizeof(gdouble)); + return v; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Construct the graphs (vertices and edges) bound to every individual context + * + * @param cSet + * @param activeFlag + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void build_contextSet_deviceList(GList** cSet, gint activeFlag) { + // Check every device their endpoints + for (GList* listnode = g_list_first(deviceList); + listnode; + listnode = g_list_next(listnode)) { + struct device_t* d = (struct device_t*)(listnode->data); + //DEBUG_PC("Exploring DeviceId: %s", d->deviceId); + + if ((activeFlag == 1) && (d->operational_status != 2)) { + // it is only considered devices with operational status enabled, i.e., set to 2 + continue; + } + // Check the associated endPoints + for (gint j = 0; j < d->numEndPoints; j++) { + struct endPoint_t* eP = &(d->endPoints[j]); + // Get endPointId (topology, context, device Id and endpoint uuid) + struct endPointId_t* ePid = &(eP->endPointId); //end point id + //DEBUG_PC(" EndPointId: %s || Type: %s", eP->endPointId.endpoint_uuid, d->deviceType); + //DEBUG_PC(" TopologyId: %s || ContextId: %s", eP->endPointId.topology_id.topology_uuid, eP->endPointId.topology_id.contextId); + // Add contextId in ContextSet and the deviceId (+endpoint) into the vertex set + struct context_t *c = find_contextId_in_set(eP->endPointId.topology_id.contextId, cSet); + if (c == NULL) { + DEBUG_PC(" contextUuid: %s MUST BE ADDED to ContextSet", eP->endPointId.topology_id.contextId); + c = add_contextId_in_set(eP->endPointId.topology_id.contextId, cSet); + } + // Check if the deviceId and endPointUuid are already considered in the graph of the context c + struct vertices_t* v = find_vertex_in_graph_context(&c->g, d->deviceId); + if (v == NULL) { + //DEBUG_PC(" deviceId: %s MUST BE ADDED to the Context Graph", d->deviceId); + v = add_vertex_in_graph(&c->g, d); + } + } + } + //print_contextSet(cSet); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Determine whether a deviceId is in the targetNode list of a specific vertex v + * + * @param v + * @param deviceId + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct targetNodes_t* find_targeted_vertex_in_graph_context(struct vertices_t* v, gchar *deviceId) { + for (gint k = 0; k < v->numTargetedVertices; k++) { + struct targetNodes_t* w = &(v->targetedVertices[k]); + if (strcmp(w->tVertice.nodeId, deviceId) == 0) { + return w; + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Add a deviceId a targetNode of a specific vertex v + * + * @param v + * @param deviceId + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct targetNodes_t* add_targeted_vertex_in_graph_context(struct vertices_t* v, gchar* bDeviceId) { + v->numTargetedVertices++; + struct targetNodes_t* w = &(v->targetedVertices[v->numTargetedVertices - 1]); + duplicate_string(w->tVertice.nodeId, bDeviceId); + return w; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Returns the structure of a device endpoint bound to a specific deviceId and endPointId + * + * @param devId + * @param endPointUuid + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct endPoint_t* find_device_tied_endpoint(gchar* devId, gchar* endPointUuid) { + //DEBUG_PC("devId: %s ePId: %s", devId, endPointUuid); + for (GList* ln = g_list_first(deviceList); + ln; + ln = g_list_next(ln)) { + struct device_t* d = (struct device_t*)(ln->data); + if (strcmp(d->deviceId, devId) != 0) { + continue; + } + // Iterate over the endpoints tied to the deviceId + for (gint j = 0; j < d->numEndPoints; j++) { + struct endPoint_t* eP = &(d->endPoints[j]); + //DEBUG_PC("looked endPointId: %s", eP->endPointId.endpoint_uuid); + if (strcmp(eP->endPointId.endpoint_uuid, endPointUuid) == 0) { + return eP; + } + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Adding the edge/linnk in the targetedNodes w list + * + * @param w + * @param l + * @param activeFlag + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void add_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l, gint activeFlag) { + //DEBUG_PC("\t targetedVertex: %s", w->tVertice.nodeId); + + // Check if the activeFlag is 1. If YES, it is only added to the edges as long as the + // associated endPoint is in status ENABLED, i.e., with operational status set to 2 + // Get the endpoints (A and Z) of the link l (assumed P2P) + struct link_endpointId_t* aEndpointId = &(l->linkEndPointId[0]); + struct link_endpointId_t* zEndpointId = &(l->linkEndPointId[1]); + // Get the endPoint Information tied to the device bound to aEndPointId + struct endPoint_t* eP = find_device_tied_endpoint(aEndpointId->deviceId, aEndpointId->endPointId); + if (eP == NULL) { + DEBUG_PC("devId: %s endPointUuid: %s NOT in Device List!!--- Weird", aEndpointId->deviceId, aEndpointId->endPointId); + exit(-1); + } + // Check whether the port in that endPoint (eP) is Active upon the activeFlag being SET + if (activeFlag == 1) { + if (eP->operational_status != 2) // NOT ENABLED, then discard this link + return; + } + + // Add the edge into the graph + w->numEdges++; + struct edges_t* e = &(w->edges[w->numEdges - 1]); + // Copy the link Id UUID + duplicate_string(e->linkId, l->linkId); + duplicate_string(e->aNodeId.nodeId, aEndpointId->deviceId); + duplicate_string(e->aEndPointId, aEndpointId->endPointId); + duplicate_string(e->aTopologyId, aEndpointId->topology_id.topology_uuid); + duplicate_string(e->zNodeId.nodeId, zEndpointId->deviceId); + duplicate_string(e->zEndPointId, zEndpointId->endPointId); + duplicate_string(e->zTopologyId, zEndpointId->topology_id.topology_uuid); + + //Potential(total) and available capacity + e->unit = eP->potential_capacity.unit; + memcpy(&e->totalCap, &eP->potential_capacity.value, sizeof(gdouble)); + memcpy(&e->availCap, &eP->available_capacity.value, sizeof(gdouble)); + // Copy interdomain local/remote Ids + memcpy(e->interDomain_localId, eP->inter_domain_plug_in.inter_domain_plug_in_local_id, + strlen(eP->inter_domain_plug_in.inter_domain_plug_in_local_id)); + memcpy(e->interDomain_remoteId, eP->inter_domain_plug_in.inter_domain_plug_in_remote_id, + strlen(eP->inter_domain_plug_in.inter_domain_plug_in_remote_id)); + // cost value + memcpy(&e->cost, &l->cost_characteristics.cost_value, sizeof(gdouble)); + // latency ms + memcpy(&e->delay, &l->latency_characteristics.fixed_latency, sizeof(gdouble)); + // energy J/bits ~ power + memcpy(&e->energy, &eP->energyConsumption, sizeof(gfloat)); + + //DEBUG_PC("Edge - Total/Available Capacity: %f/%f; Cost: %f; Delay: %f, Energy: %f", eP->potential_capacity.value, eP->available_capacity.value, + // l->cost_characteristics.cost_value, l->latency_characteristics.fixed_latency, l->energy_link); + + //DEBUG_PC("Graph Edge - Total/Available Capacity: %f/%f; Cost: %f; Delay: %f, Energy: %f", e->totalCap, e->availCap, + // e->cost, e->delay, e->energy); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Searching a specific edge/link by the linkId(UUID) + * + * @param w + * @param l + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct edges_t* find_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l) { + for (gint i = 0; i < w->numEdges; i++) { + struct edges_t* e = &(w->edges[i]); + if (strcmp(e->linkId, l->linkId) == 0) { + return e; + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief supporting the construction of the graph per context using the explicit + * contents/info of the link list + * + * @param set + * @param activeFlag + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void build_contextSet_linklList(GList** set, gint activeFlag) { + // for each link in linkList: + // 1st- Retrieve endpoints A --> B feauture (context Id, device Id, endpoint Id) + // 2st - In the graph associated to the contextId, check wheter A (deviceId) is in the vertices list + // o No, this is weird ... exist + // o Yes, get the other link endpoint (i.e., B) and check whether it exists. If NOT add it, considering + // all the attributes; Otherwise, check whether the link is different from existing edges between A and B + gdouble epsilon = 0.1; + gint j = 0; + for (GList* ln = g_list_first(linkList); + ln; + ln = g_list_next(ln)) { + struct link_t* l = (struct link_t*)(ln->data); + j++; + + // link assumed to be P2P A --> B; i.e. 2 endPoints; 1st specifies A and 2nd specifie B + struct link_endpointId_t* aEndpointId = &(l->linkEndPointId[0]); + struct topology_id_t* topologyId = &(aEndpointId->topology_id); + // get the contextId + gchar contextUuid[UUID_CHAR_LENGTH]; + duplicate_string(contextUuid, topologyId->contextId); + DEBUG_PC("Link: %s in ContextId: %s", l->linkId, contextUuid); + + // Check first contextUuid exists in the cSet + //DEBUG_PC("Length of Context: %d", g_list_length(set)); + struct context_t* c = find_contextId_in_set(contextUuid, set); + if (c == NULL) { + DEBUG_PC("ContextId: %s does NOT exist... weird", contextUuid); + exit(-1); + } + + // get the device ID of A + gchar aDeviceId[UUID_CHAR_LENGTH]; + duplicate_string(aDeviceId, aEndpointId->deviceId); + + struct graph_t* g = &(c->g); // get the graph associated to the context c + struct vertices_t* v = find_vertex_in_graph_context(g, aDeviceId); + if (v == NULL) { + DEBUG_PC("%s NOT a VERTEX of contextId: %s ... WEIRD", aDeviceId, contextUuid); + exit(-1); + } + // get the bEndpointId + struct link_endpointId_t* bEndpointId = &(l->linkEndPointId[1]); + gchar bDeviceId[UUID_CHAR_LENGTH]; + duplicate_string(bDeviceId, bEndpointId->deviceId); + DEBUG_PC("[%d] -- Link: %s [%s ==> %s]", j-1, l->linkId, aDeviceId, bDeviceId); + // Check whether device B is in the targeted Vertices from A (i.e., v)? + // If not, add B in the targeted vertices B + create the edge and add it + // If B exist, check whether the explored link/edge is already in the list of edges + struct targetNodes_t* w = find_targeted_vertex_in_graph_context(v, bDeviceId); + if (w == NULL) { + DEBUG_PC("[%s] is PEER of [%s]", bDeviceId, v->verticeId.nodeId); + w = add_targeted_vertex_in_graph_context(v, bDeviceId); + add_edge_in_targetedVertice_set(w, l, activeFlag); + } + else { + // w exists, it is needed to check whether the edge (link) should be added + struct edges_t* e = find_edge_in_targetedVertice_set(w, l); + if (e == NULL) { + // Add the link into the list + add_edge_in_targetedVertice_set(w, l, activeFlag); + } + else { + DEBUG_PC("The link already exists ..."); + continue; + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Create the set of (distinct) contexts with the deviceList and linkList + * + * @param cSet + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void build_contextSet(GList** cSet) { + gint activeFlag = 0; // this means that all the devices/links (regardless they are active or not) are considered + + // devices are tied to contexts, i.e. depending on the contextId of the devices + build_contextSet_deviceList(cSet, activeFlag); + + DEBUG_PC("Length for the Context Set: %d", g_list_length(*cSet)); + + // Once the diverse contexts are created and the devices/endpoints asigned to the + // respective graph tied to each context, it is needed to create the edges + build_contextSet_linklList(cSet, activeFlag); + + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Create the set of (distinct) contexts with the deviceList and linkList with + * operational status active + * + * @param cSet + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void build_contextSet_active(GList** cSet) { + gint activeFlag = 1; // this means that all the devices (regardless they are active or not) are considered + + // devices are tied to contexts, i.e. depending on the contextId of the devices + build_contextSet_deviceList(cSet, activeFlag); + + DEBUG_PC("Length for the Context Set: %d", g_list_length(*cSet)); + + // Once the diverse contexts are created and the devices/endpoints asigned to the + // respective graph tied to each context, it is needed to create the edges + build_contextSet_linklList(cSet, activeFlag); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Print the contents of the ContextIds + * + * @param set + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_contextSet(GList* set) { + + DEBUG_PC("Printing the ContextSet w/ number of Elements: %d", g_list_length(set)); + + for (GList* ln = g_list_first(set); + ln; + ln = g_list_next(ln)) { + struct context_t* c = (struct context_t*)(ln->data); + DEBUG_PC("-------------------------------------------------------------"); + DEBUG_PC(" Context Id: %s", c->contextId); + DEBUG_PC("-------------------------------------------------------------"); + + struct graph_t* g = &(c->g); + for (gint j = 0; j < g->numVertices; j++) { + struct vertices_t* v = &(g->vertices[j]); + DEBUG_PC(" Head Device Id: %s", v->verticeId.nodeId); + for (gint k = 0; k < v->numTargetedVertices; k++) { + struct targetNodes_t* w = &(v->targetedVertices[k]); + DEBUG_PC(" [%d] --- Peer Device Id: %s", k, w->tVertice.nodeId); + for (gint l = 0; l < w->numEdges; l++) { + struct edges_t* e = &(w->edges[l]); + DEBUG_PC(" \t link Id: %s", e->linkId); + DEBUG_PC(" \t aEndPointId: %s", e->aEndPointId); + DEBUG_PC(" \t zEndPointId: %s", e->zEndPointId); + DEBUG_PC(" \t Available Capacity: %f, Latency: %f, Cost: %f", e->availCap, e->delay, e->cost); + DEBUG_PC(" \t aTopologyId: %s", e->aTopologyId); + DEBUG_PC(" \t zTopologyId: %s", e->zTopologyId); + } + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Check whether src and dst PE nodeId of the req are the same + * + * @param r + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint same_src_dst_pe_nodeid(struct service_t* s) +{ + // Check that source PE and dst PE are NOT the same, i.e., different ingress and egress endpoints (iEp, eEp) + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); + struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); + + gchar* iEpUUID = iEp->endpoint_uuid; + gchar* eEpUUID = eEp->endpoint_uuid; + gchar* iDevUUID = iEp->device_uuid; + gchar* eDevUUID = eEp->device_uuid; + + // Compare the device uuids + if (strcmp(iDevUUID, eDevUUID) != 0) { + DEBUG_PC("DIFFERENT --- iDevId: %s and eDevId: %s", iDevUUID, eDevUUID); + return 1; + } + // Compare the endpoints (ports) + if (strcmp(iEpUUID, eEpUUID) != 0) { + DEBUG_PC("DIFFERENT --- iEpUUID: %s and eEpUUID: %s", iEpUUID, eEpUUID); + return 1; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Handles issues with the route computation + * + * @param route + * @param s + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void comp_route_connection_issue_handler (struct compRouteOutput_t *path, struct service_t *s) +{ + g_assert(path); g_assert(s); + + // Increase the number of computed routes/paths despite there was an issue to be reported + path->numPaths++; + // Copy the serviceId + copy_service_id(&(path->serviceId), &(s->serviceId)); + + // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) + for (gint i = 0; i < s->num_service_endpoints_id; i++) { + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); + struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); + copy_service_endpoint_id(oEp, iEp); + } + path->num_service_endpoints_id = s->num_service_endpoints_id; + path->noPathIssue = NO_PATH_CONS_ISSUE; + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief released the allocated memory fo compRouteOutputList_t + * + * @param ro + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void destroy_compRouteOutputList (struct compRouteOutputList_t *ro) +{ + g_assert (ro); + g_free (ro); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief creates a copy of the underlying graph + * + * @param originalGraph + * @param destGraph + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_graph (struct graph_t *originalGraph, struct graph_t *destGraph) { + g_assert (originalGraph); g_assert (destGraph); + + destGraph->numVertices = originalGraph->numVertices; + for (gint i = 0; i < originalGraph->numVertices; i++) { + struct vertices_t *oVertex = &(originalGraph->vertices[i]); + struct vertices_t *dVertex = &(destGraph->vertices[i]); + dVertex->numTargetedVertices = oVertex->numTargetedVertices; + duplicate_node_id (&oVertex->verticeId, &dVertex->verticeId); + memcpy(&dVertex->power_idle, &oVertex->power_idle, sizeof(gdouble)); + + for (gint j = 0; j < oVertex->numTargetedVertices; j++) { + struct targetNodes_t *oTargetedVertex = &(oVertex->targetedVertices[j]); + struct targetNodes_t *dTargetedVertex = &(dVertex->targetedVertices[j]); + duplicate_node_id (&oTargetedVertex->tVertice, &dTargetedVertex->tVertice); + dTargetedVertex->numEdges = oTargetedVertex->numEdges; + + for (gint k = 0; k < oTargetedVertex->numEdges; k++) { + struct edges_t *oEdge = &(oTargetedVertex->edges[k]); + struct edges_t *dEdge = &(dTargetedVertex->edges[k]); + duplicate_edge (dEdge, oEdge); + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to retrieve from the graph the edge instance associated to the + * pathLink (pL) + * + * @param pL + * @parma g + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct edges_t* get_edge_from_graph_by_linkId(struct pathLink_t* pL, struct graph_t* g) { + g_assert(pL); + g_assert(g); + + for (gint i = 0; i < g->numVertices; i++) { + struct vertices_t* v = &(g->vertices[i]); + for (gint j = 0; j < v->numTargetedVertices; j++) { + struct targetNodes_t* tv = &(v->targetedVertices[j]); + for (gint k = 0; k < tv->numEdges; k++) { + struct edges_t* e = &(tv->edges[k]); + if (strcmp(e->linkId, pL->linkId) == 0) { + return e; + } + } + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to retrieve from the graph the reverse edge (rev_e) associated to an edge (e) + * + * @param e + * @parma g + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct edges_t* get_reverse_edge_from_the_graph(struct edges_t* e, struct graph_t* g) { + g_assert(e); + g_assert(g); + + for (gint i = 0; i < g->numVertices; i++) { + struct vertices_t* v = &(g->vertices[i]); + // Check Route Element zNodeId with the v->verticeId + if (compare_node_id(&e->zNodeId, &v->verticeId) != 0) + continue; + // Check Route Element zNodeis with any of reachable targeted vertices from v + gboolean foundTargVert = FALSE; + gint indexTargVert = -1; + for (gint j = 0; j < v->numTargetedVertices; j++) { + struct targetNodes_t* tv = &(v->targetedVertices[j]); + if (compare_node_id(&e->aNodeId, &tv->tVertice) == 0) + { + foundTargVert = TRUE; + indexTargVert = j; + break; + } + } + if (foundTargVert == FALSE) { + continue; + } + + // The targeted vertice is found, then check matching with the endpoints + struct targetNodes_t* tv = &(v->targetedVertices[indexTargVert]); + for (gint k = 0; k < tv->numEdges; k++) { + struct edges_t* rev_e = &(tv->edges[k]); + if ((strcmp(rev_e->aEndPointId, e->zEndPointId) == 0) && + (strcmp(rev_e->zEndPointId, e->aEndPointId) == 0)) { + return rev_e; + } + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to reflect in the graph the assigned/allocated resources contained in the path p + * considering the needs (e.g., bandwidth) of service s + * + * @param p + * @param s + * @parma g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void allocate_graph_resources (struct path_t *p, struct service_t *s, struct graph_t *g) +{ + g_assert (p); g_assert (s); g_assert (g); + // Retrieve the requested bw by the service + struct path_constraints_t* pathCons = get_path_constraints(s); + + for (gint i = 0; i < p->numPathLinks; i++) { + struct pathLink_t* pL = &(p->pathLinks[i]); + // get the edge associated to the linkId in the graph + struct edges_t* e = get_edge_from_graph_by_linkId(pL, g); + if (e == NULL) { + DEBUG_PC("The linkId: %s is NOT found in the Graph!!!", pL->linkId); + exit(-1); + } + //Update the availBw in the edge + gdouble resBw = e->availCap - pathCons->bwConstraint; + DEBUG_PC("Updating the Avail Bw @ edge/link: %s", e->linkId); + DEBUG_PC("Initial avaiCap @ e/link: %f, demanded Bw: %f, resulting Avail Bw: %f", e->availCap, pathCons->bwConstraint, resBw); + memcpy(&e->availCap, &resBw, sizeof(gdouble)); + DEBUG_PC("Final e/link avail Bw: %f", e->availCap); + } + g_free(pathCons); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to reflect in the graph the assigned/allocated resources contained in the reverse direction of the path p + * considering the needs (e.g., bandwidth) of service s + * + * @param p + * @param s + * @parma g + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void allocate_graph_reverse_resources(struct path_t* p, struct service_t * s, struct graph_t* g) +{ + g_assert(p); g_assert(s); g_assert(g); + + struct path_constraints_t* pathCons = get_path_constraints(s); + for (gint i = 0; i < p->numPathLinks; i++) { + struct pathLink_t* pL = &(p->pathLinks[i]); + struct edges_t* e = get_edge_from_graph_by_linkId(pL, g); + if (e == NULL) { + DEBUG_PC("The linkId: %s is NOT found in the Graph!!!", pL->linkId); + exit(-1); + } + struct edges_t* rev_e = get_reverse_edge_from_the_graph(e, g); + if (rev_e == NULL) { + DEBUG_PC("the reverse edge of linkId: %s is NOT found in the Graph!!!", pL->linkId); + exit(-1); + } + //Update the availBw in the edge + gdouble resBw = rev_e->availCap - pathCons->bwConstraint; + DEBUG_PC("Updating the Avail Bw @ reverse edge/link: %s", rev_e->linkId); + DEBUG_PC("Initial avaiCap @ reverse edge e/link: %f, demanded Bw: %f, resulting Avail Bw: %f", rev_e->availCap, pathCons->bwConstraint, resBw); + memcpy(&rev_e->availCap, &resBw, sizeof(gdouble)); + DEBUG_PC("Final reverse edge e/link avail Bw: %f", rev_e->availCap); + } + g_free(pathCons); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to printall the computed paths for the requested network connectivity services + * + * @param routeList + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_path_connection_list(struct compRouteOutputList_t* routeList) { + g_assert(routeList); + for (gint i = 0; i < routeList->numCompRouteConnList; i++) { + DEBUG_PC("==================== Service instance: %d ===================", i); + struct compRouteOutput_t* rO = &(routeList->compRouteConnection[i]); + DEBUG_PC("num service endpoints: %d", rO->num_service_endpoints_id); + struct serviceId_t* s = &(rO->serviceId); + DEBUG_PC("ContextId: %s, ServiceId: %s", s->contextId, s->service_uuid); + DEBUG_PC("ingress - %s[%s]", rO->service_endpoints_id[0].device_uuid, + rO->service_endpoints_id[0].endpoint_uuid); + DEBUG_PC("egress - %s [%s]", rO->service_endpoints_id[1].device_uuid, + rO->service_endpoints_id[1].endpoint_uuid); + + if (rO->noPathIssue == NO_PATH_CONS_ISSUE) { + DEBUG_PC("NO PATH SUCCESSFULLY COMPUTED"); + continue; + } + // Path + DEBUG_PC("Number of paths: %d", rO->numPaths); + for (gint j = 0; j < rO->numPaths; j++) { + struct path_t* p = &(rO->paths[j]); + print_path_t(p); + } + } + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief update statistics for the path computation operations + * + * @param routeConnList + * @param d + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void update_stats_path_comp(struct compRouteOutputList_t* routeConnList, struct timeval d, gint numSuccesPathComp, gint numPathCompIntents) { + g_assert(routeConnList); + + total_path_comp_time.tv_sec = total_path_comp_time.tv_sec + d.tv_sec; + total_path_comp_time.tv_usec = total_path_comp_time.tv_usec + d.tv_usec; + total_path_comp_time = tv_adjust(total_path_comp_time); + + gdouble path_comp_time_msec = (((total_path_comp_time.tv_sec) * 1000) + ((total_path_comp_time.tv_usec) / 1000)); + gdouble av_alg_comp_time = ((path_comp_time_msec / numSuccesPathComp)); + DEBUG_PC("\t --- STATS PATH COMP ----"); + DEBUG_PC("Succesfully Comp: %d | Path Comp Requests: %d", numSuccesPathComp, numPathCompIntents); + DEBUG_PC("AV. PATH COMP ALG. TIME: %f ms", av_alg_comp_time); + + gint i = 0; + for (GList* listnode = g_list_first(serviceList); + listnode; + listnode = g_list_next(listnode), i++) { + struct service_t* s = (struct service_t*)(listnode->data); + char* eptr; + for (gint j = 0; j < s->num_service_constraints; j++) { + struct constraint_t* constraints = &(s->constraints[j]); + if (strncmp((const char*)(constraints->constraint_type), "bandwidth", 9) == 0) { + totalReqBw += (gdouble)(strtod((char*)constraints->constraint_value, &eptr)); + } + } + } + + for (gint k = 0; k < routeConnList->numCompRouteConnList; k++) { + struct compRouteOutput_t* rO = &(routeConnList->compRouteConnection[k]); + if (rO->noPathIssue == NO_PATH_CONS_ISSUE) { + continue; + } + // Get the requested service bw bound to that computed path + struct path_t* p = &(rO->paths[0]); + struct service_t* s = get_service_for_computed_path(rO->serviceId.service_uuid); + if (s == NULL) { + DEBUG_PC("Weird the service associated to a path is not found"); + exit(-1); + } + for (gint l = 0; l < s->num_service_constraints; l++) { + struct constraint_t* constraints = &(s->constraints[l]); + char* eptr; + if (strncmp((const char*)(constraints->constraint_type), "bandwidth", 9) == 0) { + totalServedBw += (gdouble)(strtod((char*)constraints->constraint_value, &eptr)); + } + } + } + gdouble avServedRatio = totalServedBw / totalReqBw; + DEBUG_PC("AV. Served Ratio: %f", avServedRatio); + gdouble avBlockedBwRatio = (gdouble)(1.0 - avServedRatio); + DEBUG_PC("AV. BBE: %f", avBlockedBwRatio); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate active service path + * + * @param actServPath + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_active_service_path(struct activeServPath_t* actServPath) { + g_assert(actServPath); + g_free(actServPath); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate active service + * + * @param actService + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_active_service(struct activeService_t* actService) { + g_assert(actService); + g_list_free_full(g_steal_pointer(&actService->activeServPath), (GDestroyNotify)destroy_active_service_path); + g_free(actService); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate a requested service + * + * @param s + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_requested_service(struct service_t* s) { + g_assert(s); + g_free(s); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate a device + * + * @param d + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_device(struct device_t* d) { + g_assert(d); + g_free(d); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate a link from the linkList + * + * @param d + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_link(struct link_t* l) { + g_assert(l); + g_free(l); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate a context from the contextSet + * + * @param d + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_context(struct context_t* c) { + g_assert(c); + g_free(c); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Excecution Dijkstra algorithm + * + * @param srcMapIndex + * @param dstMapIndex + * @param g + * @param s + * @param mapNodes + * @param SN + * @param RP + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void dijkstra(gint srcMapIndex, gint dstMapIndex, struct graph_t* g, struct service_t* s, + struct map_nodes_t* mapNodes, struct nodes_t* SN, struct compRouteOutputItem_t* RP, + guint arg) { + g_assert(s);g_assert(g); + + // Set params into mapNodes related to the source nodes of the request + mapNodes->map[srcMapIndex].distance = 0.0; + mapNodes->map[srcMapIndex].latency = 0.0; + mapNodes->map[srcMapIndex].avaiBandwidth = 0.0; + mapNodes->map[srcMapIndex].power = 0.0; + + // Initialize the set Q and S + GList *S = NULL, *Q = NULL; + gint indexVertice = -1; + + // Add the source into the Q + struct nodeItem_t* nodeItem = g_malloc0(sizeof(struct nodeItem_t)); + if (nodeItem == NULL) { + DEBUG_PC("memory allocation failed\n"); + exit(-1); + } + // initialize some nodeItem attributes + nodeItem->distance = 0.0; + nodeItem->latency = 0.0; + nodeItem->power = 0.0; + duplicate_node_id(&mapNodes->map[srcMapIndex].verticeId, &nodeItem->node); + + // Select the optimization process + if (arg & ENERGY_EFFICIENT_ARGUMENT) + Q = g_list_insert_sorted(Q, nodeItem, sort_by_energy); + // more "if" according to different optimization criteria ... + else + Q = g_list_insert_sorted(Q, nodeItem, sort_by_distance); + + // Check whether there is spurNode (SN) and rootPath (RP) + if (SN != NULL && RP != NULL) { + struct routeElement_t* re; + for (gint j = 0; j < RP->numRouteElements; j++) { + // Get the source and target Nodes of the routeElement within the rootPath + re = &RP->routeElement[j]; + DEBUG_PC("root Link: aNodeId: %s (%s) --> zNodeiId: %s (%s)", re->aNodeId.nodeId, re->aEndPointId, re->zNodeId.nodeId, re->zEndPointId); + + // if ingress of the root link (aNodeId) is the spurNode, then stops + if (compare_node_id(&re->aNodeId, SN) == 0) { + DEBUG_PC("root Link: aNodeId: %s and spurNode: %s -- stop exploring the rootPath (RP)", re->aNodeId.nodeId, SN->nodeId); + break; + } + // Extract from Q + GList* listnode = g_list_first(Q); + struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); + Q = g_list_remove(Q, node); + + //DEBUG_RL_RA ("Exploring node %s", node->node.nodeId); + indexVertice = graph_vertice_lookup(node->node.nodeId, g); + g_assert(indexVertice >= 0); + + // Get the indexTargetedVertice + gint indexTVertice = -1; + indexTVertice = graph_targeted_vertice_lookup(indexVertice, re->zNodeId.nodeId, g); + gint done = check_link(node, indexVertice, indexTVertice, g, s, &S, &Q, mapNodes, arg); + (void)done; + // Add to the S list + S = g_list_append(S, node); + } + // Check that the first node in Q set is SpurNode, otherwise something went wrong ... + if (compare_node_id(&re->aNodeId, SN) != 0) { + //DEBUG_PC ("root Link: aNodeId: %s is NOT the spurNode: %s -- something wrong", re->aNodeId.nodeId, SN->nodeId); + g_list_free_full(g_steal_pointer(&S), g_free); + g_list_free_full(g_steal_pointer(&Q), g_free); + return; + } + } + + while (g_list_length(Q) > 0) { + //Extract from Q set + GList* listnode = g_list_first(Q); + struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); + Q = g_list_remove(Q, node); + DEBUG_PC("Q length: %d", g_list_length(Q)); + DEBUG_PC("DeviceId: %s", node->node.nodeId); + + // visit all the links from u within the graph + indexVertice = graph_vertice_lookup(node->node.nodeId, g); + g_assert(indexVertice >= 0); + + // Check the targeted vertices from u + for (gint i = 0; i < g->vertices[indexVertice].numTargetedVertices; i++) { + gint done = check_link(node, indexVertice, i, g, s, &S, &Q, mapNodes, arg); + (void)done; + } + // Add node into the S Set + S = g_list_append(S, node); + //DEBUG_PC ("S length: %d", g_list_length (S)); + } + g_list_free_full(g_steal_pointer(&S), g_free); + g_list_free_full(g_steal_pointer(&Q), g_free); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief KSP computation using Dijkstra algorithm + * + * @param pred + * @param g + * @param s + * @param SN + * @param RP + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gint ksp_comp(struct pred_t* pred, struct graph_t* g, struct service_t* s, + struct nodes_t* SN, struct compRouteOutputItem_t* RP, + struct map_nodes_t* mapNodes, guint arg) { + g_assert(pred); g_assert(g); g_assert(s); + + DEBUG_PC("Source: %s -- Destination: %s", s->service_endpoints_id[0].device_uuid, s->service_endpoints_id[1].device_uuid); + + // Check the both ingress src and dst endpoints are in the graph + gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); + if (srcMapIndex == -1) { + DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); + return -1; + } + + gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); + if (dstMapIndex == -1) { + DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); + return -1; + } + + //DEBUG_PC("srcMapIndex: %d (node: %s)", srcMapIndex, mapNodes->map[srcMapIndex].verticeId.nodeId); + //DEBUG_PC("dstMapIndex: %d (node: %s)", dstMapIndex, mapNodes->map[dstMapIndex].verticeId.nodeId); + + // Compute the shortest path route + dijkstra(srcMapIndex, dstMapIndex, g, s, mapNodes, SN, RP, arg); + + // Check that a feasible solution in term of latency and bandwidth is found + gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); + struct map_t* dest_map = &mapNodes->map[map_dstIndex]; + if (!(dest_map->distance < INFINITY_COST)) { + DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); + return -1; + } + + DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); + // Check that the computed available bandwidth is larger than 0.0 + if (dest_map->avaiBandwidth <= (gfloat)0.0) { + DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); + return -1; + } + DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); + // Handle predecessors + build_predecessors(pred, s, mapNodes); + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief set the path parameters (e.g., latency, cost, power, ...) to an under-constructed + * path from the computed map vertex + * + * @param p + * @param mapV + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void set_path_attributes(struct compRouteOutputItem_t* p, struct map_t* mapV) { + g_assert(p); g_assert(mapV); + memcpy(&p->cost, &mapV->distance, sizeof(gdouble)); + memcpy(&p->availCap, &mapV->avaiBandwidth, sizeof(mapV->avaiBandwidth)); + memcpy(&p->delay, &mapV->latency, sizeof(mapV->latency)); + memcpy(&p->power, &mapV->power, sizeof(gdouble)); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief K-CSPF algorithm execution (YEN algorithm) + * + * @param s + * @param path + * @param g + * @param optimization_flag + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g, guint arg) { + g_assert(s); g_assert(path); g_assert(g); + + // create map of devices/nodes to handle the path computation using the context + struct map_nodes_t* mapNodes = create_map_node(); + build_map_node(mapNodes, g); + + // predecessors to store the computed path + struct pred_t* predecessors = create_predecessors(); + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); + struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); + + // Compute the 1st KSP path + gint done = ksp_comp(predecessors, g, s, NULL, NULL, mapNodes, arg); + if (done == -1) { + DEBUG_PC("NO PATH for %s[%s] --> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); + comp_route_connection_issue_handler(path, s); + g_free(mapNodes); g_free(predecessors); + return; + } + + // Construct the path from the computed predecessors + struct compRouteOutputItem_t* p = create_path_item(); + //print_predecessors(predecessors); + build_path(p, predecessors, s); + gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); + struct map_t* dst_map = &mapNodes->map[indexDest]; + // Get the delay and cost + set_path_attributes(p, dst_map); + + // Add the computed path, it may be a not feasible path, but at the end it is + // checked all the feasible paths, and select the first one + print_path(p); + + // Copy the serviceId + copy_service_id(&path->serviceId, &s->serviceId); + // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) + for (gint i = 0; i < s->num_service_endpoints_id; i++) { + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); + struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); + copy_service_endpoint_id(oEp, iEp); + } + path->num_service_endpoints_id = s->num_service_endpoints_id; + + DEBUG_PC("COMPUTE UP TO K Feasible Paths A[%d]", MAX_KSP_VALUE); + // Create A and B sets of paths to handle the YEN algorithm + struct path_set_t *A = create_path_set(), *B = create_path_set(); + // Add 1st Computed path into A->paths[0] + duplicate_path(p, &A->paths[0]); + A->numPaths++; + g_free(predecessors); g_free(p); + for (gint k = 1; k < MAX_KSP_VALUE; k++) { + DEBUG_PC("*************************** kth (%d) ***********************************", k); + struct compRouteOutputItem_t* p = create_path_item(); + duplicate_path(&A->paths[k - 1], p); + // The spurNode ranges from near-end node of the first link to the near-end of the last link forming the kth path + gint i = 0; + struct compRouteOutputItem_t* rootPath = create_path_item(); + for (i = 0; i < p->numRouteElements; i++) { + struct nodes_t *spurNode = create_node(), *nextSpurNode = create_node(); + struct routeElement_t* re = &(p->routeElement[i]); + // Create predecessors to store the computed path + struct pred_t* predecessors = create_predecessors(); + // Clear previous mapNodes, i.e. create it again + g_free(mapNodes); + mapNodes = create_map_node(); + build_map_node(mapNodes, g); + struct nodes_t* n = &re->aNodeId; + duplicate_node_id(n, spurNode); + n = &re->zNodeId; + duplicate_node_id(n, nextSpurNode); + DEBUG_PC("spurNode: %s --> nextSpurNode: %s", spurNode->nodeId, nextSpurNode->nodeId); + + // rootPath contains a set of links of A[k-1] from the source Node till the SpurNode -> NextSpurNode + // Example: A[k-1] = {L1, L2, L3, L4}, i.e. " Node_a -- L1 --> Node_b -- L2 --> Node_c -- L3 --> Node_d -- L4 --> Node_e " + // E.g., for the ith iteration if the spurNode = Node_c and NextSpurNode = Node_d; then rootPath = {L1, L2, L3} + add_routeElement_path_back(re, rootPath); + DEBUG_PC("\n"); + DEBUG_PC("^^^^^^^rootPath^^^^^^^"); + print_path(rootPath); + + // For all existing and computed paths p in A check if from the source to the NextSpurNode + // the set of links matches with those contained in the rootPath + // If YES, remove from the auxiliary graph the next link in p from NextSpurNode + // Otherwise do nothing + struct graph_t* gAux = create_graph(); + duplicate_graph(g, gAux); + // Modified graph + modify_targeted_graph(gAux, A, rootPath, spurNode); + + // Trigger the computation of the path from src to dst constrained to traverse all the links from src + // to spurNode contained into rootPath over the resulting graph + if (ksp_comp(predecessors, gAux, s, spurNode, rootPath, mapNodes, arg) == -1) { + DEBUG_PC("FAILED SP from %s via spurNode: %s to %s", iEp->device_uuid, spurNode->nodeId, eEp->device_uuid); + g_free(nextSpurNode); g_free(spurNode); + g_free(gAux); g_free(predecessors); + continue; + } + DEBUG_PC("SUCCESFUL SP from %s via spurNode: %s to %s", iEp->device_uuid, spurNode->nodeId, eEp->device_uuid); + // Create the node list from the predecessors + struct compRouteOutputItem_t* newKpath = create_path_item(); + build_path(newKpath, predecessors, s); + DEBUG_PC("new K (for k: %d) Path is built", k); + gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); + struct map_t* dst_map = &mapNodes->map[indexDest]; + set_path_attributes(newKpath, dst_map); + DEBUG_PC("New PATH (@ kth: %d) ADDED to B[%d] - {Path Cost: %f, e2e latency: %f, bw: %f, Power: %f ", k, B->numPaths, newKpath->cost, + newKpath->delay, newKpath->availCap, newKpath->power); + // Add the computed kth SP to the heap B + duplicate_path(newKpath, &B->paths[B->numPaths]); + B->numPaths++; + DEBUG_PC("Number of B paths: %d", B->numPaths); + + g_free(newKpath); g_free(nextSpurNode); g_free(spurNode); + g_free(gAux); g_free(predecessors); + } + // If B is empty then stops + if (B->numPaths == 0) { + DEBUG_PC("B does not have any path ... the stops kth computation"); + break; + } + + // Sort the potential B paths according to different optimization parameters + sort_path_set(B, arg); + // Add the lowest path into A[k] + DEBUG_PC("-------------------------------------------------------------"); + DEBUG_PC("Append SP for B[0] to A[%d] --- Cost: %f, Latency: %f, Power: %f", A->numPaths, B->paths[0].cost, + B->paths[0].delay, B->paths[0].power); + duplicate_path(&B->paths[0], &A->paths[A->numPaths]); + A->numPaths++; + DEBUG_PC("A Set size: %d", A->numPaths); + DEBUG_PC("-------------------------------------------------------------"); + + // Remove/Pop front element from the path set B (i.e. remove B[0]) + pop_front_path_set(B); + DEBUG_PC("B Set Size: %d", B->numPaths); + } + + // Copy the serviceId + copy_service_id(&path->serviceId, &s->serviceId); + // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) + for (gint m = 0; m < s->num_service_endpoints_id; m++) { + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[m]); + struct service_endpoints_id_t* oEp = &(s->service_endpoints_id[m]); + copy_service_endpoint_id(oEp, iEp); + } + + // Print all the paths i A + for (gint h = 0; h < A->numPaths; h++) { + DEBUG_PC("================== A[%d] =======================", h); + print_path(&A->paths[h]); + } + DEBUG_PC("Number of paths: %d", path->numPaths); + // For all the computed paths in A, pick the one being feasible wrt the service constraints + for (gint ksp = 0; ksp < A->numPaths; ksp++) { + if (ksp >= MAX_KSP_VALUE) { + DEBUG_PC("Number Requested paths (%d) REACHED - STOP", ksp); + break; + } + gdouble feasibleRoute = check_computed_path_feasability(s, &A->paths[ksp]); + if (feasibleRoute == TRUE) { + DEBUG_PC("A[%d] available: %f, pathCost: %f; latency: %f, Power: %f", ksp, A->paths[ksp].availCap, A->paths[ksp].cost, A->paths[ksp].delay, A->paths[ksp].power); + struct compRouteOutputItem_t* pathaux = &A->paths[ksp]; + path->numPaths++; + struct path_t* targetedPath = &path->paths[path->numPaths - 1]; + duplicate_path_t(pathaux, targetedPath); + print_path_t(targetedPath); + remove_path_set(A); + remove_path_set(B); + return; + } + } + remove_path_set(A); + remove_path_set(B); + // No paths found --> Issue + DEBUG_PC("K-SP failed!!!"); + comp_route_connection_issue_handler(path, s); + return; } \ No newline at end of file diff --git a/src/pathcomp/backend/pathComp_tools.h b/src/pathcomp/backend/pathComp_tools.h index 84334eb5e..ce78f009b 100644 --- a/src/pathcomp/backend/pathComp_tools.h +++ b/src/pathcomp/backend/pathComp_tools.h @@ -1,620 +1,624 @@ -/* - * Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) - * - * 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. - */ - -#ifndef _PATHCOMP_TOOLS_H -#define _PATHCOMP_TOOLS_H - -#include -#include -#include -#include - -// External variables -extern GList* contextSet; -extern GList* linkList; -extern GList* deviceList; -extern GList* serviceList; -extern GList* activeServList; - -////////////////////////////////////////////////////////// -// Optimization computation argument -////////////////////////////////////////////////////////// -#define NO_OPTIMIZATION_ARGUMENT 0x00000000 -#define ENERGY_EFFICIENT_ARGUMENT 0x00000001 - -#define INFINITY_COST 0xFFFFFFFF -#define MAX_NUM_PRED 100 - -#define MAX_KSP_VALUE 3 - -// HTTP RETURN CODES -#define HTTP_CODE_OK 200 -#define HTTP_CODE_CREATED 201 -#define HTTP_CODE_BAD_REQUEST 400 -#define HTTP_CODE_UNAUTHORIZED 401 -#define HTTP_CODE_FORBIDDEN 403 -#define HTTP_CODE_NOT_FOUND 404 -#define HTTP_CODE_NOT_ACCEPTABLE 406 - -#define MAX_NODE_ID_SIZE 37 // UUID 128 Bits - In hexadecimal requires 36 char -#define MAX_CONTEXT_ID 37 -//#define UUID_CHAR_LENGTH 37 -#define UUID_CHAR_LENGTH 100 -struct nodes_t { - gchar nodeId[UUID_CHAR_LENGTH]; -}; - -struct nodeItem_t { - struct nodes_t node; - gdouble distance; // traversed distance - gdouble latency; // incured latency - gdouble power; //consumed power -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Structures for collecting the RL topology including: intra WAN topology and inter-WAN links -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define MAX_INTER_DOMAIN_PLUG_IN_SIZE 128 -struct edges_t { - //aNodeId/Device Id - struct nodes_t aNodeId; - //zNodeId/Device Id - struct nodes_t zNodeId; - - // UUID of the endPointIds - gchar aEndPointId[UUID_CHAR_LENGTH]; - gchar zEndPointId[UUID_CHAR_LENGTH]; - - // UUID of the link - gchar linkId[UUID_CHAR_LENGTH]; - - // Potential(total) and available capacity - gint unit; - gdouble totalCap, availCap; - - gdouble cost; - gdouble delay; - gdouble energy; - - // inter-domain local and remote Ids - gchar interDomain_localId[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; - gchar interDomain_remoteId[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; - - gchar aTopologyId[UUID_CHAR_LENGTH]; - gchar zTopologyId[UUID_CHAR_LENGTH]; -}; - -// Structure to handle the path computation -struct pred_comp_t { - struct nodes_t v; - struct edges_t e; -}; - -struct pred_t { - struct pred_comp_t predComp[MAX_NUM_PRED]; - gint numPredComp; -}; - -// Structures for the managing the path computation algorithm -struct map_t { - struct nodes_t verticeId; - struct edges_t predecessor; - gdouble distance; - gdouble avaiBandwidth; - gdouble latency; - gdouble power; -}; - -#define MAX_MAP_NODE_SIZE 100 -struct map_nodes_t { - struct map_t map[MAX_MAP_NODE_SIZE]; - gint numMapNodes; -}; - -#define MAX_NUM_VERTICES 100 // 100 # LGR: reduced from 100 to 20 to divide by 5 the memory used -#define MAX_NUM_EDGES 5 // 100 # LGR: reduced from 100 to 5 to divide by 20 the memory used -// Structures for the graph composition -struct targetNodes_t { - // remote / targeted node - struct nodes_t tVertice; - // edge conencting a pair of vertices - struct edges_t edges[MAX_NUM_EDGES]; - gint numEdges; -}; - -struct vertices_t { - struct targetNodes_t targetedVertices[MAX_NUM_VERTICES]; - gint numTargetedVertices; - struct nodes_t verticeId; - gdouble power_idle; // power idle of the device (due to the fans, etc.) -}; - -struct graph_t { - struct vertices_t vertices[MAX_NUM_VERTICES]; - gint numVertices; -}; - -//////////////////////////////////////////////////// -// Structure for the Set of Contexts -/////////////////////////////////////////////////// -struct context_t { - gchar contextId[UUID_CHAR_LENGTH]; // UUID char format 36 chars - // conext Id has a graph associated - struct graph_t g; -}; - -#define MAX_ALG_ID_LENGTH 10 -//////////////////////////////////////////////////// -// External Variables -/////////////////////////////////////////////////// -extern gchar algId[MAX_ALG_ID_LENGTH]; - -//////////////////////////////////////////////////// -// Structure for the Requested Transport Connectivity Services -/////////////////////////////////////////////////// -#define SERVICE_TYPE_UNKNOWN 0 -#define SERVICE_TYPE_L3NM 1 -#define SERVICE_TYPE_L2NM 2 -#define SERVICE_TYPE_TAPI 3 - -/////////////////////////////////////////////////////////////////// -// Structure for the topology_id -/////////////////////////////////////////////////////////////////// -struct topology_id_t { - gchar contextId[UUID_CHAR_LENGTH]; - gchar topology_uuid[UUID_CHAR_LENGTH]; -}; - -struct inter_domain_plug_in_t { - gchar inter_domain_plug_in_local_id[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; - gchar inter_domain_plug_in_remote_id[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the endPointId -/////////////////////////////////////////////////////////////////// -struct endPointId_t { - struct topology_id_t topology_id; - gchar device_id[UUID_CHAR_LENGTH]; - gchar endpoint_uuid[UUID_CHAR_LENGTH]; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the endPoint -/////////////////////////////////////////////////////////////////// -#define CAPACITY_UNIT_TB 0 -#define CAPACITY_UNIT_TBPS 1 -#define CAPACITY_UNIT_GB 2 -#define CAPACITY_UNIT_GBPS 3 -#define CAPACITY_UNIT_MB 4 -#define CAPACITY_UNIT_MBPS 5 -#define CAPACITY_UNIT_KB 6 -#define CAPACITY_UNIT_KBPS 7 -#define CAPACITY_UNIT_GHZ 8 -#define CAPACITY_UNIT_MHZ 9 -struct capacity_t { - gdouble value; - gint unit; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the endPoint -/////////////////////////////////////////////////////////////////// -#define MAX_ENDPOINT_TYPE_SIZE 128 -// Link Port Direction -#define LINK_PORT_DIRECTION_BIDIRECTIONAL 0 -#define LINK_PORT_DIRECTION_INPUT 1 -#define LINK_PORT_DIRECTION_OUTPUT 2 -#define LINK_PORT_DIRECTION_UNKNOWN 3 -// Termination Direction -#define TERMINATION_DIRECTION_BIDIRECTIONAL 0 -#define TERMINATION_DIRECTION_SINK 1 -#define TERMINATION_DIRECTION_SOURCE 2 -#define TERMINATION_DIRECTION_UNKNOWN 3 -// Termination State -#define TERMINATION_STATE_CAN_NEVER_TERMINATE 0 -#define TERMINATION_STATE_NOT_TERMINATED 1 -#define TERMINATION_STATE_TERMINATED_SERVER_TO_CLIENT_FLOW 2 -#define TERMINATION_STATE_TERMINATED_CLIENT_TO_SERVER_FLOW 3 -#define TERMINATION_STATE_TERMINATED_BIDIRECTIONAL 4 - -struct endPoint_t { - struct endPointId_t endPointId; - gchar endpointType[MAX_ENDPOINT_TYPE_SIZE]; - guint link_port_direction; - guint termination_direction; - guint termination_state; - struct capacity_t potential_capacity; - struct capacity_t available_capacity; - // inter-domain identifiers - struct inter_domain_plug_in_t inter_domain_plug_in; - gfloat energyConsumption; // in nJ/bit - gint operational_status; // 0 Undefined, 1 Disabled, 2 Enabled -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the device contents -/////////////////////////////////////////////////////////////////// -#define MAX_DEV_TYPE_SIZE 128 -#define MAX_DEV_ENDPOINT_LENGTH 100 // 10 # LGR: controllers might have large number of endpoints -struct device_t { - gdouble power_idle; // power idle (baseline) of the switch in Watts - gint operational_status; // 0 - Undefined, 1 - Disabled, 2 - Enabled - gchar deviceId[UUID_CHAR_LENGTH]; // device ID using UUID (128 bits) - gchar deviceType[MAX_DEV_TYPE_SIZE]; // Specifies the device type - // define the endpoints attached to the device - gint numEndPoints; - struct endPoint_t endPoints[MAX_DEV_ENDPOINT_LENGTH]; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the link EndPoint Id -/////////////////////////////////////////////////////////////////// -struct link_endpointId_t { - struct topology_id_t topology_id; - gchar deviceId[UUID_CHAR_LENGTH]; // Device UUID - gchar endPointId[UUID_CHAR_LENGTH]; // Link EndPoint UUID -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the link cost characteristics -/////////////////////////////////////////////////////////////////// -#define LINK_COST_NAME_SIZE 128 -struct cost_characteristics_t { - gchar cost_name[LINK_COST_NAME_SIZE]; - gdouble cost_value; - gdouble cost_algorithm; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the latency characteristics of the link -/////////////////////////////////////////////////////////////////// -struct latency_characteristics_t { - gdouble fixed_latency; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the latency characteristics of the link -/////////////////////////////////////////////////////////////////// -struct power_characteristics_t { - gdouble power; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the link -/////////////////////////////////////////////////////////////////// -#define MAX_NUM_LINK_ENDPOINT_IDS 2 - -#define LINK_FORWARDING_DIRECTION_BIDIRECTIONAL 0 -#define LINK_FORWARDING_DIRECTION_UNIDIRECTIONAL 1 -#define LINK_FORWARDING_DIRECTION_UNKNOWN 2 -struct link_t { - gchar linkId[UUID_CHAR_LENGTH]; // link Id using UUID (128 bits) - //gdouble energy_link; // in nJ/bit - //gint operational_status; // 0 Undefined, 1 Disabled, 2 Enabled - gint numLinkEndPointIds; - struct link_endpointId_t linkEndPointId[MAX_NUM_LINK_ENDPOINT_IDS]; - guint forwarding_direction; - struct capacity_t potential_capacity; - struct capacity_t available_capacity; - struct cost_characteristics_t cost_characteristics; - struct latency_characteristics_t latency_characteristics; -}; - -//////////////////////////////////////////////////// -// Structure for service Identifier -/////////////////////////////////////////////////// -struct serviceId_t { - gchar contextId[UUID_CHAR_LENGTH]; - gchar service_uuid[UUID_CHAR_LENGTH]; -}; - -//////////////////////////////////////////////////// -// Structure the service endpoint ids -/////////////////////////////////////////////////// -struct service_endpoints_id_t { - struct topology_id_t topology_id; - gchar device_uuid[UUID_CHAR_LENGTH]; - gchar endpoint_uuid[UUID_CHAR_LENGTH]; -}; - -//////////////////////////////////////////////////// -// Structure for handling generic targeted service constraints -//////////////////////////////////////////////////// -#define MAX_CONSTRAINT_SIZE 128 -// Constraint Type: bandwidth, latency, energy, cost -struct constraint_t { - gchar constraint_type[MAX_CONSTRAINT_SIZE]; - gchar constraint_value[MAX_CONSTRAINT_SIZE]; -}; - -//////////////////////////////////////////////////// -// Structure for individual service request -//////////////////////////////////////////////////// -#define SERVICE_TYPE_UNKNOWN 0 -#define SERVICE_TYPE_L3NM 1 -#define SERVICE_TYPE_L2NM 2 -#define SERVICE_TYPE_TAPI 3 - -#define MAX_NUM_SERVICE_ENPOINTS_ID 2 - -#define MAX_NUM_SERVICE_CONSTRAINTS 10 -struct service_t { - // Indentifier used to determine the used Algorithm Id, e.g., KSP - gchar algId[MAX_ALG_ID_LENGTH]; - // PATHS expected for the output - guint kPaths; - - struct serviceId_t serviceId; - guint service_type; // unknown, l2nm, l3nm, tapi - - // endpoints of the network connectivity service, assumed p2p - // the 1st one assumed to be the source (ingress) and the 2nd one is the sink (egress) - struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; - guint num_service_endpoints_id; - - // Service Constraints - struct constraint_t constraints[MAX_NUM_SERVICE_CONSTRAINTS]; - guint num_service_constraints; -}; - -//////////////////////////////////////////////////// -// Structure to handle path constraints during computation -//////////////////////////////////////////////////// -struct path_constraints_t { - gdouble bwConstraint; - gboolean bw; - - gdouble costConstraint; - gboolean cost; - - gdouble latencyConstraint; - gboolean latency; - - gdouble energyConstraint; - gboolean energy; -}; - -//////////////////////////////////////////////////// -// Structure for the handling the service requests -/////////////////////////////////////////////////// -//#define MAX_SERVICE_LIST 100 -//struct serviceList_t { -// struct service_t services[MAX_SERVICE_LIST]; -// gint numServiceList; -//}; - -//////////////////////////////////////////////////// -// Structure for the handling the active services -/////////////////////////////////////////////////// -struct activeServPath_t { - struct topology_id_t topology_id; - gchar deviceId[UUID_CHAR_LENGTH]; - gchar endPointId[UUID_CHAR_LENGTH]; -}; - -struct activeService_t { - struct serviceId_t serviceId; - guint service_type; // unknown, l2nm, l3nm, tapi - struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; - guint num_service_endpoints_id; - GList* activeServPath; -}; - -//////////////////////////////////////////////////////////////////////////////////////////// -// Structure describing the links forming a computed path -//////////////////////////////////////////////////////////////////////////////////////////// -struct linkTopology_t { - gchar topologyId[UUID_CHAR_LENGTH]; -}; - -struct pathLink_t { - gchar linkId[UUID_CHAR_LENGTH]; // link id UUID in char format - - gchar aDeviceId[UUID_CHAR_LENGTH]; - gchar zDeviceId[UUID_CHAR_LENGTH]; - gchar aEndPointId[UUID_CHAR_LENGTH]; - gchar zEndPointId[UUID_CHAR_LENGTH]; - - struct topology_id_t topologyId; - struct linkTopology_t linkTopologies[2]; // a p2p link (at most) can connect to devices (endpoints) attached to 2 different topologies - gint numLinkTopologies; -}; - -//////////////////////////////////////////////////////////////////////////////////////////// -// Structure describing a computed path -//////////////////////////////////////////////////////////////////////////////////////////// -#define MAX_ROUTE_ELEMENTS 50 -struct routeElement_t { - //aNodeId/Device Id - struct nodes_t aNodeId; - //zNodeId/Device Id - struct nodes_t zNodeId; - - // UUID of the endPointIds - gchar aEndPointId[UUID_CHAR_LENGTH]; - gchar zEndPointId[UUID_CHAR_LENGTH]; - - // UUID of the link - gchar linkId[UUID_CHAR_LENGTH]; - - gchar aTopologyId[UUID_CHAR_LENGTH]; - gchar zTopologyId[UUID_CHAR_LENGTH]; - - // contextId - gchar contextId[UUID_CHAR_LENGTH]; -}; - -struct compRouteOutputItem_t { - gint unit; - gdouble totalCap, availCap; - - gdouble cost; - gdouble delay; - gdouble power; - - struct routeElement_t routeElement[MAX_ROUTE_ELEMENTS]; - gint numRouteElements; -}; - -#define MAX_NUM_PATHS 30 -struct path_set_t { - struct compRouteOutputItem_t paths[MAX_NUM_PATHS]; - gint numPaths; -}; - -#define MAX_NUM_PATH_LINKS 20 -struct path_t { - struct capacity_t path_capacity; - struct latency_characteristics_t path_latency; - struct cost_characteristics_t path_cost; - struct power_characteristics_t path_power; - - struct pathLink_t pathLinks[MAX_NUM_PATH_LINKS]; - guint numPathLinks; -}; - -#define NO_PATH_CONS_ISSUE 1 // No path due to a constraint issue -#define MAX_NUM_COMPUTED_PATHS 10 -struct compRouteOutput_t { - // object describing the service identifier: serviceId and contextId - struct serviceId_t serviceId; - // array describing the service endpoints ids - struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; - guint num_service_endpoints_id; - struct path_t paths[MAX_NUM_COMPUTED_PATHS]; - gint numPaths; - // if the transport connectivity service cannot be computed, this value is set to 0 determining the constraints were not fulfilled - gint noPathIssue; -}; - -//////////////////////////////////////////////////////////////////////////////////////////// -// Structure to handle the response list with all the computed network connectivity services -//////////////////////////////////////////////////////////////////////////////////////////// -#define MAX_COMP_CONN_LIST 100 -struct compRouteOutputList_t { - struct compRouteOutput_t compRouteConnection[MAX_COMP_CONN_LIST]; - gint numCompRouteConnList; - - ///////////////// Metrics ////////////////////////////////////////// - // Number of total succesfully computed connections, i.e., at least 1 feasible path exists - // for every connection in the list - gint compRouteOK; - // For the succesfully newly computed/recovered/re-allocated/re-optimized connections, this - // metric determines the average allocable bandwidth over all the (re-)computed paths for the succesfully - // (i.e., feasible path) connections - gdouble compRouteConnAvBandwidth; - // For the succesfully newly computed/recovered/re-allocated/re-optimized connections, this - // metric determines the average path length (in terms of number of hops) over the computed path for the - // succesfully (i.e., feasible path) connections - gdouble compRouteConnAvPathLength; -}; - -// Prototype of external declaration of functions -void print_path (struct compRouteOutputItem_t *); -void print_path_t(struct path_t*); -struct path_t* create_path(); - -void duplicate_string(gchar *, gchar *); - -gchar* get_uuid_char(uuid_t); -void copy_service_id(struct serviceId_t*, struct serviceId_t *); -void copy_service_endpoint_id(struct service_endpoints_id_t *, struct service_endpoints_id_t *); - -struct graph_t* get_graph_by_contextId(GList*, gchar *); - -struct pred_t * create_predecessors (); -struct edges_t* create_edge(); -void print_predecessors (struct pred_t *); -void build_predecessors (struct pred_t *, struct service_t *, struct map_nodes_t *); -struct nodes_t * create_node (); -struct routeElement_t * create_routeElement (); - -void duplicate_node_id (struct nodes_t *, struct nodes_t *); -gint compare_node_id (struct nodes_t *, struct nodes_t *); -void duplicate_routeElement (struct routeElement_t *, struct routeElement_t *); -void duplicate_edge (struct edges_t *, struct edges_t *); -void duplicate_path (struct compRouteOutputItem_t *, struct compRouteOutputItem_t *); -void duplicate_path_t(struct compRouteOutputItem_t *, struct path_t *); -gint get_map_index_by_nodeId (gchar *, struct map_nodes_t *); -void get_edge_from_map_by_node (struct edges_t *, struct nodes_t*, struct map_nodes_t *); -void get_edge_from_predecessors (struct edges_t *, struct nodes_t*, struct pred_t *); -void build_path (struct compRouteOutputItem_t *, struct pred_t *, struct service_t *); -void print_graph (struct graph_t *); - -gint graph_vertice_lookup (gchar *, struct graph_t *); -gint graph_targeted_vertice_lookup (gint, gchar *, struct graph_t *); -gint graph_targeted_vertice_add (gint, gchar *, struct graph_t *); - -void remove_edge_from_graph (struct graph_t *, struct edges_t *); - -struct path_set_t * create_path_set (); -void sort_path_set (struct path_set_t *, guint); -void pop_front_path_set (struct path_set_t *); -void remove_path_set(struct path_set_t*); - -void build_map_node(struct map_nodes_t *, struct graph_t *); -struct compRouteOutputList_t * create_route_list(); -void duplicate_route_list(struct compRouteOutputList_t *, struct compRouteOutputList_t *); -struct compRouteOutputItem_t * create_path_item (); -void add_routeElement_path_back (struct routeElement_t *, struct compRouteOutputItem_t *); -gboolean matching_path_rootPath (struct compRouteOutputItem_t *, struct compRouteOutputItem_t *, struct nodes_t *, struct edges_t *); -void modify_targeted_graph (struct graph_t *, struct path_set_t *, struct compRouteOutputItem_t *, struct nodes_t *); -gint find_nodeId (gconstpointer, gconstpointer); -gint check_link (struct nodeItem_t *, gint, gint, struct graph_t *, struct service_t *, GList **, GList **, struct map_nodes_t *, guint arg); -gboolean check_computed_path_feasability (struct service_t *, struct compRouteOutputItem_t * ); - -gint sort_by_distance (gconstpointer, gconstpointer); -gint sort_by_energy(gconstpointer, gconstpointer); - -struct graph_t * create_graph (); -struct map_nodes_t * create_map_node (); - -struct service_t * get_service_for_computed_path(gchar *); - -void print_service_type(guint); -void print_link_port_direction(guint); -void print_termination_direction(guint); -void print_termination_state(guint); -void print_capacity_unit(guint); -void print_link_forwarding_direction(guint); - -void build_contextSet(GList **); -void build_contextSet_active(GList **); -void print_contextSet(GList *); - -gint same_src_dst_pe_nodeid (struct service_t *); -void comp_route_connection_issue_handler (struct compRouteOutput_t *, struct service_t *); - -void destroy_compRouteOutputList (struct compRouteOutputList_t *); -void duplicate_graph (struct graph_t *, struct graph_t *); - -void allocate_graph_resources (struct path_t *, struct service_t *, struct graph_t *); -void allocate_graph_reverse_resources(struct path_t*, struct service_t *, struct graph_t *); -void print_route_solution_list (GList *); -struct timeval tv_adjust(struct timeval); - -void print_path_connection_list(struct compRouteOutputList_t*); -void update_stats_path_comp(struct compRouteOutputList_t*, struct timeval, gint, gint); -void destroy_active_service(struct activeService_t*); -void destroy_requested_service(struct service_t*); -void destroy_device(struct device_t*); -void destroy_link(struct link_t*); -void destroy_context(struct context_t*); -void dijkstra(gint, gint, struct graph_t*, struct service_t*, struct map_nodes_t*, struct nodes_t*, struct compRouteOutputItem_t*, guint); -void set_path_attributes(struct compRouteOutputItem_t*, struct map_t*); -void alg_comp(struct service_t*, struct compRouteOutput_t*, struct graph_t*, guint); +//////////////////////////////////////////////////////////////////////////////////////// +/** + * # Copyright 2022 Centre Tecnol�gic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es + * + * 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. + + * Author: CTTC/CERCA PONS RU Ricardo Mart�nez (ricardo.martinez@cttc.es) + */ +///////////////////////////////////////////////////////////////////////////////////////// + +#ifndef _PATHCOMP_TOOLS_H +#define _PATHCOMP_TOOLS_H + +#include +#include +#include +#include + +// External variables +extern GList* contextSet; +extern GList* linkList; +extern GList* deviceList; +extern GList* serviceList; +extern GList* activeServList; + +////////////////////////////////////////////////////////// +// Optimization computation argument +////////////////////////////////////////////////////////// +#define NO_OPTIMIZATION_ARGUMENT 0x00000000 +#define ENERGY_EFFICIENT_ARGUMENT 0x00000001 + +#define INFINITY_COST 0xFFFFFFFF +#define MAX_NUM_PRED 100 + +#define MAX_KSP_VALUE 3 + +// HTTP RETURN CODES +#define HTTP_CODE_OK 200 +#define HTTP_CODE_CREATED 201 +#define HTTP_CODE_BAD_REQUEST 400 +#define HTTP_CODE_UNAUTHORIZED 401 +#define HTTP_CODE_FORBIDDEN 403 +#define HTTP_CODE_NOT_FOUND 404 +#define HTTP_CODE_NOT_ACCEPTABLE 406 + +#define MAX_NODE_ID_SIZE 37 // UUID 128 Bits - In hexadecimal requires 36 char +#define MAX_CONTEXT_ID 37 +//#define UUID_CHAR_LENGTH 37 +#define UUID_CHAR_LENGTH 100 +struct nodes_t { + gchar nodeId[UUID_CHAR_LENGTH]; +}; + +struct nodeItem_t { + struct nodes_t node; + gdouble distance; // traversed distance + gdouble latency; // incured latency + gdouble power; //consumed power +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Structures for collecting the RL topology including: intra WAN topology and inter-WAN links +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define MAX_INTER_DOMAIN_PLUG_IN_SIZE 128 +struct edges_t { + //aNodeId/Device Id + struct nodes_t aNodeId; + //zNodeId/Device Id + struct nodes_t zNodeId; + + // UUID of the endPointIds + gchar aEndPointId[UUID_CHAR_LENGTH]; + gchar zEndPointId[UUID_CHAR_LENGTH]; + + // UUID of the link + gchar linkId[UUID_CHAR_LENGTH]; + + // Potential(total) and available capacity + gint unit; + gdouble totalCap, availCap; + + gdouble cost; + gdouble delay; + gdouble energy; + + // inter-domain local and remote Ids + gchar interDomain_localId[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; + gchar interDomain_remoteId[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; + + gchar aTopologyId[UUID_CHAR_LENGTH]; + gchar zTopologyId[UUID_CHAR_LENGTH]; +}; + +// Structure to handle the path computation +struct pred_comp_t { + struct nodes_t v; + struct edges_t e; +}; + +struct pred_t { + struct pred_comp_t predComp[MAX_NUM_PRED]; + gint numPredComp; +}; + +// Structures for the managing the path computation algorithm +struct map_t { + struct nodes_t verticeId; + struct edges_t predecessor; + gdouble distance; + gdouble avaiBandwidth; + gdouble latency; + gdouble power; +}; + +#define MAX_MAP_NODE_SIZE 100 +struct map_nodes_t { + struct map_t map[MAX_MAP_NODE_SIZE]; + gint numMapNodes; +}; + +#define MAX_NUM_VERTICES 20 // 100 # LGR: reduced from 100 to 20 to divide by 5 the memory used +#define MAX_NUM_EDGES 10 // 100 # LGR: reduced from 100 to 10 to divide by 10 the memory used +// Structures for the graph composition +struct targetNodes_t { + // remote / targeted node + struct nodes_t tVertice; + // edge conencting a pair of vertices + struct edges_t edges[MAX_NUM_EDGES]; + gint numEdges; +}; + +struct vertices_t { + struct targetNodes_t targetedVertices[MAX_NUM_VERTICES]; + gint numTargetedVertices; + struct nodes_t verticeId; + gdouble power_idle; // power idle of the device (due to the fans, etc.) +}; + +struct graph_t { + struct vertices_t vertices[MAX_NUM_VERTICES]; + gint numVertices; +}; + +//////////////////////////////////////////////////// +// Structure for the Set of Contexts +/////////////////////////////////////////////////// +struct context_t { + gchar contextId[UUID_CHAR_LENGTH]; // UUID char format 36 chars + // conext Id has a graph associated + struct graph_t g; +}; + +#define MAX_ALG_ID_LENGTH 10 +//////////////////////////////////////////////////// +// External Variables +/////////////////////////////////////////////////// +extern gchar algId[MAX_ALG_ID_LENGTH]; + +//////////////////////////////////////////////////// +// Structure for the Requested Transport Connectivity Services +/////////////////////////////////////////////////// +#define SERVICE_TYPE_UNKNOWN 0 +#define SERVICE_TYPE_L3NM 1 +#define SERVICE_TYPE_L2NM 2 +#define SERVICE_TYPE_TAPI 3 + +/////////////////////////////////////////////////////////////////// +// Structure for the topology_id +/////////////////////////////////////////////////////////////////// +struct topology_id_t { + gchar contextId[UUID_CHAR_LENGTH]; + gchar topology_uuid[UUID_CHAR_LENGTH]; +}; + +struct inter_domain_plug_in_t { + gchar inter_domain_plug_in_local_id[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; + gchar inter_domain_plug_in_remote_id[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the endPointId +/////////////////////////////////////////////////////////////////// +struct endPointId_t { + struct topology_id_t topology_id; + gchar device_id[UUID_CHAR_LENGTH]; + gchar endpoint_uuid[UUID_CHAR_LENGTH]; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the endPoint +/////////////////////////////////////////////////////////////////// +#define CAPACITY_UNIT_TB 0 +#define CAPACITY_UNIT_TBPS 1 +#define CAPACITY_UNIT_GB 2 +#define CAPACITY_UNIT_GBPS 3 +#define CAPACITY_UNIT_MB 4 +#define CAPACITY_UNIT_MBPS 5 +#define CAPACITY_UNIT_KB 6 +#define CAPACITY_UNIT_KBPS 7 +#define CAPACITY_UNIT_GHZ 8 +#define CAPACITY_UNIT_MHZ 9 +struct capacity_t { + gdouble value; + gint unit; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the endPoint +/////////////////////////////////////////////////////////////////// +#define MAX_ENDPOINT_TYPE_SIZE 128 +// Link Port Direction +#define LINK_PORT_DIRECTION_BIDIRECTIONAL 0 +#define LINK_PORT_DIRECTION_INPUT 1 +#define LINK_PORT_DIRECTION_OUTPUT 2 +#define LINK_PORT_DIRECTION_UNKNOWN 3 +// Termination Direction +#define TERMINATION_DIRECTION_BIDIRECTIONAL 0 +#define TERMINATION_DIRECTION_SINK 1 +#define TERMINATION_DIRECTION_SOURCE 2 +#define TERMINATION_DIRECTION_UNKNOWN 3 +// Termination State +#define TERMINATION_STATE_CAN_NEVER_TERMINATE 0 +#define TERMINATION_STATE_NOT_TERMINATED 1 +#define TERMINATION_STATE_TERMINATED_SERVER_TO_CLIENT_FLOW 2 +#define TERMINATION_STATE_TERMINATED_CLIENT_TO_SERVER_FLOW 3 +#define TERMINATION_STATE_TERMINATED_BIDIRECTIONAL 4 + +struct endPoint_t { + struct endPointId_t endPointId; + gchar endpointType[MAX_ENDPOINT_TYPE_SIZE]; + guint link_port_direction; + guint termination_direction; + guint termination_state; + struct capacity_t potential_capacity; + struct capacity_t available_capacity; + // inter-domain identifiers + struct inter_domain_plug_in_t inter_domain_plug_in; + gfloat energyConsumption; // in nJ/bit + gint operational_status; // 0 Undefined, 1 Disabled, 2 Enabled +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the device contents +/////////////////////////////////////////////////////////////////// +#define MAX_DEV_TYPE_SIZE 128 +#define MAX_DEV_ENDPOINT_LENGTH 10 +struct device_t { + gdouble power_idle; // power idle (baseline) of the switch in Watts + gint operational_status; // 0 - Undefined, 1 - Disabled, 2 - Enabled + gchar deviceId[UUID_CHAR_LENGTH]; // device ID using UUID (128 bits) + gchar deviceType[MAX_DEV_TYPE_SIZE]; // Specifies the device type + // define the endpoints attached to the device + gint numEndPoints; + struct endPoint_t endPoints[MAX_DEV_ENDPOINT_LENGTH]; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the link EndPoint Id +/////////////////////////////////////////////////////////////////// +struct link_endpointId_t { + struct topology_id_t topology_id; + gchar deviceId[UUID_CHAR_LENGTH]; // Device UUID + gchar endPointId[UUID_CHAR_LENGTH]; // Link EndPoint UUID +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the link cost characteristics +/////////////////////////////////////////////////////////////////// +#define LINK_COST_NAME_SIZE 128 +struct cost_characteristics_t { + gchar cost_name[LINK_COST_NAME_SIZE]; + gdouble cost_value; + gdouble cost_algorithm; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the latency characteristics of the link +/////////////////////////////////////////////////////////////////// +struct latency_characteristics_t { + gdouble fixed_latency; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the latency characteristics of the link +/////////////////////////////////////////////////////////////////// +struct power_characteristics_t { + gdouble power; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the link +/////////////////////////////////////////////////////////////////// +#define MAX_NUM_LINK_ENDPOINT_IDS 2 + +#define LINK_FORWARDING_DIRECTION_BIDIRECTIONAL 0 +#define LINK_FORWARDING_DIRECTION_UNIDIRECTIONAL 1 +#define LINK_FORWARDING_DIRECTION_UNKNOWN 2 +struct link_t { + gchar linkId[UUID_CHAR_LENGTH]; // link Id using UUID (128 bits) + //gdouble energy_link; // in nJ/bit + //gint operational_status; // 0 Undefined, 1 Disabled, 2 Enabled + gint numLinkEndPointIds; + struct link_endpointId_t linkEndPointId[MAX_NUM_LINK_ENDPOINT_IDS]; + guint forwarding_direction; + struct capacity_t potential_capacity; + struct capacity_t available_capacity; + struct cost_characteristics_t cost_characteristics; + struct latency_characteristics_t latency_characteristics; +}; + +//////////////////////////////////////////////////// +// Structure for service Identifier +/////////////////////////////////////////////////// +struct serviceId_t { + gchar contextId[UUID_CHAR_LENGTH]; + gchar service_uuid[UUID_CHAR_LENGTH]; +}; + +//////////////////////////////////////////////////// +// Structure the service endpoint ids +/////////////////////////////////////////////////// +struct service_endpoints_id_t { + struct topology_id_t topology_id; + gchar device_uuid[UUID_CHAR_LENGTH]; + gchar endpoint_uuid[UUID_CHAR_LENGTH]; +}; + +//////////////////////////////////////////////////// +// Structure for handling generic targeted service constraints +//////////////////////////////////////////////////// +#define MAX_CONSTRAINT_SIZE 128 +// Constraint Type: bandwidth, latency, energy, cost +struct constraint_t { + gchar constraint_type[MAX_CONSTRAINT_SIZE]; + gchar constraint_value[MAX_CONSTRAINT_SIZE]; +}; + +//////////////////////////////////////////////////// +// Structure for individual service request +//////////////////////////////////////////////////// +#define SERVICE_TYPE_UNKNOWN 0 +#define SERVICE_TYPE_L3NM 1 +#define SERVICE_TYPE_L2NM 2 +#define SERVICE_TYPE_TAPI 3 + +#define MAX_NUM_SERVICE_ENPOINTS_ID 2 + +#define MAX_NUM_SERVICE_CONSTRAINTS 10 +struct service_t { + // Indentifier used to determine the used Algorithm Id, e.g., KSP + gchar algId[MAX_ALG_ID_LENGTH]; + // PATHS expected for the output + guint kPaths; + + struct serviceId_t serviceId; + guint service_type; // unknown, l2nm, l3nm, tapi + + // endpoints of the network connectivity service, assumed p2p + // the 1st one assumed to be the source (ingress) and the 2nd one is the sink (egress) + struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; + guint num_service_endpoints_id; + + // Service Constraints + struct constraint_t constraints[MAX_NUM_SERVICE_CONSTRAINTS]; + guint num_service_constraints; +}; + +//////////////////////////////////////////////////// +// Structure to handle path constraints during computation +//////////////////////////////////////////////////// +struct path_constraints_t { + gdouble bwConstraint; + gboolean bw; + + gdouble costConstraint; + gboolean cost; + + gdouble latencyConstraint; + gboolean latency; + + gdouble energyConstraint; + gboolean energy; +}; + +//////////////////////////////////////////////////// +// Structure for the handling the service requests +/////////////////////////////////////////////////// +//#define MAX_SERVICE_LIST 100 +//struct serviceList_t { +// struct service_t services[MAX_SERVICE_LIST]; +// gint numServiceList; +//}; + +//////////////////////////////////////////////////// +// Structure for the handling the active services +/////////////////////////////////////////////////// +struct activeServPath_t { + struct topology_id_t topology_id; + gchar deviceId[UUID_CHAR_LENGTH]; + gchar endPointId[UUID_CHAR_LENGTH]; +}; + +struct activeService_t { + struct serviceId_t serviceId; + guint service_type; // unknown, l2nm, l3nm, tapi + struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; + guint num_service_endpoints_id; + GList* activeServPath; +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Structure describing the links forming a computed path +//////////////////////////////////////////////////////////////////////////////////////////// +struct linkTopology_t { + gchar topologyId[UUID_CHAR_LENGTH]; +}; + +struct pathLink_t { + gchar linkId[UUID_CHAR_LENGTH]; // link id UUID in char format + + gchar aDeviceId[UUID_CHAR_LENGTH]; + gchar zDeviceId[UUID_CHAR_LENGTH]; + gchar aEndPointId[UUID_CHAR_LENGTH]; + gchar zEndPointId[UUID_CHAR_LENGTH]; + + struct topology_id_t topologyId; + struct linkTopology_t linkTopologies[2]; // a p2p link (at most) can connect to devices (endpoints) attached to 2 different topologies + gint numLinkTopologies; +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Structure describing a computed path +//////////////////////////////////////////////////////////////////////////////////////////// +#define MAX_ROUTE_ELEMENTS 50 +struct routeElement_t { + //aNodeId/Device Id + struct nodes_t aNodeId; + //zNodeId/Device Id + struct nodes_t zNodeId; + + // UUID of the endPointIds + gchar aEndPointId[UUID_CHAR_LENGTH]; + gchar zEndPointId[UUID_CHAR_LENGTH]; + + // UUID of the link + gchar linkId[UUID_CHAR_LENGTH]; + + gchar aTopologyId[UUID_CHAR_LENGTH]; + gchar zTopologyId[UUID_CHAR_LENGTH]; + + // contextId + gchar contextId[UUID_CHAR_LENGTH]; +}; + +struct compRouteOutputItem_t { + gint unit; + gdouble totalCap, availCap; + + gdouble cost; + gdouble delay; + gdouble power; + + struct routeElement_t routeElement[MAX_ROUTE_ELEMENTS]; + gint numRouteElements; +}; + +#define MAX_NUM_PATHS 30 +struct path_set_t { + struct compRouteOutputItem_t paths[MAX_NUM_PATHS]; + gint numPaths; +}; + +#define MAX_NUM_PATH_LINKS 20 +struct path_t { + struct capacity_t path_capacity; + struct latency_characteristics_t path_latency; + struct cost_characteristics_t path_cost; + struct power_characteristics_t path_power; + + struct pathLink_t pathLinks[MAX_NUM_PATH_LINKS]; + guint numPathLinks; +}; + +#define NO_PATH_CONS_ISSUE 1 // No path due to a constraint issue +#define MAX_NUM_COMPUTED_PATHS 10 +struct compRouteOutput_t { + // object describing the service identifier: serviceId and contextId + struct serviceId_t serviceId; + // array describing the service endpoints ids + struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; + guint num_service_endpoints_id; + struct path_t paths[MAX_NUM_COMPUTED_PATHS]; + gint numPaths; + // if the transport connectivity service cannot be computed, this value is set to 0 determining the constraints were not fulfilled + gint noPathIssue; +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Structure to handle the response list with all the computed network connectivity services +//////////////////////////////////////////////////////////////////////////////////////////// +#define MAX_COMP_CONN_LIST 100 +struct compRouteOutputList_t { + struct compRouteOutput_t compRouteConnection[MAX_COMP_CONN_LIST]; + gint numCompRouteConnList; + + ///////////////// Metrics ////////////////////////////////////////// + // Number of total succesfully computed connections, i.e., at least 1 feasible path exists + // for every connection in the list + gint compRouteOK; + // For the succesfully newly computed/recovered/re-allocated/re-optimized connections, this + // metric determines the average allocable bandwidth over all the (re-)computed paths for the succesfully + // (i.e., feasible path) connections + gdouble compRouteConnAvBandwidth; + // For the succesfully newly computed/recovered/re-allocated/re-optimized connections, this + // metric determines the average path length (in terms of number of hops) over the computed path for the + // succesfully (i.e., feasible path) connections + gdouble compRouteConnAvPathLength; +}; + +// Prototype of external declaration of functions +void print_path (struct compRouteOutputItem_t *); +void print_path_t(struct path_t*); +struct path_t* create_path(); + +void duplicate_string(gchar *, gchar *); + +gchar* get_uuid_char(uuid_t); +void copy_service_id(struct serviceId_t*, struct serviceId_t *); +void copy_service_endpoint_id(struct service_endpoints_id_t *, struct service_endpoints_id_t *); + +struct graph_t* get_graph_by_contextId(GList*, gchar *); + +struct pred_t * create_predecessors (); +struct edges_t* create_edge(); +void print_predecessors (struct pred_t *); +void build_predecessors (struct pred_t *, struct service_t *, struct map_nodes_t *); +struct nodes_t * create_node (); +struct routeElement_t * create_routeElement (); + +void duplicate_node_id (struct nodes_t *, struct nodes_t *); +gint compare_node_id (struct nodes_t *, struct nodes_t *); +void duplicate_routeElement (struct routeElement_t *, struct routeElement_t *); +void duplicate_edge (struct edges_t *, struct edges_t *); +void duplicate_path (struct compRouteOutputItem_t *, struct compRouteOutputItem_t *); +void duplicate_path_t(struct compRouteOutputItem_t *, struct path_t *); +gint get_map_index_by_nodeId (gchar *, struct map_nodes_t *); +void get_edge_from_map_by_node (struct edges_t *, struct nodes_t*, struct map_nodes_t *); +void get_edge_from_predecessors (struct edges_t *, struct nodes_t*, struct pred_t *); +void build_path (struct compRouteOutputItem_t *, struct pred_t *, struct service_t *); +void print_graph (struct graph_t *); + +gint graph_vertice_lookup (gchar *, struct graph_t *); +gint graph_targeted_vertice_lookup (gint, gchar *, struct graph_t *); +gint graph_targeted_vertice_add (gint, gchar *, struct graph_t *); + +void remove_edge_from_graph (struct graph_t *, struct edges_t *); + +struct path_set_t * create_path_set (); +void sort_path_set (struct path_set_t *, guint); +void pop_front_path_set (struct path_set_t *); +void remove_path_set(struct path_set_t*); + +void build_map_node(struct map_nodes_t *, struct graph_t *); +struct compRouteOutputList_t * create_route_list(); +void duplicate_route_list(struct compRouteOutputList_t *, struct compRouteOutputList_t *); +struct compRouteOutputItem_t * create_path_item (); +void add_routeElement_path_back (struct routeElement_t *, struct compRouteOutputItem_t *); +gboolean matching_path_rootPath (struct compRouteOutputItem_t *, struct compRouteOutputItem_t *, struct nodes_t *, struct edges_t *); +void modify_targeted_graph (struct graph_t *, struct path_set_t *, struct compRouteOutputItem_t *, struct nodes_t *); +gint find_nodeId (gconstpointer, gconstpointer); +gint check_link (struct nodeItem_t *, gint, gint, struct graph_t *, struct service_t *, GList **, GList **, struct map_nodes_t *, guint arg); +gboolean check_computed_path_feasability (struct service_t *, struct compRouteOutputItem_t * ); + +gint sort_by_distance (gconstpointer, gconstpointer); +gint sort_by_energy(gconstpointer, gconstpointer); + +struct graph_t * create_graph (); +struct map_nodes_t * create_map_node (); + +struct service_t * get_service_for_computed_path(gchar *); + +void print_service_type(guint); +void print_link_port_direction(guint); +void print_termination_direction(guint); +void print_termination_state(guint); +void print_capacity_unit(guint); +void print_link_forwarding_direction(guint); + +void build_contextSet(GList **); +void build_contextSet_active(GList **); +void print_contextSet(GList *); + +gint same_src_dst_pe_nodeid (struct service_t *); +void comp_route_connection_issue_handler (struct compRouteOutput_t *, struct service_t *); + +void destroy_compRouteOutputList (struct compRouteOutputList_t *); +void duplicate_graph (struct graph_t *, struct graph_t *); + +void allocate_graph_resources (struct path_t *, struct service_t *, struct graph_t *); +void allocate_graph_reverse_resources(struct path_t*, struct service_t *, struct graph_t *); +void print_route_solution_list (GList *); +struct timeval tv_adjust(struct timeval); + +void print_path_connection_list(struct compRouteOutputList_t*); +void update_stats_path_comp(struct compRouteOutputList_t*, struct timeval, gint, gint); +void destroy_active_service(struct activeService_t*); +void destroy_requested_service(struct service_t*); +void destroy_device(struct device_t*); +void destroy_link(struct link_t*); +void destroy_context(struct context_t*); +void dijkstra(gint, gint, struct graph_t*, struct service_t*, struct map_nodes_t*, struct nodes_t*, struct compRouteOutputItem_t*, guint); +void set_path_attributes(struct compRouteOutputItem_t*, struct map_t*); +void alg_comp(struct service_t*, struct compRouteOutput_t*, struct graph_t*, guint); #endif \ No newline at end of file -- GitLab From 898cc5293ed3aaa938bcab7c1c1e4132498ae5b8 Mon Sep 17 00:00:00 2001 From: martinezric Date: Wed, 3 May 2023 14:51:04 +0200 Subject: [PATCH 2/7] PathComp Backend corrected line breaks --- src/pathcomp/backend/pathComp_sp.c | 588 +-- src/pathcomp/backend/pathComp_tools.c | 6800 ++++++++++++------------- src/pathcomp/backend/pathComp_tools.h | 1246 ++--- 3 files changed, 4317 insertions(+), 4317 deletions(-) diff --git a/src/pathcomp/backend/pathComp_sp.c b/src/pathcomp/backend/pathComp_sp.c index 252c1d614..6510a0d7d 100644 --- a/src/pathcomp/backend/pathComp_sp.c +++ b/src/pathcomp/backend/pathComp_sp.c @@ -1,294 +1,294 @@ -//////////////////////////////////////////////////////////////////////////////////////// -/** - * # Copyright 2022 Centre Tecnològic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es - * - * 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. - - * Author: CTTC/CERCA PONS RU Ricardo Martínez (ricardo.martinez@cttc.es) - */ - //////////////////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pathComp_log.h" -#include "pathComp_tools.h" -#include "pathComp_sp.h" - -// Global Variables -GList* contextSet; - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_sp.c - * @brief handling the Dijkstra algorithm - * - * @param pred - * @param g - * @param s - * @param mapNodes - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gint computation(struct pred_t* pred, struct graph_t* g, struct service_t* s, struct map_nodes_t* mapNodes) { - g_assert(pred); - g_assert(g); - g_assert(s); - - // Check the both ingress src and dst endpoints are in the graph - gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); - if (srcMapIndex == -1) { - DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); - return -1; - } - - gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); - if (dstMapIndex == -1) { - DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); - return -1; - } - - // Compute the shortest path - dijkstra(srcMapIndex, dstMapIndex, g, s, mapNodes, NULL, NULL, 0x00000000); - - // Check that a feasible solution in term of latency and bandwidth is found - gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); - struct map_t* dest_map = &mapNodes->map[map_dstIndex]; - if (!(dest_map->distance < INFINITY_COST)) { - DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); - return -1; - } - - DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); - // Check that the computed available bandwidth is larger than 0.0 - if (dest_map->avaiBandwidth <= (gfloat)0.0) { - DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); - return -1; - } - DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); - // Handle predecessors - build_predecessors(pred, s, mapNodes); - - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_sp.c - * @brief CSPF algorithm execution - * - * @param s - * @param path - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void computation_shortest_path(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g) { - g_assert(s); - g_assert(path); - g_assert(g); - - // create map of devices / nodes to handle the path computation using the context - struct map_nodes_t *mapNodes = create_map_node(); - build_map_node(mapNodes, g); - - // predecessors to store the computed path - struct pred_t* predecessors = create_predecessors(); - - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); - struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); - - // SP computation - gint done = computation(predecessors, g, s, mapNodes); - if (done == -1) { - DEBUG_PC("NO PATH FOUND %s[%s] ---> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); - comp_route_connection_issue_handler(path, s); - g_free(mapNodes); g_free(predecessors); - return; - } - - // Construct the path from the computed predecessors - struct compRouteOutputItem_t* p = create_path_item(); - //print_predecessors(predecessors); - build_path(p, predecessors, s); - //DEBUG_PC ("Path is constructed"); - - gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); - struct map_t* dst_map = &mapNodes->map[indexDest]; - set_path_attributes(p, dst_map); - DEBUG_PC("Computed Path Avail Bw: %f, Path Cost: %f, latency: %f", p->availCap, p->cost, p->delay); - print_path(p); - - gboolean feasibleRoute = check_computed_path_feasability(s, p); - if (feasibleRoute == TRUE) { - DEBUG_PC("SP Feasible"); - print_path(p); - path->numPaths++; - - // Copy the serviceId - DEBUG_PC("contextId: %s", s->serviceId.contextId); - copy_service_id(&path->serviceId, &s->serviceId); - - // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) - for (gint i = 0; i < s->num_service_endpoints_id; i++) { - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); - struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); - copy_service_endpoint_id(oEp, iEp); - } - path->num_service_endpoints_id = s->num_service_endpoints_id; - - // Copy the computed path - struct path_t* targetedPath = &(path->paths[path->numPaths - 1]); - duplicate_path_t(p, targetedPath); - print_path_t(targetedPath); - g_free(predecessors); - g_free(p); - g_free(mapNodes); - return; - } - DEBUG_PC("SP FAILED!!!"); - comp_route_connection_issue_handler(path, s); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_sp.c - * @brief Iterates over the list of network connectivity service requests - * to compute their own paths fulfilling the constraints - * - * @param outputList - * - * @author Ricardo Martínez - * @date 2022 - */ -void sp_execution_services(struct compRouteOutputList_t* oPathList) { - g_assert(oPathList); - // Check at least there is a service to be processed - if (g_list_length(serviceList) == 0) { - DEBUG_PC("Lengtg requested serviceList is Empty..."); - return; - } - - DEBUG_PC("----- Starting the SP Computation ------"); - gint i = 0; - for (GList* listnode = g_list_first(serviceList); - listnode; - listnode = g_list_next(listnode), i++) { - //struct service_t* service = &(serviceList->services[i]); - struct service_t* service = (struct service_t*)(listnode->data); - - DEBUG_PC("Starting the Computation for ServiceId: %s [ContextId: %s]", service->serviceId.service_uuid, service->serviceId.contextId); - struct compRouteOutput_t* pathService = &(oPathList->compRouteConnection[i]); - // check endpoints of the service are different (PE devices/nodes are different) - if (same_src_dst_pe_nodeid(service) == 0) { - DEBUG_PC("PEs are the same... no path computation"); - comp_route_connection_issue_handler(pathService, service); - oPathList->numCompRouteConnList++; - continue; - } - - // get the graph associated to the contextId in the contextSet, if no then error - struct graph_t* g = get_graph_by_contextId(contextSet, service->serviceId.contextId); - if (g == NULL) { - DEBUG_PC("The targeted contextId is NOT in the ContextSet ... then NO graph"); - comp_route_connection_issue_handler(pathService, service); - oPathList->numCompRouteConnList++; - continue; - } - - computation_shortest_path(service, pathService, g); - oPathList->numCompRouteConnList++; - - // for each network connectivity service, a single computed path (out of the KCSP) is retuned - // If path is found, then the selected resources must be pre-assigned into the context information - if (pathService->noPathIssue == NO_PATH_CONS_ISSUE) { - continue; - } - struct path_t* path = &(pathService->paths[pathService->numPaths - 1]); - allocate_graph_resources(path, service, g); - allocate_graph_reverse_resources(path, service, g); - print_graph(g); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_sp.c - * @brief handles the path computation for the constrained shortest path - * - * @param compRouteOutput - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gint pathComp_sp_alg(struct compRouteOutputList_t* routeConnList) { - g_assert(routeConnList); - gint numSuccesPathComp = 0, numPathCompIntents = 0; - - DEBUG_PC("================================================================"); - DEBUG_PC("=========================== SP ========================="); - DEBUG_PC("================================================================"); - // increase the number of Path Comp. Intents - numPathCompIntents++; - gint http_code = HTTP_CODE_OK; - - // timestamp t0 - struct timeval t0; - gettimeofday(&t0, NULL); - - // Allocate memory for the context - contextSet = NULL; - // Build up the contextSet (>= 1) - build_contextSet(&contextSet); - print_contextSet(contextSet); -#if 1 - //Triggering the path computation for each specific network connectivity service - sp_execution_services(routeConnList); - - // -- timestamp t1 - struct timeval t1, delta; - gettimeofday(&t1, NULL); - delta.tv_sec = t1.tv_sec - t0.tv_sec; - delta.tv_usec = t1.tv_usec - t0.tv_usec; - delta = tv_adjust(delta); - - numSuccesPathComp++; - update_stats_path_comp(routeConnList, delta, numSuccesPathComp, numPathCompIntents); - print_path_connection_list(routeConnList); -#endif - - g_list_free_full(g_steal_pointer(&contextSet), (GDestroyNotify)destroy_context); - return http_code; -} - - +//////////////////////////////////////////////////////////////////////////////////////// +/** + * # Copyright 2022 Centre Tecnològic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es + * + * 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. + + * Author: CTTC/CERCA PONS RU Ricardo Martínez (ricardo.martinez@cttc.es) + */ + //////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathComp_log.h" +#include "pathComp_tools.h" +#include "pathComp_sp.h" + +// Global Variables +GList* contextSet; + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_sp.c + * @brief handling the Dijkstra algorithm + * + * @param pred + * @param g + * @param s + * @param mapNodes + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gint computation(struct pred_t* pred, struct graph_t* g, struct service_t* s, struct map_nodes_t* mapNodes) { + g_assert(pred); + g_assert(g); + g_assert(s); + + // Check the both ingress src and dst endpoints are in the graph + gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); + if (srcMapIndex == -1) { + DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); + return -1; + } + + gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); + if (dstMapIndex == -1) { + DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); + return -1; + } + + // Compute the shortest path + dijkstra(srcMapIndex, dstMapIndex, g, s, mapNodes, NULL, NULL, 0x00000000); + + // Check that a feasible solution in term of latency and bandwidth is found + gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); + struct map_t* dest_map = &mapNodes->map[map_dstIndex]; + if (!(dest_map->distance < INFINITY_COST)) { + DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); + return -1; + } + + DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); + // Check that the computed available bandwidth is larger than 0.0 + if (dest_map->avaiBandwidth <= (gfloat)0.0) { + DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); + return -1; + } + DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); + // Handle predecessors + build_predecessors(pred, s, mapNodes); + + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_sp.c + * @brief CSPF algorithm execution + * + * @param s + * @param path + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void computation_shortest_path(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g) { + g_assert(s); + g_assert(path); + g_assert(g); + + // create map of devices / nodes to handle the path computation using the context + struct map_nodes_t *mapNodes = create_map_node(); + build_map_node(mapNodes, g); + + // predecessors to store the computed path + struct pred_t* predecessors = create_predecessors(); + + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); + struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); + + // SP computation + gint done = computation(predecessors, g, s, mapNodes); + if (done == -1) { + DEBUG_PC("NO PATH FOUND %s[%s] ---> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); + comp_route_connection_issue_handler(path, s); + g_free(mapNodes); g_free(predecessors); + return; + } + + // Construct the path from the computed predecessors + struct compRouteOutputItem_t* p = create_path_item(); + //print_predecessors(predecessors); + build_path(p, predecessors, s); + //DEBUG_PC ("Path is constructed"); + + gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); + struct map_t* dst_map = &mapNodes->map[indexDest]; + set_path_attributes(p, dst_map); + DEBUG_PC("Computed Path Avail Bw: %f, Path Cost: %f, latency: %f", p->availCap, p->cost, p->delay); + print_path(p); + + gboolean feasibleRoute = check_computed_path_feasability(s, p); + if (feasibleRoute == TRUE) { + DEBUG_PC("SP Feasible"); + print_path(p); + path->numPaths++; + + // Copy the serviceId + DEBUG_PC("contextId: %s", s->serviceId.contextId); + copy_service_id(&path->serviceId, &s->serviceId); + + // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) + for (gint i = 0; i < s->num_service_endpoints_id; i++) { + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); + struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); + copy_service_endpoint_id(oEp, iEp); + } + path->num_service_endpoints_id = s->num_service_endpoints_id; + + // Copy the computed path + struct path_t* targetedPath = &(path->paths[path->numPaths - 1]); + duplicate_path_t(p, targetedPath); + print_path_t(targetedPath); + g_free(predecessors); + g_free(p); + g_free(mapNodes); + return; + } + DEBUG_PC("SP FAILED!!!"); + comp_route_connection_issue_handler(path, s); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_sp.c + * @brief Iterates over the list of network connectivity service requests + * to compute their own paths fulfilling the constraints + * + * @param outputList + * + * @author Ricardo Martínez + * @date 2022 + */ +void sp_execution_services(struct compRouteOutputList_t* oPathList) { + g_assert(oPathList); + // Check at least there is a service to be processed + if (g_list_length(serviceList) == 0) { + DEBUG_PC("Lengtg requested serviceList is Empty..."); + return; + } + + DEBUG_PC("----- Starting the SP Computation ------"); + gint i = 0; + for (GList* listnode = g_list_first(serviceList); + listnode; + listnode = g_list_next(listnode), i++) { + //struct service_t* service = &(serviceList->services[i]); + struct service_t* service = (struct service_t*)(listnode->data); + + DEBUG_PC("Starting the Computation for ServiceId: %s [ContextId: %s]", service->serviceId.service_uuid, service->serviceId.contextId); + struct compRouteOutput_t* pathService = &(oPathList->compRouteConnection[i]); + // check endpoints of the service are different (PE devices/nodes are different) + if (same_src_dst_pe_nodeid(service) == 0) { + DEBUG_PC("PEs are the same... no path computation"); + comp_route_connection_issue_handler(pathService, service); + oPathList->numCompRouteConnList++; + continue; + } + + // get the graph associated to the contextId in the contextSet, if no then error + struct graph_t* g = get_graph_by_contextId(contextSet, service->serviceId.contextId); + if (g == NULL) { + DEBUG_PC("The targeted contextId is NOT in the ContextSet ... then NO graph"); + comp_route_connection_issue_handler(pathService, service); + oPathList->numCompRouteConnList++; + continue; + } + + computation_shortest_path(service, pathService, g); + oPathList->numCompRouteConnList++; + + // for each network connectivity service, a single computed path (out of the KCSP) is retuned + // If path is found, then the selected resources must be pre-assigned into the context information + if (pathService->noPathIssue == NO_PATH_CONS_ISSUE) { + continue; + } + struct path_t* path = &(pathService->paths[pathService->numPaths - 1]); + allocate_graph_resources(path, service, g); + allocate_graph_reverse_resources(path, service, g); + print_graph(g); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_sp.c + * @brief handles the path computation for the constrained shortest path + * + * @param compRouteOutput + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gint pathComp_sp_alg(struct compRouteOutputList_t* routeConnList) { + g_assert(routeConnList); + gint numSuccesPathComp = 0, numPathCompIntents = 0; + + DEBUG_PC("================================================================"); + DEBUG_PC("=========================== SP ========================="); + DEBUG_PC("================================================================"); + // increase the number of Path Comp. Intents + numPathCompIntents++; + gint http_code = HTTP_CODE_OK; + + // timestamp t0 + struct timeval t0; + gettimeofday(&t0, NULL); + + // Allocate memory for the context + contextSet = NULL; + // Build up the contextSet (>= 1) + build_contextSet(&contextSet); + print_contextSet(contextSet); +#if 1 + //Triggering the path computation for each specific network connectivity service + sp_execution_services(routeConnList); + + // -- timestamp t1 + struct timeval t1, delta; + gettimeofday(&t1, NULL); + delta.tv_sec = t1.tv_sec - t0.tv_sec; + delta.tv_usec = t1.tv_usec - t0.tv_usec; + delta = tv_adjust(delta); + + numSuccesPathComp++; + update_stats_path_comp(routeConnList, delta, numSuccesPathComp, numPathCompIntents); + print_path_connection_list(routeConnList); +#endif + + g_list_free_full(g_steal_pointer(&contextSet), (GDestroyNotify)destroy_context); + return http_code; +} + + diff --git a/src/pathcomp/backend/pathComp_tools.c b/src/pathcomp/backend/pathComp_tools.c index ab4a394f1..139d97325 100644 --- a/src/pathcomp/backend/pathComp_tools.c +++ b/src/pathcomp/backend/pathComp_tools.c @@ -1,3401 +1,3401 @@ -//////////////////////////////////////////////////////////////////////////////////////// -/** - * # Copyright 2022 Centre Tecnològic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es - * - * 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. - - * Author: CTTC/CERCA PONS RU Ricardo Martínez (ricardo.martinez@cttc.es) - */ -///////////////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pathComp_log.h" -#include "pathComp.h" -#include "pathComp_tools.h" - -gint numPathCompIntents = 0; // number of events triggering the path computation -//gint numSuccesPathComp = 0; // number of events resulting in succesfully path computations fulfilling the constraints -struct timeval total_path_comp_time; -gdouble totalReqBw = 0.0; -gdouble totalServedBw = 0.0; - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function for time processing - * - * @param a - * - * @author Ricardo Martínez - * @date 2022 - */ - //////////////////////////////////////////////////////////////////////////////////////// -struct timeval tv_adjust (struct timeval a) { - while (a.tv_usec >= 1000000) { - a.tv_usec -= 1000000; - a.tv_sec++; - } - while (a.tv_usec < 0) { - a.tv_usec += 1000000; - a.tv_sec--; - } - return a; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief friendly function to copy safely strings - * - * @param dst - * @param src - * - * @author Ricardo Martínez - * @date 2022 - */ - //////////////////////////////////////////////////////////////////////////////////////// -void duplicate_string(gchar* dst, gchar* src) { - g_assert(dst); g_assert(src); - strcpy(dst, src); - dst[strlen(dst)] = '\0'; - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to print the computed the path - * - * @param path - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void print_path (struct compRouteOutputItem_t *p) { - g_assert(p); - DEBUG_PC ("=========== COMPUTED PATH ======================="); - DEBUG_PC ("E2E Avail. Bw: %f, Latency: %f, Cost: %f, Consumed Power (in W): %f", p->availCap, p->delay, p->cost, p->power); - for (gint k = 0; k < p->numRouteElements; k++) { - DEBUG_PC ("%s[%s] --> %s[%s]", p->routeElement[k].aNodeId.nodeId, p->routeElement[k].aEndPointId, - p->routeElement[k].zNodeId.nodeId, p->routeElement[k].zEndPointId); - DEBUG_PC("\t linkId: %s", p->routeElement[k].linkId); - DEBUG_PC("\t aTopologyId: %s", p->routeElement[k].aTopologyId); - DEBUG_PC("\t zTopologyId: %s", p->routeElement[k].zTopologyId); - } - DEBUG_PC ("=================================================================="); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to print the output path formed by link Ids - * - * @param p - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_path_t(struct path_t* p) { - g_assert(p); - DEBUG_PC(" ============ COMPUTED OUTPUT PATH ================="); - DEBUG_PC("Path AvailBw: %f, Cost: %f, Latency: %f, Power: %f", p->path_capacity.value, - p->path_cost.cost_value, p->path_latency.fixed_latency, p->path_power.power); - DEBUG_PC("number of links of path %d", p->numPathLinks); - for (gint k = 0; k < p->numPathLinks; k++) { - DEBUG_PC("Link: %s", p->pathLinks[k].linkId); - for (gint l = 0; l < p->pathLinks[k].numLinkTopologies; l++) { - DEBUG_PC("end Link [%d] TopologyId: %s", l, p->pathLinks[k].linkTopologies[l].topologyId); - } - DEBUG_PC(" ContextId: %s", p->pathLinks[k].topologyId.contextId); - DEBUG_PC(" TopologyUUid: %s", p->pathLinks[k].topologyId.topology_uuid); - DEBUG_PC(" aDeviceId: %s", p->pathLinks[k].aDeviceId); - DEBUG_PC(" aEndpointId: %s", p->pathLinks[k].aEndPointId); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used allocate memory for struct path_t - * - * - * @author Ricardo Martínez - * @date 2022 - */ - //////////////////////////////////////////////////////////////////////////////////////// -struct path_t* create_path() { - struct path_t* p = g_malloc0(sizeof(struct path_t)); - if (p == NULL) { - DEBUG_PC("Memory allocation failure"); - exit(-1); - } - return(p); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Returns the char (36 bytes) format of a uuid - * - * @param uuid - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gchar* get_uuid_char(uuid_t uuid) { - gchar* uuidChar = g_malloc0(16); // uuid has 36 chars - if (uuidChar == NULL) { - DEBUG_PC("Memory Allocation failure"); - exit(-1); - } - uuid_unparse(uuid, (char *)uuidChar); - return uuidChar; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Makes a copy of the service identifier (including the context) - * - * @param o - * @param i - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void copy_service_id(struct serviceId_t* o, struct serviceId_t* i) { - g_assert(o); g_assert(i); - memcpy(o->contextId, i->contextId, sizeof(i->contextId)); - memcpy(o->service_uuid, i->service_uuid, sizeof(i->service_uuid)); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Makes a copy of the service endpoint identifier (including the topology (contect and topology id), device and endpoint (port)) - * - * @param oEp - * @param iEp - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void copy_service_endpoint_id(struct service_endpoints_id_t* oEp, struct service_endpoints_id_t* iEp) { - g_assert(oEp); g_assert(iEp); - - // copy topology information - memcpy(oEp->topology_id.contextId, iEp->topology_id.contextId, sizeof(iEp->topology_id.contextId)); - memcpy(oEp->topology_id.topology_uuid, iEp->topology_id.topology_uuid, sizeof(iEp->topology_id.topology_uuid)); - - // copy the endpoint - memcpy(oEp->device_uuid, iEp->device_uuid, sizeof(iEp->device_uuid)); - memcpy(oEp->endpoint_uuid, iEp->endpoint_uuid, sizeof(iEp->endpoint_uuid)); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief From the set of contexts, it is returned the graph associated to that context matching - * with the passed contextId. - * - * @param Set - * @param contextId - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct graph_t* get_graph_by_contextId(GList* set, gchar* contextId) { - g_assert(contextId); - - // iterate over the set of context. Pick the one matching with contextId, and return the graph. - // If not found, return NULL - struct graph_t* g = NULL; - for (GList *ln = g_list_first(set); - ln; - ln = g_list_next(ln)){ - struct context_t* context = (struct context_t*)(ln->data); - if (strcmp(context->contextId, contextId) == 0) { - g = &(context->g); - return g; - } - } - return NULL; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Process the service constraint and maps them into the path constraints - * to be fulfilled - * - * @param path_constraints - * @param s - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct path_constraints_t * get_path_constraints(struct service_t* s) { - g_assert(s); - - struct path_constraints_t* path_constraints = g_malloc0(sizeof(struct path_constraints_t)); - if (path_constraints == NULL) { - DEBUG_PC("Memory Allocation Failure"); - exit(-1); - } - - char* eptr; - for (gint i = 0; i < s->num_service_constraints; i++) { - struct constraint_t* constraint = &(s->constraints[i]);; - if (strncmp((const char*)constraint->constraint_type, "bandwidth", 9) == 0) { - path_constraints->bwConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); - path_constraints->bw = TRUE; - //DEBUG_PC("Path Constraint Bw: %f", path_constraints->bwConstraint); - } - if (strncmp((const char*)constraint->constraint_type, "cost", 4) == 0) { - path_constraints->costConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); - path_constraints->cost = TRUE; - //DEBUG_PC("Path Constraint Cost: %f", path_constraints->costConstraint); - } - if (strncmp((const char*)constraint->constraint_type, "latency", 7) == 0) { - path_constraints->latencyConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); - path_constraints->latency = TRUE; - //DEBUG_PC("Path Constraint Latency: %f", path_constraints->latencyConstraint); - } - if (strncmp((const char*)constraint->constraint_type, "energy", 6) == 0) { - path_constraints->energyConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); - path_constraints->energy = TRUE; - //DEBUG_PC("Path Constraint Energy: %f", path_constraints->energyConstraint); - } - } - return path_constraints; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Creates the predecessors to keep the computed path - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct pred_t * create_predecessors () { - struct pred_t *predecessors = g_malloc0 (sizeof (struct pred_t)); - if (predecessors == NULL) { - DEBUG_PC ("memory allocation failed\n"); - exit (-1); - } - return predecessors; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief create edge - * - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct edges_t* create_edge() { - struct edges_t* e = g_malloc0(sizeof(struct edges_t)); - if (e == NULL) { - DEBUG_PC("Memory allocation failed\n"); - exit(-1); - } - return e; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Prints the list of the predecessors for a given computed Shortest Path - * - * @param p - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void print_predecessors (struct pred_t *p) -{ - g_assert (p); - DEBUG_PC ("Number of Predecessors: %d", p->numPredComp); - for (gint i = 0; i < p->numPredComp; i++) { - struct pred_comp_t *pComp = &(p->predComp[i]); - DEBUG_PC ("deviceId: %s", pComp->v.nodeId); - struct edges_t *e = &(pComp->e); - DEBUG_PC("Edge[#%d] (linkId): %s", i, e->linkId); - DEBUG_PC ("\t %s[%s] ===>", e->aNodeId.nodeId, e->aEndPointId); - DEBUG_PC("\t %s[%s]", e->zNodeId.nodeId, e->zEndPointId); - DEBUG_PC("\t aTopologyId: %s", e->aTopologyId); - DEBUG_PC("\t zTopologyId: %s", e->zTopologyId); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Builds the list of predecessors for the request destination using the computed Shortest Path - * being stored in map - * - * @param p - * @param s - * @param map - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void build_predecessors (struct pred_t *p, struct service_t *s, struct map_nodes_t *map) { - g_assert (p); g_assert (s); g_assert (map); - - struct nodes_t *v = create_node(); - duplicate_string(v->nodeId, s->service_endpoints_id[1].device_uuid); - - struct edges_t *e = create_edge(); - get_edge_from_map_by_node (e, v, map); - - // Get u (being source of edge e) - struct nodes_t u; - duplicate_node_id (&e->aNodeId, &u); - - // Add to the predecessors list - struct pred_comp_t *pred = &(p->predComp[p->numPredComp]); - duplicate_node_id (&u, &pred->v); - struct edges_t *e1 = &(pred->e); - duplicate_edge (e1, e); - p->numPredComp++; - // Back-trace edges till reaching the srcPEId - struct nodes_t* srcNode = create_node(); - duplicate_string(srcNode->nodeId, s->service_endpoints_id[0].device_uuid); - - while (compare_node_id (&u, srcNode) != 0) { - duplicate_node_id (&u, v); - get_edge_from_map_by_node (e, v, map); - // Get the u (being source of edge e) - duplicate_node_id (&e->aNodeId, &u); - // Get the new predecessor - struct pred_comp_t *pred = &p->predComp[p->numPredComp]; - // Add to the predecessors list - duplicate_node_id (&u, &pred->v); - struct edges_t *e1 = &(pred->e); - duplicate_edge (e1, e); - p->numPredComp++; - } - print_predecessors (p); - g_free (e); g_free(v); g_free(srcNode); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief It creates a struct nodes_t - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct nodes_t * create_node () -{ - struct nodes_t *n = g_malloc0 (sizeof (struct nodes_t)); - if (n == NULL) { - DEBUG_PC ("memory allocation problem"); - exit (-1); - } - return n; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief It creates a routeElement_t - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct routeElement_t * create_routeElement () { - struct routeElement_t *rE = g_malloc0 (sizeof (struct routeElement_t)); - if (rE == NULL) { - DEBUG_PC ("memory allocation problem"); - exit (-1); - } - return rE; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief copy node ids - * - * @param src - * @param dst - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_node_id (struct nodes_t *src, struct nodes_t *dst) { - g_assert (src); - g_assert (dst); - //DEBUG_PC ("Duplicate nodeId for %s", src->nodeId); - strcpy (dst->nodeId, src->nodeId); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief compares a pair of node Ids - * - * @param a - * @param b - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint compare_node_id (struct nodes_t *a, struct nodes_t *b) { - g_assert (a); - g_assert (b); - return (memcmp (&a->nodeId, b->nodeId, strlen (b->nodeId))); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief duplicate two routeElement_t - * - * @param src - * @param dst - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_routeElement (struct routeElement_t *src, struct routeElement_t *dst) -{ - g_assert (src); - g_assert (dst); - - duplicate_node_id (&(src->aNodeId), &(dst->aNodeId)); - duplicate_node_id (&(src->zNodeId), &(dst->zNodeId)); - duplicate_string(dst->aEndPointId, src->aEndPointId); - duplicate_string(dst->zEndPointId, src->zEndPointId); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief duplicate two edges - * - * @param e1 (destination) - * @param e2 (source) - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_edge (struct edges_t *e1, struct edges_t *e2) { - g_assert (e1); g_assert (e2); - - duplicate_node_id (&e2->aNodeId, &e1->aNodeId); - duplicate_node_id (&e2->zNodeId, &e1->zNodeId); - //DEBUG_PC ("e->aNodeId: %s ---> e->zNodeId: %s", e1->aNodeId.nodeId, e1->zNodeId.nodeId); - duplicate_string(e1->aEndPointId, e2->aEndPointId); - duplicate_string(e1->zEndPointId, e2->zEndPointId); - duplicate_string(e1->linkId, e2->linkId); - duplicate_string(e1->interDomain_localId, e2->interDomain_localId); - duplicate_string(e1->interDomain_remoteId, e2->interDomain_remoteId); - duplicate_string(e1->aTopologyId, e2->aTopologyId); - duplicate_string(e1->zTopologyId, e2->zTopologyId); - - e1->unit = e2->unit; - memcpy(&e1->totalCap, &e2->totalCap, sizeof(gdouble)); - memcpy(&e1->availCap, &e2->availCap, sizeof(gdouble)); - - memcpy (&e1->cost, &e2->cost, sizeof (gdouble)); - memcpy (&e1->delay, &e2->delay, sizeof (gdouble)); - memcpy(&e1->energy, &e2->energy, sizeof(gdouble)); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Duplicate path - * - * @param a - original - * @param b - copy - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_path (struct compRouteOutputItem_t *a, struct compRouteOutputItem_t *b) { - g_assert (a); g_assert (b); - memcpy(&b->availCap, &a->availCap, sizeof (gdouble)); - memcpy(&b->cost, &a->cost, sizeof(gdouble)); - memcpy(&b->delay, &a->delay, sizeof (gdouble)); - memcpy(&b->power, &a->power, sizeof(gdouble)); - b->numRouteElements = a->numRouteElements; - for (gint k = 0; k < a->numRouteElements; k++) { - //DEBUG_PC ("aNodeId: %s // zNodeId: %s", a->routeElement[k].aNodeId.nodeId, a->routeElement[k].zNodeId.nodeId); - // aNodeId duplication - struct nodes_t *n1 = &(a->routeElement[k].aNodeId); - struct nodes_t *n2 = &(b->routeElement[k].aNodeId); - duplicate_node_id (n1, n2); - //zNodeId duplication - n1 = &(a->routeElement[k].zNodeId); - n2 = &(b->routeElement[k].zNodeId); - duplicate_node_id (n1, n2); - duplicate_string(b->routeElement[k].aEndPointId, a->routeElement[k].aEndPointId); - duplicate_string(b->routeElement[k].zEndPointId, a->routeElement[k].zEndPointId); - duplicate_string(b->routeElement[k].linkId, a->routeElement[k].linkId); - duplicate_string(b->routeElement[k].aTopologyId, a->routeElement[k].aTopologyId); - duplicate_string(b->routeElement[k].zTopologyId, a->routeElement[k].zTopologyId); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Duplicate path from compRouteOutputItem_t to path_t - * - * @param a - original - * @param b - copy - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_path_t(struct compRouteOutputItem_t* a, struct path_t* b) { - g_assert(a); g_assert(b); - - // transfer path characteristics ... - memcpy(&b->path_capacity.value, &a->availCap, sizeof(gdouble)); - memcpy(&b->path_cost.cost_value, &a->cost, sizeof(gdouble)); - memcpy(&b->path_latency.fixed_latency, &a->delay, sizeof(gdouble)); - memcpy(&b->path_power.power, &a->power, sizeof(gdouble)); - - b->numPathLinks = a->numRouteElements; - - for (gint k = 0; k < a->numRouteElements; k++) { - struct routeElement_t* rE = &(a->routeElement[k]); - struct pathLink_t* pL = &(b->pathLinks[k]); - - // copy the aDeviceId and aEndpointId, zDeviceId and zEndPointId - duplicate_string(pL->aDeviceId, rE->aNodeId.nodeId); - duplicate_string(pL->zDeviceId, rE->zNodeId.nodeId); - duplicate_string(pL->aEndPointId, rE->aEndPointId); - duplicate_string(pL->zEndPointId, rE->zEndPointId); - - duplicate_string(pL->topologyId.topology_uuid, rE->aTopologyId); - duplicate_string(pL->topologyId.contextId, rE->contextId); - - //copy the linkId - duplicate_string(pL->linkId, rE->linkId); - pL->numLinkTopologies++; - duplicate_string(pL->linkTopologies[pL->numLinkTopologies - 1].topologyId, rE->aTopologyId); - pL->numLinkTopologies++; - duplicate_string(pL->linkTopologies[pL->numLinkTopologies - 1].topologyId, rE->zTopologyId); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Return the index into mapN related nodeId - * - * @param nodeId - * @para mapN - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint get_map_index_by_nodeId (gchar *nodeId, struct map_nodes_t * mapN) { - gint i = 0; - for (i = 0; i < mapN->numMapNodes; i++) { - //DEBUG_PC ("i: %d; current: %s // targeted: %s", i, mapN->map[i].verticeId.nodeId, nodeId); - if (memcmp (mapN->map[i].verticeId.nodeId, nodeId, strlen (nodeId)) == 0) { - //DEBUG_PC ("Index: %d", i); - return i; - } - } - //DEBUG_PC ("Index: %d", index); - return -1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Get the edge e enabling reaching the computed v in mapNodes - * - * @param e - * @param v - * @param mapN - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void get_edge_from_map_by_node (struct edges_t *e, struct nodes_t* v, struct map_nodes_t *mapN) { - //DEBUG_PC ("Get the Edge into map from node v: %s", v.nodeId); - // Get the edge reaching the node v from mapNodes - gint map_vIndex = get_map_index_by_nodeId (v->nodeId, mapN); - //DEBUG_PC ("aNodeId: %s --> zNodeId: %s", mapN->map[map_vIndex].predecessor.aNodeId.nodeId, mapN->map[map_vIndex].predecessor.zNodeId.nodeId); - struct edges_t *te = &(mapN->map[map_vIndex].predecessor); - duplicate_edge (e, te); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Get the edge from the predecessors array for a given node n - * - * @param e - * @param n - * @param predecessors - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void get_edge_from_predecessors (struct edges_t *e, struct nodes_t* n, struct pred_t *predecessors) { - g_assert(predecessors); - DEBUG_PC ("Get edge outgoing node %s from predecessors list", n->nodeId); - //print_predecessors (predecessors); - for (gint i = 0; i < predecessors->numPredComp; i++) { - struct pred_comp_t *pred = &(predecessors->predComp[i]); - if (compare_node_id (n, &pred->v) == 0) { - // Add to the predecessors list - struct edges_t *te = &(pred->e); - DEBUG_PC("add e (linkId): %s", te->linkId); - duplicate_edge (e, te); - return; - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Construct the path using the predecessors list - * - * @param path - * @param predecessors - * @param s - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void build_path (struct compRouteOutputItem_t *p, struct pred_t *predecessors, struct service_t *s) { - // Get the source device Id of the network connectivity service - struct nodes_t *v = create_node(); - // Src Node of the Service set to v - duplicate_string(v->nodeId, s->service_endpoints_id[0].device_uuid); - - // Get the edge for v in predecessors - struct edges_t* e = create_edge(); - get_edge_from_predecessors (e, v, predecessors); - // Get the target for e - struct nodes_t u; - duplicate_node_id (&e->zNodeId, &u); - //DEBUG_PC ("u: %s", u.nodeId); - struct path_constraints_t* pathCons = get_path_constraints(s); - - // Add route element to the path being constructed - gint k = 0; - duplicate_node_id (&e->aNodeId, &p->routeElement[k].aNodeId); - duplicate_node_id (&e->zNodeId, &p->routeElement[k].zNodeId); - duplicate_string(p->routeElement[k].aEndPointId, e->aEndPointId); - duplicate_string(p->routeElement[k].zEndPointId, e->zEndPointId); - duplicate_string(p->routeElement[k].linkId, e->linkId); - duplicate_string(p->routeElement[k].aTopologyId, e->aTopologyId); - duplicate_string(p->routeElement[k].zTopologyId, e->zTopologyId); - duplicate_string(p->routeElement[k].contextId, s->serviceId.contextId); - p->numRouteElements++; - - // Get Dst Node of connectivity service - struct nodes_t* dst = create_node(); - duplicate_string(dst->nodeId, s->service_endpoints_id[1].device_uuid); - while (compare_node_id (&u, dst) != 0) { - k++; - p->numRouteElements++; - duplicate_node_id (&u, v); - get_edge_from_predecessors (e, v, predecessors); - // Get the target u - duplicate_node_id (&e->zNodeId, &u); - // Add route element to the path being constructed - duplicate_node_id (&e->aNodeId, &p->routeElement[k].aNodeId); - duplicate_node_id (&e->zNodeId, &p->routeElement[k].zNodeId); - duplicate_string(p->routeElement[k].aEndPointId, e->aEndPointId); - duplicate_string(p->routeElement[k].zEndPointId, e->zEndPointId); - duplicate_string(p->routeElement[k].linkId, e->linkId); - duplicate_string(p->routeElement[k].aTopologyId, e->aTopologyId); - duplicate_string(p->routeElement[k].zTopologyId, e->zTopologyId); - duplicate_string(p->routeElement[k].contextId, s->serviceId.contextId); - } - g_free(e); g_free(v); g_free(pathCons); - //DEBUG_PC ("Path is constructed"); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Print the graph for DEBUG_PCging purposes - * - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void print_graph (struct graph_t *g) { - g_assert(g); - DEBUG_PC ("================================================================"); - DEBUG_PC ("=========================== GRAPH =========================="); - DEBUG_PC ("================================================================"); - DEBUG_PC("Graph Num Vertices: %d", g->numVertices); - - for (gint i = 0; i < g->numVertices; i++) { - DEBUG_PC ("Head Vertice [%s]", g->vertices[i].verticeId.nodeId); - for (gint j = 0; j < g->vertices[i].numTargetedVertices; j++) - { - DEBUG_PC (" Tail Vertice: %s", g->vertices[i].targetedVertices[j].tVertice.nodeId); - for (gint k = 0; k < g->vertices[i].targetedVertices[j].numEdges; k++) - { - struct edges_t *e = &(g->vertices[i].targetedVertices[j].edges[k]); - DEBUG_PC ("%s(%s) --> %s(%s) [C: %f, Bw: %f b/s, Delay: %f ms]", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, - e->zEndPointId, e->cost, e->availCap, e->delay); - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Look for a given edge into the graph - * - * @param verticeIndex - * @param targetedVerticeIndex - * @param e - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint graph_edge_lookup (gint verticeIndex, gint targetedVerticeIndex, struct edges_t *e, struct graph_t *g) { - gint indexEdge = -1; - - for (gint j = 0; j < g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex].numEdges; j++) { - struct edges_t *e2 = &(g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex].edges[j]); - if ((compare_node_id (&e->aNodeId, &e2->aNodeId) == 0) && - (compare_node_id (&e->zNodeId, &e2->zNodeId) == 0) && - (strcmp (e->aEndPointId, e2->aEndPointId) == 0) && - (strcmp (e->zEndPointId, e2->zEndPointId) == 0) && - (strcmp(e->linkId, e2->linkId) == 0)) { - DEBUG_PC ("%s (%s) --> %s (%s) [linkId: %s] FOUND in the Graph at index: %d", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, - e->zEndPointId, e->linkId, j); - indexEdge = j; - return indexEdge; - } - } - return indexEdge; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Look for a given vertice within the graph using the nodeId - * - * @param nodeId - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint graph_vertice_lookup (gchar *nodeId, struct graph_t *g) -{ - gint index = -1; - //DEBUG_PC("Searching Node: %s", nodeId); - for (gint i = 0; i < g->numVertices; i++) { - //DEBUG_PC("Checked Graph Node: %s", g->vertices[i].verticeId.nodeId); - if (memcmp (g->vertices[i].verticeId.nodeId, nodeId, strlen (nodeId)) == 0) - { - index = i; - //DEBUG_PC ("%s is found in the graph vertice [%d]", nodeId, index); - break; - } - } - return (index); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Check if a nodeId is already considered into the set of targeted vertices from a given vertice - * - * @param nodeId - * @param vIndex - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint graph_targeted_vertice_lookup (gint vIndex, gchar *nodeId, struct graph_t *g) -{ - gint addedTargetedVerticeIndex = -1; - gint i = 0; - - if (g->vertices[vIndex].numTargetedVertices == 0) - { - return (addedTargetedVerticeIndex); - } - - for (i = 0; i < g->vertices[vIndex].numTargetedVertices; i++) - { - if (memcmp (g->vertices[vIndex].targetedVertices[i].tVertice.nodeId, nodeId, strlen (nodeId)) == 0) - { - DEBUG_PC ("Targeted %s reachable from %s", nodeId, g->vertices[vIndex].verticeId.nodeId); - addedTargetedVerticeIndex = i; - return (addedTargetedVerticeIndex); - } - } - // not found ... - return (addedTargetedVerticeIndex); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Check if a nodeId is already considered into the set of targeted vertices from a given vertice, if not to be added - * - * @param nodeId - * @param vIndex - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint graph_targeted_vertice_add (gint vIndex, gchar *nodeId, struct graph_t *g) -{ - gint addedTargetedVerticeIndex = -1; - gint i = 0; - - if (g->vertices[vIndex].numTargetedVertices == 0) - { - //DEBUG_PC ("targeted vertice %s being reachable from vertice %s", nodeId, g->vertices[vIndex].verticeId.nodeId); - addedTargetedVerticeIndex = 0; - return (addedTargetedVerticeIndex); - } - - for (i = 0; i < g->vertices[vIndex].numTargetedVertices; i++) - { - if (memcmp (g->vertices[vIndex].targetedVertices[i].tVertice.nodeId, nodeId, strlen (nodeId)) == 0) - { - //DEBUG_PC ("Targeted vertice %s is already considered in the reachable from vertice %s", nodeId, g->vertices[vIndex].verticeId.nodeId); - addedTargetedVerticeIndex = -1; - return (addedTargetedVerticeIndex); - } - } - // It is not found, next to be added at i position - addedTargetedVerticeIndex = i; - return (addedTargetedVerticeIndex); -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Remove edge from the graph - * - * @param g - * @param e - * - * @author Ricardo Martínez - * @date 2022 - */ -void remove_edge_from_graph (struct graph_t *g, struct edges_t *e) { - // Find the ingress vertice into the graph - DEBUG_PC ("Removing from Graph %s[%s]) ---> %s[%s] (linkId: %s)", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, e->aEndPointId, e->linkId); - gint verticeIndex = -1; - verticeIndex = graph_vertice_lookup (e->aNodeId.nodeId, g); - if (verticeIndex == -1) { - DEBUG_PC ("Edge w/ %s is NOT in the Graph!!", e->aNodeId.nodeId); - return; - } - - // Find the targeted vertice from vertice Id - gint targetedVerticeIndex = -1; - targetedVerticeIndex = graph_targeted_vertice_lookup (verticeIndex, e->zNodeId.nodeId, g); - if (targetedVerticeIndex == -1) { - DEBUG_PC ("%s --> %s NOT in the Graph!!", e->aNodeId.nodeId, e->zNodeId.nodeId); - return; - } - //DEBUG_PC ("%s --> %s found in the Graph", e->aNodeId.nodeId, e->zNodeId.nodeId); - - // Get the edge position - gint edgeIndex = -1; - edgeIndex = graph_edge_lookup (verticeIndex, targetedVerticeIndex, e, g); - if (edgeIndex == -1) { - DEBUG_PC ("%s --> %s NOT in the Graph!!", e->aNodeId.nodeId, e->zNodeId.nodeId); - return; - } - - //DEBUG_PC ("%s --> %s FOUND in Graph w/ edgeIndex: %d", e->aNodeId.nodeId, e->zNodeId.nodeId, edgeIndex); - - // Remove the edge - //DEBUG_PC ("Start Removing %s --> %s from Graph", e->aNodeId.nodeId, e->zNodeId.nodeId); - struct targetNodes_t *v = &(g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex]); - for (gint j = edgeIndex; j < v->numEdges; j++) { - struct edges_t *e1 = &(v->edges[j]); - struct edges_t *e2 = &(v->edges[j+1]); - duplicate_edge (e1, e2); - } - v->numEdges --; - DEBUG_PC ("Number of Edges between %s and %s is %d", e->aNodeId.nodeId, e->zNodeId.nodeId, v->numEdges); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief create the pointer for keeping a set of the paths (struct compRouteOutput_t) - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct path_set_t * create_path_set () { - struct path_set_t * p = g_malloc0 (sizeof (struct path_set_t)); - if (p == NULL) { - DEBUG_PC ("Memory allocation problem"); - exit (-1); - } - return p; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Remove the path set - * - * @param p - * - * @author Ricardo Martínez - * @date 2021 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void remove_path_set(struct path_set_t* p) { - g_assert(p); g_free(p); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Create map of nodes to handle the path computation - * - * @param mapN - * @param g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void build_map_node (struct map_nodes_t *mapN, struct graph_t *g) { - //DEBUG_PC ("Construction of the Map of Nodes"); - for (gint i = 0; i < g->numVertices; i++) { - duplicate_node_id (&g->vertices[i].verticeId, &mapN->map[i].verticeId); - mapN->map[i].distance = INFINITY_COST; - mapN->map[i].avaiBandwidth = 0.0; - mapN->map[i].latency = INFINITY_COST; - mapN->map[i].power = INFINITY_COST; - mapN->numMapNodes++; - } - //DEBUG_PC ("mapNodes formed by %d Nodes", mapN->numMapNodes); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Allocate memory for path of struct compRouteOutputList_t * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct compRouteOutputList_t * create_route_list () { - struct compRouteOutputList_t *p = g_malloc0 (sizeof (struct compRouteOutputList_t)); - if (p == NULL) { - DEBUG_PC ("Memory Allocation Problem"); - exit (-1); - } - return p; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Copy all the attributes defining a path - * - * @param dst_path - * @param src_path - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void copy_path(struct path_t* dst_path, struct path_t* src_path) { - g_assert(dst_path); - g_assert(src_path); - - // Path capacity - dst_path->path_capacity.unit = src_path->path_capacity.unit; - memcpy(&dst_path->path_capacity.value, &src_path->path_capacity.value, sizeof(gdouble)); - - // Path latency - memcpy(&dst_path->path_latency.fixed_latency, &src_path->path_latency.fixed_latency, sizeof(gdouble)); - - // Path cost - duplicate_string(dst_path->path_cost.cost_name, src_path->path_cost.cost_name); - memcpy(&dst_path->path_cost.cost_value, &src_path->path_cost.cost_value, sizeof(gdouble)); - memcpy(&dst_path->path_cost.cost_algorithm, &src_path->path_cost.cost_algorithm, sizeof(gdouble)); - - // Path links - dst_path->numPathLinks = src_path->numPathLinks; - for (gint i = 0; i < dst_path->numPathLinks; i++) { - struct pathLink_t* dPathLink = &(dst_path->pathLinks[i]); - struct pathLink_t* sPathLink = &(src_path->pathLinks[i]); - - duplicate_string(dPathLink->linkId, sPathLink->linkId); - duplicate_string(dPathLink->aDeviceId, sPathLink->aDeviceId); - duplicate_string(dPathLink->zDeviceId, sPathLink->zDeviceId); - duplicate_string(dPathLink->aEndPointId, sPathLink->aEndPointId); - duplicate_string(dPathLink->zEndPointId, sPathLink->zEndPointId); - - duplicate_string(dPathLink->topologyId.contextId, sPathLink->topologyId.contextId); - duplicate_string(dPathLink->topologyId.topology_uuid, sPathLink->topologyId.topology_uuid); - - dPathLink->numLinkTopologies = sPathLink->numLinkTopologies; - for (gint j = 0; j < dPathLink->numLinkTopologies; j++) { - struct linkTopology_t* dLinkTop = &(dPathLink->linkTopologies[j]); - struct linkTopology_t* sLinkTop = &(sPathLink->linkTopologies[j]); - - duplicate_string(dLinkTop->topologyId, sLinkTop->topologyId); - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Duplicate the route output instance - * - * @param dst_ro - * @param src_ro - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_compRouteOuput(struct compRouteOutput_t* dst_ro, struct compRouteOutput_t* src_ro) { - g_assert(dst_ro); g_assert(src_ro); - - // Copy the serviceId - copy_service_id(&dst_ro->serviceId, &src_ro->serviceId); - dst_ro->num_service_endpoints_id = src_ro->num_service_endpoints_id; - - for (gint j = 0; j < dst_ro->num_service_endpoints_id; j++) { - struct service_endpoints_id_t* iEp = &(src_ro->service_endpoints_id[j]); - struct service_endpoints_id_t* oEp = &(dst_ro->service_endpoints_id[j]); - copy_service_endpoint_id(oEp, iEp); - } - - // Copy paths - dst_ro->numPaths = src_ro->numPaths; - for (gint j = 0; j < dst_ro->numPaths; j++) { - struct path_t* dst_path = &(dst_ro->paths[j]); - struct path_t* src_path = &(src_ro->paths[j]); - copy_path(dst_path, src_path); - } - // copy no path issue value - dst_ro->noPathIssue = src_ro->noPathIssue; - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Duplicate the computation route output list - * - * @param dst - * @param src - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_route_list(struct compRouteOutputList_t* dst, struct compRouteOutputList_t* src) { - g_assert(src); g_assert(dst); - - dst->numCompRouteConnList = src->numCompRouteConnList; - dst->compRouteOK = src->compRouteOK; - memcpy(&dst->compRouteConnAvBandwidth, &src->compRouteConnAvBandwidth, sizeof(gdouble)); - memcpy(&dst->compRouteConnAvPathLength, &src->compRouteConnAvPathLength, sizeof(gdouble)); - for (gint i = 0; i < src->numCompRouteConnList; i++) { - struct compRouteOutput_t* src_ro = &(src->compRouteConnection[i]); - struct compRouteOutput_t* dst_ro = &(dst->compRouteConnection[i]); - duplicate_compRouteOuput(dst_ro, src_ro); - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Allocate memory for path of struct compRouteOutputItem_t * - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct compRouteOutputItem_t *create_path_item () { - struct compRouteOutputItem_t *p = g_malloc0 (sizeof (struct compRouteOutputItem_t)); - if (p == NULL) { - DEBUG_PC ("Memory Allocation Problem"); - exit (-1); - } - return p; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Sort the set of paths the AvailBw, Cost and Delay - * - * @params setP - * @params args - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void sort_path_set(struct path_set_t* setP, guint args) { - g_assert(setP); - // Sort the paths contained in setP by: - // 1st Criteria: The path cost (maybe bound to link distance) - // 2nd Criteria: The consumed path power - // 3nd Criteria: The path latency - // 3rd Criteria: The available Bw - float epsilon = 0.1; - - for (gint i = 0; i < setP->numPaths; i++) { - for (gint j = 0; j < (setP->numPaths - i - 1); j++) { - struct compRouteOutputItem_t* path1 = &setP->paths[j]; - struct compRouteOutputItem_t* path2 = &setP->paths[j + 1]; - struct compRouteOutputItem_t* pathTmp = create_path_item(); - //////////////////////// Criterias //////////////////////////////////////// - // 1st Criteria (Cost) - if (path2->cost < path1->cost) { - duplicate_path(path1, pathTmp); - duplicate_path(path2, path1); - duplicate_path(pathTmp, path2); - g_free(pathTmp); - continue; - } - if (path2->cost == path1->cost) { - // 2nd Criteria (Energy) - if (args & ENERGY_EFFICIENT_ARGUMENT) { - if (path2->power < path1->power) { - duplicate_path(path1, pathTmp); - duplicate_path(path2, path1); - duplicate_path(pathTmp, path2); - g_free(pathTmp); - continue; - } - else { // path1->power < path2->power - g_free(pathTmp); - continue; - } - } - else { // No enery efficient argument - // 3rd Criteria (latency) - if (path2->delay < path1->delay) { - duplicate_path(path1, pathTmp); - duplicate_path(path2, path1); - duplicate_path(pathTmp, path2); - g_free(pathTmp); - continue; - } - else if (path1->delay < path2->delay) { - g_free(pathTmp); - continue; - } - else { // path1->delay == path2->delay - // 4th Criteria (available bw) - if (path2->availCap > path1->availCap) { - duplicate_path(path1, pathTmp); - duplicate_path(path2, path1); - duplicate_path(pathTmp, path2); - g_free(pathTmp); - continue; - } - else { - g_free(pathTmp); - continue; - } - } - } - } - else { // path1->cost < path2->cost - g_free(pathTmp); - continue; - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Remove first element from the path sets - * - * @params setP - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void pop_front_path_set (struct path_set_t *setP) { - for (gint j = 0; j < setP->numPaths - 1; j++) { - struct compRouteOutputItem_t *path1 = &setP->paths[j]; - struct compRouteOutputItem_t *path2 = &setP->paths[j+1]; - duplicate_path (path2, path1); - } - setP->numPaths--; - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Add routeElement to the back of the path - * - * @param rE - * @param p - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void add_routeElement_path_back (struct routeElement_t *rE, struct compRouteOutputItem_t *p) { - //DEBUG_PC ("p->numRouteElements: %d", p->numRouteElements); - p->numRouteElements++; - gint index = p->numRouteElements - 1; - - struct nodes_t *pn = &(p->routeElement[index].aNodeId); - struct nodes_t *rEn = &(rE->aNodeId); - - // duplicate aNodeId - duplicate_node_id (rEn, pn); - pn = &(p->routeElement[index].zNodeId); - rEn = &(rE->zNodeId); - duplicate_node_id (rEn, pn); - duplicate_string(p->routeElement[index].aEndPointId, rE->aEndPointId); - duplicate_string(p->routeElement[index].zEndPointId, rE->zEndPointId); - duplicate_string(p->routeElement[index].linkId, rE->linkId); - duplicate_string(p->routeElement[index].aTopologyId, rE->aTopologyId); - duplicate_string(p->routeElement[index].zTopologyId, rE->zTopologyId); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief This function compares ap and rootPath. If all the links are equal between both ap and rootPath till the sN, then the link from sN to next node - * ap is returned - * - * @params ap - * @params p - * @params sN - * @params e - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gboolean matching_path_rootPath (struct compRouteOutputItem_t *ap, struct compRouteOutputItem_t *rootPath, struct nodes_t *sN, struct edges_t *e) { - gint j = 0; - gboolean ret = FALSE; - while ((j < ap->numRouteElements) && (j < rootPath->numRouteElements)) { - if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0) && - //(memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) != 0) && - (memcmp (sN->nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0)) { - duplicate_node_id (&ap->routeElement[j].aNodeId, &e->aNodeId); - duplicate_node_id (&ap->routeElement[j].zNodeId, &e->zNodeId); - duplicate_string(e->aEndPointId, ap->routeElement[j].aEndPointId); - duplicate_string(e->zEndPointId, ap->routeElement[j].zEndPointId); - duplicate_string(e->linkId, ap->routeElement[j].linkId); - return TRUE; - } - if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0) && - (memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) == 0)) { - j++; - continue; - } - - if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) != 0) || - (memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) != 0)) { - //DEBUG_PC ("ap and rootPath not in the same path"); - return ret; - } - } - return ret; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief This function is used to modify the graph to be used for running the subsequent SP computations acording to the YEN algorithm principles - * - * @params g - * @params A - * @params rootPath - * @params spurNode - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void modify_targeted_graph (struct graph_t *g, struct path_set_t *A, struct compRouteOutputItem_t * rootPath, struct nodes_t * spurNode) { - //DEBUG_PC ("Modify the Targeted graph according to the Yen algorithm principles"); - for (gint j = 0; j < A->numPaths; j++) { - struct compRouteOutputItem_t *ap = &A->paths[j]; - struct edges_t *e = create_edge(); - gboolean ret = FALSE; - ret = matching_path_rootPath (ap, rootPath, spurNode, e); - if (ret == TRUE) { - DEBUG_PC ("Removal %s[%s] --> %s[%s] from the graph", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, e->aEndPointId); - remove_edge_from_graph (g, e); - //DEBUG_PC ("Print Resulting Graph"); - print_graph (g); - g_free (e); - } - if (ret == FALSE) { - g_free (e); - continue; - } - } - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Supporting fucntion to Check if a nodeId is already in the items of a given GList - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint find_nodeId (gconstpointer data, gconstpointer userdata) -{ - /** check values */ - g_assert(data != NULL); - g_assert(userdata != NULL); - - struct nodeItem_t *SNodeId = (struct nodeItem_t *)data; - guchar * nodeId = (guchar *)userdata; - - //DEBUG_PC ("SNodeId (%s) nodeId (%s)", SNodeId->node.nodeId, nodeId); - - if (!memcmp(SNodeId->node.nodeId, nodeId, strlen (SNodeId->node.nodeId))) - { - return (0); - } - return -1; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Explores the link between u and v - * - * @param u - * @param v - * @param g - * @param s - * @param S - * @param Q - * @param mapNodes - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struct graph_t *g, - struct service_t *s, GList **S, GList **Q, struct map_nodes_t *mapNodes, - guint arg) { - g_assert(g); g_assert(s); g_assert(mapNodes); - - struct targetNodes_t *v = &(g->vertices[indexGraphU].targetedVertices[indexGraphV]); - DEBUG_PC("Explored Link %s => %s)", u->node.nodeId, v->tVertice.nodeId); - //DEBUG_PC("\t %s => %s", u->node.nodeId, v->tVertice.nodeId); - - // v already explored in S? then, discard it - GList *found = g_list_find_custom (*S, v->tVertice.nodeId, find_nodeId); - if (found != NULL) { - DEBUG_PC ("v (%s) in S, Discard", v->tVertice.nodeId); - return 0; - } - - // Get the set of constraints imposed by the service - struct path_constraints_t* path_constraints = get_path_constraints(s); - gdouble distance_through_u = INFINITY_COST ,latency_through_u = INFINITY_COST, power_through_u = INFINITY_COST; - gint i = 0, foundAvailBw = 0; - // BANDWIDTH requirement to be fulfilled on EDGE u->v - gdouble edgeAvailBw = 0.0, edgeTotalBw = 0.0; - for (i = 0; i < v->numEdges; i++) { - struct edges_t *e = &(v->edges[i]); - memcpy (&edgeAvailBw, &(e->availCap), sizeof (gdouble)); - memcpy(&edgeTotalBw, &(e->totalCap), sizeof(gdouble)); - DEBUG_PC("EDGE %s[%s] => %s[%s]", u->node.nodeId, e->aEndPointId, v->tVertice.nodeId, e->zEndPointId); - //DEBUG_PC ("\t %s[%s] =>", u->node.nodeId, e->aEndPointId); - //DEBUG_PC("\t => %s[%s]", v->tVertice.nodeId, e->zEndPointId); - DEBUG_PC("\t AvailBw: %f, TotalBw: %f", edgeAvailBw, edgeTotalBw); - // Check Service Bw constraint - if ((path_constraints->bw == TRUE) && (edgeAvailBw < path_constraints->bwConstraint)) - continue; - else { - foundAvailBw = 1; - break; - } - } - // BW constraint NOT MET, then DISCARD edge - if ((path_constraints->bw == TRUE) && (foundAvailBw == 0)) { - DEBUG_PC ("AvailBw: %f < path_constraint: %f -- Discard Edge", edgeAvailBw, path_constraints->bwConstraint); - g_free(path_constraints); - return 0; - } - - gint indexEdge = i; // get the index for the explored edge - // Update distance, latency and availBw through u to reach v - gint map_uIndex = get_map_index_by_nodeId (u->node.nodeId, mapNodes); - struct map_t *u_map = &mapNodes->map[map_uIndex]; - distance_through_u = u_map->distance + v->edges[indexEdge].cost; - latency_through_u = u_map->latency + v->edges[indexEdge].delay; - // Consumed power at v through u is the sum - // 1. Power from src to u - // 2. Power-idle at node u - // 3. power consumed over the edge between u and v, i.e. energy*usedBw - power_through_u = u_map->power + g->vertices[indexGraphU].power_idle + ((edgeTotalBw - edgeAvailBw + path_constraints->bwConstraint) * (v->edges[indexEdge].energy)); - gdouble availBw_through_u = 0.0; - - // ingress endpoint (u) is the src of the request - if (strcmp (u->node.nodeId, s->service_endpoints_id[0].device_uuid) == 0) { - //DEBUG_PC ("AvailBw %f on %s --> %s", edgeAvailBw, u->node.nodeId, v->tVertice.nodeId); - memcpy (&availBw_through_u, &edgeAvailBw, sizeof (gdouble)); - } - else { - // Get the minimum available bandwidth between the src-->u and the new added edge u-->v - //DEBUG_PC ("Current AvailBw: %f from src to %s", u_map->avaiBandwidth, u->node.nodeId); - //DEBUG_PC ("AvailBw: %f %s --> %s", edgeAvailBw, u->node.nodeId, v->tVertice.nodeId); - if (u_map->avaiBandwidth <= edgeAvailBw) { - memcpy (&availBw_through_u, &u_map->avaiBandwidth, sizeof (gdouble)); - } - else { - memcpy (&availBw_through_u, &edgeAvailBw, sizeof (gdouble)); - } - } - // Relax the link according to the pathCost, latency, and energy - gint map_vIndex = get_map_index_by_nodeId (v->tVertice.nodeId, mapNodes); - struct map_t *v_map = &mapNodes->map[map_vIndex]; - // If cost dist (u, v) > dist (src, v) relax the link - if (distance_through_u > v_map->distance) { - //DEBUG_PC ("dist(src, u) + dist(u, v): %f > dist (src, v): %f --> Discard Link", distance_through_u, v_map->distance); - return 0; - } - // If energy consumption optimization is requested - if (arg & ENERGY_EFFICIENT_ARGUMENT) { - if (distance_through_u == v_map->distance) { - if (power_through_u > v_map->power) { - DEBUG_PC("Energy (src -> u + u -> v: %f (Watts) >Energy (src, v): %f (Watts)--> DISCARD LINK", power_through_u, v_map->power); - return 0; - } - // same energy consumption, consider latency - if ((power_through_u == v_map->power) && (latency_through_u > v_map->latency)) { - return 0; - } - if ((power_through_u == v_map->power) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { - return 0; - } - } - } // No optimization, rely on latency and available e2e bandwidth - else { - // If dist (src, u) + dist (u, v) = current dist(src, v), then use the latency as discarding criteria - if ((distance_through_u == v_map->distance) && (latency_through_u > v_map->latency)) { - //DEBUG_PC ("dist(src, u) + dist(u,v) = current dist(src, v), but latency (src,u) + latency (u, v) > current latency (src, v)"); - return 0; - } - // If dist (src, u) + dist (u,v) == current dist(src, v) AND latency (src, u) + latency (u, v) == current latency (src, v), the available bandwidth is the criteria - if ((distance_through_u == v_map->distance) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { - return 0; - } - } - DEBUG_PC ("%s --> %s Relaxed", u->node.nodeId, v->tVertice.nodeId); - DEBUG_PC ("\t AvailBw: %f Mb/s, Cost: %f, Latency: %f ms, Energy: %f Watts", availBw_through_u, distance_through_u, latency_through_u, power_through_u); - - // Update Q list -- - struct nodeItem_t *nodeItem = g_malloc0 (sizeof (struct nodeItem_t)); - if (nodeItem == NULL) { - DEBUG_PC ("memory allocation failed\n"); - exit (-1); - } - nodeItem->distance = distance_through_u; - memcpy(&nodeItem->distance, &distance_through_u, sizeof(gdouble)); - memcpy(&nodeItem->latency, &latency_through_u, sizeof(gdouble)); - memcpy(&nodeItem->power, &power_through_u, sizeof(gdouble)); - duplicate_node_id (&v->tVertice, &nodeItem->node); - // add node to the Q list - if (arg & ENERGY_EFFICIENT_ARGUMENT) { - *Q = g_list_insert_sorted(*Q, nodeItem, sort_by_energy); - } - else - *Q = g_list_insert_sorted (*Q, nodeItem, sort_by_distance); - - // Update the mapNodes for the specific reached tv - v_map->distance = distance_through_u; - memcpy(&v_map->distance, &distance_through_u, sizeof(gdouble)); - memcpy (&v_map->avaiBandwidth, &availBw_through_u, sizeof (gdouble)); - memcpy (&v_map->latency, &latency_through_u, sizeof (gdouble)); - memcpy(&v_map->power, &power_through_u, sizeof(gdouble)); - // Duplicate the predecessor edge into the mapNodes - struct edges_t *e1 = &(v_map->predecessor); - struct edges_t *e2 = &(v->edges[indexEdge]); - duplicate_edge(e1, e2); - DEBUG_PC ("u->v Edge: %s(%s) --> %s(%s)", e2->aNodeId.nodeId, e2->aEndPointId, e2->zNodeId.nodeId, e2->zEndPointId); - //DEBUG_PC("v-pred aTopology: %s", e2->aTopologyId); - DEBUG_PC("v-pred zTopology: %s", e2->zTopologyId); - - // Check whether v is dstPEId - //DEBUG_PC ("Targeted dstId: %s", s->service_endpoints_id[1].device_uuid); - //DEBUG_PC ("nodeId added to the map: %s", v_map->verticeId.nodeId); - //DEBUG_PC ("Q Length: %d", g_list_length(*Q)); - g_free(path_constraints); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Check the feasability of a path wrt the constraints imposed by the request in terms of latency - * - * @param s - * @param p - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gboolean check_computed_path_feasability (struct service_t *s, struct compRouteOutputItem_t* p) { - float epsilon = 0.0000001; - struct path_constraints_t* pathCons = get_path_constraints(s); - gboolean ret = TRUE; - if (pathCons->latency == TRUE) { - if ((pathCons->latencyConstraint - p->delay > 0.0) || (fabs(pathCons->latencyConstraint - p->delay) < epsilon)) { - DEBUG_PC("Computed Path (latency: %f) is feasible wrt Connection Demand: %f", p->delay, pathCons->latencyConstraint); - } - else { - DEBUG_PC("Computed Path (latency: %f) is NOT feasible wrt Connection Demand: %f", p->delay, pathCons->latencyConstraint); - g_free(pathCons); - return FALSE; - } - } - // Other constraints... - g_free(pathCons); - return ret; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Sorting the GList Q items by distance - * - * @param a - * @param b - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint sort_by_distance (gconstpointer a, gconstpointer b) { - //DEBUG_PC ("sort by distance a and b"); - g_assert(a != NULL); - g_assert(b != NULL); - - //DEBUG_PC ("sort by distance a and b"); - struct nodeItem_t *node1 = (struct nodeItem_t *)a; - struct nodeItem_t *node2 = (struct nodeItem_t *)b; - g_assert (node1); - g_assert (node2); - - //DEBUG_PC ("a->distance %u; b->distance %u", node1->distance, node2->distance); - //DEBUG_PC("a->latency: %f; b->latency: %f", node1->latency, node2->latency); - //1st criteria, sorting by lowest distance - if (node1->distance > node2->distance) - return 1; - else if (node1->distance < node2->distance) - return 0; - if (node1->distance == node2->distance) { - if (node1->latency > node2->latency) - return 1; - else if (node1->latency <= node2->latency) - return 0; - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Sorting the GList Q items by distance - * - * @param a - * @param b - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gint sort_by_energy(gconstpointer a, gconstpointer b) { - g_assert(a != NULL); - g_assert(b != NULL); - - //DEBUG_PC ("sort by distance a and b"); - struct nodeItem_t* node1 = (struct nodeItem_t*)a; - struct nodeItem_t* node2 = (struct nodeItem_t*)b; - g_assert(node1); - g_assert(node2); - - //1st criteria: sorting by lowest distance - if (node1->distance > node2->distance) - return 1; - if (node1->distance < node2->distance) - return 0; - - // 2nd Criteria: sorting by the lowest energy - if (node1->power > node2->power) - return 1; - if (node1->power < node1->power) - return 0; - - // 3rd Criteria: by the latency - if (node1->latency > node2->latency) - return 1; - if (node1->latency <= node2->latency) - return 0; - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Allocate memory for graph - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct graph_t * create_graph () { - struct graph_t * g = g_malloc0 (sizeof (struct graph_t)); - if (g == NULL) { - DEBUG_PC ("Memory Allocation Problem"); - exit (-1); - } - return g; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Allocate memory for mapNodes - * - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -struct map_nodes_t * create_map_node () { - struct map_nodes_t * mN = g_malloc0 (sizeof (struct map_nodes_t)); - if (mN == NULL) { - DEBUG_PC ("Memory allocation failed"); - exit (-1); - } - return mN; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Look up for the service in the servieList bound to a serviceUUID - * - * @params serviceUUID - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct service_t* get_service_for_computed_path(gchar* serviceUUID) { - gint i = 0; - for(GList *listnode = g_list_first(serviceList); - listnode; - listnode = g_list_next(listnode), i++) { - struct service_t* s = (struct service_t*)(listnode->data); - if (strcmp(s->serviceId.service_uuid, serviceUUID) == 0) - return s; - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the service type - * - * @param type - * - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_service_type(guint type) { - switch (type) { - case SERVICE_TYPE_UNKNOWN: - DEBUG_PC("Service Type UNKNOWN"); - break; - case SERVICE_TYPE_L3NM: - DEBUG_PC("Service Type L3NM"); - break; - case SERVICE_TYPE_L2NM: - DEBUG_PC("Service Type L2NM"); - break; - case SERVICE_TYPE_TAPI: - DEBUG_PC("Service Type L2NM"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the port direction - * - * @param direction - * - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_link_port_direction(guint direction) { - switch (direction) { - case LINK_PORT_DIRECTION_BIDIRECTIONAL: - //DEBUG_PC("Bidirectional Port Direction"); - break; - case LINK_PORT_DIRECTION_INPUT: - //DEBUG_PC("Input Port Direction"); - break; - case LINK_PORT_DIRECTION_OUTPUT: - //DEBUG_PC("Output Port Direction"); - break; - case LINK_PORT_DIRECTION_UNKNOWN: - //DEBUG_PC("Unknown Port Direction"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the port termination direction - * - * @param direction - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_termination_direction(guint direction) { - switch (direction) { - case TERMINATION_DIRECTION_BIDIRECTIONAL: - //DEBUG_PC("Bidirectional Termination Direction"); - break; - case TERMINATION_DIRECTION_SINK: - //DEBUG_PC("Input Termination Direction"); - break; - case TERMINATION_DIRECTION_SOURCE: - //DEBUG_PC("Output Termination Direction"); - break; - case TERMINATION_DIRECTION_UNKNOWN: - //DEBUG_PC("Unknown Termination Direction"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the termination state - * - * @param state - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_termination_state(guint state) -{ - switch (state) { - case TERMINATION_STATE_CAN_NEVER_TERMINATE: - //DEBUG_PC("Can never Terminate"); - break; - case TERMINATION_STATE_NOT_TERMINATED: - DEBUG_PC("Not terminated"); - break; - case TERMINATION_STATE_TERMINATED_SERVER_TO_CLIENT_FLOW: - DEBUG_PC("Terminated server to client flow"); - break; - case TERMINATION_STATE_TERMINATED_CLIENT_TO_SERVER_FLOW: - DEBUG_PC("Terminated client to server flow"); - break; - case TERMINATION_STATE_TERMINATED_BIDIRECTIONAL: - //DEBUG_PC("Terminated bidirectional"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the capacity unit - * - * @param unit - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_capacity_unit(guint unit) { - - switch (unit) { - case CAPACITY_UNIT_TB: - DEBUG_PC("Unit in TB"); - break; - case CAPACITY_UNIT_TBPS: - DEBUG_PC("Unit in TB/s"); - break; - case CAPACITY_UNIT_GB: - DEBUG_PC("Unit in GB"); - break; - case CAPACITY_UNIT_GBPS: - DEBUG_PC("Unit in GB/s"); - break; - case CAPACITY_UNIT_MB: - DEBUG_PC("Unit in MB"); - break; - case CAPACITY_UNIT_MBPS: - //DEBUG_PC("Unit in MB/s"); - break; - case CAPACITY_UNIT_KB: - DEBUG_PC("Unit in KB"); - break; - case CAPACITY_UNIT_KBPS: - DEBUG_PC("Unit in KB/s"); - break; - case CAPACITY_UNIT_GHZ: - DEBUG_PC("Unit in GHz"); - break; - case CAPACITY_UNIT_MHZ: - DEBUG_PC("Unit in MHz"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Friendly function to log the link forwarding direction - * - * @param linkFwDir - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_link_forwarding_direction(guint linkFwDir) { - switch (linkFwDir) { - case LINK_FORWARDING_DIRECTION_BIDIRECTIONAL: - DEBUG_PC("BIDIRECTIONAL LINK FORWARDING DIRECTION"); - break; - case LINK_FORWARDING_DIRECTION_UNIDIRECTIONAL: - DEBUG_PC("UNIDIRECTIONAL LINK FORWARDING DIRECTION"); - break; - case LINK_FORWARDING_DIRECTION_UNKNOWN: - DEBUG_PC("UNKNOWN LINK FORWARDING DIRECTION"); - break; - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Search a specific contextUuid element into the contextSet - * - * @param contextUuid - * @param set - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct context_t* find_contextId_in_set(gchar* contextUuid, GList** set) { - //DEBUG_PC("Checking if contextId: %s in in the ContextSet??", contextUuid); - gint i = 0; - for (GList *ln = g_list_first(*set); - ln; - ln = g_list_next(ln)){ - struct context_t* c = (struct context_t*)(ln->data); - //DEBUG_PC("Context Item [%d] Id: %s", i, c->contextId); - if (strcmp(contextUuid, c->contextId) == 0) { - //DEBUG_PC("contextId: %s is FOUND in the ContextSet_List", contextUuid); - return c; - } - i++; - } - //DEBUG_PC("contextId: %s NOT FOUND in the ContextSet_List", contextUuid); - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Add a specific context uuid into the context set - * - * @param contextUuid - * @param set - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct context_t* add_contextId_in_set(gchar *contextUuid, GList** set) { - - struct context_t* c = g_malloc0(sizeof(struct context_t)); - if (c == NULL) { - DEBUG_PC("Memory Allocation Failure"); - exit(-1); - } - duplicate_string(c->contextId, contextUuid); - // Add the context into the context set - //DEBUG_PC("Adding ContextId: %s", contextUuid); - //DEBUG_PC(" (BEFORE ADDING) Context Set Length: %d", g_list_length(*set)); - *set = g_list_append(*set, c); - //DEBUG_PC(" (AFTER ADDING) Context Set Length: %d", g_list_length(*set)); - return c; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Find a vertex in a specific graph - * - * @param contextUuid - * @param set - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct vertices_t* find_vertex_in_graph_context(struct graph_t *g, gchar* deviceId) { - for (gint i = 0; i < g->numVertices; i++) { - struct vertices_t* v = &(g->vertices[i]); - if (strcmp(v->verticeId.nodeId, deviceId) == 0) { - return v; - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Adding a deviceId into a graph - * - * @param g - * @param deviceId - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct vertices_t* add_vertex_in_graph(struct graph_t* g, struct device_t *d) { - g->numVertices++; - struct vertices_t* v = &(g->vertices[g->numVertices - 1]); - duplicate_string(v->verticeId.nodeId, d->deviceId); - memcpy(&v->power_idle, &d->power_idle, sizeof(gdouble)); - return v; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Construct the graphs (vertices and edges) bound to every individual context - * - * @param cSet - * @param activeFlag - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void build_contextSet_deviceList(GList** cSet, gint activeFlag) { - // Check every device their endpoints - for (GList* listnode = g_list_first(deviceList); - listnode; - listnode = g_list_next(listnode)) { - struct device_t* d = (struct device_t*)(listnode->data); - //DEBUG_PC("Exploring DeviceId: %s", d->deviceId); - - if ((activeFlag == 1) && (d->operational_status != 2)) { - // it is only considered devices with operational status enabled, i.e., set to 2 - continue; - } - // Check the associated endPoints - for (gint j = 0; j < d->numEndPoints; j++) { - struct endPoint_t* eP = &(d->endPoints[j]); - // Get endPointId (topology, context, device Id and endpoint uuid) - struct endPointId_t* ePid = &(eP->endPointId); //end point id - //DEBUG_PC(" EndPointId: %s || Type: %s", eP->endPointId.endpoint_uuid, d->deviceType); - //DEBUG_PC(" TopologyId: %s || ContextId: %s", eP->endPointId.topology_id.topology_uuid, eP->endPointId.topology_id.contextId); - // Add contextId in ContextSet and the deviceId (+endpoint) into the vertex set - struct context_t *c = find_contextId_in_set(eP->endPointId.topology_id.contextId, cSet); - if (c == NULL) { - DEBUG_PC(" contextUuid: %s MUST BE ADDED to ContextSet", eP->endPointId.topology_id.contextId); - c = add_contextId_in_set(eP->endPointId.topology_id.contextId, cSet); - } - // Check if the deviceId and endPointUuid are already considered in the graph of the context c - struct vertices_t* v = find_vertex_in_graph_context(&c->g, d->deviceId); - if (v == NULL) { - //DEBUG_PC(" deviceId: %s MUST BE ADDED to the Context Graph", d->deviceId); - v = add_vertex_in_graph(&c->g, d); - } - } - } - //print_contextSet(cSet); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Determine whether a deviceId is in the targetNode list of a specific vertex v - * - * @param v - * @param deviceId - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct targetNodes_t* find_targeted_vertex_in_graph_context(struct vertices_t* v, gchar *deviceId) { - for (gint k = 0; k < v->numTargetedVertices; k++) { - struct targetNodes_t* w = &(v->targetedVertices[k]); - if (strcmp(w->tVertice.nodeId, deviceId) == 0) { - return w; - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Add a deviceId a targetNode of a specific vertex v - * - * @param v - * @param deviceId - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct targetNodes_t* add_targeted_vertex_in_graph_context(struct vertices_t* v, gchar* bDeviceId) { - v->numTargetedVertices++; - struct targetNodes_t* w = &(v->targetedVertices[v->numTargetedVertices - 1]); - duplicate_string(w->tVertice.nodeId, bDeviceId); - return w; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Returns the structure of a device endpoint bound to a specific deviceId and endPointId - * - * @param devId - * @param endPointUuid - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct endPoint_t* find_device_tied_endpoint(gchar* devId, gchar* endPointUuid) { - //DEBUG_PC("devId: %s ePId: %s", devId, endPointUuid); - for (GList* ln = g_list_first(deviceList); - ln; - ln = g_list_next(ln)) { - struct device_t* d = (struct device_t*)(ln->data); - if (strcmp(d->deviceId, devId) != 0) { - continue; - } - // Iterate over the endpoints tied to the deviceId - for (gint j = 0; j < d->numEndPoints; j++) { - struct endPoint_t* eP = &(d->endPoints[j]); - //DEBUG_PC("looked endPointId: %s", eP->endPointId.endpoint_uuid); - if (strcmp(eP->endPointId.endpoint_uuid, endPointUuid) == 0) { - return eP; - } - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Adding the edge/linnk in the targetedNodes w list - * - * @param w - * @param l - * @param activeFlag - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void add_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l, gint activeFlag) { - //DEBUG_PC("\t targetedVertex: %s", w->tVertice.nodeId); - - // Check if the activeFlag is 1. If YES, it is only added to the edges as long as the - // associated endPoint is in status ENABLED, i.e., with operational status set to 2 - // Get the endpoints (A and Z) of the link l (assumed P2P) - struct link_endpointId_t* aEndpointId = &(l->linkEndPointId[0]); - struct link_endpointId_t* zEndpointId = &(l->linkEndPointId[1]); - // Get the endPoint Information tied to the device bound to aEndPointId - struct endPoint_t* eP = find_device_tied_endpoint(aEndpointId->deviceId, aEndpointId->endPointId); - if (eP == NULL) { - DEBUG_PC("devId: %s endPointUuid: %s NOT in Device List!!--- Weird", aEndpointId->deviceId, aEndpointId->endPointId); - exit(-1); - } - // Check whether the port in that endPoint (eP) is Active upon the activeFlag being SET - if (activeFlag == 1) { - if (eP->operational_status != 2) // NOT ENABLED, then discard this link - return; - } - - // Add the edge into the graph - w->numEdges++; - struct edges_t* e = &(w->edges[w->numEdges - 1]); - // Copy the link Id UUID - duplicate_string(e->linkId, l->linkId); - duplicate_string(e->aNodeId.nodeId, aEndpointId->deviceId); - duplicate_string(e->aEndPointId, aEndpointId->endPointId); - duplicate_string(e->aTopologyId, aEndpointId->topology_id.topology_uuid); - duplicate_string(e->zNodeId.nodeId, zEndpointId->deviceId); - duplicate_string(e->zEndPointId, zEndpointId->endPointId); - duplicate_string(e->zTopologyId, zEndpointId->topology_id.topology_uuid); - - //Potential(total) and available capacity - e->unit = eP->potential_capacity.unit; - memcpy(&e->totalCap, &eP->potential_capacity.value, sizeof(gdouble)); - memcpy(&e->availCap, &eP->available_capacity.value, sizeof(gdouble)); - // Copy interdomain local/remote Ids - memcpy(e->interDomain_localId, eP->inter_domain_plug_in.inter_domain_plug_in_local_id, - strlen(eP->inter_domain_plug_in.inter_domain_plug_in_local_id)); - memcpy(e->interDomain_remoteId, eP->inter_domain_plug_in.inter_domain_plug_in_remote_id, - strlen(eP->inter_domain_plug_in.inter_domain_plug_in_remote_id)); - // cost value - memcpy(&e->cost, &l->cost_characteristics.cost_value, sizeof(gdouble)); - // latency ms - memcpy(&e->delay, &l->latency_characteristics.fixed_latency, sizeof(gdouble)); - // energy J/bits ~ power - memcpy(&e->energy, &eP->energyConsumption, sizeof(gfloat)); - - //DEBUG_PC("Edge - Total/Available Capacity: %f/%f; Cost: %f; Delay: %f, Energy: %f", eP->potential_capacity.value, eP->available_capacity.value, - // l->cost_characteristics.cost_value, l->latency_characteristics.fixed_latency, l->energy_link); - - //DEBUG_PC("Graph Edge - Total/Available Capacity: %f/%f; Cost: %f; Delay: %f, Energy: %f", e->totalCap, e->availCap, - // e->cost, e->delay, e->energy); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Searching a specific edge/link by the linkId(UUID) - * - * @param w - * @param l - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct edges_t* find_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l) { - for (gint i = 0; i < w->numEdges; i++) { - struct edges_t* e = &(w->edges[i]); - if (strcmp(e->linkId, l->linkId) == 0) { - return e; - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief supporting the construction of the graph per context using the explicit - * contents/info of the link list - * - * @param set - * @param activeFlag - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void build_contextSet_linklList(GList** set, gint activeFlag) { - // for each link in linkList: - // 1st- Retrieve endpoints A --> B feauture (context Id, device Id, endpoint Id) - // 2st - In the graph associated to the contextId, check wheter A (deviceId) is in the vertices list - // o No, this is weird ... exist - // o Yes, get the other link endpoint (i.e., B) and check whether it exists. If NOT add it, considering - // all the attributes; Otherwise, check whether the link is different from existing edges between A and B - gdouble epsilon = 0.1; - gint j = 0; - for (GList* ln = g_list_first(linkList); - ln; - ln = g_list_next(ln)) { - struct link_t* l = (struct link_t*)(ln->data); - j++; - - // link assumed to be P2P A --> B; i.e. 2 endPoints; 1st specifies A and 2nd specifie B - struct link_endpointId_t* aEndpointId = &(l->linkEndPointId[0]); - struct topology_id_t* topologyId = &(aEndpointId->topology_id); - // get the contextId - gchar contextUuid[UUID_CHAR_LENGTH]; - duplicate_string(contextUuid, topologyId->contextId); - DEBUG_PC("Link: %s in ContextId: %s", l->linkId, contextUuid); - - // Check first contextUuid exists in the cSet - //DEBUG_PC("Length of Context: %d", g_list_length(set)); - struct context_t* c = find_contextId_in_set(contextUuid, set); - if (c == NULL) { - DEBUG_PC("ContextId: %s does NOT exist... weird", contextUuid); - exit(-1); - } - - // get the device ID of A - gchar aDeviceId[UUID_CHAR_LENGTH]; - duplicate_string(aDeviceId, aEndpointId->deviceId); - - struct graph_t* g = &(c->g); // get the graph associated to the context c - struct vertices_t* v = find_vertex_in_graph_context(g, aDeviceId); - if (v == NULL) { - DEBUG_PC("%s NOT a VERTEX of contextId: %s ... WEIRD", aDeviceId, contextUuid); - exit(-1); - } - // get the bEndpointId - struct link_endpointId_t* bEndpointId = &(l->linkEndPointId[1]); - gchar bDeviceId[UUID_CHAR_LENGTH]; - duplicate_string(bDeviceId, bEndpointId->deviceId); - DEBUG_PC("[%d] -- Link: %s [%s ==> %s]", j-1, l->linkId, aDeviceId, bDeviceId); - // Check whether device B is in the targeted Vertices from A (i.e., v)? - // If not, add B in the targeted vertices B + create the edge and add it - // If B exist, check whether the explored link/edge is already in the list of edges - struct targetNodes_t* w = find_targeted_vertex_in_graph_context(v, bDeviceId); - if (w == NULL) { - DEBUG_PC("[%s] is PEER of [%s]", bDeviceId, v->verticeId.nodeId); - w = add_targeted_vertex_in_graph_context(v, bDeviceId); - add_edge_in_targetedVertice_set(w, l, activeFlag); - } - else { - // w exists, it is needed to check whether the edge (link) should be added - struct edges_t* e = find_edge_in_targetedVertice_set(w, l); - if (e == NULL) { - // Add the link into the list - add_edge_in_targetedVertice_set(w, l, activeFlag); - } - else { - DEBUG_PC("The link already exists ..."); - continue; - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Create the set of (distinct) contexts with the deviceList and linkList - * - * @param cSet - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void build_contextSet(GList** cSet) { - gint activeFlag = 0; // this means that all the devices/links (regardless they are active or not) are considered - - // devices are tied to contexts, i.e. depending on the contextId of the devices - build_contextSet_deviceList(cSet, activeFlag); - - DEBUG_PC("Length for the Context Set: %d", g_list_length(*cSet)); - - // Once the diverse contexts are created and the devices/endpoints asigned to the - // respective graph tied to each context, it is needed to create the edges - build_contextSet_linklList(cSet, activeFlag); - - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Create the set of (distinct) contexts with the deviceList and linkList with - * operational status active - * - * @param cSet - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void build_contextSet_active(GList** cSet) { - gint activeFlag = 1; // this means that all the devices (regardless they are active or not) are considered - - // devices are tied to contexts, i.e. depending on the contextId of the devices - build_contextSet_deviceList(cSet, activeFlag); - - DEBUG_PC("Length for the Context Set: %d", g_list_length(*cSet)); - - // Once the diverse contexts are created and the devices/endpoints asigned to the - // respective graph tied to each context, it is needed to create the edges - build_contextSet_linklList(cSet, activeFlag); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Print the contents of the ContextIds - * - * @param set - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_contextSet(GList* set) { - - DEBUG_PC("Printing the ContextSet w/ number of Elements: %d", g_list_length(set)); - - for (GList* ln = g_list_first(set); - ln; - ln = g_list_next(ln)) { - struct context_t* c = (struct context_t*)(ln->data); - DEBUG_PC("-------------------------------------------------------------"); - DEBUG_PC(" Context Id: %s", c->contextId); - DEBUG_PC("-------------------------------------------------------------"); - - struct graph_t* g = &(c->g); - for (gint j = 0; j < g->numVertices; j++) { - struct vertices_t* v = &(g->vertices[j]); - DEBUG_PC(" Head Device Id: %s", v->verticeId.nodeId); - for (gint k = 0; k < v->numTargetedVertices; k++) { - struct targetNodes_t* w = &(v->targetedVertices[k]); - DEBUG_PC(" [%d] --- Peer Device Id: %s", k, w->tVertice.nodeId); - for (gint l = 0; l < w->numEdges; l++) { - struct edges_t* e = &(w->edges[l]); - DEBUG_PC(" \t link Id: %s", e->linkId); - DEBUG_PC(" \t aEndPointId: %s", e->aEndPointId); - DEBUG_PC(" \t zEndPointId: %s", e->zEndPointId); - DEBUG_PC(" \t Available Capacity: %f, Latency: %f, Cost: %f", e->availCap, e->delay, e->cost); - DEBUG_PC(" \t aTopologyId: %s", e->aTopologyId); - DEBUG_PC(" \t zTopologyId: %s", e->zTopologyId); - } - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Check whether src and dst PE nodeId of the req are the same - * - * @param r - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -gint same_src_dst_pe_nodeid(struct service_t* s) -{ - // Check that source PE and dst PE are NOT the same, i.e., different ingress and egress endpoints (iEp, eEp) - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); - struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); - - gchar* iEpUUID = iEp->endpoint_uuid; - gchar* eEpUUID = eEp->endpoint_uuid; - gchar* iDevUUID = iEp->device_uuid; - gchar* eDevUUID = eEp->device_uuid; - - // Compare the device uuids - if (strcmp(iDevUUID, eDevUUID) != 0) { - DEBUG_PC("DIFFERENT --- iDevId: %s and eDevId: %s", iDevUUID, eDevUUID); - return 1; - } - // Compare the endpoints (ports) - if (strcmp(iEpUUID, eEpUUID) != 0) { - DEBUG_PC("DIFFERENT --- iEpUUID: %s and eEpUUID: %s", iEpUUID, eEpUUID); - return 1; - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Handles issues with the route computation - * - * @param route - * @param s - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void comp_route_connection_issue_handler (struct compRouteOutput_t *path, struct service_t *s) -{ - g_assert(path); g_assert(s); - - // Increase the number of computed routes/paths despite there was an issue to be reported - path->numPaths++; - // Copy the serviceId - copy_service_id(&(path->serviceId), &(s->serviceId)); - - // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) - for (gint i = 0; i < s->num_service_endpoints_id; i++) { - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); - struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); - copy_service_endpoint_id(oEp, iEp); - } - path->num_service_endpoints_id = s->num_service_endpoints_id; - path->noPathIssue = NO_PATH_CONS_ISSUE; - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief released the allocated memory fo compRouteOutputList_t - * - * @param ro - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void destroy_compRouteOutputList (struct compRouteOutputList_t *ro) -{ - g_assert (ro); - g_free (ro); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief creates a copy of the underlying graph - * - * @param originalGraph - * @param destGraph - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void duplicate_graph (struct graph_t *originalGraph, struct graph_t *destGraph) { - g_assert (originalGraph); g_assert (destGraph); - - destGraph->numVertices = originalGraph->numVertices; - for (gint i = 0; i < originalGraph->numVertices; i++) { - struct vertices_t *oVertex = &(originalGraph->vertices[i]); - struct vertices_t *dVertex = &(destGraph->vertices[i]); - dVertex->numTargetedVertices = oVertex->numTargetedVertices; - duplicate_node_id (&oVertex->verticeId, &dVertex->verticeId); - memcpy(&dVertex->power_idle, &oVertex->power_idle, sizeof(gdouble)); - - for (gint j = 0; j < oVertex->numTargetedVertices; j++) { - struct targetNodes_t *oTargetedVertex = &(oVertex->targetedVertices[j]); - struct targetNodes_t *dTargetedVertex = &(dVertex->targetedVertices[j]); - duplicate_node_id (&oTargetedVertex->tVertice, &dTargetedVertex->tVertice); - dTargetedVertex->numEdges = oTargetedVertex->numEdges; - - for (gint k = 0; k < oTargetedVertex->numEdges; k++) { - struct edges_t *oEdge = &(oTargetedVertex->edges[k]); - struct edges_t *dEdge = &(dTargetedVertex->edges[k]); - duplicate_edge (dEdge, oEdge); - } - } - } - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to retrieve from the graph the edge instance associated to the - * pathLink (pL) - * - * @param pL - * @parma g - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct edges_t* get_edge_from_graph_by_linkId(struct pathLink_t* pL, struct graph_t* g) { - g_assert(pL); - g_assert(g); - - for (gint i = 0; i < g->numVertices; i++) { - struct vertices_t* v = &(g->vertices[i]); - for (gint j = 0; j < v->numTargetedVertices; j++) { - struct targetNodes_t* tv = &(v->targetedVertices[j]); - for (gint k = 0; k < tv->numEdges; k++) { - struct edges_t* e = &(tv->edges[k]); - if (strcmp(e->linkId, pL->linkId) == 0) { - return e; - } - } - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to retrieve from the graph the reverse edge (rev_e) associated to an edge (e) - * - * @param e - * @parma g - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -struct edges_t* get_reverse_edge_from_the_graph(struct edges_t* e, struct graph_t* g) { - g_assert(e); - g_assert(g); - - for (gint i = 0; i < g->numVertices; i++) { - struct vertices_t* v = &(g->vertices[i]); - // Check Route Element zNodeId with the v->verticeId - if (compare_node_id(&e->zNodeId, &v->verticeId) != 0) - continue; - // Check Route Element zNodeis with any of reachable targeted vertices from v - gboolean foundTargVert = FALSE; - gint indexTargVert = -1; - for (gint j = 0; j < v->numTargetedVertices; j++) { - struct targetNodes_t* tv = &(v->targetedVertices[j]); - if (compare_node_id(&e->aNodeId, &tv->tVertice) == 0) - { - foundTargVert = TRUE; - indexTargVert = j; - break; - } - } - if (foundTargVert == FALSE) { - continue; - } - - // The targeted vertice is found, then check matching with the endpoints - struct targetNodes_t* tv = &(v->targetedVertices[indexTargVert]); - for (gint k = 0; k < tv->numEdges; k++) { - struct edges_t* rev_e = &(tv->edges[k]); - if ((strcmp(rev_e->aEndPointId, e->zEndPointId) == 0) && - (strcmp(rev_e->zEndPointId, e->aEndPointId) == 0)) { - return rev_e; - } - } - } - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to reflect in the graph the assigned/allocated resources contained in the path p - * considering the needs (e.g., bandwidth) of service s - * - * @param p - * @param s - * @parma g - * - * @author Ricardo Martínez - * @date 2022 - */ -///////////////////////////////////////////////////////////////////////////////////////// -void allocate_graph_resources (struct path_t *p, struct service_t *s, struct graph_t *g) -{ - g_assert (p); g_assert (s); g_assert (g); - // Retrieve the requested bw by the service - struct path_constraints_t* pathCons = get_path_constraints(s); - - for (gint i = 0; i < p->numPathLinks; i++) { - struct pathLink_t* pL = &(p->pathLinks[i]); - // get the edge associated to the linkId in the graph - struct edges_t* e = get_edge_from_graph_by_linkId(pL, g); - if (e == NULL) { - DEBUG_PC("The linkId: %s is NOT found in the Graph!!!", pL->linkId); - exit(-1); - } - //Update the availBw in the edge - gdouble resBw = e->availCap - pathCons->bwConstraint; - DEBUG_PC("Updating the Avail Bw @ edge/link: %s", e->linkId); - DEBUG_PC("Initial avaiCap @ e/link: %f, demanded Bw: %f, resulting Avail Bw: %f", e->availCap, pathCons->bwConstraint, resBw); - memcpy(&e->availCap, &resBw, sizeof(gdouble)); - DEBUG_PC("Final e/link avail Bw: %f", e->availCap); - } - g_free(pathCons); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to reflect in the graph the assigned/allocated resources contained in the reverse direction of the path p - * considering the needs (e.g., bandwidth) of service s - * - * @param p - * @param s - * @parma g - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void allocate_graph_reverse_resources(struct path_t* p, struct service_t * s, struct graph_t* g) -{ - g_assert(p); g_assert(s); g_assert(g); - - struct path_constraints_t* pathCons = get_path_constraints(s); - for (gint i = 0; i < p->numPathLinks; i++) { - struct pathLink_t* pL = &(p->pathLinks[i]); - struct edges_t* e = get_edge_from_graph_by_linkId(pL, g); - if (e == NULL) { - DEBUG_PC("The linkId: %s is NOT found in the Graph!!!", pL->linkId); - exit(-1); - } - struct edges_t* rev_e = get_reverse_edge_from_the_graph(e, g); - if (rev_e == NULL) { - DEBUG_PC("the reverse edge of linkId: %s is NOT found in the Graph!!!", pL->linkId); - exit(-1); - } - //Update the availBw in the edge - gdouble resBw = rev_e->availCap - pathCons->bwConstraint; - DEBUG_PC("Updating the Avail Bw @ reverse edge/link: %s", rev_e->linkId); - DEBUG_PC("Initial avaiCap @ reverse edge e/link: %f, demanded Bw: %f, resulting Avail Bw: %f", rev_e->availCap, pathCons->bwConstraint, resBw); - memcpy(&rev_e->availCap, &resBw, sizeof(gdouble)); - DEBUG_PC("Final reverse edge e/link avail Bw: %f", rev_e->availCap); - } - g_free(pathCons); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Function used to printall the computed paths for the requested network connectivity services - * - * @param routeList - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void print_path_connection_list(struct compRouteOutputList_t* routeList) { - g_assert(routeList); - for (gint i = 0; i < routeList->numCompRouteConnList; i++) { - DEBUG_PC("==================== Service instance: %d ===================", i); - struct compRouteOutput_t* rO = &(routeList->compRouteConnection[i]); - DEBUG_PC("num service endpoints: %d", rO->num_service_endpoints_id); - struct serviceId_t* s = &(rO->serviceId); - DEBUG_PC("ContextId: %s, ServiceId: %s", s->contextId, s->service_uuid); - DEBUG_PC("ingress - %s[%s]", rO->service_endpoints_id[0].device_uuid, - rO->service_endpoints_id[0].endpoint_uuid); - DEBUG_PC("egress - %s [%s]", rO->service_endpoints_id[1].device_uuid, - rO->service_endpoints_id[1].endpoint_uuid); - - if (rO->noPathIssue == NO_PATH_CONS_ISSUE) { - DEBUG_PC("NO PATH SUCCESSFULLY COMPUTED"); - continue; - } - // Path - DEBUG_PC("Number of paths: %d", rO->numPaths); - for (gint j = 0; j < rO->numPaths; j++) { - struct path_t* p = &(rO->paths[j]); - print_path_t(p); - } - } - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief update statistics for the path computation operations - * - * @param routeConnList - * @param d - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void update_stats_path_comp(struct compRouteOutputList_t* routeConnList, struct timeval d, gint numSuccesPathComp, gint numPathCompIntents) { - g_assert(routeConnList); - - total_path_comp_time.tv_sec = total_path_comp_time.tv_sec + d.tv_sec; - total_path_comp_time.tv_usec = total_path_comp_time.tv_usec + d.tv_usec; - total_path_comp_time = tv_adjust(total_path_comp_time); - - gdouble path_comp_time_msec = (((total_path_comp_time.tv_sec) * 1000) + ((total_path_comp_time.tv_usec) / 1000)); - gdouble av_alg_comp_time = ((path_comp_time_msec / numSuccesPathComp)); - DEBUG_PC("\t --- STATS PATH COMP ----"); - DEBUG_PC("Succesfully Comp: %d | Path Comp Requests: %d", numSuccesPathComp, numPathCompIntents); - DEBUG_PC("AV. PATH COMP ALG. TIME: %f ms", av_alg_comp_time); - - gint i = 0; - for (GList* listnode = g_list_first(serviceList); - listnode; - listnode = g_list_next(listnode), i++) { - struct service_t* s = (struct service_t*)(listnode->data); - char* eptr; - for (gint j = 0; j < s->num_service_constraints; j++) { - struct constraint_t* constraints = &(s->constraints[j]); - if (strncmp((const char*)(constraints->constraint_type), "bandwidth", 9) == 0) { - totalReqBw += (gdouble)(strtod((char*)constraints->constraint_value, &eptr)); - } - } - } - - for (gint k = 0; k < routeConnList->numCompRouteConnList; k++) { - struct compRouteOutput_t* rO = &(routeConnList->compRouteConnection[k]); - if (rO->noPathIssue == NO_PATH_CONS_ISSUE) { - continue; - } - // Get the requested service bw bound to that computed path - struct path_t* p = &(rO->paths[0]); - struct service_t* s = get_service_for_computed_path(rO->serviceId.service_uuid); - if (s == NULL) { - DEBUG_PC("Weird the service associated to a path is not found"); - exit(-1); - } - for (gint l = 0; l < s->num_service_constraints; l++) { - struct constraint_t* constraints = &(s->constraints[l]); - char* eptr; - if (strncmp((const char*)(constraints->constraint_type), "bandwidth", 9) == 0) { - totalServedBw += (gdouble)(strtod((char*)constraints->constraint_value, &eptr)); - } - } - } - gdouble avServedRatio = totalServedBw / totalReqBw; - DEBUG_PC("AV. Served Ratio: %f", avServedRatio); - gdouble avBlockedBwRatio = (gdouble)(1.0 - avServedRatio); - DEBUG_PC("AV. BBE: %f", avBlockedBwRatio); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate active service path - * - * @param actServPath - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_active_service_path(struct activeServPath_t* actServPath) { - g_assert(actServPath); - g_free(actServPath); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate active service - * - * @param actService - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_active_service(struct activeService_t* actService) { - g_assert(actService); - g_list_free_full(g_steal_pointer(&actService->activeServPath), (GDestroyNotify)destroy_active_service_path); - g_free(actService); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate a requested service - * - * @param s - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_requested_service(struct service_t* s) { - g_assert(s); - g_free(s); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate a device - * - * @param d - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_device(struct device_t* d) { - g_assert(d); - g_free(d); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate a link from the linkList - * - * @param d - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_link(struct link_t* l) { - g_assert(l); - g_free(l); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Eliminate a context from the contextSet - * - * @param d - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void destroy_context(struct context_t* c) { - g_assert(c); - g_free(c); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief Excecution Dijkstra algorithm - * - * @param srcMapIndex - * @param dstMapIndex - * @param g - * @param s - * @param mapNodes - * @param SN - * @param RP - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void dijkstra(gint srcMapIndex, gint dstMapIndex, struct graph_t* g, struct service_t* s, - struct map_nodes_t* mapNodes, struct nodes_t* SN, struct compRouteOutputItem_t* RP, - guint arg) { - g_assert(s);g_assert(g); - - // Set params into mapNodes related to the source nodes of the request - mapNodes->map[srcMapIndex].distance = 0.0; - mapNodes->map[srcMapIndex].latency = 0.0; - mapNodes->map[srcMapIndex].avaiBandwidth = 0.0; - mapNodes->map[srcMapIndex].power = 0.0; - - // Initialize the set Q and S - GList *S = NULL, *Q = NULL; - gint indexVertice = -1; - - // Add the source into the Q - struct nodeItem_t* nodeItem = g_malloc0(sizeof(struct nodeItem_t)); - if (nodeItem == NULL) { - DEBUG_PC("memory allocation failed\n"); - exit(-1); - } - // initialize some nodeItem attributes - nodeItem->distance = 0.0; - nodeItem->latency = 0.0; - nodeItem->power = 0.0; - duplicate_node_id(&mapNodes->map[srcMapIndex].verticeId, &nodeItem->node); - - // Select the optimization process - if (arg & ENERGY_EFFICIENT_ARGUMENT) - Q = g_list_insert_sorted(Q, nodeItem, sort_by_energy); - // more "if" according to different optimization criteria ... - else - Q = g_list_insert_sorted(Q, nodeItem, sort_by_distance); - - // Check whether there is spurNode (SN) and rootPath (RP) - if (SN != NULL && RP != NULL) { - struct routeElement_t* re; - for (gint j = 0; j < RP->numRouteElements; j++) { - // Get the source and target Nodes of the routeElement within the rootPath - re = &RP->routeElement[j]; - DEBUG_PC("root Link: aNodeId: %s (%s) --> zNodeiId: %s (%s)", re->aNodeId.nodeId, re->aEndPointId, re->zNodeId.nodeId, re->zEndPointId); - - // if ingress of the root link (aNodeId) is the spurNode, then stops - if (compare_node_id(&re->aNodeId, SN) == 0) { - DEBUG_PC("root Link: aNodeId: %s and spurNode: %s -- stop exploring the rootPath (RP)", re->aNodeId.nodeId, SN->nodeId); - break; - } - // Extract from Q - GList* listnode = g_list_first(Q); - struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); - Q = g_list_remove(Q, node); - - //DEBUG_RL_RA ("Exploring node %s", node->node.nodeId); - indexVertice = graph_vertice_lookup(node->node.nodeId, g); - g_assert(indexVertice >= 0); - - // Get the indexTargetedVertice - gint indexTVertice = -1; - indexTVertice = graph_targeted_vertice_lookup(indexVertice, re->zNodeId.nodeId, g); - gint done = check_link(node, indexVertice, indexTVertice, g, s, &S, &Q, mapNodes, arg); - (void)done; - // Add to the S list - S = g_list_append(S, node); - } - // Check that the first node in Q set is SpurNode, otherwise something went wrong ... - if (compare_node_id(&re->aNodeId, SN) != 0) { - //DEBUG_PC ("root Link: aNodeId: %s is NOT the spurNode: %s -- something wrong", re->aNodeId.nodeId, SN->nodeId); - g_list_free_full(g_steal_pointer(&S), g_free); - g_list_free_full(g_steal_pointer(&Q), g_free); - return; - } - } - - while (g_list_length(Q) > 0) { - //Extract from Q set - GList* listnode = g_list_first(Q); - struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); - Q = g_list_remove(Q, node); - DEBUG_PC("Q length: %d", g_list_length(Q)); - DEBUG_PC("DeviceId: %s", node->node.nodeId); - - // visit all the links from u within the graph - indexVertice = graph_vertice_lookup(node->node.nodeId, g); - g_assert(indexVertice >= 0); - - // Check the targeted vertices from u - for (gint i = 0; i < g->vertices[indexVertice].numTargetedVertices; i++) { - gint done = check_link(node, indexVertice, i, g, s, &S, &Q, mapNodes, arg); - (void)done; - } - // Add node into the S Set - S = g_list_append(S, node); - //DEBUG_PC ("S length: %d", g_list_length (S)); - } - g_list_free_full(g_steal_pointer(&S), g_free); - g_list_free_full(g_steal_pointer(&Q), g_free); - return; -} - -/////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief KSP computation using Dijkstra algorithm - * - * @param pred - * @param g - * @param s - * @param SN - * @param RP - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -gint ksp_comp(struct pred_t* pred, struct graph_t* g, struct service_t* s, - struct nodes_t* SN, struct compRouteOutputItem_t* RP, - struct map_nodes_t* mapNodes, guint arg) { - g_assert(pred); g_assert(g); g_assert(s); - - DEBUG_PC("Source: %s -- Destination: %s", s->service_endpoints_id[0].device_uuid, s->service_endpoints_id[1].device_uuid); - - // Check the both ingress src and dst endpoints are in the graph - gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); - if (srcMapIndex == -1) { - DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); - return -1; - } - - gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); - if (dstMapIndex == -1) { - DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); - return -1; - } - - //DEBUG_PC("srcMapIndex: %d (node: %s)", srcMapIndex, mapNodes->map[srcMapIndex].verticeId.nodeId); - //DEBUG_PC("dstMapIndex: %d (node: %s)", dstMapIndex, mapNodes->map[dstMapIndex].verticeId.nodeId); - - // Compute the shortest path route - dijkstra(srcMapIndex, dstMapIndex, g, s, mapNodes, SN, RP, arg); - - // Check that a feasible solution in term of latency and bandwidth is found - gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); - struct map_t* dest_map = &mapNodes->map[map_dstIndex]; - if (!(dest_map->distance < INFINITY_COST)) { - DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); - return -1; - } - - DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); - // Check that the computed available bandwidth is larger than 0.0 - if (dest_map->avaiBandwidth <= (gfloat)0.0) { - DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); - return -1; - } - DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); - // Handle predecessors - build_predecessors(pred, s, mapNodes); - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief set the path parameters (e.g., latency, cost, power, ...) to an under-constructed - * path from the computed map vertex - * - * @param p - * @param mapV - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void set_path_attributes(struct compRouteOutputItem_t* p, struct map_t* mapV) { - g_assert(p); g_assert(mapV); - memcpy(&p->cost, &mapV->distance, sizeof(gdouble)); - memcpy(&p->availCap, &mapV->avaiBandwidth, sizeof(mapV->avaiBandwidth)); - memcpy(&p->delay, &mapV->latency, sizeof(mapV->latency)); - memcpy(&p->power, &mapV->power, sizeof(gdouble)); - return; -} - -//////////////////////////////////////////////////////////////////////////////////////// -/** - * @file pathComp_tools.c - * @brief K-CSPF algorithm execution (YEN algorithm) - * - * @param s - * @param path - * @param g - * @param optimization_flag - * - * @author Ricardo Martínez - * @date 2022 - */ - ///////////////////////////////////////////////////////////////////////////////////////// -void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g, guint arg) { - g_assert(s); g_assert(path); g_assert(g); - - // create map of devices/nodes to handle the path computation using the context - struct map_nodes_t* mapNodes = create_map_node(); - build_map_node(mapNodes, g); - - // predecessors to store the computed path - struct pred_t* predecessors = create_predecessors(); - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); - struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); - - // Compute the 1st KSP path - gint done = ksp_comp(predecessors, g, s, NULL, NULL, mapNodes, arg); - if (done == -1) { - DEBUG_PC("NO PATH for %s[%s] --> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); - comp_route_connection_issue_handler(path, s); - g_free(mapNodes); g_free(predecessors); - return; - } - - // Construct the path from the computed predecessors - struct compRouteOutputItem_t* p = create_path_item(); - //print_predecessors(predecessors); - build_path(p, predecessors, s); - gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); - struct map_t* dst_map = &mapNodes->map[indexDest]; - // Get the delay and cost - set_path_attributes(p, dst_map); - - // Add the computed path, it may be a not feasible path, but at the end it is - // checked all the feasible paths, and select the first one - print_path(p); - - // Copy the serviceId - copy_service_id(&path->serviceId, &s->serviceId); - // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) - for (gint i = 0; i < s->num_service_endpoints_id; i++) { - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); - struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); - copy_service_endpoint_id(oEp, iEp); - } - path->num_service_endpoints_id = s->num_service_endpoints_id; - - DEBUG_PC("COMPUTE UP TO K Feasible Paths A[%d]", MAX_KSP_VALUE); - // Create A and B sets of paths to handle the YEN algorithm - struct path_set_t *A = create_path_set(), *B = create_path_set(); - // Add 1st Computed path into A->paths[0] - duplicate_path(p, &A->paths[0]); - A->numPaths++; - g_free(predecessors); g_free(p); - for (gint k = 1; k < MAX_KSP_VALUE; k++) { - DEBUG_PC("*************************** kth (%d) ***********************************", k); - struct compRouteOutputItem_t* p = create_path_item(); - duplicate_path(&A->paths[k - 1], p); - // The spurNode ranges from near-end node of the first link to the near-end of the last link forming the kth path - gint i = 0; - struct compRouteOutputItem_t* rootPath = create_path_item(); - for (i = 0; i < p->numRouteElements; i++) { - struct nodes_t *spurNode = create_node(), *nextSpurNode = create_node(); - struct routeElement_t* re = &(p->routeElement[i]); - // Create predecessors to store the computed path - struct pred_t* predecessors = create_predecessors(); - // Clear previous mapNodes, i.e. create it again - g_free(mapNodes); - mapNodes = create_map_node(); - build_map_node(mapNodes, g); - struct nodes_t* n = &re->aNodeId; - duplicate_node_id(n, spurNode); - n = &re->zNodeId; - duplicate_node_id(n, nextSpurNode); - DEBUG_PC("spurNode: %s --> nextSpurNode: %s", spurNode->nodeId, nextSpurNode->nodeId); - - // rootPath contains a set of links of A[k-1] from the source Node till the SpurNode -> NextSpurNode - // Example: A[k-1] = {L1, L2, L3, L4}, i.e. " Node_a -- L1 --> Node_b -- L2 --> Node_c -- L3 --> Node_d -- L4 --> Node_e " - // E.g., for the ith iteration if the spurNode = Node_c and NextSpurNode = Node_d; then rootPath = {L1, L2, L3} - add_routeElement_path_back(re, rootPath); - DEBUG_PC("\n"); - DEBUG_PC("^^^^^^^rootPath^^^^^^^"); - print_path(rootPath); - - // For all existing and computed paths p in A check if from the source to the NextSpurNode - // the set of links matches with those contained in the rootPath - // If YES, remove from the auxiliary graph the next link in p from NextSpurNode - // Otherwise do nothing - struct graph_t* gAux = create_graph(); - duplicate_graph(g, gAux); - // Modified graph - modify_targeted_graph(gAux, A, rootPath, spurNode); - - // Trigger the computation of the path from src to dst constrained to traverse all the links from src - // to spurNode contained into rootPath over the resulting graph - if (ksp_comp(predecessors, gAux, s, spurNode, rootPath, mapNodes, arg) == -1) { - DEBUG_PC("FAILED SP from %s via spurNode: %s to %s", iEp->device_uuid, spurNode->nodeId, eEp->device_uuid); - g_free(nextSpurNode); g_free(spurNode); - g_free(gAux); g_free(predecessors); - continue; - } - DEBUG_PC("SUCCESFUL SP from %s via spurNode: %s to %s", iEp->device_uuid, spurNode->nodeId, eEp->device_uuid); - // Create the node list from the predecessors - struct compRouteOutputItem_t* newKpath = create_path_item(); - build_path(newKpath, predecessors, s); - DEBUG_PC("new K (for k: %d) Path is built", k); - gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); - struct map_t* dst_map = &mapNodes->map[indexDest]; - set_path_attributes(newKpath, dst_map); - DEBUG_PC("New PATH (@ kth: %d) ADDED to B[%d] - {Path Cost: %f, e2e latency: %f, bw: %f, Power: %f ", k, B->numPaths, newKpath->cost, - newKpath->delay, newKpath->availCap, newKpath->power); - // Add the computed kth SP to the heap B - duplicate_path(newKpath, &B->paths[B->numPaths]); - B->numPaths++; - DEBUG_PC("Number of B paths: %d", B->numPaths); - - g_free(newKpath); g_free(nextSpurNode); g_free(spurNode); - g_free(gAux); g_free(predecessors); - } - // If B is empty then stops - if (B->numPaths == 0) { - DEBUG_PC("B does not have any path ... the stops kth computation"); - break; - } - - // Sort the potential B paths according to different optimization parameters - sort_path_set(B, arg); - // Add the lowest path into A[k] - DEBUG_PC("-------------------------------------------------------------"); - DEBUG_PC("Append SP for B[0] to A[%d] --- Cost: %f, Latency: %f, Power: %f", A->numPaths, B->paths[0].cost, - B->paths[0].delay, B->paths[0].power); - duplicate_path(&B->paths[0], &A->paths[A->numPaths]); - A->numPaths++; - DEBUG_PC("A Set size: %d", A->numPaths); - DEBUG_PC("-------------------------------------------------------------"); - - // Remove/Pop front element from the path set B (i.e. remove B[0]) - pop_front_path_set(B); - DEBUG_PC("B Set Size: %d", B->numPaths); - } - - // Copy the serviceId - copy_service_id(&path->serviceId, &s->serviceId); - // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) - for (gint m = 0; m < s->num_service_endpoints_id; m++) { - struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[m]); - struct service_endpoints_id_t* oEp = &(s->service_endpoints_id[m]); - copy_service_endpoint_id(oEp, iEp); - } - - // Print all the paths i A - for (gint h = 0; h < A->numPaths; h++) { - DEBUG_PC("================== A[%d] =======================", h); - print_path(&A->paths[h]); - } - DEBUG_PC("Number of paths: %d", path->numPaths); - // For all the computed paths in A, pick the one being feasible wrt the service constraints - for (gint ksp = 0; ksp < A->numPaths; ksp++) { - if (ksp >= MAX_KSP_VALUE) { - DEBUG_PC("Number Requested paths (%d) REACHED - STOP", ksp); - break; - } - gdouble feasibleRoute = check_computed_path_feasability(s, &A->paths[ksp]); - if (feasibleRoute == TRUE) { - DEBUG_PC("A[%d] available: %f, pathCost: %f; latency: %f, Power: %f", ksp, A->paths[ksp].availCap, A->paths[ksp].cost, A->paths[ksp].delay, A->paths[ksp].power); - struct compRouteOutputItem_t* pathaux = &A->paths[ksp]; - path->numPaths++; - struct path_t* targetedPath = &path->paths[path->numPaths - 1]; - duplicate_path_t(pathaux, targetedPath); - print_path_t(targetedPath); - remove_path_set(A); - remove_path_set(B); - return; - } - } - remove_path_set(A); - remove_path_set(B); - // No paths found --> Issue - DEBUG_PC("K-SP failed!!!"); - comp_route_connection_issue_handler(path, s); - return; +//////////////////////////////////////////////////////////////////////////////////////// +/** + * # Copyright 2022 Centre Tecnològic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es + * + * 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. + + * Author: CTTC/CERCA PONS RU Ricardo Martínez (ricardo.martinez@cttc.es) + */ +///////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathComp_log.h" +#include "pathComp.h" +#include "pathComp_tools.h" + +gint numPathCompIntents = 0; // number of events triggering the path computation +//gint numSuccesPathComp = 0; // number of events resulting in succesfully path computations fulfilling the constraints +struct timeval total_path_comp_time; +gdouble totalReqBw = 0.0; +gdouble totalServedBw = 0.0; + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function for time processing + * + * @param a + * + * @author Ricardo Martínez + * @date 2022 + */ + //////////////////////////////////////////////////////////////////////////////////////// +struct timeval tv_adjust (struct timeval a) { + while (a.tv_usec >= 1000000) { + a.tv_usec -= 1000000; + a.tv_sec++; + } + while (a.tv_usec < 0) { + a.tv_usec += 1000000; + a.tv_sec--; + } + return a; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief friendly function to copy safely strings + * + * @param dst + * @param src + * + * @author Ricardo Martínez + * @date 2022 + */ + //////////////////////////////////////////////////////////////////////////////////////// +void duplicate_string(gchar* dst, gchar* src) { + g_assert(dst); g_assert(src); + strcpy(dst, src); + dst[strlen(dst)] = '\0'; + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to print the computed the path + * + * @param path + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void print_path (struct compRouteOutputItem_t *p) { + g_assert(p); + DEBUG_PC ("=========== COMPUTED PATH ======================="); + DEBUG_PC ("E2E Avail. Bw: %f, Latency: %f, Cost: %f, Consumed Power (in W): %f", p->availCap, p->delay, p->cost, p->power); + for (gint k = 0; k < p->numRouteElements; k++) { + DEBUG_PC ("%s[%s] --> %s[%s]", p->routeElement[k].aNodeId.nodeId, p->routeElement[k].aEndPointId, + p->routeElement[k].zNodeId.nodeId, p->routeElement[k].zEndPointId); + DEBUG_PC("\t linkId: %s", p->routeElement[k].linkId); + DEBUG_PC("\t aTopologyId: %s", p->routeElement[k].aTopologyId); + DEBUG_PC("\t zTopologyId: %s", p->routeElement[k].zTopologyId); + } + DEBUG_PC ("=================================================================="); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to print the output path formed by link Ids + * + * @param p + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_path_t(struct path_t* p) { + g_assert(p); + DEBUG_PC(" ============ COMPUTED OUTPUT PATH ================="); + DEBUG_PC("Path AvailBw: %f, Cost: %f, Latency: %f, Power: %f", p->path_capacity.value, + p->path_cost.cost_value, p->path_latency.fixed_latency, p->path_power.power); + DEBUG_PC("number of links of path %d", p->numPathLinks); + for (gint k = 0; k < p->numPathLinks; k++) { + DEBUG_PC("Link: %s", p->pathLinks[k].linkId); + for (gint l = 0; l < p->pathLinks[k].numLinkTopologies; l++) { + DEBUG_PC("end Link [%d] TopologyId: %s", l, p->pathLinks[k].linkTopologies[l].topologyId); + } + DEBUG_PC(" ContextId: %s", p->pathLinks[k].topologyId.contextId); + DEBUG_PC(" TopologyUUid: %s", p->pathLinks[k].topologyId.topology_uuid); + DEBUG_PC(" aDeviceId: %s", p->pathLinks[k].aDeviceId); + DEBUG_PC(" aEndpointId: %s", p->pathLinks[k].aEndPointId); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used allocate memory for struct path_t + * + * + * @author Ricardo Martínez + * @date 2022 + */ + //////////////////////////////////////////////////////////////////////////////////////// +struct path_t* create_path() { + struct path_t* p = g_malloc0(sizeof(struct path_t)); + if (p == NULL) { + DEBUG_PC("Memory allocation failure"); + exit(-1); + } + return(p); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Returns the char (36 bytes) format of a uuid + * + * @param uuid + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gchar* get_uuid_char(uuid_t uuid) { + gchar* uuidChar = g_malloc0(16); // uuid has 36 chars + if (uuidChar == NULL) { + DEBUG_PC("Memory Allocation failure"); + exit(-1); + } + uuid_unparse(uuid, (char *)uuidChar); + return uuidChar; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Makes a copy of the service identifier (including the context) + * + * @param o + * @param i + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void copy_service_id(struct serviceId_t* o, struct serviceId_t* i) { + g_assert(o); g_assert(i); + memcpy(o->contextId, i->contextId, sizeof(i->contextId)); + memcpy(o->service_uuid, i->service_uuid, sizeof(i->service_uuid)); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Makes a copy of the service endpoint identifier (including the topology (contect and topology id), device and endpoint (port)) + * + * @param oEp + * @param iEp + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void copy_service_endpoint_id(struct service_endpoints_id_t* oEp, struct service_endpoints_id_t* iEp) { + g_assert(oEp); g_assert(iEp); + + // copy topology information + memcpy(oEp->topology_id.contextId, iEp->topology_id.contextId, sizeof(iEp->topology_id.contextId)); + memcpy(oEp->topology_id.topology_uuid, iEp->topology_id.topology_uuid, sizeof(iEp->topology_id.topology_uuid)); + + // copy the endpoint + memcpy(oEp->device_uuid, iEp->device_uuid, sizeof(iEp->device_uuid)); + memcpy(oEp->endpoint_uuid, iEp->endpoint_uuid, sizeof(iEp->endpoint_uuid)); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief From the set of contexts, it is returned the graph associated to that context matching + * with the passed contextId. + * + * @param Set + * @param contextId + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct graph_t* get_graph_by_contextId(GList* set, gchar* contextId) { + g_assert(contextId); + + // iterate over the set of context. Pick the one matching with contextId, and return the graph. + // If not found, return NULL + struct graph_t* g = NULL; + for (GList *ln = g_list_first(set); + ln; + ln = g_list_next(ln)){ + struct context_t* context = (struct context_t*)(ln->data); + if (strcmp(context->contextId, contextId) == 0) { + g = &(context->g); + return g; + } + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Process the service constraint and maps them into the path constraints + * to be fulfilled + * + * @param path_constraints + * @param s + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct path_constraints_t * get_path_constraints(struct service_t* s) { + g_assert(s); + + struct path_constraints_t* path_constraints = g_malloc0(sizeof(struct path_constraints_t)); + if (path_constraints == NULL) { + DEBUG_PC("Memory Allocation Failure"); + exit(-1); + } + + char* eptr; + for (gint i = 0; i < s->num_service_constraints; i++) { + struct constraint_t* constraint = &(s->constraints[i]);; + if (strncmp((const char*)constraint->constraint_type, "bandwidth", 9) == 0) { + path_constraints->bwConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); + path_constraints->bw = TRUE; + //DEBUG_PC("Path Constraint Bw: %f", path_constraints->bwConstraint); + } + if (strncmp((const char*)constraint->constraint_type, "cost", 4) == 0) { + path_constraints->costConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); + path_constraints->cost = TRUE; + //DEBUG_PC("Path Constraint Cost: %f", path_constraints->costConstraint); + } + if (strncmp((const char*)constraint->constraint_type, "latency", 7) == 0) { + path_constraints->latencyConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); + path_constraints->latency = TRUE; + //DEBUG_PC("Path Constraint Latency: %f", path_constraints->latencyConstraint); + } + if (strncmp((const char*)constraint->constraint_type, "energy", 6) == 0) { + path_constraints->energyConstraint = (gdouble)(strtod((char*)constraint->constraint_value, &eptr)); + path_constraints->energy = TRUE; + //DEBUG_PC("Path Constraint Energy: %f", path_constraints->energyConstraint); + } + } + return path_constraints; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Creates the predecessors to keep the computed path + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct pred_t * create_predecessors () { + struct pred_t *predecessors = g_malloc0 (sizeof (struct pred_t)); + if (predecessors == NULL) { + DEBUG_PC ("memory allocation failed\n"); + exit (-1); + } + return predecessors; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief create edge + * + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct edges_t* create_edge() { + struct edges_t* e = g_malloc0(sizeof(struct edges_t)); + if (e == NULL) { + DEBUG_PC("Memory allocation failed\n"); + exit(-1); + } + return e; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Prints the list of the predecessors for a given computed Shortest Path + * + * @param p + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void print_predecessors (struct pred_t *p) +{ + g_assert (p); + DEBUG_PC ("Number of Predecessors: %d", p->numPredComp); + for (gint i = 0; i < p->numPredComp; i++) { + struct pred_comp_t *pComp = &(p->predComp[i]); + DEBUG_PC ("deviceId: %s", pComp->v.nodeId); + struct edges_t *e = &(pComp->e); + DEBUG_PC("Edge[#%d] (linkId): %s", i, e->linkId); + DEBUG_PC ("\t %s[%s] ===>", e->aNodeId.nodeId, e->aEndPointId); + DEBUG_PC("\t %s[%s]", e->zNodeId.nodeId, e->zEndPointId); + DEBUG_PC("\t aTopologyId: %s", e->aTopologyId); + DEBUG_PC("\t zTopologyId: %s", e->zTopologyId); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Builds the list of predecessors for the request destination using the computed Shortest Path + * being stored in map + * + * @param p + * @param s + * @param map + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void build_predecessors (struct pred_t *p, struct service_t *s, struct map_nodes_t *map) { + g_assert (p); g_assert (s); g_assert (map); + + struct nodes_t *v = create_node(); + duplicate_string(v->nodeId, s->service_endpoints_id[1].device_uuid); + + struct edges_t *e = create_edge(); + get_edge_from_map_by_node (e, v, map); + + // Get u (being source of edge e) + struct nodes_t u; + duplicate_node_id (&e->aNodeId, &u); + + // Add to the predecessors list + struct pred_comp_t *pred = &(p->predComp[p->numPredComp]); + duplicate_node_id (&u, &pred->v); + struct edges_t *e1 = &(pred->e); + duplicate_edge (e1, e); + p->numPredComp++; + // Back-trace edges till reaching the srcPEId + struct nodes_t* srcNode = create_node(); + duplicate_string(srcNode->nodeId, s->service_endpoints_id[0].device_uuid); + + while (compare_node_id (&u, srcNode) != 0) { + duplicate_node_id (&u, v); + get_edge_from_map_by_node (e, v, map); + // Get the u (being source of edge e) + duplicate_node_id (&e->aNodeId, &u); + // Get the new predecessor + struct pred_comp_t *pred = &p->predComp[p->numPredComp]; + // Add to the predecessors list + duplicate_node_id (&u, &pred->v); + struct edges_t *e1 = &(pred->e); + duplicate_edge (e1, e); + p->numPredComp++; + } + print_predecessors (p); + g_free (e); g_free(v); g_free(srcNode); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief It creates a struct nodes_t + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct nodes_t * create_node () +{ + struct nodes_t *n = g_malloc0 (sizeof (struct nodes_t)); + if (n == NULL) { + DEBUG_PC ("memory allocation problem"); + exit (-1); + } + return n; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief It creates a routeElement_t + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct routeElement_t * create_routeElement () { + struct routeElement_t *rE = g_malloc0 (sizeof (struct routeElement_t)); + if (rE == NULL) { + DEBUG_PC ("memory allocation problem"); + exit (-1); + } + return rE; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief copy node ids + * + * @param src + * @param dst + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_node_id (struct nodes_t *src, struct nodes_t *dst) { + g_assert (src); + g_assert (dst); + //DEBUG_PC ("Duplicate nodeId for %s", src->nodeId); + strcpy (dst->nodeId, src->nodeId); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief compares a pair of node Ids + * + * @param a + * @param b + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint compare_node_id (struct nodes_t *a, struct nodes_t *b) { + g_assert (a); + g_assert (b); + return (memcmp (&a->nodeId, b->nodeId, strlen (b->nodeId))); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief duplicate two routeElement_t + * + * @param src + * @param dst + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_routeElement (struct routeElement_t *src, struct routeElement_t *dst) +{ + g_assert (src); + g_assert (dst); + + duplicate_node_id (&(src->aNodeId), &(dst->aNodeId)); + duplicate_node_id (&(src->zNodeId), &(dst->zNodeId)); + duplicate_string(dst->aEndPointId, src->aEndPointId); + duplicate_string(dst->zEndPointId, src->zEndPointId); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief duplicate two edges + * + * @param e1 (destination) + * @param e2 (source) + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_edge (struct edges_t *e1, struct edges_t *e2) { + g_assert (e1); g_assert (e2); + + duplicate_node_id (&e2->aNodeId, &e1->aNodeId); + duplicate_node_id (&e2->zNodeId, &e1->zNodeId); + //DEBUG_PC ("e->aNodeId: %s ---> e->zNodeId: %s", e1->aNodeId.nodeId, e1->zNodeId.nodeId); + duplicate_string(e1->aEndPointId, e2->aEndPointId); + duplicate_string(e1->zEndPointId, e2->zEndPointId); + duplicate_string(e1->linkId, e2->linkId); + duplicate_string(e1->interDomain_localId, e2->interDomain_localId); + duplicate_string(e1->interDomain_remoteId, e2->interDomain_remoteId); + duplicate_string(e1->aTopologyId, e2->aTopologyId); + duplicate_string(e1->zTopologyId, e2->zTopologyId); + + e1->unit = e2->unit; + memcpy(&e1->totalCap, &e2->totalCap, sizeof(gdouble)); + memcpy(&e1->availCap, &e2->availCap, sizeof(gdouble)); + + memcpy (&e1->cost, &e2->cost, sizeof (gdouble)); + memcpy (&e1->delay, &e2->delay, sizeof (gdouble)); + memcpy(&e1->energy, &e2->energy, sizeof(gdouble)); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Duplicate path + * + * @param a - original + * @param b - copy + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_path (struct compRouteOutputItem_t *a, struct compRouteOutputItem_t *b) { + g_assert (a); g_assert (b); + memcpy(&b->availCap, &a->availCap, sizeof (gdouble)); + memcpy(&b->cost, &a->cost, sizeof(gdouble)); + memcpy(&b->delay, &a->delay, sizeof (gdouble)); + memcpy(&b->power, &a->power, sizeof(gdouble)); + b->numRouteElements = a->numRouteElements; + for (gint k = 0; k < a->numRouteElements; k++) { + //DEBUG_PC ("aNodeId: %s // zNodeId: %s", a->routeElement[k].aNodeId.nodeId, a->routeElement[k].zNodeId.nodeId); + // aNodeId duplication + struct nodes_t *n1 = &(a->routeElement[k].aNodeId); + struct nodes_t *n2 = &(b->routeElement[k].aNodeId); + duplicate_node_id (n1, n2); + //zNodeId duplication + n1 = &(a->routeElement[k].zNodeId); + n2 = &(b->routeElement[k].zNodeId); + duplicate_node_id (n1, n2); + duplicate_string(b->routeElement[k].aEndPointId, a->routeElement[k].aEndPointId); + duplicate_string(b->routeElement[k].zEndPointId, a->routeElement[k].zEndPointId); + duplicate_string(b->routeElement[k].linkId, a->routeElement[k].linkId); + duplicate_string(b->routeElement[k].aTopologyId, a->routeElement[k].aTopologyId); + duplicate_string(b->routeElement[k].zTopologyId, a->routeElement[k].zTopologyId); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Duplicate path from compRouteOutputItem_t to path_t + * + * @param a - original + * @param b - copy + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_path_t(struct compRouteOutputItem_t* a, struct path_t* b) { + g_assert(a); g_assert(b); + + // transfer path characteristics ... + memcpy(&b->path_capacity.value, &a->availCap, sizeof(gdouble)); + memcpy(&b->path_cost.cost_value, &a->cost, sizeof(gdouble)); + memcpy(&b->path_latency.fixed_latency, &a->delay, sizeof(gdouble)); + memcpy(&b->path_power.power, &a->power, sizeof(gdouble)); + + b->numPathLinks = a->numRouteElements; + + for (gint k = 0; k < a->numRouteElements; k++) { + struct routeElement_t* rE = &(a->routeElement[k]); + struct pathLink_t* pL = &(b->pathLinks[k]); + + // copy the aDeviceId and aEndpointId, zDeviceId and zEndPointId + duplicate_string(pL->aDeviceId, rE->aNodeId.nodeId); + duplicate_string(pL->zDeviceId, rE->zNodeId.nodeId); + duplicate_string(pL->aEndPointId, rE->aEndPointId); + duplicate_string(pL->zEndPointId, rE->zEndPointId); + + duplicate_string(pL->topologyId.topology_uuid, rE->aTopologyId); + duplicate_string(pL->topologyId.contextId, rE->contextId); + + //copy the linkId + duplicate_string(pL->linkId, rE->linkId); + pL->numLinkTopologies++; + duplicate_string(pL->linkTopologies[pL->numLinkTopologies - 1].topologyId, rE->aTopologyId); + pL->numLinkTopologies++; + duplicate_string(pL->linkTopologies[pL->numLinkTopologies - 1].topologyId, rE->zTopologyId); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Return the index into mapN related nodeId + * + * @param nodeId + * @para mapN + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint get_map_index_by_nodeId (gchar *nodeId, struct map_nodes_t * mapN) { + gint i = 0; + for (i = 0; i < mapN->numMapNodes; i++) { + //DEBUG_PC ("i: %d; current: %s // targeted: %s", i, mapN->map[i].verticeId.nodeId, nodeId); + if (memcmp (mapN->map[i].verticeId.nodeId, nodeId, strlen (nodeId)) == 0) { + //DEBUG_PC ("Index: %d", i); + return i; + } + } + //DEBUG_PC ("Index: %d", index); + return -1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Get the edge e enabling reaching the computed v in mapNodes + * + * @param e + * @param v + * @param mapN + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void get_edge_from_map_by_node (struct edges_t *e, struct nodes_t* v, struct map_nodes_t *mapN) { + //DEBUG_PC ("Get the Edge into map from node v: %s", v.nodeId); + // Get the edge reaching the node v from mapNodes + gint map_vIndex = get_map_index_by_nodeId (v->nodeId, mapN); + //DEBUG_PC ("aNodeId: %s --> zNodeId: %s", mapN->map[map_vIndex].predecessor.aNodeId.nodeId, mapN->map[map_vIndex].predecessor.zNodeId.nodeId); + struct edges_t *te = &(mapN->map[map_vIndex].predecessor); + duplicate_edge (e, te); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Get the edge from the predecessors array for a given node n + * + * @param e + * @param n + * @param predecessors + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void get_edge_from_predecessors (struct edges_t *e, struct nodes_t* n, struct pred_t *predecessors) { + g_assert(predecessors); + DEBUG_PC ("Get edge outgoing node %s from predecessors list", n->nodeId); + //print_predecessors (predecessors); + for (gint i = 0; i < predecessors->numPredComp; i++) { + struct pred_comp_t *pred = &(predecessors->predComp[i]); + if (compare_node_id (n, &pred->v) == 0) { + // Add to the predecessors list + struct edges_t *te = &(pred->e); + DEBUG_PC("add e (linkId): %s", te->linkId); + duplicate_edge (e, te); + return; + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Construct the path using the predecessors list + * + * @param path + * @param predecessors + * @param s + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void build_path (struct compRouteOutputItem_t *p, struct pred_t *predecessors, struct service_t *s) { + // Get the source device Id of the network connectivity service + struct nodes_t *v = create_node(); + // Src Node of the Service set to v + duplicate_string(v->nodeId, s->service_endpoints_id[0].device_uuid); + + // Get the edge for v in predecessors + struct edges_t* e = create_edge(); + get_edge_from_predecessors (e, v, predecessors); + // Get the target for e + struct nodes_t u; + duplicate_node_id (&e->zNodeId, &u); + //DEBUG_PC ("u: %s", u.nodeId); + struct path_constraints_t* pathCons = get_path_constraints(s); + + // Add route element to the path being constructed + gint k = 0; + duplicate_node_id (&e->aNodeId, &p->routeElement[k].aNodeId); + duplicate_node_id (&e->zNodeId, &p->routeElement[k].zNodeId); + duplicate_string(p->routeElement[k].aEndPointId, e->aEndPointId); + duplicate_string(p->routeElement[k].zEndPointId, e->zEndPointId); + duplicate_string(p->routeElement[k].linkId, e->linkId); + duplicate_string(p->routeElement[k].aTopologyId, e->aTopologyId); + duplicate_string(p->routeElement[k].zTopologyId, e->zTopologyId); + duplicate_string(p->routeElement[k].contextId, s->serviceId.contextId); + p->numRouteElements++; + + // Get Dst Node of connectivity service + struct nodes_t* dst = create_node(); + duplicate_string(dst->nodeId, s->service_endpoints_id[1].device_uuid); + while (compare_node_id (&u, dst) != 0) { + k++; + p->numRouteElements++; + duplicate_node_id (&u, v); + get_edge_from_predecessors (e, v, predecessors); + // Get the target u + duplicate_node_id (&e->zNodeId, &u); + // Add route element to the path being constructed + duplicate_node_id (&e->aNodeId, &p->routeElement[k].aNodeId); + duplicate_node_id (&e->zNodeId, &p->routeElement[k].zNodeId); + duplicate_string(p->routeElement[k].aEndPointId, e->aEndPointId); + duplicate_string(p->routeElement[k].zEndPointId, e->zEndPointId); + duplicate_string(p->routeElement[k].linkId, e->linkId); + duplicate_string(p->routeElement[k].aTopologyId, e->aTopologyId); + duplicate_string(p->routeElement[k].zTopologyId, e->zTopologyId); + duplicate_string(p->routeElement[k].contextId, s->serviceId.contextId); + } + g_free(e); g_free(v); g_free(pathCons); + //DEBUG_PC ("Path is constructed"); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Print the graph for DEBUG_PCging purposes + * + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void print_graph (struct graph_t *g) { + g_assert(g); + DEBUG_PC ("================================================================"); + DEBUG_PC ("=========================== GRAPH =========================="); + DEBUG_PC ("================================================================"); + DEBUG_PC("Graph Num Vertices: %d", g->numVertices); + + for (gint i = 0; i < g->numVertices; i++) { + DEBUG_PC ("Head Vertice [%s]", g->vertices[i].verticeId.nodeId); + for (gint j = 0; j < g->vertices[i].numTargetedVertices; j++) + { + DEBUG_PC (" Tail Vertice: %s", g->vertices[i].targetedVertices[j].tVertice.nodeId); + for (gint k = 0; k < g->vertices[i].targetedVertices[j].numEdges; k++) + { + struct edges_t *e = &(g->vertices[i].targetedVertices[j].edges[k]); + DEBUG_PC ("%s(%s) --> %s(%s) [C: %f, Bw: %f b/s, Delay: %f ms]", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, + e->zEndPointId, e->cost, e->availCap, e->delay); + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Look for a given edge into the graph + * + * @param verticeIndex + * @param targetedVerticeIndex + * @param e + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint graph_edge_lookup (gint verticeIndex, gint targetedVerticeIndex, struct edges_t *e, struct graph_t *g) { + gint indexEdge = -1; + + for (gint j = 0; j < g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex].numEdges; j++) { + struct edges_t *e2 = &(g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex].edges[j]); + if ((compare_node_id (&e->aNodeId, &e2->aNodeId) == 0) && + (compare_node_id (&e->zNodeId, &e2->zNodeId) == 0) && + (strcmp (e->aEndPointId, e2->aEndPointId) == 0) && + (strcmp (e->zEndPointId, e2->zEndPointId) == 0) && + (strcmp(e->linkId, e2->linkId) == 0)) { + DEBUG_PC ("%s (%s) --> %s (%s) [linkId: %s] FOUND in the Graph at index: %d", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, + e->zEndPointId, e->linkId, j); + indexEdge = j; + return indexEdge; + } + } + return indexEdge; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Look for a given vertice within the graph using the nodeId + * + * @param nodeId + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint graph_vertice_lookup (gchar *nodeId, struct graph_t *g) +{ + gint index = -1; + //DEBUG_PC("Searching Node: %s", nodeId); + for (gint i = 0; i < g->numVertices; i++) { + //DEBUG_PC("Checked Graph Node: %s", g->vertices[i].verticeId.nodeId); + if (memcmp (g->vertices[i].verticeId.nodeId, nodeId, strlen (nodeId)) == 0) + { + index = i; + //DEBUG_PC ("%s is found in the graph vertice [%d]", nodeId, index); + break; + } + } + return (index); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Check if a nodeId is already considered into the set of targeted vertices from a given vertice + * + * @param nodeId + * @param vIndex + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint graph_targeted_vertice_lookup (gint vIndex, gchar *nodeId, struct graph_t *g) +{ + gint addedTargetedVerticeIndex = -1; + gint i = 0; + + if (g->vertices[vIndex].numTargetedVertices == 0) + { + return (addedTargetedVerticeIndex); + } + + for (i = 0; i < g->vertices[vIndex].numTargetedVertices; i++) + { + if (memcmp (g->vertices[vIndex].targetedVertices[i].tVertice.nodeId, nodeId, strlen (nodeId)) == 0) + { + DEBUG_PC ("Targeted %s reachable from %s", nodeId, g->vertices[vIndex].verticeId.nodeId); + addedTargetedVerticeIndex = i; + return (addedTargetedVerticeIndex); + } + } + // not found ... + return (addedTargetedVerticeIndex); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Check if a nodeId is already considered into the set of targeted vertices from a given vertice, if not to be added + * + * @param nodeId + * @param vIndex + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint graph_targeted_vertice_add (gint vIndex, gchar *nodeId, struct graph_t *g) +{ + gint addedTargetedVerticeIndex = -1; + gint i = 0; + + if (g->vertices[vIndex].numTargetedVertices == 0) + { + //DEBUG_PC ("targeted vertice %s being reachable from vertice %s", nodeId, g->vertices[vIndex].verticeId.nodeId); + addedTargetedVerticeIndex = 0; + return (addedTargetedVerticeIndex); + } + + for (i = 0; i < g->vertices[vIndex].numTargetedVertices; i++) + { + if (memcmp (g->vertices[vIndex].targetedVertices[i].tVertice.nodeId, nodeId, strlen (nodeId)) == 0) + { + //DEBUG_PC ("Targeted vertice %s is already considered in the reachable from vertice %s", nodeId, g->vertices[vIndex].verticeId.nodeId); + addedTargetedVerticeIndex = -1; + return (addedTargetedVerticeIndex); + } + } + // It is not found, next to be added at i position + addedTargetedVerticeIndex = i; + return (addedTargetedVerticeIndex); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Remove edge from the graph + * + * @param g + * @param e + * + * @author Ricardo Martínez + * @date 2022 + */ +void remove_edge_from_graph (struct graph_t *g, struct edges_t *e) { + // Find the ingress vertice into the graph + DEBUG_PC ("Removing from Graph %s[%s]) ---> %s[%s] (linkId: %s)", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, e->aEndPointId, e->linkId); + gint verticeIndex = -1; + verticeIndex = graph_vertice_lookup (e->aNodeId.nodeId, g); + if (verticeIndex == -1) { + DEBUG_PC ("Edge w/ %s is NOT in the Graph!!", e->aNodeId.nodeId); + return; + } + + // Find the targeted vertice from vertice Id + gint targetedVerticeIndex = -1; + targetedVerticeIndex = graph_targeted_vertice_lookup (verticeIndex, e->zNodeId.nodeId, g); + if (targetedVerticeIndex == -1) { + DEBUG_PC ("%s --> %s NOT in the Graph!!", e->aNodeId.nodeId, e->zNodeId.nodeId); + return; + } + //DEBUG_PC ("%s --> %s found in the Graph", e->aNodeId.nodeId, e->zNodeId.nodeId); + + // Get the edge position + gint edgeIndex = -1; + edgeIndex = graph_edge_lookup (verticeIndex, targetedVerticeIndex, e, g); + if (edgeIndex == -1) { + DEBUG_PC ("%s --> %s NOT in the Graph!!", e->aNodeId.nodeId, e->zNodeId.nodeId); + return; + } + + //DEBUG_PC ("%s --> %s FOUND in Graph w/ edgeIndex: %d", e->aNodeId.nodeId, e->zNodeId.nodeId, edgeIndex); + + // Remove the edge + //DEBUG_PC ("Start Removing %s --> %s from Graph", e->aNodeId.nodeId, e->zNodeId.nodeId); + struct targetNodes_t *v = &(g->vertices[verticeIndex].targetedVertices[targetedVerticeIndex]); + for (gint j = edgeIndex; j < v->numEdges; j++) { + struct edges_t *e1 = &(v->edges[j]); + struct edges_t *e2 = &(v->edges[j+1]); + duplicate_edge (e1, e2); + } + v->numEdges --; + DEBUG_PC ("Number of Edges between %s and %s is %d", e->aNodeId.nodeId, e->zNodeId.nodeId, v->numEdges); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief create the pointer for keeping a set of the paths (struct compRouteOutput_t) + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct path_set_t * create_path_set () { + struct path_set_t * p = g_malloc0 (sizeof (struct path_set_t)); + if (p == NULL) { + DEBUG_PC ("Memory allocation problem"); + exit (-1); + } + return p; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Remove the path set + * + * @param p + * + * @author Ricardo Martínez + * @date 2021 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void remove_path_set(struct path_set_t* p) { + g_assert(p); g_free(p); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Create map of nodes to handle the path computation + * + * @param mapN + * @param g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void build_map_node (struct map_nodes_t *mapN, struct graph_t *g) { + //DEBUG_PC ("Construction of the Map of Nodes"); + for (gint i = 0; i < g->numVertices; i++) { + duplicate_node_id (&g->vertices[i].verticeId, &mapN->map[i].verticeId); + mapN->map[i].distance = INFINITY_COST; + mapN->map[i].avaiBandwidth = 0.0; + mapN->map[i].latency = INFINITY_COST; + mapN->map[i].power = INFINITY_COST; + mapN->numMapNodes++; + } + //DEBUG_PC ("mapNodes formed by %d Nodes", mapN->numMapNodes); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Allocate memory for path of struct compRouteOutputList_t * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct compRouteOutputList_t * create_route_list () { + struct compRouteOutputList_t *p = g_malloc0 (sizeof (struct compRouteOutputList_t)); + if (p == NULL) { + DEBUG_PC ("Memory Allocation Problem"); + exit (-1); + } + return p; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Copy all the attributes defining a path + * + * @param dst_path + * @param src_path + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void copy_path(struct path_t* dst_path, struct path_t* src_path) { + g_assert(dst_path); + g_assert(src_path); + + // Path capacity + dst_path->path_capacity.unit = src_path->path_capacity.unit; + memcpy(&dst_path->path_capacity.value, &src_path->path_capacity.value, sizeof(gdouble)); + + // Path latency + memcpy(&dst_path->path_latency.fixed_latency, &src_path->path_latency.fixed_latency, sizeof(gdouble)); + + // Path cost + duplicate_string(dst_path->path_cost.cost_name, src_path->path_cost.cost_name); + memcpy(&dst_path->path_cost.cost_value, &src_path->path_cost.cost_value, sizeof(gdouble)); + memcpy(&dst_path->path_cost.cost_algorithm, &src_path->path_cost.cost_algorithm, sizeof(gdouble)); + + // Path links + dst_path->numPathLinks = src_path->numPathLinks; + for (gint i = 0; i < dst_path->numPathLinks; i++) { + struct pathLink_t* dPathLink = &(dst_path->pathLinks[i]); + struct pathLink_t* sPathLink = &(src_path->pathLinks[i]); + + duplicate_string(dPathLink->linkId, sPathLink->linkId); + duplicate_string(dPathLink->aDeviceId, sPathLink->aDeviceId); + duplicate_string(dPathLink->zDeviceId, sPathLink->zDeviceId); + duplicate_string(dPathLink->aEndPointId, sPathLink->aEndPointId); + duplicate_string(dPathLink->zEndPointId, sPathLink->zEndPointId); + + duplicate_string(dPathLink->topologyId.contextId, sPathLink->topologyId.contextId); + duplicate_string(dPathLink->topologyId.topology_uuid, sPathLink->topologyId.topology_uuid); + + dPathLink->numLinkTopologies = sPathLink->numLinkTopologies; + for (gint j = 0; j < dPathLink->numLinkTopologies; j++) { + struct linkTopology_t* dLinkTop = &(dPathLink->linkTopologies[j]); + struct linkTopology_t* sLinkTop = &(sPathLink->linkTopologies[j]); + + duplicate_string(dLinkTop->topologyId, sLinkTop->topologyId); + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Duplicate the route output instance + * + * @param dst_ro + * @param src_ro + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_compRouteOuput(struct compRouteOutput_t* dst_ro, struct compRouteOutput_t* src_ro) { + g_assert(dst_ro); g_assert(src_ro); + + // Copy the serviceId + copy_service_id(&dst_ro->serviceId, &src_ro->serviceId); + dst_ro->num_service_endpoints_id = src_ro->num_service_endpoints_id; + + for (gint j = 0; j < dst_ro->num_service_endpoints_id; j++) { + struct service_endpoints_id_t* iEp = &(src_ro->service_endpoints_id[j]); + struct service_endpoints_id_t* oEp = &(dst_ro->service_endpoints_id[j]); + copy_service_endpoint_id(oEp, iEp); + } + + // Copy paths + dst_ro->numPaths = src_ro->numPaths; + for (gint j = 0; j < dst_ro->numPaths; j++) { + struct path_t* dst_path = &(dst_ro->paths[j]); + struct path_t* src_path = &(src_ro->paths[j]); + copy_path(dst_path, src_path); + } + // copy no path issue value + dst_ro->noPathIssue = src_ro->noPathIssue; + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Duplicate the computation route output list + * + * @param dst + * @param src + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_route_list(struct compRouteOutputList_t* dst, struct compRouteOutputList_t* src) { + g_assert(src); g_assert(dst); + + dst->numCompRouteConnList = src->numCompRouteConnList; + dst->compRouteOK = src->compRouteOK; + memcpy(&dst->compRouteConnAvBandwidth, &src->compRouteConnAvBandwidth, sizeof(gdouble)); + memcpy(&dst->compRouteConnAvPathLength, &src->compRouteConnAvPathLength, sizeof(gdouble)); + for (gint i = 0; i < src->numCompRouteConnList; i++) { + struct compRouteOutput_t* src_ro = &(src->compRouteConnection[i]); + struct compRouteOutput_t* dst_ro = &(dst->compRouteConnection[i]); + duplicate_compRouteOuput(dst_ro, src_ro); + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Allocate memory for path of struct compRouteOutputItem_t * + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct compRouteOutputItem_t *create_path_item () { + struct compRouteOutputItem_t *p = g_malloc0 (sizeof (struct compRouteOutputItem_t)); + if (p == NULL) { + DEBUG_PC ("Memory Allocation Problem"); + exit (-1); + } + return p; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Sort the set of paths the AvailBw, Cost and Delay + * + * @params setP + * @params args + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void sort_path_set(struct path_set_t* setP, guint args) { + g_assert(setP); + // Sort the paths contained in setP by: + // 1st Criteria: The path cost (maybe bound to link distance) + // 2nd Criteria: The consumed path power + // 3nd Criteria: The path latency + // 3rd Criteria: The available Bw + float epsilon = 0.1; + + for (gint i = 0; i < setP->numPaths; i++) { + for (gint j = 0; j < (setP->numPaths - i - 1); j++) { + struct compRouteOutputItem_t* path1 = &setP->paths[j]; + struct compRouteOutputItem_t* path2 = &setP->paths[j + 1]; + struct compRouteOutputItem_t* pathTmp = create_path_item(); + //////////////////////// Criterias //////////////////////////////////////// + // 1st Criteria (Cost) + if (path2->cost < path1->cost) { + duplicate_path(path1, pathTmp); + duplicate_path(path2, path1); + duplicate_path(pathTmp, path2); + g_free(pathTmp); + continue; + } + if (path2->cost == path1->cost) { + // 2nd Criteria (Energy) + if (args & ENERGY_EFFICIENT_ARGUMENT) { + if (path2->power < path1->power) { + duplicate_path(path1, pathTmp); + duplicate_path(path2, path1); + duplicate_path(pathTmp, path2); + g_free(pathTmp); + continue; + } + else { // path1->power < path2->power + g_free(pathTmp); + continue; + } + } + else { // No enery efficient argument + // 3rd Criteria (latency) + if (path2->delay < path1->delay) { + duplicate_path(path1, pathTmp); + duplicate_path(path2, path1); + duplicate_path(pathTmp, path2); + g_free(pathTmp); + continue; + } + else if (path1->delay < path2->delay) { + g_free(pathTmp); + continue; + } + else { // path1->delay == path2->delay + // 4th Criteria (available bw) + if (path2->availCap > path1->availCap) { + duplicate_path(path1, pathTmp); + duplicate_path(path2, path1); + duplicate_path(pathTmp, path2); + g_free(pathTmp); + continue; + } + else { + g_free(pathTmp); + continue; + } + } + } + } + else { // path1->cost < path2->cost + g_free(pathTmp); + continue; + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Remove first element from the path sets + * + * @params setP + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void pop_front_path_set (struct path_set_t *setP) { + for (gint j = 0; j < setP->numPaths - 1; j++) { + struct compRouteOutputItem_t *path1 = &setP->paths[j]; + struct compRouteOutputItem_t *path2 = &setP->paths[j+1]; + duplicate_path (path2, path1); + } + setP->numPaths--; + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Add routeElement to the back of the path + * + * @param rE + * @param p + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void add_routeElement_path_back (struct routeElement_t *rE, struct compRouteOutputItem_t *p) { + //DEBUG_PC ("p->numRouteElements: %d", p->numRouteElements); + p->numRouteElements++; + gint index = p->numRouteElements - 1; + + struct nodes_t *pn = &(p->routeElement[index].aNodeId); + struct nodes_t *rEn = &(rE->aNodeId); + + // duplicate aNodeId + duplicate_node_id (rEn, pn); + pn = &(p->routeElement[index].zNodeId); + rEn = &(rE->zNodeId); + duplicate_node_id (rEn, pn); + duplicate_string(p->routeElement[index].aEndPointId, rE->aEndPointId); + duplicate_string(p->routeElement[index].zEndPointId, rE->zEndPointId); + duplicate_string(p->routeElement[index].linkId, rE->linkId); + duplicate_string(p->routeElement[index].aTopologyId, rE->aTopologyId); + duplicate_string(p->routeElement[index].zTopologyId, rE->zTopologyId); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief This function compares ap and rootPath. If all the links are equal between both ap and rootPath till the sN, then the link from sN to next node + * ap is returned + * + * @params ap + * @params p + * @params sN + * @params e + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gboolean matching_path_rootPath (struct compRouteOutputItem_t *ap, struct compRouteOutputItem_t *rootPath, struct nodes_t *sN, struct edges_t *e) { + gint j = 0; + gboolean ret = FALSE; + while ((j < ap->numRouteElements) && (j < rootPath->numRouteElements)) { + if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0) && + //(memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) != 0) && + (memcmp (sN->nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0)) { + duplicate_node_id (&ap->routeElement[j].aNodeId, &e->aNodeId); + duplicate_node_id (&ap->routeElement[j].zNodeId, &e->zNodeId); + duplicate_string(e->aEndPointId, ap->routeElement[j].aEndPointId); + duplicate_string(e->zEndPointId, ap->routeElement[j].zEndPointId); + duplicate_string(e->linkId, ap->routeElement[j].linkId); + return TRUE; + } + if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) == 0) && + (memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) == 0)) { + j++; + continue; + } + + if ((memcmp (ap->routeElement[j].aNodeId.nodeId, rootPath->routeElement[j].aNodeId.nodeId, sizeof (ap->routeElement[j].aNodeId.nodeId)) != 0) || + (memcmp (ap->routeElement[j].zNodeId.nodeId, rootPath->routeElement[j].zNodeId.nodeId, sizeof (ap->routeElement[j].zNodeId.nodeId)) != 0)) { + //DEBUG_PC ("ap and rootPath not in the same path"); + return ret; + } + } + return ret; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief This function is used to modify the graph to be used for running the subsequent SP computations acording to the YEN algorithm principles + * + * @params g + * @params A + * @params rootPath + * @params spurNode + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void modify_targeted_graph (struct graph_t *g, struct path_set_t *A, struct compRouteOutputItem_t * rootPath, struct nodes_t * spurNode) { + //DEBUG_PC ("Modify the Targeted graph according to the Yen algorithm principles"); + for (gint j = 0; j < A->numPaths; j++) { + struct compRouteOutputItem_t *ap = &A->paths[j]; + struct edges_t *e = create_edge(); + gboolean ret = FALSE; + ret = matching_path_rootPath (ap, rootPath, spurNode, e); + if (ret == TRUE) { + DEBUG_PC ("Removal %s[%s] --> %s[%s] from the graph", e->aNodeId.nodeId, e->aEndPointId, e->zNodeId.nodeId, e->aEndPointId); + remove_edge_from_graph (g, e); + //DEBUG_PC ("Print Resulting Graph"); + print_graph (g); + g_free (e); + } + if (ret == FALSE) { + g_free (e); + continue; + } + } + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Supporting fucntion to Check if a nodeId is already in the items of a given GList + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint find_nodeId (gconstpointer data, gconstpointer userdata) +{ + /** check values */ + g_assert(data != NULL); + g_assert(userdata != NULL); + + struct nodeItem_t *SNodeId = (struct nodeItem_t *)data; + guchar * nodeId = (guchar *)userdata; + + //DEBUG_PC ("SNodeId (%s) nodeId (%s)", SNodeId->node.nodeId, nodeId); + + if (!memcmp(SNodeId->node.nodeId, nodeId, strlen (SNodeId->node.nodeId))) + { + return (0); + } + return -1; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Explores the link between u and v + * + * @param u + * @param v + * @param g + * @param s + * @param S + * @param Q + * @param mapNodes + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struct graph_t *g, + struct service_t *s, GList **S, GList **Q, struct map_nodes_t *mapNodes, + guint arg) { + g_assert(g); g_assert(s); g_assert(mapNodes); + + struct targetNodes_t *v = &(g->vertices[indexGraphU].targetedVertices[indexGraphV]); + DEBUG_PC("Explored Link %s => %s)", u->node.nodeId, v->tVertice.nodeId); + //DEBUG_PC("\t %s => %s", u->node.nodeId, v->tVertice.nodeId); + + // v already explored in S? then, discard it + GList *found = g_list_find_custom (*S, v->tVertice.nodeId, find_nodeId); + if (found != NULL) { + DEBUG_PC ("v (%s) in S, Discard", v->tVertice.nodeId); + return 0; + } + + // Get the set of constraints imposed by the service + struct path_constraints_t* path_constraints = get_path_constraints(s); + gdouble distance_through_u = INFINITY_COST ,latency_through_u = INFINITY_COST, power_through_u = INFINITY_COST; + gint i = 0, foundAvailBw = 0; + // BANDWIDTH requirement to be fulfilled on EDGE u->v + gdouble edgeAvailBw = 0.0, edgeTotalBw = 0.0; + for (i = 0; i < v->numEdges; i++) { + struct edges_t *e = &(v->edges[i]); + memcpy (&edgeAvailBw, &(e->availCap), sizeof (gdouble)); + memcpy(&edgeTotalBw, &(e->totalCap), sizeof(gdouble)); + DEBUG_PC("EDGE %s[%s] => %s[%s]", u->node.nodeId, e->aEndPointId, v->tVertice.nodeId, e->zEndPointId); + //DEBUG_PC ("\t %s[%s] =>", u->node.nodeId, e->aEndPointId); + //DEBUG_PC("\t => %s[%s]", v->tVertice.nodeId, e->zEndPointId); + DEBUG_PC("\t AvailBw: %f, TotalBw: %f", edgeAvailBw, edgeTotalBw); + // Check Service Bw constraint + if ((path_constraints->bw == TRUE) && (edgeAvailBw < path_constraints->bwConstraint)) + continue; + else { + foundAvailBw = 1; + break; + } + } + // BW constraint NOT MET, then DISCARD edge + if ((path_constraints->bw == TRUE) && (foundAvailBw == 0)) { + DEBUG_PC ("AvailBw: %f < path_constraint: %f -- Discard Edge", edgeAvailBw, path_constraints->bwConstraint); + g_free(path_constraints); + return 0; + } + + gint indexEdge = i; // get the index for the explored edge + // Update distance, latency and availBw through u to reach v + gint map_uIndex = get_map_index_by_nodeId (u->node.nodeId, mapNodes); + struct map_t *u_map = &mapNodes->map[map_uIndex]; + distance_through_u = u_map->distance + v->edges[indexEdge].cost; + latency_through_u = u_map->latency + v->edges[indexEdge].delay; + // Consumed power at v through u is the sum + // 1. Power from src to u + // 2. Power-idle at node u + // 3. power consumed over the edge between u and v, i.e. energy*usedBw + power_through_u = u_map->power + g->vertices[indexGraphU].power_idle + ((edgeTotalBw - edgeAvailBw + path_constraints->bwConstraint) * (v->edges[indexEdge].energy)); + gdouble availBw_through_u = 0.0; + + // ingress endpoint (u) is the src of the request + if (strcmp (u->node.nodeId, s->service_endpoints_id[0].device_uuid) == 0) { + //DEBUG_PC ("AvailBw %f on %s --> %s", edgeAvailBw, u->node.nodeId, v->tVertice.nodeId); + memcpy (&availBw_through_u, &edgeAvailBw, sizeof (gdouble)); + } + else { + // Get the minimum available bandwidth between the src-->u and the new added edge u-->v + //DEBUG_PC ("Current AvailBw: %f from src to %s", u_map->avaiBandwidth, u->node.nodeId); + //DEBUG_PC ("AvailBw: %f %s --> %s", edgeAvailBw, u->node.nodeId, v->tVertice.nodeId); + if (u_map->avaiBandwidth <= edgeAvailBw) { + memcpy (&availBw_through_u, &u_map->avaiBandwidth, sizeof (gdouble)); + } + else { + memcpy (&availBw_through_u, &edgeAvailBw, sizeof (gdouble)); + } + } + // Relax the link according to the pathCost, latency, and energy + gint map_vIndex = get_map_index_by_nodeId (v->tVertice.nodeId, mapNodes); + struct map_t *v_map = &mapNodes->map[map_vIndex]; + // If cost dist (u, v) > dist (src, v) relax the link + if (distance_through_u > v_map->distance) { + //DEBUG_PC ("dist(src, u) + dist(u, v): %f > dist (src, v): %f --> Discard Link", distance_through_u, v_map->distance); + return 0; + } + // If energy consumption optimization is requested + if (arg & ENERGY_EFFICIENT_ARGUMENT) { + if (distance_through_u == v_map->distance) { + if (power_through_u > v_map->power) { + DEBUG_PC("Energy (src -> u + u -> v: %f (Watts) >Energy (src, v): %f (Watts)--> DISCARD LINK", power_through_u, v_map->power); + return 0; + } + // same energy consumption, consider latency + if ((power_through_u == v_map->power) && (latency_through_u > v_map->latency)) { + return 0; + } + if ((power_through_u == v_map->power) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { + return 0; + } + } + } // No optimization, rely on latency and available e2e bandwidth + else { + // If dist (src, u) + dist (u, v) = current dist(src, v), then use the latency as discarding criteria + if ((distance_through_u == v_map->distance) && (latency_through_u > v_map->latency)) { + //DEBUG_PC ("dist(src, u) + dist(u,v) = current dist(src, v), but latency (src,u) + latency (u, v) > current latency (src, v)"); + return 0; + } + // If dist (src, u) + dist (u,v) == current dist(src, v) AND latency (src, u) + latency (u, v) == current latency (src, v), the available bandwidth is the criteria + if ((distance_through_u == v_map->distance) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { + return 0; + } + } + DEBUG_PC ("%s --> %s Relaxed", u->node.nodeId, v->tVertice.nodeId); + DEBUG_PC ("\t AvailBw: %f Mb/s, Cost: %f, Latency: %f ms, Energy: %f Watts", availBw_through_u, distance_through_u, latency_through_u, power_through_u); + + // Update Q list -- + struct nodeItem_t *nodeItem = g_malloc0 (sizeof (struct nodeItem_t)); + if (nodeItem == NULL) { + DEBUG_PC ("memory allocation failed\n"); + exit (-1); + } + nodeItem->distance = distance_through_u; + memcpy(&nodeItem->distance, &distance_through_u, sizeof(gdouble)); + memcpy(&nodeItem->latency, &latency_through_u, sizeof(gdouble)); + memcpy(&nodeItem->power, &power_through_u, sizeof(gdouble)); + duplicate_node_id (&v->tVertice, &nodeItem->node); + // add node to the Q list + if (arg & ENERGY_EFFICIENT_ARGUMENT) { + *Q = g_list_insert_sorted(*Q, nodeItem, sort_by_energy); + } + else + *Q = g_list_insert_sorted (*Q, nodeItem, sort_by_distance); + + // Update the mapNodes for the specific reached tv + v_map->distance = distance_through_u; + memcpy(&v_map->distance, &distance_through_u, sizeof(gdouble)); + memcpy (&v_map->avaiBandwidth, &availBw_through_u, sizeof (gdouble)); + memcpy (&v_map->latency, &latency_through_u, sizeof (gdouble)); + memcpy(&v_map->power, &power_through_u, sizeof(gdouble)); + // Duplicate the predecessor edge into the mapNodes + struct edges_t *e1 = &(v_map->predecessor); + struct edges_t *e2 = &(v->edges[indexEdge]); + duplicate_edge(e1, e2); + DEBUG_PC ("u->v Edge: %s(%s) --> %s(%s)", e2->aNodeId.nodeId, e2->aEndPointId, e2->zNodeId.nodeId, e2->zEndPointId); + //DEBUG_PC("v-pred aTopology: %s", e2->aTopologyId); + DEBUG_PC("v-pred zTopology: %s", e2->zTopologyId); + + // Check whether v is dstPEId + //DEBUG_PC ("Targeted dstId: %s", s->service_endpoints_id[1].device_uuid); + //DEBUG_PC ("nodeId added to the map: %s", v_map->verticeId.nodeId); + //DEBUG_PC ("Q Length: %d", g_list_length(*Q)); + g_free(path_constraints); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Check the feasability of a path wrt the constraints imposed by the request in terms of latency + * + * @param s + * @param p + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gboolean check_computed_path_feasability (struct service_t *s, struct compRouteOutputItem_t* p) { + float epsilon = 0.0000001; + struct path_constraints_t* pathCons = get_path_constraints(s); + gboolean ret = TRUE; + if (pathCons->latency == TRUE) { + if ((pathCons->latencyConstraint - p->delay > 0.0) || (fabs(pathCons->latencyConstraint - p->delay) < epsilon)) { + DEBUG_PC("Computed Path (latency: %f) is feasible wrt Connection Demand: %f", p->delay, pathCons->latencyConstraint); + } + else { + DEBUG_PC("Computed Path (latency: %f) is NOT feasible wrt Connection Demand: %f", p->delay, pathCons->latencyConstraint); + g_free(pathCons); + return FALSE; + } + } + // Other constraints... + g_free(pathCons); + return ret; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Sorting the GList Q items by distance + * + * @param a + * @param b + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint sort_by_distance (gconstpointer a, gconstpointer b) { + //DEBUG_PC ("sort by distance a and b"); + g_assert(a != NULL); + g_assert(b != NULL); + + //DEBUG_PC ("sort by distance a and b"); + struct nodeItem_t *node1 = (struct nodeItem_t *)a; + struct nodeItem_t *node2 = (struct nodeItem_t *)b; + g_assert (node1); + g_assert (node2); + + //DEBUG_PC ("a->distance %u; b->distance %u", node1->distance, node2->distance); + //DEBUG_PC("a->latency: %f; b->latency: %f", node1->latency, node2->latency); + //1st criteria, sorting by lowest distance + if (node1->distance > node2->distance) + return 1; + else if (node1->distance < node2->distance) + return 0; + if (node1->distance == node2->distance) { + if (node1->latency > node2->latency) + return 1; + else if (node1->latency <= node2->latency) + return 0; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Sorting the GList Q items by distance + * + * @param a + * @param b + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gint sort_by_energy(gconstpointer a, gconstpointer b) { + g_assert(a != NULL); + g_assert(b != NULL); + + //DEBUG_PC ("sort by distance a and b"); + struct nodeItem_t* node1 = (struct nodeItem_t*)a; + struct nodeItem_t* node2 = (struct nodeItem_t*)b; + g_assert(node1); + g_assert(node2); + + //1st criteria: sorting by lowest distance + if (node1->distance > node2->distance) + return 1; + if (node1->distance < node2->distance) + return 0; + + // 2nd Criteria: sorting by the lowest energy + if (node1->power > node2->power) + return 1; + if (node1->power < node1->power) + return 0; + + // 3rd Criteria: by the latency + if (node1->latency > node2->latency) + return 1; + if (node1->latency <= node2->latency) + return 0; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Allocate memory for graph + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct graph_t * create_graph () { + struct graph_t * g = g_malloc0 (sizeof (struct graph_t)); + if (g == NULL) { + DEBUG_PC ("Memory Allocation Problem"); + exit (-1); + } + return g; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Allocate memory for mapNodes + * + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +struct map_nodes_t * create_map_node () { + struct map_nodes_t * mN = g_malloc0 (sizeof (struct map_nodes_t)); + if (mN == NULL) { + DEBUG_PC ("Memory allocation failed"); + exit (-1); + } + return mN; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Look up for the service in the servieList bound to a serviceUUID + * + * @params serviceUUID + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct service_t* get_service_for_computed_path(gchar* serviceUUID) { + gint i = 0; + for(GList *listnode = g_list_first(serviceList); + listnode; + listnode = g_list_next(listnode), i++) { + struct service_t* s = (struct service_t*)(listnode->data); + if (strcmp(s->serviceId.service_uuid, serviceUUID) == 0) + return s; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the service type + * + * @param type + * + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_service_type(guint type) { + switch (type) { + case SERVICE_TYPE_UNKNOWN: + DEBUG_PC("Service Type UNKNOWN"); + break; + case SERVICE_TYPE_L3NM: + DEBUG_PC("Service Type L3NM"); + break; + case SERVICE_TYPE_L2NM: + DEBUG_PC("Service Type L2NM"); + break; + case SERVICE_TYPE_TAPI: + DEBUG_PC("Service Type L2NM"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the port direction + * + * @param direction + * + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_link_port_direction(guint direction) { + switch (direction) { + case LINK_PORT_DIRECTION_BIDIRECTIONAL: + //DEBUG_PC("Bidirectional Port Direction"); + break; + case LINK_PORT_DIRECTION_INPUT: + //DEBUG_PC("Input Port Direction"); + break; + case LINK_PORT_DIRECTION_OUTPUT: + //DEBUG_PC("Output Port Direction"); + break; + case LINK_PORT_DIRECTION_UNKNOWN: + //DEBUG_PC("Unknown Port Direction"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the port termination direction + * + * @param direction + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_termination_direction(guint direction) { + switch (direction) { + case TERMINATION_DIRECTION_BIDIRECTIONAL: + //DEBUG_PC("Bidirectional Termination Direction"); + break; + case TERMINATION_DIRECTION_SINK: + //DEBUG_PC("Input Termination Direction"); + break; + case TERMINATION_DIRECTION_SOURCE: + //DEBUG_PC("Output Termination Direction"); + break; + case TERMINATION_DIRECTION_UNKNOWN: + //DEBUG_PC("Unknown Termination Direction"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the termination state + * + * @param state + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_termination_state(guint state) +{ + switch (state) { + case TERMINATION_STATE_CAN_NEVER_TERMINATE: + //DEBUG_PC("Can never Terminate"); + break; + case TERMINATION_STATE_NOT_TERMINATED: + DEBUG_PC("Not terminated"); + break; + case TERMINATION_STATE_TERMINATED_SERVER_TO_CLIENT_FLOW: + DEBUG_PC("Terminated server to client flow"); + break; + case TERMINATION_STATE_TERMINATED_CLIENT_TO_SERVER_FLOW: + DEBUG_PC("Terminated client to server flow"); + break; + case TERMINATION_STATE_TERMINATED_BIDIRECTIONAL: + //DEBUG_PC("Terminated bidirectional"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the capacity unit + * + * @param unit + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_capacity_unit(guint unit) { + + switch (unit) { + case CAPACITY_UNIT_TB: + DEBUG_PC("Unit in TB"); + break; + case CAPACITY_UNIT_TBPS: + DEBUG_PC("Unit in TB/s"); + break; + case CAPACITY_UNIT_GB: + DEBUG_PC("Unit in GB"); + break; + case CAPACITY_UNIT_GBPS: + DEBUG_PC("Unit in GB/s"); + break; + case CAPACITY_UNIT_MB: + DEBUG_PC("Unit in MB"); + break; + case CAPACITY_UNIT_MBPS: + //DEBUG_PC("Unit in MB/s"); + break; + case CAPACITY_UNIT_KB: + DEBUG_PC("Unit in KB"); + break; + case CAPACITY_UNIT_KBPS: + DEBUG_PC("Unit in KB/s"); + break; + case CAPACITY_UNIT_GHZ: + DEBUG_PC("Unit in GHz"); + break; + case CAPACITY_UNIT_MHZ: + DEBUG_PC("Unit in MHz"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Friendly function to log the link forwarding direction + * + * @param linkFwDir + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_link_forwarding_direction(guint linkFwDir) { + switch (linkFwDir) { + case LINK_FORWARDING_DIRECTION_BIDIRECTIONAL: + DEBUG_PC("BIDIRECTIONAL LINK FORWARDING DIRECTION"); + break; + case LINK_FORWARDING_DIRECTION_UNIDIRECTIONAL: + DEBUG_PC("UNIDIRECTIONAL LINK FORWARDING DIRECTION"); + break; + case LINK_FORWARDING_DIRECTION_UNKNOWN: + DEBUG_PC("UNKNOWN LINK FORWARDING DIRECTION"); + break; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Search a specific contextUuid element into the contextSet + * + * @param contextUuid + * @param set + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct context_t* find_contextId_in_set(gchar* contextUuid, GList** set) { + //DEBUG_PC("Checking if contextId: %s in in the ContextSet??", contextUuid); + gint i = 0; + for (GList *ln = g_list_first(*set); + ln; + ln = g_list_next(ln)){ + struct context_t* c = (struct context_t*)(ln->data); + //DEBUG_PC("Context Item [%d] Id: %s", i, c->contextId); + if (strcmp(contextUuid, c->contextId) == 0) { + //DEBUG_PC("contextId: %s is FOUND in the ContextSet_List", contextUuid); + return c; + } + i++; + } + //DEBUG_PC("contextId: %s NOT FOUND in the ContextSet_List", contextUuid); + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Add a specific context uuid into the context set + * + * @param contextUuid + * @param set + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct context_t* add_contextId_in_set(gchar *contextUuid, GList** set) { + + struct context_t* c = g_malloc0(sizeof(struct context_t)); + if (c == NULL) { + DEBUG_PC("Memory Allocation Failure"); + exit(-1); + } + duplicate_string(c->contextId, contextUuid); + // Add the context into the context set + //DEBUG_PC("Adding ContextId: %s", contextUuid); + //DEBUG_PC(" (BEFORE ADDING) Context Set Length: %d", g_list_length(*set)); + *set = g_list_append(*set, c); + //DEBUG_PC(" (AFTER ADDING) Context Set Length: %d", g_list_length(*set)); + return c; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Find a vertex in a specific graph + * + * @param contextUuid + * @param set + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct vertices_t* find_vertex_in_graph_context(struct graph_t *g, gchar* deviceId) { + for (gint i = 0; i < g->numVertices; i++) { + struct vertices_t* v = &(g->vertices[i]); + if (strcmp(v->verticeId.nodeId, deviceId) == 0) { + return v; + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Adding a deviceId into a graph + * + * @param g + * @param deviceId + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct vertices_t* add_vertex_in_graph(struct graph_t* g, struct device_t *d) { + g->numVertices++; + struct vertices_t* v = &(g->vertices[g->numVertices - 1]); + duplicate_string(v->verticeId.nodeId, d->deviceId); + memcpy(&v->power_idle, &d->power_idle, sizeof(gdouble)); + return v; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Construct the graphs (vertices and edges) bound to every individual context + * + * @param cSet + * @param activeFlag + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void build_contextSet_deviceList(GList** cSet, gint activeFlag) { + // Check every device their endpoints + for (GList* listnode = g_list_first(deviceList); + listnode; + listnode = g_list_next(listnode)) { + struct device_t* d = (struct device_t*)(listnode->data); + //DEBUG_PC("Exploring DeviceId: %s", d->deviceId); + + if ((activeFlag == 1) && (d->operational_status != 2)) { + // it is only considered devices with operational status enabled, i.e., set to 2 + continue; + } + // Check the associated endPoints + for (gint j = 0; j < d->numEndPoints; j++) { + struct endPoint_t* eP = &(d->endPoints[j]); + // Get endPointId (topology, context, device Id and endpoint uuid) + struct endPointId_t* ePid = &(eP->endPointId); //end point id + //DEBUG_PC(" EndPointId: %s || Type: %s", eP->endPointId.endpoint_uuid, d->deviceType); + //DEBUG_PC(" TopologyId: %s || ContextId: %s", eP->endPointId.topology_id.topology_uuid, eP->endPointId.topology_id.contextId); + // Add contextId in ContextSet and the deviceId (+endpoint) into the vertex set + struct context_t *c = find_contextId_in_set(eP->endPointId.topology_id.contextId, cSet); + if (c == NULL) { + DEBUG_PC(" contextUuid: %s MUST BE ADDED to ContextSet", eP->endPointId.topology_id.contextId); + c = add_contextId_in_set(eP->endPointId.topology_id.contextId, cSet); + } + // Check if the deviceId and endPointUuid are already considered in the graph of the context c + struct vertices_t* v = find_vertex_in_graph_context(&c->g, d->deviceId); + if (v == NULL) { + //DEBUG_PC(" deviceId: %s MUST BE ADDED to the Context Graph", d->deviceId); + v = add_vertex_in_graph(&c->g, d); + } + } + } + //print_contextSet(cSet); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Determine whether a deviceId is in the targetNode list of a specific vertex v + * + * @param v + * @param deviceId + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct targetNodes_t* find_targeted_vertex_in_graph_context(struct vertices_t* v, gchar *deviceId) { + for (gint k = 0; k < v->numTargetedVertices; k++) { + struct targetNodes_t* w = &(v->targetedVertices[k]); + if (strcmp(w->tVertice.nodeId, deviceId) == 0) { + return w; + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Add a deviceId a targetNode of a specific vertex v + * + * @param v + * @param deviceId + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct targetNodes_t* add_targeted_vertex_in_graph_context(struct vertices_t* v, gchar* bDeviceId) { + v->numTargetedVertices++; + struct targetNodes_t* w = &(v->targetedVertices[v->numTargetedVertices - 1]); + duplicate_string(w->tVertice.nodeId, bDeviceId); + return w; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Returns the structure of a device endpoint bound to a specific deviceId and endPointId + * + * @param devId + * @param endPointUuid + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct endPoint_t* find_device_tied_endpoint(gchar* devId, gchar* endPointUuid) { + //DEBUG_PC("devId: %s ePId: %s", devId, endPointUuid); + for (GList* ln = g_list_first(deviceList); + ln; + ln = g_list_next(ln)) { + struct device_t* d = (struct device_t*)(ln->data); + if (strcmp(d->deviceId, devId) != 0) { + continue; + } + // Iterate over the endpoints tied to the deviceId + for (gint j = 0; j < d->numEndPoints; j++) { + struct endPoint_t* eP = &(d->endPoints[j]); + //DEBUG_PC("looked endPointId: %s", eP->endPointId.endpoint_uuid); + if (strcmp(eP->endPointId.endpoint_uuid, endPointUuid) == 0) { + return eP; + } + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Adding the edge/linnk in the targetedNodes w list + * + * @param w + * @param l + * @param activeFlag + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void add_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l, gint activeFlag) { + //DEBUG_PC("\t targetedVertex: %s", w->tVertice.nodeId); + + // Check if the activeFlag is 1. If YES, it is only added to the edges as long as the + // associated endPoint is in status ENABLED, i.e., with operational status set to 2 + // Get the endpoints (A and Z) of the link l (assumed P2P) + struct link_endpointId_t* aEndpointId = &(l->linkEndPointId[0]); + struct link_endpointId_t* zEndpointId = &(l->linkEndPointId[1]); + // Get the endPoint Information tied to the device bound to aEndPointId + struct endPoint_t* eP = find_device_tied_endpoint(aEndpointId->deviceId, aEndpointId->endPointId); + if (eP == NULL) { + DEBUG_PC("devId: %s endPointUuid: %s NOT in Device List!!--- Weird", aEndpointId->deviceId, aEndpointId->endPointId); + exit(-1); + } + // Check whether the port in that endPoint (eP) is Active upon the activeFlag being SET + if (activeFlag == 1) { + if (eP->operational_status != 2) // NOT ENABLED, then discard this link + return; + } + + // Add the edge into the graph + w->numEdges++; + struct edges_t* e = &(w->edges[w->numEdges - 1]); + // Copy the link Id UUID + duplicate_string(e->linkId, l->linkId); + duplicate_string(e->aNodeId.nodeId, aEndpointId->deviceId); + duplicate_string(e->aEndPointId, aEndpointId->endPointId); + duplicate_string(e->aTopologyId, aEndpointId->topology_id.topology_uuid); + duplicate_string(e->zNodeId.nodeId, zEndpointId->deviceId); + duplicate_string(e->zEndPointId, zEndpointId->endPointId); + duplicate_string(e->zTopologyId, zEndpointId->topology_id.topology_uuid); + + //Potential(total) and available capacity + e->unit = eP->potential_capacity.unit; + memcpy(&e->totalCap, &eP->potential_capacity.value, sizeof(gdouble)); + memcpy(&e->availCap, &eP->available_capacity.value, sizeof(gdouble)); + // Copy interdomain local/remote Ids + memcpy(e->interDomain_localId, eP->inter_domain_plug_in.inter_domain_plug_in_local_id, + strlen(eP->inter_domain_plug_in.inter_domain_plug_in_local_id)); + memcpy(e->interDomain_remoteId, eP->inter_domain_plug_in.inter_domain_plug_in_remote_id, + strlen(eP->inter_domain_plug_in.inter_domain_plug_in_remote_id)); + // cost value + memcpy(&e->cost, &l->cost_characteristics.cost_value, sizeof(gdouble)); + // latency ms + memcpy(&e->delay, &l->latency_characteristics.fixed_latency, sizeof(gdouble)); + // energy J/bits ~ power + memcpy(&e->energy, &eP->energyConsumption, sizeof(gfloat)); + + //DEBUG_PC("Edge - Total/Available Capacity: %f/%f; Cost: %f; Delay: %f, Energy: %f", eP->potential_capacity.value, eP->available_capacity.value, + // l->cost_characteristics.cost_value, l->latency_characteristics.fixed_latency, l->energy_link); + + //DEBUG_PC("Graph Edge - Total/Available Capacity: %f/%f; Cost: %f; Delay: %f, Energy: %f", e->totalCap, e->availCap, + // e->cost, e->delay, e->energy); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Searching a specific edge/link by the linkId(UUID) + * + * @param w + * @param l + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct edges_t* find_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l) { + for (gint i = 0; i < w->numEdges; i++) { + struct edges_t* e = &(w->edges[i]); + if (strcmp(e->linkId, l->linkId) == 0) { + return e; + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief supporting the construction of the graph per context using the explicit + * contents/info of the link list + * + * @param set + * @param activeFlag + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void build_contextSet_linklList(GList** set, gint activeFlag) { + // for each link in linkList: + // 1st- Retrieve endpoints A --> B feauture (context Id, device Id, endpoint Id) + // 2st - In the graph associated to the contextId, check wheter A (deviceId) is in the vertices list + // o No, this is weird ... exist + // o Yes, get the other link endpoint (i.e., B) and check whether it exists. If NOT add it, considering + // all the attributes; Otherwise, check whether the link is different from existing edges between A and B + gdouble epsilon = 0.1; + gint j = 0; + for (GList* ln = g_list_first(linkList); + ln; + ln = g_list_next(ln)) { + struct link_t* l = (struct link_t*)(ln->data); + j++; + + // link assumed to be P2P A --> B; i.e. 2 endPoints; 1st specifies A and 2nd specifie B + struct link_endpointId_t* aEndpointId = &(l->linkEndPointId[0]); + struct topology_id_t* topologyId = &(aEndpointId->topology_id); + // get the contextId + gchar contextUuid[UUID_CHAR_LENGTH]; + duplicate_string(contextUuid, topologyId->contextId); + DEBUG_PC("Link: %s in ContextId: %s", l->linkId, contextUuid); + + // Check first contextUuid exists in the cSet + //DEBUG_PC("Length of Context: %d", g_list_length(set)); + struct context_t* c = find_contextId_in_set(contextUuid, set); + if (c == NULL) { + DEBUG_PC("ContextId: %s does NOT exist... weird", contextUuid); + exit(-1); + } + + // get the device ID of A + gchar aDeviceId[UUID_CHAR_LENGTH]; + duplicate_string(aDeviceId, aEndpointId->deviceId); + + struct graph_t* g = &(c->g); // get the graph associated to the context c + struct vertices_t* v = find_vertex_in_graph_context(g, aDeviceId); + if (v == NULL) { + DEBUG_PC("%s NOT a VERTEX of contextId: %s ... WEIRD", aDeviceId, contextUuid); + exit(-1); + } + // get the bEndpointId + struct link_endpointId_t* bEndpointId = &(l->linkEndPointId[1]); + gchar bDeviceId[UUID_CHAR_LENGTH]; + duplicate_string(bDeviceId, bEndpointId->deviceId); + DEBUG_PC("[%d] -- Link: %s [%s ==> %s]", j-1, l->linkId, aDeviceId, bDeviceId); + // Check whether device B is in the targeted Vertices from A (i.e., v)? + // If not, add B in the targeted vertices B + create the edge and add it + // If B exist, check whether the explored link/edge is already in the list of edges + struct targetNodes_t* w = find_targeted_vertex_in_graph_context(v, bDeviceId); + if (w == NULL) { + DEBUG_PC("[%s] is PEER of [%s]", bDeviceId, v->verticeId.nodeId); + w = add_targeted_vertex_in_graph_context(v, bDeviceId); + add_edge_in_targetedVertice_set(w, l, activeFlag); + } + else { + // w exists, it is needed to check whether the edge (link) should be added + struct edges_t* e = find_edge_in_targetedVertice_set(w, l); + if (e == NULL) { + // Add the link into the list + add_edge_in_targetedVertice_set(w, l, activeFlag); + } + else { + DEBUG_PC("The link already exists ..."); + continue; + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Create the set of (distinct) contexts with the deviceList and linkList + * + * @param cSet + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void build_contextSet(GList** cSet) { + gint activeFlag = 0; // this means that all the devices/links (regardless they are active or not) are considered + + // devices are tied to contexts, i.e. depending on the contextId of the devices + build_contextSet_deviceList(cSet, activeFlag); + + DEBUG_PC("Length for the Context Set: %d", g_list_length(*cSet)); + + // Once the diverse contexts are created and the devices/endpoints asigned to the + // respective graph tied to each context, it is needed to create the edges + build_contextSet_linklList(cSet, activeFlag); + + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Create the set of (distinct) contexts with the deviceList and linkList with + * operational status active + * + * @param cSet + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void build_contextSet_active(GList** cSet) { + gint activeFlag = 1; // this means that all the devices (regardless they are active or not) are considered + + // devices are tied to contexts, i.e. depending on the contextId of the devices + build_contextSet_deviceList(cSet, activeFlag); + + DEBUG_PC("Length for the Context Set: %d", g_list_length(*cSet)); + + // Once the diverse contexts are created and the devices/endpoints asigned to the + // respective graph tied to each context, it is needed to create the edges + build_contextSet_linklList(cSet, activeFlag); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Print the contents of the ContextIds + * + * @param set + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_contextSet(GList* set) { + + DEBUG_PC("Printing the ContextSet w/ number of Elements: %d", g_list_length(set)); + + for (GList* ln = g_list_first(set); + ln; + ln = g_list_next(ln)) { + struct context_t* c = (struct context_t*)(ln->data); + DEBUG_PC("-------------------------------------------------------------"); + DEBUG_PC(" Context Id: %s", c->contextId); + DEBUG_PC("-------------------------------------------------------------"); + + struct graph_t* g = &(c->g); + for (gint j = 0; j < g->numVertices; j++) { + struct vertices_t* v = &(g->vertices[j]); + DEBUG_PC(" Head Device Id: %s", v->verticeId.nodeId); + for (gint k = 0; k < v->numTargetedVertices; k++) { + struct targetNodes_t* w = &(v->targetedVertices[k]); + DEBUG_PC(" [%d] --- Peer Device Id: %s", k, w->tVertice.nodeId); + for (gint l = 0; l < w->numEdges; l++) { + struct edges_t* e = &(w->edges[l]); + DEBUG_PC(" \t link Id: %s", e->linkId); + DEBUG_PC(" \t aEndPointId: %s", e->aEndPointId); + DEBUG_PC(" \t zEndPointId: %s", e->zEndPointId); + DEBUG_PC(" \t Available Capacity: %f, Latency: %f, Cost: %f", e->availCap, e->delay, e->cost); + DEBUG_PC(" \t aTopologyId: %s", e->aTopologyId); + DEBUG_PC(" \t zTopologyId: %s", e->zTopologyId); + } + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Check whether src and dst PE nodeId of the req are the same + * + * @param r + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +gint same_src_dst_pe_nodeid(struct service_t* s) +{ + // Check that source PE and dst PE are NOT the same, i.e., different ingress and egress endpoints (iEp, eEp) + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); + struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); + + gchar* iEpUUID = iEp->endpoint_uuid; + gchar* eEpUUID = eEp->endpoint_uuid; + gchar* iDevUUID = iEp->device_uuid; + gchar* eDevUUID = eEp->device_uuid; + + // Compare the device uuids + if (strcmp(iDevUUID, eDevUUID) != 0) { + DEBUG_PC("DIFFERENT --- iDevId: %s and eDevId: %s", iDevUUID, eDevUUID); + return 1; + } + // Compare the endpoints (ports) + if (strcmp(iEpUUID, eEpUUID) != 0) { + DEBUG_PC("DIFFERENT --- iEpUUID: %s and eEpUUID: %s", iEpUUID, eEpUUID); + return 1; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Handles issues with the route computation + * + * @param route + * @param s + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void comp_route_connection_issue_handler (struct compRouteOutput_t *path, struct service_t *s) +{ + g_assert(path); g_assert(s); + + // Increase the number of computed routes/paths despite there was an issue to be reported + path->numPaths++; + // Copy the serviceId + copy_service_id(&(path->serviceId), &(s->serviceId)); + + // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) + for (gint i = 0; i < s->num_service_endpoints_id; i++) { + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); + struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); + copy_service_endpoint_id(oEp, iEp); + } + path->num_service_endpoints_id = s->num_service_endpoints_id; + path->noPathIssue = NO_PATH_CONS_ISSUE; + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief released the allocated memory fo compRouteOutputList_t + * + * @param ro + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void destroy_compRouteOutputList (struct compRouteOutputList_t *ro) +{ + g_assert (ro); + g_free (ro); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief creates a copy of the underlying graph + * + * @param originalGraph + * @param destGraph + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void duplicate_graph (struct graph_t *originalGraph, struct graph_t *destGraph) { + g_assert (originalGraph); g_assert (destGraph); + + destGraph->numVertices = originalGraph->numVertices; + for (gint i = 0; i < originalGraph->numVertices; i++) { + struct vertices_t *oVertex = &(originalGraph->vertices[i]); + struct vertices_t *dVertex = &(destGraph->vertices[i]); + dVertex->numTargetedVertices = oVertex->numTargetedVertices; + duplicate_node_id (&oVertex->verticeId, &dVertex->verticeId); + memcpy(&dVertex->power_idle, &oVertex->power_idle, sizeof(gdouble)); + + for (gint j = 0; j < oVertex->numTargetedVertices; j++) { + struct targetNodes_t *oTargetedVertex = &(oVertex->targetedVertices[j]); + struct targetNodes_t *dTargetedVertex = &(dVertex->targetedVertices[j]); + duplicate_node_id (&oTargetedVertex->tVertice, &dTargetedVertex->tVertice); + dTargetedVertex->numEdges = oTargetedVertex->numEdges; + + for (gint k = 0; k < oTargetedVertex->numEdges; k++) { + struct edges_t *oEdge = &(oTargetedVertex->edges[k]); + struct edges_t *dEdge = &(dTargetedVertex->edges[k]); + duplicate_edge (dEdge, oEdge); + } + } + } + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to retrieve from the graph the edge instance associated to the + * pathLink (pL) + * + * @param pL + * @parma g + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct edges_t* get_edge_from_graph_by_linkId(struct pathLink_t* pL, struct graph_t* g) { + g_assert(pL); + g_assert(g); + + for (gint i = 0; i < g->numVertices; i++) { + struct vertices_t* v = &(g->vertices[i]); + for (gint j = 0; j < v->numTargetedVertices; j++) { + struct targetNodes_t* tv = &(v->targetedVertices[j]); + for (gint k = 0; k < tv->numEdges; k++) { + struct edges_t* e = &(tv->edges[k]); + if (strcmp(e->linkId, pL->linkId) == 0) { + return e; + } + } + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to retrieve from the graph the reverse edge (rev_e) associated to an edge (e) + * + * @param e + * @parma g + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +struct edges_t* get_reverse_edge_from_the_graph(struct edges_t* e, struct graph_t* g) { + g_assert(e); + g_assert(g); + + for (gint i = 0; i < g->numVertices; i++) { + struct vertices_t* v = &(g->vertices[i]); + // Check Route Element zNodeId with the v->verticeId + if (compare_node_id(&e->zNodeId, &v->verticeId) != 0) + continue; + // Check Route Element zNodeis with any of reachable targeted vertices from v + gboolean foundTargVert = FALSE; + gint indexTargVert = -1; + for (gint j = 0; j < v->numTargetedVertices; j++) { + struct targetNodes_t* tv = &(v->targetedVertices[j]); + if (compare_node_id(&e->aNodeId, &tv->tVertice) == 0) + { + foundTargVert = TRUE; + indexTargVert = j; + break; + } + } + if (foundTargVert == FALSE) { + continue; + } + + // The targeted vertice is found, then check matching with the endpoints + struct targetNodes_t* tv = &(v->targetedVertices[indexTargVert]); + for (gint k = 0; k < tv->numEdges; k++) { + struct edges_t* rev_e = &(tv->edges[k]); + if ((strcmp(rev_e->aEndPointId, e->zEndPointId) == 0) && + (strcmp(rev_e->zEndPointId, e->aEndPointId) == 0)) { + return rev_e; + } + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to reflect in the graph the assigned/allocated resources contained in the path p + * considering the needs (e.g., bandwidth) of service s + * + * @param p + * @param s + * @parma g + * + * @author Ricardo Martínez + * @date 2022 + */ +///////////////////////////////////////////////////////////////////////////////////////// +void allocate_graph_resources (struct path_t *p, struct service_t *s, struct graph_t *g) +{ + g_assert (p); g_assert (s); g_assert (g); + // Retrieve the requested bw by the service + struct path_constraints_t* pathCons = get_path_constraints(s); + + for (gint i = 0; i < p->numPathLinks; i++) { + struct pathLink_t* pL = &(p->pathLinks[i]); + // get the edge associated to the linkId in the graph + struct edges_t* e = get_edge_from_graph_by_linkId(pL, g); + if (e == NULL) { + DEBUG_PC("The linkId: %s is NOT found in the Graph!!!", pL->linkId); + exit(-1); + } + //Update the availBw in the edge + gdouble resBw = e->availCap - pathCons->bwConstraint; + DEBUG_PC("Updating the Avail Bw @ edge/link: %s", e->linkId); + DEBUG_PC("Initial avaiCap @ e/link: %f, demanded Bw: %f, resulting Avail Bw: %f", e->availCap, pathCons->bwConstraint, resBw); + memcpy(&e->availCap, &resBw, sizeof(gdouble)); + DEBUG_PC("Final e/link avail Bw: %f", e->availCap); + } + g_free(pathCons); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to reflect in the graph the assigned/allocated resources contained in the reverse direction of the path p + * considering the needs (e.g., bandwidth) of service s + * + * @param p + * @param s + * @parma g + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void allocate_graph_reverse_resources(struct path_t* p, struct service_t * s, struct graph_t* g) +{ + g_assert(p); g_assert(s); g_assert(g); + + struct path_constraints_t* pathCons = get_path_constraints(s); + for (gint i = 0; i < p->numPathLinks; i++) { + struct pathLink_t* pL = &(p->pathLinks[i]); + struct edges_t* e = get_edge_from_graph_by_linkId(pL, g); + if (e == NULL) { + DEBUG_PC("The linkId: %s is NOT found in the Graph!!!", pL->linkId); + exit(-1); + } + struct edges_t* rev_e = get_reverse_edge_from_the_graph(e, g); + if (rev_e == NULL) { + DEBUG_PC("the reverse edge of linkId: %s is NOT found in the Graph!!!", pL->linkId); + exit(-1); + } + //Update the availBw in the edge + gdouble resBw = rev_e->availCap - pathCons->bwConstraint; + DEBUG_PC("Updating the Avail Bw @ reverse edge/link: %s", rev_e->linkId); + DEBUG_PC("Initial avaiCap @ reverse edge e/link: %f, demanded Bw: %f, resulting Avail Bw: %f", rev_e->availCap, pathCons->bwConstraint, resBw); + memcpy(&rev_e->availCap, &resBw, sizeof(gdouble)); + DEBUG_PC("Final reverse edge e/link avail Bw: %f", rev_e->availCap); + } + g_free(pathCons); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Function used to printall the computed paths for the requested network connectivity services + * + * @param routeList + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void print_path_connection_list(struct compRouteOutputList_t* routeList) { + g_assert(routeList); + for (gint i = 0; i < routeList->numCompRouteConnList; i++) { + DEBUG_PC("==================== Service instance: %d ===================", i); + struct compRouteOutput_t* rO = &(routeList->compRouteConnection[i]); + DEBUG_PC("num service endpoints: %d", rO->num_service_endpoints_id); + struct serviceId_t* s = &(rO->serviceId); + DEBUG_PC("ContextId: %s, ServiceId: %s", s->contextId, s->service_uuid); + DEBUG_PC("ingress - %s[%s]", rO->service_endpoints_id[0].device_uuid, + rO->service_endpoints_id[0].endpoint_uuid); + DEBUG_PC("egress - %s [%s]", rO->service_endpoints_id[1].device_uuid, + rO->service_endpoints_id[1].endpoint_uuid); + + if (rO->noPathIssue == NO_PATH_CONS_ISSUE) { + DEBUG_PC("NO PATH SUCCESSFULLY COMPUTED"); + continue; + } + // Path + DEBUG_PC("Number of paths: %d", rO->numPaths); + for (gint j = 0; j < rO->numPaths; j++) { + struct path_t* p = &(rO->paths[j]); + print_path_t(p); + } + } + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief update statistics for the path computation operations + * + * @param routeConnList + * @param d + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void update_stats_path_comp(struct compRouteOutputList_t* routeConnList, struct timeval d, gint numSuccesPathComp, gint numPathCompIntents) { + g_assert(routeConnList); + + total_path_comp_time.tv_sec = total_path_comp_time.tv_sec + d.tv_sec; + total_path_comp_time.tv_usec = total_path_comp_time.tv_usec + d.tv_usec; + total_path_comp_time = tv_adjust(total_path_comp_time); + + gdouble path_comp_time_msec = (((total_path_comp_time.tv_sec) * 1000) + ((total_path_comp_time.tv_usec) / 1000)); + gdouble av_alg_comp_time = ((path_comp_time_msec / numSuccesPathComp)); + DEBUG_PC("\t --- STATS PATH COMP ----"); + DEBUG_PC("Succesfully Comp: %d | Path Comp Requests: %d", numSuccesPathComp, numPathCompIntents); + DEBUG_PC("AV. PATH COMP ALG. TIME: %f ms", av_alg_comp_time); + + gint i = 0; + for (GList* listnode = g_list_first(serviceList); + listnode; + listnode = g_list_next(listnode), i++) { + struct service_t* s = (struct service_t*)(listnode->data); + char* eptr; + for (gint j = 0; j < s->num_service_constraints; j++) { + struct constraint_t* constraints = &(s->constraints[j]); + if (strncmp((const char*)(constraints->constraint_type), "bandwidth", 9) == 0) { + totalReqBw += (gdouble)(strtod((char*)constraints->constraint_value, &eptr)); + } + } + } + + for (gint k = 0; k < routeConnList->numCompRouteConnList; k++) { + struct compRouteOutput_t* rO = &(routeConnList->compRouteConnection[k]); + if (rO->noPathIssue == NO_PATH_CONS_ISSUE) { + continue; + } + // Get the requested service bw bound to that computed path + struct path_t* p = &(rO->paths[0]); + struct service_t* s = get_service_for_computed_path(rO->serviceId.service_uuid); + if (s == NULL) { + DEBUG_PC("Weird the service associated to a path is not found"); + exit(-1); + } + for (gint l = 0; l < s->num_service_constraints; l++) { + struct constraint_t* constraints = &(s->constraints[l]); + char* eptr; + if (strncmp((const char*)(constraints->constraint_type), "bandwidth", 9) == 0) { + totalServedBw += (gdouble)(strtod((char*)constraints->constraint_value, &eptr)); + } + } + } + gdouble avServedRatio = totalServedBw / totalReqBw; + DEBUG_PC("AV. Served Ratio: %f", avServedRatio); + gdouble avBlockedBwRatio = (gdouble)(1.0 - avServedRatio); + DEBUG_PC("AV. BBE: %f", avBlockedBwRatio); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate active service path + * + * @param actServPath + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_active_service_path(struct activeServPath_t* actServPath) { + g_assert(actServPath); + g_free(actServPath); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate active service + * + * @param actService + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_active_service(struct activeService_t* actService) { + g_assert(actService); + g_list_free_full(g_steal_pointer(&actService->activeServPath), (GDestroyNotify)destroy_active_service_path); + g_free(actService); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate a requested service + * + * @param s + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_requested_service(struct service_t* s) { + g_assert(s); + g_free(s); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate a device + * + * @param d + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_device(struct device_t* d) { + g_assert(d); + g_free(d); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate a link from the linkList + * + * @param d + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_link(struct link_t* l) { + g_assert(l); + g_free(l); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Eliminate a context from the contextSet + * + * @param d + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void destroy_context(struct context_t* c) { + g_assert(c); + g_free(c); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief Excecution Dijkstra algorithm + * + * @param srcMapIndex + * @param dstMapIndex + * @param g + * @param s + * @param mapNodes + * @param SN + * @param RP + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void dijkstra(gint srcMapIndex, gint dstMapIndex, struct graph_t* g, struct service_t* s, + struct map_nodes_t* mapNodes, struct nodes_t* SN, struct compRouteOutputItem_t* RP, + guint arg) { + g_assert(s);g_assert(g); + + // Set params into mapNodes related to the source nodes of the request + mapNodes->map[srcMapIndex].distance = 0.0; + mapNodes->map[srcMapIndex].latency = 0.0; + mapNodes->map[srcMapIndex].avaiBandwidth = 0.0; + mapNodes->map[srcMapIndex].power = 0.0; + + // Initialize the set Q and S + GList *S = NULL, *Q = NULL; + gint indexVertice = -1; + + // Add the source into the Q + struct nodeItem_t* nodeItem = g_malloc0(sizeof(struct nodeItem_t)); + if (nodeItem == NULL) { + DEBUG_PC("memory allocation failed\n"); + exit(-1); + } + // initialize some nodeItem attributes + nodeItem->distance = 0.0; + nodeItem->latency = 0.0; + nodeItem->power = 0.0; + duplicate_node_id(&mapNodes->map[srcMapIndex].verticeId, &nodeItem->node); + + // Select the optimization process + if (arg & ENERGY_EFFICIENT_ARGUMENT) + Q = g_list_insert_sorted(Q, nodeItem, sort_by_energy); + // more "if" according to different optimization criteria ... + else + Q = g_list_insert_sorted(Q, nodeItem, sort_by_distance); + + // Check whether there is spurNode (SN) and rootPath (RP) + if (SN != NULL && RP != NULL) { + struct routeElement_t* re; + for (gint j = 0; j < RP->numRouteElements; j++) { + // Get the source and target Nodes of the routeElement within the rootPath + re = &RP->routeElement[j]; + DEBUG_PC("root Link: aNodeId: %s (%s) --> zNodeiId: %s (%s)", re->aNodeId.nodeId, re->aEndPointId, re->zNodeId.nodeId, re->zEndPointId); + + // if ingress of the root link (aNodeId) is the spurNode, then stops + if (compare_node_id(&re->aNodeId, SN) == 0) { + DEBUG_PC("root Link: aNodeId: %s and spurNode: %s -- stop exploring the rootPath (RP)", re->aNodeId.nodeId, SN->nodeId); + break; + } + // Extract from Q + GList* listnode = g_list_first(Q); + struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); + Q = g_list_remove(Q, node); + + //DEBUG_RL_RA ("Exploring node %s", node->node.nodeId); + indexVertice = graph_vertice_lookup(node->node.nodeId, g); + g_assert(indexVertice >= 0); + + // Get the indexTargetedVertice + gint indexTVertice = -1; + indexTVertice = graph_targeted_vertice_lookup(indexVertice, re->zNodeId.nodeId, g); + gint done = check_link(node, indexVertice, indexTVertice, g, s, &S, &Q, mapNodes, arg); + (void)done; + // Add to the S list + S = g_list_append(S, node); + } + // Check that the first node in Q set is SpurNode, otherwise something went wrong ... + if (compare_node_id(&re->aNodeId, SN) != 0) { + //DEBUG_PC ("root Link: aNodeId: %s is NOT the spurNode: %s -- something wrong", re->aNodeId.nodeId, SN->nodeId); + g_list_free_full(g_steal_pointer(&S), g_free); + g_list_free_full(g_steal_pointer(&Q), g_free); + return; + } + } + + while (g_list_length(Q) > 0) { + //Extract from Q set + GList* listnode = g_list_first(Q); + struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); + Q = g_list_remove(Q, node); + DEBUG_PC("Q length: %d", g_list_length(Q)); + DEBUG_PC("DeviceId: %s", node->node.nodeId); + + // visit all the links from u within the graph + indexVertice = graph_vertice_lookup(node->node.nodeId, g); + g_assert(indexVertice >= 0); + + // Check the targeted vertices from u + for (gint i = 0; i < g->vertices[indexVertice].numTargetedVertices; i++) { + gint done = check_link(node, indexVertice, i, g, s, &S, &Q, mapNodes, arg); + (void)done; + } + // Add node into the S Set + S = g_list_append(S, node); + //DEBUG_PC ("S length: %d", g_list_length (S)); + } + g_list_free_full(g_steal_pointer(&S), g_free); + g_list_free_full(g_steal_pointer(&Q), g_free); + return; +} + +/////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief KSP computation using Dijkstra algorithm + * + * @param pred + * @param g + * @param s + * @param SN + * @param RP + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +gint ksp_comp(struct pred_t* pred, struct graph_t* g, struct service_t* s, + struct nodes_t* SN, struct compRouteOutputItem_t* RP, + struct map_nodes_t* mapNodes, guint arg) { + g_assert(pred); g_assert(g); g_assert(s); + + DEBUG_PC("Source: %s -- Destination: %s", s->service_endpoints_id[0].device_uuid, s->service_endpoints_id[1].device_uuid); + + // Check the both ingress src and dst endpoints are in the graph + gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); + if (srcMapIndex == -1) { + DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); + return -1; + } + + gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); + if (dstMapIndex == -1) { + DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); + return -1; + } + + //DEBUG_PC("srcMapIndex: %d (node: %s)", srcMapIndex, mapNodes->map[srcMapIndex].verticeId.nodeId); + //DEBUG_PC("dstMapIndex: %d (node: %s)", dstMapIndex, mapNodes->map[dstMapIndex].verticeId.nodeId); + + // Compute the shortest path route + dijkstra(srcMapIndex, dstMapIndex, g, s, mapNodes, SN, RP, arg); + + // Check that a feasible solution in term of latency and bandwidth is found + gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); + struct map_t* dest_map = &mapNodes->map[map_dstIndex]; + if (!(dest_map->distance < INFINITY_COST)) { + DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); + return -1; + } + + DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); + // Check that the computed available bandwidth is larger than 0.0 + if (dest_map->avaiBandwidth <= (gfloat)0.0) { + DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); + return -1; + } + DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); + // Handle predecessors + build_predecessors(pred, s, mapNodes); + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief set the path parameters (e.g., latency, cost, power, ...) to an under-constructed + * path from the computed map vertex + * + * @param p + * @param mapV + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void set_path_attributes(struct compRouteOutputItem_t* p, struct map_t* mapV) { + g_assert(p); g_assert(mapV); + memcpy(&p->cost, &mapV->distance, sizeof(gdouble)); + memcpy(&p->availCap, &mapV->avaiBandwidth, sizeof(mapV->avaiBandwidth)); + memcpy(&p->delay, &mapV->latency, sizeof(mapV->latency)); + memcpy(&p->power, &mapV->power, sizeof(gdouble)); + return; +} + +//////////////////////////////////////////////////////////////////////////////////////// +/** + * @file pathComp_tools.c + * @brief K-CSPF algorithm execution (YEN algorithm) + * + * @param s + * @param path + * @param g + * @param optimization_flag + * + * @author Ricardo Martínez + * @date 2022 + */ + ///////////////////////////////////////////////////////////////////////////////////////// +void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g, guint arg) { + g_assert(s); g_assert(path); g_assert(g); + + // create map of devices/nodes to handle the path computation using the context + struct map_nodes_t* mapNodes = create_map_node(); + build_map_node(mapNodes, g); + + // predecessors to store the computed path + struct pred_t* predecessors = create_predecessors(); + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); + struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); + + // Compute the 1st KSP path + gint done = ksp_comp(predecessors, g, s, NULL, NULL, mapNodes, arg); + if (done == -1) { + DEBUG_PC("NO PATH for %s[%s] --> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); + comp_route_connection_issue_handler(path, s); + g_free(mapNodes); g_free(predecessors); + return; + } + + // Construct the path from the computed predecessors + struct compRouteOutputItem_t* p = create_path_item(); + //print_predecessors(predecessors); + build_path(p, predecessors, s); + gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); + struct map_t* dst_map = &mapNodes->map[indexDest]; + // Get the delay and cost + set_path_attributes(p, dst_map); + + // Add the computed path, it may be a not feasible path, but at the end it is + // checked all the feasible paths, and select the first one + print_path(p); + + // Copy the serviceId + copy_service_id(&path->serviceId, &s->serviceId); + // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) + for (gint i = 0; i < s->num_service_endpoints_id; i++) { + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[i]); + struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[i]); + copy_service_endpoint_id(oEp, iEp); + } + path->num_service_endpoints_id = s->num_service_endpoints_id; + + DEBUG_PC("COMPUTE UP TO K Feasible Paths A[%d]", MAX_KSP_VALUE); + // Create A and B sets of paths to handle the YEN algorithm + struct path_set_t *A = create_path_set(), *B = create_path_set(); + // Add 1st Computed path into A->paths[0] + duplicate_path(p, &A->paths[0]); + A->numPaths++; + g_free(predecessors); g_free(p); + for (gint k = 1; k < MAX_KSP_VALUE; k++) { + DEBUG_PC("*************************** kth (%d) ***********************************", k); + struct compRouteOutputItem_t* p = create_path_item(); + duplicate_path(&A->paths[k - 1], p); + // The spurNode ranges from near-end node of the first link to the near-end of the last link forming the kth path + gint i = 0; + struct compRouteOutputItem_t* rootPath = create_path_item(); + for (i = 0; i < p->numRouteElements; i++) { + struct nodes_t *spurNode = create_node(), *nextSpurNode = create_node(); + struct routeElement_t* re = &(p->routeElement[i]); + // Create predecessors to store the computed path + struct pred_t* predecessors = create_predecessors(); + // Clear previous mapNodes, i.e. create it again + g_free(mapNodes); + mapNodes = create_map_node(); + build_map_node(mapNodes, g); + struct nodes_t* n = &re->aNodeId; + duplicate_node_id(n, spurNode); + n = &re->zNodeId; + duplicate_node_id(n, nextSpurNode); + DEBUG_PC("spurNode: %s --> nextSpurNode: %s", spurNode->nodeId, nextSpurNode->nodeId); + + // rootPath contains a set of links of A[k-1] from the source Node till the SpurNode -> NextSpurNode + // Example: A[k-1] = {L1, L2, L3, L4}, i.e. " Node_a -- L1 --> Node_b -- L2 --> Node_c -- L3 --> Node_d -- L4 --> Node_e " + // E.g., for the ith iteration if the spurNode = Node_c and NextSpurNode = Node_d; then rootPath = {L1, L2, L3} + add_routeElement_path_back(re, rootPath); + DEBUG_PC("\n"); + DEBUG_PC("^^^^^^^rootPath^^^^^^^"); + print_path(rootPath); + + // For all existing and computed paths p in A check if from the source to the NextSpurNode + // the set of links matches with those contained in the rootPath + // If YES, remove from the auxiliary graph the next link in p from NextSpurNode + // Otherwise do nothing + struct graph_t* gAux = create_graph(); + duplicate_graph(g, gAux); + // Modified graph + modify_targeted_graph(gAux, A, rootPath, spurNode); + + // Trigger the computation of the path from src to dst constrained to traverse all the links from src + // to spurNode contained into rootPath over the resulting graph + if (ksp_comp(predecessors, gAux, s, spurNode, rootPath, mapNodes, arg) == -1) { + DEBUG_PC("FAILED SP from %s via spurNode: %s to %s", iEp->device_uuid, spurNode->nodeId, eEp->device_uuid); + g_free(nextSpurNode); g_free(spurNode); + g_free(gAux); g_free(predecessors); + continue; + } + DEBUG_PC("SUCCESFUL SP from %s via spurNode: %s to %s", iEp->device_uuid, spurNode->nodeId, eEp->device_uuid); + // Create the node list from the predecessors + struct compRouteOutputItem_t* newKpath = create_path_item(); + build_path(newKpath, predecessors, s); + DEBUG_PC("new K (for k: %d) Path is built", k); + gint indexDest = get_map_index_by_nodeId(eEp->device_uuid, mapNodes); + struct map_t* dst_map = &mapNodes->map[indexDest]; + set_path_attributes(newKpath, dst_map); + DEBUG_PC("New PATH (@ kth: %d) ADDED to B[%d] - {Path Cost: %f, e2e latency: %f, bw: %f, Power: %f ", k, B->numPaths, newKpath->cost, + newKpath->delay, newKpath->availCap, newKpath->power); + // Add the computed kth SP to the heap B + duplicate_path(newKpath, &B->paths[B->numPaths]); + B->numPaths++; + DEBUG_PC("Number of B paths: %d", B->numPaths); + + g_free(newKpath); g_free(nextSpurNode); g_free(spurNode); + g_free(gAux); g_free(predecessors); + } + // If B is empty then stops + if (B->numPaths == 0) { + DEBUG_PC("B does not have any path ... the stops kth computation"); + break; + } + + // Sort the potential B paths according to different optimization parameters + sort_path_set(B, arg); + // Add the lowest path into A[k] + DEBUG_PC("-------------------------------------------------------------"); + DEBUG_PC("Append SP for B[0] to A[%d] --- Cost: %f, Latency: %f, Power: %f", A->numPaths, B->paths[0].cost, + B->paths[0].delay, B->paths[0].power); + duplicate_path(&B->paths[0], &A->paths[A->numPaths]); + A->numPaths++; + DEBUG_PC("A Set size: %d", A->numPaths); + DEBUG_PC("-------------------------------------------------------------"); + + // Remove/Pop front element from the path set B (i.e. remove B[0]) + pop_front_path_set(B); + DEBUG_PC("B Set Size: %d", B->numPaths); + } + + // Copy the serviceId + copy_service_id(&path->serviceId, &s->serviceId); + // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) + for (gint m = 0; m < s->num_service_endpoints_id; m++) { + struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[m]); + struct service_endpoints_id_t* oEp = &(s->service_endpoints_id[m]); + copy_service_endpoint_id(oEp, iEp); + } + + // Print all the paths i A + for (gint h = 0; h < A->numPaths; h++) { + DEBUG_PC("================== A[%d] =======================", h); + print_path(&A->paths[h]); + } + DEBUG_PC("Number of paths: %d", path->numPaths); + // For all the computed paths in A, pick the one being feasible wrt the service constraints + for (gint ksp = 0; ksp < A->numPaths; ksp++) { + if (ksp >= MAX_KSP_VALUE) { + DEBUG_PC("Number Requested paths (%d) REACHED - STOP", ksp); + break; + } + gdouble feasibleRoute = check_computed_path_feasability(s, &A->paths[ksp]); + if (feasibleRoute == TRUE) { + DEBUG_PC("A[%d] available: %f, pathCost: %f; latency: %f, Power: %f", ksp, A->paths[ksp].availCap, A->paths[ksp].cost, A->paths[ksp].delay, A->paths[ksp].power); + struct compRouteOutputItem_t* pathaux = &A->paths[ksp]; + path->numPaths++; + struct path_t* targetedPath = &path->paths[path->numPaths - 1]; + duplicate_path_t(pathaux, targetedPath); + print_path_t(targetedPath); + remove_path_set(A); + remove_path_set(B); + return; + } + } + remove_path_set(A); + remove_path_set(B); + // No paths found --> Issue + DEBUG_PC("K-SP failed!!!"); + comp_route_connection_issue_handler(path, s); + return; } \ No newline at end of file diff --git a/src/pathcomp/backend/pathComp_tools.h b/src/pathcomp/backend/pathComp_tools.h index ce78f009b..041d42019 100644 --- a/src/pathcomp/backend/pathComp_tools.h +++ b/src/pathcomp/backend/pathComp_tools.h @@ -1,624 +1,624 @@ -//////////////////////////////////////////////////////////////////////////////////////// -/** - * # Copyright 2022 Centre Tecnol�gic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es - * - * 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. - - * Author: CTTC/CERCA PONS RU Ricardo Mart�nez (ricardo.martinez@cttc.es) - */ -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef _PATHCOMP_TOOLS_H -#define _PATHCOMP_TOOLS_H - -#include -#include -#include -#include - -// External variables -extern GList* contextSet; -extern GList* linkList; -extern GList* deviceList; -extern GList* serviceList; -extern GList* activeServList; - -////////////////////////////////////////////////////////// -// Optimization computation argument -////////////////////////////////////////////////////////// -#define NO_OPTIMIZATION_ARGUMENT 0x00000000 -#define ENERGY_EFFICIENT_ARGUMENT 0x00000001 - -#define INFINITY_COST 0xFFFFFFFF -#define MAX_NUM_PRED 100 - -#define MAX_KSP_VALUE 3 - -// HTTP RETURN CODES -#define HTTP_CODE_OK 200 -#define HTTP_CODE_CREATED 201 -#define HTTP_CODE_BAD_REQUEST 400 -#define HTTP_CODE_UNAUTHORIZED 401 -#define HTTP_CODE_FORBIDDEN 403 -#define HTTP_CODE_NOT_FOUND 404 -#define HTTP_CODE_NOT_ACCEPTABLE 406 - -#define MAX_NODE_ID_SIZE 37 // UUID 128 Bits - In hexadecimal requires 36 char -#define MAX_CONTEXT_ID 37 -//#define UUID_CHAR_LENGTH 37 -#define UUID_CHAR_LENGTH 100 -struct nodes_t { - gchar nodeId[UUID_CHAR_LENGTH]; -}; - -struct nodeItem_t { - struct nodes_t node; - gdouble distance; // traversed distance - gdouble latency; // incured latency - gdouble power; //consumed power -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Structures for collecting the RL topology including: intra WAN topology and inter-WAN links -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define MAX_INTER_DOMAIN_PLUG_IN_SIZE 128 -struct edges_t { - //aNodeId/Device Id - struct nodes_t aNodeId; - //zNodeId/Device Id - struct nodes_t zNodeId; - - // UUID of the endPointIds - gchar aEndPointId[UUID_CHAR_LENGTH]; - gchar zEndPointId[UUID_CHAR_LENGTH]; - - // UUID of the link - gchar linkId[UUID_CHAR_LENGTH]; - - // Potential(total) and available capacity - gint unit; - gdouble totalCap, availCap; - - gdouble cost; - gdouble delay; - gdouble energy; - - // inter-domain local and remote Ids - gchar interDomain_localId[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; - gchar interDomain_remoteId[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; - - gchar aTopologyId[UUID_CHAR_LENGTH]; - gchar zTopologyId[UUID_CHAR_LENGTH]; -}; - -// Structure to handle the path computation -struct pred_comp_t { - struct nodes_t v; - struct edges_t e; -}; - -struct pred_t { - struct pred_comp_t predComp[MAX_NUM_PRED]; - gint numPredComp; -}; - -// Structures for the managing the path computation algorithm -struct map_t { - struct nodes_t verticeId; - struct edges_t predecessor; - gdouble distance; - gdouble avaiBandwidth; - gdouble latency; - gdouble power; -}; - -#define MAX_MAP_NODE_SIZE 100 -struct map_nodes_t { - struct map_t map[MAX_MAP_NODE_SIZE]; - gint numMapNodes; -}; - -#define MAX_NUM_VERTICES 20 // 100 # LGR: reduced from 100 to 20 to divide by 5 the memory used -#define MAX_NUM_EDGES 10 // 100 # LGR: reduced from 100 to 10 to divide by 10 the memory used -// Structures for the graph composition -struct targetNodes_t { - // remote / targeted node - struct nodes_t tVertice; - // edge conencting a pair of vertices - struct edges_t edges[MAX_NUM_EDGES]; - gint numEdges; -}; - -struct vertices_t { - struct targetNodes_t targetedVertices[MAX_NUM_VERTICES]; - gint numTargetedVertices; - struct nodes_t verticeId; - gdouble power_idle; // power idle of the device (due to the fans, etc.) -}; - -struct graph_t { - struct vertices_t vertices[MAX_NUM_VERTICES]; - gint numVertices; -}; - -//////////////////////////////////////////////////// -// Structure for the Set of Contexts -/////////////////////////////////////////////////// -struct context_t { - gchar contextId[UUID_CHAR_LENGTH]; // UUID char format 36 chars - // conext Id has a graph associated - struct graph_t g; -}; - -#define MAX_ALG_ID_LENGTH 10 -//////////////////////////////////////////////////// -// External Variables -/////////////////////////////////////////////////// -extern gchar algId[MAX_ALG_ID_LENGTH]; - -//////////////////////////////////////////////////// -// Structure for the Requested Transport Connectivity Services -/////////////////////////////////////////////////// -#define SERVICE_TYPE_UNKNOWN 0 -#define SERVICE_TYPE_L3NM 1 -#define SERVICE_TYPE_L2NM 2 -#define SERVICE_TYPE_TAPI 3 - -/////////////////////////////////////////////////////////////////// -// Structure for the topology_id -/////////////////////////////////////////////////////////////////// -struct topology_id_t { - gchar contextId[UUID_CHAR_LENGTH]; - gchar topology_uuid[UUID_CHAR_LENGTH]; -}; - -struct inter_domain_plug_in_t { - gchar inter_domain_plug_in_local_id[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; - gchar inter_domain_plug_in_remote_id[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the endPointId -/////////////////////////////////////////////////////////////////// -struct endPointId_t { - struct topology_id_t topology_id; - gchar device_id[UUID_CHAR_LENGTH]; - gchar endpoint_uuid[UUID_CHAR_LENGTH]; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the endPoint -/////////////////////////////////////////////////////////////////// -#define CAPACITY_UNIT_TB 0 -#define CAPACITY_UNIT_TBPS 1 -#define CAPACITY_UNIT_GB 2 -#define CAPACITY_UNIT_GBPS 3 -#define CAPACITY_UNIT_MB 4 -#define CAPACITY_UNIT_MBPS 5 -#define CAPACITY_UNIT_KB 6 -#define CAPACITY_UNIT_KBPS 7 -#define CAPACITY_UNIT_GHZ 8 -#define CAPACITY_UNIT_MHZ 9 -struct capacity_t { - gdouble value; - gint unit; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the endPoint -/////////////////////////////////////////////////////////////////// -#define MAX_ENDPOINT_TYPE_SIZE 128 -// Link Port Direction -#define LINK_PORT_DIRECTION_BIDIRECTIONAL 0 -#define LINK_PORT_DIRECTION_INPUT 1 -#define LINK_PORT_DIRECTION_OUTPUT 2 -#define LINK_PORT_DIRECTION_UNKNOWN 3 -// Termination Direction -#define TERMINATION_DIRECTION_BIDIRECTIONAL 0 -#define TERMINATION_DIRECTION_SINK 1 -#define TERMINATION_DIRECTION_SOURCE 2 -#define TERMINATION_DIRECTION_UNKNOWN 3 -// Termination State -#define TERMINATION_STATE_CAN_NEVER_TERMINATE 0 -#define TERMINATION_STATE_NOT_TERMINATED 1 -#define TERMINATION_STATE_TERMINATED_SERVER_TO_CLIENT_FLOW 2 -#define TERMINATION_STATE_TERMINATED_CLIENT_TO_SERVER_FLOW 3 -#define TERMINATION_STATE_TERMINATED_BIDIRECTIONAL 4 - -struct endPoint_t { - struct endPointId_t endPointId; - gchar endpointType[MAX_ENDPOINT_TYPE_SIZE]; - guint link_port_direction; - guint termination_direction; - guint termination_state; - struct capacity_t potential_capacity; - struct capacity_t available_capacity; - // inter-domain identifiers - struct inter_domain_plug_in_t inter_domain_plug_in; - gfloat energyConsumption; // in nJ/bit - gint operational_status; // 0 Undefined, 1 Disabled, 2 Enabled -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the device contents -/////////////////////////////////////////////////////////////////// -#define MAX_DEV_TYPE_SIZE 128 -#define MAX_DEV_ENDPOINT_LENGTH 10 -struct device_t { - gdouble power_idle; // power idle (baseline) of the switch in Watts - gint operational_status; // 0 - Undefined, 1 - Disabled, 2 - Enabled - gchar deviceId[UUID_CHAR_LENGTH]; // device ID using UUID (128 bits) - gchar deviceType[MAX_DEV_TYPE_SIZE]; // Specifies the device type - // define the endpoints attached to the device - gint numEndPoints; - struct endPoint_t endPoints[MAX_DEV_ENDPOINT_LENGTH]; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the link EndPoint Id -/////////////////////////////////////////////////////////////////// -struct link_endpointId_t { - struct topology_id_t topology_id; - gchar deviceId[UUID_CHAR_LENGTH]; // Device UUID - gchar endPointId[UUID_CHAR_LENGTH]; // Link EndPoint UUID -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the link cost characteristics -/////////////////////////////////////////////////////////////////// -#define LINK_COST_NAME_SIZE 128 -struct cost_characteristics_t { - gchar cost_name[LINK_COST_NAME_SIZE]; - gdouble cost_value; - gdouble cost_algorithm; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the latency characteristics of the link -/////////////////////////////////////////////////////////////////// -struct latency_characteristics_t { - gdouble fixed_latency; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the latency characteristics of the link -/////////////////////////////////////////////////////////////////// -struct power_characteristics_t { - gdouble power; -}; - -/////////////////////////////////////////////////////////////////// -// Structure for the link -/////////////////////////////////////////////////////////////////// -#define MAX_NUM_LINK_ENDPOINT_IDS 2 - -#define LINK_FORWARDING_DIRECTION_BIDIRECTIONAL 0 -#define LINK_FORWARDING_DIRECTION_UNIDIRECTIONAL 1 -#define LINK_FORWARDING_DIRECTION_UNKNOWN 2 -struct link_t { - gchar linkId[UUID_CHAR_LENGTH]; // link Id using UUID (128 bits) - //gdouble energy_link; // in nJ/bit - //gint operational_status; // 0 Undefined, 1 Disabled, 2 Enabled - gint numLinkEndPointIds; - struct link_endpointId_t linkEndPointId[MAX_NUM_LINK_ENDPOINT_IDS]; - guint forwarding_direction; - struct capacity_t potential_capacity; - struct capacity_t available_capacity; - struct cost_characteristics_t cost_characteristics; - struct latency_characteristics_t latency_characteristics; -}; - -//////////////////////////////////////////////////// -// Structure for service Identifier -/////////////////////////////////////////////////// -struct serviceId_t { - gchar contextId[UUID_CHAR_LENGTH]; - gchar service_uuid[UUID_CHAR_LENGTH]; -}; - -//////////////////////////////////////////////////// -// Structure the service endpoint ids -/////////////////////////////////////////////////// -struct service_endpoints_id_t { - struct topology_id_t topology_id; - gchar device_uuid[UUID_CHAR_LENGTH]; - gchar endpoint_uuid[UUID_CHAR_LENGTH]; -}; - -//////////////////////////////////////////////////// -// Structure for handling generic targeted service constraints -//////////////////////////////////////////////////// -#define MAX_CONSTRAINT_SIZE 128 -// Constraint Type: bandwidth, latency, energy, cost -struct constraint_t { - gchar constraint_type[MAX_CONSTRAINT_SIZE]; - gchar constraint_value[MAX_CONSTRAINT_SIZE]; -}; - -//////////////////////////////////////////////////// -// Structure for individual service request -//////////////////////////////////////////////////// -#define SERVICE_TYPE_UNKNOWN 0 -#define SERVICE_TYPE_L3NM 1 -#define SERVICE_TYPE_L2NM 2 -#define SERVICE_TYPE_TAPI 3 - -#define MAX_NUM_SERVICE_ENPOINTS_ID 2 - -#define MAX_NUM_SERVICE_CONSTRAINTS 10 -struct service_t { - // Indentifier used to determine the used Algorithm Id, e.g., KSP - gchar algId[MAX_ALG_ID_LENGTH]; - // PATHS expected for the output - guint kPaths; - - struct serviceId_t serviceId; - guint service_type; // unknown, l2nm, l3nm, tapi - - // endpoints of the network connectivity service, assumed p2p - // the 1st one assumed to be the source (ingress) and the 2nd one is the sink (egress) - struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; - guint num_service_endpoints_id; - - // Service Constraints - struct constraint_t constraints[MAX_NUM_SERVICE_CONSTRAINTS]; - guint num_service_constraints; -}; - -//////////////////////////////////////////////////// -// Structure to handle path constraints during computation -//////////////////////////////////////////////////// -struct path_constraints_t { - gdouble bwConstraint; - gboolean bw; - - gdouble costConstraint; - gboolean cost; - - gdouble latencyConstraint; - gboolean latency; - - gdouble energyConstraint; - gboolean energy; -}; - -//////////////////////////////////////////////////// -// Structure for the handling the service requests -/////////////////////////////////////////////////// -//#define MAX_SERVICE_LIST 100 -//struct serviceList_t { -// struct service_t services[MAX_SERVICE_LIST]; -// gint numServiceList; -//}; - -//////////////////////////////////////////////////// -// Structure for the handling the active services -/////////////////////////////////////////////////// -struct activeServPath_t { - struct topology_id_t topology_id; - gchar deviceId[UUID_CHAR_LENGTH]; - gchar endPointId[UUID_CHAR_LENGTH]; -}; - -struct activeService_t { - struct serviceId_t serviceId; - guint service_type; // unknown, l2nm, l3nm, tapi - struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; - guint num_service_endpoints_id; - GList* activeServPath; -}; - -//////////////////////////////////////////////////////////////////////////////////////////// -// Structure describing the links forming a computed path -//////////////////////////////////////////////////////////////////////////////////////////// -struct linkTopology_t { - gchar topologyId[UUID_CHAR_LENGTH]; -}; - -struct pathLink_t { - gchar linkId[UUID_CHAR_LENGTH]; // link id UUID in char format - - gchar aDeviceId[UUID_CHAR_LENGTH]; - gchar zDeviceId[UUID_CHAR_LENGTH]; - gchar aEndPointId[UUID_CHAR_LENGTH]; - gchar zEndPointId[UUID_CHAR_LENGTH]; - - struct topology_id_t topologyId; - struct linkTopology_t linkTopologies[2]; // a p2p link (at most) can connect to devices (endpoints) attached to 2 different topologies - gint numLinkTopologies; -}; - -//////////////////////////////////////////////////////////////////////////////////////////// -// Structure describing a computed path -//////////////////////////////////////////////////////////////////////////////////////////// -#define MAX_ROUTE_ELEMENTS 50 -struct routeElement_t { - //aNodeId/Device Id - struct nodes_t aNodeId; - //zNodeId/Device Id - struct nodes_t zNodeId; - - // UUID of the endPointIds - gchar aEndPointId[UUID_CHAR_LENGTH]; - gchar zEndPointId[UUID_CHAR_LENGTH]; - - // UUID of the link - gchar linkId[UUID_CHAR_LENGTH]; - - gchar aTopologyId[UUID_CHAR_LENGTH]; - gchar zTopologyId[UUID_CHAR_LENGTH]; - - // contextId - gchar contextId[UUID_CHAR_LENGTH]; -}; - -struct compRouteOutputItem_t { - gint unit; - gdouble totalCap, availCap; - - gdouble cost; - gdouble delay; - gdouble power; - - struct routeElement_t routeElement[MAX_ROUTE_ELEMENTS]; - gint numRouteElements; -}; - -#define MAX_NUM_PATHS 30 -struct path_set_t { - struct compRouteOutputItem_t paths[MAX_NUM_PATHS]; - gint numPaths; -}; - -#define MAX_NUM_PATH_LINKS 20 -struct path_t { - struct capacity_t path_capacity; - struct latency_characteristics_t path_latency; - struct cost_characteristics_t path_cost; - struct power_characteristics_t path_power; - - struct pathLink_t pathLinks[MAX_NUM_PATH_LINKS]; - guint numPathLinks; -}; - -#define NO_PATH_CONS_ISSUE 1 // No path due to a constraint issue -#define MAX_NUM_COMPUTED_PATHS 10 -struct compRouteOutput_t { - // object describing the service identifier: serviceId and contextId - struct serviceId_t serviceId; - // array describing the service endpoints ids - struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; - guint num_service_endpoints_id; - struct path_t paths[MAX_NUM_COMPUTED_PATHS]; - gint numPaths; - // if the transport connectivity service cannot be computed, this value is set to 0 determining the constraints were not fulfilled - gint noPathIssue; -}; - -//////////////////////////////////////////////////////////////////////////////////////////// -// Structure to handle the response list with all the computed network connectivity services -//////////////////////////////////////////////////////////////////////////////////////////// -#define MAX_COMP_CONN_LIST 100 -struct compRouteOutputList_t { - struct compRouteOutput_t compRouteConnection[MAX_COMP_CONN_LIST]; - gint numCompRouteConnList; - - ///////////////// Metrics ////////////////////////////////////////// - // Number of total succesfully computed connections, i.e., at least 1 feasible path exists - // for every connection in the list - gint compRouteOK; - // For the succesfully newly computed/recovered/re-allocated/re-optimized connections, this - // metric determines the average allocable bandwidth over all the (re-)computed paths for the succesfully - // (i.e., feasible path) connections - gdouble compRouteConnAvBandwidth; - // For the succesfully newly computed/recovered/re-allocated/re-optimized connections, this - // metric determines the average path length (in terms of number of hops) over the computed path for the - // succesfully (i.e., feasible path) connections - gdouble compRouteConnAvPathLength; -}; - -// Prototype of external declaration of functions -void print_path (struct compRouteOutputItem_t *); -void print_path_t(struct path_t*); -struct path_t* create_path(); - -void duplicate_string(gchar *, gchar *); - -gchar* get_uuid_char(uuid_t); -void copy_service_id(struct serviceId_t*, struct serviceId_t *); -void copy_service_endpoint_id(struct service_endpoints_id_t *, struct service_endpoints_id_t *); - -struct graph_t* get_graph_by_contextId(GList*, gchar *); - -struct pred_t * create_predecessors (); -struct edges_t* create_edge(); -void print_predecessors (struct pred_t *); -void build_predecessors (struct pred_t *, struct service_t *, struct map_nodes_t *); -struct nodes_t * create_node (); -struct routeElement_t * create_routeElement (); - -void duplicate_node_id (struct nodes_t *, struct nodes_t *); -gint compare_node_id (struct nodes_t *, struct nodes_t *); -void duplicate_routeElement (struct routeElement_t *, struct routeElement_t *); -void duplicate_edge (struct edges_t *, struct edges_t *); -void duplicate_path (struct compRouteOutputItem_t *, struct compRouteOutputItem_t *); -void duplicate_path_t(struct compRouteOutputItem_t *, struct path_t *); -gint get_map_index_by_nodeId (gchar *, struct map_nodes_t *); -void get_edge_from_map_by_node (struct edges_t *, struct nodes_t*, struct map_nodes_t *); -void get_edge_from_predecessors (struct edges_t *, struct nodes_t*, struct pred_t *); -void build_path (struct compRouteOutputItem_t *, struct pred_t *, struct service_t *); -void print_graph (struct graph_t *); - -gint graph_vertice_lookup (gchar *, struct graph_t *); -gint graph_targeted_vertice_lookup (gint, gchar *, struct graph_t *); -gint graph_targeted_vertice_add (gint, gchar *, struct graph_t *); - -void remove_edge_from_graph (struct graph_t *, struct edges_t *); - -struct path_set_t * create_path_set (); -void sort_path_set (struct path_set_t *, guint); -void pop_front_path_set (struct path_set_t *); -void remove_path_set(struct path_set_t*); - -void build_map_node(struct map_nodes_t *, struct graph_t *); -struct compRouteOutputList_t * create_route_list(); -void duplicate_route_list(struct compRouteOutputList_t *, struct compRouteOutputList_t *); -struct compRouteOutputItem_t * create_path_item (); -void add_routeElement_path_back (struct routeElement_t *, struct compRouteOutputItem_t *); -gboolean matching_path_rootPath (struct compRouteOutputItem_t *, struct compRouteOutputItem_t *, struct nodes_t *, struct edges_t *); -void modify_targeted_graph (struct graph_t *, struct path_set_t *, struct compRouteOutputItem_t *, struct nodes_t *); -gint find_nodeId (gconstpointer, gconstpointer); -gint check_link (struct nodeItem_t *, gint, gint, struct graph_t *, struct service_t *, GList **, GList **, struct map_nodes_t *, guint arg); -gboolean check_computed_path_feasability (struct service_t *, struct compRouteOutputItem_t * ); - -gint sort_by_distance (gconstpointer, gconstpointer); -gint sort_by_energy(gconstpointer, gconstpointer); - -struct graph_t * create_graph (); -struct map_nodes_t * create_map_node (); - -struct service_t * get_service_for_computed_path(gchar *); - -void print_service_type(guint); -void print_link_port_direction(guint); -void print_termination_direction(guint); -void print_termination_state(guint); -void print_capacity_unit(guint); -void print_link_forwarding_direction(guint); - -void build_contextSet(GList **); -void build_contextSet_active(GList **); -void print_contextSet(GList *); - -gint same_src_dst_pe_nodeid (struct service_t *); -void comp_route_connection_issue_handler (struct compRouteOutput_t *, struct service_t *); - -void destroy_compRouteOutputList (struct compRouteOutputList_t *); -void duplicate_graph (struct graph_t *, struct graph_t *); - -void allocate_graph_resources (struct path_t *, struct service_t *, struct graph_t *); -void allocate_graph_reverse_resources(struct path_t*, struct service_t *, struct graph_t *); -void print_route_solution_list (GList *); -struct timeval tv_adjust(struct timeval); - -void print_path_connection_list(struct compRouteOutputList_t*); -void update_stats_path_comp(struct compRouteOutputList_t*, struct timeval, gint, gint); -void destroy_active_service(struct activeService_t*); -void destroy_requested_service(struct service_t*); -void destroy_device(struct device_t*); -void destroy_link(struct link_t*); -void destroy_context(struct context_t*); -void dijkstra(gint, gint, struct graph_t*, struct service_t*, struct map_nodes_t*, struct nodes_t*, struct compRouteOutputItem_t*, guint); -void set_path_attributes(struct compRouteOutputItem_t*, struct map_t*); -void alg_comp(struct service_t*, struct compRouteOutput_t*, struct graph_t*, guint); +//////////////////////////////////////////////////////////////////////////////////////// +/** + * # Copyright 2022 Centre Tecnol�gic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es + * + * 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. + + * Author: CTTC/CERCA PONS RU Ricardo Mart�nez (ricardo.martinez@cttc.es) + */ +///////////////////////////////////////////////////////////////////////////////////////// + +#ifndef _PATHCOMP_TOOLS_H +#define _PATHCOMP_TOOLS_H + +#include +#include +#include +#include + +// External variables +extern GList* contextSet; +extern GList* linkList; +extern GList* deviceList; +extern GList* serviceList; +extern GList* activeServList; + +////////////////////////////////////////////////////////// +// Optimization computation argument +////////////////////////////////////////////////////////// +#define NO_OPTIMIZATION_ARGUMENT 0x00000000 +#define ENERGY_EFFICIENT_ARGUMENT 0x00000001 + +#define INFINITY_COST 0xFFFFFFFF +#define MAX_NUM_PRED 100 + +#define MAX_KSP_VALUE 3 + +// HTTP RETURN CODES +#define HTTP_CODE_OK 200 +#define HTTP_CODE_CREATED 201 +#define HTTP_CODE_BAD_REQUEST 400 +#define HTTP_CODE_UNAUTHORIZED 401 +#define HTTP_CODE_FORBIDDEN 403 +#define HTTP_CODE_NOT_FOUND 404 +#define HTTP_CODE_NOT_ACCEPTABLE 406 + +#define MAX_NODE_ID_SIZE 37 // UUID 128 Bits - In hexadecimal requires 36 char +#define MAX_CONTEXT_ID 37 +//#define UUID_CHAR_LENGTH 37 +#define UUID_CHAR_LENGTH 100 +struct nodes_t { + gchar nodeId[UUID_CHAR_LENGTH]; +}; + +struct nodeItem_t { + struct nodes_t node; + gdouble distance; // traversed distance + gdouble latency; // incured latency + gdouble power; //consumed power +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Structures for collecting the RL topology including: intra WAN topology and inter-WAN links +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define MAX_INTER_DOMAIN_PLUG_IN_SIZE 128 +struct edges_t { + //aNodeId/Device Id + struct nodes_t aNodeId; + //zNodeId/Device Id + struct nodes_t zNodeId; + + // UUID of the endPointIds + gchar aEndPointId[UUID_CHAR_LENGTH]; + gchar zEndPointId[UUID_CHAR_LENGTH]; + + // UUID of the link + gchar linkId[UUID_CHAR_LENGTH]; + + // Potential(total) and available capacity + gint unit; + gdouble totalCap, availCap; + + gdouble cost; + gdouble delay; + gdouble energy; + + // inter-domain local and remote Ids + gchar interDomain_localId[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; + gchar interDomain_remoteId[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; + + gchar aTopologyId[UUID_CHAR_LENGTH]; + gchar zTopologyId[UUID_CHAR_LENGTH]; +}; + +// Structure to handle the path computation +struct pred_comp_t { + struct nodes_t v; + struct edges_t e; +}; + +struct pred_t { + struct pred_comp_t predComp[MAX_NUM_PRED]; + gint numPredComp; +}; + +// Structures for the managing the path computation algorithm +struct map_t { + struct nodes_t verticeId; + struct edges_t predecessor; + gdouble distance; + gdouble avaiBandwidth; + gdouble latency; + gdouble power; +}; + +#define MAX_MAP_NODE_SIZE 100 +struct map_nodes_t { + struct map_t map[MAX_MAP_NODE_SIZE]; + gint numMapNodes; +}; + +#define MAX_NUM_VERTICES 20 // 100 # LGR: reduced from 100 to 20 to divide by 5 the memory used +#define MAX_NUM_EDGES 10 // 100 # LGR: reduced from 100 to 10 to divide by 10 the memory used +// Structures for the graph composition +struct targetNodes_t { + // remote / targeted node + struct nodes_t tVertice; + // edge conencting a pair of vertices + struct edges_t edges[MAX_NUM_EDGES]; + gint numEdges; +}; + +struct vertices_t { + struct targetNodes_t targetedVertices[MAX_NUM_VERTICES]; + gint numTargetedVertices; + struct nodes_t verticeId; + gdouble power_idle; // power idle of the device (due to the fans, etc.) +}; + +struct graph_t { + struct vertices_t vertices[MAX_NUM_VERTICES]; + gint numVertices; +}; + +//////////////////////////////////////////////////// +// Structure for the Set of Contexts +/////////////////////////////////////////////////// +struct context_t { + gchar contextId[UUID_CHAR_LENGTH]; // UUID char format 36 chars + // conext Id has a graph associated + struct graph_t g; +}; + +#define MAX_ALG_ID_LENGTH 10 +//////////////////////////////////////////////////// +// External Variables +/////////////////////////////////////////////////// +extern gchar algId[MAX_ALG_ID_LENGTH]; + +//////////////////////////////////////////////////// +// Structure for the Requested Transport Connectivity Services +/////////////////////////////////////////////////// +#define SERVICE_TYPE_UNKNOWN 0 +#define SERVICE_TYPE_L3NM 1 +#define SERVICE_TYPE_L2NM 2 +#define SERVICE_TYPE_TAPI 3 + +/////////////////////////////////////////////////////////////////// +// Structure for the topology_id +/////////////////////////////////////////////////////////////////// +struct topology_id_t { + gchar contextId[UUID_CHAR_LENGTH]; + gchar topology_uuid[UUID_CHAR_LENGTH]; +}; + +struct inter_domain_plug_in_t { + gchar inter_domain_plug_in_local_id[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; + gchar inter_domain_plug_in_remote_id[MAX_INTER_DOMAIN_PLUG_IN_SIZE]; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the endPointId +/////////////////////////////////////////////////////////////////// +struct endPointId_t { + struct topology_id_t topology_id; + gchar device_id[UUID_CHAR_LENGTH]; + gchar endpoint_uuid[UUID_CHAR_LENGTH]; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the endPoint +/////////////////////////////////////////////////////////////////// +#define CAPACITY_UNIT_TB 0 +#define CAPACITY_UNIT_TBPS 1 +#define CAPACITY_UNIT_GB 2 +#define CAPACITY_UNIT_GBPS 3 +#define CAPACITY_UNIT_MB 4 +#define CAPACITY_UNIT_MBPS 5 +#define CAPACITY_UNIT_KB 6 +#define CAPACITY_UNIT_KBPS 7 +#define CAPACITY_UNIT_GHZ 8 +#define CAPACITY_UNIT_MHZ 9 +struct capacity_t { + gdouble value; + gint unit; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the endPoint +/////////////////////////////////////////////////////////////////// +#define MAX_ENDPOINT_TYPE_SIZE 128 +// Link Port Direction +#define LINK_PORT_DIRECTION_BIDIRECTIONAL 0 +#define LINK_PORT_DIRECTION_INPUT 1 +#define LINK_PORT_DIRECTION_OUTPUT 2 +#define LINK_PORT_DIRECTION_UNKNOWN 3 +// Termination Direction +#define TERMINATION_DIRECTION_BIDIRECTIONAL 0 +#define TERMINATION_DIRECTION_SINK 1 +#define TERMINATION_DIRECTION_SOURCE 2 +#define TERMINATION_DIRECTION_UNKNOWN 3 +// Termination State +#define TERMINATION_STATE_CAN_NEVER_TERMINATE 0 +#define TERMINATION_STATE_NOT_TERMINATED 1 +#define TERMINATION_STATE_TERMINATED_SERVER_TO_CLIENT_FLOW 2 +#define TERMINATION_STATE_TERMINATED_CLIENT_TO_SERVER_FLOW 3 +#define TERMINATION_STATE_TERMINATED_BIDIRECTIONAL 4 + +struct endPoint_t { + struct endPointId_t endPointId; + gchar endpointType[MAX_ENDPOINT_TYPE_SIZE]; + guint link_port_direction; + guint termination_direction; + guint termination_state; + struct capacity_t potential_capacity; + struct capacity_t available_capacity; + // inter-domain identifiers + struct inter_domain_plug_in_t inter_domain_plug_in; + gfloat energyConsumption; // in nJ/bit + gint operational_status; // 0 Undefined, 1 Disabled, 2 Enabled +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the device contents +/////////////////////////////////////////////////////////////////// +#define MAX_DEV_TYPE_SIZE 128 +#define MAX_DEV_ENDPOINT_LENGTH 10 +struct device_t { + gdouble power_idle; // power idle (baseline) of the switch in Watts + gint operational_status; // 0 - Undefined, 1 - Disabled, 2 - Enabled + gchar deviceId[UUID_CHAR_LENGTH]; // device ID using UUID (128 bits) + gchar deviceType[MAX_DEV_TYPE_SIZE]; // Specifies the device type + // define the endpoints attached to the device + gint numEndPoints; + struct endPoint_t endPoints[MAX_DEV_ENDPOINT_LENGTH]; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the link EndPoint Id +/////////////////////////////////////////////////////////////////// +struct link_endpointId_t { + struct topology_id_t topology_id; + gchar deviceId[UUID_CHAR_LENGTH]; // Device UUID + gchar endPointId[UUID_CHAR_LENGTH]; // Link EndPoint UUID +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the link cost characteristics +/////////////////////////////////////////////////////////////////// +#define LINK_COST_NAME_SIZE 128 +struct cost_characteristics_t { + gchar cost_name[LINK_COST_NAME_SIZE]; + gdouble cost_value; + gdouble cost_algorithm; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the latency characteristics of the link +/////////////////////////////////////////////////////////////////// +struct latency_characteristics_t { + gdouble fixed_latency; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the latency characteristics of the link +/////////////////////////////////////////////////////////////////// +struct power_characteristics_t { + gdouble power; +}; + +/////////////////////////////////////////////////////////////////// +// Structure for the link +/////////////////////////////////////////////////////////////////// +#define MAX_NUM_LINK_ENDPOINT_IDS 2 + +#define LINK_FORWARDING_DIRECTION_BIDIRECTIONAL 0 +#define LINK_FORWARDING_DIRECTION_UNIDIRECTIONAL 1 +#define LINK_FORWARDING_DIRECTION_UNKNOWN 2 +struct link_t { + gchar linkId[UUID_CHAR_LENGTH]; // link Id using UUID (128 bits) + //gdouble energy_link; // in nJ/bit + //gint operational_status; // 0 Undefined, 1 Disabled, 2 Enabled + gint numLinkEndPointIds; + struct link_endpointId_t linkEndPointId[MAX_NUM_LINK_ENDPOINT_IDS]; + guint forwarding_direction; + struct capacity_t potential_capacity; + struct capacity_t available_capacity; + struct cost_characteristics_t cost_characteristics; + struct latency_characteristics_t latency_characteristics; +}; + +//////////////////////////////////////////////////// +// Structure for service Identifier +/////////////////////////////////////////////////// +struct serviceId_t { + gchar contextId[UUID_CHAR_LENGTH]; + gchar service_uuid[UUID_CHAR_LENGTH]; +}; + +//////////////////////////////////////////////////// +// Structure the service endpoint ids +/////////////////////////////////////////////////// +struct service_endpoints_id_t { + struct topology_id_t topology_id; + gchar device_uuid[UUID_CHAR_LENGTH]; + gchar endpoint_uuid[UUID_CHAR_LENGTH]; +}; + +//////////////////////////////////////////////////// +// Structure for handling generic targeted service constraints +//////////////////////////////////////////////////// +#define MAX_CONSTRAINT_SIZE 128 +// Constraint Type: bandwidth, latency, energy, cost +struct constraint_t { + gchar constraint_type[MAX_CONSTRAINT_SIZE]; + gchar constraint_value[MAX_CONSTRAINT_SIZE]; +}; + +//////////////////////////////////////////////////// +// Structure for individual service request +//////////////////////////////////////////////////// +#define SERVICE_TYPE_UNKNOWN 0 +#define SERVICE_TYPE_L3NM 1 +#define SERVICE_TYPE_L2NM 2 +#define SERVICE_TYPE_TAPI 3 + +#define MAX_NUM_SERVICE_ENPOINTS_ID 2 + +#define MAX_NUM_SERVICE_CONSTRAINTS 10 +struct service_t { + // Indentifier used to determine the used Algorithm Id, e.g., KSP + gchar algId[MAX_ALG_ID_LENGTH]; + // PATHS expected for the output + guint kPaths; + + struct serviceId_t serviceId; + guint service_type; // unknown, l2nm, l3nm, tapi + + // endpoints of the network connectivity service, assumed p2p + // the 1st one assumed to be the source (ingress) and the 2nd one is the sink (egress) + struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; + guint num_service_endpoints_id; + + // Service Constraints + struct constraint_t constraints[MAX_NUM_SERVICE_CONSTRAINTS]; + guint num_service_constraints; +}; + +//////////////////////////////////////////////////// +// Structure to handle path constraints during computation +//////////////////////////////////////////////////// +struct path_constraints_t { + gdouble bwConstraint; + gboolean bw; + + gdouble costConstraint; + gboolean cost; + + gdouble latencyConstraint; + gboolean latency; + + gdouble energyConstraint; + gboolean energy; +}; + +//////////////////////////////////////////////////// +// Structure for the handling the service requests +/////////////////////////////////////////////////// +//#define MAX_SERVICE_LIST 100 +//struct serviceList_t { +// struct service_t services[MAX_SERVICE_LIST]; +// gint numServiceList; +//}; + +//////////////////////////////////////////////////// +// Structure for the handling the active services +/////////////////////////////////////////////////// +struct activeServPath_t { + struct topology_id_t topology_id; + gchar deviceId[UUID_CHAR_LENGTH]; + gchar endPointId[UUID_CHAR_LENGTH]; +}; + +struct activeService_t { + struct serviceId_t serviceId; + guint service_type; // unknown, l2nm, l3nm, tapi + struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; + guint num_service_endpoints_id; + GList* activeServPath; +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Structure describing the links forming a computed path +//////////////////////////////////////////////////////////////////////////////////////////// +struct linkTopology_t { + gchar topologyId[UUID_CHAR_LENGTH]; +}; + +struct pathLink_t { + gchar linkId[UUID_CHAR_LENGTH]; // link id UUID in char format + + gchar aDeviceId[UUID_CHAR_LENGTH]; + gchar zDeviceId[UUID_CHAR_LENGTH]; + gchar aEndPointId[UUID_CHAR_LENGTH]; + gchar zEndPointId[UUID_CHAR_LENGTH]; + + struct topology_id_t topologyId; + struct linkTopology_t linkTopologies[2]; // a p2p link (at most) can connect to devices (endpoints) attached to 2 different topologies + gint numLinkTopologies; +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Structure describing a computed path +//////////////////////////////////////////////////////////////////////////////////////////// +#define MAX_ROUTE_ELEMENTS 50 +struct routeElement_t { + //aNodeId/Device Id + struct nodes_t aNodeId; + //zNodeId/Device Id + struct nodes_t zNodeId; + + // UUID of the endPointIds + gchar aEndPointId[UUID_CHAR_LENGTH]; + gchar zEndPointId[UUID_CHAR_LENGTH]; + + // UUID of the link + gchar linkId[UUID_CHAR_LENGTH]; + + gchar aTopologyId[UUID_CHAR_LENGTH]; + gchar zTopologyId[UUID_CHAR_LENGTH]; + + // contextId + gchar contextId[UUID_CHAR_LENGTH]; +}; + +struct compRouteOutputItem_t { + gint unit; + gdouble totalCap, availCap; + + gdouble cost; + gdouble delay; + gdouble power; + + struct routeElement_t routeElement[MAX_ROUTE_ELEMENTS]; + gint numRouteElements; +}; + +#define MAX_NUM_PATHS 30 +struct path_set_t { + struct compRouteOutputItem_t paths[MAX_NUM_PATHS]; + gint numPaths; +}; + +#define MAX_NUM_PATH_LINKS 20 +struct path_t { + struct capacity_t path_capacity; + struct latency_characteristics_t path_latency; + struct cost_characteristics_t path_cost; + struct power_characteristics_t path_power; + + struct pathLink_t pathLinks[MAX_NUM_PATH_LINKS]; + guint numPathLinks; +}; + +#define NO_PATH_CONS_ISSUE 1 // No path due to a constraint issue +#define MAX_NUM_COMPUTED_PATHS 10 +struct compRouteOutput_t { + // object describing the service identifier: serviceId and contextId + struct serviceId_t serviceId; + // array describing the service endpoints ids + struct service_endpoints_id_t service_endpoints_id[MAX_NUM_SERVICE_ENPOINTS_ID]; + guint num_service_endpoints_id; + struct path_t paths[MAX_NUM_COMPUTED_PATHS]; + gint numPaths; + // if the transport connectivity service cannot be computed, this value is set to 0 determining the constraints were not fulfilled + gint noPathIssue; +}; + +//////////////////////////////////////////////////////////////////////////////////////////// +// Structure to handle the response list with all the computed network connectivity services +//////////////////////////////////////////////////////////////////////////////////////////// +#define MAX_COMP_CONN_LIST 100 +struct compRouteOutputList_t { + struct compRouteOutput_t compRouteConnection[MAX_COMP_CONN_LIST]; + gint numCompRouteConnList; + + ///////////////// Metrics ////////////////////////////////////////// + // Number of total succesfully computed connections, i.e., at least 1 feasible path exists + // for every connection in the list + gint compRouteOK; + // For the succesfully newly computed/recovered/re-allocated/re-optimized connections, this + // metric determines the average allocable bandwidth over all the (re-)computed paths for the succesfully + // (i.e., feasible path) connections + gdouble compRouteConnAvBandwidth; + // For the succesfully newly computed/recovered/re-allocated/re-optimized connections, this + // metric determines the average path length (in terms of number of hops) over the computed path for the + // succesfully (i.e., feasible path) connections + gdouble compRouteConnAvPathLength; +}; + +// Prototype of external declaration of functions +void print_path (struct compRouteOutputItem_t *); +void print_path_t(struct path_t*); +struct path_t* create_path(); + +void duplicate_string(gchar *, gchar *); + +gchar* get_uuid_char(uuid_t); +void copy_service_id(struct serviceId_t*, struct serviceId_t *); +void copy_service_endpoint_id(struct service_endpoints_id_t *, struct service_endpoints_id_t *); + +struct graph_t* get_graph_by_contextId(GList*, gchar *); + +struct pred_t * create_predecessors (); +struct edges_t* create_edge(); +void print_predecessors (struct pred_t *); +void build_predecessors (struct pred_t *, struct service_t *, struct map_nodes_t *); +struct nodes_t * create_node (); +struct routeElement_t * create_routeElement (); + +void duplicate_node_id (struct nodes_t *, struct nodes_t *); +gint compare_node_id (struct nodes_t *, struct nodes_t *); +void duplicate_routeElement (struct routeElement_t *, struct routeElement_t *); +void duplicate_edge (struct edges_t *, struct edges_t *); +void duplicate_path (struct compRouteOutputItem_t *, struct compRouteOutputItem_t *); +void duplicate_path_t(struct compRouteOutputItem_t *, struct path_t *); +gint get_map_index_by_nodeId (gchar *, struct map_nodes_t *); +void get_edge_from_map_by_node (struct edges_t *, struct nodes_t*, struct map_nodes_t *); +void get_edge_from_predecessors (struct edges_t *, struct nodes_t*, struct pred_t *); +void build_path (struct compRouteOutputItem_t *, struct pred_t *, struct service_t *); +void print_graph (struct graph_t *); + +gint graph_vertice_lookup (gchar *, struct graph_t *); +gint graph_targeted_vertice_lookup (gint, gchar *, struct graph_t *); +gint graph_targeted_vertice_add (gint, gchar *, struct graph_t *); + +void remove_edge_from_graph (struct graph_t *, struct edges_t *); + +struct path_set_t * create_path_set (); +void sort_path_set (struct path_set_t *, guint); +void pop_front_path_set (struct path_set_t *); +void remove_path_set(struct path_set_t*); + +void build_map_node(struct map_nodes_t *, struct graph_t *); +struct compRouteOutputList_t * create_route_list(); +void duplicate_route_list(struct compRouteOutputList_t *, struct compRouteOutputList_t *); +struct compRouteOutputItem_t * create_path_item (); +void add_routeElement_path_back (struct routeElement_t *, struct compRouteOutputItem_t *); +gboolean matching_path_rootPath (struct compRouteOutputItem_t *, struct compRouteOutputItem_t *, struct nodes_t *, struct edges_t *); +void modify_targeted_graph (struct graph_t *, struct path_set_t *, struct compRouteOutputItem_t *, struct nodes_t *); +gint find_nodeId (gconstpointer, gconstpointer); +gint check_link (struct nodeItem_t *, gint, gint, struct graph_t *, struct service_t *, GList **, GList **, struct map_nodes_t *, guint arg); +gboolean check_computed_path_feasability (struct service_t *, struct compRouteOutputItem_t * ); + +gint sort_by_distance (gconstpointer, gconstpointer); +gint sort_by_energy(gconstpointer, gconstpointer); + +struct graph_t * create_graph (); +struct map_nodes_t * create_map_node (); + +struct service_t * get_service_for_computed_path(gchar *); + +void print_service_type(guint); +void print_link_port_direction(guint); +void print_termination_direction(guint); +void print_termination_state(guint); +void print_capacity_unit(guint); +void print_link_forwarding_direction(guint); + +void build_contextSet(GList **); +void build_contextSet_active(GList **); +void print_contextSet(GList *); + +gint same_src_dst_pe_nodeid (struct service_t *); +void comp_route_connection_issue_handler (struct compRouteOutput_t *, struct service_t *); + +void destroy_compRouteOutputList (struct compRouteOutputList_t *); +void duplicate_graph (struct graph_t *, struct graph_t *); + +void allocate_graph_resources (struct path_t *, struct service_t *, struct graph_t *); +void allocate_graph_reverse_resources(struct path_t*, struct service_t *, struct graph_t *); +void print_route_solution_list (GList *); +struct timeval tv_adjust(struct timeval); + +void print_path_connection_list(struct compRouteOutputList_t*); +void update_stats_path_comp(struct compRouteOutputList_t*, struct timeval, gint, gint); +void destroy_active_service(struct activeService_t*); +void destroy_requested_service(struct service_t*); +void destroy_device(struct device_t*); +void destroy_link(struct link_t*); +void destroy_context(struct context_t*); +void dijkstra(gint, gint, struct graph_t*, struct service_t*, struct map_nodes_t*, struct nodes_t*, struct compRouteOutputItem_t*, guint); +void set_path_attributes(struct compRouteOutputItem_t*, struct map_t*); +void alg_comp(struct service_t*, struct compRouteOutput_t*, struct graph_t*, guint); #endif \ No newline at end of file -- GitLab From a4ddc9a4d031d5d7c5b34e292b05d0895d472ab8 Mon Sep 17 00:00:00 2001 From: martinezric Date: Wed, 3 May 2023 12:55:20 +0000 Subject: [PATCH 3/7] Updated the file headers --- src/pathcomp/backend/pathComp_sp.c | 16 +++++++--------- src/pathcomp/backend/pathComp_tools.c | 11 ++++------- src/pathcomp/backend/pathComp_tools.h | 11 ++++------- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/pathcomp/backend/pathComp_sp.c b/src/pathcomp/backend/pathComp_sp.c index 6510a0d7d..084fc14f3 100644 --- a/src/pathcomp/backend/pathComp_sp.c +++ b/src/pathcomp/backend/pathComp_sp.c @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////////////// -/** - * # Copyright 2022 Centre Tecnològic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es +/* + * Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,8 @@ * 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. - - * Author: CTTC/CERCA PONS RU Ricardo Martínez (ricardo.martinez@cttc.es) */ - //////////////////////////////////////////////////////////////////////////////////////// + #include #include #include @@ -51,7 +49,7 @@ GList* contextSet; * @param s * @param mapNodes * - * @author Ricardo Martínez + * @author Ricardo Mart�nez * @date 2022 */ ///////////////////////////////////////////////////////////////////////////////////////// @@ -106,7 +104,7 @@ gint computation(struct pred_t* pred, struct graph_t* g, struct service_t* s, st * @param path * @param g * - * @author Ricardo Martínez + * @author Ricardo Mart�nez * @date 2022 */ ///////////////////////////////////////////////////////////////////////////////////////// @@ -186,7 +184,7 @@ void computation_shortest_path(struct service_t* s, struct compRouteOutput_t* pa * * @param outputList * - * @author Ricardo Martínez + * @author Ricardo Mart�nez * @date 2022 */ void sp_execution_services(struct compRouteOutputList_t* oPathList) { @@ -247,7 +245,7 @@ void sp_execution_services(struct compRouteOutputList_t* oPathList) { * * @param compRouteOutput * - * @author Ricardo Martínez + * @author Ricardo Mart�nez * @date 2022 */ ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/pathcomp/backend/pathComp_tools.c b/src/pathcomp/backend/pathComp_tools.c index 139d97325..8fbef0476 100644 --- a/src/pathcomp/backend/pathComp_tools.c +++ b/src/pathcomp/backend/pathComp_tools.c @@ -1,6 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////////////// -/** - * # Copyright 2022 Centre Tecnològic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es +/* + * Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +12,8 @@ * 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. - - * Author: CTTC/CERCA PONS RU Ricardo Martínez (ricardo.martinez@cttc.es) */ -///////////////////////////////////////////////////////////////////////////////////////// + #include #include @@ -3398,4 +3395,4 @@ void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_ DEBUG_PC("K-SP failed!!!"); comp_route_connection_issue_handler(path, s); return; -} \ No newline at end of file +} diff --git a/src/pathcomp/backend/pathComp_tools.h b/src/pathcomp/backend/pathComp_tools.h index 041d42019..f69de1836 100644 --- a/src/pathcomp/backend/pathComp_tools.h +++ b/src/pathcomp/backend/pathComp_tools.h @@ -1,6 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////////////// -/** - * # Copyright 2022 Centre Tecnol�gic de Telecomunicacions de Catalunya (CTTC/CERCA) www.cttc.es +/* + * Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +12,8 @@ * 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. - - * Author: CTTC/CERCA PONS RU Ricardo Mart�nez (ricardo.martinez@cttc.es) */ -///////////////////////////////////////////////////////////////////////////////////////// + #ifndef _PATHCOMP_TOOLS_H #define _PATHCOMP_TOOLS_H @@ -621,4 +618,4 @@ void destroy_context(struct context_t*); void dijkstra(gint, gint, struct graph_t*, struct service_t*, struct map_nodes_t*, struct nodes_t*, struct compRouteOutputItem_t*, guint); void set_path_attributes(struct compRouteOutputItem_t*, struct map_t*); void alg_comp(struct service_t*, struct compRouteOutput_t*, struct graph_t*, guint); -#endif \ No newline at end of file +#endif -- GitLab From f43fe219736096cc0346cc8590ac266c0edc602e Mon Sep 17 00:00:00 2001 From: martinezric Date: Fri, 5 May 2023 11:00:23 +0200 Subject: [PATCH 4/7] PathComp component - Backend: - Added missing gitignore entries - Added log messages --- src/pathcomp/.gitignore | 3 ++ src/pathcomp/backend/pathComp_sp.c | 2 +- src/pathcomp/backend/pathComp_tools.c | 70 +++++++++++++++------------ src/pathcomp/backend/pathComp_tools.h | 4 +- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/pathcomp/.gitignore b/src/pathcomp/.gitignore index 48a680bf0..82fc0ca31 100644 --- a/src/pathcomp/.gitignore +++ b/src/pathcomp/.gitignore @@ -1 +1,4 @@ backend/wireshark +backend/*.o +backend/pathComp +backend/pathComp-dbg diff --git a/src/pathcomp/backend/pathComp_sp.c b/src/pathcomp/backend/pathComp_sp.c index 084fc14f3..6c48a8d1b 100644 --- a/src/pathcomp/backend/pathComp_sp.c +++ b/src/pathcomp/backend/pathComp_sp.c @@ -144,7 +144,7 @@ void computation_shortest_path(struct service_t* s, struct compRouteOutput_t* pa DEBUG_PC("Computed Path Avail Bw: %f, Path Cost: %f, latency: %f", p->availCap, p->cost, p->delay); print_path(p); - gboolean feasibleRoute = check_computed_path_feasability(s, p); + gboolean feasibleRoute = check_computed_path_feasibility(s, p); if (feasibleRoute == TRUE) { DEBUG_PC("SP Feasible"); print_path(p); diff --git a/src/pathcomp/backend/pathComp_tools.c b/src/pathcomp/backend/pathComp_tools.c index 8fbef0476..321821f45 100644 --- a/src/pathcomp/backend/pathComp_tools.c +++ b/src/pathcomp/backend/pathComp_tools.c @@ -1460,8 +1460,7 @@ void modify_targeted_graph (struct graph_t *g, struct path_set_t *A, struct comp * @date 2022 */ ///////////////////////////////////////////////////////////////////////////////////////// -gint find_nodeId (gconstpointer data, gconstpointer userdata) -{ +gint find_nodeId (gconstpointer data, gconstpointer userdata) { /** check values */ g_assert(data != NULL); g_assert(userdata != NULL); @@ -1471,8 +1470,7 @@ gint find_nodeId (gconstpointer data, gconstpointer userdata) //DEBUG_PC ("SNodeId (%s) nodeId (%s)", SNodeId->node.nodeId, nodeId); - if (!memcmp(SNodeId->node.nodeId, nodeId, strlen (SNodeId->node.nodeId))) - { + if (!memcmp(SNodeId->node.nodeId, nodeId, strlen (SNodeId->node.nodeId))) { return (0); } return -1; @@ -1501,13 +1499,13 @@ gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struc g_assert(g); g_assert(s); g_assert(mapNodes); struct targetNodes_t *v = &(g->vertices[indexGraphU].targetedVertices[indexGraphV]); - DEBUG_PC("Explored Link %s => %s)", u->node.nodeId, v->tVertice.nodeId); + DEBUG_PC("=======================CHECK Edge %s => %s =================================", u->node.nodeId, v->tVertice.nodeId); //DEBUG_PC("\t %s => %s", u->node.nodeId, v->tVertice.nodeId); // v already explored in S? then, discard it GList *found = g_list_find_custom (*S, v->tVertice.nodeId, find_nodeId); if (found != NULL) { - DEBUG_PC ("v (%s) in S, Discard", v->tVertice.nodeId); + DEBUG_PC ("%s in S, DISCARD", v->tVertice.nodeId); return 0; } @@ -1524,10 +1522,11 @@ gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struc DEBUG_PC("EDGE %s[%s] => %s[%s]", u->node.nodeId, e->aEndPointId, v->tVertice.nodeId, e->zEndPointId); //DEBUG_PC ("\t %s[%s] =>", u->node.nodeId, e->aEndPointId); //DEBUG_PC("\t => %s[%s]", v->tVertice.nodeId, e->zEndPointId); - DEBUG_PC("\t AvailBw: %f, TotalBw: %f", edgeAvailBw, edgeTotalBw); + DEBUG_PC("\t Edge Att: AvailBw: %f, TotalBw: %f", edgeAvailBw, edgeTotalBw); // Check Service Bw constraint - if ((path_constraints->bw == TRUE) && (edgeAvailBw < path_constraints->bwConstraint)) + if ((path_constraints->bw == TRUE) && (edgeAvailBw < path_constraints->bwConstraint)) { continue; + } else { foundAvailBw = 1; break; @@ -1535,7 +1534,7 @@ gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struc } // BW constraint NOT MET, then DISCARD edge if ((path_constraints->bw == TRUE) && (foundAvailBw == 0)) { - DEBUG_PC ("AvailBw: %f < path_constraint: %f -- Discard Edge", edgeAvailBw, path_constraints->bwConstraint); + DEBUG_PC ("Edge AvailBw: %f < path_constraint: %f -- DISCARD Edge", edgeAvailBw, path_constraints->bwConstraint); g_free(path_constraints); return 0; } @@ -1581,13 +1580,14 @@ gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struc if (arg & ENERGY_EFFICIENT_ARGUMENT) { if (distance_through_u == v_map->distance) { if (power_through_u > v_map->power) { - DEBUG_PC("Energy (src -> u + u -> v: %f (Watts) >Energy (src, v): %f (Watts)--> DISCARD LINK", power_through_u, v_map->power); + DEBUG_PC("Energy (src -> u + u -> v: %f (Watts) > Energy (src, v): %f (Watts) --> DISCARD EDGE", power_through_u, v_map->power); return 0; } // same energy consumption, consider latency if ((power_through_u == v_map->power) && (latency_through_u > v_map->latency)) { return 0; } + // same energy, same latency, criteria: choose the one having the largest available bw if ((power_through_u == v_map->power) && (latency_through_u == v_map->latency) && (availBw_through_u < v_map->avaiBandwidth)) { return 0; } @@ -1604,8 +1604,9 @@ gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struc return 0; } } - DEBUG_PC ("%s --> %s Relaxed", u->node.nodeId, v->tVertice.nodeId); - DEBUG_PC ("\t AvailBw: %f Mb/s, Cost: %f, Latency: %f ms, Energy: %f Watts", availBw_through_u, distance_through_u, latency_through_u, power_through_u); + DEBUG_PC ("Edge %s --> %s [RELAXED]", u->node.nodeId, v->tVertice.nodeId); + DEBUG_PC ("\t path till %s: AvailBw: %f Mb/s | Cost: %f | Latency: %f ms | Energy: %f Watts", v->tVertice.nodeId, availBw_through_u, distance_through_u, + latency_through_u, power_through_u); // Update Q list -- struct nodeItem_t *nodeItem = g_malloc0 (sizeof (struct nodeItem_t)); @@ -1622,8 +1623,9 @@ gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struc if (arg & ENERGY_EFFICIENT_ARGUMENT) { *Q = g_list_insert_sorted(*Q, nodeItem, sort_by_energy); } - else + else { *Q = g_list_insert_sorted (*Q, nodeItem, sort_by_distance); + } // Update the mapNodes for the specific reached tv v_map->distance = distance_through_u; @@ -1635,9 +1637,9 @@ gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struc struct edges_t *e1 = &(v_map->predecessor); struct edges_t *e2 = &(v->edges[indexEdge]); duplicate_edge(e1, e2); - DEBUG_PC ("u->v Edge: %s(%s) --> %s(%s)", e2->aNodeId.nodeId, e2->aEndPointId, e2->zNodeId.nodeId, e2->zEndPointId); + //DEBUG_PC ("u->v Edge: %s(%s) --> %s(%s)", e2->aNodeId.nodeId, e2->aEndPointId, e2->zNodeId.nodeId, e2->zEndPointId); //DEBUG_PC("v-pred aTopology: %s", e2->aTopologyId); - DEBUG_PC("v-pred zTopology: %s", e2->zTopologyId); + //DEBUG_PC("v-pred zTopology: %s", e2->zTopologyId); // Check whether v is dstPEId //DEBUG_PC ("Targeted dstId: %s", s->service_endpoints_id[1].device_uuid); @@ -1659,7 +1661,7 @@ gint check_link (struct nodeItem_t *u, gint indexGraphU, gint indexGraphV, struc * @date 2022 */ ///////////////////////////////////////////////////////////////////////////////////////// -gboolean check_computed_path_feasability (struct service_t *s, struct compRouteOutputItem_t* p) { +gboolean check_computed_path_feasibility (struct service_t *s, struct compRouteOutputItem_t* p) { float epsilon = 0.0000001; struct path_constraints_t* pathCons = get_path_constraints(s); gboolean ret = TRUE; @@ -2346,7 +2348,7 @@ void build_contextSet_linklList(GList** set, gint activeFlag) { // for each link in linkList: // 1st- Retrieve endpoints A --> B feauture (context Id, device Id, endpoint Id) // 2st - In the graph associated to the contextId, check wheter A (deviceId) is in the vertices list - // o No, this is weird ... exist + // o No, this is weird ... exit // o Yes, get the other link endpoint (i.e., B) and check whether it exists. If NOT add it, considering // all the attributes; Otherwise, check whether the link is different from existing edges between A and B gdouble epsilon = 0.1; @@ -3065,7 +3067,7 @@ void dijkstra(gint srcMapIndex, gint dstMapIndex, struct graph_t* g, struct serv // if ingress of the root link (aNodeId) is the spurNode, then stops if (compare_node_id(&re->aNodeId, SN) == 0) { - DEBUG_PC("root Link: aNodeId: %s and spurNode: %s -- stop exploring the rootPath (RP)", re->aNodeId.nodeId, SN->nodeId); + DEBUG_PC("Ingress Node rootLink %s = spurNode %s; STOP exploring rootPath (RP)", re->aNodeId.nodeId, SN->nodeId); break; } // Extract from Q @@ -3073,7 +3075,6 @@ void dijkstra(gint srcMapIndex, gint dstMapIndex, struct graph_t* g, struct serv struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); Q = g_list_remove(Q, node); - //DEBUG_RL_RA ("Exploring node %s", node->node.nodeId); indexVertice = graph_vertice_lookup(node->node.nodeId, g); g_assert(indexVertice >= 0); @@ -3087,22 +3088,21 @@ void dijkstra(gint srcMapIndex, gint dstMapIndex, struct graph_t* g, struct serv } // Check that the first node in Q set is SpurNode, otherwise something went wrong ... if (compare_node_id(&re->aNodeId, SN) != 0) { - //DEBUG_PC ("root Link: aNodeId: %s is NOT the spurNode: %s -- something wrong", re->aNodeId.nodeId, SN->nodeId); + DEBUG_PC ("root Link: aNodeId: %s is NOT the spurNode: %s -- something wrong", re->aNodeId.nodeId, SN->nodeId); g_list_free_full(g_steal_pointer(&S), g_free); g_list_free_full(g_steal_pointer(&Q), g_free); return; } } - while (g_list_length(Q) > 0) { //Extract from Q set GList* listnode = g_list_first(Q); struct nodeItem_t* node = (struct nodeItem_t*)(listnode->data); Q = g_list_remove(Q, node); DEBUG_PC("Q length: %d", g_list_length(Q)); - DEBUG_PC("DeviceId: %s", node->node.nodeId); + DEBUG_PC("Explored DeviceId: %s", node->node.nodeId); - // visit all the links from u within the graph + // scan all the links from u within the graph indexVertice = graph_vertice_lookup(node->node.nodeId, g); g_assert(indexVertice >= 0); @@ -3140,18 +3140,19 @@ gint ksp_comp(struct pred_t* pred, struct graph_t* g, struct service_t* s, struct map_nodes_t* mapNodes, guint arg) { g_assert(pred); g_assert(g); g_assert(s); - DEBUG_PC("Source: %s -- Destination: %s", s->service_endpoints_id[0].device_uuid, s->service_endpoints_id[1].device_uuid); + DEBUG_PC("SOURCE: %s --> DESTINATION: %s", s->service_endpoints_id[0].device_uuid, + s->service_endpoints_id[1].device_uuid); // Check the both ingress src and dst endpoints are in the graph gint srcMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[0].device_uuid, mapNodes); if (srcMapIndex == -1) { - DEBUG_PC("ingress DeviceId: %s NOT in the graph", s->service_endpoints_id[0].device_uuid); + DEBUG_PC("ingress DeviceId: %s NOT in G", s->service_endpoints_id[0].device_uuid); return -1; } gint dstMapIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); if (dstMapIndex == -1) { - DEBUG_PC("egress DeviceId: %s NOT in the graph", s->service_endpoints_id[1].device_uuid); + DEBUG_PC("egress DeviceId: %s NOT in G", s->service_endpoints_id[1].device_uuid); return -1; } @@ -3165,17 +3166,17 @@ gint ksp_comp(struct pred_t* pred, struct graph_t* g, struct service_t* s, gint map_dstIndex = get_map_index_by_nodeId(s->service_endpoints_id[1].device_uuid, mapNodes); struct map_t* dest_map = &mapNodes->map[map_dstIndex]; if (!(dest_map->distance < INFINITY_COST)) { - DEBUG_PC("destination: %s NOT reachable", s->service_endpoints_id[1].device_uuid); + DEBUG_PC("DESTINATION: %s NOT reachable", s->service_endpoints_id[1].device_uuid); return -1; } DEBUG_PC("AvailBw @ %s is %f", dest_map->verticeId.nodeId, dest_map->avaiBandwidth); // Check that the computed available bandwidth is larger than 0.0 if (dest_map->avaiBandwidth <= (gfloat)0.0) { - DEBUG_PC("dst: %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); + DEBUG_PC("DESTINATION %s NOT REACHABLE", s->service_endpoints_id[1].device_uuid); return -1; } - DEBUG_PC("dst: %s REACHABLE", s->service_endpoints_id[1].device_uuid); + DEBUG_PC("DESTINATION %s REACHABLE", s->service_endpoints_id[1].device_uuid); // Handle predecessors build_predecessors(pred, s, mapNodes); return 1; @@ -3229,6 +3230,9 @@ void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_ struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[0]); struct service_endpoints_id_t* eEp = &(s->service_endpoints_id[1]); + DEBUG_PC("======================================================================================="); + DEBUG_PC("STARTING PATH COMP FOR %s[%s] --> %s[%s]", iEp->device_uuid, iEp->endpoint_uuid, eEp->device_uuid, eEp->endpoint_uuid); + // Compute the 1st KSP path gint done = ksp_comp(predecessors, g, s, NULL, NULL, mapNodes, arg); if (done == -1) { @@ -3360,9 +3364,10 @@ void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_ // copy the service endpoints, in general, there will be 2 (point-to-point network connectivity services) for (gint m = 0; m < s->num_service_endpoints_id; m++) { struct service_endpoints_id_t* iEp = &(s->service_endpoints_id[m]); - struct service_endpoints_id_t* oEp = &(s->service_endpoints_id[m]); + struct service_endpoints_id_t* oEp = &(path->service_endpoints_id[m]); copy_service_endpoint_id(oEp, iEp); } + path->num_service_endpoints_id = s->num_service_endpoints_id; // Print all the paths i A for (gint h = 0; h < A->numPaths; h++) { @@ -3376,9 +3381,10 @@ void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_ DEBUG_PC("Number Requested paths (%d) REACHED - STOP", ksp); break; } - gdouble feasibleRoute = check_computed_path_feasability(s, &A->paths[ksp]); + gdouble feasibleRoute = check_computed_path_feasibility(s, &A->paths[ksp]); if (feasibleRoute == TRUE) { - DEBUG_PC("A[%d] available: %f, pathCost: %f; latency: %f, Power: %f", ksp, A->paths[ksp].availCap, A->paths[ksp].cost, A->paths[ksp].delay, A->paths[ksp].power); + DEBUG_PC("A[%d] available: %f, pathCost: %f; latency: %f, Power: %f", ksp, A->paths[ksp].availCap, + A->paths[ksp].cost, A->paths[ksp].delay, A->paths[ksp].power); struct compRouteOutputItem_t* pathaux = &A->paths[ksp]; path->numPaths++; struct path_t* targetedPath = &path->paths[path->numPaths - 1]; diff --git a/src/pathcomp/backend/pathComp_tools.h b/src/pathcomp/backend/pathComp_tools.h index f69de1836..9819c9080 100644 --- a/src/pathcomp/backend/pathComp_tools.h +++ b/src/pathcomp/backend/pathComp_tools.h @@ -39,7 +39,7 @@ extern GList* activeServList; #define INFINITY_COST 0xFFFFFFFF #define MAX_NUM_PRED 100 -#define MAX_KSP_VALUE 3 +#define MAX_KSP_VALUE 5 // HTTP RETURN CODES #define HTTP_CODE_OK 200 @@ -576,7 +576,7 @@ gboolean matching_path_rootPath (struct compRouteOutputItem_t *, struct compRout void modify_targeted_graph (struct graph_t *, struct path_set_t *, struct compRouteOutputItem_t *, struct nodes_t *); gint find_nodeId (gconstpointer, gconstpointer); gint check_link (struct nodeItem_t *, gint, gint, struct graph_t *, struct service_t *, GList **, GList **, struct map_nodes_t *, guint arg); -gboolean check_computed_path_feasability (struct service_t *, struct compRouteOutputItem_t * ); +gboolean check_computed_path_feasibility (struct service_t *, struct compRouteOutputItem_t * ); gint sort_by_distance (gconstpointer, gconstpointer); gint sort_by_energy(gconstpointer, gconstpointer); -- GitLab From a74f61000353d2236c3a583158199fd23a10300d Mon Sep 17 00:00:00 2001 From: martinezric Date: Fri, 5 May 2023 11:09:56 +0200 Subject: [PATCH 5/7] PathComp component - Backend: - Minor code cleanup --- src/pathcomp/backend/pathComp_sp.c | 6 +++--- src/pathcomp/backend/pathComp_tools.h | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pathcomp/backend/pathComp_sp.c b/src/pathcomp/backend/pathComp_sp.c index 6c48a8d1b..9cbd29eff 100644 --- a/src/pathcomp/backend/pathComp_sp.c +++ b/src/pathcomp/backend/pathComp_sp.c @@ -231,9 +231,9 @@ void sp_execution_services(struct compRouteOutputList_t* oPathList) { continue; } struct path_t* path = &(pathService->paths[pathService->numPaths - 1]); - allocate_graph_resources(path, service, g); - allocate_graph_reverse_resources(path, service, g); - print_graph(g); + //allocate_graph_resources(path, service, g); // LGR: crashes in some cases with assymetric topos + //allocate_graph_reverse_resources(path, service, g); // LGR: crashes in some cases with assymetric topos + print_graph(g); } return; } diff --git a/src/pathcomp/backend/pathComp_tools.h b/src/pathcomp/backend/pathComp_tools.h index 9819c9080..fb458d8c0 100644 --- a/src/pathcomp/backend/pathComp_tools.h +++ b/src/pathcomp/backend/pathComp_tools.h @@ -125,8 +125,9 @@ struct map_nodes_t { gint numMapNodes; }; -#define MAX_NUM_VERTICES 20 // 100 # LGR: reduced from 100 to 20 to divide by 5 the memory used -#define MAX_NUM_EDGES 10 // 100 # LGR: reduced from 100 to 10 to divide by 10 the memory used +#define MAX_NUM_VERTICES 100 // 100 # LGR: reduced from 100 to 20 to divide by 5 the memory used +#define MAX_NUM_EDGES 5 // 100 # LGR: reduced from 100 to 5 to divide by 20 the memory used + // Structures for the graph composition struct targetNodes_t { // remote / targeted node @@ -250,7 +251,7 @@ struct endPoint_t { // Structure for the device contents /////////////////////////////////////////////////////////////////// #define MAX_DEV_TYPE_SIZE 128 -#define MAX_DEV_ENDPOINT_LENGTH 10 +#define MAX_DEV_ENDPOINT_LENGTH 100 // 10 # LGR: controllers might have large number of endpoints struct device_t { gdouble power_idle; // power idle (baseline) of the switch in Watts gint operational_status; // 0 - Undefined, 1 - Disabled, 2 - Enabled -- GitLab From 5150d83061957bba46161d4c4808fc512e966777 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Fri, 5 May 2023 10:44:24 +0000 Subject: [PATCH 6/7] PathComp component - Backend: - Pre-merge code cleanup --- src/pathcomp/backend/pathComp_sp.c | 57 +++++++++++++-------------- src/pathcomp/backend/pathComp_tools.c | 1 - src/pathcomp/backend/pathComp_tools.h | 1 - 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/pathcomp/backend/pathComp_sp.c b/src/pathcomp/backend/pathComp_sp.c index 9cbd29eff..b6fd885e3 100644 --- a/src/pathcomp/backend/pathComp_sp.c +++ b/src/pathcomp/backend/pathComp_sp.c @@ -1,4 +1,3 @@ -//////////////////////////////////////////////////////////////////////////////////////// /* * Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) * @@ -203,34 +202,34 @@ void sp_execution_services(struct compRouteOutputList_t* oPathList) { //struct service_t* service = &(serviceList->services[i]); struct service_t* service = (struct service_t*)(listnode->data); - DEBUG_PC("Starting the Computation for ServiceId: %s [ContextId: %s]", service->serviceId.service_uuid, service->serviceId.contextId); - struct compRouteOutput_t* pathService = &(oPathList->compRouteConnection[i]); - // check endpoints of the service are different (PE devices/nodes are different) - if (same_src_dst_pe_nodeid(service) == 0) { - DEBUG_PC("PEs are the same... no path computation"); - comp_route_connection_issue_handler(pathService, service); - oPathList->numCompRouteConnList++; - continue; - } - - // get the graph associated to the contextId in the contextSet, if no then error - struct graph_t* g = get_graph_by_contextId(contextSet, service->serviceId.contextId); - if (g == NULL) { - DEBUG_PC("The targeted contextId is NOT in the ContextSet ... then NO graph"); - comp_route_connection_issue_handler(pathService, service); - oPathList->numCompRouteConnList++; - continue; - } - - computation_shortest_path(service, pathService, g); - oPathList->numCompRouteConnList++; - - // for each network connectivity service, a single computed path (out of the KCSP) is retuned - // If path is found, then the selected resources must be pre-assigned into the context information - if (pathService->noPathIssue == NO_PATH_CONS_ISSUE) { - continue; - } - struct path_t* path = &(pathService->paths[pathService->numPaths - 1]); + DEBUG_PC("Starting the Computation for ServiceId: %s [ContextId: %s]", service->serviceId.service_uuid, service->serviceId.contextId); + struct compRouteOutput_t* pathService = &(oPathList->compRouteConnection[i]); + // check endpoints of the service are different (PE devices/nodes are different) + if (same_src_dst_pe_nodeid(service) == 0) { + DEBUG_PC("PEs are the same... no path computation"); + comp_route_connection_issue_handler(pathService, service); + oPathList->numCompRouteConnList++; + continue; + } + + // get the graph associated to the contextId in the contextSet, if no then error + struct graph_t* g = get_graph_by_contextId(contextSet, service->serviceId.contextId); + if (g == NULL) { + DEBUG_PC("The targeted contextId is NOT in the ContextSet ... then NO graph"); + comp_route_connection_issue_handler(pathService, service); + oPathList->numCompRouteConnList++; + continue; + } + + computation_shortest_path(service, pathService, g); + oPathList->numCompRouteConnList++; + + // for each network connectivity service, a single computed path (out of the KCSP) is retuned + // If path is found, then the selected resources must be pre-assigned into the context information + if (pathService->noPathIssue == NO_PATH_CONS_ISSUE) { + continue; + } + struct path_t* path = &(pathService->paths[pathService->numPaths - 1]); //allocate_graph_resources(path, service, g); // LGR: crashes in some cases with assymetric topos //allocate_graph_reverse_resources(path, service, g); // LGR: crashes in some cases with assymetric topos print_graph(g); diff --git a/src/pathcomp/backend/pathComp_tools.c b/src/pathcomp/backend/pathComp_tools.c index 321821f45..37d93b304 100644 --- a/src/pathcomp/backend/pathComp_tools.c +++ b/src/pathcomp/backend/pathComp_tools.c @@ -14,7 +14,6 @@ * limitations under the License. */ - #include #include #include diff --git a/src/pathcomp/backend/pathComp_tools.h b/src/pathcomp/backend/pathComp_tools.h index fb458d8c0..d31a6d5e5 100644 --- a/src/pathcomp/backend/pathComp_tools.h +++ b/src/pathcomp/backend/pathComp_tools.h @@ -14,7 +14,6 @@ * limitations under the License. */ - #ifndef _PATHCOMP_TOOLS_H #define _PATHCOMP_TOOLS_H -- GitLab From 8632129190dd9232bdb8fb959f4a2e0b83cd6d14 Mon Sep 17 00:00:00 2001 From: martinezric Date: Thu, 18 May 2023 10:31:53 +0200 Subject: [PATCH 7/7] pathComp Component-backend - Added KPath returned - Modified path computation response to for K paths for a single service --- src/pathcomp/backend/pathComp_RESTapi.c | 15 ++++++++---- src/pathcomp/backend/pathComp_ksp.c | 12 +++++----- src/pathcomp/backend/pathComp_tools.c | 31 +++++++++++++++++++------ src/pathcomp/backend/pathComp_tools.h | 11 ++++----- 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/pathcomp/backend/pathComp_RESTapi.c b/src/pathcomp/backend/pathComp_RESTapi.c index 1780cfde2..5e22136e7 100644 --- a/src/pathcomp/backend/pathComp_RESTapi.c +++ b/src/pathcomp/backend/pathComp_RESTapi.c @@ -281,7 +281,6 @@ void add_comp_path_deviceId_endpointId_json(cJSON* pathObj, struct path_t* p, st return; } - //////////////////////////////////////////////////////////////////////////////////////// /** * @file pathComp_RESTapi.c @@ -812,12 +811,18 @@ void parsing_json_serviceList_array(cJSON* serviceArray) { parse_service_constraints(constraintArray, service); } - // Get the maximum number of paths to be computed (kPaths) - cJSON* kPathsObj = cJSON_GetObjectItemCaseSensitive(item, "kPaths"); - if (cJSON_IsNumber(kPathsObj)){ - service->kPaths = (guint)(kPathsObj->valuedouble); + // Get the maximum number of paths to be computed (kPaths) inspected/explored + cJSON* kPathsInspObj = cJSON_GetObjectItemCaseSensitive(item, "kPaths_inspection"); + if (cJSON_IsNumber(kPathsInspObj)){ + service->kPaths_inspected = (guint)(kPathsInspObj->valuedouble); } + // Get the maximum number of paths to be computed (kPaths) returned + cJSON* kPathsRetpObj = cJSON_GetObjectItemCaseSensitive(item, "kPaths_return"); + if (cJSON_IsNumber(kPathsRetpObj)){ + service->kPaths_returned = (guint)(kPathsRetpObj->valuedouble); + } + // Append the requested service to the serviceList serviceList = g_list_append(serviceList, service); } diff --git a/src/pathcomp/backend/pathComp_ksp.c b/src/pathcomp/backend/pathComp_ksp.c index 00ebaf5b8..f5e3c8fb8 100644 --- a/src/pathcomp/backend/pathComp_ksp.c +++ b/src/pathcomp/backend/pathComp_ksp.c @@ -63,15 +63,14 @@ void ksp_alg_execution_services(struct compRouteOutputList_t* outputList) { gint i = 0; for (GList* listnode = g_list_first(serviceList); listnode; - listnode = g_list_next(listnode), i++){ - //struct service_t* service = &(serviceList->services[i]); + listnode = g_list_next(listnode), i++){ struct service_t* service = (struct service_t*)(listnode->data); DEBUG_PC("Starting the Computation for ServiceId: %s [ContextId: %s]", service->serviceId.service_uuid, service->serviceId.contextId); struct compRouteOutput_t* pathService = &(outputList->compRouteConnection[i]); // check endpoints of the service are different (PE devices/nodes are different) if (same_src_dst_pe_nodeid(service) == 0) { - DEBUG_PC("PEs are the same... no path computation"); + DEBUG_PC("PEs are the same... NO PATH COMPUTATION"); comp_route_connection_issue_handler(pathService, service); outputList->numCompRouteConnList++; continue; @@ -84,6 +83,7 @@ void ksp_alg_execution_services(struct compRouteOutputList_t* outputList) { outputList->numCompRouteConnList++; continue; } + alg_comp(service, pathService, g, NO_OPTIMIZATION_ARGUMENT); // last parameter 0 is related to an optimization computation argument outputList->numCompRouteConnList++; @@ -92,7 +92,8 @@ void ksp_alg_execution_services(struct compRouteOutputList_t* outputList) { if (pathService->noPathIssue == NO_PATH_CONS_ISSUE) { continue; } - struct path_t* path = &(pathService->paths[pathService->numPaths - 1]); + // Out of the comnputed paths for the pathservice, the first one is chosen to be locally allocated + struct path_t* path = &(pathService->paths[0]); allocate_graph_resources(path, service, g); allocate_graph_reverse_resources(path, service, g); print_graph(g); @@ -111,8 +112,7 @@ void ksp_alg_execution_services(struct compRouteOutputList_t* outputList) { * @date 2022 */ ///////////////////////////////////////////////////////////////////////////////////////// -gint pathComp_ksp_alg(struct compRouteOutputList_t * routeConnList) -{ +gint pathComp_ksp_alg(struct compRouteOutputList_t * routeConnList) { g_assert(routeConnList); gint numSuccesPathComp = 0, numPathCompIntents = 0; diff --git a/src/pathcomp/backend/pathComp_tools.c b/src/pathcomp/backend/pathComp_tools.c index 321821f45..e5d4ac846 100644 --- a/src/pathcomp/backend/pathComp_tools.c +++ b/src/pathcomp/backend/pathComp_tools.c @@ -3221,6 +3221,18 @@ void set_path_attributes(struct compRouteOutputItem_t* p, struct map_t* mapV) { void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_t* g, guint arg) { g_assert(s); g_assert(path); g_assert(g); + // Check if the service specifies a nuumber of K paths to be explored/computed for the + // service. If not, compute that number; otherwise set the max number of explored + // computed paths to MAX_KSP_VALUE + guint maxK = 0; + if(s->kPaths_inspected == 0) { + maxK = MAX_KSP_VALUE; + } + else { + maxK = s->kPaths_inspected; + } + DEBUG_PC("The KSP considers K: %d", maxK); + // create map of devices/nodes to handle the path computation using the context struct map_nodes_t* mapNodes = create_map_node(); build_map_node(mapNodes, g); @@ -3265,14 +3277,14 @@ void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_ } path->num_service_endpoints_id = s->num_service_endpoints_id; - DEBUG_PC("COMPUTE UP TO K Feasible Paths A[%d]", MAX_KSP_VALUE); + DEBUG_PC("COMPUTE UP TO K Feasible Paths A[%d]", maxK); // Create A and B sets of paths to handle the YEN algorithm struct path_set_t *A = create_path_set(), *B = create_path_set(); // Add 1st Computed path into A->paths[0] duplicate_path(p, &A->paths[0]); A->numPaths++; g_free(predecessors); g_free(p); - for (gint k = 1; k < MAX_KSP_VALUE; k++) { + for (gint k = 1; k < maxK; k++) { DEBUG_PC("*************************** kth (%d) ***********************************", k); struct compRouteOutputItem_t* p = create_path_item(); duplicate_path(&A->paths[k - 1], p); @@ -3377,8 +3389,8 @@ void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_ DEBUG_PC("Number of paths: %d", path->numPaths); // For all the computed paths in A, pick the one being feasible wrt the service constraints for (gint ksp = 0; ksp < A->numPaths; ksp++) { - if (ksp >= MAX_KSP_VALUE) { - DEBUG_PC("Number Requested paths (%d) REACHED - STOP", ksp); + if (ksp >= s->kPaths_returned) { + DEBUG_PC("Number Requested/returned paths (%d) REACHED - STOP", ksp); break; } gdouble feasibleRoute = check_computed_path_feasibility(s, &A->paths[ksp]); @@ -3390,13 +3402,18 @@ void alg_comp(struct service_t* s, struct compRouteOutput_t* path, struct graph_ struct path_t* targetedPath = &path->paths[path->numPaths - 1]; duplicate_path_t(pathaux, targetedPath); print_path_t(targetedPath); - remove_path_set(A); - remove_path_set(B); - return; + //remove_path_set(A); + //remove_path_set(B); + //return; } } remove_path_set(A); remove_path_set(B); + // At least 1 out (K) paths was found, then K-SP succeded + if (path->numPaths > 0) { + DEBUG_PC("K-SP succeeded"); + return; + } // No paths found --> Issue DEBUG_PC("K-SP failed!!!"); comp_route_connection_issue_handler(path, s); diff --git a/src/pathcomp/backend/pathComp_tools.h b/src/pathcomp/backend/pathComp_tools.h index fb458d8c0..fde38f66b 100644 --- a/src/pathcomp/backend/pathComp_tools.h +++ b/src/pathcomp/backend/pathComp_tools.h @@ -354,11 +354,10 @@ struct constraint_t { #define MAX_NUM_SERVICE_ENPOINTS_ID 2 #define MAX_NUM_SERVICE_CONSTRAINTS 10 -struct service_t { - // Indentifier used to determine the used Algorithm Id, e.g., KSP - gchar algId[MAX_ALG_ID_LENGTH]; - // PATHS expected for the output - guint kPaths; +struct service_t { + gchar algId[MAX_ALG_ID_LENGTH]; // Indentifier used to determine the used Algorithm Id, e.g., KSP + guint kPaths_inspected; // PATHS expected to be inspected + guint kPaths_returned; // Maximum number of PATHS to be returned struct serviceId_t serviceId; guint service_type; // unknown, l2nm, l3nm, tapi @@ -432,7 +431,7 @@ struct pathLink_t { gchar zEndPointId[UUID_CHAR_LENGTH]; struct topology_id_t topologyId; - struct linkTopology_t linkTopologies[2]; // a p2p link (at most) can connect to devices (endpoints) attached to 2 different topologies + struct linkTopology_t linkTopologies[2]; // A p2p link (at most) can connect to devices (endpoints) attached to 2 different topologies gint numLinkTopologies; }; -- GitLab