From 94a6caa2a0859b8d4ffa45d9f5d6b5eb0ffa91ed Mon Sep 17 00:00:00 2001 From: Ryan Izard <rizard@g.clemson.edu> Date: Sun, 21 Dec 2014 12:58:34 -0500 Subject: [PATCH] Updated circuitpusher with new SFP syntax. Updated Forwarding(Base) to use a default priority of 1, since in OF1.3 we have a priority=0 table-miss flow that will also match. Trying to update the Web UI to display flows correctly. --- apps/circuitpusher/circuitpusher.py | 18 +- .../forwarding/Forwarding.java | 32 +- .../routing/ForwardingBase.java | 9 +- .../resources/web/js/models/switchmodel.js | 484 +++++++++--------- 4 files changed, 277 insertions(+), 266 deletions(-) diff --git a/apps/circuitpusher/circuitpusher.py b/apps/circuitpusher/circuitpusher.py index 49bbcfacc..4fa66904a 100755 --- a/apps/circuitpusher/circuitpusher.py +++ b/apps/circuitpusher/circuitpusher.py @@ -143,26 +143,26 @@ if args.action=='add': # send one flow mod per pair of APs in route # using StaticFlowPusher rest API - # IMPORTANT NOTE: current Floodlight StaticflowEntryPusher + # IMPORTANT NOTE: current Floodlight StaticflowPusher # assumes all flow entries to have unique name across all switches # this will most possibly be relaxed later, but for now we # encode each flow entry's name with both switch dpid, user # specified name, and flow type (f: forward, r: reverse, farp/rarp: arp) - command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"nw_src\":\"%s\", \"nw_dst\":\"%s\", \"dl_type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"ingress_port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowentrypusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".f", args.srcAddress, args.dstAddress, "0x800", ap1Port['shortPortNumber'], ap2Port['shortPortNumber'], controllerRestIp) + command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"ipv4_src\":\"%s\", \"ipv4_dst\":\"%s\", \"eth_type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"in_port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowpusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".f", args.srcAddress, args.dstAddress, "0x800", ap1Port['shortPortNumber'], ap2Port['shortPortNumber'], controllerRestIp) result = os.popen(command).read() print command - command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"arp_spa\":\"%s\", \"arp_dpa\":\"%s\", \"dl_type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"ingress_port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowentrypusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".farp", args.srcAddress, args.dstAddress, "0x806", ap1Port['shortPortNumber'], ap2Port['shortPortNumber'], controllerRestIp) + command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"arp_spa\":\"%s\", \"arp_tpa\":\"%s\", \"eth_type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"in_port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowpusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".farp", args.srcAddress, args.dstAddress, "0x806", ap1Port['shortPortNumber'], ap2Port['shortPortNumber'], controllerRestIp) result = os.popen(command).read() print command - command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"nw_src\":\"%s\", \"nw_dst\":\"%s\", \"dl_type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"ingress_port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowentrypusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".r", args.dstAddress, args.srcAddress, "0x800", ap2Port['shortPortNumber'], ap1Port['shortPortNumber'], controllerRestIp) + command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"ipv4_src\":\"%s\", \"ipv4_dst\":\"%s\", \"eth_type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"in_port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowpusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".r", args.dstAddress, args.srcAddress, "0x800", ap2Port['shortPortNumber'], ap1Port['shortPortNumber'], controllerRestIp) result = os.popen(command).read() print command - command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"arp_spa\":\"%s\", \"arp_dpa\":\"%s\", \"dl_type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"ingress_port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowentrypusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".rarp",args.dstAddress, args.srcAddress, "0x806", ap2Port['shortPortNumber'], ap1Port['shortPortNumber'], controllerRestIp) + command = "curl -s -d '{\"switch\": \"%s\", \"name\":\"%s\", \"arp_spa\":\"%s\", \"arp_tpa\":\"%s\", \"eth_type\":\"%s\", \"cookie\":\"0\", \"priority\":\"32768\", \"in_port\":\"%s\",\"active\":\"true\", \"actions\":\"output=%s\"}' http://%s/wm/staticflowpusher/json" % (ap1Dpid, ap1Dpid+"."+args.circuitName+".rarp",args.dstAddress, args.srcAddress, "0x806", ap2Port['shortPortNumber'], ap1Port['shortPortNumber'], controllerRestIp) result = os.popen(command).read() print command @@ -198,19 +198,19 @@ elif args.action=='delete': sw = data['Dpid'] print data, sw - command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowentrypusher/json" % (sw+"."+args.circuitName+".f", sw, controllerRestIp) + command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowpusher/json" % (sw+"."+args.circuitName+".f", sw, controllerRestIp) result = os.popen(command).read() print command, result - command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowentrypusher/json" % (sw+"."+args.circuitName+".farp", sw, controllerRestIp) + command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowpusher/json" % (sw+"."+args.circuitName+".farp", sw, controllerRestIp) result = os.popen(command).read() print command, result - command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowentrypusher/json" % (sw+"."+args.circuitName+".r", sw, controllerRestIp) + command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowpusher/json" % (sw+"."+args.circuitName+".r", sw, controllerRestIp) result = os.popen(command).read() print command, result - command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowentrypusher/json" % (sw+"."+args.circuitName+".rarp", sw, controllerRestIp) + command = "curl -X DELETE -d '{\"name\":\"%s\", \"switch\":\"%s\"}' http://%s/wm/staticflowpusher/json" % (sw+"."+args.circuitName+".rarp", sw, controllerRestIp) result = os.popen(command).read() print command, result diff --git a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java index 48643d6e2..107ee8016 100644 --- a/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java +++ b/src/main/java/net/floodlightcontroller/forwarding/Forwarding.java @@ -75,9 +75,6 @@ import org.slf4j.LoggerFactory; public class Forwarding extends ForwardingBase implements IFloodlightModule { protected static Logger log = LoggerFactory.getLogger(Forwarding.class); - protected static int DEFAULT_HARD_TIMEOUT = 0; // not final b/c could be configured from config file - protected static int DEFAULT_IDLE_TIMEOUT = 5; - @Override @LogMessageDoc(level="ERROR", message="Unexpected decision made for this packet-in={}", @@ -155,11 +152,12 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { U64 cookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0); fmb.setCookie(cookie) - .setHardTimeout(DEFAULT_HARD_TIMEOUT) - .setIdleTimeout(DEFAULT_IDLE_TIMEOUT) + .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT) + .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT) .setBufferId(OFBufferId.NO_BUFFER) .setMatch(mb.build()) - .setActions(actions); // empty list + .setActions(actions) // empty list + .setPriority(FLOWMOD_DEFAULT_PRIORITY); try { if (log.isDebugEnabled()) { @@ -449,21 +447,25 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule { Map<String, String> configParameters = context.getConfigParams(this); String tmp = configParameters.get("hard-timeout"); if (tmp != null) { - DEFAULT_HARD_TIMEOUT = Integer.parseInt(tmp); - log.info("Default hard timeout set to {}.", DEFAULT_HARD_TIMEOUT); + FLOWMOD_DEFAULT_HARD_TIMEOUT = Integer.parseInt(tmp); + log.info("Default hard timeout set to {}.", FLOWMOD_DEFAULT_HARD_TIMEOUT); } else { - log.info("Default hard timeout not configured. Using {}.", DEFAULT_HARD_TIMEOUT); + log.info("Default hard timeout not configured. Using {}.", FLOWMOD_DEFAULT_HARD_TIMEOUT); } tmp = configParameters.get("idle-timeout"); if (tmp != null) { - DEFAULT_IDLE_TIMEOUT = Integer.parseInt(tmp); - log.info("Default idle timeout set to {}.", DEFAULT_IDLE_TIMEOUT); + FLOWMOD_DEFAULT_IDLE_TIMEOUT = Integer.parseInt(tmp); + log.info("Default idle timeout set to {}.", FLOWMOD_DEFAULT_IDLE_TIMEOUT); } else { - log.info("Default idle timeout not configured. Using {}.", DEFAULT_IDLE_TIMEOUT); + log.info("Default idle timeout not configured. Using {}.", FLOWMOD_DEFAULT_IDLE_TIMEOUT); + } + tmp = configParameters.get("priority"); + if (tmp != null) { + FLOWMOD_DEFAULT_PRIORITY = Integer.parseInt(tmp); + log.info("Default priority set to {}.", FLOWMOD_DEFAULT_PRIORITY); + } else { + log.info("Default priority not configured. Using {}.", FLOWMOD_DEFAULT_PRIORITY); } - - - } @Override diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java index 634757b52..1235cf522 100644 --- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java +++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java @@ -80,8 +80,9 @@ public abstract class ForwardingBase implements IOFMessageListener { protected static int OFMESSAGE_DAMPER_CAPACITY = 10000; // TODO: find sweet spot protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms - public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds - public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite + public static int FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds + public static int FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite + public static int FLOWMOD_DEFAULT_PRIORITY = 1; // 0 is the default table-miss flow in OF1.3+, so we need to use 1 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT_CONSTANT = 5; public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT_CONSTANT = 0; @@ -266,7 +267,8 @@ public abstract class ForwardingBase implements IOFMessageListener { .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT) .setBufferId(OFBufferId.NO_BUFFER) .setCookie(cookie) - .setOutPort(outPort); + .setOutPort(outPort) + .setPriority(FLOWMOD_DEFAULT_PRIORITY); try { if (log.isTraceEnabled()) { @@ -487,6 +489,7 @@ public abstract class ForwardingBase implements IOFMessageListener { fmb.setCookie(cookie) .setHardTimeout(hardTimeout) .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT) + .setPriority(FLOWMOD_DEFAULT_PRIORITY) .setBufferId(OFBufferId.NO_BUFFER) .setMatch(mb.build()) .setActions(actions); diff --git a/src/main/resources/web/js/models/switchmodel.js b/src/main/resources/web/js/models/switchmodel.js index fc47aea60..5a9403fed 100644 --- a/src/main/resources/web/js/models/switchmodel.js +++ b/src/main/resources/web/js/models/switchmodel.js @@ -1,244 +1,250 @@ /* - Copyright 2012 IBM - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ + Copyright 2012 IBM + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ window.Switch = Backbone.Model.extend({ - - urlRoot:"/wm/core/switch/", - - defaults: { - datapathDescription: '', - hardwareDescription: '', - manufacturerDescription: '', - serialNumber: '', - softwareDescription: '', - flowCount: ' ', - packetCount: ' ', - byteCount: ' ', - }, - - initialize:function () { - var self = this; - - //console.log("fetching switch " + this.id + " desc") - $.ajax({ - url:hackBase + "/wm/core/switch/" + self.id + '/desc/json', - dataType:"json", - success:function (data) { - //console.log("fetched switch " + self.id + " desc"); - //console.log(data['desc']); - self.set(data['desc']); - } - }); - - //console.log("fetching switch " + this.id + " aggregate") - $.ajax({ - url:hackBase + "/wm/core/switch/" + self.id + '/aggregate/json', - dataType:"json", - success:function (data) { - //console.log("fetched switch " + self.id + " aggregate"); - //console.log(data['aggregate']); - self.set(data['aggregate']); - } - }); - self.trigger('add'); - this.ports = new PortCollection(); - this.flows = new FlowCollection(); - //this.loadPorts(); - //this.loadFlows(); - }, - - fetch:function () { - this.initialize() - }, - - loadPorts:function () { - var self = this; - //console.log("fetching switch " + this.id + " ports") - //console.log("fetching switch " + this.id + " features") - $.when($.ajax({ - url:hackBase + "/wm/core/switch/" + self.id + '/port/json', - dataType:"json", - success:function (data) { - //console.log("fetched switch " + self.id + " ports"); - var old_ids = self.ports.pluck('id'); - //console.log("old_ids" + old_ids); - - // create port models - _.each(data['port'], function(p) { - // workaround for REST serialization signed/unsigned bug - if(p.portNumber < 0) {p.portNumber = 65536 + p.portNumber}; - - p.id = self.id+'-'+p.portNumber; - old_ids = _.without(old_ids, p.id); - p.dropped = p.receiveDropped + p.transmitDropped; - p.errors = p.receiveCRCErrors + p.receiveFrameErrors + p.receiveOverrunErrors + - p.receiveFrameErrors + p.transmitErrors; - // this is a knda kludgy way to merge models - var m = self.ports.get(p.id); - if(m) { - m.set(p, {silent: true}); - } else { - self.ports.add(p, {silent: true}); - } - //console.log(p); - }); - - // old_ids now holds ports that no longer exist; remove them - //console.log("old_ids" + old_ids); - _.each(old_ids, function(p) { - console.log("removing port " + p); - self.remove({id:p}); - }); - } - }), - $.ajax({ - url:hackBase + "/wm/core/switch/" + self.id + '/port-desc/json', - dataType:"json", - success:function (data) { - //console.log("fetched switch " + self.id + " features"); - //console.log(data['portDesc']); - // update port models - _.each(data['portDesc'], function(p) { - p.id = self.id+'-'+p.portNumber; - if(p.name != p.portNumber) { - p.name = p.portNumber + ' (' + p.name + ')'; - } - p.status = ''; - p.status += (p.state & 1) ? 'DOWN' : 'UP'; - switch(p.currentFeatures & 0x7f) { - case 1: - p.status += ' 10 Mbps'; - break; - case 2: - p.status += ' 10 Mbps FDX'; - break; - case 4: - p.status += ' 100 Mbps'; - break; - case 8: - p.status += ' 100 Mbps FDX'; - break; - case 16: - p.status += ' 1 Gbps'; // RLY? - break; - case 32: - p.status += ' 1 Gbps FDX'; - break; - case 64: - p.status += ' 10 Gbps FDX'; - break; - } - // TODO parse copper/fiber, autoneg, pause - - // this is a knda kludgy way to merge models - var m = self.ports.get(p.id); - if(m) { - m.set(p, {silent: true}); - } else { - self.ports.add(p, {silent: true}); - } - //console.log(p); - }); - } - })).done(function() { - self.ports.trigger('add'); // batch redraws - }); - }, - - loadFlows:function () { - var self = this; - //console.log("fetching switch " + this.id + " flows") - $.ajax({ - url:hackBase + "/wm/core/switch/" + self.id + '/flow/json', - dataType:"json", - success:function (data) { - //console.log("fetched switch " + self.id + " flows"); - var flows = data['flows']; - //console.log(flows); - - // create flow models - var i = 0; - _.each(flows, function(f) { - f.id = self.id + '-' + i++; - - // build human-readable match - f.matchHTML = ''; - if(f.hasOwnProperty('match')) { - _.each(f.match, function(value , key) { - f.matchHTML += key + "=" + value +" "; - },f); - } - f.matchHTML = f.matchHTML.substr(0, f.matchHTML.length - 2); - - f.applyActionText = ''; - f.writeActionText = ''; - if(f.hasOwnProperty('instructions')) { - if(f.instructions.hasOwnProperty('instruction_apply_actions')) { - _.each(f.instructions.instruction_apply_actions, function(value, key) { - f.applyActionText += key + ":" + value +" "; - },f); - } - if(f.instructions.hasOwnProperty('instruction_write_actions')) { - _.each(f.instructions.instruction_write_actions, function(value, key) { - f.writeActionText += key + ":" + value +" "; - },f); - } - - } - // build human-readable action list - f.applyActionText = f.applyActionText.substr(0, f.applyActionText.length - 2); - f.writeActionText = f.writeActionText.substr(0, f.writeActionText.length - 2); - //console.log(f); - self.flows.add(f, {silent: true}); - }); - self.flows.trigger('add'); - } - }); - }, -}); + + urlRoot:"/wm/core/switch/", + + defaults: { + datapathDescription: '', + hardwareDescription: '', + manufacturerDescription: '', + serialNumber: '', + softwareDescription: '', + flowCount: ' ', + packetCount: ' ', + byteCount: ' ', + }, + + initialize:function () { + var self = this; + + //console.log("fetching switch " + this.id + " desc") + $.ajax({ + url:hackBase + "/wm/core/switch/" + self.id + '/desc/json', + dataType:"json", + success:function (data) { + //console.log("fetched switch " + self.id + " desc"); + //console.log(data['desc']); + self.set(data['desc']); + } + }); + + //console.log("fetching switch " + this.id + " aggregate") + $.ajax({ + url:hackBase + "/wm/core/switch/" + self.id + '/aggregate/json', + dataType:"json", + success:function (data) { + //console.log("fetched switch " + self.id + " aggregate"); + //console.log(data['aggregate']); + self.set(data['aggregate']); + } + }); + self.trigger('add'); + this.ports = new PortCollection(); + this.flows = new FlowCollection(); + //this.loadPorts(); + //this.loadFlows(); + }, + + fetch:function () { + this.initialize() + }, + + loadPorts:function () { + var self = this; + //console.log("fetching switch " + this.id + " ports") + //console.log("fetching switch " + this.id + " features") + $.when($.ajax({ + url:hackBase + "/wm/core/switch/" + self.id + '/port/json', + dataType:"json", + success:function (data) { + //console.log("fetched switch " + self.id + " ports"); + var old_ids = self.ports.pluck('id'); + //console.log("old_ids" + old_ids); + + // create port models + _.each(data['port'], function(p) { + // workaround for REST serialization signed/unsigned bug + if(p.portNumber < 0) {p.portNumber = 65536 + p.portNumber}; + + p.id = self.id+'-'+p.portNumber; + old_ids = _.without(old_ids, p.id); + p.dropped = p.receiveDropped + p.transmitDropped; + p.errors = p.receiveCRCErrors + p.receiveFrameErrors + p.receiveOverrunErrors + + p.receiveFrameErrors + p.transmitErrors; + // this is a knda kludgy way to merge models + var m = self.ports.get(p.id); + if(m) { + m.set(p, {silent: true}); + } else { + self.ports.add(p, {silent: true}); + } + //console.log(p); + }); + + // old_ids now holds ports that no longer exist; remove them + //console.log("old_ids" + old_ids); + _.each(old_ids, function(p) { + console.log("removing port " + p); + self.remove({id:p}); + }); + } + }), + $.ajax({ + url:hackBase + "/wm/core/switch/" + self.id + '/port-desc/json', + dataType:"json", + success:function (data) { + //console.log("fetched switch " + self.id + " features"); + //console.log(data['portDesc']); + // update port models + _.each(data['portDesc'], function(p) { + p.id = self.id+'-'+p.portNumber; + if(p.name != p.portNumber) { + p.name = p.portNumber + ' (' + p.name + ')'; + } + p.status = ''; + p.status += (p.state & 1) ? 'DOWN' : 'UP'; + switch(p.currentFeatures & 0x7f) { + case 1: + p.status += ' 10 Mbps'; + break; + case 2: + p.status += ' 10 Mbps FDX'; + break; + case 4: + p.status += ' 100 Mbps'; + break; + case 8: + p.status += ' 100 Mbps FDX'; + break; + case 16: + p.status += ' 1 Gbps'; // RLY? + break; + case 32: + p.status += ' 1 Gbps FDX'; + break; + case 64: + p.status += ' 10 Gbps FDX'; + break; + } + // TODO parse copper/fiber, autoneg, pause + + // this is a knda kludgy way to merge models + var m = self.ports.get(p.id); + if(m) { + m.set(p, {silent: true}); + } else { + self.ports.add(p, {silent: true}); + } + //console.log(p); + }); + } + })).done(function() { + self.ports.trigger('add'); // batch redraws + }); + }, + + loadFlows:function () { + var self = this; + //console.log("fetching switch " + this.id + " flows") + $.ajax({ + url:hackBase + "/wm/core/switch/" + self.id + '/flow/json', + dataType:"json", + success:function (data) { + console.log("fetched switch " + self.id + " flows"); + var flows = data['flows']; + console.log(flows); + + // create flow models + var i = 0; + _.each(flows, function(f) { + f.id = self.id + '-' + i++; + + // build human-readable match + f.matchHTML = ''; + if(f.hasOwnProperty('match')) { + _.each(f.match, function(value , key) { + f.matchHTML += key + "=" + value +" "; + },f); + } + f.matchHTML = f.matchHTML.substr(0, f.matchHTML.length - 1); + + f.applyActionText = ''; + f.writeActionText = ''; + if(f.hasOwnProperty('instructions')) { + if(f.instructions.hasOwnProperty('instruction_apply_actions')) { + _.each(f.instructions.instruction_apply_actions, function(value, key) { + f.applyActionText += key + ":" + value +" "; + },f); + } + if(f.instructions.hasOwnProperty('instruction_write_actions')) { + _.each(f.instructions.instruction_write_actions, function(value, key) { + f.writeActionText += key + ":" + value +" "; + },f); + } + + } + if(f.hasOwnProperty('actions')) { + _.each(f.actions, function(value, key) { + f.applyActionText += key + ":" + value +" "; + },f); + } + } + // build human-readable action list + f.applyActionText = f.applyActionText.substr(0, f.applyActionText.length - 1); + f.writeActionText = f.writeActionText.substr(0, f.writeActionText.length - 1); + console.log(f); + self.flows.add(f, {silent: true}); + }); + self.flows.trigger('add'); + } + }); + }, + }); window.SwitchCollection = Backbone.Collection.extend({ - - model:Switch, - - fetch:function () { - var self = this; - //console.log("fetching switch list") - $.ajax({ - url:hackBase + "/wm/core/controller/switches/json", - dataType:"json", - success:function (data) { - //console.log("fetched switch list: " + data.length); - //console.log(data); - var old_ids = self.pluck('id'); - //console.log("old_ids" + old_ids); - - _.each(data, function(sw) { - old_ids = _.without(old_ids, sw['switchDPID']); - self.add({id: sw['switchDPID'], inetAddress: sw.inetAddress, - connectedSince: new Date(sw.connectedSince).toLocaleString()})}); - - // old_ids now holds switches that no longer exist; remove them - //console.log("old_ids" + old_ids); - _.each(old_ids, function(sw) { - console.log("removing switch " + sw); - self.remove({id:sw}); - }); - }, - }); - }, - -}); + + model:Switch, + + fetch:function () { + var self = this; + //console.log("fetching switch list") + $.ajax({ + url:hackBase + "/wm/core/controller/switches/json", + dataType:"json", + success:function (data) { + //console.log("fetched switch list: " + data.length); + //console.log(data); + var old_ids = self.pluck('id'); + //console.log("old_ids" + old_ids); + + _.each(data, function(sw) { + old_ids = _.without(old_ids, sw['switchDPID']); + self.add({id: sw['switchDPID'], inetAddress: sw.inetAddress, + connectedSince: new Date(sw.connectedSince).toLocaleString()})}); + + // old_ids now holds switches that no longer exist; remove them + //console.log("old_ids" + old_ids); + _.each(old_ids, function(sw) { + console.log("removing switch " + sw); + self.remove({id:sw}); + }); + }, + }); + }, + + }); -- GitLab