From 3eb152af347368b87703b2f753522738bf1fd1f8 Mon Sep 17 00:00:00 2001 From: Justin Tracey Date: Mon, 11 Mar 2019 01:24:31 -0400 Subject: [PATCH] allow for asymetric links --- src/netmirage-core/graphml.c | 85 ++++++++++++++++++++++++++++++----- src/netmirage-core/graphml.h | 3 +- src/netmirage-core/setup.c | 8 ++-- src/netmirage-core/topology.h | 12 +++-- src/netmirage-core/worker.c | 6 +-- 5 files changed, 90 insertions(+), 24 deletions(-) diff --git a/src/netmirage-core/graphml.c b/src/netmirage-core/graphml.c index 58b09d5..6cfc36d 100644 --- a/src/netmirage-core/graphml.c +++ b/src/netmirage-core/graphml.c @@ -76,7 +76,10 @@ typedef struct { // Value used in nodes' type attribute to indicate that they are a client const char* clientType; - const char* weightKey; // Key for shortest path detection + // Keys for shortest path detection + const char* weightKey; + const char* weightKeyUp; + const char* weightKeyDown; // GpUnknown state unsigned int unknownDepth; // The depth since the first unknown element @@ -98,6 +101,16 @@ typedef struct { xmlChar* packetLossId; xmlChar* jitterId; xmlChar* queueLenId; + xmlChar* weightUpId; + xmlChar* latencyUpId; + xmlChar* packetLossUpId; + xmlChar* jitterUpId; + xmlChar* queueLenUpId; + xmlChar* weightDownId; + xmlChar* latencyDownId; + xmlChar* packetLossDownId; + xmlChar* jitterDownId; + xmlChar* queueLenDownId; } edgeAttribs; // Attribute values @@ -173,6 +186,13 @@ static void graphFatalError(GraphParserState* state, const char* fmt, ...) { static void initGraphParserState(GraphParserState* state, NewNodeFunc newNode, NewLinkFunc newLink, void* userData, const char* clientType, const char* weightKey) { state->clientType = clientType; state->weightKey = weightKey; + size_t keylen = strlen(weightKey); + char* weightKeyUp = emalloc(keylen+3); + strcpy(weightKeyUp, weightKey); + state->weightKeyUp = strcat(weightKeyUp, "up"); + char* weightKeyDown = emalloc(keylen+5); + strcpy(weightKeyDown, weightKey); + state->weightKeyDown = strcat(weightKeyDown, "down"); state->newNodeFunc = newNode; state->newLinkFunc = newLink; state->userData = userData; @@ -272,15 +292,26 @@ static void graphStartElement(void* ctx, const xmlChar* name, const xmlChar** at else CHECK_SET_ATTR("bandwidthdown", true, true, false, node, bandwidthDown) } else if (xmlStrEqual(keyFor, (const xmlChar*)"edge")) { CHECK_SET_ATTR(state->weightKey, false, true, false, edge, weight) + else CHECK_SET_ATTR(state->weightKeyUp, false, true, false, edge, weightUp) + else CHECK_SET_ATTR(state->weightKeyDown, false, true, false, edge, weightDown) CHECK_SET_ATTR("latency", true, true, false, edge, latency) else CHECK_SET_ATTR("packetloss", true, true, false, edge, packetLoss) else CHECK_SET_ATTR("jitter", true, true, false, edge, jitter) else CHECK_SET_ATTR("queue_len", true, false, false, edge, queueLen) + else CHECK_SET_ATTR("latencyup", true, true, false, edge, latencyUp) + else CHECK_SET_ATTR("packetlossup", true, true, false, edge, packetLossUp) + else CHECK_SET_ATTR("jitterup", true, true, false, edge, jitterUp) + else CHECK_SET_ATTR("queue_lenup", true, false, false, edge, queueLenUp) + else CHECK_SET_ATTR("latencydown", true, true, false, edge, latencyDown) + else CHECK_SET_ATTR("packetlossdown", true, true, false, edge, packetLossDown) + else CHECK_SET_ATTR("jitterdown", true, true, false, edge, jitterDown) + else CHECK_SET_ATTR("queue_lendown", true, false, false, edge, queueLenDown) } } unknown = true; } else if (xmlStrEqual(name, (const xmlChar*)"graph")) { - if (state->edgeAttribs.weightId == NULL) graphFatalError(state, "The topology file did not include an edge parameter '%s' for route calculations. Specify --weight to use a different attribute.\n", state->weightKey); + if (state->edgeAttribs.weightId == NULL && (state->edgeAttribs.weightUpId == NULL || state->edgeAttribs.weightDownId == NULL)) + graphFatalError(state, "The topology file did not include an edge parameter '%s' for route calculations. Specify --weight to use a different attribute.\n", state->weightKey); for (const xmlChar** att = atts; *att; att += 2) { if (xmlStrEqual(att[0], (const xmlChar*)"edgedefault")) { state->defaultUndirected = xmlStrEqual(att[1], (const xmlChar*)"undirected"); @@ -334,11 +365,16 @@ static void graphStartElement(void* ctx, const xmlChar* name, const xmlChar** at copyXmlStr(&state->linkTargetId, target); state->link.sourceName = (const char*)state->linkSourceId.data; state->link.targetName = (const char*)state->linkTargetId.data; - state->link.weight = INFINITY; - state->link.t.latency = 0.0; - state->link.t.packetLoss = 0.0; - state->link.t.jitter = 0.0; - state->link.t.queueLen = 0; + state->link.weightUp = INFINITY; + state->link.weightDown = INFINITY; + state->link.t.latencyUp = 0.0; + state->link.t.packetLossUp = 0.0; + state->link.t.jitterUp = 0.0; + state->link.t.latencyDown = 0.0; + state->link.t.packetLossDown = 0.0; + state->link.t.jitterDown = 0.0; + state->link.t.queueLenUp = 0; + state->link.t.queueLenDown = 0; state->mode = GpEdge; } } else unknown = true; @@ -412,16 +448,41 @@ static void graphEndElement(void* ctx, const xmlChar* name) { case GpEdge: if (state->edgeAttribs.weightId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.weightId)) { - state->link.weight = strtof((const char*)value, NULL); + state->link.weightUp = state->link.weightDown = strtof((const char*)value, NULL); + lprintf(LogDebug, "weight set to %f\n", state->link.weightUp); + } else if (state->edgeAttribs.weightUpId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.weightUpId)) { + state->link.weightUp = strtof((const char*)value, NULL); + lprintf(LogDebug, "weightUp set to %f\n", state->link.weightUp); + } else if (state->edgeAttribs.weightDownId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.weightDownId)) { + state->link.weightDown = strtof((const char*)value, NULL); + lprintf(LogDebug, "weightDown set to %f\n", state->link.weightDown); } if (state->edgeAttribs.latencyId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.latencyId)) { - state->link.t.latency = strtod((const char*)value, NULL); + state->link.t.latencyUp = state->link.t.latencyDown = strtod((const char*)value, NULL); } else if (state->edgeAttribs.packetLossId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.packetLossId)) { - state->link.t.packetLoss = strtod((const char*)value, NULL); + state->link.t.packetLossUp = state->link.t.packetLossDown = strtod((const char*)value, NULL); } else if (state->edgeAttribs.jitterId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.jitterId)) { - state->link.t.jitter = strtod((const char*)value, NULL); + state->link.t.jitterUp = state->link.t.jitterDown = strtod((const char*)value, NULL); } else if (state->edgeAttribs.queueLenId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.queueLenId)) { - state->link.t.queueLen = (uint32_t)strtoul((const char*)value, NULL, 10); + state->link.t.queueLenUp = state->link.t.queueLenDown = (uint32_t)strtoul((const char*)value, NULL, 10); + } else if (state->edgeAttribs.latencyUpId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.latencyUpId)) { + state->link.t.latencyUp = strtod((const char*)value, NULL); + lprintf(LogDebug, "latencyUp set to %f\n", state->link.t.latencyUp); + } else if (state->edgeAttribs.packetLossUpId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.packetLossUpId)) { + state->link.t.packetLossUp = strtod((const char*)value, NULL); + } else if (state->edgeAttribs.jitterUpId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.jitterUpId)) { + state->link.t.jitterUp = strtod((const char*)value, NULL); + } else if (state->edgeAttribs.queueLenUpId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.queueLenUpId)) { + state->link.t.queueLenUp = (uint32_t)strtoul((const char*)value, NULL, 10); + } else if (state->edgeAttribs.latencyDownId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.latencyDownId)) { + state->link.t.latencyDown = strtod((const char*)value, NULL); + lprintf(LogDebug, "latencyDown set to %f\n", state->link.t.latencyDown); + } else if (state->edgeAttribs.packetLossDownId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.packetLossDownId)) { + state->link.t.packetLossDown = strtod((const char*)value, NULL); + } else if (state->edgeAttribs.jitterDownId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.jitterDownId)) { + state->link.t.jitterDown = strtod((const char*)value, NULL); + } else if (state->edgeAttribs.queueLenDownId && xmlStrEqual(state->dataKey.data, state->edgeAttribs.queueLenDownId)) { + state->link.t.queueLenDown = (uint32_t)strtoul((const char*)value, NULL, 10); } break; diff --git a/src/netmirage-core/graphml.h b/src/netmirage-core/graphml.h index ee79b16..6b186c1 100644 --- a/src/netmirage-core/graphml.h +++ b/src/netmirage-core/graphml.h @@ -36,7 +36,8 @@ typedef struct { const char* sourceName; const char* targetName; - float weight; + float weightUp; + float weightDown; TopoLink t; } GmlLink; diff --git a/src/netmirage-core/setup.c b/src/netmirage-core/setup.c index 0610063..efeec71 100644 --- a/src/netmirage-core/setup.c +++ b/src/netmirage-core/setup.c @@ -358,12 +358,12 @@ static int gmlAddLink(const GmlLink* link, void* userData) { return 1; } DO_OR_RETURN(workAddLink(sourceId, targetId, sourceState->addr, targetState->addr, macs, ctx->mtu, &link->t)); - if (link->weight < 0.f) { - lprintf(LogError, "The link from '%s' to '%s' in the topology has negative weight %f, which is not supported.\n", link->sourceName, link->targetName, link->weight); + if (link->weightUp < 0.f || link->weightDown < 0.f) { + lprintf(LogError, "The link from '%s' to '%s' in the topology has negative weight %f, which is not supported.\n", link->sourceName, link->targetName, link->weightUp < link->weightDown ? link->weightUp : link->weightDown); return 1; } else { - rpSetWeight(ctx->routes, sourceId, targetId, link->weight); - rpSetWeight(ctx->routes, targetId, sourceId, link->weight); + rpSetWeight(ctx->routes, sourceId, targetId, link->weightUp); + rpSetWeight(ctx->routes, targetId, sourceId, link->weightDown); } } return 0; diff --git a/src/netmirage-core/topology.h b/src/netmirage-core/topology.h index da89f0d..844cb42 100644 --- a/src/netmirage-core/topology.h +++ b/src/netmirage-core/topology.h @@ -41,8 +41,12 @@ typedef struct { // A link represents a network connection between nodes typedef struct { - double latency; - double packetLoss; - double jitter; - uint32_t queueLen; + double latencyUp; + double packetLossUp; + double jitterUp; + uint32_t queueLenUp; + double latencyDown; + double packetLossDown; + double jitterDown; + uint32_t queueLenDown; } TopoLink; diff --git a/src/netmirage-core/worker.c b/src/netmirage-core/worker.c index dfeb2d5..28e00ea 100644 --- a/src/netmirage-core/worker.c +++ b/src/netmirage-core/worker.c @@ -434,7 +434,7 @@ int workerSetSelfLink(nodeId id, const TopoLink* link) { if (intfIdx == -1) return err; // We apply the whole shaping in one direction in order to respect jitter - return netSetEgressShaping(net, intfIdx, link->latency, link->jitter, link->packetLoss, 0.0, link->queueLen, true); + return netSetEgressShaping(net, intfIdx, link->latencyDown, link->jitterDown, link->packetLossDown, 0.0, link->queueLenDown, true); } static int workGetLinkEndpoints(nodeId id1, nodeId id2, char* name1, char* name2, netContext** net1, netContext** net2, char* intf1, char* intf2) { @@ -513,9 +513,9 @@ int workerAddLink(nodeId sourceId, nodeId targetId, ip4Addr sourceIp, ip4Addr ta err = buildVethPair(sourceNet, targetNet, sourceIntf, targetIntf, sourceIp, targetIp, &macs[0], &macs[1], mtu, &sourceIntfIdx, &targetIntfIdx); if (err != 0) return err; - err = netSetEgressShaping(sourceNet, sourceIntfIdx, link->latency, link->jitter, link->packetLoss, 0.0, link->queueLen, true); + err = netSetEgressShaping(sourceNet, sourceIntfIdx, link->latencyDown, link->jitterDown, link->packetLossDown, 0.0, link->queueLenDown, true); if (err != 0) return err; - err = netSetEgressShaping(targetNet, targetIntfIdx, link->latency, link->jitter, link->packetLoss, 0.0, link->queueLen, true); + err = netSetEgressShaping(targetNet, targetIntfIdx, link->latencyUp, link->jitterUp, link->packetLossUp, 0.0, link->queueLenUp, true); if (err != 0) return err; err = netModifyRoute(sourceNet, false, netGetTableId(TableMain), ScopeLink, CreatorAdmin, targetIp, 32, 0, sourceIntfIdx, true);