diff --git a/src/main/images/Floodlight Icons.sketch/Data b/src/main/images/Floodlight Icons.sketch/Data index bb5c893b9e5d4172708bd150a5c1137548333db9..0fbceabe0c97c926b15762291f968aca11db5a96 100644 Binary files a/src/main/images/Floodlight Icons.sketch/Data and b/src/main/images/Floodlight Icons.sketch/Data differ diff --git a/src/main/images/Floodlight Icons.sketch/QuickLook/Preview.png b/src/main/images/Floodlight Icons.sketch/QuickLook/Preview.png index 77fc493ec2b292f44d48e5a360f0459b45dab267..4a36e7cbb504eacc1a3a70237183873e35cbb61c 100644 Binary files a/src/main/images/Floodlight Icons.sketch/QuickLook/Preview.png and b/src/main/images/Floodlight Icons.sketch/QuickLook/Preview.png differ diff --git a/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png b/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png index 942c917bac3f2f0d351c47e4ad18001e31c4132d..50ebe22932430361c768192df9e1f4a2e3c2423a 100644 Binary files a/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png and b/src/main/images/Floodlight Icons.sketch/QuickLook/Thumbnail.png differ diff --git a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java index 3ccef428d1b25d5e96a6e89a14dd7fc5778ad1b1..780e56f3efe539536d929bf9a31e5fe5842f0b8d 100755 --- a/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java +++ b/src/main/java/net/floodlightcontroller/devicemanager/internal/Device.java @@ -104,6 +104,16 @@ public class Device implements IDevice { List<AttachmentPoint>oldAP = new ArrayList<AttachmentPoint>(attachmentPoints); + // Remove invalid attachment points before sorting. + List<AttachmentPoint>tempAP = + new ArrayList<AttachmentPoint>(); + for(AttachmentPoint ap: oldAP) { + if (deviceManager.isValidAttachmentPoint(ap.getSw(), ap.getPort())){ + tempAP.add(ap); + } + } + oldAP = tempAP; + Collections.sort(oldAP, deviceManager.apComparator); // Map of attachment point by L2 domain Id. diff --git a/src/main/resources/web/img/switch.png b/src/main/resources/web/img/switch.png index d241d92d74d012aa886823a597936b7dcab759c3..f8e69108f7d9c26ae92fcc41d7fb286cfc390edb 100644 Binary files a/src/main/resources/web/img/switch.png and b/src/main/resources/web/img/switch.png differ diff --git a/src/main/resources/web/index.html b/src/main/resources/web/index.html index 1812037aed3ce286cdcd31ace15edd21f4a16e9c..54e1cb398d464d81dee4bda46e9353f96cfb24e2 100644 --- a/src/main/resources/web/index.html +++ b/src/main/resources/web/index.html @@ -50,31 +50,8 @@ <div class="header"></div> -<!-- FIXME closing these alerts returns to the dashboard; why? --> - - <div class="container"> -<!-- -<div class="row"> -<div class="span12"> -<div class="alert alert-info"> -Floodlight is the awesomest OpenFlow controller, and you're running it right now. -<a class="close" data-dismiss="alert" href="#">×</a> -</div> -</div> -</div> - -<div class="row"> -<div class="span12"> -<div class="alert alert-error"> -This Web interface is <strong>incomplete and buggy</strong>! Don't be surprised if you see errors or missing data. -<a class="close" data-dismiss="alert" href="#">×</a> -</div> -</div> -</div> ---> - <div id="content"></div> <hr> diff --git a/src/main/resources/web/js/main.js b/src/main/resources/web/js/main.js index 7e0ac8106a78109f9b48da40c70f61d43c749ad3..2362757ac690fb3c27bc6a6a54fbe3e2eead68a6 100644 --- a/src/main/resources/web/js/main.js +++ b/src/main/resources/web/js/main.js @@ -47,8 +47,8 @@ var AppRouter = Backbone.Router.extend({ }, topology:function () { - //console.log("switching to topology view"); - var topo = new Topology(); + //console.log("switching to topology view"); + var topo = new Topology(); $('#content').html(new TopologyView({model:topo, hosts:hl}).render().el); // TODO factor this code out $('ul.nav > li').removeClass('active'); @@ -56,30 +56,30 @@ var AppRouter = Backbone.Router.extend({ }, switchDetails:function (id) { - //console.log("switching [sic] to single switch view"); - var sw = swl.get(id); - $('#content').html(new SwitchView({model:sw}).render().el); + //console.log("switching [sic] to single switch view"); + var sw = swl.get(id); + $('#content').html(new SwitchView({model:sw}).render().el); $('ul.nav > li').removeClass('active'); $('li > a[href*="/switches"]').parent().addClass('active'); }, switchList:function () { - //console.log("switching [sic] to switch list view"); + //console.log("switching [sic] to switch list view"); $('#content').html(new SwitchListView({model:swl}).render().el); $('ul.nav > li').removeClass('active'); $('li > a[href*="/switches"]').parent().addClass('active'); }, hostDetails:function (id) { - //console.log("switching to single host view"); - var h = hl.get(id); - $('#content').html(new HostView({model:h}).render().el); + //console.log("switching to single host view"); + var h = hl.get(id); + $('#content').html(new HostView({model:h}).render().el); $('ul.nav > li').removeClass('active'); $('li > a[href*="/hosts"]').parent().addClass('active'); }, hostList:function () { - //console.log("switching to host list view"); + //console.log("switching to host list view"); $('#content').html(new HostListView({model:hl}).render().el); $('ul.nav > li').removeClass('active'); $('li > a[href*="/hosts"]').parent().addClass('active'); @@ -99,21 +99,21 @@ tpl.loadTemplates(['home', 'status', 'topology', 'header', 'switch', 'switch-lis $(document).ready(function () { // trigger Backbone routing when clicking on links, thanks to Atinux and pbnv - app.navigate("", true); - - window.document.addEventListener('click', function(e) { - e = e || window.event - var target = e.target || e.srcElement - if ( target.nodeName.toLowerCase() === 'a' ) { - e.preventDefault() - var uri = target.getAttribute('href') - app.navigate(uri.substr(1), true) - } - }); - window.addEventListener('popstate', function(e) { - app.navigate(location.pathname.substr(1), true); - }); - + app.navigate("", true); + + window.document.addEventListener('click', function(e) { + e = e || window.event + var target = e.target || e.srcElement + if ( target.nodeName.toLowerCase() === 'a' ) { + e.preventDefault() + var uri = target.getAttribute('href') + app.navigate(uri.substr(1), true) + } + }); + window.addEventListener('popstate', function(e) { + app.navigate(location.pathname.substr(1), true); + }); + }); }); diff --git a/src/main/resources/web/js/models/flowmodel.js b/src/main/resources/web/js/models/flowmodel.js index 4923f610c415ca1e8e518e02c5bd3229c00f5a6b..80777c334f15c01bf7590bdf456320a2657a23ad 100644 --- a/src/main/resources/web/js/models/flowmodel.js +++ b/src/main/resources/web/js/models/flowmodel.js @@ -16,13 +16,13 @@ window.Flow = Backbone.Model.extend({ - defaults: { - receiveBytes: 0, - receivePackets: 0, - transmitBytes: 0, - transmitPackets: 0, - }, - + defaults: { + receiveBytes: 0, + receivePackets: 0, + transmitBytes: 0, + transmitPackets: 0, + }, + // initialize:function () {} }); diff --git a/src/main/resources/web/js/models/hostmodel.js b/src/main/resources/web/js/models/hostmodel.js index ec37d1573c043dd9f61cbdb159696da2e7c49774..47ae4207e97fb2168c81e900e42f38ac853fe2c4 100644 --- a/src/main/resources/web/js/models/hostmodel.js +++ b/src/main/resources/web/js/models/hostmodel.js @@ -62,11 +62,11 @@ window.HostCollection = Backbone.Collection.extend({ } /* - * findByName:function (key) { // TODO: Modify service to include firstName - * in search var url = (key == '') ? '/host/' : "/host/search/" + key; - * console.log('findByName: ' + key); var self = this; $.ajax({ url:url, - * dataType:"json", success:function (data) { console.log("search success: " + - * data.length); self.reset(data); } }); } - */ + * findByName:function (key) { // TODO: Modify service to include firstName + * in search var url = (key == '') ? '/host/' : "/host/search/" + key; + * console.log('findByName: ' + key); var self = this; $.ajax({ url:url, + * dataType:"json", success:function (data) { console.log("search success: " + + * data.length); self.reset(data); } }); } + */ }); diff --git a/src/main/resources/web/js/models/statusmodel.js b/src/main/resources/web/js/models/statusmodel.js index aac2f8d2aab44609bae4805d2667ade896f058ce..31bdff37565b54d2ccd2a66d1cac348d5ac8a0b8 100644 --- a/src/main/resources/web/js/models/statusmodel.js +++ b/src/main/resources/web/js/models/statusmodel.js @@ -16,14 +16,14 @@ window.Status = Backbone.Model.extend({ defaults: { - host: 'localhost', - ofport: 6633, - uptime: 'unknown', - free: 0, - total: 0, - healthy: 'unknown', - modules: [], - moduleText: '' + host: 'localhost', + ofport: 6633, + uptime: 'unknown', + free: 0, + total: 0, + healthy: 'unknown', + modules: [], + moduleText: '' }, initialize:function () { @@ -54,7 +54,8 @@ window.Status = Backbone.Model.extend({ console.log("fetched controller status: modules loaded"); // console.log(data); self.set({modules:_.keys(data)}); - self.set({moduleText:_.reduce(_.keys(data), function(s, m){return s+m.replace("net.floodlightcontroller", "n.f")+", "}, '')}); + self.set({moduleText:_.reduce(_.keys(data), function(s, m) + {return s+m.replace("net.floodlightcontroller", "n.f")+", "}, '')}); } }); diff --git a/src/main/resources/web/js/models/switchmodel.js b/src/main/resources/web/js/models/switchmodel.js index 252b316e45c605e02477a57a167827cdd560865d..a2483a5a5cb5fb0ff78e245dc3aee542f0340d0a 100644 --- a/src/main/resources/web/js/models/switchmodel.js +++ b/src/main/resources/web/js/models/switchmodel.js @@ -185,8 +185,10 @@ window.SwitchCollection = Backbone.Collection.extend({ dataType:"json", success:function (data) { //console.log("fetched switch list: " + data.length); - // console.log(data); - _.each(data, function(sw) {self.add({id: sw['dpid']})}); + //console.log(data); + _.each(data, function(sw) {self.add({id: sw['dpid'], + inetAddress: sw.inetAddress, + connectedSince: new Date(sw.connectedSince).toLocaleString()})}); } }); }, diff --git a/src/main/resources/web/js/models/topologymodel.js b/src/main/resources/web/js/models/topologymodel.js index be9fa302fa2b78ed0260e04118acaddd9823ade9..c5d8f9bff2cc9bbf13a7ee615faca1f173f23457 100644 --- a/src/main/resources/web/js/models/topologymodel.js +++ b/src/main/resources/web/js/models/topologymodel.js @@ -19,8 +19,8 @@ window.Topology = Backbone.Model.extend({ url:"/wm/topology/links/json", defaults:{ - nodes: [], - links: [], + nodes: [], + links: [], }, initialize:function () { @@ -34,19 +34,25 @@ window.Topology = Backbone.Model.extend({ // console.log(data); self.nodes = {}; self.links = []; + // step 1: build unique array of switch IDs + /* this doesn't work if there's only one switch, + because there are no switch-switch links _.each(data, function (l) { - self.nodes[l['src-switch']] = true; - self.nodes[l['dst-switch']] = true; + self.nodes[l['src-switch']] = true; + self.nodes[l['dst-switch']] = true; }); // console.log(self.nodes); var nl = _.keys(self.nodes); + */ + var nl = swl.pluck('id'); self.nodes = _.map(nl, function (n) {return {name:n}}); + // step 2: build array of links in format D3 expects _.each(data, function (l) { - self.links.push({source:nl.indexOf(l['src-switch']), - target:nl.indexOf(l['dst-switch']), - value:10}); + self.links.push({source:nl.indexOf(l['src-switch']), + target:nl.indexOf(l['dst-switch']), + value:10}); }); // console.log(self.nodes); // console.log(self.links); diff --git a/src/main/resources/web/js/views/flow.js b/src/main/resources/web/js/views/flow.js index 3d0609240edef0e4281d6b9741cea1d36e39d5d7..65e0b71d9e70a4522250e9c53f26499f68ad4c1e 100644 --- a/src/main/resources/web/js/views/flow.js +++ b/src/main/resources/web/js/views/flow.js @@ -48,7 +48,7 @@ window.FlowListItemView = Backbone.View.extend({ // TODO throughput (bps) and pps sparklines would be nice here // TODO hovering over a MAC address could show a compact view of that host window.FlowListView = Backbone.View.extend({ - + initialize:function () { this.template = _.template(tpl.get('flow-list')); this.model.bind("change", this.render, this); @@ -56,11 +56,11 @@ window.FlowListView = Backbone.View.extend({ }, render:function (eventName) { - // console.log("rendering flow list view: " + this.model.models.length); + // console.log("rendering flow list view: " + this.model.models.length); $(this.el).html(this.template({nflows:this.model.length})); _.each(this.model.models, function (f) { $(this.el).find('table.flow-table > tbody') - .append(new FlowListItemView({model:f}).render().el); + .append(new FlowListItemView({model:f}).render().el); }, this); return this; }, diff --git a/src/main/resources/web/js/views/port.js b/src/main/resources/web/js/views/port.js index e6001e334df06e0d219a08a69af8f67dae2d7892..e9aadb9103a13b320e9131add8e0dfc68ca015fe 100644 --- a/src/main/resources/web/js/views/port.js +++ b/src/main/resources/web/js/views/port.js @@ -49,7 +49,7 @@ window.PortListItemView = Backbone.View.extend({ // TODO throughput sparklines would be nice here window.PortListView = Backbone.View.extend({ - + initialize:function () { this.template = _.template(tpl.get('port-list')); this.model.bind("change", this.render, this); @@ -57,11 +57,11 @@ window.PortListView = Backbone.View.extend({ }, render:function (eventName) { - // console.log("rendering port list view"); + // console.log("rendering port list view"); $(this.el).html(this.template({nports:this.model.length})); _.each(this.model.models, function (p) { $(this.el).find('table.port-table > tbody') - .append(new PortListItemView({model:p}).render().el); + .append(new PortListItemView({model:p}).render().el); }, this); return this; }, diff --git a/src/main/resources/web/js/views/status.js b/src/main/resources/web/js/views/status.js index d56507e29e142be3993f0d708fbd1fe5ed1d5c64..52c6c1cbaa3e5a3279983979f625086ebe742f67 100644 --- a/src/main/resources/web/js/views/status.js +++ b/src/main/resources/web/js/views/status.js @@ -22,7 +22,7 @@ window.StatusView = Backbone.View.extend({ }, render:function (eventName) { - // console.log("rendering status"); + // console.log("rendering status"); $(this.el).html(this.template(this.model.toJSON())); //$(this.el).html(this.template()); return this; diff --git a/src/main/resources/web/js/views/switch.js b/src/main/resources/web/js/views/switch.js index 9aa850a364ced8f85374fa1522268127da8c9590..178dd99bba9021ac1675a17a46af2e77dc90e7f3 100644 --- a/src/main/resources/web/js/views/switch.js +++ b/src/main/resources/web/js/views/switch.js @@ -42,7 +42,7 @@ window.SwitchListItemView = Backbone.View.extend({ initialize:function () { this.template = _.template(tpl.get('switch-list-item')); this.model.bind("change", this.render, this); - //this.model.bind("destroy", this.close, this); + //this.model.bind("destroy", this.close, this); }, render:function (eventName) { @@ -53,7 +53,7 @@ window.SwitchListItemView = Backbone.View.extend({ }); window.SwitchListView = Backbone.View.extend({ - + initialize:function () { this.template = _.template(tpl.get('switch-list')); this.model.bind("change", this.render, this); @@ -63,7 +63,7 @@ window.SwitchListView = Backbone.View.extend({ $(this.el).html(this.template({nswitches:swl.length})); _.each(this.model.models, function (sw) { $(this.el).find('table.switch-table > tbody') - .append(new SwitchListItemView({model:sw}).render().el); + .append(new SwitchListItemView({model:sw}).render().el); }, this); return this; }, diff --git a/src/main/resources/web/tpl/flow-list.html b/src/main/resources/web/tpl/flow-list.html index 4b6e4065b97cbdd5fe3b98c4eeea92c270bb804c..4bd0a856c9e47138aa88af71404b4567f1a822dd 100644 --- a/src/main/resources/web/tpl/flow-list.html +++ b/src/main/resources/web/tpl/flow-list.html @@ -1,7 +1,7 @@ <div class="page-header"> <h1>Flows (<%= nflows %>)</h1> </div> -<table class="table striped-table flow-table"> +<table class="table table-striped flow-table"> <thead><tr><th>Cookie</th><th>Priority</th><th>Match</th><th>Action</th><th>Packets</th><th>Bytes</th><th>Age</th><th>Timeout</th></tr></thead> <tbody> <!-- flows will be inserted here by FlowListView:render --> diff --git a/src/main/resources/web/tpl/host-list.html b/src/main/resources/web/tpl/host-list.html index ec63b3a76cab06455e251644f4e61736b209e0f8..cc4a2c067835eee5e331747d284eb86a3de1e4f3 100644 --- a/src/main/resources/web/tpl/host-list.html +++ b/src/main/resources/web/tpl/host-list.html @@ -3,7 +3,7 @@ <div class="page-header"> <h1>Hosts (<%= nhosts %>)</h1> </div> -<table class="table striped-table host-table"> +<table class="table table-striped host-table"> <thead><tr><th>MAC Address</th><!-- <th>VLAN</th> --><th>IP Address</th><th>Switch Port</th><th>Last Seen</th></tr></thead> <tbody> <!-- hosts will be inserted here by HostListView.render --> diff --git a/src/main/resources/web/tpl/port-list.html b/src/main/resources/web/tpl/port-list.html index d4c30606af8270b512d537497c8c144e732e377d..044fffff406fb22ff7eaae25d7583a2524edd66d 100644 --- a/src/main/resources/web/tpl/port-list.html +++ b/src/main/resources/web/tpl/port-list.html @@ -1,7 +1,7 @@ <div class="page-header"> <h1>Ports (<%= nports %>)</h1> </div> -<table class="table striped-table port-table"> +<table class="table table-striped port-table"> <thead><tr><th>#</th><th>Link Status</th><th>TX Bytes</th><th>RX Bytes</th><th>TX Pkts</th><th>RX Pkts</th><th>Dropped</th><th>Errors</th></tr></thead> <tbody> <!-- ports will be inserted here by PortListView:render --> diff --git a/src/main/resources/web/tpl/switch-list-item.html b/src/main/resources/web/tpl/switch-list-item.html index 7a20a5a09ad02cb3123d38e4029ddb7c4c0e98c9..c6cd4ac58b52cb5994824e615301d8251404bc21 100644 --- a/src/main/resources/web/tpl/switch-list-item.html +++ b/src/main/resources/web/tpl/switch-list-item.html @@ -1 +1 @@ -<td><a href="/switch/<%= id %>"><%= id %></a></td><td><%= manufacturerDescription %><td><%= packetCount %></td><td><%= byteCount %></td><td><%= flowCount %></td> +<td><a href="/switch/<%= id %>"><%= id %></a></td><td><%= inetAddress %></td><td><%= manufacturerDescription %><td><%= packetCount %></td><td><%= byteCount %></td><td><%= flowCount %></td><td><%= connectedSince %></td> diff --git a/src/main/resources/web/tpl/switch-list.html b/src/main/resources/web/tpl/switch-list.html index 45c02f55f13b1024d9882bb489cda6cce8f6c8f4..7e577aac84c0ed5fbb9a613fa4931a0ba6f9cdd1 100644 --- a/src/main/resources/web/tpl/switch-list.html +++ b/src/main/resources/web/tpl/switch-list.html @@ -3,8 +3,8 @@ <div class="page-header"> <h1>Switches (<%= nswitches %>)</h1> </div> -<table class="table striped-table switch-table"> - <thead><tr><th>DPID</th><th>Vendor</th><th>Packets</th><th>Bytes</th><th>Flows</th></tr></thead> +<table class="table table-striped switch-table"> + <thead><tr><th>DPID</th><th>IP Address</th><th>Vendor</th><th>Packets</th><th>Bytes</th><th>Flows</th><th>Connected Since</th></tr></thead> <tbody> <!-- switches will be inserted here by SwitchListView:render --> </tbody> diff --git a/src/main/resources/web/tpl/switch.html b/src/main/resources/web/tpl/switch.html index bfba96795031241c30500042d1331bd6ba5b400e..bc1169d383438f970a5444e8dbac679e015c0bbf 100644 --- a/src/main/resources/web/tpl/switch.html +++ b/src/main/resources/web/tpl/switch.html @@ -1,9 +1,10 @@ <div class="row"> <div class="span12"> <div class="page-header"> - <h1>Switch <%= id %></h1> + <h1>Switch <%= id %> <%= inetAddress %></h1> </div> -<p><%= manufacturerDescription %><br> +<p>Connected since <%= connectedSince %><br> +<%= manufacturerDescription %><br> <%= hardwareDescription %><br> <%= softwareDescription %><br> S/N: <%= serialNumber %><br>