Skip to content
Snippets Groups Projects
Commit c0008947 authored by Alex Reimers's avatar Alex Reimers
Browse files

FLOODLIGHT-30 - Fix sending down the flowmod.

Also fixed an issue in Static Flow Pusher that would leave an orphaned flow if a static flow changed it's DPID.
parent a21f516d
No related branches found
No related tags found
No related merge requests found
......@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.HashMap;
import java.util.List;
......@@ -35,11 +36,11 @@ import net.floodlightcontroller.storage.IStorageSourceListener;
import net.floodlightcontroller.storage.StorageException;
import org.openflow.protocol.OFBarrierRequest;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFFlowRemoved;
import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFType;
import org.openflow.util.HexString;
import org.openflow.util.U16;
......@@ -186,7 +187,7 @@ public class StaticFlowEntryPusher
protected Map<String, String> computeEntry2DpidMap(
Map<String, Map<String, OFFlowMod>> map) {
Map<String, String> ret = new HashMap<String, String>();
Map<String, String> ret = new ConcurrentHashMap<String, String>();
for(String dpid : map.keySet()) {
for( String entry: map.get(dpid).keySet())
ret.put(entry, dpid);
......@@ -279,8 +280,7 @@ public class StaticFlowEntryPusher
flowMod.setCookie(
StaticFlowEntries.computeEntryCookie(flowMod,
Integer.valueOf((String) row.get(COLUMN_COOKIE)),
entryName)
);
entryName));
} else if (key.equals(COLUMN_PRIORITY)) {
flowMod.setPriority(U16.t(Integer.valueOf((String) row.get(COLUMN_PRIORITY))));
} else { // the rest of the keys are for OFMatch().fromString()
......@@ -317,7 +317,7 @@ public class StaticFlowEntryPusher
@Override
public void addedSwitch(IOFSwitch sw) {
log.debug("addedSwitch {}; processing its static entries", sw);
log.debug("Switch {} connected; processing its static entries", HexString.toHexString(sw.getId()));
sendEntriesToSwitch(sw);
}
......@@ -355,10 +355,22 @@ public class StaticFlowEntryPusher
List<OFMessage> outQueue = new ArrayList<OFMessage>();
for(String entry : entriesToAdd.get(dpid).keySet()) {
OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry);
OFFlowMod oldFlowMod = entriesFromStorage.get(dpid).get(entry);
if (oldFlowMod != null) { // remove any pre-existing rule
//OFFlowMod oldFlowMod = entriesFromStorage.get(dpid).get(entry);
OFFlowMod oldFlowMod = null;
String dpidOldFlowMod = entry2dpid.get(entry);
if (dpidOldFlowMod != null) {
oldFlowMod = entriesFromStorage.get(dpidOldFlowMod).remove(entry);
}
if (oldFlowMod != null) {
// Remove any pre-existing rule
// If the old rule is on a different switch
// then we have to handle that as well.
oldFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
outQueue.add(oldFlowMod);
if (dpidOldFlowMod.equals(dpid)) {
outQueue.add(oldFlowMod);
} else {
writeOFMessageToSwitch(HexString.toLong(dpidOldFlowMod), oldFlowMod);
}
}
if (newFlowMod != null) {
entriesFromStorage.get(dpid).put(entry, newFlowMod);
......@@ -397,15 +409,16 @@ public class StaticFlowEntryPusher
private void deleteStaticFlowEntry(String entryName) {
String dpid = entry2dpid.remove(entryName);
if (log.isDebugEnabled()) {
log.debug("Deleting flow {} for switch {}", entryName, dpid);
}
if (dpid == null) {
// assume state has been cleared by deleteFlowsForSwitch() or
// deleteAllFlows()
return;
}
if (log.isDebugEnabled()) {
log.debug("Sending delete flow mod for flow {} for switch {}", entryName, dpid);
}
// send flow_mod delete
OFFlowMod flowMod = entriesFromStorage.get(dpid).get(entryName);
flowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
......@@ -431,7 +444,7 @@ public class StaticFlowEntryPusher
@LogMessageDoc(level="ERROR",
message="Tried to write to switch {switch} but got {error}",
explanation="An I/O error occured while trying to write a " +
"static flow to a switch",
"static flow to a switch",
recommendation=LogMessageDoc.CHECK_SWITCH)
private void writeOFMessagesToSwitch(long dpid, List<OFMessage> messages) {
IOFSwitch ofswitch = floodlightProvider.getSwitches().get(dpid);
......@@ -448,6 +461,31 @@ public class StaticFlowEntryPusher
}
}
/**
* Writes a single OFMessage to a switch
* @param dpid The datapath ID of the switch to write to
* @param message The OFMessage to write.
*/
@LogMessageDoc(level="ERROR",
message="Tried to write to switch {switch} but got {error}",
explanation="An I/O error occured while trying to write a " +
"static flow to a switch",
recommendation=LogMessageDoc.CHECK_SWITCH)
private void writeOFMessageToSwitch(long dpid, OFMessage message) {
IOFSwitch ofswitch = floodlightProvider.getSwitches().get(dpid);
if (ofswitch != null) { // is the switch connected
try {
if (log.isDebugEnabled()) {
log.debug("Sending 1 new entries to {}", HexString.toHexString(dpid));
}
ofswitch.write(message, null);
ofswitch.flush();
} catch (IOException e) {
log.error("Tried to write to switch {} but got {}", dpid, e.getMessage());
}
}
}
/**
* Writes an OFFlowMod to a switch. It checks to make sure the switch
* exists before it sends
......@@ -492,29 +530,32 @@ public class StaticFlowEntryPusher
return StaticFlowName;
}
public Command handleFlowRemoved(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
OFFlowRemoved flowRemoved = (OFFlowRemoved) msg;
long cookie = flowRemoved.getCookie();
/**
* Handles a flow removed message from a switch. If the flow was removed
* and we did not explicitly delete it we re-install it. If we explicitly
* removed the flow we stop the processing of the flow removed message.
* @param sw The switch that sent the flow removed message.
* @param msg The flow removed message.
* @param cntx The associated context.
* @return Whether to continue processing this message.
*/
public Command handleFlowRemoved(IOFSwitch sw, OFFlowRemoved msg, FloodlightContext cntx) {
long cookie = msg.getCookie();
/**
* This is just to sanity check our assumption that static flows
* never expire.
*/
if (AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) {
if (flowRemoved.getReason() !=
OFFlowRemoved.OFFlowRemovedReason.OFPRR_DELETE)
if (msg.getReason() != OFFlowRemoved.OFFlowRemovedReason.OFPRR_DELETE)
log.error("Got a FlowRemove message for a infinite " +
"timeout flow: {} from switch {}", msg, sw);
return Command.STOP; // only for us
// Stop the processing chain since we sent the delete.
return Command.STOP;
}
return Command.CONTINUE;
}
public Command handleBarrierReply(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
return Command.CONTINUE;
}
@Override
@LogMessageDoc(level="ERROR",
message="Got a FlowRemove message for a infinite " +
......@@ -525,9 +566,7 @@ public class StaticFlowEntryPusher
public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
switch (msg.getType()) {
case FLOW_REMOVED:
return handleFlowRemoved(sw, msg, cntx);
case BARRIER_REPLY:
return handleBarrierReply(sw, msg, cntx);
return handleFlowRemoved(sw, (OFFlowRemoved) msg, cntx);
default:
return Command.CONTINUE;
}
......@@ -587,7 +626,6 @@ public class StaticFlowEntryPusher
@Override
public void startUp(FloodlightModuleContext context) {
floodlightProvider.addOFMessageListener(OFType.FLOW_REMOVED, this);
floodlightProvider.addOFMessageListener(OFType.BARRIER_REPLY, this);
floodlightProvider.addOFSwitchListener(this);
floodlightProvider.addHAListener(this);
......@@ -623,13 +661,13 @@ public class StaticFlowEntryPusher
@Override
public void deleteAllFlows() {
// Send a delete for each switch
Set<String> swSet = new HashSet<String>();
for (String dpid : entry2dpid.values()) {
sendDeleteByCookie(HexString.toLong(dpid));
}
// Delete it from the DB
for (String entry : entry2dpid.keySet()) {
deleteFlow(entry);
// Avoid sending duplicate deletes
if (!swSet.contains(dpid)) {
swSet.add(dpid);
sendDeleteByCookie(HexString.toLong(dpid));
}
}
// Clear our map
......@@ -640,13 +678,15 @@ public class StaticFlowEntryPusher
eMap.clear();
}
// Reset our DB
storageSource.deleteMatchingRowsAsync(TABLE_NAME, null);
}
@Override
public void deleteFlowsForSwitch(long dpid) {
String sDpid = HexString.toHexString(dpid);
sendDeleteByCookie(dpid);
String sDpid = HexString.toHexString(dpid);
// Clear all internal flows for this switch
Map<String, OFFlowMod> sMap = entriesFromStorage.get(sDpid);
if (sMap != null) {
......@@ -666,12 +706,11 @@ public class StaticFlowEntryPusher
* We send a delete flow mod with the static flow pusher app ID in the cookie.
* Since OF1.0 doesn't support masking based on the cookie we have to
* disable having flow specific cookies.
* @param dpid
* @param dpid The DPID of the switch to clear all it's flows.
*/
public void sendDeleteByCookie(long dpid) {
private void sendDeleteByCookie(long dpid) {
if (log.isDebugEnabled())
log.debug("Delete all static flows on switch {}",
HexString.toHexString(dpid));
log.debug("Deleting all static flows on switch {}", HexString.toHexString(dpid));
IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
if (sw == null) {
......@@ -686,15 +725,10 @@ public class StaticFlowEntryPusher
fm.setMatch(ofm);
fm.setCookie(AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, 0));
fm.setCommand(OFFlowMod.OFPFC_DELETE);
OFBarrierRequest ofbr = (OFBarrierRequest) floodlightProvider.getOFMessageFactory().
getMessage(OFType.BARRIER_REQUEST);
List<OFMessage> mList = new ArrayList<OFMessage>(2);
mList.add(fm);
mList.add(ofbr);
fm.setOutPort(OFPort.OFPP_NONE);
try {
sw.write(mList, null);
sw.write(fm, null);
sw.flush();
} catch (IOException e1) {
log.error("Error deleting all flows for switch {}:\n {}",
......@@ -712,7 +746,6 @@ public class StaticFlowEntryPusher
public Map<String, OFFlowMod> getFlows(String dpid) {
return entriesFromStorage.get(dpid);
}
// IHAListener
......
......@@ -59,6 +59,7 @@ public class OFFlowMod extends OFMessage implements OFActionFactoryAware, Clonea
public OFFlowMod() {
super();
this.outPort = OFPort.OFPP_NONE.getValue();
this.type = OFType.FLOW_MOD;
this.length = U16.t(MINIMUM_LENGTH);
}
......
......@@ -21,6 +21,8 @@ import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.Arrays;
import net.floodlightcontroller.packet.Ethernet;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.jboss.netty.buffer.ChannelBuffer;
import org.openflow.protocol.serializers.OFMatchJSONSerializer;
......@@ -121,7 +123,7 @@ public class OFMatch implements Cloneable, Serializable {
this.dataLayerDestination = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0,
0x0 };
this.dataLayerSource = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
this.dataLayerVirtualLan = -1;
this.dataLayerVirtualLan = Ethernet.VLAN_UNTAGGED;
this.dataLayerVirtualLanPriorityCodePoint = 0;
this.dataLayerType = 0;
this.inputPort = 0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment