Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 73 additions & 12 deletions src/netmirage-core/graphml.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion src/netmirage-core/graphml.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ typedef struct {
const char* sourceName;
const char* targetName;

float weight;
float weightUp;
float weightDown;
TopoLink t;
} GmlLink;

Expand Down
8 changes: 4 additions & 4 deletions src/netmirage-core/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 8 additions & 4 deletions src/netmirage-core/topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
6 changes: 3 additions & 3 deletions src/netmirage-core/worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down