Skip to content
Snippets Groups Projects
pathComp_tools.c 119 KiB
Newer Older
  • Learn to ignore specific revisions
  •  *
     * 	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    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;
    		}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    struct context_t* add_contextId_in_set(gchar *contextUuid, GList** set) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	// 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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    struct vertices_t* find_vertex_in_graph_context(struct graph_t *g, gchar* deviceId) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    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]);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
     * @param activeFlag
    
     *
     * 	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    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);
    
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		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) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    				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);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    				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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    struct endPoint_t* find_device_tied_endpoint(gchar* devId, gchar* endPointUuid) {
    
    	//DEBUG_PC("devId: %s ePId: %s", devId, endPointUuid);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
     * @param activeFlag
    
     *
     * 	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    void add_edge_in_targetedVertice_set(struct targetNodes_t* w, struct link_t* l, gint activeFlag) {
    
    	//DEBUG_PC("\t targetedVertex: %s", w->tVertice.nodeId);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    
    	// 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);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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));
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	// latency ms
    
    	memcpy(&e->delay, &l->latency_characteristics.fixed_latency, sizeof(gdouble));
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	// 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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    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
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
     * @param activeFlag
    
     *
     * 	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    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
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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++;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		// 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);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		DEBUG_PC("Link: %s in ContextId: %s", l->linkId, contextUuid);
    
    
    		// Check first contextUuid exists in the cSet
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		//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) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			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);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		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) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			DEBUG_PC("[%s] is PEER of [%s]", bDeviceId, v->verticeId.nodeId);
    
    			w = add_targeted_vertex_in_graph_context(v, bDeviceId);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    			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
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    				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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    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
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	build_contextSet_linklList(cSet, activeFlag);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    ////////////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    void print_contextSet(GList* set) {
    
    	DEBUG_PC("Printing the ContextSet w/ number of Elements: %d", g_list_length(set));
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    void comp_route_connection_issue_handler (struct compRouteOutput_t *path, struct service_t *s)
    {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    void duplicate_graph (struct graph_t *originalGraph, struct graph_t *destGraph)	{
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@date 2022
     */
    /////////////////////////////////////////////////////////////////////////////////////////
    void allocate_graph_resources (struct path_t *p, struct service_t *s, struct graph_t *g)
    {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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);	
    	}
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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 <ricardo.martinez@cttc.es>
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
     *	@date 2022
    
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    void allocate_graph_reverse_resources(struct path_t* p, struct service_t * s, struct graph_t* g)
    {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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 <ricardo.martinez@cttc.es>
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
     *	@date 2022
    
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    void print_path_connection_list(struct compRouteOutputList_t* routeList) {
    	g_assert(routeList);
    	for (gint i = 0; i < routeList->numCompRouteConnList; i++) {
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		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);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		DEBUG_PC("ingress - %s[%s]", rO->service_endpoints_id[0].device_uuid, 
    
    			rO->service_endpoints_id[0].endpoint_uuid);
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    		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 <ricardo.martinez@cttc.es>
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
     *	@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);
    
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    	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;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    }
    
    ///////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_tools.c
     * 	@brief Eliminate active service	path
     *
     *  @param actServPath
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@date 2022
     */
     /////////////////////////////////////////////////////////////////////////////////////////
    void destroy_active_service_path(struct activeServPath_t* actServPath) {
    	g_assert(actServPath);
    	g_free(actServPath);
    	return;
    }
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    ///////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_tools.c
     * 	@brief Eliminate active service
     *
     *  @param actService
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@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;
    
    Ricardo Martínez's avatar
    Ricardo Martínez committed
    
    ///////////////////////////////////////////////////////////////////////////////////
    /**
     * 	@file pathComp_tools.c
     * 	@brief Eliminate a requested service 
     *
     *  @param s
     *
     *	@author Ricardo Martínez <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>
     *	@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 <ricardo.martinez@cttc.es>