Added SpringOpenTTP switch driver (ONOS-822/ONOS-682).
Modified OpenFlpwRuleProvider to support FlowRule with multiple-table feature.
Change-Id: If95284077b96213593c5c1e3ab12900001bf49a2
diff --git a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTP.java b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTP.java
index 925a744..0fbdfa8 100644
--- a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTP.java
+++ b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFSwitchImplSpringOpenTTP.java
@@ -16,28 +16,99 @@
package org.onosproject.openflow.drivers;
import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.RoleState;
import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
+import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
+import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
+import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
+import org.projectfloodlight.openflow.protocol.OFErrorMsg;
+import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
+import org.projectfloodlight.openflow.protocol.OFMatchV3;
+import org.projectfloodlight.openflow.protocol.OFOxmList;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFType;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TableId;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.util.HexString;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
-/**
- * Created by sanghoshin on 1/22/15.
- */
public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch {
- protected OFSwitchImplSpringOpenTTP(Dpid dp) {
- super(dp);
+ private OFFactory factory;
+
+ private final AtomicBoolean driverHandshakeComplete;
+ private AtomicBoolean haltStateMachine;
+
+ private DriverState driverState;
+
+ /* Default table ID - compatible with CpqD switch */
+ private static final int TABLE_VLAN = 0;
+ private static final int TABLE_TMAC = 1;
+ private static final int TABLE_IPV4_UNICAST = 2;
+ private static final int TABLE_MPLS = 3;
+ private static final int TABLE_ACL = 5;
+
+ private static final long TEST_FLOW_REMOVED_MASK = 0xf;
+ private static final long TEST_PACKET_IN_MASK = 0x7;
+ private static final long TEST_PORT_STATUS_MASK = 0x7;
+
+ private static final int OFPCML_NO_BUFFER = 0xffff;
+
+ private long barrierXidToWaitFor = -1;
+
+ /* Set the default values. These variables will get
+ * overwritten based on the switch vendor type
+ */
+ protected int vlanTableId = TABLE_VLAN;
+ protected int tmacTableId = TABLE_TMAC;
+ protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST;
+ protected int mplsTableId = TABLE_MPLS;
+ protected int aclTableId = TABLE_ACL;
+
+ /* priority values for OF message */
+ private static final short MAX_PRIORITY = (short) 0xffff;
+ private static final short PRIORITY_MULTIPLIER = (short) 2046;
+ private static final short MIN_PRIORITY = 0x0;
+
+
+ protected OFSwitchImplSpringOpenTTP(Dpid dpid, OFDescStatsReply desc) {
+ super(dpid);
+ driverHandshakeComplete = new AtomicBoolean(false);
+ haltStateMachine = new AtomicBoolean(false);
+ driverState = DriverState.INIT;
+ setSwitchDescription(desc);
}
- @Override
- public void write(OFMessage msg) {
-
- }
@Override
- public void write(List<OFMessage> msgs) {
-
+ public String toString() {
+ return "OFSwitchImplSpringOpenTTP [" + ((channel != null)
+ ? channel.getRemoteAddress() : "?")
+ + " DPID[" + ((this.getStringId() != null) ?
+ this.getStringId() : "?") + "]]";
}
@Override
@@ -47,17 +118,458 @@
@Override
public void startDriverHandshake() {
+ log.debug("Starting driver handshake for sw {}", getStringId());
+ if (startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeAlreadyStarted();
+ }
+ startDriverHandshakeCalled = true;
+ factory = this.factory();
+ try {
+ nextDriverState();
+ } catch (IOException e) {
+ log.error("Error {} during driver handshake for sw {}", e.getCause(),
+ getStringId());
+ }
}
@Override
public boolean isDriverHandshakeComplete() {
- return false;
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+ return driverHandshakeComplete.get();
}
@Override
public void processDriverHandshakeMessage(OFMessage m) {
-
+ if (!startDriverHandshakeCalled) {
+ throw new SwitchDriverSubHandshakeNotStarted();
+ }
+ if (driverHandshakeComplete.get()) {
+ throw new SwitchDriverSubHandshakeCompleted(m);
+ }
+ try {
+ processOFMessage(m);
+ } catch (IOException e) {
+ log.error("Error generated when processing OFMessage {}", e.getCause());
+ }
}
-}
+ @Override
+ public void write(OFMessage msg) {
+ this.channel.write(Collections.singletonList(msg));
+ }
+
+ @Override
+ public void write(List<OFMessage> msgs) {
+ this.channel.write(msgs);
+ }
+
+ @Override
+ public void sendMsg(OFMessage m, TableType tableType) {
+
+ if (m.getType() == OFType.FLOW_MOD) {
+ OFFlowMod flowMod = (OFFlowMod) m;
+ OFFlowMod.Builder builder = flowMod.createBuilder();
+ builder.setTableId(getTableId(tableType));
+ OFFlowMod newFlowMod = builder.build();
+ if (role == RoleState.MASTER) {
+ this.write(newFlowMod);
+ }
+ } else {
+ if (role == RoleState.MASTER) {
+ this.write(m);
+ }
+ }
+ }
+
+ /*
+ * Driver handshake state machine
+ */
+
+ enum DriverState {
+ INIT,
+ SET_TABLE_MISS_ENTRIES,
+ SET_TABLE_VLAN_TMAC,
+ AUDIT_GROUPS,
+ SET_GROUPS,
+ VERIFY_GROUPS,
+ SET_ADJACENCY_LABELS,
+ EXIT
+ }
+
+ protected void nextDriverState() throws IOException {
+ DriverState currentState = driverState;
+ if (haltStateMachine.get()) {
+ return;
+ }
+ switch (currentState) {
+ case INIT:
+ driverState = DriverState.SET_TABLE_MISS_ENTRIES;
+ setTableMissEntries();
+ sendHandshakeBarrier();
+ break;
+ case SET_TABLE_MISS_ENTRIES:
+ driverState = DriverState.SET_TABLE_VLAN_TMAC;
+ /* TODO: read network configuration
+ boolean isConfigured = getNetworkConfig();
+ if (!isConfigured) {
+ return; // this will result in a handshake timeout
+ }
+ */
+ populateTableVlan();
+ populateTableTMac();
+ sendHandshakeBarrier();
+ break;
+ case SET_TABLE_VLAN_TMAC:
+ driverState = DriverState.EXIT;
+ driverHandshakeComplete.set(true);
+ log.debug("Driver handshake is complete");
+ break;
+ case EXIT:
+ default:
+ driverState = DriverState.EXIT;
+ log.error("Driver handshake has exited for sw: {}", getStringId());
+ }
+ }
+
+ private void processStatsReply(OFStatsReply sr) {
+ switch (sr.getStatsType()) {
+ case AGGREGATE:
+ break;
+ case DESC:
+ break;
+ case EXPERIMENTER:
+ break;
+ case FLOW:
+ break;
+ case GROUP_DESC:
+ processGroupDesc((OFGroupDescStatsReply) sr);
+ break;
+ case GROUP_FEATURES:
+ processGroupFeatures((OFGroupFeaturesStatsReply) sr);
+ break;
+ case METER_CONFIG:
+ break;
+ case METER_FEATURES:
+ break;
+ case PORT_DESC:
+ break;
+ case TABLE_FEATURES:
+ break;
+ default:
+ break;
+
+ }
+ }
+
+ private void processOFMessage(OFMessage m) throws IOException {
+ switch (m.getType()) {
+ case BARRIER_REPLY:
+ processBarrierReply(m);
+ break;
+
+ case ERROR:
+ processErrorMessage(m);
+ break;
+
+ case GET_ASYNC_REPLY:
+ OFAsyncGetReply asrep = (OFAsyncGetReply) m;
+ decodeAsyncGetReply(asrep);
+ break;
+
+ case PACKET_IN:
+ // not ready to handle packet-ins
+ break;
+
+ case QUEUE_GET_CONFIG_REPLY:
+ // not doing queue config yet
+ break;
+
+ case STATS_REPLY:
+ processStatsReply((OFStatsReply) m);
+ break;
+
+ case ROLE_REPLY: // channelHandler should handle this
+ case PORT_STATUS: // channelHandler should handle this
+ case FEATURES_REPLY: // don't care
+ case FLOW_REMOVED: // don't care
+ default:
+ log.debug("Received message {} during switch-driver subhandshake "
+ + "from switch {} ... Ignoring message", m, getStringId());
+ }
+ }
+
+ private void processBarrierReply(OFMessage m) throws IOException {
+ if (m.getXid() == barrierXidToWaitFor) {
+ // Driver state-machine progresses to the next state.
+ // If Barrier messages is not received, then eventually
+ // the ChannelHandler state machine will timeout, and the switch
+ // will be disconnected.
+ nextDriverState();
+ } else {
+ log.error("Received incorrect barrier-message xid {} (expected: {}) in "
+ + "switch-driver state {} for switch {}", m, barrierXidToWaitFor,
+ driverState, getStringId());
+ }
+ }
+
+ private void processErrorMessage(OFMessage m) {
+ log.error("Switch {} Error {} in DriverState", getStringId(),
+ (OFErrorMsg) m, driverState);
+ }
+
+ private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
+ log.info("Sw: {} Group Features {}", getStringId(), gfsr);
+ }
+
+ private void processGroupDesc(OFGroupDescStatsReply gdsr) {
+ log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
+ }
+
+ /*
+ * Utility functions
+ */
+
+ private void decodeAsyncGetReply(OFAsyncGetReply rep) {
+ long frm = rep.getFlowRemovedMaskEqualMaster();
+ //long frs = rep.getFlowRemovedMaskSlave();
+ long pim = rep.getPacketInMaskEqualMaster();
+ //long pis = rep.getPacketInMaskSlave();
+ long psm = rep.getPortStatusMaskEqualMaster();
+ //long pss = rep.getPortStatusMaskSlave();
+
+ if (role == RoleState.MASTER || role == RoleState.EQUAL) { // should separate
+ log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
+ log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
+ log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
+ }
+ }
+
+ protected void setTableMissEntries() throws IOException {
+ // set all table-miss-entries
+ populateTableMissEntry(vlanTableId, true, false, false, -1);
+ populateTableMissEntry(tmacTableId, true, false, false, -1);
+ populateTableMissEntry(ipv4UnicastTableId, false, true, true,
+ aclTableId);
+ populateTableMissEntry(mplsTableId, false, true, true,
+ aclTableId);
+ populateTableMissEntry(aclTableId, false, false, false, -1);
+ log.debug("TableMissEntries are set");
+ }
+
+ /**
+ * Adds a table-miss-entry to a pipeline table.
+ * <p>
+ * The table-miss-entry can be added with 'write-actions' or
+ * 'apply-actions'. It can also add a 'goto-table' instruction. By default
+ * if none of the booleans in the call are set, then the table-miss entry is
+ * added with no instructions, which means that if a packet hits the
+ * table-miss-entry, pipeline execution will stop, and the action set
+ * associated with the packet will be executed.
+ *
+ * @param tableToAdd the table to where the table-miss-entry will be added
+ * @param toControllerNow as an APPLY_ACTION instruction
+ * @param toControllerWrite as a WRITE_ACTION instruction
+ * @param toTable as a GOTO_TABLE instruction
+ * @param tableToSend the table to send as per the GOTO_TABLE instruction it
+ * needs to be set if 'toTable' is true. Ignored of 'toTable' is
+ * false.
+ * @throws IOException
+ */
+ protected void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
+ boolean toControllerWrite,
+ boolean toTable, int tableToSend) throws IOException {
+ OFOxmList oxmList = OFOxmList.EMPTY;
+ OFMatchV3 match = factory.buildMatchV3()
+ .setOxmList(oxmList)
+ .build();
+ OFAction outc = factory.actions()
+ .buildOutput()
+ .setPort(OFPort.CONTROLLER)
+ .setMaxLen(OFPCML_NO_BUFFER)
+ .build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ if (toControllerNow) {
+ // table-miss instruction to send to controller immediately
+ OFInstruction instr = factory.instructions()
+ .buildApplyActions()
+ .setActions(Collections.singletonList(outc))
+ .build();
+ instructions.add(instr);
+ }
+
+ if (toControllerWrite) {
+ // table-miss instruction to write-action to send to controller
+ // this will be executed whenever the action-set gets executed
+ OFInstruction instr = factory.instructions()
+ .buildWriteActions()
+ .setActions(Collections.singletonList(outc))
+ .build();
+ instructions.add(instr);
+ }
+
+ if (toTable) {
+ // table-miss instruction to goto-table x
+ OFInstruction instr = factory.instructions()
+ .gotoTable(TableId.of(tableToSend));
+ instructions.add(instr);
+ }
+
+ if (!toControllerNow && !toControllerWrite && !toTable) {
+ // table-miss has no instruction - at which point action-set will be
+ // executed - if there is an action to output/group in the action
+ // set
+ // the packet will be sent there, otherwise it will be dropped.
+ instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
+ }
+
+ OFMessage tableMissEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(tableToAdd))
+ .setMatch(match) // match everything
+ .setInstructions(instructions)
+ .setPriority(MIN_PRIORITY)
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ write(tableMissEntry);
+ }
+
+ private void populateTableVlan() throws IOException {
+ List<OFMessage> msglist = new ArrayList<OFMessage>();
+ for (OFPortDesc p : getPorts()) {
+ int pnum = p.getPortNo().getPortNumber();
+ if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
+ OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
+ OFOxmVlanVid oxv = factory.oxms()
+ .vlanVid(OFVlanVidMatch.UNTAGGED);
+ OFOxmList oxmList = OFOxmList.of(oxp, oxv);
+ OFMatchV3 match = factory.buildMatchV3()
+ .setOxmList(oxmList).build();
+
+ // TODO: match on vlan-tagged packets for vlans configured on
+ // subnet ports and strip-vlan
+
+ OFInstruction gotoTbl = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(tmacTableId)).build();
+ List<OFInstruction> instructions = new ArrayList<OFInstruction>();
+ instructions.add(gotoTbl);
+ OFMessage flowEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(vlanTableId))
+ .setMatch(match)
+ .setInstructions(instructions)
+ .setPriority(1000) // does not matter - all rules
+ // exclusive
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+ msglist.add(flowEntry);
+ }
+ }
+ write(msglist);
+ log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId());
+ }
+
+ private void populateTableTMac() throws IOException {
+ // match for router-mac and ip-packets
+ OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
+
+ /* TODO: need to read network config and need to allow only
+ the packets with DMAC as the correspondent router MAC address
+ Until network configuration is implemented, all packets are allowed
+
+ OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr());
+ OFOxmList oxmListIp = OFOxmList.of(dmac, oxe);
+ OFMatchV3 matchIp = factory.buildMatchV3()
+ .setOxmList(oxmListIp).build();
+ */
+ OFOxmList oxmList = OFOxmList.EMPTY;
+ OFMatchV3 matchIp = factory.buildMatchV3()
+ .setOxmList(oxmList)
+ .build();
+
+ OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(ipv4UnicastTableId)).build();
+ List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
+ OFMessage ipEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(tmacTableId))
+ .setMatch(matchIp)
+ .setInstructions(instructionsIp)
+ .setPriority(1000) // strict priority required lower than
+ // multicastMac
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+
+ // match for router-mac and mpls packets
+ OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
+ /* TODO: need to read network config and need to allow only
+ the packets with DMAC as the correspondent router MAC address
+ OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls);
+ OFMatchV3 matchMpls = factory.buildMatchV3()
+ .setOxmList(oxmListMpls).build();
+ */
+ OFOxmList oxmListMpls = OFOxmList.EMPTY;
+ OFMatchV3 matchMpls = factory.buildMatchV3()
+ .setOxmList(oxmList)
+ .build();
+
+ OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
+ .setTableId(TableId.of(mplsTableId)).build();
+ List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
+ OFMessage mplsEntry = factory.buildFlowAdd()
+ .setTableId(TableId.of(tmacTableId))
+ .setMatch(matchMpls)
+ .setInstructions(instructionsMpls)
+ .setPriority(1001) // strict priority required lower than
+ // multicastMac
+ .setBufferId(OFBufferId.NO_BUFFER)
+ .setIdleTimeout(0)
+ .setHardTimeout(0)
+ .setXid(getNextTransactionId())
+ .build();
+
+ log.debug("Adding termination-mac-rules in sw {}", getStringId());
+ List<OFMessage> msglist = new ArrayList<OFMessage>(2);
+ msglist.add(ipEntry);
+ msglist.add(mplsEntry);
+ write(msglist);
+ }
+
+ private MacAddress getRouterMacAddr() {
+ // TODO: need to read network config : RouterIp
+ return MacAddress.of("00:00:00:00:00:00");
+ }
+
+ private TableId getTableId(TableType tableType) {
+ switch (tableType) {
+ case IP:
+ return TableId.of(ipv4UnicastTableId);
+ case MPLS:
+ return TableId.of(mplsTableId);
+ case ACL:
+ return TableId.of(aclTableId);
+ default: {
+ log.error("Table type {} is not supported in the driver", tableType);
+ return TableId.NONE;
+ }
+ }
+ }
+
+ private void sendHandshakeBarrier() throws IOException {
+ long xid = getNextTransactionId();
+ barrierXidToWaitFor = xid;
+ OFBarrierRequest br = factory()
+ .buildBarrierRequest()
+ .setXid(xid)
+ .build();
+ write(br);
+ }
+}
\ No newline at end of file
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
index 32dfefd..f80ab06 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -166,8 +166,13 @@
private void applyRule(FlowRule flowRule) {
OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
- sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
- Optional.empty()).buildFlowAdd());
+ if (flowRule.type() == FlowRule.Type.DEFAULT) {
+ sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
+ Optional.empty()).buildFlowAdd());
+ } else {
+ sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
+ Optional.empty()).buildFlowAdd(), getTableType(flowRule.type()));
+ }
}
@@ -181,8 +186,13 @@
private void removeRule(FlowRule flowRule) {
OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
- sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
- Optional.empty()).buildFlowDel());
+ if (flowRule.type() == FlowRule.Type.DEFAULT) {
+ sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
+ Optional.empty()).buildFlowDel());
+ } else {
+ sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
+ Optional.empty()).buildFlowDel(), getTableType(flowRule.type()));
+ }
}
@Override
@@ -195,11 +205,13 @@
public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
final Set<Dpid> sws = Sets.newConcurrentHashSet();
final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<>();
+
/*
* Use identity hash map for reference equality as we could have equal
* flow mods for different switches.
*/
Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap();
+ Map<OFFlowMod, OpenFlowSwitch.TableType> modTypes = Maps.newIdentityHashMap();
for (FlowRuleBatchEntry fbe : batch.getOperations()) {
FlowRule flowRule = fbe.target();
final Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
@@ -235,6 +247,7 @@
}
if (mod != null) {
mods.put(mod, sw);
+ modTypes.put(mod, getTableType(flowRule.type()));
fmXids.put(flowModXid, fbe);
} else {
log.error("Conversion of flowrule {} failed.", flowRule);
@@ -249,12 +262,29 @@
for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) {
OpenFlowSwitch sw = entry.getValue();
OFFlowMod mod = entry.getKey();
- sw.sendMsg(mod);
+ OpenFlowSwitch.TableType tableType = modTypes.get(mod);
+ if (tableType == OpenFlowSwitch.TableType.NONE) {
+ sw.sendMsg(mod);
+ } else {
+ sw.sendMsg(mod, tableType);
+ }
}
installation.verify();
return installation;
}
+ private OpenFlowSwitch.TableType getTableType(FlowRule.Type type) {
+ switch (type) {
+ case IP:
+ return OpenFlowSwitch.TableType.IP;
+ case MPLS:
+ return OpenFlowSwitch.TableType.MPLS;
+ case ACL:
+ return OpenFlowSwitch.TableType.ACL;
+ default:
+ return OpenFlowSwitch.TableType.NONE;
+ }
+ }
private class InternalFlowProvider
implements OpenFlowSwitchListener, OpenFlowEventListener {