From 21e9004d245e55c07162bc71920dd9e4d48295a1 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Thu, 20 Jun 2019 12:18:40 -0400 Subject: [PATCH 01/12] [WIP] traceroute gui [webapp] --- webapp/config/servers_default.json | 26 ++++++++++++++++ webapp/lib/config.go | 3 ++ webapp/static/js/webapp.js | 49 ++++++++++++++++++++++++++++-- webapp/template/index.html | 23 ++++++++++++++ 4 files changed, 98 insertions(+), 3 deletions(-) diff --git a/webapp/config/servers_default.json b/webapp/config/servers_default.json index 08f24bd8..4a12e199 100644 --- a/webapp/config/servers_default.json +++ b/webapp/config/servers_default.json @@ -96,5 +96,31 @@ "addr": "203.230.60.98", "port": 40002 } + ], + "traceroute": [ + { + "name": "17-ffaa:0:1107 Attachment Point", + "isdas": "17-ffaa:0:1107", + "addr": "192.33.93.195", + "port": 40002 + }, + { + "name": "18-ffaa:0:1202 Attachment Point", + "isdas": "18-ffaa:0:1202", + "addr": "128.105.21.208", + "port": 40002 + }, + { + "name": "19-ffaa:0:1303 Attachment Point", + "isdas": "19-ffaa:0:1303", + "addr": "141.44.25.144", + "port": 40002 + }, + { + "name": "20-ffaa:0:1404 Attachment Point", + "isdas": "20-ffaa:0:1404", + "addr": "203.230.60.98", + "port": 40002 + } ] } diff --git a/webapp/lib/config.go b/webapp/lib/config.go index 7c176a5e..624fc68e 100644 --- a/webapp/lib/config.go +++ b/webapp/lib/config.go @@ -101,6 +101,9 @@ func GenServerNodeDefaults(srcpath string) { serIaDef + `", "addr":"` + serDefAddr + `","port":` + serPortDefSen + `}], `) jsonBuf = append(jsonBuf, json...) json = []byte(`"echo": [{"name":"localhost","isdas":"` + + serIaDef + `", "addr":"` + serDefAddr + `","port":` + serPortDefSen + `}], `) + jsonBuf = append(jsonBuf, json...) + json = []byte(`"traceroute": [{"name":"localhost","isdas":"` + serIaDef + `", "addr":"` + serDefAddr + `","port":` + serPortDefSen + `}]`) jsonBuf = append(jsonBuf, json...) diff --git a/webapp/static/js/webapp.js b/webapp/static/js/webapp.js index c690f7f1..ffbd75c5 100644 --- a/webapp/static/js/webapp.js +++ b/webapp/static/js/webapp.js @@ -119,13 +119,13 @@ function showOnlyConsoleGraphs(activeApp) { $('#echo-continuous').css("display", (activeApp == "echo") ? "block" : "none"); var isConsole = (activeApp == "bwtester" || activeApp == "camerapp" - || activeApp == "sensorapp" || activeApp == "echo"); + || activeApp == "sensorapp" || activeApp == "echo" || activeApp == "traceroute"); $('.stdout').css("display", isConsole ? "block" : "none"); } function handleSwitchTabs() { var activeApp = $('.nav-tabs .active > a').attr('name'); - var isCont = (activeApp == "bwtester" || activeApp == "echo"); + var isCont = (activeApp == "bwtester" || activeApp == "echo" || activeApp == "traceroute"); enableContControls(isCont); // show/hide graphs for bwtester showOnlyConsoleGraphs(activeApp); @@ -364,6 +364,8 @@ function manageTestData() { requestBwTestByTime(form_data); } else if (activeApp == "echo") { requestEchoByTime(form_data); + } else if (activeApp == "traceroute") { + requestTraceRouteByTime(form_data); } lastTimeBwDb = now; }, dataIntervalMs); @@ -467,6 +469,42 @@ function requestEchoByTime(form_data) { }); } +function requestTraceRouteByTime(form_data) { + $.post("/gettraceroutebytime", form_data, function(json) { + var d = JSON.parse(json); + console.info('resp:', JSON.stringify(d)); + if (d != null) { + if (d.active != null) { + $('#switch_cont').prop("checked", d.active); + if (d.active) { + enableTestControls(false); + lockTab("traceroute"); + } else { + enableTestControls(true); + releaseTabs(); + clearInterval(intervalGraphData); + } + } + if (d.graph != null) { + // write data on graph + for (var i = 0; i < d.graph.length; i++) { + if (d.graph[i].CmdOutput != null + && d.graph[i].CmdOutput != "") { + // result returned, display it and reset progress + handleEndCmdDisplay(d.graph[i].CmdOutput); + } + + console.info(JSON.stringify(data)); + console.info('continous traceroute', 'duration:', + d.graph[i].ActualDuration, 'ms'); + + // TODO (mwfarb): implement traceroute graph + } + } + } + }); +} + function refreshTickData(chart, newTime) { var x = newTime, y = null; var series0 = chart.series[0]; @@ -587,7 +625,8 @@ function command(continuous) { name : "apps", value : activeApp }); - if (activeApp == "bwtester" || activeApp == "echo") { + if (activeApp == "bwtester" || activeApp == "echo" + || activeApp == "traceroute") { // add extra bwtester options required form_data.push({ name : "continuous", @@ -639,6 +678,8 @@ function command(continuous) { } else if (activeApp == "echo") { // check for usable data for graphing handleContResponse(resp, continuous, startTime); + } else if (activeApp == "traceroute") { + handleContResponse(resp, continuous, startTime); } else { handleGeneralResponse(); } @@ -685,6 +726,7 @@ function lockTab(href) { enableTab("camerapp", "camerapp" == href); enableTab("sensorapp", "sensorapp" == href); enableTab("echo", "echo" == href); + enableTab("traceroute", "traceroute" == href); } function releaseTabs() { @@ -692,6 +734,7 @@ function releaseTabs() { enableTab("camerapp", true); enableTab("sensorapp", true); enableTab("echo", true); + enableTab("traceroute", true); } function enableTab(href, enable) { diff --git a/webapp/template/index.html b/webapp/template/index.html index 33ac35de..c307143d 100644 --- a/webapp/template/index.html +++ b/webapp/template/index.html @@ -69,6 +69,7 @@

SCIONLab Apps

  • camerapp
  • sensorapp
  • echo
  • +
  • traceroute
  • @@ -265,6 +266,28 @@

    SCIONLab Apps

    + + +
    + +
    + + + +
    + +
    Interval: sec. + Additional Argument: + +
    + + From d6fc16720b3f6e1f230da72eb6637464134647b1 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Tue, 9 Jul 2019 10:55:34 -0400 Subject: [PATCH 02/12] adding test json --- webapp/static/js/webapp.js | 1 - webapp/tests/asviz/bwtester-d.json | 16 +++++++ webapp/tests/asviz/echo-d.json | 15 ++++++ webapp/tests/asviz/traceroute-d.json | 71 ++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 webapp/tests/asviz/bwtester-d.json create mode 100644 webapp/tests/asviz/echo-d.json create mode 100644 webapp/tests/asviz/traceroute-d.json diff --git a/webapp/static/js/webapp.js b/webapp/static/js/webapp.js index ffbd75c5..7f5f479a 100644 --- a/webapp/static/js/webapp.js +++ b/webapp/static/js/webapp.js @@ -494,7 +494,6 @@ function requestTraceRouteByTime(form_data) { handleEndCmdDisplay(d.graph[i].CmdOutput); } - console.info(JSON.stringify(data)); console.info('continous traceroute', 'duration:', d.graph[i].ActualDuration, 'ms'); diff --git a/webapp/tests/asviz/bwtester-d.json b/webapp/tests/asviz/bwtester-d.json new file mode 100644 index 00000000..cbc37ce1 --- /dev/null +++ b/webapp/tests/asviz/bwtester-d.json @@ -0,0 +1,16 @@ +{ + "graph": [ + { + "Inserted": 1562683731800, + "ActualDuration": 5041, + "CSBandwidth": 80000, + "CSThroughput": 80000, + "SCBandwidth": 80000, + "SCThroughput": 80000, + "Error": "", + "Path": "Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450", + "Log": "t=2019-07-09T10:48:46-0400 lvl=dbug msg=\"Path selection algorithm choice\" path=\"Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450\" score=0.993\nt=2019-07-09T10:48:46-0400 lvl=dbug msg=\"Registered with dispatcher\" addr=\"1-ff00:0:111,[127.0.0.1]:30001 (UDP)\"\nClient DC \tNext Hop [127.0.0.74]:31070\tServer Host [127.0.0.2]:30101\nt=2019-07-09T10:48:46-0400 lvl=dbug msg=\"Registered with dispatcher\" addr=\"1-ff00:0:111,[127.0.0.1]:30002 (UDP)\"\n\nTest parameters:\nclientDCAddr -> serverDCAddr 1-ff00:0:111,[127.0.0.1]:30002 (UDP) -> 1-ff00:0:112,[127.0.0.2]:30101 (UDP)\nclient->server: 3 seconds, 1000 bytes, 30 packets\nserver->client: 3 seconds, 1000 bytes, 30 packets\n\nS->C results\nAttempted bandwidth: 80000 bps / 0.08 Mbps\nAchieved bandwidth: 80000 bps / 0.08 Mbps\nLoss rate: 0 %\nInterarrival time variance: 23ms, average interarrival time: 103ms\nInterarrival time min: 82ms, interarrival time max: 127ms\nWe need to sleep for 2 seconds before we can get the results\n\nC->S results\nAttempted bandwidth: 80000 bps / 0.08 Mbps\nAchieved bandwidth: 80000 bps / 0.08 Mbps\nLoss rate: 0 %\nInterarrival time variance: 23ms, average interarrival time: 103ms\nInterarrival time min: 82ms, interarrival time max: 126ms\n" + } + ], + "active": false +} diff --git a/webapp/tests/asviz/echo-d.json b/webapp/tests/asviz/echo-d.json new file mode 100644 index 00000000..2204c9e7 --- /dev/null +++ b/webapp/tests/asviz/echo-d.json @@ -0,0 +1,15 @@ +{ + "graph": [ + { + "Inserted": 1562683883823, + "ActualDuration": 263, + "ResponseTime": 13.352, + "RunTime": 226.525, + "PktLoss": 0, + "CmdOutput": "Using path:\n Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450\n104 bytes from 1-ff00:0:112,[127.0.0.2] scmp_seq=0 time=13.352ms\n\n--- 1-ff00:0:112,[[127.0.0.2]] statistics ---\n1 packets transmitted, 1 received, 0% packet loss, time 226.525ms\n", + "Path": "Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450", + "Error": "" + } + ], + "active": false +} diff --git a/webapp/tests/asviz/traceroute-d.json b/webapp/tests/asviz/traceroute-d.json new file mode 100644 index 00000000..cc80ccb3 --- /dev/null +++ b/webapp/tests/asviz/traceroute-d.json @@ -0,0 +1,71 @@ +{ + "graph": [ + { + "Inserted": 1562179946689, + "ActualDuration": 50, + "TrHops": [ + { + "HopIa": "1-ff00:0:111", + "HopAddr": "127.0.0.74", + "IntfID": 103, + "RespTime1": 0.896, + "RespTime2": 1.482, + "RespTime3": 1.915 + }, + { + "HopIa": "1-ff00:0:112", + "HopAddr": "127.0.0.82", + "IntfID": 4094, + "RespTime1": 1.39, + "RespTime2": 0.772, + "RespTime3": 0.856 + }, + { + "HopIa": "1-ff00:0:112", + "HopAddr": "127.0.0.2", + "IntfID": -1, + "RespTime1": 1.057, + "RespTime2": 0.85, + "RespTime3": 0.866 + } + ], + "CmdOutput": "Using path:\n Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450\n0 1-ff00:0:111,[127.0.0.74] IfID=103 896µs 1.482ms 1.915ms\n1 1-ff00:0:112,[127.0.0.82] IfID=4094 1.39ms 772µs 856µs\n2 1-ff00:0:112,[127.0.0.2] 1.057ms 850µs 866µs\n", + "Path": "Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450", + "Error": "" + }, + { + "Inserted": 1562179946298, + "ActualDuration": 73, + "TrHops": [ + { + "HopIa": "1-ff00:0:111", + "HopAddr": "127.0.0.74", + "IntfID": 103, + "RespTime1": 1.189, + "RespTime2": 0.847, + "RespTime3": 0.707 + }, + { + "HopIa": "1-ff00:0:112", + "HopAddr": "127.0.0.82", + "IntfID": 4094, + "RespTime1": 5.503, + "RespTime2": 1.127, + "RespTime3": 1.486 + }, + { + "HopIa": "1-ff00:0:112", + "HopAddr": "127.0.0.2", + "IntfID": -1, + "RespTime1": 1.051, + "RespTime2": 1.331, + "RespTime3": 3.499 + } + ], + "CmdOutput": "Using path:\n Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450\n0 1-ff00:0:111,[127.0.0.74] IfID=103 1.189ms 847µs 707µs\n1 1-ff00:0:112,[127.0.0.82] IfID=4094 5.503ms 1.127ms 1.486ms\n2 1-ff00:0:112,[127.0.0.2] 1.051ms 1.331ms 3.499ms\n", + "Path": "Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450", + "Error": "" + } + ], + "active": false +} From 1064fbf1af3afcb9e792f69b2d4763083b7af588 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Fri, 20 Sep 2019 15:08:22 -0400 Subject: [PATCH 03/12] [webapp] WIP Path Latency Survey moving path text color fix here adding test link text adding latency placeholders in path lists updated path header, fixed path latency text adding traceroute last call convert incoming paths to hash map tr appears in wrong order, but path latency updates now use best results find min/max and report min' adding stats object to trace needed stats adding stats to path graph restore traceroute --- webapp/static/css/style-viz.css | 4 + webapp/static/js/asviz.js | 7 +- webapp/static/js/tab-paths.js | 150 +++++++++++++++++++++++++++---- webapp/static/js/tab-topocola.js | 26 +++++- webapp/static/js/webapp.js | 32 ++++++- webapp/template/index.html | 17 +++- 6 files changed, 208 insertions(+), 28 deletions(-) diff --git a/webapp/static/css/style-viz.css b/webapp/static/css/style-viz.css index da9270dc..a67c5055 100644 --- a/webapp/static/css/style-viz.css +++ b/webapp/static/css/style-viz.css @@ -229,6 +229,10 @@ ul.tree li.open>ul { ul.tree li a { color: black; text-decoration: none; +} + +.path-text { + color: white; padding-left: 5px; /* background shape */ padding-right: 5px; /* background shape */ border-radius: 10px; /* background shape */ diff --git a/webapp/static/js/asviz.js b/webapp/static/js/asviz.js index 3a082fb9..6f7e0fb4 100644 --- a/webapp/static/js/asviz.js +++ b/webapp/static/js/asviz.js @@ -68,7 +68,8 @@ function setPaths(type, idx, open) { } else if (type == 'UP') { addSegments(resUp, idx, num, colorSegUp, type); } else if (type == 'PATH') { - addPaths(resPath, idx, num, colorPaths, type); + var latencies = getPathLatencyAvg(formatPathString(resPath, idx, type)); + addPaths(resPath, idx, num, colorPaths, type, latencies); } self.segType = type; self.segNum = idx; @@ -111,9 +112,9 @@ function formatPathString(res, idx, type) { /* * Adds D3 forwarding path links with arrows and a title to paths graph. */ -function addPaths(res, idx, num, color, type) { +function addPaths(res, idx, num, color, type, latencies) { if (graphPath) { - drawPath(res, idx, color); + drawPath(res, idx, color, latencies); if (res.if_lists[idx].expTime) { drawTitle(type + ' ' + num, color, res.if_lists[idx].expTime); } else { diff --git a/webapp/static/js/tab-paths.js b/webapp/static/js/tab-paths.js index 69e56990..efb9f1b5 100644 --- a/webapp/static/js/tab-paths.js +++ b/webapp/static/js/tab-paths.js @@ -3,7 +3,7 @@ var iaLabels; var iaLocations = []; var iaGeoLoc; var g = {}; -var jPathColors = []; +var jPathsAvailable = {}; function setupDebug(src, dst) { var src = $('#ia_cli').val(); @@ -26,14 +26,99 @@ function path_colors(n) { } function getPathColor(hops) { - var idx = jPathColors.indexOf(hops + ''); - if (idx < 0) { + if (!jPathsAvailable[hops]) { return cMissingPath; } else { - return path_colors(idx); + return jPathsAvailable[hops].color; } } +/** + * Updates statistics. + */ +function updateStats(fStat, oldStat) { + var newStat = {} + newStat.Last = fStat; + newStat.Num = oldStat ? (oldStat.Num + 1) : 1; + newStat.Avg = oldStat ? (((oldStat.Avg * oldStat.Num) + fStat) / newStat.Num) + : fStat; + newStat.Min = oldStat ? Math.min(fStat, oldStat.Min) : fStat; + newStat.Max = oldStat ? Math.max(fStat, oldStat.Max) : fStat; + return newStat; +} + +function getPathLatencyLast(hops) { + return getPathLatency(hops, false); +} + +function getPathLatencyAvg(hops) { + return getPathLatency(hops, true); +} + +/** + * Returns array of interface and full path latency stats. + */ +function getPathLatency(hops, avg) { + var path = {}; + if (jPathsAvailable[hops]) { + path = jPathsAvailable[hops]; + } + var latencies = []; + for (var i = 0; i < path.interfaces.length; i++) { + if (path.interfaces[i].latency) { + latencies.push(avg ? path.interfaces[i].latency.Last + : path.interfaces[i].latency.Avg); + } else { + latencies.push(undefined); + } + } + if (path.latency) { + latencies.push(avg ? path.latency.Last : path.latency.Avg); + } else { + latencies.push(undefined); + } + return latencies; +} + +function setEchoLatency(hops, latency) { + var path = {}; + if (jPathsAvailable[hops]) { + path = jPathsAvailable[hops]; + } + path.latency = updateStats(latency, path.latency); + var latStr = parseFloat(path.latency.Last).toFixed(1); + $('#path-lat-' + path.listIdx).html(latStr); + jPathsAvailable[hops] = path; +} + +function setTracerouteLatency(hops, interfaces) { + var path = {}; + if (jPathsAvailable[hops]) { + path = jPathsAvailable[hops]; + } + for (var i = 0; i < interfaces.length; i++) { + var if_ = interfaces[i]; + if (i < interfaces.length - 1) { + path.interfaces[i].addr = if_.HopAddr; + path.interfaces[i].latency = updateStats(if_.RespTime1, + path.interfaces[i].latency); + path.interfaces[i].latency = updateStats(if_.RespTime2, + path.interfaces[i].latency); + path.interfaces[i].latency = updateStats(if_.RespTime3, + path.interfaces[i].latency); + var latStr = parseFloat(path.interfaces[i].latency.Last).toFixed(1); + $('#path-lat-' + path.listIdx + '-' + i).html(latStr); + } else { + path.latency = updateStats(if_.RespTime1, path.latency); + path.latency = updateStats(if_.RespTime2, path.latency); + path.latency = updateStats(if_.RespTime3, path.latency); + var latStr = parseFloat(path.latency.Last).toFixed(1); + $('#path-lat-' + path.listIdx).html(latStr); + } + } + jPathsAvailable[hops] = path; +} + function isConfigComplete(data, textStatus, jqXHR) { console.log(JSON.stringify(data)); g['nodes_xml_url'] = data.nodes_xml_url; @@ -376,11 +461,18 @@ function get_path_html(paths, csegs, usegs, dsegs, show_segs) { if_ = ent.Path.Interfaces; var hops = if_.length / 2; - var style = "style='background-color: " - + getPathColor(formatPathJson(paths, parseInt(p))) + "; '"; - html += "
  • PATH " + (parseInt(p) + 1) - + " " + hops + ""; + var pathStr = formatPathJson(paths, parseInt(p)); + var latencies = getPathLatencyAvg(pathStr); + var latencyPath = latencies[latencies.length - 1]; + var latPathStr = latencyPath ? parseFloat(latencyPath).toFixed(1) : ''; + var aStyle = "style='background-color:" + getPathColor(pathStr) + ";'"; + var latStyle = "style='color:purple; position:absolute; right:0;'"; + html += "
  • PATH " + + (parseInt(p) + 1) + " " + hops + + " " + + latPathStr + ""; exp.setUTCSeconds(ent.Path.ExpTime); html += ""; } @@ -662,6 +757,34 @@ function get_nonseg_links(paths, lType) { return hops; } +function addAvailablePaths(paths) { + Object.keys(jPathsAvailable).forEach(function(key) { + jPathsAvailable[key].listIdx = undefined; // reset + }); + for (var idx = 0; idx < paths.length; idx++) { + var hops = formatPathJson(paths, idx, 'PATH'); + if (!jPathsAvailable[hops]) { + jPathsAvailable[hops] = {}; + } + // update path preserving old values + var path = jPathsAvailable[hops]; + var pathLen = Object.keys(jPathsAvailable).length; + path.interfaces = []; + var ifs = paths[idx].Entry.Path.Interfaces; + for (var i = 0; i < ifs.length; i++) { + var if_ = {}; + if_.ifid = ifs[i].IfID; + if_.isdas = iaRaw2Read(ifs[i].RawIsdas); + path.interfaces.push(if_); + } + path.expTime = paths[idx].Entry.Path.ExpTime; + path.mtu = paths[idx].Entry.Path.Mtu; + path.color = path_colors(pathLen - 1); + path.listIdx = idx; + jPathsAvailable[hops] = path; + } +} + function requestPaths() { // make sure to get path topo after IAs are loaded var form_data = $('#command-form').serializeArray(); @@ -685,12 +808,7 @@ function requestPaths() { resDown = resSegs.down_segments; // store incoming paths - for (var idx = 0; idx < resPath.if_lists.length; idx++) { - var hops = formatPathString(resPath, idx, 'PATH'); - if (!jPathColors.includes(hops)) { - jPathColors.push(hops); - } - } + addAvailablePaths(data.paths); jTopo = get_json_path_links(resPath, resCore, resUp, resDown); $('#path-info').html( diff --git a/webapp/static/js/tab-topocola.js b/webapp/static/js/tab-topocola.js index bb40f4a0..247b6466 100644 --- a/webapp/static/js/tab-topocola.js +++ b/webapp/static/js/tab-topocola.js @@ -327,6 +327,17 @@ function update() { }); markerPath.exit().remove(); + svgPath.selectAll("text.latency").remove(); + var markerText = pathsg.selectAll("path.latency").data(markerLinks) + markerText.enter().append("text").attr("dy", ".35em").attr("text-anchor", + "middle").style("font-size", "12px").style("fill", "purple").attr( + "class", function(d) { + return "latency " + d.type; + }).text(function(d) { + return d.latency ? parseFloat(d.latency).toFixed(1) : ''; + }); + markerText.exit().remove(); + var node = circlesg.selectAll(".node").data(realGraphNodes, function(d) { return d.name; }) @@ -399,6 +410,13 @@ function update() { path.attr("d", linkStraight); markerPath.attr("d", linkArc); node.attr("transform", nodeTransform); + + markerText.attr("x", function(d) { + return ((d.source.x + d.target.x) / 2); + }).attr("y", function(d) { + return ((d.source.y + d.target.y) / 2); + }); + }); colaPath.start(50, 100, 200); @@ -591,7 +609,7 @@ function addFixedLabel(label, x, y, lastLabel) { /* * Post-rendering method to draw path arcs for the given path and color. */ -function drawPath(res, path, color) { +function drawPath(res, path, color, latencies) { // get the index of the routes to render var routes = []; if (path < 0) { @@ -627,12 +645,16 @@ function drawPath(res, path, color) { for (var i = 0; i < path_ids.length - 1; i++) { // prevent src == dst links from being formed if (path_ids[i] != path_ids[i + 1]) { + console.warn(latencies) + var latInterIntra = latencies ? (latencies[(i * 2) + 1] + latencies[(i * 2) + 2]) + : undefined; graphPath.links.push({ "color" : color, "path" : true, "source" : graphPath["ids"][path_ids[i]], "target" : graphPath["ids"][path_ids[i + 1]], - "type" : "PARENT" + "type" : "PARENT", + "latency" : latInterIntra, }); } } diff --git a/webapp/static/js/webapp.js b/webapp/static/js/webapp.js index c609ebf9..c9b5a846 100644 --- a/webapp/static/js/webapp.js +++ b/webapp/static/js/webapp.js @@ -463,11 +463,17 @@ function requestEchoByTime(form_data) { data.runTime = d.graph[i].ActualDuration; } console.info(JSON.stringify(data)); - console.info('continous echo', 'duration:', + console.info('continuous echo', 'duration:', d.graph[i].ActualDuration, 'ms'); // use the time the test began var time = d.graph[i].Inserted - d.graph[i].ActualDuration; updatePingGraph(chartSE, data, time) + + // update latency stats, when valid + if (d.graph[i].ResponseTime > 0) { + setEchoLatency(d.graph[i].Path.match("\\[.*]"), + d.graph[i].ResponseTime); + } } } } @@ -480,10 +486,10 @@ function requestTraceRouteByTime(form_data) { console.info('resp:', JSON.stringify(d)); if (d != null) { if (d.active != null) { - $('#switch_cont').prop("checked", d.active); if (d.active) { enableTestControls(false); lockTab("traceroute"); + failContinuousOff(); } else { enableTestControls(true); releaseTabs(); @@ -498,11 +504,29 @@ function requestTraceRouteByTime(form_data) { // result returned, display it and reset progress handleEndCmdDisplay(d.graph[i].CmdOutput); } - - console.info('continous traceroute', 'duration:', + // var data = { + // 'responseTime' : d.graph[i].ResponseTime, + // 'runTime' : d.graph[i].RunTime, + // 'loss' : d.graph[i].PktLoss, + // 'path' : d.graph[i].Path, + // 'error' : d.graph[i].Error, + // }; + // if (data.runTime == 0) { + // // for other errors, use execution time + // data.runTime = d.graph[i].ActualDuration; + // } + // console.info(JSON.stringify(data)); + console.info('continuous traceroute', 'duration:', d.graph[i].ActualDuration, 'ms'); + // use the time the test began + var time = d.graph[i].Inserted - d.graph[i].ActualDuration; + // updatePingGraph(chartSE, data, time) // TODO (mwfarb): implement traceroute graph + + // update latency stats + setTracerouteLatency(d.graph[i].Path.match("\\[.*]"), + d.graph[i].TrHops); } } } diff --git a/webapp/template/index.html b/webapp/template/index.html index ca095757..8bc402e5 100644 --- a/webapp/template/index.html +++ b/webapp/template/index.html @@ -411,10 +411,21 @@

    SCIONLab Apps

    -

    - Available Paths hops -

    + +

    +

    + + Available Paths Hops Latency + +

    From 65b75a6a9f2d3930ed75092fb67d5531df648ef3 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Mon, 7 Oct 2019 15:35:13 -0400 Subject: [PATCH 04/12] adding survey with continuous switch --- webapp/lib/traceroutecont.go | 3 +- webapp/tests/asviz/traceroute-d.json | 77 +++++++++++----------------- webapp/web/static/js/asviz.js | 17 +++++- webapp/web/static/js/tab-paths.js | 15 +++--- webapp/web/static/js/tab-topocola.js | 33 +++++++++--- webapp/web/static/js/webapp.js | 62 ++++++++++++++-------- webapp/webapp.go | 41 ++++++++------- 7 files changed, 146 insertions(+), 102 deletions(-) diff --git a/webapp/lib/traceroutecont.go b/webapp/lib/traceroutecont.go index e964652f..a9048c1a 100644 --- a/webapp/lib/traceroutecont.go +++ b/webapp/lib/traceroutecont.go @@ -144,7 +144,7 @@ func GetTracerouteByTimeHandler(w http.ResponseWriter, r *http.Request, active b returnError(w, err) return } - // log.Debug("Requested data:", "tracerouteResults", tracerouteResults) + log.Debug("Requested data:", "tracerouteResults", tracerouteResults) tracerouteJSON, err := json.Marshal(tracerouteResults) if CheckError(err) { @@ -156,7 +156,6 @@ func GetTracerouteByTimeHandler(w http.ResponseWriter, r *http.Request, active b jsonBuf = append(jsonBuf, json...) jsonBuf = append(jsonBuf, []byte(`}`)...) - //log.Debug(string(jsonBuf)) // ensure % if any, is escaped correctly before writing to printf formatter fmt.Fprintf(w, strings.Replace(string(jsonBuf), "%", "%%", -1)) } diff --git a/webapp/tests/asviz/traceroute-d.json b/webapp/tests/asviz/traceroute-d.json index cc80ccb3..d9fbd634 100644 --- a/webapp/tests/asviz/traceroute-d.json +++ b/webapp/tests/asviz/traceroute-d.json @@ -1,70 +1,53 @@ { "graph": [ { - "Inserted": 1562179946689, - "ActualDuration": 50, + "Inserted": 1570192000394, + "ActualDuration": 35, "TrHops": [ { "HopIa": "1-ff00:0:111", - "HopAddr": "127.0.0.74", - "IntfID": 103, - "RespTime1": 0.896, - "RespTime2": 1.482, - "RespTime3": 1.915 + "HopAddr": "127.0.0.17", + "IntfID": 41, + "RespTime1": 0.558, + "RespTime2": 0.439, + "RespTime3": 0.41 }, { - "HopIa": "1-ff00:0:112", - "HopAddr": "127.0.0.82", - "IntfID": 4094, - "RespTime1": 1.39, - "RespTime2": 0.772, - "RespTime3": 0.856 + "HopIa": "1-ff00:0:110", + "HopAddr": "127.0.0.9", + "IntfID": 1, + "RespTime1": 0.577, + "RespTime2": 0.597, + "RespTime3": 0.601 }, { - "HopIa": "1-ff00:0:112", - "HopAddr": "127.0.0.2", - "IntfID": -1, - "RespTime1": 1.057, - "RespTime2": 0.85, - "RespTime3": 0.866 - } - ], - "CmdOutput": "Using path:\n Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450\n0 1-ff00:0:111,[127.0.0.74] IfID=103 896µs 1.482ms 1.915ms\n1 1-ff00:0:112,[127.0.0.82] IfID=4094 1.39ms 772µs 856µs\n2 1-ff00:0:112,[127.0.0.2] 1.057ms 850µs 866µs\n", - "Path": "Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450", - "Error": "" - }, - { - "Inserted": 1562179946298, - "ActualDuration": 73, - "TrHops": [ - { - "HopIa": "1-ff00:0:111", - "HopAddr": "127.0.0.74", - "IntfID": 103, - "RespTime1": 1.189, - "RespTime2": 0.847, - "RespTime3": 0.707 + "HopIa": "1-ff00:0:110", + "HopAddr": "127.0.0.10", + "IntfID": 2, + "RespTime1": 0.797, + "RespTime2": 0.666, + "RespTime3": 0.771 }, { "HopIa": "1-ff00:0:112", - "HopAddr": "127.0.0.82", - "IntfID": 4094, - "RespTime1": 5.503, - "RespTime2": 1.127, - "RespTime3": 1.486 + "HopAddr": "127.0.0.25", + "IntfID": 1, + "RespTime1": 1.18, + "RespTime2": 1.922, + "RespTime3": 1.322 }, { "HopIa": "1-ff00:0:112", "HopAddr": "127.0.0.2", "IntfID": -1, - "RespTime1": 1.051, - "RespTime2": 1.331, - "RespTime3": 3.499 + "RespTime1": 1.107, + "RespTime2": 0.899, + "RespTime3": 0.835 } ], - "CmdOutput": "Using path:\n Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450\n0 1-ff00:0:111,[127.0.0.74] IfID=103 1.189ms 847µs 707µs\n1 1-ff00:0:112,[127.0.0.82] IfID=4094 5.503ms 1.127ms 1.486ms\n2 1-ff00:0:112,[127.0.0.2] 1.051ms 1.331ms 3.499ms\n", - "Path": "Hops: [1-ff00:0:111 103>4094 1-ff00:0:112] Mtu: 1450", - "Error": "" + "CmdOutput": "Available paths to 1-ff00:0:112\n[ 0] Hops: [1-ff00:0:111 41>1 1-ff00:0:110 2>1 1-ff00:0:112] Mtu: 1280\nChoose path: Using path:\n Hops: [1-ff00:0:111 41>1 1-ff00:0:110 2>1 1-ff00:0:112] Mtu: 1280\n0 1-ff00:0:111,[127.0.0.17] IfID=41 558µs 439µs 410µs\n1 1-ff00:0:110,[127.0.0.9] IfID=1 577µs 597µs 601µs\n2 1-ff00:0:110,[127.0.0.10] IfID=2 797µs 666µs 771µs\n3 1-ff00:0:112,[127.0.0.25] IfID=1 1.18ms 1.922ms 1.322ms\n4 1-ff00:0:112,[127.0.0.2] 1.107ms 899µs 835µs\n", + "Error": "", + "Path": "Hops: [1-ff00:0:111 41>1 1-ff00:0:110 2>1 1-ff00:0:112] Mtu: 1280" } ], "active": false diff --git a/webapp/web/static/js/asviz.js b/webapp/web/static/js/asviz.js index 6f7e0fb4..33587356 100644 --- a/webapp/web/static/js/asviz.js +++ b/webapp/web/static/js/asviz.js @@ -68,7 +68,8 @@ function setPaths(type, idx, open) { } else if (type == 'UP') { addSegments(resUp, idx, num, colorSegUp, type); } else if (type == 'PATH') { - var latencies = getPathLatencyAvg(formatPathString(resPath, idx, type)); + var latencies = getPathLatencyAvg(formatPathString(resPath, idx, + type)); addPaths(resPath, idx, num, colorPaths, type, latencies); } self.segType = type; @@ -109,6 +110,20 @@ function formatPathString(res, idx, type) { return path; } +function formatPathStringAll(res, type) { + var paths = ""; + for (var i = 0; i < res.if_lists.length; i++) { + var path = formatPathString(res, i, type); + if (path != "") { + if (i > 0) { + paths += ","; + } + paths += formatPathString(res, i, type); + } + } + return paths; +} + /* * Adds D3 forwarding path links with arrows and a title to paths graph. */ diff --git a/webapp/web/static/js/tab-paths.js b/webapp/web/static/js/tab-paths.js index 11de0fb0..08266aab 100644 --- a/webapp/web/static/js/tab-paths.js +++ b/webapp/web/static/js/tab-paths.js @@ -100,9 +100,8 @@ function setEchoLatency(hops, latency) { path = jPathsAvailable[hops]; } path.latency = updateStats(latency, path.latency); - var latStr = parseFloat(path.latency.Last).toFixed(1); - $('#path-lat-' + path.listIdx).html(latStr); jPathsAvailable[hops] = path; + return path; } function setTracerouteLatency(hops, interfaces) { @@ -120,17 +119,14 @@ function setTracerouteLatency(hops, interfaces) { path.interfaces[i].latency); path.interfaces[i].latency = updateStats(if_.RespTime3, path.interfaces[i].latency); - var latStr = parseFloat(path.interfaces[i].latency.Last).toFixed(1); - $('#path-lat-' + path.listIdx + '-' + i).html(latStr); } else { path.latency = updateStats(if_.RespTime1, path.latency); path.latency = updateStats(if_.RespTime2, path.latency); path.latency = updateStats(if_.RespTime3, path.latency); - var latStr = parseFloat(path.latency.Last).toFixed(1); - $('#path-lat-' + path.listIdx).html(latStr); } } jPathsAvailable[hops] = path; + return path; } function isConfigComplete(data, textStatus, jqXHR) { @@ -775,6 +771,9 @@ function addAvailablePaths(paths) { Object.keys(jPathsAvailable).forEach(function(key) { jPathsAvailable[key].listIdx = undefined; // reset }); + if (!paths) { + return; + } for (var idx = 0; idx < paths.length; idx++) { var hops = formatPathJson(paths, idx, 'PATH'); if (!jPathsAvailable[hops]) { @@ -793,7 +792,9 @@ function addAvailablePaths(paths) { } path.expTime = paths[idx].Entry.Path.ExpTime; path.mtu = paths[idx].Entry.Path.Mtu; - path.color = path_colors(pathLen - 1); + if (!path.color) { + path.color = path_colors(pathLen - 1); + } path.listIdx = idx; jPathsAvailable[hops] = path; } diff --git a/webapp/web/static/js/tab-topocola.js b/webapp/web/static/js/tab-topocola.js index 247b6466..15c27c23 100644 --- a/webapp/web/static/js/tab-topocola.js +++ b/webapp/web/static/js/tab-topocola.js @@ -333,7 +333,9 @@ function update() { "middle").style("font-size", "12px").style("fill", "purple").attr( "class", function(d) { return "latency " + d.type; - }).text(function(d) { + }).attr("id", function(d) { + return d.id; + }).text(function(d) { return d.latency ? parseFloat(d.latency).toFixed(1) : ''; }); markerText.exit().remove(); @@ -609,7 +611,7 @@ function addFixedLabel(label, x, y, lastLabel) { /* * Post-rendering method to draw path arcs for the given path and color. */ -function drawPath(res, path, color, latencies) { +function drawPath(res, path, color, lats) { // get the index of the routes to render var routes = []; if (path < 0) { @@ -642,25 +644,44 @@ function drawPath(res, path, color, latencies) { graphPath.links = graphPath.links.filter(function(link) { return !link.path; }); + var fullLat = fullPathLatencies(lats); for (var i = 0; i < path_ids.length - 1; i++) { // prevent src == dst links from being formed if (path_ids[i] != path_ids[i + 1]) { - console.warn(latencies) - var latInterIntra = latencies ? (latencies[(i * 2) + 1] + latencies[(i * 2) + 2]) - : undefined; + var linkLat = undefined; + if (fullLat) { + // report latency from target AS + linkLat = lats ? (lats[i + 2]) : undefined; + } graphPath.links.push({ "color" : color, "path" : true, "source" : graphPath["ids"][path_ids[i]], "target" : graphPath["ids"][path_ids[i + 1]], "type" : "PARENT", - "latency" : latInterIntra, + "latency" : linkLat, + "id" : "path-lat-" + path + "-" + i, // TODO }); } } update(); } +/** + * Interrogate latencies for missing values. + */ +function fullPathLatencies(lats) { + if (!lats) { + return false; + } + for (var i = 0; i < lats.length; i++) { + if (!lats[i]) { + return false; + } + } + return true; +} + /* * Removes all path arcs from the graph. */ diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index 9d7032da..a92283a8 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -483,10 +483,15 @@ function requestEchoByTime(form_data) { var time = d.graph[i].Inserted - d.graph[i].ActualDuration; updatePingGraph(chartSE, data, time) - // update latency stats, when valid + // update latency stats, when valid, use average if (d.graph[i].ResponseTime > 0) { - setEchoLatency(d.graph[i].Path.match("\\[.*]"), - d.graph[i].ResponseTime); + var path = setEchoLatency(d.graph[i].Path + .match("\\[.*]"), d.graph[i].ResponseTime); + if (path.latency) { + var latStr = parseFloat(path.latency.Avg) + .toFixed(1); + $('#path-lat-' + path.listIdx).html(latStr); + } } } } @@ -507,7 +512,11 @@ function requestTraceRouteByTime(form_data) { } else { enableTestControls(true); releaseTabs(); - clearInterval(intervalGraphData); + if (d.graph != null) { + clearInterval(intervalGraphData); + } else { + lastTimeBwDb = form_data.since; + } } } if (d.graph != null) { @@ -518,29 +527,35 @@ function requestTraceRouteByTime(form_data) { // result returned, display it and reset progress handleEndCmdDisplay(d.graph[i].CmdOutput); } - // var data = { - // 'responseTime' : d.graph[i].ResponseTime, - // 'runTime' : d.graph[i].RunTime, - // 'loss' : d.graph[i].PktLoss, - // 'path' : d.graph[i].Path, - // 'error' : d.graph[i].Error, - // }; - // if (data.runTime == 0) { - // // for other errors, use execution time - // data.runTime = d.graph[i].ActualDuration; - // } - // console.info(JSON.stringify(data)); + console.info('continuous traceroute', 'duration:', d.graph[i].ActualDuration, 'ms'); // use the time the test began var time = d.graph[i].Inserted - d.graph[i].ActualDuration; - // updatePingGraph(chartSE, data, time) // TODO (mwfarb): implement traceroute graph - // update latency stats - setTracerouteLatency(d.graph[i].Path.match("\\[.*]"), - d.graph[i].TrHops); + // update latency stats, when valid, use average + var path = setTracerouteLatency(d.graph[i].Path + .match("\\[.*]"), d.graph[i].TrHops); + for (var i = 0; i < path.interfaces.length; i++) { + var if_ = path.interfaces[i]; + if (i < path.interfaces.length - 1) { + if (path.interfaces[i].latency) { + var latStr = parseFloat( + path.interfaces[i].latency.Avg) + .toFixed(1); + $('#path-lat-' + path.listIdx + '-' + i).html( + latStr); + } + } else { + if (path.latency) { + var latStr = parseFloat(path.latency.Avg) + .toFixed(1); + $('#path-lat-' + path.listIdx).html(latStr); + } + } + } } } } @@ -683,6 +698,11 @@ function command(continuous) { name : "pathStr", value : formatPathString(resPath, self.segNum, self.segType) }); + } else if (continuous) { // all paths in survey + form_data.push({ + name : "pathStr", + value : formatPathStringAll(resPath, 'PATH') + }); } } if (activeApp == "bwtester") { @@ -827,7 +847,7 @@ function handleContResponse(resp, continuous, startTime) { clearInterval(intervalGraphData); } if (!continuous) { - manageTestData(); + manageTestData(startTime); } } diff --git a/webapp/webapp.go b/webapp/webapp.go index bc89e398..1e24b3c6 100644 --- a/webapp/webapp.go +++ b/webapp/webapp.go @@ -213,7 +213,7 @@ func initLocalIaOptions() { } func initServeHandlers() { - serveExact("/favicon.ico", "./favicon.ico") + serveExact("/favicon.ico", path.Join(options.StaticRoot, "favicon.ico")) http.HandleFunc("/", mainHandler) http.HandleFunc("/about", aboutHandler) http.HandleFunc("/apps", appsHandler) @@ -394,10 +394,6 @@ func parseCmdItem2Cmd(dOrinial model.CmdItem, appSel string, pathStr string) []s bwSC := fmt.Sprintf("-sc=%d,%d,%d,%dbps", d.SCDuration/1000, d.SCPktSize, d.SCPackets, d.SCBandwidth) command = append(command, bwCS, bwSC) - if len(pathStr) > 0 { - // if path choice provided, use interactive mode - command = append(command, "-i") - } } isdCli, _ = strconv.Atoi(strings.Split(d.CIa, "-")[0]) @@ -414,10 +410,6 @@ func parseCmdItem2Cmd(dOrinial model.CmdItem, appSel string, pathStr string) []s optTimeout := fmt.Sprintf("-timeout=%fs", d.Timeout) optInterval := fmt.Sprintf("-interval=%fs", d.Interval) command = append(command, installpath, optApp, optRemote, optLocal, optCount, optTimeout, optInterval) - if len(pathStr) > 0 { - // if path choice provided, use interactive mode - command = append(command, "-i") - } isdCli, _ = strconv.Atoi(strings.Split(d.CIa, "-")[0]) case "traceroute": @@ -431,13 +423,13 @@ func parseCmdItem2Cmd(dOrinial model.CmdItem, appSel string, pathStr string) []s optRemote := fmt.Sprintf("-remote=%s,[%s]", d.SIa, d.SAddr) optTimeout := fmt.Sprintf("-timeout=%fs", d.Timeout) command = append(command, installpath, optApp, optRemote, optLocal, optTimeout) - if len(pathStr) > 0 { - // if path choice provided, use interactive mode - command = append(command, "-i") - } isdCli, _ = strconv.Atoi(strings.Split(d.CIa, "-")[0]) } + if len(pathStr) > 0 { + // if path choice provided, use interactive mode + command = append(command, "-i") + } if isdCli < 16 { // -sciondFromIA is better for localhost testing, with test isds command = append(command, "-sciondFromIA") @@ -489,13 +481,15 @@ func commandHandler(w http.ResponseWriter, r *http.Request) { } } else { // single run - executeCommand(w, r) + pathStr := r.PostFormValue("pathStr") + executeCommand(w, r, pathStr) } } // Could either be bwtest, echo or traceroute func continuousCmd(t contCmd) { log.Info(fmt.Sprintf("Starting continuous %s...", t)) + pathIdx := 0 defer func() { log.Info(fmt.Sprintf("Ending continuous %s...", t)) }() @@ -506,9 +500,16 @@ func continuousCmd(t contCmd) { contCmdActive = false break } + r := contCmdRequest + thePath := "" + pathStr := r.PostFormValue("pathStr") + paths := strings.Split(pathStr, ",") + if pathIdx >= 0 && pathIdx < len(paths) { + thePath = paths[pathIdx] + } start := time.Now() - executeCommand(nil, r) + executeCommand(nil, r, thePath) // block on cmd output finish <-contCmdChanDone @@ -522,14 +523,18 @@ func continuousCmd(t contCmd) { } log.Info(fmt.Sprintf("Test took %d ms, sleeping for remaining interval: %d ms", elapsed.Nanoseconds()/1e6, remaining.Nanoseconds()/1e6)) + if pathIdx >= (len(paths) - 1) { // iterate all paths given + pathIdx = 0 + } else { + pathIdx++ + } time.Sleep(remaining) } } -func executeCommand(w http.ResponseWriter, r *http.Request) { +func executeCommand(w http.ResponseWriter, r *http.Request, pathStr string) { r.ParseForm() appSel := r.PostFormValue("apps") - pathStr := r.PostFormValue("pathStr") d, addlOpt := parseRequest2CmdItem(r, appSel) command := parseCmdItem2Cmd(d, appSel, pathStr) if addlOpt != "" { @@ -707,7 +712,7 @@ func writeCmdOutput(w http.ResponseWriter, reader io.Reader, stdin io.WriteClose } if appSel == "traceroute" { - // parse traceroute data/error + // parse scmp traceroute data/error d, ok := d.(model.TracerouteItem) if !ok { log.Error("Parsing error, CmdItem category doesn't match its name") From 1ab475da66fee8bf289b7c8aaa942ad18a27afa2 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Fri, 25 Oct 2019 15:17:00 -0400 Subject: [PATCH 05/12] repaired echo/bw display update --- webapp/web/static/js/webapp.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index a92283a8..93cf9778 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -403,7 +403,11 @@ function requestBwTestByTime(form_data) { } else { enableTestControls(true); releaseTabs(); - clearInterval(intervalGraphData); + if (d.graph != null) { + clearInterval(intervalGraphData); + } else { + lastTimeBwDb = form_data.since; + } } } if (d.graph != null) { @@ -454,7 +458,11 @@ function requestEchoByTime(form_data) { } else { enableTestControls(true); releaseTabs(); - clearInterval(intervalGraphData); + if (d.graph != null) { + clearInterval(intervalGraphData); + } else { + lastTimeBwDb = form_data.since; + } } } if (d.graph != null) { From ac33123befc62961edf9fa1684d4aa91088a32a1 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Mon, 28 Oct 2019 20:30:11 -0400 Subject: [PATCH 06/12] consolidate end of data handlers, add background echo latency --- webapp/web/static/js/tab-paths.js | 2 + webapp/web/static/js/webapp.js | 133 ++++++++++++++++++++---------- webapp/webapp.go | 11 ++- 3 files changed, 99 insertions(+), 47 deletions(-) diff --git a/webapp/web/static/js/tab-paths.js b/webapp/web/static/js/tab-paths.js index 08266aab..f1954f50 100644 --- a/webapp/web/static/js/tab-paths.js +++ b/webapp/web/static/js/tab-paths.js @@ -838,6 +838,8 @@ function requestPaths() { setupDebug(); ajaxConfig(); + surveyEchoBackground(); + // path info label switches $('#switch_as_names').change(function() { handleAsLabelSwitch(); diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index 93cf9778..b27abd5d 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -390,26 +390,30 @@ function manageTestData() { }, dataIntervalMs); } +function manageTestEnd(d, appSel, since) { + if (d.active != null) { + if (d.active) { + enableTestControls(false); + lockTab(appSel); + failContinuousOff(); + } else { + enableTestControls(true); + releaseTabs(); + if (d.graph != null) { + clearInterval(intervalGraphData); + } else { + lastTimeBwDb = since; + } + } + } +} + function requestBwTestByTime(form_data) { $.post("/getbwbytime", form_data, function(json) { var d = JSON.parse(json); console.info('resp:', JSON.stringify(d)); if (d != null) { - if (d.active != null) { - if (d.active) { - enableTestControls(false); - lockTab("bwtester"); - failContinuousOff(); - } else { - enableTestControls(true); - releaseTabs(); - if (d.graph != null) { - clearInterval(intervalGraphData); - } else { - lastTimeBwDb = form_data.since; - } - } - } + manageTestEnd(d, "bwtester", form_data.since); if (d.graph != null) { // write data on graph for (var i = 0; i < d.graph.length; i++) { @@ -450,21 +454,7 @@ function requestEchoByTime(form_data) { var d = JSON.parse(json); console.info('resp:', JSON.stringify(d)); if (d != null) { - if (d.active != null) { - if (d.active) { - enableTestControls(false); - lockTab("echo"); - failContinuousOff(); - } else { - enableTestControls(true); - releaseTabs(); - if (d.graph != null) { - clearInterval(intervalGraphData); - } else { - lastTimeBwDb = form_data.since; - } - } - } + manageTestEnd(d, "echo", form_data.since); if (d.graph != null) { // write data on graph for (var i = 0; i < d.graph.length; i++) { @@ -512,21 +502,7 @@ function requestTraceRouteByTime(form_data) { var d = JSON.parse(json); console.info('resp:', JSON.stringify(d)); if (d != null) { - if (d.active != null) { - if (d.active) { - enableTestControls(false); - lockTab("traceroute"); - failContinuousOff(); - } else { - enableTestControls(true); - releaseTabs(); - if (d.graph != null) { - clearInterval(intervalGraphData); - } else { - lastTimeBwDb = form_data.since; - } - } - } + manageTestEnd(d, "traceroute", form_data.since); if (d.graph != null) { // write data on graph for (var i = 0; i < d.graph.length; i++) { @@ -570,6 +546,72 @@ function requestTraceRouteByTime(form_data) { }); } +var backgroundEcho; +function surveyEchoBackground() { + var lastTimeBwDb = (new Date()).getTime(); + var form_data = $('#command-form').serializeArray(); + var interval = 0.1; + var count = 3; + form_data.push({ + name : "apps", + value : "echo" + }, { + name : "count", + value : count + }, { + name : "continuous", + value : true + }, { + name : "pathStr", + value : formatPathStringAll(resPath, 'PATH') + }, { + name : "interval", + value : interval + }); + // start background echo + console.info('req:', JSON.stringify(form_data)); + $.post('/command', form_data, function(resp, status, jqXHR) { + console.info('resp:', resp); + }).fail(function(error) { + showError(error.responseJSON); + }); + + clearInterval(backgroundEcho); + backgroundEcho = setInterval(function() { + reportEchoBackground({ + since : lastTimeBwDb + }); + lastTimeBwDb = (new Date()).getTime(); + }, dataIntervalMs); +} + +function reportEchoBackground(form_data) { + $.post("/getechobytime", form_data, function(json) { + var d = JSON.parse(json); + console.info('resp:', JSON.stringify(d)); + if (d != null) { + if (!d.active) { + // end background echo + clearInterval(backgroundEcho); + } + if (d.graph != null) { + for (var i = 0; i < d.graph.length; i++) { + // update latency stats, when valid, use average + if (d.graph[i].ResponseTime > 0) { + var path = setEchoLatency(d.graph[i].Path + .match("\\[.*]"), d.graph[i].ResponseTime); + if (path.latency) { + var latStr = parseFloat(path.latency.Avg) + .toFixed(1); + $('#path-lat-' + path.listIdx).html(latStr); + } + } + } + } + } + }); +} + function refreshTickData(chart, newTime) { var x = newTime, y = null; var series0 = chart.series[0]; @@ -713,6 +755,7 @@ function command(continuous) { }); } } + if (activeApp == "bwtester") { form_data.push({ name : "interval", diff --git a/webapp/webapp.go b/webapp/webapp.go index 1e24b3c6..f5108ba7 100644 --- a/webapp/webapp.go +++ b/webapp/webapp.go @@ -444,6 +444,7 @@ func commandHandler(w http.ResponseWriter, r *http.Request) { appSel := r.PostFormValue("apps") continuous, _ := strconv.ParseBool(r.PostFormValue("continuous")) interval, _ := strconv.Atoi(r.PostFormValue("interval")) + count, _ := strconv.Atoi(r.PostFormValue("count")) if appSel == "" { fmt.Fprintf(w, "Unknown SCION client app. Is one selected?") return @@ -468,7 +469,7 @@ func commandHandler(w http.ResponseWriter, r *http.Request) { if !contCmdActive { // run continuous goroutine contCmdActive = true - go continuousCmd(t) + go continuousCmd(t, count) } else { // continuous goroutine running? if continuous { @@ -487,9 +488,10 @@ func commandHandler(w http.ResponseWriter, r *http.Request) { } // Could either be bwtest, echo or traceroute -func continuousCmd(t contCmd) { +func continuousCmd(t contCmd, count int) { log.Info(fmt.Sprintf("Starting continuous %s...", t)) pathIdx := 0 + attempts := 0 defer func() { log.Info(fmt.Sprintf("Ending continuous %s...", t)) }() @@ -525,9 +527,14 @@ func continuousCmd(t contCmd) { elapsed.Nanoseconds()/1e6, remaining.Nanoseconds()/1e6)) if pathIdx >= (len(paths) - 1) { // iterate all paths given pathIdx = 0 + attempts++ } else { pathIdx++ } + if attempts >= count { + log.Info("Continuous count reached ", "count", count, "attempts", attempts) + contCmdActive = false + } time.Sleep(remaining) } } From d08019440abc4d7bf91b4c205f177a45c44f4926 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Wed, 30 Oct 2019 15:00:20 -0400 Subject: [PATCH 07/12] request config/echo only when none exist --- webapp/web/static/js/tab-paths.js | 13 +++++++++++-- webapp/web/static/js/webapp.js | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/webapp/web/static/js/tab-paths.js b/webapp/web/static/js/tab-paths.js index f1954f50..0f975a76 100644 --- a/webapp/web/static/js/tab-paths.js +++ b/webapp/web/static/js/tab-paths.js @@ -836,9 +836,18 @@ function requestPaths() { // setup path config based on defaults loaded setupDebug(); - ajaxConfig(); - surveyEchoBackground(); + // request config/paths if none exists + if (!iaLabels || !iaGeoLoc || !iaLocations) { + ajaxConfig(); // ajaxConfig => loadPathData + } else { + loadPathData(g.src, g.dst); + } + + // auto survey latency if none exists + if (!$('#path-lat-0').text()) { + surveyEchoBackground(); + } // path info label switches $('#switch_as_names').change(function() { diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index b27abd5d..258a0d0e 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -743,7 +743,7 @@ function command(continuous) { name : "continuous", value : continuous }); - if (self.segType == 'PATH') { // only full paths allowed + if (self.segType == 'PATH') { // single path open form_data.push({ name : "pathStr", value : formatPathString(resPath, self.segNum, self.segType) From 0d1573779454f747f5f72f5c9812d9f9fc004677 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Thu, 31 Oct 2019 09:53:02 -0400 Subject: [PATCH 08/12] fixing some tr writes --- webapp/web/static/js/webapp.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index 258a0d0e..66ac7b11 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -127,7 +127,7 @@ function initBwGraphs() { // setup interval to manage smooth ticking lastTime = (new Date()).getTime() - (ticks * tickMs) + xLeftTrimMs; manageTickData(); - manageTestData(); + // avoid manageTestData on startup before tests } function showOnlyConsoleGraphs(activeApp) { @@ -522,24 +522,24 @@ function requestTraceRouteByTime(form_data) { // update latency stats, when valid, use average var path = setTracerouteLatency(d.graph[i].Path .match("\\[.*]"), d.graph[i].TrHops); + console.debug(path) for (var i = 0; i < path.interfaces.length; i++) { var if_ = path.interfaces[i]; - if (i < path.interfaces.length - 1) { - if (path.interfaces[i].latency) { - var latStr = parseFloat( - path.interfaces[i].latency.Avg) - .toFixed(1); - $('#path-lat-' + path.listIdx + '-' + i).html( - latStr); - } - } else { - if (path.latency) { - var latStr = parseFloat(path.latency.Avg) - .toFixed(1); - $('#path-lat-' + path.listIdx).html(latStr); - } + if (path.interfaces[i].latency) { + var latStr = parseFloat( + path.interfaces[i].latency.Avg).toFixed(1); + console.debug("writing " + latStr + ' #path-lat-' + + path.listIdx + '-' + i) + $('#path-lat-' + path.listIdx + '-' + i).html( + latStr); } } + if (path.latency) { + var latStr = parseFloat(path.latency.Avg).toFixed(1); + console.debug("writing " + latStr + ' #path-lat-' + + path.listIdx) + $('#path-lat-' + path.listIdx).html(latStr); + } } } } From d7de84a015956eb7e0a4b584970d3fd62d90ec1b Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Fri, 1 Nov 2019 14:11:45 -0400 Subject: [PATCH 09/12] error checks, adding inter-AS latency --- webapp/web/static/js/tab-topocola.js | 13 ++++++++----- webapp/web/static/js/webapp.js | 7 +++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/webapp/web/static/js/tab-topocola.js b/webapp/web/static/js/tab-topocola.js index 15c27c23..37ead22e 100644 --- a/webapp/web/static/js/tab-topocola.js +++ b/webapp/web/static/js/tab-topocola.js @@ -644,24 +644,27 @@ function drawPath(res, path, color, lats) { graphPath.links = graphPath.links.filter(function(link) { return !link.path; }); + console.debug(lats) var fullLat = fullPathLatencies(lats); for (var i = 0; i < path_ids.length - 1; i++) { // prevent src == dst links from being formed if (path_ids[i] != path_ids[i + 1]) { var linkLat = undefined; if (fullLat) { - // report latency from target AS - linkLat = lats ? (lats[i + 2]) : undefined; + // report latency difference between inter-AS links + linkLat = lats ? (lats[i + 1] - lats[i]) : undefined; } - graphPath.links.push({ + var link = { "color" : color, "path" : true, "source" : graphPath["ids"][path_ids[i]], "target" : graphPath["ids"][path_ids[i + 1]], "type" : "PARENT", "latency" : linkLat, - "id" : "path-lat-" + path + "-" + i, // TODO - }); + "id" : "path-lat-diff-" + path + "-" + i, // TODO + }; + graphPath.links.push(link); + console.debug(link) } } update(); diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index 66ac7b11..1d4cf059 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -520,6 +520,13 @@ function requestTraceRouteByTime(form_data) { // TODO (mwfarb): implement traceroute graph // update latency stats, when valid, use average + var trhops = ((d.graph[i].Path.split('>').length) * 2) - 1; + if (!d.graph[i].TrHops + || d.graph[i].TrHops.length != trhops) { + showError("Did not receive expected " + trhops + + " traceroute hops."); + continue; + } var path = setTracerouteLatency(d.graph[i].Path .match("\\[.*]"), d.graph[i].TrHops); console.debug(path) From 6c796df881156f0c4186af583992cfb804a2e782 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Tue, 5 Nov 2019 14:03:13 -0500 Subject: [PATCH 10/12] update latency on realtime path --- webapp/web/static/js/tab-paths.js | 14 +++++++++++--- webapp/web/static/js/tab-topocola.js | 2 +- webapp/web/static/js/webapp.js | 21 +++++++++++++-------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/webapp/web/static/js/tab-paths.js b/webapp/web/static/js/tab-paths.js index 0f975a76..0a3311eb 100644 --- a/webapp/web/static/js/tab-paths.js +++ b/webapp/web/static/js/tab-paths.js @@ -69,6 +69,15 @@ function getPathLatencyAvg(hops) { return getPathLatency(hops, true); } +function formatLatency(lat) { + // ignore 1ms negative margin of error + if (lat > -1 && lat < 0) { + return 0; + } else { + return parseFloat(lat).toFixed(0); + } +} + /** * Returns array of interface and full path latency stats. */ @@ -474,7 +483,7 @@ function get_path_html(paths, csegs, usegs, dsegs, show_segs) { var pathStr = formatPathJson(paths, parseInt(p)); var latencies = getPathLatencyAvg(pathStr); var latencyPath = latencies[latencies.length - 1]; - var latPathStr = latencyPath ? parseFloat(latencyPath).toFixed(1) : ''; + var latPathStr = latencyPath ? formatLatency(latencyPath) : ''; var aStyle = "style='background-color:" + getPathColor(pathStr) + ";'"; var latStyle = "style='color:purple; position:absolute; right:0;'"; html += "
  • Expiration: " + exp.toLocaleDateString() + " " + exp.toLocaleTimeString() + ""; for (i in if_) { - var latIfStr = latencies[i] ? parseFloat(latencies[i]).toFixed(1) - : ''; + var latIfStr = latencies[i] ? formatLatency(latencies[i]) : ''; html += "
  • " + iaRaw2Read(if_[i].RawIsdas) + " (" + if_[i].IfID + ") " + latIfStr + ""; diff --git a/webapp/web/static/js/tab-topocola.js b/webapp/web/static/js/tab-topocola.js index 37ead22e..f097ea94 100644 --- a/webapp/web/static/js/tab-topocola.js +++ b/webapp/web/static/js/tab-topocola.js @@ -336,7 +336,7 @@ function update() { }).attr("id", function(d) { return d.id; }).text(function(d) { - return d.latency ? parseFloat(d.latency).toFixed(1) : ''; + return d.latency ? formatLatency(d.latency) : ''; }); markerText.exit().remove(); diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index 1d4cf059..b6577d29 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -486,8 +486,7 @@ function requestEchoByTime(form_data) { var path = setEchoLatency(d.graph[i].Path .match("\\[.*]"), d.graph[i].ResponseTime); if (path.latency) { - var latStr = parseFloat(path.latency.Avg) - .toFixed(1); + var latStr = formatLatency(path.latency.Avg); $('#path-lat-' + path.listIdx).html(latStr); } } @@ -532,17 +531,24 @@ function requestTraceRouteByTime(form_data) { console.debug(path) for (var i = 0; i < path.interfaces.length; i++) { var if_ = path.interfaces[i]; - if (path.interfaces[i].latency) { - var latStr = parseFloat( - path.interfaces[i].latency.Avg).toFixed(1); + var if_prev = path.interfaces[i - 1]; + if (if_.latency) { + var latStr = formatLatency(if_.latency.Avg); console.debug("writing " + latStr + ' #path-lat-' + path.listIdx + '-' + i) $('#path-lat-' + path.listIdx + '-' + i).html( latStr); } + // update each inter-AS link with difference + if (i % 2 == 1) { + var diff = if_.latency.Avg - if_prev.latency.Avg; + var latStr = formatLatency(diff); + $('#path-lat-diff-' + path.listIdx + '-' + (i - 1)) + .html(latStr); + } } if (path.latency) { - var latStr = parseFloat(path.latency.Avg).toFixed(1); + var latStr = formatLatency(path.latency.Avg); console.debug("writing " + latStr + ' #path-lat-' + path.listIdx) $('#path-lat-' + path.listIdx).html(latStr); @@ -608,8 +614,7 @@ function reportEchoBackground(form_data) { var path = setEchoLatency(d.graph[i].Path .match("\\[.*]"), d.graph[i].ResponseTime); if (path.latency) { - var latStr = parseFloat(path.latency.Avg) - .toFixed(1); + var latStr = formatLatency(path.latency.Avg); $('#path-lat-' + path.listIdx).html(latStr); } } From 3213c50015a8da21718ac995971e26ba24ba76ac Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Wed, 6 Nov 2019 15:48:02 -0500 Subject: [PATCH 11/12] migrate --- webapp/web/static/css/style-viz.css | 6 ++++++ webapp/web/static/js/tab-paths.js | 6 +++--- webapp/web/static/js/webapp.js | 5 ++++- webapp/web/template/index.html | 9 ++------- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/webapp/web/static/css/style-viz.css b/webapp/web/static/css/style-viz.css index 7bd232ec..1e8e3599 100644 --- a/webapp/web/static/css/style-viz.css +++ b/webapp/web/static/css/style-viz.css @@ -254,6 +254,12 @@ ul.tree li a { border-radius: 10px; /* background shape */ } +.latency-text { + color: purple; + position: absolute; + right: 0; +} + ul.tree li a:before { height: 1em; padding: 0 .1em; diff --git a/webapp/web/static/js/tab-paths.js b/webapp/web/static/js/tab-paths.js index 0a3311eb..5b525ddf 100644 --- a/webapp/web/static/js/tab-paths.js +++ b/webapp/web/static/js/tab-paths.js @@ -485,12 +485,12 @@ function get_path_html(paths, csegs, usegs, dsegs, show_segs) { var latencyPath = latencies[latencies.length - 1]; var latPathStr = latencyPath ? formatLatency(latencyPath) : ''; var aStyle = "style='background-color:" + getPathColor(pathStr) + ";'"; - var latStyle = "style='color:purple; position:absolute; right:0;'"; html += "
  • PATH " + (parseInt(p) + 1) + " " + hops - + " " + + " " + latPathStr + ""; exp.setUTCSeconds(ent.Path.ExpTime); html += "
      "; @@ -510,7 +510,7 @@ function get_path_html(paths, csegs, usegs, dsegs, show_segs) { var latIfStr = latencies[i] ? formatLatency(latencies[i]) : ''; html += "
    • " + iaRaw2Read(if_[i].RawIsdas) + " (" + if_[i].IfID + ") " + latIfStr + ""; + + "' class='latency-text' >" + latIfStr + ""; } html += "
    "; } diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index b6577d29..9696bcf9 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -522,7 +522,7 @@ function requestTraceRouteByTime(form_data) { var trhops = ((d.graph[i].Path.split('>').length) * 2) - 1; if (!d.graph[i].TrHops || d.graph[i].TrHops.length != trhops) { - showError("Did not receive expected " + trhops + console.error("Did not receive expected " + trhops + " traceroute hops."); continue; } @@ -543,6 +543,9 @@ function requestTraceRouteByTime(form_data) { if (i % 2 == 1) { var diff = if_.latency.Avg - if_prev.latency.Avg; var latStr = formatLatency(diff); + console.debug("writing " + latStr + + ' #path-lat-diff-' + path.listIdx + '-' + + (i - 1)) $('#path-lat-diff-' + path.listIdx + '-' + (i - 1)) .html(latStr); } diff --git a/webapp/web/template/index.html b/webapp/web/template/index.html index 8bc402e5..eeab871d 100644 --- a/webapp/web/template/index.html +++ b/webapp/web/template/index.html @@ -412,19 +412,14 @@

    SCIONLab Apps

    -

    Available Paths Hops Latency - + id='path-lat-title' class='latency-text' + style='font-weight: bold;'>Latency

    From fe057f4aa7c2f43e1900e9c57e646ea11952cc49 Mon Sep 17 00:00:00 2001 From: Michael Farb Date: Thu, 9 Jan 2020 14:27:48 -0500 Subject: [PATCH 12/12] use Last stat, make sync based on actual insert time --- webapp/web/static/js/asviz.js | 3 ++- webapp/web/static/js/tab-paths.js | 2 +- webapp/web/static/js/webapp.js | 15 +++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/webapp/web/static/js/asviz.js b/webapp/web/static/js/asviz.js index 33587356..1f9c1eb7 100644 --- a/webapp/web/static/js/asviz.js +++ b/webapp/web/static/js/asviz.js @@ -68,7 +68,8 @@ function setPaths(type, idx, open) { } else if (type == 'UP') { addSegments(resUp, idx, num, colorSegUp, type); } else if (type == 'PATH') { - var latencies = getPathLatencyAvg(formatPathString(resPath, idx, + // use min(best) for inter AS as it will be more accurate for length + var latencies = getPathLatencyLast(formatPathString(resPath, idx, type)); addPaths(resPath, idx, num, colorPaths, type, latencies); } diff --git a/webapp/web/static/js/tab-paths.js b/webapp/web/static/js/tab-paths.js index 5b525ddf..65fbe1c2 100644 --- a/webapp/web/static/js/tab-paths.js +++ b/webapp/web/static/js/tab-paths.js @@ -481,7 +481,7 @@ function get_path_html(paths, csegs, usegs, dsegs, show_segs) { var hops = if_.length / 2; var pathStr = formatPathJson(paths, parseInt(p)); - var latencies = getPathLatencyAvg(pathStr); + var latencies = getPathLatencyLast(pathStr); var latencyPath = latencies[latencies.length - 1]; var latPathStr = latencyPath ? formatLatency(latencyPath) : ''; var aStyle = "style='background-color:" + getPathColor(pathStr) + ";'"; diff --git a/webapp/web/static/js/webapp.js b/webapp/web/static/js/webapp.js index 9696bcf9..b84bec8b 100644 --- a/webapp/web/static/js/webapp.js +++ b/webapp/web/static/js/webapp.js @@ -386,7 +386,7 @@ function manageTestData() { } else if (activeApp == "traceroute") { requestTraceRouteByTime(form_data); } - lastTimeBwDb = now; + // lastTimeBwDb = now; }, dataIntervalMs); } @@ -401,8 +401,8 @@ function manageTestEnd(d, appSel, since) { releaseTabs(); if (d.graph != null) { clearInterval(intervalGraphData); - } else { - lastTimeBwDb = since; + // } else { + // lastTimeBwDb = since; } } } @@ -440,6 +440,7 @@ function requestBwTestByTime(form_data) { console.info(JSON.stringify(data)); console.info('continuous bwtester', 'duration:', d.graph[i].ActualDuration, 'ms'); + lastTimeBwDb = d.graph[i].Inserted; // use the time the test began var time = d.graph[i].Inserted - d.graph[i].ActualDuration; updateBwGraph(data, time) @@ -477,6 +478,7 @@ function requestEchoByTime(form_data) { console.info(JSON.stringify(data)); console.info('continuous echo', 'duration:', d.graph[i].ActualDuration, 'ms'); + lastTimeBwDb = d.graph[i].Inserted; // use the time the test began var time = d.graph[i].Inserted - d.graph[i].ActualDuration; updatePingGraph(chartSE, data, time) @@ -513,6 +515,7 @@ function requestTraceRouteByTime(form_data) { console.info('continuous traceroute', 'duration:', d.graph[i].ActualDuration, 'ms'); + lastTimeBwDb = d.graph[i].Inserted; // use the time the test began var time = d.graph[i].Inserted - d.graph[i].ActualDuration; @@ -564,7 +567,7 @@ function requestTraceRouteByTime(form_data) { var backgroundEcho; function surveyEchoBackground() { - var lastTimeBwDb = (new Date()).getTime(); + var blastTimeBwDb = (new Date()).getTime(); var form_data = $('#command-form').serializeArray(); var interval = 0.1; var count = 3; @@ -595,9 +598,9 @@ function surveyEchoBackground() { clearInterval(backgroundEcho); backgroundEcho = setInterval(function() { reportEchoBackground({ - since : lastTimeBwDb + since : blastTimeBwDb }); - lastTimeBwDb = (new Date()).getTime(); + blastTimeBwDb = (new Date()).getTime(); }, dataIntervalMs); }