package net.onrc.onos.core.drivermanager; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted; import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted; import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted; import net.floodlightcontroller.core.internal.OFSwitchImplBase; import org.projectfloodlight.openflow.protocol.OFBarrierRequest; import org.projectfloodlight.openflow.protocol.OFDescStatsReply; import org.projectfloodlight.openflow.protocol.OFErrorMsg; import org.projectfloodlight.openflow.protocol.OFMatchV3; import org.projectfloodlight.openflow.protocol.OFMessage; import org.projectfloodlight.openflow.protocol.OFOxmList; import org.projectfloodlight.openflow.protocol.action.OFAction; import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFPort; import org.projectfloodlight.openflow.types.TableId; /** * OFDescriptionStatistics Vendor (Manufacturer Desc.): Nicira, Inc. Make * (Hardware Desc.) : Open vSwitch Model (Datapath Desc.) : None Software : * 2.1.0 (or whatever version + build) Serial : None */ public class OFSwitchImplOVS13 extends OFSwitchImplBase { private AtomicBoolean driverHandshakeComplete; private long barrierXidToWaitFor = -1; public OFSwitchImplOVS13(OFDescStatsReply desc) { super(); driverHandshakeComplete = new AtomicBoolean(false); setSwitchDescription(desc); } @Override public String toString() { return "OFSwitchImplOVS13 [" + ((channel != null) ? channel.getRemoteAddress() : "?") + " DPID[" + ((stringId != null) ? stringId : "?") + "]]"; } @Override public void startDriverHandshake() throws IOException { log.debug("Starting driver handshake for sw {}", getStringId()); if (startDriverHandshakeCalled) { throw new SwitchDriverSubHandshakeAlreadyStarted(); } startDriverHandshakeCalled = true; populateTableMissEntry(0, true, false, false, 0); configureSwitch(); } @Override public boolean isDriverHandshakeComplete() { 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); } switch (m.getType()) { case BARRIER_REPLY: if (m.getXid() == barrierXidToWaitFor) { driverHandshakeComplete.set(true); } break; case ERROR: log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m); break; case FEATURES_REPLY: break; case FLOW_REMOVED: break; case GET_ASYNC_REPLY: // OFAsyncGetReply asrep = (OFAsyncGetReply)m; // decodeAsyncGetReply(asrep); break; case PACKET_IN: break; case PORT_STATUS: break; case QUEUE_GET_CONFIG_REPLY: break; case ROLE_REPLY: break; case STATS_REPLY: // processStatsReply((OFStatsReply) m); break; default: log.debug("Received message {} during switch-driver subhandshake " + "from switch {} ... Ignoring message", m, getStringId()); } } private void configureSwitch() throws IOException { // setAsyncConfig(); // getTableFeatures(); /*sendGroupFeaturesRequest(); setL2Groups(); sendBarrier(false); setL3Groups(); setL25Groups(); sendGroupDescRequest();*/ // populateTableVlan(); // populateTableTMac(); // populateIpTable(); // populateMplsTable(); // populateTableMissEntry(TABLE_ACL, false, false, false, -1); sendBarrier(true); } private void sendBarrier(boolean finalBarrier) throws IOException { int xid = getNextTransactionId(); if (finalBarrier) { barrierXidToWaitFor = xid; } OFBarrierRequest br = getFactory() .buildBarrierRequest() .setXid(xid) .build(); write(br, null); } /** * 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 pipeline * execution will stop, and the action set associated with the packet will * be executed. * * @param tableToAdd table number to add the table miss entry in * @param toControllerNow as an APPLY_ACTION instruction * @param toControllerWrite as a WRITE_ACITION instruction * @param toTable as a GOTO_TABLE instruction * @param tableToSend table number to a a GOTO_TABLE instruction to * @throws IOException if there's a problem writing to the channel */ // TODO: This is copied straight from the CPqD switch. We need to find // an abstraction for this behaviour. @SuppressWarnings("unchecked") private void populateTableMissEntry(int tableToAdd, boolean toControllerNow, boolean toControllerWrite, boolean toTable, int tableToSend) throws IOException { OFOxmList oxmList = OFOxmList.EMPTY; OFMatchV3 match = getFactory().buildMatchV3() .setOxmList(oxmList) .build(); OFAction outc = getFactory().actions() .buildOutput() .setPort(OFPort.CONTROLLER) .setMaxLen(0xffff) .build(); List<OFInstruction> instructions = new ArrayList<OFInstruction>(); if (toControllerNow) { // table-miss instruction to send to controller immediately OFInstruction instr = getFactory().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 = getFactory().instructions() .buildWriteActions() .setActions(Collections.singletonList(outc)) .build(); instructions.add(instr); } if (toTable) { // table-miss instruction to goto-table x OFInstruction instr = getFactory().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 = getFactory().buildFlowAdd() .setTableId(TableId.of(tableToAdd)) .setMatch(match) // match everything .setInstructions(instructions) .setPriority(0) .setBufferId(OFBufferId.NO_BUFFER) .setIdleTimeout(0) .setHardTimeout(0) .setXid(getNextTransactionId()) .build(); write(tableMissEntry, null); } }