diff --git a/logback.xml b/logback.xml index a25cc7f639cbb65d64acfca5a5df190e83c674d4..f5163007d4c2af4ea21c0c62b023614e2689ee79 100644 --- a/logback.xml +++ b/logback.xml @@ -11,5 +11,5 @@ <logger name="LogService" level="DEBUG"/> <!-- Restlet access logging --> <logger name="net.floodlightcontroller" level="DEBUG"/> <logger name="net.floodlightcontroller.logging" level="DEBUG"/> - <logger name="org.sdnplatform" level="DEBUG"/> + <logger name="org.sdnplatform" level="INFO"/> </configuration> diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/MatchSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/MatchSerializer.java index c242cc6305711654eff318152d0348b6e5e34a89..9bc587ced4742c47e9bfc1f8a7472406ca334605 100644 --- a/src/main/java/net/floodlightcontroller/core/web/serializers/MatchSerializer.java +++ b/src/main/java/net/floodlightcontroller/core/web/serializers/MatchSerializer.java @@ -31,6 +31,11 @@ public class MatchSerializer extends JsonSerializer<Match> { JsonProcessingException { serializeMatch(jGen, match); } + + @SuppressWarnings("unchecked") + public static String matchValueToString(Match m, @SuppressWarnings("rawtypes") MatchField mf) { + return m.isPartiallyMasked(mf) ? m.getMasked(mf).toString() : m.get(mf).toString(); + } public static void serializeMatch(JsonGenerator jGen, Match match) throws IOException, JsonProcessingException { // list flow matches @@ -42,115 +47,116 @@ public class MatchSerializer extends JsonSerializer<Match> { MatchField<?> mf = mi.next(); switch (mf.id) { case IN_PORT: - jGen.writeStringField(MatchUtils.STR_IN_PORT, m.get(MatchField.IN_PORT).toString()); + jGen.writeStringField(MatchUtils.STR_IN_PORT, matchValueToString(m, mf)); break; case IN_PHY_PORT: - jGen.writeStringField(MatchUtils.STR_IN_PHYS_PORT, m.get(MatchField.IN_PHY_PORT).toString()); + jGen.writeStringField(MatchUtils.STR_IN_PHYS_PORT, matchValueToString(m, mf)); break; case ARP_OP: - jGen.writeNumberField(MatchUtils.STR_ARP_OPCODE, m.get(MatchField.ARP_OP).getOpcode()); + jGen.writeStringField(MatchUtils.STR_ARP_OPCODE, matchValueToString(m, mf)); break; case ARP_SHA: - jGen.writeStringField(MatchUtils.STR_ARP_SHA, m.get(MatchField.ARP_SHA).toString()); + jGen.writeStringField(MatchUtils.STR_ARP_SHA, matchValueToString(m, mf)); break; case ARP_SPA: - jGen.writeStringField(MatchUtils.STR_ARP_SPA, m.get(MatchField.ARP_SPA).toString()); + jGen.writeStringField(MatchUtils.STR_ARP_SPA, matchValueToString(m, mf)); break; case ARP_THA: - jGen.writeStringField(MatchUtils.STR_ARP_DHA, m.get(MatchField.ARP_THA).toString()); + jGen.writeStringField(MatchUtils.STR_ARP_DHA, matchValueToString(m, mf)); break; case ARP_TPA: - jGen.writeStringField(MatchUtils.STR_ARP_DPA, m.get(MatchField.ARP_TPA).toString()); + jGen.writeStringField(MatchUtils.STR_ARP_DPA, matchValueToString(m, mf)); break; - case ETH_TYPE: - jGen.writeNumberField(MatchUtils.STR_DL_TYPE, m.get(MatchField.ETH_TYPE).getValue()); + case ETH_TYPE: // TODO Remove this "0x" when Loxigen is updated. + jGen.writeStringField(MatchUtils.STR_DL_TYPE, m.isPartiallyMasked(mf) ? + "0x" + m.getMasked(mf).toString() : "0x" + m.get(mf).toString()); break; case ETH_SRC: - jGen.writeStringField(MatchUtils.STR_DL_SRC, m.get(MatchField.ETH_SRC).toString()); + jGen.writeStringField(MatchUtils.STR_DL_SRC, matchValueToString(m, mf)); break; case ETH_DST: - jGen.writeStringField(MatchUtils.STR_DL_DST, m.get(MatchField.ETH_DST).toString()); + jGen.writeStringField(MatchUtils.STR_DL_DST, matchValueToString(m, mf)); break; case VLAN_VID: - jGen.writeNumberField(MatchUtils.STR_DL_VLAN, m.get(MatchField.VLAN_VID).getVlan()); + jGen.writeStringField(MatchUtils.STR_DL_VLAN, matchValueToString(m, mf)); break; case VLAN_PCP: - jGen.writeNumberField(MatchUtils.STR_DL_VLAN_PCP, m.get(MatchField.VLAN_PCP).getValue()); + jGen.writeStringField(MatchUtils.STR_DL_VLAN_PCP, matchValueToString(m, mf)); break; case ICMPV4_TYPE: - jGen.writeNumberField(MatchUtils.STR_ICMP_TYPE, m.get(MatchField.ICMPV4_TYPE).getType()); + jGen.writeStringField(MatchUtils.STR_ICMP_TYPE, matchValueToString(m, mf)); break; case ICMPV4_CODE: - jGen.writeNumberField(MatchUtils.STR_ICMP_CODE, m.get(MatchField.ICMPV4_CODE).getCode()); + jGen.writeStringField(MatchUtils.STR_ICMP_CODE, matchValueToString(m, mf)); break; case ICMPV6_TYPE: - jGen.writeNumberField(MatchUtils.STR_ICMPV6_TYPE, m.get(MatchField.ICMPV6_TYPE).getValue()); + jGen.writeStringField(MatchUtils.STR_ICMPV6_TYPE, matchValueToString(m, mf)); break; case ICMPV6_CODE: - jGen.writeNumberField(MatchUtils.STR_ICMPV6_CODE, m.get(MatchField.ICMPV6_CODE).getValue()); + jGen.writeStringField(MatchUtils.STR_ICMPV6_CODE, matchValueToString(m, mf)); break; case IP_DSCP: - jGen.writeNumberField(MatchUtils.STR_NW_DSCP, m.get(MatchField.IP_DSCP).getDscpValue()); + jGen.writeStringField(MatchUtils.STR_NW_DSCP, matchValueToString(m, mf)); break; case IP_ECN: - jGen.writeNumberField(MatchUtils.STR_NW_ECN, m.get(MatchField.IP_ECN).getEcnValue()); + jGen.writeStringField(MatchUtils.STR_NW_ECN, matchValueToString(m, mf)); break; case IP_PROTO: - jGen.writeNumberField(MatchUtils.STR_NW_PROTO, m.get(MatchField.IP_PROTO).getIpProtocolNumber()); + jGen.writeStringField(MatchUtils.STR_NW_PROTO, matchValueToString(m, mf)); break; case IPV4_SRC: - jGen.writeStringField(MatchUtils.STR_NW_SRC, m.get(MatchField.IPV4_SRC).toString()); + jGen.writeStringField(MatchUtils.STR_NW_SRC, matchValueToString(m, mf)); break; case IPV4_DST: - jGen.writeStringField(MatchUtils.STR_NW_DST, m.get(MatchField.IPV4_DST).toString()); + jGen.writeStringField(MatchUtils.STR_NW_DST, matchValueToString(m, mf)); break; case IPV6_SRC: - jGen.writeStringField(MatchUtils.STR_IPV6_SRC, m.get(MatchField.IPV6_SRC).toString()); + jGen.writeStringField(MatchUtils.STR_IPV6_SRC, matchValueToString(m, mf)); break; case IPV6_DST: - jGen.writeStringField(MatchUtils.STR_IPV6_DST, m.get(MatchField.IPV6_DST).toString()); + jGen.writeStringField(MatchUtils.STR_IPV6_DST, matchValueToString(m, mf)); break; case IPV6_FLABEL: - jGen.writeNumberField(MatchUtils.STR_IPV6_FLOW_LABEL, m.get(MatchField.IPV6_FLABEL).getIPv6FlowLabelValue()); + jGen.writeStringField(MatchUtils.STR_IPV6_FLOW_LABEL, matchValueToString(m, mf)); break; case IPV6_ND_SLL: - jGen.writeNumberField(MatchUtils.STR_IPV6_ND_SSL, m.get(MatchField.IPV6_ND_SLL).getLong()); + jGen.writeStringField(MatchUtils.STR_IPV6_ND_SSL, matchValueToString(m, mf)); break; case IPV6_ND_TARGET: - jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TARGET, m.get(MatchField.IPV6_ND_TARGET).getZeroCompressStart()); + jGen.writeStringField(MatchUtils.STR_IPV6_ND_TARGET, matchValueToString(m, mf)); break; case IPV6_ND_TLL: - jGen.writeNumberField(MatchUtils.STR_IPV6_ND_TTL, m.get(MatchField.IPV6_ND_TLL).getLong()); + jGen.writeStringField(MatchUtils.STR_IPV6_ND_TTL, matchValueToString(m, mf)); break; case METADATA: - jGen.writeNumberField(MatchUtils.STR_METADATA, m.get(MatchField.METADATA).getValue().getValue()); + jGen.writeStringField(MatchUtils.STR_METADATA, matchValueToString(m, mf)); break; case MPLS_LABEL: - jGen.writeNumberField(MatchUtils.STR_MPLS_LABEL, m.get(MatchField.MPLS_LABEL).getValue()); + jGen.writeStringField(MatchUtils.STR_MPLS_LABEL, matchValueToString(m, mf)); break; case MPLS_TC: - jGen.writeNumberField(MatchUtils.STR_MPLS_TC, m.get(MatchField.MPLS_TC).getValue()); + jGen.writeStringField(MatchUtils.STR_MPLS_TC, matchValueToString(m, mf)); break; case MPLS_BOS: - jGen.writeStringField(MatchUtils.STR_MPLS_BOS, m.get(MatchField.MPLS_BOS).toString()); + jGen.writeStringField(MatchUtils.STR_MPLS_BOS, matchValueToString(m, mf)); break; case SCTP_SRC: - jGen.writeNumberField(MatchUtils.STR_SCTP_SRC, m.get(MatchField.SCTP_SRC).getPort()); + jGen.writeStringField(MatchUtils.STR_SCTP_SRC, matchValueToString(m, mf)); break; case SCTP_DST: - jGen.writeNumberField(MatchUtils.STR_SCTP_DST, m.get(MatchField.SCTP_DST).getPort()); + jGen.writeStringField(MatchUtils.STR_SCTP_DST, matchValueToString(m, mf)); break; case TCP_SRC: - jGen.writeNumberField(MatchUtils.STR_TCP_SRC, m.get(MatchField.TCP_SRC).getPort()); + jGen.writeStringField(MatchUtils.STR_TCP_SRC, matchValueToString(m, mf)); break; case TCP_DST: - jGen.writeNumberField(MatchUtils.STR_TCP_DST, m.get(MatchField.TCP_DST).getPort()); + jGen.writeStringField(MatchUtils.STR_TCP_DST, matchValueToString(m, mf)); break; case UDP_SRC: - jGen.writeNumberField(MatchUtils.STR_UDP_SRC, m.get(MatchField.UDP_SRC).getPort()); + jGen.writeStringField(MatchUtils.STR_UDP_SRC, matchValueToString(m, mf)); break; case UDP_DST: - jGen.writeNumberField(MatchUtils.STR_UDP_DST, m.get(MatchField.UDP_DST).getPort()); + jGen.writeStringField(MatchUtils.STR_UDP_DST, matchValueToString(m, mf)); break; default: // either a BSN or unknown match type diff --git a/src/main/java/net/floodlightcontroller/core/web/serializers/OFInstructionListSerializer.java b/src/main/java/net/floodlightcontroller/core/web/serializers/OFInstructionListSerializer.java index e16b1854826c709812cb9e79ab5cb638671efb68..a59d38fd3132544e07f8b37dbde600a03c814070 100644 --- a/src/main/java/net/floodlightcontroller/core/web/serializers/OFInstructionListSerializer.java +++ b/src/main/java/net/floodlightcontroller/core/web/serializers/OFInstructionListSerializer.java @@ -45,20 +45,20 @@ public class OFInstructionListSerializer extends JsonSerializer<List<OFInstructi jGen.writeObjectFieldStart(InstructionUtils.STR_CLEAR_ACTIONS); break; case WRITE_METADATA: - jGen.writeStartObject(); + jGen.writeObjectFieldStart(InstructionUtils.STR_WRITE_METADATA); 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.writeObjectFieldStart(InstructionUtils.STR_EXPERIMENTER); jGen.writeNumberField(InstructionUtils.STR_EXPERIMENTER, ((OFInstructionExperimenter)i).getExperimenter()); break; case GOTO_TABLE: - jGen.writeStartObject(); + jGen.writeObjectFieldStart(InstructionUtils.STR_GOTO_TABLE); jGen.writeNumberField(InstructionUtils.STR_GOTO_TABLE, ((OFInstructionGotoTable)i).getTableId().getValue()); break; case METER: - jGen.writeStartObject(); + jGen.writeObjectFieldStart(InstructionUtils.STR_GOTO_METER); jGen.writeNumberField(InstructionUtils.STR_GOTO_METER, ((OFInstructionMeter)i).getMeterId()); break; case APPLY_ACTIONS: diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java b/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java index 22b60197be03a9dbd2063552c78b121de6297620..0abf9d2f39ffdd3320ae64e0a1156bacb2cf3b98 100644 --- a/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java +++ b/src/main/java/net/floodlightcontroller/staticflowentry/IStaticFlowEntryPusherService.java @@ -39,7 +39,7 @@ public interface IStaticFlowEntryPusherService extends IFloodlightService { public void deleteFlow(String name); /** - * Deletes all static flows for a practicular switch + * Deletes all static flows for a particular switch * @param dpid The DPID of the switch to delete flows for. */ public void deleteFlowsForSwitch(DatapathId dpid); diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java index fec72f40add7fcc13d94894453a025f0074a1cfe..94a8686afe655dbfe2ff3ce3eb935c6fc14b24e1 100644 --- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java +++ b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java @@ -17,6 +17,7 @@ package net.floodlightcontroller.staticflowentry; import java.io.IOException; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -37,6 +38,7 @@ import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.MappingJsonFactory; import org.projectfloodlight.openflow.protocol.OFFlowMod; +import org.projectfloodlight.openflow.protocol.OFFlowModFlags; import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions; import org.projectfloodlight.openflow.protocol.instruction.OFInstructionClearActions; @@ -90,7 +92,8 @@ public class StaticFlowEntries { .setBufferId(OFBufferId.NO_BUFFER) .setOutPort(OFPort.ANY) .setCookie(computeEntryCookie(0, entryName)) - .setPriority(Integer.MAX_VALUE); + .setPriority(Integer.MAX_VALUE) + .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)); return; } @@ -144,6 +147,8 @@ public class StaticFlowEntries { entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw); entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true)); entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Integer.toString(fm.getPriority())); + entry.put(StaticFlowEntryPusher.COLUMN_IDLE_TIMEOUT, Integer.toString(fm.getIdleTimeout())); + entry.put(StaticFlowEntryPusher.COLUMN_HARD_TIMEOUT, Integer.toString(fm.getHardTimeout())); switch (fm.getVersion()) { case OF_10: @@ -367,9 +372,6 @@ public class StaticFlowEntries { String n = jp.getCurrentName(); jp.nextToken(); - if (jp.getText().equals("")) { - continue; - } // Java 7 switch-case on strings automatically checks for (deep) string equality. // IMHO, this makes things easier on the eyes than if, else if, else's, and it @@ -559,6 +561,7 @@ public class StaticFlowEntries { break; default: log.error("Could not decode field from JSON string: {}", n); + break; } } diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java index ba8a2c5fff06087f1771249d532f5c1b6e8c91e7..3730a095f75b90a6e33c5c4102f54743730a61c6 100644 --- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java +++ b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java @@ -65,6 +65,11 @@ import org.projectfloodlight.openflow.protocol.OFPortDesc; import org.projectfloodlight.openflow.protocol.OFMessage; import org.projectfloodlight.openflow.protocol.OFType; import org.projectfloodlight.openflow.protocol.OFVersion; +import org.projectfloodlight.openflow.protocol.ver10.OFFlowRemovedReasonSerializerVer10; +import org.projectfloodlight.openflow.protocol.ver11.OFFlowRemovedReasonSerializerVer11; +import org.projectfloodlight.openflow.protocol.ver12.OFFlowRemovedReasonSerializerVer12; +import org.projectfloodlight.openflow.protocol.ver13.OFFlowRemovedReasonSerializerVer13; +import org.projectfloodlight.openflow.protocol.ver14.OFFlowRemovedReasonSerializerVer14; import org.projectfloodlight.openflow.types.DatapathId; import org.projectfloodlight.openflow.types.TableId; import org.projectfloodlight.openflow.types.U16; @@ -132,7 +137,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, public static final String COLUMN_ARP_DHA = MatchUtils.STR_ARP_DHA; public static final String COLUMN_ARP_SPA = MatchUtils.STR_ARP_SPA; public static final String COLUMN_ARP_DPA = MatchUtils.STR_ARP_DPA; - + /* IPv6 related columns */ public static final String COLUMN_NW6_SRC = MatchUtils.STR_IPV6_SRC; public static final String COLUMN_NW6_DST = MatchUtils.STR_IPV6_DST; @@ -154,7 +159,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, /* end newly added matches */ public static final String COLUMN_ACTIONS = "actions"; - + public static final String COLUMN_INSTR_GOTO_TABLE = InstructionUtils.STR_GOTO_TABLE; // instructions are each getting their own column, due to write and apply actions, which themselves contain a variable list of actions public static final String COLUMN_INSTR_WRITE_METADATA = InstructionUtils.STR_WRITE_METADATA; public static final String COLUMN_INSTR_WRITE_ACTIONS = InstructionUtils.STR_WRITE_ACTIONS; @@ -175,7 +180,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, COLUMN_ICMP_TYPE, COLUMN_ICMP_CODE, COLUMN_ARP_OPCODE, COLUMN_ARP_SHA, COLUMN_ARP_DHA, COLUMN_ARP_SPA, COLUMN_ARP_DPA, - + /* IPv6 related matches */ COLUMN_NW6_SRC, COLUMN_NW6_DST, COLUMN_ICMP6_TYPE, COLUMN_ICMP6_CODE, COLUMN_IPV6_FLOW_LABEL, COLUMN_ND_SLL, COLUMN_ND_TLL, COLUMN_ND_TARGET, @@ -189,7 +194,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, COLUMN_INSTR_CLEAR_ACTIONS, COLUMN_INSTR_GOTO_METER, COLUMN_INSTR_EXPERIMENTER /* end newly added instructions */ - }; + }; protected IFloodlightProviderService floodlightProviderService; protected IOFSwitchService switchService; @@ -365,11 +370,11 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, if (row.get(key) == null) { continue; } - + if (key.equals(COLUMN_SWITCH) || key.equals(COLUMN_NAME) || key.equals("id")) { continue; // already handled } - + if (key.equals(COLUMN_ACTIVE)) { if (!Boolean.valueOf((String) row.get(COLUMN_ACTIVE))) { log.debug("skipping inactive entry {} for switch {}", entryName, switchName); @@ -489,17 +494,17 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, entriesFromStorage.put(dpid, new HashMap<String, OFFlowMod>()); List<OFMessage> outQueue = new ArrayList<OFMessage>(); - + /* For every flow per dpid, decide how to "add" the flow. */ for (String entry : entriesToAdd.get(dpid).keySet()) { OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry); OFFlowMod oldFlowMod = null; - + String dpidOldFlowMod = entry2dpid.get(entry); if (dpidOldFlowMod != null) { oldFlowMod = entriesFromStorage.get(dpidOldFlowMod).remove(entry); } - + /* Modify, which can be either a Flow MODIFY_STRICT or a Flow DELETE_STRICT with a side of Flow ADD */ if (oldFlowMod != null && newFlowMod != null) { /* MODIFY_STRICT b/c the match is still the same */ @@ -511,7 +516,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, entry2dpid.put(entry, dpid); newFlowMod = FlowModUtils.toFlowModifyStrict(newFlowMod); outQueue.add(newFlowMod); - /* DELETE_STRICT and then ADD b/c the match is now different */ + /* DELETE_STRICT and then ADD b/c the match is now different */ } else { log.debug("DeleteStrict and Add SFP Flow"); oldFlowMod = FlowModUtils.toFlowDeleteStrict(oldFlowMod); @@ -520,7 +525,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, if (dpidOldFlowMod.equals(dpid)) { outQueue.add(oldFlowMod); outQueue.add(addTmp); - /* Otherwise, go ahead and send the flows now (since queuing them will send to the wrong switch). */ + /* Otherwise, go ahead and send the flows now (since queuing them will send to the wrong switch). */ } else { writeOFMessageToSwitch(DatapathId.of(dpidOldFlowMod), oldFlowMod); writeOFMessageToSwitch(DatapathId.of(dpid), FlowModUtils.toFlowAdd(newFlowMod)); @@ -528,14 +533,14 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, entriesFromStorage.get(dpid).put(entry, addTmp); entry2dpid.put(entry, dpid); } - /* Add a brand-new flow with ADD */ + /* Add a brand-new flow with ADD */ } else if (newFlowMod != null && oldFlowMod == null) { log.debug("Add SFP Flow"); OFFlowAdd addTmp = FlowModUtils.toFlowAdd(newFlowMod); entriesFromStorage.get(dpid).put(entry, addTmp); entry2dpid.put(entry, dpid); outQueue.add(addTmp); - /* Something strange happened, so remove the flow */ + /* Something strange happened, so remove the flow */ } else if (newFlowMod == null) { entriesFromStorage.get(dpid).remove(entry); entry2dpid.remove(entry); @@ -666,7 +671,6 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, sw.write(flowMod); sw.flush(); } - @Override public String getName() { return StaticFlowName; @@ -688,13 +692,74 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, * never expire. */ if (AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) { - if (OFFlowRemovedReason.DELETE.equals(msg.getReason())) - log.error("Got a FlowRemove message for a infinite " + - "timeout flow: {} from switch {}", msg, sw); - // Stop the processing chain since we sent the delete. - return Command.STOP; + OFFlowRemovedReason reason = null; + switch (msg.getVersion()) { + case OF_10: + reason = OFFlowRemovedReasonSerializerVer10.ofWireValue((byte) msg.getReason()); + break; + case OF_11: + reason = OFFlowRemovedReasonSerializerVer11.ofWireValue((byte) msg.getReason()); + break; + case OF_12: + reason = OFFlowRemovedReasonSerializerVer12.ofWireValue((byte) msg.getReason()); + break; + case OF_13: + reason = OFFlowRemovedReasonSerializerVer13.ofWireValue((byte) msg.getReason()); + break; + case OF_14: + reason = OFFlowRemovedReasonSerializerVer14.ofWireValue((byte) msg.getReason()); + break; + default: + log.debug("OpenFlow version {} unsupported for OFFlowRemovedReasonSerializerVerXX", msg.getVersion()); + break; + } + if (reason != null) { + if (OFFlowRemovedReason.DELETE == reason) { + log.error("Got a FlowRemove message for a infinite " + + "timeout flow: {} from switch {}", msg, sw); + } else if (OFFlowRemovedReason.HARD_TIMEOUT == reason || OFFlowRemovedReason.IDLE_TIMEOUT == reason) { + /* Remove the Flow from the DB since it timed out */ + log.debug("Received an IDLE or HARD timeout for an SFP flow. Removing it from the SFP DB."); + /* + * Lookup the flow based on the flow contents. We do not know/care about the name of the + * flow based on this message, but we can get the table values for this switch and search. + */ + String flowToRemove = null; + Map<String, OFFlowMod> flowsByName = getFlows(sw.getId()); + for (Map.Entry<String, OFFlowMod> entry : flowsByName.entrySet()) { + if (msg.getCookie().equals(entry.getValue().getCookie()) && + msg.getHardTimeout() == entry.getValue().getHardTimeout() && + msg.getIdleTimeout() == entry.getValue().getIdleTimeout() && + msg.getMatch().equals(entry.getValue().getMatch()) && + msg.getPriority() == entry.getValue().getPriority() && + msg.getTableId().equals(entry.getValue().getTableId()) + ) { + flowToRemove = entry.getKey(); + break; + } + } + + log.debug("Flow to Remove: {}", flowToRemove); + + /* + * Remove the flow. This will send the delete message to the switch, + * since we cannot tell the storage listener rowsdeleted() that we + * are only removing our local DB copy of the flow and that it actually + * timed out on the switch and is already gone. The switch will silently + * discard the delete message in this case. + * + * TODO: We should come up with a way to convey to the storage listener + * the reason for the flow being removed. + */ + if (flowToRemove != null) { + deleteFlow(flowToRemove); + } + } + /* Stop the processing chain since we sent or asked for the delete message. */ + return Command.STOP; + } } - + /* Continue the processing chain, since we did not send the delete. */ return Command.CONTINUE; } @@ -787,7 +852,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService, storageSourceService.insertRowAsync(TABLE_NAME, fmMap); } catch (Exception e) { log.error("Error! Check the fields specified for the flow.Make sure IPv4 fields are not mixed with IPv6 fields or all " - + "mandatory fields are specified. "); + + "mandatory fields are specified. "); } } diff --git a/src/main/java/net/floodlightcontroller/util/InstructionUtils.java b/src/main/java/net/floodlightcontroller/util/InstructionUtils.java index 1de33710366a6d2c8057498d5411780165dc92ce..aa89c1b581156c6dbdda3f75107bf2db74dfbe9b 100644 --- a/src/main/java/net/floodlightcontroller/util/InstructionUtils.java +++ b/src/main/java/net/floodlightcontroller/util/InstructionUtils.java @@ -278,7 +278,7 @@ public class InstructionUtils { return; } - if (inst != null && inst.isEmpty()) { + if (inst != null && inst.trim().isEmpty()) { /* Allow the empty string, since this is what specifies clear (i.e. key clear does not have any defined values). */ OFInstructionClearActions i = OFFactories.getFactory(fmb.getVersion()).instructions().clearActions(); log.debug("Appending ClearActions instruction: {}", i); appendInstruction(fmb, i); diff --git a/src/main/java/net/floodlightcontroller/util/MatchUtils.java b/src/main/java/net/floodlightcontroller/util/MatchUtils.java index 9b16fa7a8ebaa4f1deb8301049e47b605755f15f..9693561690f146aa6e9d7280fc8aadca2eacfb83 100644 --- a/src/main/java/net/floodlightcontroller/util/MatchUtils.java +++ b/src/main/java/net/floodlightcontroller/util/MatchUtils.java @@ -11,9 +11,7 @@ import org.projectfloodlight.openflow.types.ArpOpcode; import org.projectfloodlight.openflow.types.EthType; import org.projectfloodlight.openflow.types.ICMPv4Code; import org.projectfloodlight.openflow.types.ICMPv4Type; -import org.projectfloodlight.openflow.types.IPv4Address; import org.projectfloodlight.openflow.types.IPv4AddressWithMask; -import org.projectfloodlight.openflow.types.IPv6Address; import org.projectfloodlight.openflow.types.IPv6AddressWithMask; import org.projectfloodlight.openflow.types.IPv6FlowLabel; import org.projectfloodlight.openflow.types.IpDscp; @@ -388,19 +386,33 @@ public class MatchUtils { switch (key_value[0]) { case STR_IN_PORT: - mb.setExact(MatchField.IN_PORT, OFPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.IN_PORT, OFPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.IN_PORT, OFPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + OFPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } break; - case STR_DL_DST: - mb.setExact(MatchField.ETH_DST, MacAddress.of(key_value[1])); + case STR_DL_DST: /* Only accept hex-string for MAC addresses */ + if (dataMask.length == 1) { + mb.setExact(MatchField.ETH_DST, MacAddress.of(dataMask[0])); + } else { + mb.setMasked(MatchField.ETH_DST, MacAddress.of(dataMask[0]), MacAddress.of(dataMask[1])); + } break; case STR_DL_SRC: - mb.setExact(MatchField.ETH_SRC, MacAddress.of(key_value[1])); + if (dataMask.length == 1) { + mb.setExact(MatchField.ETH_SRC, MacAddress.of(dataMask[0])); + } else { + mb.setMasked(MatchField.ETH_SRC, MacAddress.of(dataMask[0]), MacAddress.of(dataMask[1])); + } break; case STR_DL_TYPE: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.ETH_TYPE, EthType.of(Integer.valueOf(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.ETH_TYPE, EthType.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.ETH_TYPE, EthType.of(Integer.valueOf(key_value[1]))); + mb.setMasked(MatchField.ETH_TYPE, EthType.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + EthType.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); } break; case STR_DL_VLAN: @@ -413,19 +425,20 @@ public class MatchUtils { } break; case STR_DL_VLAN_PCP: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.VLAN_PCP, VlanPcp.of(U8.t(Short.valueOf(key_value[1].replaceFirst("0x", ""), 16)))); + if (dataMask.length == 1) { + mb.setExact(MatchField.VLAN_PCP, VlanPcp.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0])))); } else { - mb.setExact(MatchField.VLAN_PCP, VlanPcp.of(U8.t(Short.valueOf(key_value[1])))); + mb.setMasked(MatchField.VLAN_PCP, VlanPcp.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0]))), + VlanPcp.of(dataMask[1].contains("0x") ? U8.t(Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[1])))); } break; - case STR_NW_DST: + case STR_NW_DST: /* Only accept dotted-decimal for IPv4 addresses */ mb.setMasked(MatchField.IPV4_DST, IPv4AddressWithMask.of(key_value[1])); break; case STR_NW_SRC: mb.setMasked(MatchField.IPV4_SRC, IPv4AddressWithMask.of(key_value[1])); break; - case STR_IPV6_DST: + case STR_IPV6_DST: /* Only accept hex-string for IPv6 addresses */ if (ver10 == true) { throw new IllegalArgumentException("OF Version incompatible"); } @@ -441,207 +454,297 @@ public class MatchUtils { if (ver10 == true) { throw new IllegalArgumentException("OF Version incompatible"); } - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.IPV6_FLABEL, IPv6FlowLabel.of(Integer.parseInt(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.IPV6_FLABEL, IPv6FlowLabel.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.IPV6_FLABEL, IPv6FlowLabel.of(Integer.parseInt(key_value[1]))); + mb.setMasked(MatchField.IPV6_FLABEL, IPv6FlowLabel.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + IPv6FlowLabel.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); } break; case STR_NW_PROTO: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.IP_PROTO, IpProtocol.of(Short.valueOf(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.IP_PROTO, IpProtocol.of(dataMask[0].contains("0x") ? Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.IP_PROTO, IpProtocol.of(Short.valueOf(key_value[1]))); + mb.setMasked(MatchField.IP_PROTO, IpProtocol.of(dataMask[0].contains("0x") ? Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[0])), + IpProtocol.of(dataMask[1].contains("0x") ? Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[1]))); } break; case STR_NW_TOS: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.IP_ECN, IpEcn.of(U8.t(Short.valueOf(key_value[1].replaceFirst("0x", ""), 16)))); - mb.setExact(MatchField.IP_DSCP, IpDscp.of(U8.t(Short.valueOf(key_value[1].replaceFirst("0x", ""), 16)))); + if (dataMask.length == 1) { + mb.setExact(MatchField.IP_ECN, IpEcn.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0])))); + mb.setExact(MatchField.IP_DSCP, IpDscp.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0])))); } else { - mb.setExact(MatchField.IP_ECN, IpEcn.of(U8.t(Short.valueOf(key_value[1])))); - mb.setExact(MatchField.IP_DSCP, IpDscp.of(U8.t(Short.valueOf(key_value[1])))); + mb.setMasked(MatchField.IP_ECN, IpEcn.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0]))), + IpEcn.of(dataMask[1].contains("0x") ? U8.t(Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[1])))); + mb.setMasked(MatchField.IP_DSCP, IpDscp.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0]))), + IpDscp.of(dataMask[1].contains("0x") ? U8.t(Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[1])))); } break; case STR_NW_ECN: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.IP_ECN, IpEcn.of(U8.t(Short.valueOf(key_value[1].replaceFirst("0x", ""), 16)))); + if (dataMask.length == 1) { + mb.setExact(MatchField.IP_ECN, IpEcn.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0])))); } else { - mb.setExact(MatchField.IP_ECN, IpEcn.of(U8.t(Short.valueOf(key_value[1])))); + mb.setMasked(MatchField.IP_ECN, IpEcn.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0]))), + IpEcn.of(dataMask[1].contains("0x") ? U8.t(Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[1])))); } break; case STR_NW_DSCP: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.IP_DSCP, IpDscp.of(U8.t(Short.valueOf(key_value[1].replaceFirst("0x", ""), 16)))); + if (dataMask.length == 1) { + mb.setExact(MatchField.IP_DSCP, IpDscp.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0])))); } else { - mb.setExact(MatchField.IP_DSCP, IpDscp.of(U8.t(Short.valueOf(key_value[1])))); + mb.setMasked(MatchField.IP_DSCP, IpDscp.of(dataMask[0].contains("0x") ? U8.t(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[0]))), + IpDscp.of(dataMask[1].contains("0x") ? U8.t(Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U8.t(Short.valueOf(dataMask[1])))); } break; case STR_SCTP_DST: // for transport ports, if we don't know the transport protocol yet, postpone parsing this [key, value] pair until we know. Put it at the back of the queue. if (mb.get(MatchField.IP_PROTO) == null) { llValues.add(key_value); // place it back if we can't proceed yet } else { - mb.setExact(MatchField.SCTP_DST, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.SCTP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.SCTP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } break; case STR_SCTP_SRC: if (mb.get(MatchField.IP_PROTO) == null) { llValues.add(key_value); // place it back if we can't proceed yet } else { - mb.setExact(MatchField.SCTP_SRC, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.SCTP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.SCTP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } break; case STR_UDP_DST: if (mb.get(MatchField.IP_PROTO) == null) { llValues.add(key_value); // place it back if we can't proceed yet } else { - mb.setExact(MatchField.UDP_DST, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.UDP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.UDP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } break; case STR_UDP_SRC: if (mb.get(MatchField.IP_PROTO) == null) { llValues.add(key_value); // place it back if we can't proceed yet } else { - mb.setExact(MatchField.UDP_SRC, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.UDP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.UDP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } break; case STR_TCP_DST: if (mb.get(MatchField.IP_PROTO) == null) { llValues.add(key_value); // place it back if we can't proceed yet } else { - mb.setExact(MatchField.TCP_DST, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.TCP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.TCP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } break; case STR_TCP_SRC: if (mb.get(MatchField.IP_PROTO) == null) { llValues.add(key_value); // place it back if we can't proceed yet } else { - mb.setExact(MatchField.TCP_SRC, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.TCP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.TCP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } break; case STR_TP_DST: // support for OF1.0 generic transport ports if ((ipProto = mb.get(MatchField.IP_PROTO)) == null) { llValues.add(key_value); // place it back if we can't proceed yet } else if (ipProto == IpProtocol.TCP){ - mb.setExact(MatchField.TCP_DST, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.TCP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.TCP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } else if (ipProto == IpProtocol.UDP){ - mb.setExact(MatchField.UDP_DST, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.UDP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.UDP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } else if (ipProto == IpProtocol.SCTP){ - mb.setExact(MatchField.SCTP_DST, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.SCTP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.SCTP_DST, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } break; case STR_TP_SRC: if ((ipProto = mb.get(MatchField.IP_PROTO)) == null) { llValues.add(key_value); // place it back if we can't proceed yet } else if (ipProto == IpProtocol.TCP){ - mb.setExact(MatchField.TCP_SRC, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.TCP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.TCP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } else if (ipProto == IpProtocol.UDP){ - mb.setExact(MatchField.UDP_SRC, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.UDP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.UDP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } else if (ipProto == IpProtocol.SCTP){ - mb.setExact(MatchField.SCTP_SRC, TransportPort.of(Integer.valueOf(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.SCTP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.SCTP_SRC, TransportPort.of(dataMask[0].contains("0x") ? Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[0])), + TransportPort.of(dataMask[1].contains("0x") ? Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Integer.valueOf(dataMask[1]))); + } } break; case STR_ICMP_TYPE: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.ICMPV4_TYPE, ICMPv4Type.of(Short.parseShort(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.ICMPV4_TYPE, ICMPv4Type.of(dataMask[0].contains("0x") ? Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.ICMPV4_TYPE, ICMPv4Type.of(Short.parseShort(key_value[1]))); + mb.setMasked(MatchField.ICMPV4_TYPE, ICMPv4Type.of(dataMask[0].contains("0x") ? Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[0])), + ICMPv4Type.of(dataMask[1].contains("0x") ? Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[1]))); } break; case STR_ICMP_CODE: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.ICMPV4_CODE, ICMPv4Code.of(Short.parseShort(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.ICMPV4_CODE, ICMPv4Code.of(dataMask[0].contains("0x") ? Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.ICMPV4_CODE, ICMPv4Code.of(Short.parseShort(key_value[1]))); + mb.setMasked(MatchField.ICMPV4_CODE, ICMPv4Code.of(dataMask[0].contains("0x") ? Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[0])), + ICMPv4Code.of(dataMask[1].contains("0x") ? Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16) : Short.valueOf(dataMask[1]))); } break; - - //sanjivini case STR_ICMPV6_TYPE: if (ver10 == true) { throw new IllegalArgumentException("OF Version incompatible"); - //throw new Exception("OF Version incompatible"); } - mb.setExact(MatchField.ICMPV6_TYPE, U8.of(Short.parseShort(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.ICMPV6_TYPE, dataMask[0].contains("0x") ? U8.of(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.ICMPV6_TYPE, dataMask[0].contains("0x") ? U8.of(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[0])), + dataMask[1].contains("0x") ? U8.of(Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[1]))); + } break; case STR_ICMPV6_CODE: if (ver10 == true) { throw new IllegalArgumentException("OF Version incompatible"); - //throw new Exception("OF Version incompatible"); } - mb.setExact(MatchField.ICMPV6_CODE, U8.of(Short.parseShort(key_value[1]))); + if (dataMask.length == 1) { + mb.setExact(MatchField.ICMPV6_CODE, dataMask[0].contains("0x") ? U8.of(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[0]))); + } else { + mb.setMasked(MatchField.ICMPV6_CODE, dataMask[0].contains("0x") ? U8.of(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[0])), + dataMask[1].contains("0x") ? U8.of(Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[1]))); + } break; case STR_IPV6_ND_SSL: if (ver10 == true) { throw new IllegalArgumentException("OF Version incompatible"); - //throw new Exception("OF Version incompatible"); } - mb.setExact(MatchField.IPV6_ND_SLL, MacAddress.of(key_value[1])); + if (dataMask.length == 1) { + mb.setExact(MatchField.IPV6_ND_SLL, MacAddress.of(dataMask[0])); + } else { + mb.setMasked(MatchField.IPV6_ND_SLL, MacAddress.of(dataMask[0]), MacAddress.of(dataMask[1])); + } break; case STR_IPV6_ND_TTL: if (ver10 == true) { throw new IllegalArgumentException("OF Version incompatible"); - //throw new Exception("OF Version incompatible"); } - mb.setExact(MatchField.IPV6_ND_TLL, MacAddress.of(key_value[1])); + if (dataMask.length == 1) { + mb.setExact(MatchField.IPV6_ND_TLL, MacAddress.of(dataMask[0])); + } else { + mb.setMasked(MatchField.IPV6_ND_TLL, MacAddress.of(dataMask[0]), MacAddress.of(dataMask[1])); + } break; case STR_IPV6_ND_TARGET: if (ver10 == true) { throw new IllegalArgumentException("OF Version incompatible"); - //throw new Exception("OF Version incompatible"); } - mb.setExact(MatchField.IPV6_ND_TARGET, IPv6Address.of(key_value[1])); + mb.setMasked(MatchField.IPV6_ND_TARGET, IPv6AddressWithMask.of(key_value[1])); break; - //sanjivini - case STR_ARP_OPCODE: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.ARP_OP, ArpOpcode.of(Integer.parseInt(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.ARP_OP, dataMask[0].contains("0x") ? ArpOpcode.of(Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : ArpOpcode.of(Integer.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.ARP_OP, ArpOpcode.of(Integer.parseInt(key_value[1]))); + mb.setMasked(MatchField.ARP_OP, dataMask[0].contains("0x") ? ArpOpcode.of(Integer.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : ArpOpcode.of(Integer.valueOf(dataMask[0])), + dataMask[1].contains("0x") ? ArpOpcode.of(Integer.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : ArpOpcode.of(Integer.valueOf(dataMask[1]))); } break; case STR_ARP_SHA: - mb.setExact(MatchField.ARP_SHA, MacAddress.of(key_value[1])); + if (dataMask.length == 1) { + mb.setExact(MatchField.ARP_SHA, MacAddress.of(dataMask[0])); + } else { + mb.setMasked(MatchField.ARP_SHA, MacAddress.of(dataMask[0]), MacAddress.of(dataMask[1])); + } break; case STR_ARP_DHA: - mb.setExact(MatchField.ARP_THA, MacAddress.of(key_value[1])); + if (dataMask.length == 1) { + mb.setExact(MatchField.ARP_THA, MacAddress.of(dataMask[0])); + } else { + mb.setMasked(MatchField.ARP_THA, MacAddress.of(dataMask[0]), MacAddress.of(dataMask[1])); + } break; case STR_ARP_SPA: - mb.setExact(MatchField.ARP_SPA, IPv4Address.of(key_value[1])); + mb.setMasked(MatchField.ARP_SPA, IPv4AddressWithMask.of(key_value[1])); break; case STR_ARP_DPA: - mb.setExact(MatchField.ARP_TPA, IPv4Address.of(key_value[1])); + mb.setMasked(MatchField.ARP_TPA, IPv4AddressWithMask.of(key_value[1])); break; case STR_MPLS_LABEL: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.MPLS_LABEL, U32.of(Long.parseLong(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.MPLS_LABEL, dataMask[0].contains("0x") ? U32.of(Long.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U32.of(Long.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.MPLS_LABEL, U32.of(Long.parseLong(key_value[1]))); + mb.setMasked(MatchField.MPLS_LABEL, dataMask[0].contains("0x") ? U32.of(Long.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U32.of(Long.valueOf(dataMask[0])), + dataMask[1].contains("0x") ? U32.of(Long.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U32.of(Long.valueOf(dataMask[1]))); } break; case STR_MPLS_TC: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.MPLS_TC, U8.of(Short.parseShort(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.MPLS_TC, dataMask[0].contains("0x") ? U8.of(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.MPLS_TC, U8.of(Short.parseShort(key_value[1]))); + mb.setMasked(MatchField.MPLS_TC, dataMask[0].contains("0x") ? U8.of(Short.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[0])), + dataMask[1].contains("0x") ? U8.of(Short.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U8.of(Short.valueOf(dataMask[1]))); } break; case STR_MPLS_BOS: mb.setExact(MatchField.MPLS_BOS, key_value[1].equalsIgnoreCase("true") ? OFBooleanValue.TRUE : OFBooleanValue.FALSE); break; case STR_METADATA: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.METADATA, OFMetadata.ofRaw(Long.parseLong(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.METADATA, dataMask[0].contains("0x") ? OFMetadata.ofRaw(Long.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : OFMetadata.ofRaw(Long.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.METADATA, OFMetadata.ofRaw(Long.parseLong(key_value[1]))); + mb.setMasked(MatchField.METADATA, dataMask[0].contains("0x") ? OFMetadata.ofRaw(Long.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : OFMetadata.ofRaw(Long.valueOf(dataMask[0])), + dataMask[1].contains("0x") ? OFMetadata.ofRaw(Long.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : OFMetadata.ofRaw(Long.valueOf(dataMask[1]))); } break; case STR_TUNNEL_ID: - if (key_value[1].startsWith("0x")) { - mb.setExact(MatchField.TUNNEL_ID, U64.of(Long.parseLong(key_value[1].replaceFirst("0x", ""), 16))); + if (dataMask.length == 1) { + mb.setExact(MatchField.TUNNEL_ID, dataMask[0].contains("0x") ? U64.of(Long.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U64.of(Long.valueOf(dataMask[0]))); } else { - mb.setExact(MatchField.TUNNEL_ID, U64.of(Long.parseLong(key_value[1]))); + mb.setMasked(MatchField.TUNNEL_ID, dataMask[0].contains("0x") ? U64.of(Long.valueOf(dataMask[0].replaceFirst("0x", ""), 16)) : U64.of(Long.valueOf(dataMask[0])), + dataMask[1].contains("0x") ? U64.of(Long.valueOf(dataMask[1].replaceFirst("0x", ""), 16)) : U64.of(Long.valueOf(dataMask[1]))); } break; case STR_PBB_ISID: