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

Make static flow pusher into a service (IStaticFlowEntryPusherService). This...

Make static flow pusher into a service (IStaticFlowEntryPusherService). This will allow other Floodlight modules to push static flows without using the REST API.
parent 7c9c6777
No related branches found
No related tags found
No related merge requests found
package net.floodlightcontroller.staticflowentry;
import org.openflow.protocol.OFFlowMod;
import net.floodlightcontroller.core.module.IFloodlightService;
public interface IStaticFlowEntryPusherService extends IFloodlightService {
/**
* Adds a static flow.
* @param name Name of the flow mod. Must be unique.
* @param fm The flow to push.
* @param swDpid The switch DPID to push it to.
*/
public void addFlow(String name, OFFlowMod fm, String swDpid);
/**
* Deletes a static flow
* @param name The name of the static flow to delete.
*/
public void deleteFlow(String name);
/**
* Deletes all flows.
*/
public void deleteAllFlows();
}
...@@ -7,7 +7,12 @@ import java.util.List; ...@@ -7,7 +7,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.floodlightcontroller.core.util.AppCookie;
import net.floodlightcontroller.packet.IPv4;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParseException;
...@@ -15,6 +20,8 @@ import org.codehaus.jackson.JsonParser; ...@@ -15,6 +20,8 @@ import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.map.MappingJsonFactory; import org.codehaus.jackson.map.MappingJsonFactory;
import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFPacketOut;
import org.openflow.protocol.OFPort; import org.openflow.protocol.OFPort;
import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFAction;
import org.openflow.protocol.action.OFActionDataLayerDestination; import org.openflow.protocol.action.OFActionDataLayerDestination;
...@@ -29,14 +36,57 @@ import org.openflow.protocol.action.OFActionTransportLayerDestination; ...@@ -29,14 +36,57 @@ import org.openflow.protocol.action.OFActionTransportLayerDestination;
import org.openflow.protocol.action.OFActionTransportLayerSource; import org.openflow.protocol.action.OFActionTransportLayerSource;
import org.openflow.protocol.action.OFActionVirtualLanIdentifier; import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint; import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
import org.openflow.util.HexString;
public class StaticFlowEntries { public class StaticFlowEntries {
protected static Logger log = LoggerFactory.getLogger(StaticFlowEntries.class);
private static class SubActionStruct { private static class SubActionStruct {
OFAction action; OFAction action;
int len; int len;
} }
/**
* This function generates a random hash for the bottom half of the cookie
*
* @param fm
* @param userCookie
* @param name
* @return A cookie that encodes the application ID and a hash
*/
public static long computeEntryCookie(OFFlowMod fm, int userCookie, String name) {
// flow-specific hash is next 20 bits LOOK! who knows if this
int prime = 211;
int flowHash = 2311;
for (int i=0; i < name.length(); i++)
flowHash = flowHash * prime + (int)name.charAt(i);
return AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, flowHash);
}
/**
* Sets defaults for an OFFlowMod
* @param fm The OFFlowMod to set defaults for
* @param entryName The name of the entry. Used to compute the cookie.
*/
public static void initDefaultFlowMod(OFFlowMod fm, String entryName) {
fm.setIdleTimeout((short) 0); // infinite
fm.setHardTimeout((short) 0); // infinite
fm.setBufferId(OFPacketOut.BUFFER_ID_NONE);
fm.setCommand((short) 0);
fm.setFlags((short) 0);
fm.setOutPort(OFPort.OFPP_NONE.getValue());
fm.setCookie(computeEntryCookie(fm, 0, entryName));
fm.setPriority(Short.MAX_VALUE);
}
/**
* Gets the entry name of a flow mod
* @param fmJson The OFFlowMod in a JSON representation
* @return The name of the OFFlowMod, null if not found
* @throws IOException If ther was an error parsing the JSON
*/
public static String getEntryNameFromJson(String fmJson) throws IOException{ public static String getEntryNameFromJson(String fmJson) throws IOException{
MappingJsonFactory f = new MappingJsonFactory(); MappingJsonFactory f = new MappingJsonFactory();
JsonParser jp; JsonParser jp;
...@@ -69,6 +119,98 @@ public class StaticFlowEntries { ...@@ -69,6 +119,98 @@ public class StaticFlowEntries {
return null; return null;
} }
/**
* Parses an OFFlowMod (and it's inner OFMatch) to the storage entry format.
* @param fm The FlowMod to parse
* @param sw The switch the FlowMod is going to be installed on
* @param name The name of this static flow entry
* @return A Map representation of the storage entry
*/
public static Map<String, Object> flowModToStorageEntry(OFFlowMod fm, String sw, String name) {
Map<String, Object> entry = new HashMap<String, Object>();
OFMatch match = fm.getMatch();
entry.put(StaticFlowEntryPusher.COLUMN_NAME, name);
entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw);
entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, StaticFlowEntries.flowModActionsToString(fm.getActions()));
entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Short.toString(fm.getPriority()));
entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true));
entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, Integer.toString(match.getWildcards()));
entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, Short.toString(match.getInputPort()));
entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, HexString.toHexString(match.getDataLayerSource()));
entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, HexString.toHexString(match.getDataLayerDestination()));
entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, Short.toString(match.getDataLayerVirtualLan()));
entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, Short.toString(match.getDataLayerVirtualLanPriorityCodePoint()));
entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, Short.toString(match.getDataLayerType()));
entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Short.toString(match.getNetworkTypeOfService()));
entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Short.toString(match.getNetworkProtocol()));
entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, IPv4.fromIPv4Address(match.getNetworkSource()));
entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, IPv4.fromIPv4Address(match.getNetworkDestination()));
entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, Short.toString(match.getTransportSource()));
entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, Short.toString(match.getTransportDestination()));
return entry;
}
/**
* Returns a
* @param fmActions A list of OFActions to encode into one string
* @return A string of the actions encoded for our database
*/
private static String flowModActionsToString(List<OFAction> fmActions) {
// TODO commas?, make a string array then join with commas in between
// TODO - some values may be in hex....i.e. ethertype
String actions = "";
for (OFAction a : fmActions) {
switch(a.getType()) {
case OUTPUT:
actions += "output=" + Short.toString(((OFActionOutput)a).getPort());
break;
case OPAQUE_ENQUEUE:
actions += "enqueue=" + Integer.toString(((OFActionEnqueue)a).getQueueId());
break;
case SET_VLAN_ID:
actions += "set-vlan-id=" +
Short.toString(((OFActionVirtualLanIdentifier)a).getVirtualLanIdentifier());
break;
case SET_VLAN_PCP:
actions += "set-vlan-priority=" +
Byte.toString(((OFActionVirtualLanPriorityCodePoint)a).getVirtualLanPriorityCodePoint());
break;
case SET_DL_SRC:
actions += "set-src-mac=" +
HexString.toHexString(((OFActionDataLayerSource)a).getDataLayerAddress());
break;
case SET_DL_DST:
actions += "set-dst-mac=" +
HexString.toHexString(((OFActionDataLayerDestination)a).getDataLayerAddress());
break;
case SET_NW_TOS:
actions += "set-tos-bits=" +
Byte.toString(((OFActionNetworkTypeOfService)a).getNetworkTypeOfService());
break;
case SET_NW_SRC:
actions += "set-nw-src=" +
IPv4.fromIPv4Address(((OFActionNetworkLayerSource)a).getNetworkAddress());
break;
case SET_NW_DST:
actions += "set-nw-dst=" +
IPv4.fromIPv4Address(((OFActionNetworkLayerDestination)a).getNetworkAddress());
break;
case SET_TP_SRC:
actions += "set-src-port=" +
Short.toString(((OFActionTransportLayerSource)a).getTransportPort());
break;
case SET_TP_DST:
actions += "set-dst-port=" +
Short.toString(((OFActionTransportLayerDestination)a).getTransportPort());
break;
default:
}
}
return actions;
}
/** /**
* Turns a JSON formatted Static Flow Pusher string into a storage entry * Turns a JSON formatted Static Flow Pusher string into a storage entry
* Expects a string in JSON along the lines of: * Expects a string in JSON along the lines of:
...@@ -151,8 +293,13 @@ public class StaticFlowEntries { ...@@ -151,8 +293,13 @@ public class StaticFlowEntries {
return entry; return entry;
} }
public static void parseActionString(String entryName, String switchName, /**
OFFlowMod flowMod, String actionstr, Logger log) { * Parses OFFlowMod actions from a database
* @param flowMod The OFFlowMod to set the actions for
* @param actionstr The string containing all the actions
* @param log A logger to log for errors.
*/
public static void parseActionString(OFFlowMod flowMod, String actionstr, Logger log) {
List<OFAction> actions = new LinkedList<OFAction>(); List<OFAction> actions = new LinkedList<OFAction>();
int actionsLength = 0; int actionsLength = 0;
if (actionstr != null) { if (actionstr != null) {
...@@ -304,9 +451,8 @@ public class StaticFlowEntries { ...@@ -304,9 +451,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_strip_vlan(String subaction, Logger log) { private static SubActionStruct decode_strip_vlan(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("strip-vlan").matcher(subaction);
n = Pattern.compile("strip-vlan").matcher(subaction);
if (n.matches()) { if (n.matches()) {
OFActionStripVirtualLan action = new OFActionStripVirtualLan(); OFActionStripVirtualLan action = new OFActionStripVirtualLan();
log.debug(" action {}", action); log.debug(" action {}", action);
...@@ -319,16 +465,14 @@ public class StaticFlowEntries { ...@@ -319,16 +465,14 @@ public class StaticFlowEntries {
log.debug(" Invalid action: '{}'", subaction); log.debug(" Invalid action: '{}'", subaction);
return null; return null;
} }
return sa; return sa;
} }
private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) { private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction);
n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction);
if (n.matches()) { if (n.matches()) {
if (n.group(1) != null) { if (n.group(1) != null) {
try { try {
...@@ -357,9 +501,8 @@ public class StaticFlowEntries { ...@@ -357,9 +501,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) { private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction);
n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction);
if (n.matches()) { if (n.matches()) {
if (n.group(1) != null) { if (n.group(1) != null) {
try { try {
...@@ -388,9 +531,8 @@ public class StaticFlowEntries { ...@@ -388,9 +531,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_set_src_mac(String subaction, Logger log) { private static SubActionStruct decode_set_src_mac(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
if (n.matches()) { if (n.matches()) {
byte[] macaddr = get_mac_addr(n, subaction, log); byte[] macaddr = get_mac_addr(n, subaction, log);
if (macaddr != null) { if (macaddr != null) {
...@@ -413,9 +555,8 @@ public class StaticFlowEntries { ...@@ -413,9 +555,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) { private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
if (n.matches()) { if (n.matches()) {
byte[] macaddr = get_mac_addr(n, subaction, log); byte[] macaddr = get_mac_addr(n, subaction, log);
if (macaddr != null) { if (macaddr != null) {
...@@ -438,9 +579,8 @@ public class StaticFlowEntries { ...@@ -438,9 +579,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) { private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction);
n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction);
if (n.matches()) { if (n.matches()) {
if (n.group(1) != null) { if (n.group(1) != null) {
try { try {
...@@ -469,9 +609,8 @@ public class StaticFlowEntries { ...@@ -469,9 +609,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_set_src_ip(String subaction, Logger log) { private static SubActionStruct decode_set_src_ip(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
if (n.matches()) { if (n.matches()) {
int ipaddr = get_ip_addr(n, subaction, log); int ipaddr = get_ip_addr(n, subaction, log);
OFActionNetworkLayerSource action = new OFActionNetworkLayerSource(); OFActionNetworkLayerSource action = new OFActionNetworkLayerSource();
...@@ -492,9 +631,8 @@ public class StaticFlowEntries { ...@@ -492,9 +631,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) { private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
if (n.matches()) { if (n.matches()) {
int ipaddr = get_ip_addr(n, subaction, log); int ipaddr = get_ip_addr(n, subaction, log);
OFActionNetworkLayerDestination action = new OFActionNetworkLayerDestination(); OFActionNetworkLayerDestination action = new OFActionNetworkLayerDestination();
...@@ -515,9 +653,8 @@ public class StaticFlowEntries { ...@@ -515,9 +653,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_set_src_port(String subaction, Logger log) { private static SubActionStruct decode_set_src_port(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction);
n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction);
if (n.matches()) { if (n.matches()) {
if (n.group(1) != null) { if (n.group(1) != null) {
try { try {
...@@ -546,9 +683,8 @@ public class StaticFlowEntries { ...@@ -546,9 +683,8 @@ public class StaticFlowEntries {
private static SubActionStruct decode_set_dst_port(String subaction, Logger log) { private static SubActionStruct decode_set_dst_port(String subaction, Logger log) {
SubActionStruct sa = null; SubActionStruct sa = null;
Matcher n; Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction);
n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction);
if (n.matches()) { if (n.matches()) {
if (n.group(1) != null) { if (n.group(1) != null) {
try { try {
...@@ -621,20 +757,17 @@ public class StaticFlowEntries { ...@@ -621,20 +757,17 @@ public class StaticFlowEntries {
} }
// Parse int as decimal, hex (start with 0x or #) or octal (starts with 0) // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
private static int get_int(String str) private static int get_int(String str) {
{
return (int)Integer.decode(str); return (int)Integer.decode(str);
} }
// Parse short as decimal, hex (start with 0x or #) or octal (starts with 0) // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
private static short get_short(String str) private static short get_short(String str) {
{
return (short)(int)Integer.decode(str); return (short)(int)Integer.decode(str);
} }
// Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0) // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
private static byte get_byte(String str) private static byte get_byte(String str) {
{
return Integer.decode(str).byteValue(); return Integer.decode(str).byteValue();
} }
......
...@@ -23,6 +23,7 @@ import net.floodlightcontroller.core.module.IFloodlightService; ...@@ -23,6 +23,7 @@ import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.core.util.AppCookie; import net.floodlightcontroller.core.util.AppCookie;
import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.restserver.IRestApiService;
import net.floodlightcontroller.staticflowentry.web.StaticFlowEntryWebRoutable; import net.floodlightcontroller.staticflowentry.web.StaticFlowEntryWebRoutable;
import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
import net.floodlightcontroller.storage.IResultSet; import net.floodlightcontroller.storage.IResultSet;
import net.floodlightcontroller.storage.IStorageSourceService; import net.floodlightcontroller.storage.IStorageSourceService;
import net.floodlightcontroller.storage.IStorageSourceListener; import net.floodlightcontroller.storage.IStorageSourceListener;
...@@ -32,7 +33,6 @@ import org.openflow.protocol.OFFlowMod; ...@@ -32,7 +33,6 @@ import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFFlowRemoved; import org.openflow.protocol.OFFlowRemoved;
import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFType; import org.openflow.protocol.OFType;
import org.openflow.protocol.factory.BasicFactory; import org.openflow.protocol.factory.BasicFactory;
import org.openflow.util.HexString; import org.openflow.util.HexString;
...@@ -41,7 +41,7 @@ import org.slf4j.Logger; ...@@ -41,7 +41,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class StaticFlowEntryPusher public class StaticFlowEntryPusher
implements IOFSwitchListener, IFloodlightModule, implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
IStorageSourceListener, IOFMessageListener { IStorageSourceListener, IOFMessageListener {
protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusher.class); protected static Logger log = LoggerFactory.getLogger(StaticFlowEntryPusher.class);
public static final String StaticFlowName = "staticflowentry"; public static final String StaticFlowName = "staticflowentry";
...@@ -84,8 +84,9 @@ public class StaticFlowEntryPusher ...@@ -84,8 +84,9 @@ public class StaticFlowEntryPusher
protected IStorageSourceService storageSource; protected IStorageSourceService storageSource;
protected IRestApiService restApi; protected IRestApiService restApi;
// entriesFromStorage[$dpid]->[$entryName = FlowMod] ; FlowMod can be null to indicate non-active // Map<DPID, Map<Name, FlowMod>> ; FlowMod can be null to indicate non-active
protected HashMap<String, Map<String, OFFlowMod>> entriesFromStorage; protected HashMap<String, Map<String, OFFlowMod>> entriesFromStorage;
// Entry Name -> DPID of Switch it's on
protected Map<String, String> entry2dpid; protected Map<String, String> entry2dpid;
private BasicFactory ofMessageFactory; private BasicFactory ofMessageFactory;
...@@ -110,7 +111,6 @@ public class StaticFlowEntryPusher ...@@ -110,7 +111,6 @@ public class StaticFlowEntryPusher
* used for debugging and unittests * used for debugging and unittests
* @return the number of static flow entries as cached from storage * @return the number of static flow entries as cached from storage
*/ */
public int countEntries() { public int countEntries() {
int size = 0; int size = 0;
if (entriesFromStorage == null) if (entriesFromStorage == null)
...@@ -132,17 +132,6 @@ public class StaticFlowEntryPusher ...@@ -132,17 +132,6 @@ public class StaticFlowEntryPusher
this.storageSource = storageSource; this.storageSource = storageSource;
} }
protected void initDefaultFlowMod(OFFlowMod fm, String entryName) {
fm.setIdleTimeout((short) 0); // infinite
fm.setHardTimeout((short) 0); // infinite
fm.setBufferId(-1);
fm.setCommand((short) 0);
fm.setFlags((short) 0);
fm.setOutPort(OFPort.OFPP_NONE.getValue());
fm.setCookie(computeEntryCookie(fm, 0, entryName));
fm.setPriority(Short.MAX_VALUE);
}
/** /**
* Reads from our entriesFromStorage for the specified switch and * Reads from our entriesFromStorage for the specified switch and
* sends the FlowMods down to the controller in <b>sorted</b> order. * sends the FlowMods down to the controller in <b>sorted</b> order.
...@@ -156,9 +145,8 @@ public class StaticFlowEntryPusher ...@@ -156,9 +145,8 @@ public class StaticFlowEntryPusher
* TODO consider adding a "block all" flow mod and then removing it * TODO consider adding a "block all" flow mod and then removing it
* while starting up. * while starting up.
* *
* @param sw * @param sw The switch to send entries to
*/ */
protected void sendEntriesToSwitch(IOFSwitch sw) { protected void sendEntriesToSwitch(IOFSwitch sw) {
String dpid = sw.getStringId(); String dpid = sw.getStringId();
...@@ -169,16 +157,11 @@ public class StaticFlowEntryPusher ...@@ -169,16 +157,11 @@ public class StaticFlowEntryPusher
Collections.sort( sortedList, new FlowModSorter(dpid)); Collections.sort( sortedList, new FlowModSorter(dpid));
for (String entryName : sortedList) { for (String entryName : sortedList) {
OFFlowMod flowMod = entries.get(entryName); OFFlowMod flowMod = entries.get(entryName);
try { if (flowMod != null) {
if ( flowMod != null) { if (log.isDebugEnabled()) {
log.debug(" push static entry {} for {}", dpid, entryName); log.debug("Pushing static entry {} for {}", dpid, entryName);
sw.write(flowMod, null);
sw.flush();
// Srini: FlowMod Sent to Switches
} }
} catch (IOException e) { writeFlowModToSwitch(sw, flowMod);
log.error("Failed to push static flow entry for {}: {}",
dpid, e.getMessage());
} }
} }
} }
...@@ -261,7 +244,7 @@ public class StaticFlowEntryPusher ...@@ -261,7 +244,7 @@ public class StaticFlowEntryPusher
entryName = (String) row.get(COLUMN_NAME); entryName = (String) row.get(COLUMN_NAME);
if (!entries.containsKey(switchName)) if (!entries.containsKey(switchName))
entries.put(switchName, new HashMap<String, OFFlowMod>()); entries.put(switchName, new HashMap<String, OFFlowMod>());
initDefaultFlowMod(flowMod, entryName); StaticFlowEntries.initDefaultFlowMod(flowMod, entryName);
for (String key : row.keySet()) { for (String key : row.keySet()) {
if (row.get(key) == null) if (row.get(key) == null)
...@@ -281,12 +264,11 @@ public class StaticFlowEntryPusher ...@@ -281,12 +264,11 @@ public class StaticFlowEntryPusher
return; return;
} }
} else if ( key.equals(COLUMN_ACTIONS)){ } else if ( key.equals(COLUMN_ACTIONS)){
StaticFlowEntries.parseActionString(entryName, switchName, flowMod, StaticFlowEntries.parseActionString(flowMod, (String) row.get(COLUMN_ACTIONS), log);
(String) row.get(COLUMN_ACTIONS), log);
} else if ( key.equals(COLUMN_COOKIE)) { } else if ( key.equals(COLUMN_COOKIE)) {
flowMod.setCookie( flowMod.setCookie(
computeEntryCookie(flowMod, StaticFlowEntries.computeEntryCookie(flowMod,
Integer.valueOf( (String) row.get(COLUMN_COOKIE)), Integer.valueOf((String) row.get(COLUMN_COOKIE)),
entryName) entryName)
); );
} else if ( key.equals(COLUMN_PRIORITY)) { } else if ( key.equals(COLUMN_PRIORITY)) {
...@@ -322,28 +304,6 @@ public class StaticFlowEntryPusher ...@@ -322,28 +304,6 @@ public class StaticFlowEntryPusher
entries.get(switchName).put(entryName, flowMod); entries.get(switchName).put(entryName, flowMod);
} }
/**
* This function generates a random hash for the bottom half of the cookie
*
* FIXME Decide if we really want this... it's actually very likely that this was
* a misunderstanding that cookies needed to be unique, which they definitely don't.
*
* @param fm
* @param userCookie
* @param name
* @return A cookie that encodes the Application ID and a hash
*/
public static long computeEntryCookie(OFFlowMod fm, int userCookie, String name) {
// flow-specific hash is next 20 bits LOOK! who knows if this
int prime = 211;
int flowHash = 2311;
for (int i=0; i < name.length(); i++)
flowHash = flowHash * prime + (int)name.charAt(i);
return AppCookie.makeCookie(STATIC_FLOW_APP_ID, flowHash);
}
@Override @Override
public void addedSwitch(IOFSwitch sw) { public void addedSwitch(IOFSwitch sw) {
log.debug("addedSwitch {}; processing its static entries", sw); log.debug("addedSwitch {}; processing its static entries", sw);
...@@ -380,14 +340,14 @@ public class StaticFlowEntryPusher ...@@ -380,14 +340,14 @@ public class StaticFlowEntryPusher
if (!entriesFromStorage.containsKey(dpid)) if (!entriesFromStorage.containsKey(dpid))
entriesFromStorage.put(dpid, new HashMap<String, OFFlowMod>()); entriesFromStorage.put(dpid, new HashMap<String, OFFlowMod>());
List<OFMessage> outQueue = new ArrayList<OFMessage>(); List<OFMessage> outQueue = new ArrayList<OFMessage>();
for(String entry: entriesToAdd.get(dpid).keySet()) { for(String entry : entriesToAdd.get(dpid).keySet()) {
OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry); OFFlowMod newFlowMod = entriesToAdd.get(dpid).get(entry);
OFFlowMod oldFlowMod = entriesFromStorage.get(dpid).get(entry); OFFlowMod oldFlowMod = entriesFromStorage.get(dpid).get(entry);
if (oldFlowMod != null) { // remove any pre-existing rule if (oldFlowMod != null) { // remove any pre-existing rule
oldFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); oldFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
outQueue.add(oldFlowMod); outQueue.add(oldFlowMod);
} }
if ( newFlowMod != null) { if (newFlowMod != null) {
entriesFromStorage.get(dpid).put(entry, newFlowMod); entriesFromStorage.get(dpid).put(entry, newFlowMod);
outQueue.add(newFlowMod); outQueue.add(newFlowMod);
entry2dpid.put(entry, dpid); entry2dpid.put(entry, dpid);
...@@ -396,19 +356,8 @@ public class StaticFlowEntryPusher ...@@ -396,19 +356,8 @@ public class StaticFlowEntryPusher
entry2dpid.remove(entry); entry2dpid.remove(entry);
} }
} }
IOFSwitch ofswitch = floodlightProvider.getSwitches().get(HexString.toLong(dpid));
if (ofswitch != null) { // is the switch connected writeOFMessagesToSwitch(HexString.toLong(dpid), outQueue);
try {
if (log.isDebugEnabled()) {
log.debug("Sending {} new entries to {}", outQueue.size(), dpid);
}
ofswitch.write(outQueue, null);
ofswitch.flush();
} catch (IOException e) {
log.error("writed to write to switch {} but got {}",
dpid, e.getMessage());
}
}
} }
} }
...@@ -423,40 +372,91 @@ public class StaticFlowEntryPusher ...@@ -423,40 +372,91 @@ public class StaticFlowEntryPusher
log.error("tried to delete non-string key {}; ignoring", obj); log.error("tried to delete non-string key {}; ignoring", obj);
continue; continue;
} }
String entryName = (String) obj; deleteStaticFlowEntry((String) obj);
String dpid = entry2dpid.get(entryName); }
if (dpid == null) { }
log.error("inconsistent internal state: no switch has rule {}",
entryName); private boolean deleteStaticFlowEntry(String entryName) {
continue; String dpid = entry2dpid.get(entryName);
} if (log.isDebugEnabled()) {
// send flow_mod delete log.debug("Deleting flow {} for switch {}", entryName, dpid);
OFFlowMod flowMod = entriesFromStorage.get(dpid).get(entryName); }
flowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT); if (dpid == null) {
log.debug("deleting flow {} for switch {}", entryName, dpid); log.error("inconsistent internal state: no switch has rule {}",
Map<Long,IOFSwitch> switches = floodlightProvider.getSwitches(); entryName);
return false;
if ( entriesFromStorage.containsKey(dpid) && }
entriesFromStorage.get(dpid).containsKey(entryName))
entriesFromStorage.get(dpid).remove(entryName); // send flow_mod delete
else OFFlowMod flowMod = entriesFromStorage.get(dpid).get(entryName);
log.error("tried to delete non-existent entry {} for switch {}", flowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT);
entryName, dpid);
if (entriesFromStorage.containsKey(dpid) &&
IOFSwitch ofSwitch = switches.get(HexString.toLong(dpid)); entriesFromStorage.get(dpid).containsKey(entryName)) {
if ( ofSwitch == null) { entriesFromStorage.get(dpid).remove(entryName);
log.debug("Not deleting key {} :: switch {} not connected", dpid); } else {
continue; log.error("Tried to delete non-existent entry {} for switch {}",
} entryName, dpid);
return false;
}
writeFlowModToSwitch(HexString.toLong(dpid), flowMod);
return true;
}
/**
* Writes a list of OFMessages to a switch
* @param dpid The datapath ID of the switch to write to
* @param messages The list of OFMessages to write.
*/
private void writeOFMessagesToSwitch(long dpid, List<OFMessage> messages) {
IOFSwitch ofswitch = floodlightProvider.getSwitches().get(dpid);
if (ofswitch != null) { // is the switch connected
try { try {
ofSwitch.write(flowMod, null); if (log.isDebugEnabled()) {
ofSwitch.flush(); log.debug("Sending {} new entries to {}", messages.size(), dpid);
}
ofswitch.write(messages, null);
ofswitch.flush();
} catch (IOException e) { } catch (IOException e) {
log.error("tried to write flow_mod delete to {} but failed: {}", log.error("writed to write to switch {} but got {}", dpid, e.getMessage());
dpid, e.getMessage());
} }
} }
} }
/**
* Writes an OFFlowMod to a switch. It checks to make sure the switch
* exists before it sends
* @param dpid The data to write the flow mod to
* @param flowMod The OFFlowMod to write
*/
private void writeFlowModToSwitch(long dpid, OFFlowMod flowMod) {
Map<Long,IOFSwitch> switches = floodlightProvider.getSwitches();
IOFSwitch ofSwitch = switches.get(dpid);
if (ofSwitch == null) {
if (log.isDebugEnabled()) {
log.debug("Not deleting key {} :: switch {} not connected",
dpid);
}
return;
}
writeFlowModToSwitch(ofSwitch, flowMod);
}
/**
* Writes an OFFlowMod to a switch
* @param sw The IOFSwitch to write to
* @param flowMod The OFFlowMod to write
*/
private void writeFlowModToSwitch(IOFSwitch sw, OFFlowMod flowMod) {
try {
sw.write(flowMod, null);
sw.flush();
} catch (IOException e) {
log.error("Tried to write OFFlowMod to {} but failed: {}",
HexString.toHexString(sw.getId()), e.getMessage());
}
}
@Override @Override
public String getName() { public String getName() {
...@@ -479,7 +479,7 @@ public class StaticFlowEntryPusher ...@@ -479,7 +479,7 @@ public class StaticFlowEntryPusher
* never expire. * never expire.
*/ */
if( AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) { if( AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) {
if ( flowRemoved.getReason() != OFFlowRemoved.OFFlowRemovedReason.OFPRR_DELETE) if (flowRemoved.getReason() != OFFlowRemoved.OFFlowRemovedReason.OFPRR_DELETE)
log.error("PANIC -- got a FlowRemove message for a infinite timeout flow: {} from switch {}", log.error("PANIC -- got a FlowRemove message for a infinite timeout flow: {} from switch {}",
msg, sw); msg, sw);
return Command.STOP; // only for us return Command.STOP; // only for us
...@@ -489,19 +489,11 @@ public class StaticFlowEntryPusher ...@@ -489,19 +489,11 @@ public class StaticFlowEntryPusher
@Override @Override
public boolean isCallbackOrderingPrereq(OFType type, String name) { public boolean isCallbackOrderingPrereq(OFType type, String name) {
// packet in listener goes after topology
if (type == OFType.PACKET_IN && "topology".equals(name)) {
return true;
}
return false; // no dependency for non-packet in return false; // no dependency for non-packet in
} }
@Override @Override
public boolean isCallbackOrderingPostreq(OFType type, String name) { public boolean isCallbackOrderingPostreq(OFType type, String name) {
// packet in listener goes before devicemanager
if (type == OFType.PACKET_IN && "devicemanager".equals(name)) {
return true;
}
return false; // no dependency for non-packet in return false; // no dependency for non-packet in
} }
...@@ -509,14 +501,20 @@ public class StaticFlowEntryPusher ...@@ -509,14 +501,20 @@ public class StaticFlowEntryPusher
@Override @Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() { public Collection<Class<? extends IFloodlightService>> getModuleServices() {
// We don't have any services Collection<Class<? extends IFloodlightService>> l =
return null; new ArrayList<Class<? extends IFloodlightService>>();
l.add(IStaticFlowEntryPusherService.class);
return l;
} }
@Override @Override
public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
// We don't have any services Map<Class<? extends IFloodlightService>,
return null; IFloodlightService> m =
new HashMap<Class<? extends IFloodlightService>,
IFloodlightService>();
m.put(IStaticFlowEntryPusherService.class, this);
return m;
} }
@Override @Override
...@@ -553,4 +551,32 @@ public class StaticFlowEntryPusher ...@@ -553,4 +551,32 @@ public class StaticFlowEntryPusher
entry2dpid = computeEntry2DpidMap(entriesFromStorage); entry2dpid = computeEntry2DpidMap(entriesFromStorage);
restApi.addRestletRoutable(new StaticFlowEntryWebRoutable()); restApi.addRestletRoutable(new StaticFlowEntryWebRoutable());
} }
// IStaticFlowEntryPusherService methods
@Override
public void addFlow(String name, OFFlowMod fm, String swDpid) {
Map<String, Object> fmMap = StaticFlowEntries.flowModToStorageEntry(fm, swDpid, name);
entry2dpid.put(name, swDpid);
Map<String, OFFlowMod> switchEntries = entriesFromStorage.get(swDpid);
if (switchEntries == null) {
switchEntries = new HashMap<String, OFFlowMod>();
entriesFromStorage.put(swDpid, switchEntries);
}
switchEntries.put(name, fm);
storageSource.insertRowAsync(TABLE_NAME, fmMap);
}
@Override
public void deleteFlow(String name) {
storageSource.deleteRowAsync(TABLE_NAME, name);
// TODO - What if there is a delay in storage?
}
@Override
public void deleteAllFlows() {
for (String entry : entry2dpid.keySet()) {
deleteFlow(entry);
}
}
} }
package net.floodlightcontroller.staticflowentry.web;
import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ClearStaticFlowEntriesResource extends ServerResource {
protected static Logger log = LoggerFactory.getLogger(ClearStaticFlowEntriesResource.class);
@Get
public void IStaticFlowEntryPusherService() {
IStaticFlowEntryPusherService sfpService =
(IStaticFlowEntryPusherService)getContext().getAttributes().
get(IStaticFlowEntryPusherService.class.getCanonicalName());
log.debug("Clearing all static flow entires");
sfpService.deleteAllFlows();
}
}
...@@ -14,6 +14,7 @@ public class StaticFlowEntryWebRoutable implements RestletRoutable { ...@@ -14,6 +14,7 @@ public class StaticFlowEntryWebRoutable implements RestletRoutable {
public Restlet getRestlet(Context context) { public Restlet getRestlet(Context context) {
Router router = new Router(context); Router router = new Router(context);
router.attach("/json", StaticFlowEntryPusherResource.class); router.attach("/json", StaticFlowEntryPusherResource.class);
router.attach("/clear/json", ClearStaticFlowEntriesResource.class);
return router; return router;
} }
......
...@@ -36,7 +36,7 @@ public enum OFActionType { ...@@ -36,7 +36,7 @@ public enum OFActionType {
public OFAction instantiate() { public OFAction instantiate() {
return new OFActionOutput(); return new OFActionOutput();
}}), }}),
SET_VLAN_VID (1, OFActionVirtualLanIdentifier.class, new Instantiable<OFAction>() { SET_VLAN_ID (1, OFActionVirtualLanIdentifier.class, new Instantiable<OFAction>() {
@Override @Override
public OFAction instantiate() { public OFAction instantiate() {
return new OFActionVirtualLanIdentifier(); return new OFActionVirtualLanIdentifier();
......
...@@ -33,7 +33,7 @@ public class OFActionVirtualLanIdentifier extends OFAction { ...@@ -33,7 +33,7 @@ public class OFActionVirtualLanIdentifier extends OFAction {
protected short virtualLanIdentifier; protected short virtualLanIdentifier;
public OFActionVirtualLanIdentifier() { public OFActionVirtualLanIdentifier() {
super.setType(OFActionType.SET_VLAN_VID); super.setType(OFActionType.SET_VLAN_ID);
super.setLength((short) MINIMUM_LENGTH); super.setLength((short) MINIMUM_LENGTH);
} }
......
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