diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java index 63d361fcd9a3fc73500c48a770aa0cf9c6a9410b..423b8c1f6de9421fa78ba0d9733573db250dcf36 100644 --- a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java @@ -18,25 +18,59 @@ package net.floodlightcontroller.core.web; import java.util.Set; +import java.util.HashSet; import net.floodlightcontroller.core.internal.IOFSwitchService; +import net.floodlightcontroller.core.IOFSwitch; import org.projectfloodlight.openflow.types.DatapathId; import org.restlet.resource.Get; import org.restlet.resource.ServerResource; +import net.floodlightcontroller.core.web.serializers.DPIDSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + /** * Get a list of switches connected to the controller * @author readams */ public class ControllerSwitchesResource extends ServerResource { - - public static final String DPID_ERROR = "Invalid switch DPID string. Must be a 64-bit value in the form 00:11:22:33:44:55:66:77."; - + + public static final String DPID_ERROR = "Invalid switch DPID string. Must be a 64-bit value in the form 00:11:22:33:44:55:66:77."; + public static class DatapathIDJsonSerializerWrapper { + private final DatapathId dpid; + private final String inetAddress; + private final long connectedSince; + public DatapathIDJsonSerializerWrapper(DatapathId dpid, String inetAddress, long connectedSince) { + this.dpid = dpid; + this.inetAddress = inetAddress; + this.connectedSince = connectedSince; + } + + @JsonSerialize(using=DPIDSerializer.class) + public DatapathId getSwitchDPID() { + return dpid; + } + public String getInetAddress() { + return inetAddress; + } + public long getConnectedSince() { + return connectedSince; + } + + + + } + @Get("json") - public Set<DatapathId> retrieve(){ + public Set<DatapathIDJsonSerializerWrapper> retrieve(){ IOFSwitchService switchService = (IOFSwitchService) getContext().getAttributes(). get(IOFSwitchService.class.getCanonicalName()); - return switchService.getAllSwitchDpids(); + Set<DatapathIDJsonSerializerWrapper> dpidSets = new HashSet<DatapathIDJsonSerializerWrapper>(); + for(IOFSwitch sw: switchService.getAllSwitchMap().values()) { + dpidSets.add(new DatapathIDJsonSerializerWrapper(sw.getId(), sw.getInetAddress().toString(), sw.getConnectedSince().getTime())); + + } + return dpidSets; } } diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java index 75e99083591fe2bc25597ddf119c5a1d8dac320b..1609818f4bc836e3b8cfb0e9a0e9d968105af368 100644 --- a/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java +++ b/src/main/java/net/floodlightcontroller/core/web/SwitchResourceBase.java @@ -127,6 +127,8 @@ public class SwitchResourceBase extends ServerResource { case METER_CONFIG: case METER_FEATURES: case PORT_DESC: + req = sw.getOFFactory().buildPortDescStatsRequest() + .build(); case TABLE_FEATURES: default: log.error("Stats Request Type {} not implemented yet", statType.name()); @@ -174,4 +176,4 @@ public class SwitchResourceBase extends ServerResource { return getSwitchFeaturesReply(DatapathId.of(switchId)); } -} \ No newline at end of file +} diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java index a6e7ad5e3d1145e9eed765f3333a735506a46aad..a100ddaf0b01fe1867e9d5738beaeca3ece335f1 100644 --- a/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/SwitchStatisticsResource.java @@ -91,7 +91,7 @@ public class SwitchStatisticsResource extends SwitchResourceBase { result.setStatType(OFStatsType.EXPERIMENTER); break; case OFStatsTypeStrings.PORT_DESC: - values = getSwitchFeaturesReply(switchId); + values = getSwitchStatistics(switchId, OFStatsType.PORT_DESC); result.setStatType(OFStatsType.PORT_DESC); break; case OFStatsTypeStrings.GROUP: diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java index e9766245a8e25905470715aed9ef8eff563ba75d..16012307a7c0a9763e2c5892cd4933de828cf671 100644 --- a/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java +++ b/src/main/java/net/floodlightcontroller/core/web/serializers/StatsReplySerializer.java @@ -35,465 +35,602 @@ import net.floodlightcontroller.util.MatchUtils; import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; +import org.projectfloodlight.openflow.protocol.OFDescStatsReply; +import org.projectfloodlight.openflow.protocol.OFPortStatsReply; +import org.projectfloodlight.openflow.protocol.OFPortStatsEntry; +import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply; +import org.projectfloodlight.openflow.protocol.OFPortDesc; +import org.projectfloodlight.openflow.protocol.OFPortFeatures; + +//Use the loxigen's serializer +import org.projectfloodlight.openflow.protocol.ver13.OFPortFeaturesSerializerVer13; +import org.projectfloodlight.openflow.protocol.ver12.OFPortFeaturesSerializerVer12; +import org.projectfloodlight.openflow.protocol.ver11.OFPortFeaturesSerializerVer11; +import org.projectfloodlight.openflow.protocol.ver10.OFPortFeaturesSerializerVer10; +import org.projectfloodlight.openflow.protocol.ver13.OFPortStateSerializerVer13; +import org.projectfloodlight.openflow.protocol.ver12.OFPortStateSerializerVer12; +import org.projectfloodlight.openflow.protocol.ver11.OFPortStateSerializerVer11; +import org.projectfloodlight.openflow.protocol.ver10.OFPortStateSerializerVer10; +import org.projectfloodlight.openflow.protocol.ver13.OFPortConfigSerializerVer13; +import org.projectfloodlight.openflow.protocol.ver12.OFPortConfigSerializerVer12; +import org.projectfloodlight.openflow.protocol.ver11.OFPortConfigSerializerVer11; +import org.projectfloodlight.openflow.protocol.ver10.OFPortConfigSerializerVer10; + +import org.projectfloodlight.openflow.protocol.OFAggregateStatsReply; import org.projectfloodlight.openflow.protocol.OFVersion; import org.projectfloodlight.openflow.protocol.match.*; import org.projectfloodlight.openflow.protocol.oxm.*; import org.projectfloodlight.openflow.protocol.instruction.*; import org.projectfloodlight.openflow.protocol.action.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Serialize a DPID as colon-separated hexadecimal */ public class StatsReplySerializer extends JsonSerializer<StatsReply> { - @SuppressWarnings("unchecked") - @Override - public void serialize(StatsReply reply, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { - // Return a nice error to user if the request we're about to serialize was bad - if (reply.getValues() == null) { - jGen.writeStartObject(); - jGen.writeObjectFieldStart("ERROR"); - jGen.writeStringField("1)", "Invalid DPID and/or stats/features request, or"); - jGen.writeStringField("2)", "The switch might also be disconncted from the controller"); - jGen.writeEndObject(); - jGen.writeObjectFieldStart("Valid OFStatsTypes are"); - jGen.writeStringField("1)", OFStatsTypeStrings.AGGREGATE); - jGen.writeStringField("2)", OFStatsTypeStrings.DESC); - jGen.writeStringField("3)", OFStatsTypeStrings.EXPERIMENTER); - jGen.writeStringField("4)", OFStatsTypeStrings.FEATURES); - jGen.writeStringField("5)", OFStatsTypeStrings.FLOW); - jGen.writeStringField("6)", OFStatsTypeStrings.GROUP); - jGen.writeStringField("7)", OFStatsTypeStrings.GROUP_DESC); - jGen.writeStringField("8)", OFStatsTypeStrings.GROUP_FEATURES); - jGen.writeStringField("9)", OFStatsTypeStrings.METER); - jGen.writeStringField("A)", OFStatsTypeStrings.METER_CONFIG); - jGen.writeStringField("B)", OFStatsTypeStrings.PORT); - jGen.writeStringField("C)", OFStatsTypeStrings.PORT_DESC); - jGen.writeStringField("D)", OFStatsTypeStrings.QUEUE); - jGen.writeStringField("E)", OFStatsTypeStrings.TABLE); - jGen.writeStringField("F)", OFStatsTypeStrings.TABLE_FEATURES); - jGen.writeEndObject(); - jGen.writeEndObject(); - return; - } - - jGen.configure(Feature.WRITE_NUMBERS_AS_STRINGS, true); // IMHO this just looks nicer and is easier to read if everything is quoted - jGen.writeStartObject(); - jGen.writeStringField("dpid", reply.getDatapathId().toString()); - switch (reply.getStatType()) { - case PORT: - // handle port - break; - case QUEUE: - // handle queue - break; - case FLOW: - // handle flow. Can safely cast to List<OFFlowStatsReply>. - serializeFlowReply((List<OFFlowStatsReply>) reply.getValues(), jGen); - break; - case AGGREGATE: - // handle aggregate - break; - case DESC: - // handle desc - break; - case TABLE: - // handle table - break; - case TABLE_FEATURES: - // handle features - break; - // TODO need to handle new OF1.1+ stats reply types - case EXPERIMENTER: - break; - case GROUP: - break; - case GROUP_DESC: - break; - case GROUP_FEATURES: - break; - case METER: - break; - case METER_CONFIG: - break; - case METER_FEATURES: - break; - case PORT_DESC: - break; - default: - break; - } - jGen.writeEndObject(); - } + protected static Logger logger = LoggerFactory.getLogger(StatsReplySerializer.class); + @SuppressWarnings("unchecked") + @Override + public void serialize(StatsReply reply, JsonGenerator jGen, SerializerProvider serializer) throws IOException, JsonProcessingException { + // Return a nice error to user if the request we're about to serialize was bad + if (reply.getValues() == null) { + jGen.writeStartObject(); + jGen.writeObjectFieldStart("ERROR"); + jGen.writeStringField("1)", "Invalid DPID and/or stats/features request, or"); + jGen.writeStringField("2)", "The switch might also be disconncted from the controller"); + jGen.writeEndObject(); + jGen.writeObjectFieldStart("Valid OFStatsTypes are"); + jGen.writeStringField("1)", OFStatsTypeStrings.AGGREGATE); + jGen.writeStringField("2)", OFStatsTypeStrings.DESC); + jGen.writeStringField("3)", OFStatsTypeStrings.EXPERIMENTER); + jGen.writeStringField("4)", OFStatsTypeStrings.FEATURES); + jGen.writeStringField("5)", OFStatsTypeStrings.FLOW); + jGen.writeStringField("6)", OFStatsTypeStrings.GROUP); + jGen.writeStringField("7)", OFStatsTypeStrings.GROUP_DESC); + jGen.writeStringField("8)", OFStatsTypeStrings.GROUP_FEATURES); + jGen.writeStringField("9)", OFStatsTypeStrings.METER); + jGen.writeStringField("A)", OFStatsTypeStrings.METER_CONFIG); + jGen.writeStringField("B)", OFStatsTypeStrings.PORT); + jGen.writeStringField("C)", OFStatsTypeStrings.PORT_DESC); + jGen.writeStringField("D)", OFStatsTypeStrings.QUEUE); + jGen.writeStringField("E)", OFStatsTypeStrings.TABLE); + jGen.writeStringField("F)", OFStatsTypeStrings.TABLE_FEATURES); + jGen.writeEndObject(); + jGen.writeEndObject(); + return; + } + + jGen.configure(Feature.WRITE_NUMBERS_AS_STRINGS, true); // IMHO this just looks nicer and is easier to read if everything is quoted + jGen.writeStartObject(); + jGen.writeStringField("dpid", reply.getDatapathId().toString()); + switch (reply.getStatType()) { + case PORT: + // handle port + serializePortReply((List<OFPortStatsReply>) reply.getValues(), jGen); + break; + case QUEUE: + // handle queue + break; + case FLOW: + // handle flow. Can safely cast to List<OFFlowStatsReply>. + serializeFlowReply((List<OFFlowStatsReply>) reply.getValues(), jGen); + break; + case AGGREGATE: + // handle aggregate + serializeAggregateReply((List<OFAggregateStatsReply>) reply.getValues(), jGen); + break; + case DESC: + // handle desc + serializeDescReply((List<OFDescStatsReply>) reply.getValues(), jGen); + break; + case TABLE: + // handle table + break; + case TABLE_FEATURES: + // handle features + break; + // TODO need to handle new OF1.1+ stats reply types + case EXPERIMENTER: + break; + case GROUP: + break; + case GROUP_DESC: + break; + case GROUP_FEATURES: + break; + case METER: + break; + case METER_CONFIG: + break; + case METER_FEATURES: + break; + case PORT_DESC: + serializePortDescReply((List<OFPortDescStatsReply>) reply.getValues(), jGen); + break; + default: + break; + } + jGen.writeEndObject(); + } + + public void serializePortReply(List<OFPortStatsReply> portReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{ + OFPortStatsReply portReply = portReplies.get(0); // we will get only one PortReply and it will contains many OFPortStatsEntry ? + jGen.writeStringField("version", portReply.getVersion().toString()); //return the enum name + jGen.writeFieldName("port"); + jGen.writeStartArray(); + for(OFPortStatsEntry entry : portReply.getEntries()) { + jGen.writeStartObject(); + jGen.writeStringField("portNumber",entry.getPortNo().toString()); + jGen.writeNumberField("receivePackets", entry.getRxPackets().getValue()); + jGen.writeNumberField("transmitPackets", entry.getTxPackets().getValue()); + jGen.writeNumberField("receiveBytes", entry.getRxBytes().getValue()); + jGen.writeNumberField("transmitBytes", entry.getTxBytes().getValue()); + jGen.writeNumberField("receiveDropped", entry.getRxDropped().getValue()); + jGen.writeNumberField("transmitDropped", entry.getTxDropped().getValue()); + jGen.writeNumberField("receiveErrors", entry.getRxErrors().getValue()); + jGen.writeNumberField("transmitErrors", entry.getTxErrors().getValue()); + jGen.writeNumberField("receiveFrameErrors", entry.getRxFrameErr().getValue()); + jGen.writeNumberField("receiveOverrunErrors", entry.getRxOverErr().getValue()); + jGen.writeNumberField("receiveCRCErrors", entry.getRxCrcErr().getValue()); + jGen.writeNumberField("collisions", entry.getCollisions().getValue()); + if (OFVersion.OF_13 == entry.getVersion()) { + jGen.writeNumberField("durationSec", entry.getDurationSec()); + jGen.writeNumberField("durationNsec", entry.getDurationNsec()); + } + jGen.writeEndObject(); + } + jGen.writeEndArray(); + } + public void serializeFlowReply(List<OFFlowStatsReply> flowReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{ + int flowCount = 0; + for (OFFlowStatsReply flowReply : flowReplies) { // for each flow stats reply + //Dose the switch will reply multiple OFFlowStatsReply ? + //Or we juse need to use the first item of the list. + List<OFFlowStatsEntry> entries = flowReply.getEntries(); + jGen.writeFieldName("flows"); + jGen.writeStartArray(); + for (OFFlowStatsEntry entry : entries) { // for each flow + jGen.writeStartObject(); + // list flow stats/info + jGen.writeStringField("version", entry.getVersion().toString()); // return the enum name + jGen.writeNumberField("cookie", entry.getCookie().getValue()); + jGen.writeNumberField("tableId", entry.getTableId().getValue()); + jGen.writeNumberField("packetCount", entry.getPacketCount().getValue()); + jGen.writeNumberField("byteCount", entry.getByteCount().getValue()); + jGen.writeNumberField("durationSeconds", entry.getDurationSec()); + jGen.writeNumberField("priority", entry.getPriority()); + jGen.writeNumberField("idleTimeoutSec", entry.getIdleTimeout()); + jGen.writeNumberField("hardTimeoutSec", entry.getHardTimeout()); + jGen.writeNumberField("flags", entry.getFlags()); + // list flow matches + jGen.writeObjectFieldStart("match"); + Iterator<MatchField<?>> mi = entry.getMatch().getMatchFields().iterator(); // get iter to any match field type + Match m = entry.getMatch(); + + while (mi.hasNext()) { + MatchField<?> mf = mi.next(); + switch (mf.id) { + case IN_PORT: + jGen.writeNumberField(MatchUtils.STR_IN_PORT, m.get(MatchField.IN_PORT).getPortNumber()); + break; + case IN_PHY_PORT: + jGen.writeNumberField(MatchUtils.STR_IN_PHYS_PORT, m.get(MatchField.IN_PHY_PORT).getPortNumber()); + break; + case ARP_OP: + jGen.writeNumberField(MatchUtils.STR_ARP_OPCODE, m.get(MatchField.ARP_OP).getOpcode()); + break; + case ARP_SHA: + jGen.writeStringField(MatchUtils.STR_ARP_SHA, m.get(MatchField.ARP_SHA).toString()); + break; + case ARP_SPA: + jGen.writeStringField(MatchUtils.STR_ARP_SPA, m.get(MatchField.ARP_SPA).toString()); + break; + case ARP_THA: + jGen.writeStringField(MatchUtils.STR_ARP_DHA, m.get(MatchField.ARP_THA).toString()); + break; + case ARP_TPA: + jGen.writeStringField(MatchUtils.STR_ARP_DPA, m.get(MatchField.ARP_TPA).toString()); + break; + case ETH_TYPE: + jGen.writeNumberField(MatchUtils.STR_DL_TYPE, m.get(MatchField.ETH_TYPE).getValue()); + break; + case ETH_SRC: + jGen.writeStringField(MatchUtils.STR_DL_SRC, m.get(MatchField.ETH_SRC).toString()); + break; + case ETH_DST: + jGen.writeStringField(MatchUtils.STR_DL_DST, m.get(MatchField.ETH_DST).toString()); + break; + case VLAN_VID: + jGen.writeNumberField(MatchUtils.STR_DL_VLAN, m.get(MatchField.VLAN_VID).getVlan()); + break; + case VLAN_PCP: + jGen.writeNumberField(MatchUtils.STR_DL_VLAN_PCP, m.get(MatchField.VLAN_PCP).getValue()); + break; + case ICMPV4_TYPE: + jGen.writeNumberField(MatchUtils.STR_ICMP_TYPE, m.get(MatchField.ICMPV4_TYPE).getType()); + break; + case ICMPV4_CODE: + jGen.writeNumberField(MatchUtils.STR_ICMP_CODE, m.get(MatchField.ICMPV4_CODE).getCode()); + break; + case ICMPV6_TYPE: + jGen.writeNumberField(MatchUtils.STR_ICMPV6_TYPE, m.get(MatchField.ICMPV6_TYPE).getValue()); + break; + case ICMPV6_CODE: + jGen.writeNumberField(MatchUtils.STR_ICMPV6_CODE, m.get(MatchField.ICMPV6_CODE).getValue()); + break; + case IP_DSCP: + jGen.writeNumberField(MatchUtils.STR_NW_DSCP, m.get(MatchField.IP_DSCP).getDscpValue()); + break; + case IP_ECN: + jGen.writeNumberField(MatchUtils.STR_NW_ECN, m.get(MatchField.IP_ECN).getEcnValue()); + break; + case IP_PROTO: + jGen.writeNumberField(MatchUtils.STR_NW_PROTO, m.get(MatchField.IP_PROTO).getIpProtocolNumber()); + break; + case IPV4_SRC: + jGen.writeStringField(MatchUtils.STR_NW_SRC, m.get(MatchField.IPV4_SRC).toString()); + break; + case IPV4_DST: + jGen.writeStringField(MatchUtils.STR_NW_DST, m.get(MatchField.IPV4_DST).toString()); + break; + case IPV6_SRC: + jGen.writeStringField(MatchUtils.STR_IPV6_SRC, m.get(MatchField.IPV6_SRC).toString()); + break; + case IPV6_DST: + jGen.writeStringField(MatchUtils.STR_IPV6_DST, m.get(MatchField.IPV6_DST).toString()); + break; + case IPV6_FLABEL: + jGen.writeNumberField(MatchUtils.STR_IPV6_FLOW_LABEL, m.get(MatchField.IPV6_FLABEL).getIPv6FlowLabelValue()); + break; + case IPV6_ND_SLL: + jGen.writeNumberField(MatchUtils.STR_IPV6_ND_SSL, m.get(MatchField.IPV6_ND_SLL).getLong()); + break; + case IPV6_ND_TARGET: + jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TARGET, m.get(MatchField.IPV6_ND_TARGET).getZeroCompressStart()); + break; + case IPV6_ND_TLL: + jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TTL, m.get(MatchField.IPV6_ND_TLL).getLong()); + break; + case METADATA: + jGen.writeNumberField(MatchUtils.STR_METADATA, m.get(MatchField.METADATA).getValue().getValue()); + break; + case MPLS_LABEL: + jGen.writeNumberField(MatchUtils.STR_MPLS_LABEL, m.get(MatchField.MPLS_LABEL).getValue()); + break; + case MPLS_TC: + jGen.writeNumberField(MatchUtils.STR_MPLS_TC, m.get(MatchField.MPLS_TC).getValue()); + break; + case SCTP_SRC: + jGen.writeNumberField(MatchUtils.STR_SCTP_SRC, m.get(MatchField.SCTP_SRC).getPort()); + break; + case SCTP_DST: + jGen.writeNumberField(MatchUtils.STR_SCTP_DST, m.get(MatchField.SCTP_DST).getPort()); + break; + case TCP_SRC: + jGen.writeNumberField(MatchUtils.STR_TCP_SRC, m.get(MatchField.TCP_SRC).getPort()); + break; + case TCP_DST: + jGen.writeNumberField(MatchUtils.STR_TCP_DST, m.get(MatchField.TCP_DST).getPort()); + break; + case UDP_SRC: + jGen.writeNumberField(MatchUtils.STR_UDP_SRC, m.get(MatchField.UDP_SRC).getPort()); + break; + case UDP_DST: + jGen.writeNumberField(MatchUtils.STR_UDP_DST, m.get(MatchField.UDP_DST).getPort()); + break; + default: + // either a BSN or unknown match type + break; + } // end switch of match type + } // end while over non-wildcarded matches - public void serializeFlowReply(List<OFFlowStatsReply> flowReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{ - int flowCount = 0; - for (OFFlowStatsReply flowReply : flowReplies) { // for each flow stats reply - List<OFFlowStatsEntry> entries = flowReply.getEntries(); - for (OFFlowStatsEntry entry : entries) { // for each flow - // list flow stats/info - jGen.writeObjectFieldStart("flow" + Integer.toString(flowCount++)); // need to have different object names or JSON parser might only show the last one - jGen.writeStringField("version", entry.getVersion().toString()); // return the enum name - jGen.writeNumberField("cookie", entry.getCookie().getValue()); - jGen.writeNumberField("table_id", entry.getTableId().getValue()); - jGen.writeNumberField("packet_count", entry.getPacketCount().getValue()); - jGen.writeNumberField("byte_count", entry.getByteCount().getValue()); - jGen.writeNumberField("duration_sec", entry.getDurationSec()); - jGen.writeNumberField("priority", entry.getPriority()); - jGen.writeNumberField("idle_timeout_sec", entry.getIdleTimeout()); - jGen.writeNumberField("hard_timeout_sec", entry.getHardTimeout()); - jGen.writeNumberField("flags", entry.getFlags()); - // list flow matches - jGen.writeObjectFieldStart("match"); - Iterator<MatchField<?>> mi = entry.getMatch().getMatchFields().iterator(); // get iter to any match field type - Match m = entry.getMatch(); + jGen.writeEndObject(); // end match - while (mi.hasNext()) { - MatchField<?> mf = mi.next(); - switch (mf.id) { - case IN_PORT: - jGen.writeNumberField(MatchUtils.STR_IN_PORT, m.get(MatchField.IN_PORT).getPortNumber()); - break; - case IN_PHY_PORT: - jGen.writeNumberField(MatchUtils.STR_IN_PHYS_PORT, m.get(MatchField.IN_PHY_PORT).getPortNumber()); - break; - case ARP_OP: - jGen.writeNumberField(MatchUtils.STR_ARP_OPCODE, m.get(MatchField.ARP_OP).getOpcode()); - break; - case ARP_SHA: - jGen.writeStringField(MatchUtils.STR_ARP_SHA, m.get(MatchField.ARP_SHA).toString()); - break; - case ARP_SPA: - jGen.writeStringField(MatchUtils.STR_ARP_SPA, m.get(MatchField.ARP_SPA).toString()); - break; - case ARP_THA: - jGen.writeStringField(MatchUtils.STR_ARP_DHA, m.get(MatchField.ARP_THA).toString()); - break; - case ARP_TPA: - jGen.writeStringField(MatchUtils.STR_ARP_DPA, m.get(MatchField.ARP_TPA).toString()); - break; - case ETH_TYPE: - jGen.writeNumberField(MatchUtils.STR_DL_TYPE, m.get(MatchField.ETH_TYPE).getValue()); - break; - case ETH_SRC: - jGen.writeStringField(MatchUtils.STR_DL_SRC, m.get(MatchField.ETH_SRC).toString()); - break; - case ETH_DST: - jGen.writeStringField(MatchUtils.STR_DL_DST, m.get(MatchField.ETH_DST).toString()); - break; - case VLAN_VID: - jGen.writeNumberField(MatchUtils.STR_DL_VLAN, m.get(MatchField.VLAN_VID).getVlan()); - break; - case VLAN_PCP: - jGen.writeNumberField(MatchUtils.STR_DL_VLAN_PCP, m.get(MatchField.VLAN_PCP).getValue()); - break; - case ICMPV4_TYPE: - jGen.writeNumberField(MatchUtils.STR_ICMP_TYPE, m.get(MatchField.ICMPV4_TYPE).getType()); - break; - case ICMPV4_CODE: - jGen.writeNumberField(MatchUtils.STR_ICMP_CODE, m.get(MatchField.ICMPV4_CODE).getCode()); - break; - case ICMPV6_TYPE: - jGen.writeNumberField(MatchUtils.STR_ICMPV6_TYPE, m.get(MatchField.ICMPV6_TYPE).getValue()); - break; - case ICMPV6_CODE: - jGen.writeNumberField(MatchUtils.STR_ICMPV6_CODE, m.get(MatchField.ICMPV6_CODE).getValue()); - break; - case IP_DSCP: - jGen.writeNumberField(MatchUtils.STR_NW_DSCP, m.get(MatchField.IP_DSCP).getDscpValue()); - break; - case IP_ECN: - jGen.writeNumberField(MatchUtils.STR_NW_ECN, m.get(MatchField.IP_ECN).getEcnValue()); - break; - case IP_PROTO: - jGen.writeNumberField(MatchUtils.STR_NW_PROTO, m.get(MatchField.IP_PROTO).getIpProtocolNumber()); - break; - case IPV4_SRC: - jGen.writeStringField(MatchUtils.STR_NW_SRC, m.get(MatchField.IPV4_SRC).toString()); - break; - case IPV4_DST: - jGen.writeStringField(MatchUtils.STR_NW_DST, m.get(MatchField.IPV4_DST).toString()); - break; - case IPV6_SRC: - jGen.writeStringField(MatchUtils.STR_IPV6_SRC, m.get(MatchField.IPV6_SRC).toString()); - break; - case IPV6_DST: - jGen.writeStringField(MatchUtils.STR_IPV6_DST, m.get(MatchField.IPV6_DST).toString()); - break; - case IPV6_FLABEL: - jGen.writeNumberField(MatchUtils.STR_IPV6_FLOW_LABEL, m.get(MatchField.IPV6_FLABEL).getIPv6FlowLabelValue()); - break; - case IPV6_ND_SLL: - jGen.writeNumberField(MatchUtils.STR_IPV6_ND_SSL, m.get(MatchField.IPV6_ND_SLL).getLong()); - break; - case IPV6_ND_TARGET: - jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TARGET, m.get(MatchField.IPV6_ND_TARGET).getZeroCompressStart()); - break; - case IPV6_ND_TLL: - jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TTL, m.get(MatchField.IPV6_ND_TLL).getLong()); - break; - case METADATA: - jGen.writeNumberField(MatchUtils.STR_METADATA, m.get(MatchField.METADATA).getValue().getValue()); - break; - case MPLS_LABEL: - jGen.writeNumberField(MatchUtils.STR_MPLS_LABEL, m.get(MatchField.MPLS_LABEL).getValue()); - break; - case MPLS_TC: - jGen.writeNumberField(MatchUtils.STR_MPLS_TC, m.get(MatchField.MPLS_TC).getValue()); - break; - case SCTP_SRC: - jGen.writeNumberField(MatchUtils.STR_SCTP_SRC, m.get(MatchField.SCTP_SRC).getPort()); - break; - case SCTP_DST: - jGen.writeNumberField(MatchUtils.STR_SCTP_DST, m.get(MatchField.SCTP_DST).getPort()); - break; - case TCP_SRC: - jGen.writeNumberField(MatchUtils.STR_TCP_SRC, m.get(MatchField.TCP_SRC).getPort()); - break; - case TCP_DST: - jGen.writeNumberField(MatchUtils.STR_TCP_DST, m.get(MatchField.TCP_DST).getPort()); - break; - case UDP_SRC: - jGen.writeNumberField(MatchUtils.STR_UDP_SRC, m.get(MatchField.UDP_SRC).getPort()); - break; - case UDP_DST: - jGen.writeNumberField(MatchUtils.STR_UDP_DST, m.get(MatchField.UDP_DST).getPort()); - break; - default: - // either a BSN or unknown match type - break; - } // end switch of match type - } // end while over non-wildcarded matches + // handle OF1.1+ instructions with actions within + if (entry.getVersion() == OFVersion.OF_10) { + serializeActions(jGen, entry.getActions()); + } else { + List<OFInstruction> instructions = entry.getInstructions(); + jGen.writeObjectFieldStart("instructions"); + if (instructions.isEmpty()) { + jGen.writeStringField("none", "drop"); + } else { + for (OFInstruction i : instructions) { + switch (i.getType()) { + case CLEAR_ACTIONS: + jGen.writeObjectFieldStart(InstructionUtils.STR_CLEAR_ACTIONS); + break; + case WRITE_METADATA: + jGen.writeStartObject(); + jGen.writeNumberField(InstructionUtils.STR_WRITE_METADATA, ((OFInstructionWriteMetadata)i).getMetadata().getValue()); + jGen.writeNumberField(InstructionUtils.STR_WRITE_METADATA + "_mask", ((OFInstructionWriteMetadata)i).getMetadataMask().getValue()); + break; + case EXPERIMENTER: + jGen.writeStartObject(); + jGen.writeNumberField(InstructionUtils.STR_EXPERIMENTER, ((OFInstructionExperimenter)i).getExperimenter()); + break; + case GOTO_TABLE: + jGen.writeStartObject(); + jGen.writeNumberField(InstructionUtils.STR_GOTO_TABLE, ((OFInstructionGotoTable)i).getTableId().getValue()); + break; + case METER: + jGen.writeStartObject(); + jGen.writeNumberField(InstructionUtils.STR_GOTO_METER, ((OFInstructionMeter)i).getMeterId()); + break; + case APPLY_ACTIONS: + jGen.writeObjectFieldStart(InstructionUtils.STR_APPLY_ACTIONS); + serializeActions(jGen, ((OFInstructionApplyActions)i).getActions()); + break; + case WRITE_ACTIONS: + jGen.writeObjectFieldStart(InstructionUtils.STR_WRITE_ACTIONS); + serializeActions(jGen, ((OFInstructionWriteActions)i).getActions()); + default: + // shouldn't ever get here + break; + } // end switch on instruction + jGen.writeEndObject(); // end specific instruction + } // end for instructions + jGen.writeEndObject(); + } // end process instructions (OF1.1+ only) + } // end not-empty instructions (else) + jGen.writeEndObject(); + } // end for each OFFlowStatsReply entry + jGen.writeEndArray(); + } // end for each OFStatsReply + } // end method - jGen.writeEndObject(); // end match + /** + * Write a JSON string given a list of OFAction. Supports OF1.0 - OF1.3. + * This is the only place actions are serialized, for any OF version. Because + * some OF version share actions, it makes sense to have them in one place. + * @param jsonGenerator + * @param actions + * @throws IOException + * @throws JsonProcessingException + */ + public void serializeActions(JsonGenerator jsonGenerator, List<OFAction> actions) throws IOException, JsonProcessingException { + //jsonGenerator.writeStartObject(); + if (actions.isEmpty()) { + jsonGenerator.writeStringField("none", "drop"); + } + for (OFAction a : actions) { + switch (a.getType()) { + case OUTPUT: //TODO @Ryan need to reference the predefined string constants for each of the actions/oxms + jsonGenerator.writeNumberField(ActionUtils.STR_OUTPUT, ((OFActionOutput)a).getPort().getPortNumber()); + break; + /* begin OF1.0 ONLY actions */ + case SET_VLAN_VID: + jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_SET_VID, ((OFActionSetVlanVid)a).getVlanVid().getVlan()); + break; + case SET_VLAN_PCP: + jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_SET_PCP, ((OFActionSetVlanPcp)a).getVlanPcp().getValue()); + break; + case SET_QUEUE: + jsonGenerator.writeNumberField(ActionUtils.STR_QUEUE_SET, ((OFActionSetQueue)a).getQueueId()); + break; + case SET_DL_SRC: + jsonGenerator.writeStringField(ActionUtils.STR_DL_SRC_SET, ((OFActionSetDlSrc)a).getDlAddr().toString()); + break; + case SET_DL_DST: + jsonGenerator.writeStringField(ActionUtils.STR_DL_DST_SET, ((OFActionSetDlDst)a).getDlAddr().toString()); + break; + case SET_NW_SRC: + jsonGenerator.writeStringField(ActionUtils.STR_NW_SRC_SET, ((OFActionSetNwSrc)a).getNwAddr().toString()); + break; + case SET_NW_DST: + jsonGenerator.writeStringField(ActionUtils.STR_NW_DST_SET, ((OFActionSetNwDst)a).getNwAddr().toString()); + break; + case SET_NW_TOS: + jsonGenerator.writeNumberField(ActionUtils.STR_NW_TOS_SET, ((OFActionSetNwTos)a).getNwTos()); + break; + case SET_TP_SRC: + jsonGenerator.writeNumberField(ActionUtils.STR_TP_SRC_SET, ((OFActionSetTpSrc)a).getTpPort().getPort()); + break; + case SET_TP_DST: + jsonGenerator.writeNumberField(ActionUtils.STR_TP_DST_SET, ((OFActionSetTpDst)a).getTpPort().getPort()); + break; + /* end OF1.0 ONLY actions; begin OF1.1+ actions */ + case ENQUEUE: + jsonGenerator.writeNumberField(ActionUtils.STR_ENQUEUE, ((OFActionEnqueue)a).getPort().getPortNumber()); + break; + case GROUP: + jsonGenerator.writeNumberField(ActionUtils.STR_GROUP, ((OFActionGroup)a).getGroup().getGroupNumber()); + break; + case STRIP_VLAN: + jsonGenerator.writeString(ActionUtils.STR_VLAN_STRIP); + break; + case PUSH_VLAN: + jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_PUSH, ((OFActionPushVlan)a).getEthertype().getValue()); + break; + case PUSH_MPLS: + jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_PUSH, ((OFActionPushMpls)a).getEthertype().getValue()); + break; + case PUSH_PBB: + jsonGenerator.writeNumberField(ActionUtils.STR_PBB_PUSH, ((OFActionPushPbb)a).getEthertype().getValue()); + break; + case POP_VLAN: + jsonGenerator.writeString(ActionUtils.STR_VLAN_POP); + break; + case POP_MPLS: + jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_POP, ((OFActionPopMpls)a).getEthertype().getValue()); + break; + case POP_PBB: + jsonGenerator.writeString(ActionUtils.STR_PBB_POP); + break; + case COPY_TTL_IN: + jsonGenerator.writeString(ActionUtils.STR_TTL_IN_COPY); + break; + case COPY_TTL_OUT: + jsonGenerator.writeString(ActionUtils.STR_TTL_OUT_COPY); + break; + case DEC_NW_TTL: + jsonGenerator.writeString(ActionUtils.STR_NW_TTL_DEC); + break; + case DEC_MPLS_TTL: + jsonGenerator.writeString(ActionUtils.STR_MPLS_TTL_DEC); + break; + case SET_MPLS_LABEL: + jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_LABEL_SET, ((OFActionSetMplsLabel)a).getMplsLabel()); + break; + case SET_MPLS_TC: + jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_TC_SET, ((OFActionSetMplsTc)a).getMplsTc()); + break; + case SET_MPLS_TTL: + jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_TTL_SET, ((OFActionSetMplsTtl)a).getMplsTtl()); + break; + case SET_NW_ECN: + jsonGenerator.writeNumberField(ActionUtils.STR_NW_ECN_SET, ((OFActionSetNwEcn)a).getNwEcn().getEcnValue()); + break; + case SET_NW_TTL: + jsonGenerator.writeNumberField(ActionUtils.STR_NW_TTL_SET, ((OFActionSetNwTtl)a).getNwTtl()); + break; + case EXPERIMENTER: + jsonGenerator.writeNumberField(ActionUtils.STR_EXPERIMENTER, ((OFActionExperimenter)a).getExperimenter()); + break; + case SET_FIELD: + if (((OFActionSetField)a).getField() instanceof OFOxmArpOp) { + jsonGenerator.writeNumberField(MatchUtils.STR_ARP_OPCODE, ((OFOxmArpOp) ((OFActionSetField) a).getField()).getValue().getOpcode()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmArpSha) { + jsonGenerator.writeStringField(MatchUtils.STR_ARP_SHA, ((OFOxmArpSha) ((OFActionSetField) a).getField()).getValue().toString()); // macaddress formats string already + } else if (((OFActionSetField)a).getField() instanceof OFOxmArpTha) { + jsonGenerator.writeStringField(MatchUtils.STR_ARP_DHA, ((OFOxmArpTha) ((OFActionSetField) a).getField()).getValue().toString()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmArpSpa) { + jsonGenerator.writeStringField(MatchUtils.STR_ARP_SPA, ((OFOxmArpSpa) ((OFActionSetField) a).getField()).getValue().toString()); // ipaddress formats string already + } else if (((OFActionSetField)a).getField() instanceof OFOxmArpTpa) { + jsonGenerator.writeStringField(MatchUtils.STR_ARP_DPA, ((OFOxmArpTpa) ((OFActionSetField) a).getField()).getValue().toString()); + } + /* DATA LAYER */ + else if (((OFActionSetField)a).getField() instanceof OFOxmEthType) { + jsonGenerator.writeNumberField(MatchUtils.STR_DL_TYPE, ((OFOxmEthType) ((OFActionSetField) a).getField()).getValue().getValue()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmEthSrc) { + jsonGenerator.writeStringField(MatchUtils.STR_DL_SRC, ((OFOxmEthSrc) ((OFActionSetField) a).getField()).getValue().toString()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmEthDst) { + jsonGenerator.writeStringField(MatchUtils.STR_DL_DST, ((OFOxmEthDst) ((OFActionSetField) a).getField()).getValue().toString()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmVlanVid) { + jsonGenerator.writeNumberField(MatchUtils.STR_DL_VLAN, ((OFOxmVlanVid) ((OFActionSetField) a).getField()).getValue().getVlan()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmVlanPcp) { + } + /* ICMP */ + else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Code) { + jsonGenerator.writeNumberField(MatchUtils.STR_ICMP_CODE, ((OFOxmIcmpv4Code) ((OFActionSetField) a).getField()).getValue().getCode()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Type) { + jsonGenerator.writeNumberField(MatchUtils.STR_ICMP_TYPE, ((OFOxmIcmpv4Type) ((OFActionSetField) a).getField()).getValue().getType()); + } + /* NETWORK LAYER */ + else if (((OFActionSetField)a).getField() instanceof OFOxmIpProto) { + jsonGenerator.writeNumberField(MatchUtils.STR_NW_PROTO, ((OFOxmIpProto) ((OFActionSetField) a).getField()).getValue().getIpProtocolNumber()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Src) { + jsonGenerator.writeStringField(MatchUtils.STR_NW_SRC, ((OFOxmIpv4Src) ((OFActionSetField) a).getField()).getValue().toString()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Dst) { + jsonGenerator.writeStringField(MatchUtils.STR_NW_DST, ((OFOxmIpv4Dst) ((OFActionSetField) a).getField()).getValue().toString()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmIpEcn) { + jsonGenerator.writeNumberField(MatchUtils.STR_NW_ECN, ((OFOxmIpEcn) ((OFActionSetField) a).getField()).getValue().getEcnValue()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmIpDscp) { + jsonGenerator.writeNumberField(MatchUtils.STR_NW_DSCP, ((OFOxmIpDscp) ((OFActionSetField) a).getField()).getValue().getDscpValue()); + } + /* TRANSPORT LAYER, TCP, UDP, and SCTP */ + else if (((OFActionSetField)a).getField() instanceof OFOxmTcpSrc) { + jsonGenerator.writeNumberField(MatchUtils.STR_TCP_SRC, ((OFOxmTcpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmTcpDst) { + jsonGenerator.writeNumberField(MatchUtils.STR_TCP_DST, ((OFOxmTcpDst) ((OFActionSetField) a).getField()).getValue().getPort()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmUdpSrc) { + jsonGenerator.writeNumberField(MatchUtils.STR_UDP_SRC, ((OFOxmUdpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmUdpDst) { + jsonGenerator.writeNumberField(MatchUtils.STR_UDP_DST, ((OFOxmUdpDst) ((OFActionSetField) a).getField()).getValue().getPort()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmSctpSrc) { + jsonGenerator.writeNumberField(MatchUtils.STR_SCTP_SRC, ((OFOxmSctpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmSctpDst) { + jsonGenerator.writeNumberField(MatchUtils.STR_SCTP_DST, ((OFOxmSctpDst) ((OFActionSetField) a).getField()).getValue().getPort()); + } + /* MPLS */ + else if (((OFActionSetField)a).getField() instanceof OFOxmMplsLabel) { + jsonGenerator.writeNumberField(MatchUtils.STR_MPLS_LABEL, ((OFOxmMplsLabel) ((OFActionSetField) a).getField()).getValue().getValue()); + } else if (((OFActionSetField)a).getField() instanceof OFOxmMplsTc) { + jsonGenerator.writeNumberField(MatchUtils.STR_MPLS_TC, ((OFOxmMplsTc) ((OFActionSetField) a).getField()).getValue().getValue()); + } // MPLS_BOS not implemented in loxi + /* METADATA */ + else if (((OFActionSetField)a).getField() instanceof OFOxmMetadata) { + jsonGenerator.writeNumberField(MatchUtils.STR_METADATA, ((OFOxmMetadata) ((OFActionSetField) a).getField()).getValue().getValue().getValue()); + } else { + logger.error("Could not decode Set-Field action field: {}", ((OFActionSetField) a)); + // need to get a logger in here somehow log.error("Could not decode Set-Field action field: {}", ((OFActionSetField) a)); + } + } // end switch over action type + } // end for over all actions + } // end method - // handle OF1.1+ instructions with actions within - if (entry.getVersion() == OFVersion.OF_10) { - serializeActions(jGen, entry.getActions()); - } else { - List<OFInstruction> instructions = entry.getInstructions(); - jGen.writeObjectFieldStart("instructions"); - if (instructions.isEmpty()) { - jGen.writeStringField("none", "drop"); - } else { - for (OFInstruction i : instructions) { - switch (i.getType()) { - case CLEAR_ACTIONS: - jGen.writeObjectFieldStart(InstructionUtils.STR_CLEAR_ACTIONS); - break; - case WRITE_METADATA: - jGen.writeStartObject(); - jGen.writeNumberField(InstructionUtils.STR_WRITE_METADATA, ((OFInstructionWriteMetadata)i).getMetadata().getValue()); - jGen.writeNumberField(InstructionUtils.STR_WRITE_METADATA + "_mask", ((OFInstructionWriteMetadata)i).getMetadataMask().getValue()); - break; - case EXPERIMENTER: - jGen.writeStartObject(); - jGen.writeNumberField(InstructionUtils.STR_EXPERIMENTER, ((OFInstructionExperimenter)i).getExperimenter()); - break; - case GOTO_TABLE: - jGen.writeStartObject(); - jGen.writeNumberField(InstructionUtils.STR_GOTO_TABLE, ((OFInstructionGotoTable)i).getTableId().getValue()); - break; - case METER: - jGen.writeStartObject(); - jGen.writeNumberField(InstructionUtils.STR_GOTO_METER, ((OFInstructionMeter)i).getMeterId()); - break; - case APPLY_ACTIONS: - jGen.writeObjectFieldStart(InstructionUtils.STR_APPLY_ACTIONS); - serializeActions(jGen, ((OFInstructionApplyActions)i).getActions()); - break; - case WRITE_ACTIONS: - jGen.writeObjectFieldStart(InstructionUtils.STR_WRITE_ACTIONS); - serializeActions(jGen, ((OFInstructionWriteActions)i).getActions()); - default: - // shouldn't ever get here - break; - } // end switch on instruction - jGen.writeEndObject(); // end specific instruction - } // end for instructions - jGen.writeEndObject(); - } // end process instructions (OF1.1+ only) - } // end not-empty instructions (else) - jGen.writeEndObject(); - } // end for each OFFlowStatsReply entry - } // end for each OFStatsReply - } // end method + public void serializeDescReply(List<OFDescStatsReply> descReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{ + OFDescStatsReply descReply = descReplies.get(0); // There are only one descReply from the switch + jGen.writeObjectFieldStart("desc"); + jGen.writeStringField("version", descReply.getVersion().toString()); //return the enum name + jGen.writeStringField("manufacturerDescription", descReply.getMfrDesc()); + jGen.writeStringField("hardwareDescription", descReply.getHwDesc()); + jGen.writeStringField("softwareDescription", descReply.getSwDesc()); + jGen.writeStringField("serialNumber", descReply.getSerialNum()); + jGen.writeStringField("datapathDescription", descReply.getDpDesc()); + jGen.writeEndObject(); // end match + } + public void serializeAggregateReply(List<OFAggregateStatsReply> aggregateReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{ + OFAggregateStatsReply aggregateReply = aggregateReplies.get(0); // There are only one aggregateReply from the switch + jGen.writeObjectFieldStart("aggregate"); + jGen.writeStringField("version", aggregateReply.getVersion().toString()); //return the enum name + jGen.writeNumberField("flowCount", aggregateReply.getFlowCount()); + jGen.writeNumberField("packetCount", aggregateReply.getPacketCount().getValue()); + jGen.writeNumberField("byteCount", aggregateReply.getByteCount().getValue()); + jGen.writeEndObject(); // end match + } - /** - * Write a JSON string given a list of OFAction. Supports OF1.0 - OF1.3. - * This is the only place actions are serialized, for any OF version. Because - * some OF version share actions, it makes sense to have them in one place. - * @param jsonGenerator - * @param actions - * @throws IOException - * @throws JsonProcessingException - */ - public void serializeActions(JsonGenerator jsonGenerator, List<OFAction> actions) throws IOException, JsonProcessingException { - //jsonGenerator.writeStartObject(); - if (actions.isEmpty()) { - jsonGenerator.writeStringField("none", "drop"); - } - for (OFAction a : actions) { - switch (a.getType()) { - case OUTPUT: //TODO @Ryan need to reference the predefined string constants for each of the actions/oxms - jsonGenerator.writeNumberField(ActionUtils.STR_OUTPUT, ((OFActionOutput)a).getPort().getPortNumber()); - break; - /* begin OF1.0 ONLY actions */ - case SET_VLAN_VID: - jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_SET_VID, ((OFActionSetVlanVid)a).getVlanVid().getVlan()); - break; - case SET_VLAN_PCP: - jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_SET_PCP, ((OFActionSetVlanPcp)a).getVlanPcp().getValue()); - break; - case SET_QUEUE: - jsonGenerator.writeNumberField(ActionUtils.STR_QUEUE_SET, ((OFActionSetQueue)a).getQueueId()); - break; - case SET_DL_SRC: - jsonGenerator.writeStringField(ActionUtils.STR_DL_SRC_SET, ((OFActionSetDlSrc)a).getDlAddr().toString()); - break; - case SET_DL_DST: - jsonGenerator.writeStringField(ActionUtils.STR_DL_DST_SET, ((OFActionSetDlDst)a).getDlAddr().toString()); - break; - case SET_NW_SRC: - jsonGenerator.writeStringField(ActionUtils.STR_NW_SRC_SET, ((OFActionSetNwSrc)a).getNwAddr().toString()); - break; - case SET_NW_DST: - jsonGenerator.writeStringField(ActionUtils.STR_NW_DST_SET, ((OFActionSetNwDst)a).getNwAddr().toString()); - break; - case SET_NW_TOS: - jsonGenerator.writeNumberField(ActionUtils.STR_NW_TOS_SET, ((OFActionSetNwTos)a).getNwTos()); - break; - case SET_TP_SRC: - jsonGenerator.writeNumberField(ActionUtils.STR_TP_SRC_SET, ((OFActionSetTpSrc)a).getTpPort().getPort()); - break; - case SET_TP_DST: - jsonGenerator.writeNumberField(ActionUtils.STR_TP_DST_SET, ((OFActionSetTpDst)a).getTpPort().getPort()); - break; - /* end OF1.0 ONLY actions; begin OF1.1+ actions */ - case ENQUEUE: - jsonGenerator.writeNumberField(ActionUtils.STR_ENQUEUE, ((OFActionEnqueue)a).getPort().getPortNumber()); - break; - case GROUP: - jsonGenerator.writeNumberField(ActionUtils.STR_GROUP, ((OFActionGroup)a).getGroup().getGroupNumber()); - break; - case STRIP_VLAN: - jsonGenerator.writeString(ActionUtils.STR_VLAN_STRIP); - break; - case PUSH_VLAN: - jsonGenerator.writeNumberField(ActionUtils.STR_VLAN_PUSH, ((OFActionPushVlan)a).getEthertype().getValue()); - break; - case PUSH_MPLS: - jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_PUSH, ((OFActionPushMpls)a).getEthertype().getValue()); - break; - case PUSH_PBB: - jsonGenerator.writeNumberField(ActionUtils.STR_PBB_PUSH, ((OFActionPushPbb)a).getEthertype().getValue()); - break; - case POP_VLAN: - jsonGenerator.writeString(ActionUtils.STR_VLAN_POP); - break; - case POP_MPLS: - jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_POP, ((OFActionPopMpls)a).getEthertype().getValue()); - break; - case POP_PBB: - jsonGenerator.writeString(ActionUtils.STR_PBB_POP); - break; - case COPY_TTL_IN: - jsonGenerator.writeString(ActionUtils.STR_TTL_IN_COPY); - break; - case COPY_TTL_OUT: - jsonGenerator.writeString(ActionUtils.STR_TTL_OUT_COPY); - break; - case DEC_NW_TTL: - jsonGenerator.writeString(ActionUtils.STR_NW_TTL_DEC); - break; - case DEC_MPLS_TTL: - jsonGenerator.writeString(ActionUtils.STR_MPLS_TTL_DEC); - break; - case SET_MPLS_LABEL: - jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_LABEL_SET, ((OFActionSetMplsLabel)a).getMplsLabel()); - break; - case SET_MPLS_TC: - jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_TC_SET, ((OFActionSetMplsTc)a).getMplsTc()); - break; - case SET_MPLS_TTL: - jsonGenerator.writeNumberField(ActionUtils.STR_MPLS_TTL_SET, ((OFActionSetMplsTtl)a).getMplsTtl()); - break; - case SET_NW_ECN: - jsonGenerator.writeNumberField(ActionUtils.STR_NW_ECN_SET, ((OFActionSetNwEcn)a).getNwEcn().getEcnValue()); - break; - case SET_NW_TTL: - jsonGenerator.writeNumberField(ActionUtils.STR_NW_TTL_SET, ((OFActionSetNwTtl)a).getNwTtl()); - break; - case EXPERIMENTER: - jsonGenerator.writeNumberField(ActionUtils.STR_EXPERIMENTER, ((OFActionExperimenter)a).getExperimenter()); - break; - case SET_FIELD: - if (((OFActionSetField)a).getField() instanceof OFOxmArpOp) { - jsonGenerator.writeNumberField(MatchUtils.STR_ARP_OPCODE, ((OFOxmArpOp) ((OFActionSetField) a).getField()).getValue().getOpcode()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmArpSha) { - jsonGenerator.writeStringField(MatchUtils.STR_ARP_SHA, ((OFOxmArpSha) ((OFActionSetField) a).getField()).getValue().toString()); // macaddress formats string already - } else if (((OFActionSetField)a).getField() instanceof OFOxmArpTha) { - jsonGenerator.writeStringField(MatchUtils.STR_ARP_DHA, ((OFOxmArpTha) ((OFActionSetField) a).getField()).getValue().toString()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmArpSpa) { - jsonGenerator.writeStringField(MatchUtils.STR_ARP_SPA, ((OFOxmArpSpa) ((OFActionSetField) a).getField()).getValue().toString()); // ipaddress formats string already - } else if (((OFActionSetField)a).getField() instanceof OFOxmArpTpa) { - jsonGenerator.writeStringField(MatchUtils.STR_ARP_DPA, ((OFOxmArpTpa) ((OFActionSetField) a).getField()).getValue().toString()); - } - /* DATA LAYER */ - else if (((OFActionSetField)a).getField() instanceof OFOxmEthType) { - jsonGenerator.writeNumberField(MatchUtils.STR_DL_TYPE, ((OFOxmEthType) ((OFActionSetField) a).getField()).getValue().getValue()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmEthSrc) { - jsonGenerator.writeStringField(MatchUtils.STR_DL_SRC, ((OFOxmEthSrc) ((OFActionSetField) a).getField()).getValue().toString()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmEthDst) { - jsonGenerator.writeStringField(MatchUtils.STR_DL_DST, ((OFOxmEthDst) ((OFActionSetField) a).getField()).getValue().toString()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmVlanVid) { - jsonGenerator.writeNumberField(MatchUtils.STR_DL_VLAN, ((OFOxmVlanVid) ((OFActionSetField) a).getField()).getValue().getVlan()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmVlanPcp) { - } - /* ICMP */ - else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Code) { - jsonGenerator.writeNumberField(MatchUtils.STR_ICMP_CODE, ((OFOxmIcmpv4Code) ((OFActionSetField) a).getField()).getValue().getCode()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmIcmpv4Type) { - jsonGenerator.writeNumberField(MatchUtils.STR_ICMP_TYPE, ((OFOxmIcmpv4Type) ((OFActionSetField) a).getField()).getValue().getType()); - } - /* NETWORK LAYER */ - else if (((OFActionSetField)a).getField() instanceof OFOxmIpProto) { - jsonGenerator.writeNumberField(MatchUtils.STR_NW_PROTO, ((OFOxmIpProto) ((OFActionSetField) a).getField()).getValue().getIpProtocolNumber()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Src) { - jsonGenerator.writeStringField(MatchUtils.STR_NW_SRC, ((OFOxmIpv4Src) ((OFActionSetField) a).getField()).getValue().toString()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmIpv4Dst) { - jsonGenerator.writeStringField(MatchUtils.STR_NW_DST, ((OFOxmIpv4Dst) ((OFActionSetField) a).getField()).getValue().toString()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmIpEcn) { - jsonGenerator.writeNumberField(MatchUtils.STR_NW_ECN, ((OFOxmIpEcn) ((OFActionSetField) a).getField()).getValue().getEcnValue()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmIpDscp) { - jsonGenerator.writeNumberField(MatchUtils.STR_NW_DSCP, ((OFOxmIpDscp) ((OFActionSetField) a).getField()).getValue().getDscpValue()); - } - /* TRANSPORT LAYER, TCP, UDP, and SCTP */ - else if (((OFActionSetField)a).getField() instanceof OFOxmTcpSrc) { - jsonGenerator.writeNumberField(MatchUtils.STR_TCP_SRC, ((OFOxmTcpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmTcpDst) { - jsonGenerator.writeNumberField(MatchUtils.STR_TCP_DST, ((OFOxmTcpDst) ((OFActionSetField) a).getField()).getValue().getPort()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmUdpSrc) { - jsonGenerator.writeNumberField(MatchUtils.STR_UDP_SRC, ((OFOxmUdpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmUdpDst) { - jsonGenerator.writeNumberField(MatchUtils.STR_UDP_DST, ((OFOxmUdpDst) ((OFActionSetField) a).getField()).getValue().getPort()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmSctpSrc) { - jsonGenerator.writeNumberField(MatchUtils.STR_SCTP_SRC, ((OFOxmSctpSrc) ((OFActionSetField) a).getField()).getValue().getPort()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmSctpDst) { - jsonGenerator.writeNumberField(MatchUtils.STR_SCTP_DST, ((OFOxmSctpDst) ((OFActionSetField) a).getField()).getValue().getPort()); - } - /* MPLS */ - else if (((OFActionSetField)a).getField() instanceof OFOxmMplsLabel) { - jsonGenerator.writeNumberField(MatchUtils.STR_MPLS_LABEL, ((OFOxmMplsLabel) ((OFActionSetField) a).getField()).getValue().getValue()); - } else if (((OFActionSetField)a).getField() instanceof OFOxmMplsTc) { - jsonGenerator.writeNumberField(MatchUtils.STR_MPLS_TC, ((OFOxmMplsTc) ((OFActionSetField) a).getField()).getValue().getValue()); - } // MPLS_BOS not implemented in loxi - /* METADATA */ - else if (((OFActionSetField)a).getField() instanceof OFOxmMetadata) { - jsonGenerator.writeNumberField(MatchUtils.STR_METADATA, ((OFOxmMetadata) ((OFActionSetField) a).getField()).getValue().getValue().getValue()); - } else { - // need to get a logger in here somehow log.error("Could not decode Set-Field action field: {}", ((OFActionSetField) a)); - } - } // end switch over action type - } // end for over all actions - } // end method + public void serializePortDescReply(List<OFPortDescStatsReply> portDescReplies, JsonGenerator jGen) throws IOException, JsonProcessingException{ + OFPortDescStatsReply portDescReply = portDescReplies.get(0); // we will get only one PortDescReply and it will contains many OFPortDescStatsEntry ? + jGen.writeStringField("version", portDescReply.getVersion().toString()); //return the enum name + jGen.writeFieldName("portDesc"); + jGen.writeStartArray(); + for(OFPortDesc entry : portDescReply.getEntries()) { + jGen.writeStartObject(); + jGen.writeStringField("portNumber",entry.getPortNo().toString()); + jGen.writeStringField("hardwareAddress", entry.getHwAddr().toString()); + jGen.writeStringField("name", entry.getName()); + switch(entry.getVersion()) { + case OF_10: + jGen.writeNumberField("config", OFPortConfigSerializerVer10.toWireValue(entry.getConfig())); + jGen.writeNumberField("state", OFPortStateSerializerVer10.toWireValue(entry.getState())); + jGen.writeNumberField("currentFeatures", OFPortFeaturesSerializerVer10.toWireValue(entry.getCurr())); + jGen.writeNumberField("advertisedFeatures", OFPortFeaturesSerializerVer10.toWireValue(entry.getAdvertised())); + jGen.writeNumberField("supportedFeatures", OFPortFeaturesSerializerVer10.toWireValue(entry.getSupported())); + jGen.writeNumberField("peerFeatures", OFPortFeaturesSerializerVer10.toWireValue(entry.getPeer())); + break; + case OF_11: + jGen.writeNumberField("config", OFPortConfigSerializerVer11.toWireValue(entry.getConfig())); + jGen.writeNumberField("state", OFPortStateSerializerVer11.toWireValue(entry.getState())); + jGen.writeNumberField("currentFeatures", OFPortFeaturesSerializerVer11.toWireValue(entry.getCurr())); + jGen.writeNumberField("advertisedFeatures", OFPortFeaturesSerializerVer11.toWireValue(entry.getAdvertised())); + jGen.writeNumberField("supportedFeatures", OFPortFeaturesSerializerVer11.toWireValue(entry.getSupported())); + jGen.writeNumberField("peerFeatures", OFPortFeaturesSerializerVer11.toWireValue(entry.getPeer())); + break; + case OF_12: + jGen.writeNumberField("config", OFPortConfigSerializerVer12.toWireValue(entry.getConfig())); + jGen.writeNumberField("state", OFPortStateSerializerVer12.toWireValue(entry.getState())); + jGen.writeNumberField("currentFeatures", OFPortFeaturesSerializerVer12.toWireValue(entry.getCurr())); + jGen.writeNumberField("advertisedFeatures", OFPortFeaturesSerializerVer12.toWireValue(entry.getAdvertised())); + jGen.writeNumberField("supportedFeatures", OFPortFeaturesSerializerVer12.toWireValue(entry.getSupported())); + jGen.writeNumberField("peerFeatures", OFPortFeaturesSerializerVer12.toWireValue(entry.getPeer())); + break; + case OF_13: + jGen.writeNumberField("config", OFPortConfigSerializerVer13.toWireValue(entry.getConfig())); + jGen.writeNumberField("state", OFPortStateSerializerVer13.toWireValue(entry.getState())); + jGen.writeNumberField("currentFeatures", OFPortFeaturesSerializerVer13.toWireValue(entry.getCurr())); + jGen.writeNumberField("advertisedFeatures", OFPortFeaturesSerializerVer13.toWireValue(entry.getAdvertised())); + jGen.writeNumberField("supportedFeatures", OFPortFeaturesSerializerVer13.toWireValue(entry.getSupported())); + jGen.writeNumberField("peerFeatures", OFPortFeaturesSerializerVer13.toWireValue(entry.getPeer())); + break; + } + if (OFVersion.OF_10 != entry.getVersion()) { + jGen.writeNumberField("currSpeed",entry.getCurrSpeed()); + jGen.writeNumberField("maxSpeed",entry.getMaxSpeed()); + } + jGen.writeEndObject(); + } + jGen.writeEndArray(); + } } diff --git a/src/main/resources/web/js/models/switchmodel.js b/src/main/resources/web/js/models/switchmodel.js index 4104dd0dfd898d9e462da0cc04f3fb6808342981..785e1f6464beac7e54ad13cba154ec656eb664d6 100644 --- a/src/main/resources/web/js/models/switchmodel.js +++ b/src/main/resources/web/js/models/switchmodel.js @@ -38,8 +38,8 @@ window.Switch = Backbone.Model.extend({ dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " desc"); - //console.log(data[self.id][0]); - self.set(data[self.id][0]); + //console.log(data['desc']); + self.set(data['desc']); } }); @@ -49,8 +49,8 @@ window.Switch = Backbone.Model.extend({ dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " aggregate"); - //console.log(data[self.id][0]); - self.set(data[self.id][0]); + //console.log(data['aggregate']); + self.set(data['aggregate']); } }); self.trigger('add'); @@ -73,19 +73,18 @@ window.Switch = Backbone.Model.extend({ dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " ports"); - //console.log(data[self.id]); var old_ids = self.ports.pluck('id'); //console.log("old_ids" + old_ids); // create port models - _.each(data[self.id], function(p) { + _.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.receiveErrors + p.receiveOverrunErrors + + 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); @@ -106,13 +105,13 @@ window.Switch = Backbone.Model.extend({ } }), $.ajax({ - url:hackBase + "/wm/core/switch/" + self.id + '/features/json', + 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[self.id]); + //console.log(data['portDesc']); // update port models - _.each(data[self.id].ports, function(p) { + _.each(data['portDesc'], function(p) { p.id = self.id+'-'+p.portNumber; if(p.name != p.portNumber) { p.name = p.portNumber + ' (' + p.name + ')'; @@ -167,7 +166,7 @@ window.Switch = Backbone.Model.extend({ dataType:"json", success:function (data) { //console.log("fetched switch " + self.id + " flows"); - var flows = data[self.id]; + var flows = data['flows']; //console.log(flows); // create flow models @@ -177,81 +176,31 @@ window.Switch = Backbone.Model.extend({ // build human-readable match f.matchHTML = ''; - if(!(f.match.wildcards & (1<<0))) { // input port - f.matchHTML += "port=" + f.match.inputPort + ", "; + if(f.hasOwnProperty('match')) { + _.each(f.match, function(value , key) { + f.matchHTML += key + "=" + value +" "; + },f); } - if(!(f.match.wildcards & (1<<1))) { // VLAN ID - f.matchHTML += "VLAN=" + f.match.dataLayerVirtualLan + ", "; - } - if(!(f.match.wildcards & (1<<20))) { // VLAN prio - f.matchHTML += "prio=" + f.match.dataLayerVirtualLanPriorityCodePoint + ", "; - } - if(!(f.match.wildcards & (1<<2))) { // src MAC - f.matchHTML += "src=<a href='/host/" + f.match.dataLayerSource + "'>" + - f.match.dataLayerSource + "</a>, "; - } - if(!(f.match.wildcards & (1<<3))) { // dest MAC - f.matchHTML += "dest=<a href='/host/" + f.match.dataLayerDestination + "'>" + - f.match.dataLayerDestination + "</a>, "; - } - if(!(f.match.wildcards & (1<<4))) { // Ethertype - // TODO print a human-readable name instead of hex - f.matchHTML += "ethertype=" + f.match.dataLayerType + ", "; - } - if(!(f.match.wildcards & (1<<5))) { // IP protocol - // TODO print a human-readable name - f.matchHTML += "proto=" + f.match.networkProtocol + ", "; - } - if(!(f.match.wildcards & (1<<6))) { // TCP/UDP source port - f.matchHTML += "IP src port=" + f.match.transportSource + ", "; - } - if(!(f.match.wildcards & (1<<7))) { // TCP/UDP dest port - f.matchHTML += "IP dest port=" + f.match.transportDestination + ", "; - } - if(!(f.match.wildcards & (32<<8))) { // src IP - f.matchHTML += "src=" + f.match.networkSource + ", "; - } - if(!(f.match.wildcards & (32<<14))) { // dest IP - f.matchHTML += "dest=" + f.match.networkDestination + ", "; - } - if(!(f.match.wildcards & (1<<21))) { // IP TOS - f.matchHTML += "TOS=" + f.match.networkTypeOfService + ", "; - } - // remove trailing ", " f.matchHTML = f.matchHTML.substr(0, f.matchHTML.length - 2); - - // build human-readable action list - f.actionText = _.reduce(f.actions, function (memo, a) { - switch (a.type) { - case "OUTPUT": - return memo + "output " + a.port + ', '; - case "OPAQUE_ENQUEUE": - return memo + "enqueue " + a.port + ':' + a.queueId + ', '; - case "STRIP_VLAN": - return memo + "strip VLAN, "; - case "SET_VLAN_ID": - return memo + "VLAN=" + a.virtualLanIdentifier + ', '; - case "SET_VLAN_PCP": - return memo + "prio=" + a.virtualLanPriorityCodePoint + ', '; - case "SET_DL_SRC": - return memo + "src=" + a.dataLayerAddress + ', '; - case "SET_DL_DST": - return memo + "dest=" + a.dataLayerAddress + ', '; - case "SET_NW_TOS": - return memo + "TOS=" + a.networkTypeOfService + ', '; - case "SET_NW_SRC": - return memo + "src=" + a.networkAddress + ', '; - case "SET_NW_DST": - return memo + "dest=" + a.networkAddress + ', '; - case "SET_TP_SRC": - return memo + "src port=" + a.transportPort + ', '; - case "SET_TP_DST": - return memo + "dest port=" + a.transportPort + ', '; + + f.applyActionText = ''; + f.writeActionText = ''; + if(f.hasOwnProperty('instructions')) { + if(f.instructions.hasOwnProperty('apply_actions')) { + _.each(f.instructions.apply_actions, function(value, key) { + f.applyActionText += key + ":" + value +" "; + },f); + } + if(f.instructions.hasOwnProperty('write_actions')) { + _.each(f.instructions.write_actions, function(value, key) { + f.writeActionText += key + ":" + value +" "; + },f); } - }, ""); - // remove trailing ", " - f.actionText = f.actionText.substr(0, f.actionText.length - 2); + } + // 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}); }); @@ -278,8 +227,8 @@ window.SwitchCollection = Backbone.Collection.extend({ //console.log("old_ids" + old_ids); _.each(data, function(sw) { - old_ids = _.without(old_ids, sw['dpid']); - self.add({id: sw['dpid'], inetAddress: sw.inetAddress, + 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 diff --git a/src/main/resources/web/tpl/flow-list-item.html b/src/main/resources/web/tpl/flow-list-item.html index 7c099c3e7e0e43c9612412dc7b4220fcbe7b1001..4fb9a3ec87f5058627483d6114807ea7ab5978db 100644 --- a/src/main/resources/web/tpl/flow-list-item.html +++ b/src/main/resources/web/tpl/flow-list-item.html @@ -1 +1 @@ - <td><%= cookie %></td><td><%= priority %></td><td><%= matchHTML %></td><td><%= actionText %></td><td><%= packetCount %></td><td><%= byteCount %></td><td><%= durationSeconds %> s</td><td><%= idleTimeout %> s</td> + <td><%= cookie %></td><td><%= priority %></td><td><%= matchHTML %></td><td><%= applyActionText %></td><td><%= writeActionText %></td><td><%= packetCount %></td><td><%= byteCount %></td><td><%= durationSeconds %> s</td><td><%= idleTimeoutSec %> s</td> diff --git a/src/main/resources/web/tpl/flow-list.html b/src/main/resources/web/tpl/flow-list.html index 21a30cf8d1b67633cb5869e68e88c51f96db82ec..3c23a292e47c7565566a0dc70ca783e5af91c046 100644 --- a/src/main/resources/web/tpl/flow-list.html +++ b/src/main/resources/web/tpl/flow-list.html @@ -2,7 +2,7 @@ <h1>Flows (<%= nflows %>)</h1> </div> <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> + <thead><tr><th>Cookie</th><th>Priority</th><th>Match</th><th>Apply Actions</th><th>Write Actions</th><th>Packets</th><th>Bytes</th><th>Age</th><th>Timeout</th></tr></thead> <tbody> <!-- flows will be inserted here by FlowListView:render --> </tbody> @@ -16,4 +16,4 @@ <li><a href="">→</a> </ul></div> --> - \ No newline at end of file +