blob: 2248658f1d993d2560b5c637a1ea4ac9900b1f60 [file] [log] [blame]
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);
}
}