blob: 69078038b73c70368c3fcf258df4a8a5c65fe0cd [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08006import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.HashMap;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07008import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +00009import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000012import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070013import java.util.TreeMap;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080014import java.util.concurrent.Executors;
15import java.util.concurrent.ScheduledExecutorService;
16import java.util.concurrent.ScheduledFuture;
17import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080018
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import net.floodlightcontroller.core.IFloodlightProviderService;
20import net.floodlightcontroller.core.INetMapStorage;
21import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
22import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070023import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070024import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070025import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080026import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080027import net.floodlightcontroller.core.module.FloodlightModuleContext;
28import net.floodlightcontroller.core.module.FloodlightModuleException;
29import net.floodlightcontroller.core.module.IFloodlightModule;
30import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080031import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
32import net.floodlightcontroller.restserver.IRestApiService;
33import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080034import net.floodlightcontroller.util.DataPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080035import net.floodlightcontroller.util.DataPathEndpoints;
Jonathan Hart01f2d272013-04-04 20:03:46 -070036import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080037import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070038import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070040import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntrySwitchState;
42import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080043import net.floodlightcontroller.util.FlowId;
44import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070045import net.floodlightcontroller.util.IPv4Net;
46import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080047import net.floodlightcontroller.util.OFMessageDamper;
48import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070049import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070050import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080051import net.onrc.onos.util.GraphDBConnection;
52import net.onrc.onos.util.GraphDBConnection.Transaction;
53
54import org.openflow.protocol.OFFlowMod;
55import org.openflow.protocol.OFMatch;
56import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070057import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080058import org.openflow.protocol.OFType;
59import org.openflow.protocol.action.OFAction;
60import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080061import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070064public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080065
66 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080067
68 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080069 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070070 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070071 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072
73 protected OFMessageDamper messageDamper;
74
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070075 //
76 // TODO: Values copied from elsewhere (class LearningSwitch).
77 // The local copy should go away!
78 //
79 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
80 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
81 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
82 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
83 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080084
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000085 // Flow Entry ID generation state
86 private static Random randomGenerator = new Random();
87 private static int nextFlowEntryIdPrefix = 0;
88 private static int nextFlowEntryIdSuffix = 0;
89 private static long nextFlowEntryId = 0;
90
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070091 private static long measurementFlowId = 100000;
92 private static String measurementFlowIdStr = "0x186a0"; // 100000
93 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070094
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080095 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080096 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
97
98 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070099 private final ScheduledExecutorService mapReaderScheduler =
100 Executors.newScheduledThreadPool(1);
101
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700102 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800103 public void run() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700104 long startTime = System.nanoTime();
105 int counterAllFlowEntries = 0;
106 int counterMyNotUpdatedFlowEntries = 0;
107 int counterAllFlowPaths = 0;
108 int counterMyFlowPaths = 0;
109
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800110 if (floodlightProvider == null) {
111 log.debug("FloodlightProvider service not found!");
112 return;
113 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000114 Map<Long, IOFSwitch> mySwitches =
115 floodlightProvider.getSwitches();
116 Map<Long, IFlowEntry> myFlowEntries =
117 new TreeMap<Long, IFlowEntry>();
118 LinkedList<IFlowEntry> deleteFlowEntries =
119 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700120
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700121
122 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700123 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700124 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700125 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000126 Iterable<IFlowEntry> allFlowEntries =
127 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700128 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700129 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700131 String userState = flowEntryObj.getUserState();
132 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000133 String dpidStr = flowEntryObj.getSwitchDpid();
134 if ((flowEntryIdStr == null) ||
135 (userState == null) ||
136 (switchState == null) ||
137 (dpidStr == null)) {
138 log.debug("IGNORING Flow Entry entry with null fields");
139 continue;
140 }
141 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
142 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800143
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000144 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
145 continue; // Ignore the entry: nothing to do
146
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800147 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000148 if (mySwitch == null)
149 continue; // Ignore the entry: not my switch
150
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700151 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
152 }
153
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700154 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
155 myFlowEntries.size());
156
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700157 //
158 // Process my Flow Entries
159 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700160 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700161 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700162 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700163 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700164 IFlowPath flowObj =
165 conn.utils().getFlowPathByFlowEntry(conn,
166 flowEntryObj);
167 if (flowObj == null)
168 continue; // Should NOT happen
169
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700170 // Code for measurement purpose
171 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700172 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700173 processed_measurement_flow = true;
174 }
175 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700176
177 //
178 // TODO: Eliminate the re-fetching of flowEntryId,
179 // userState, switchState, and dpid from the flowEntryObj.
180 //
181 FlowEntryId flowEntryId =
182 new FlowEntryId(flowEntryObj.getFlowEntryId());
183 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
184 String userState = flowEntryObj.getUserState();
185 String switchState = flowEntryObj.getSwitchState();
186 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000187 if (mySwitch == null)
188 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800189
190 //
191 // Create the Open Flow Flow Modification Entry to push
192 //
193 OFFlowMod fm =
194 (OFFlowMod) floodlightProvider.getOFMessageFactory()
195 .getMessage(OFType.FLOW_MOD);
196 long cookie = flowEntryId.value();
197
198 short flowModCommand = OFFlowMod.OFPFC_ADD;
199 if (userState.equals("FE_USER_ADD")) {
200 flowModCommand = OFFlowMod.OFPFC_ADD;
201 } else if (userState.equals("FE_USER_MODIFY")) {
202 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
203 } else if (userState.equals("FE_USER_DELETE")) {
204 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
205 } else {
206 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700207 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
208 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800209 continue;
210 }
211
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700212 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700213 // Fetch the match conditions.
214 //
215 // NOTE: The Flow matching conditions common for all
216 // Flow Entries are used ONLY if a Flow Entry does NOT
217 // have the corresponding matching condition set.
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700218 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800219 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700220 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700221 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700222 Short matchInPort = flowEntryObj.getMatchInPort();
223 if (matchInPort != null) {
224 match.setInputPort(matchInPort);
225 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
226 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700227 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700228 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700229 if (matchEthernetFrameType == null)
230 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700231 if (matchEthernetFrameType != null) {
232 match.setDataLayerType(matchEthernetFrameType);
233 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
234 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700235 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700236 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700237 if (matchSrcIPv4Net == null)
238 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700239 if (matchSrcIPv4Net != null) {
240 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
241 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700242 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700243 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700244 if (matchDstIPv4Net == null)
245 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700246 if (matchDstIPv4Net != null) {
247 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
248 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700249 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700250 String matchSrcMac = flowEntryObj.getMatchSrcMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700251 if (matchSrcMac == null)
252 matchSrcMac = flowObj.getMatchSrcMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700253 if (matchSrcMac != null) {
254 match.setDataLayerSource(matchSrcMac);
255 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
256 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700257 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700258 String matchDstMac = flowEntryObj.getMatchDstMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700259 if (matchDstMac == null)
260 matchDstMac = flowObj.getMatchDstMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700261 if (matchDstMac != null) {
262 match.setDataLayerDestination(matchDstMac);
263 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
264 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700265
266 //
267 // Fetch the actions
268 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800269 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700270 Short actionOutputPort = flowEntryObj.getActionOutput();
271 if (actionOutputPort != null) {
272 OFActionOutput action = new OFActionOutput();
273 // XXX: The max length is hard-coded for now
274 action.setMaxLength((short)0xffff);
275 action.setPort(actionOutputPort);
276 actions.add(action);
277 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800278
279 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
280 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700281 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800282 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
283 .setCookie(cookie)
284 .setCommand(flowModCommand)
285 .setMatch(match)
286 .setActions(actions)
287 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700288 fm.setOutPort(OFPort.OFPP_NONE.getValue());
289 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
290 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
291 if (actionOutputPort != null)
292 fm.setOutPort(actionOutputPort);
293 }
294
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800295 //
296 // TODO: Set the following flag
297 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
298 // See method ForwardingBase::pushRoute()
299 //
300 try {
301 messageDamper.write(mySwitch, fm, null);
302 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000303 //
304 // TODO: We should use the OpenFlow Barrier mechanism
305 // to check for errors, and update the SwitchState
306 // for a flow entry after the Barrier message is
307 // is received.
308 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800309 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
310 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000311 // An entry that needs to be deleted.
312 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800313 }
314 } catch (IOException e) {
315 log.error("Failure writing flow mod from network map", e);
316 }
317 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000318
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700319 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
320 deleteFlowEntries.size());
321
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000322 //
323 // Delete all entries marked for deletion
324 //
325 // TODO: We should use the OpenFlow Barrier mechanism
326 // to check for errors, and delete the Flow Entries after the
327 // Barrier message is received.
328 //
329 while (! deleteFlowEntries.isEmpty()) {
330 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
331 IFlowPath flowObj =
332 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
333 if (flowObj == null) {
334 log.debug("Did not find FlowPath to be deleted");
335 continue;
336 }
337 flowObj.removeFlowEntry(flowEntryObj);
338 conn.utils().removeFlowEntry(conn, flowEntryObj);
339
340 // Test whether the last flow entry
341 Iterable<IFlowEntry> tmpflowEntries =
342 flowObj.getFlowEntries();
343 boolean found = false;
344 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
345 found = true;
346 break;
347 }
348 if (! found) {
349 // Remove the Flow Path as well
350 conn.utils().removeFlowPath(conn, flowObj);
351 }
352 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700353
354
355 //
356 // Fetch and recompute the Shortest Path for those
357 // Flow Paths this controller is responsible for.
358 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700359 topoRouteService.prepareShortestPathTopo();
360 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
361 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
362 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700363 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700364 if (flowPathObj == null)
365 continue;
366 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
367 if (dataPathSummaryStr == null)
368 continue; // Could be invalid entry?
369 if (dataPathSummaryStr.isEmpty())
370 continue; // No need to maintain this flow
371
372 // Fetch the fields needed to recompute the shortest path
373 String flowIdStr = flowPathObj.getFlowId();
374 String srcDpidStr = flowPathObj.getSrcSwitch();
375 Short srcPortShort = flowPathObj.getSrcPort();
376 String dstDpidStr = flowPathObj.getDstSwitch();
377 Short dstPortShort = flowPathObj.getDstPort();
378 if ((flowIdStr == null) ||
379 (srcDpidStr == null) ||
380 (srcPortShort == null) ||
381 (dstDpidStr == null) ||
382 (dstPortShort == null)) {
383 log.debug("IGNORING Flow Path entry with null fields");
384 continue;
385 }
386
387 FlowId flowId = new FlowId(flowIdStr);
388 Dpid srcDpid = new Dpid(srcDpidStr);
389 Port srcPort = new Port(srcPortShort);
390 Dpid dstDpid = new Dpid(dstDpidStr);
391 Port dstPort = new Port(dstPortShort);
392 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
393 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700394
395 //
396 // Use the source DPID as a heuristic to decide
397 // which controller is responsible for maintaining the
398 // shortest path.
399 // NOTE: This heuristic is error-prone: if the switch
400 // goes away and no controller is responsible for that
401 // switch, then the original Flow Path is not cleaned-up
402 //
403 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
404 if (mySwitch == null)
405 continue; // Ignore: not my responsibility
406
407 counterMyFlowPaths++;
408
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700409 //
410 // NOTE: Using here the regular getShortestPath() method
411 // won't work here, because that method calls internally
412 // "conn.endTx(Transaction.COMMIT)", and that will
413 // invalidate all handlers to the Titan database.
414 // If we want to experiment with calling here
415 // getShortestPath(), we need to refactor that code
416 // to avoid closing the transaction.
417 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700418 DataPath dataPath =
419 topoRouteService.getTopoShortestPath(srcSwitchPort,
420 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000421 if (dataPath == null) {
422 // We need the DataPath to compare the paths
423 dataPath = new DataPath();
424 dataPath.setSrcPort(srcSwitchPort);
425 dataPath.setDstPort(dstSwitchPort);
426 }
427
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700428 String newDataPathSummaryStr = dataPath.dataPathSummary();
429 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
430 continue; // Nothing changed
431
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700432 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
433 flowId.toString());
434 flowObjSet.add(flowPathObj);
435 }
Pavlin Radoslavov53a3a8c2013-04-04 04:34:50 -0700436 log.debug("MEASUREMENT: Found {} Flows to reconcile",
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700437 flowObjSet.size());
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700438 reconcileFlows(flowObjSet);
439 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700440
441
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800442 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700443
444 if (processed_measurement_flow) {
445 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
446 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
447 (double)estimatedTime / 1000000000 + " sec";
448 log.debug(logMsg);
449 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700450
451 long estimatedTime = System.nanoTime() - startTime;
452 double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
453 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
454 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800455 }
456 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700457
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700458 final ScheduledFuture<?> mapReaderHandle =
459 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800460
461 @Override
462 public void init(String conf) {
463 conn = GraphDBConnection.getInstance(conf);
464 }
465
466 public void finalize() {
467 close();
468 }
469
470 @Override
471 public void close() {
472 conn.close();
473 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800474
475 @Override
476 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
477 Collection<Class<? extends IFloodlightService>> l =
478 new ArrayList<Class<? extends IFloodlightService>>();
479 l.add(IFlowService.class);
480 return l;
481 }
482
483 @Override
484 public Map<Class<? extends IFloodlightService>, IFloodlightService>
485 getServiceImpls() {
486 Map<Class<? extends IFloodlightService>,
487 IFloodlightService> m =
488 new HashMap<Class<? extends IFloodlightService>,
489 IFloodlightService>();
490 m.put(IFlowService.class, this);
491 return m;
492 }
493
494 @Override
495 public Collection<Class<? extends IFloodlightService>>
496 getModuleDependencies() {
497 Collection<Class<? extends IFloodlightService>> l =
498 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800499 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700500 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800501 l.add(IRestApiService.class);
502 return l;
503 }
504
505 @Override
506 public void init(FloodlightModuleContext context)
507 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700508 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800509 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700510 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800511 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800512 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
513 EnumSet.of(OFType.FLOW_MOD),
514 OFMESSAGE_DAMPER_TIMEOUT);
515 // TODO: An ugly hack!
516 String conf = "/tmp/cassandra.titan";
517 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800518 }
519
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000520 private long getNextFlowEntryId() {
521 //
522 // Generate the next Flow Entry ID.
523 // NOTE: For now, the higher 32 bits are random, and
524 // the lower 32 bits are sequential.
525 // In the future, we need a better allocation mechanism.
526 //
527 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
528 nextFlowEntryIdPrefix = randomGenerator.nextInt();
529 nextFlowEntryIdSuffix = 0;
530 } else {
531 nextFlowEntryIdSuffix++;
532 }
533 long result = (long)nextFlowEntryIdPrefix << 32;
534 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
535 return result;
536 }
537
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800538 @Override
539 public void startUp(FloodlightModuleContext context) {
540 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700541
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000542 // Initialize the Flow Entry ID generator
543 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800544 }
545
546 /**
547 * Add a flow.
548 *
549 * Internally, ONOS will automatically register the installer for
550 * receiving Flow Path Notifications for that path.
551 *
552 * @param flowPath the Flow Path to install.
553 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700554 * @param dataPathSummaryStr the data path summary string if the added
555 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800556 * @return true on success, otherwise false.
557 */
558 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700559 public boolean addFlow(FlowPath flowPath, FlowId flowId,
560 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700561 if (flowPath.flowId().value() == measurementFlowId) {
562 modifiedMeasurementFlowTime = System.nanoTime();
563 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800564
565 //
566 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700567 // Right now every new flow entry gets a new flow entry ID
568 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800569 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800570 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000571 long id = getNextFlowEntryId();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800572 flowEntry.setFlowEntryId(new FlowEntryId(id));
573 }
574
575 IFlowPath flowObj = null;
576 try {
577 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
578 != null) {
579 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
580 flowPath.flowId().toString());
581 } else {
582 flowObj = conn.utils().newFlowPath(conn);
583 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
584 flowPath.flowId().toString());
585 }
586 } catch (Exception e) {
587 // TODO: handle exceptions
588 conn.endTx(Transaction.ROLLBACK);
589 log.error(":addFlow FlowId:{} failed",
590 flowPath.flowId().toString());
591 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700592 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000593 log.error(":addFlow FlowId:{} failed: Flow object not created",
594 flowPath.flowId().toString());
595 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800596 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700597 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800598
599 //
600 // Set the Flow key:
601 // - flowId
602 //
603 flowObj.setFlowId(flowPath.flowId().toString());
604 flowObj.setType("flow");
605
606 //
607 // Set the Flow attributes:
608 // - flowPath.installerId()
609 // - flowPath.dataPath().srcPort()
610 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700611 // - flowPath.matchEthernetFrameType()
612 // - flowPath.matchSrcIPv4Net()
613 // - flowPath.matchDstIPv4Net()
614 // - flowPath.matchSrcMac()
615 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800616 //
617 flowObj.setInstallerId(flowPath.installerId().toString());
618 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
619 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
620 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
621 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700622 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
623 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
624 }
625 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
626 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
627 }
628 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
629 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
630 }
631 if (flowPath.flowEntryMatch().matchSrcMac()) {
632 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
633 }
634 if (flowPath.flowEntryMatch().matchDstMac()) {
635 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
636 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800637
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700638 if (dataPathSummaryStr != null) {
639 flowObj.setDataPathSummary(dataPathSummaryStr);
640 } else {
641 flowObj.setDataPathSummary("");
642 }
643
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800644 // Flow edges:
645 // HeadFE
646
647
648 //
649 // Flow Entries:
650 // flowPath.dataPath().flowEntries()
651 //
652 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
653 IFlowEntry flowEntryObj = null;
654 boolean found = false;
655 try {
656 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
657 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
658 flowEntry.flowEntryId().toString());
659 found = true;
660 } else {
661 flowEntryObj = conn.utils().newFlowEntry(conn);
662 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
663 flowEntry.flowEntryId().toString());
664 }
665 } catch (Exception e) {
666 // TODO: handle exceptions
667 conn.endTx(Transaction.ROLLBACK);
668 log.error(":addFlow FlowEntryId:{} failed",
669 flowEntry.flowEntryId().toString());
670 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700671 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000672 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
673 flowEntry.flowEntryId().toString());
674 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800675 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700676 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800677
678 //
679 // Set the Flow Entry key:
680 // - flowEntry.flowEntryId()
681 //
682 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
683 flowEntryObj.setType("flow_entry");
684
685 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700686 // Set the Flow Entry Edges and attributes:
687 // - Switch edge
688 // - InPort edge
689 // - OutPort edge
690 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800691 // - flowEntry.flowEntryMatch()
692 // - flowEntry.flowEntryActions()
693 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800694 // - flowEntry.flowEntryUserState()
695 // - flowEntry.flowEntrySwitchState()
696 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700697 // - flowEntry.matchInPort()
698 // - flowEntry.matchEthernetFrameType()
699 // - flowEntry.matchSrcIPv4Net()
700 // - flowEntry.matchDstIPv4Net()
701 // - flowEntry.matchSrcMac()
702 // - flowEntry.matchDstMac()
703 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800704 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700705 ISwitchObject sw =
706 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800707 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700708 flowEntryObj.setSwitch(sw);
709 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700710 IPortObject inport =
711 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
712 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700713 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
714 flowEntryObj.setInPort(inport);
715 }
716 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
717 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
718 }
719 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
720 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
721 }
722 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
723 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
724 }
725 if (flowEntry.flowEntryMatch().matchSrcMac()) {
726 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
727 }
728 if (flowEntry.flowEntryMatch().matchDstMac()) {
729 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
730 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700731
732 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700733 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700734 IPortObject outport =
735 conn.utils().searchPort(conn,
736 flowEntry.dpid().toString(),
737 fa.actionOutput().port().value());
738 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
739 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700740 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700741 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800742 // TODO: Hacks with hard-coded state names!
743 if (found)
744 flowEntryObj.setUserState("FE_USER_MODIFY");
745 else
746 flowEntryObj.setUserState("FE_USER_ADD");
747 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
748 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700749 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800750 //
751
752 // Flow Entries edges:
753 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700754 // NextFE (TODO)
755 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800756 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700757 flowEntryObj.setFlow(flowObj);
758 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800759 }
760 conn.endTx(Transaction.COMMIT);
761
762 //
763 // TODO: We need a proper Flow ID allocation mechanism.
764 //
765 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700766
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800767 return true;
768 }
769
770 /**
771 * Delete a previously added flow.
772 *
773 * @param flowId the Flow ID of the flow to delete.
774 * @return true on success, otherwise false.
775 */
776 @Override
777 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700778 if (flowId.value() == measurementFlowId) {
779 modifiedMeasurementFlowTime = System.nanoTime();
780 }
781
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800782 IFlowPath flowObj = null;
783 //
784 // We just mark the entries for deletion,
785 // and let the switches remove each individual entry after
786 // it has been removed from the switches.
787 //
788 try {
789 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
790 != null) {
791 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
792 flowId.toString());
793 } else {
794 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
795 flowId.toString());
796 }
797 } catch (Exception e) {
798 // TODO: handle exceptions
799 conn.endTx(Transaction.ROLLBACK);
800 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
801 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700802 if (flowObj == null) {
803 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800804 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700805 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800806
807 //
808 // Find and mark for deletion all Flow Entries
809 //
810 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
811 boolean empty = true; // TODO: an ugly hack
812 for (IFlowEntry flowEntryObj : flowEntries) {
813 empty = false;
814 // flowObj.removeFlowEntry(flowEntryObj);
815 // conn.utils().removeFlowEntry(conn, flowEntryObj);
816 flowEntryObj.setUserState("FE_USER_DELETE");
817 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
818 }
819 // Remove from the database empty flows
820 if (empty)
821 conn.utils().removeFlowPath(conn, flowObj);
822 conn.endTx(Transaction.COMMIT);
823
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800824 return true;
825 }
826
827 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700828 * Clear the state for a previously added flow.
829 *
830 * @param flowId the Flow ID of the flow to clear.
831 * @return true on success, otherwise false.
832 */
833 @Override
834 public boolean clearFlow(FlowId flowId) {
835 IFlowPath flowObj = null;
836 try {
837 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
838 != null) {
839 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
840 flowId.toString());
841 } else {
842 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
843 flowId.toString());
844 }
845 } catch (Exception e) {
846 // TODO: handle exceptions
847 conn.endTx(Transaction.ROLLBACK);
848 log.error(":clearFlow FlowId:{} failed", flowId.toString());
849 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700850 if (flowObj == null) {
851 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700852 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700853 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700854
855 //
856 // Remove all Flow Entries
857 //
858 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
859 for (IFlowEntry flowEntryObj : flowEntries) {
860 flowObj.removeFlowEntry(flowEntryObj);
861 conn.utils().removeFlowEntry(conn, flowEntryObj);
862 }
863 // Remove the Flow itself
864 conn.utils().removeFlowPath(conn, flowObj);
865 conn.endTx(Transaction.COMMIT);
866
867 return true;
868 }
869
870 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800871 * Get a previously added flow.
872 *
873 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800874 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800875 */
876 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800877 public FlowPath getFlow(FlowId flowId) {
878 IFlowPath flowObj = null;
879 try {
880 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
881 != null) {
882 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
883 flowId.toString());
884 } else {
885 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
886 flowId.toString());
887 }
888 } catch (Exception e) {
889 // TODO: handle exceptions
890 conn.endTx(Transaction.ROLLBACK);
891 log.error(":getFlow FlowId:{} failed", flowId.toString());
892 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700893 if (flowObj == null) {
894 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800895 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700896 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800897
898 //
899 // Extract the Flow state
900 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800901 FlowPath flowPath = extractFlowPath(flowObj);
902 conn.endTx(Transaction.COMMIT);
903
904 return flowPath;
905 }
906
907 /**
908 * Get all previously added flows by a specific installer for a given
909 * data path endpoints.
910 *
911 * @param installerId the Caller ID of the installer of the flow to get.
912 * @param dataPathEndpoints the data path endpoints of the flow to get.
913 * @return the Flow Paths if found, otherwise null.
914 */
915 @Override
916 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
917 DataPathEndpoints dataPathEndpoints) {
918 //
919 // TODO: The implementation below is not optimal:
920 // We fetch all flows, and then return only the subset that match
921 // the query conditions.
922 // We should use the appropriate Titan/Gremlin query to filter-out
923 // the flows as appropriate.
924 //
925 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700926 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800927
928 if (allFlows == null) {
929 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700930 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800931 }
932
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800933 for (FlowPath flow : allFlows) {
934 //
935 // TODO: String-based comparison is sub-optimal.
936 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800937 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800938 //
939 if (! flow.installerId().toString().equals(installerId.toString()))
940 continue;
941 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
942 continue;
943 }
944 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
945 continue;
946 }
947 flowPaths.add(flow);
948 }
949
950 if (flowPaths.isEmpty()) {
951 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800952 } else {
953 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
954 }
955
956 return flowPaths;
957 }
958
959 /**
960 * Get all installed flows by all installers for given data path endpoints.
961 *
962 * @param dataPathEndpoints the data path endpoints of the flows to get.
963 * @return the Flow Paths if found, otherwise null.
964 */
965 @Override
966 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
967 //
968 // TODO: The implementation below is not optimal:
969 // We fetch all flows, and then return only the subset that match
970 // the query conditions.
971 // We should use the appropriate Titan/Gremlin query to filter-out
972 // the flows as appropriate.
973 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700974 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
975 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800976
977 if (allFlows == null) {
978 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700979 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800980 }
981
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800982 for (FlowPath flow : allFlows) {
983 //
984 // TODO: String-based comparison is sub-optimal.
985 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800986 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800987 //
988 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
989 continue;
990 }
991 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
992 continue;
993 }
994 flowPaths.add(flow);
995 }
996
997 if (flowPaths.isEmpty()) {
998 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800999 } else {
1000 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1001 }
1002
1003 return flowPaths;
1004 }
1005
1006 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001007 * Get summary of all installed flows by all installers in a given range
1008 *
1009 * @param flowId the data path endpoints of the flows to get.
1010 * @param maxFlows: the maximum number of flows to be returned
1011 * @return the Flow Paths if found, otherwise null.
1012 */
1013 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001014 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1015
1016
1017
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001018 //
1019 // TODO: The implementation below is not optimal:
1020 // We fetch all flows, and then return only the subset that match
1021 // the query conditions.
1022 // We should use the appropriate Titan/Gremlin query to filter-out
1023 // the flows as appropriate.
1024 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001025 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001026
Jonathan Hart01f2d272013-04-04 20:03:46 -07001027 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1028
1029 return flowPathsWithoutFlowEntries;
1030
1031 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001032 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001033
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001034 if (allFlows == null) {
1035 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001036 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001037 }
1038
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001039 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001040
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001041 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001042 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001043
1044 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001045 //if (flow.flowId().value() < flowId.value()) {
1046 // continue;
1047 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001048
1049 // Summarize by making null flow entry fields that are not relevant to report
1050 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1051 flowEntry.setFlowEntryActions(null);
1052 flowEntry.setFlowEntryMatch(null);
1053 }
1054
1055 flowPaths.add(flow);
1056 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1057 break;
1058 }
1059 }
1060
1061 if (flowPaths.isEmpty()) {
1062 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001063 } else {
1064 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1065 }
1066
1067 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001068 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001069 }
1070
1071 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001072 * Get all installed flows by all installers.
1073 *
1074 * @return the Flow Paths if found, otherwise null.
1075 */
1076 @Override
1077 public ArrayList<FlowPath> getAllFlows() {
1078 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001079 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001080
1081 try {
1082 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1083 log.debug("Get all FlowPaths: found FlowPaths");
1084 } else {
1085 log.debug("Get all FlowPaths: no FlowPaths found");
1086 }
1087 } catch (Exception e) {
1088 // TODO: handle exceptions
1089 conn.endTx(Transaction.ROLLBACK);
1090 log.error(":getAllFlowPaths failed");
1091 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001092 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1093 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001094 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001095 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001096
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001097 for (IFlowPath flowObj : flowPathsObj) {
1098 //
1099 // Extract the Flow state
1100 //
1101 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001102 if (flowPath != null)
1103 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001104 }
1105
1106 conn.endTx(Transaction.COMMIT);
1107
1108 return flowPaths;
1109 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001110
1111 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1112 Iterable<IFlowPath> flowPathsObj = null;
1113 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1114 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1115
1116 try {
1117 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1118 log.debug("Get all FlowPaths: found FlowPaths");
1119 } else {
1120 log.debug("Get all FlowPaths: no FlowPaths found");
1121 }
1122 } catch (Exception e) {
1123 // TODO: handle exceptions
1124 conn.endTx(Transaction.ROLLBACK);
1125 log.error(":getAllFlowPaths failed");
1126 }
1127 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1128 return new ArrayList<IFlowPath>(); // No Flows found
1129 }
1130
1131 for (IFlowPath flowObj : flowPathsObj){
1132 flowPathsObjArray.add(flowObj);
1133 }
1134 /*
1135 for (IFlowPath flowObj : flowPathsObj) {
1136 //
1137 // Extract the Flow state
1138 //
1139 FlowPath flowPath = extractFlowPath(flowObj);
1140 if (flowPath != null)
1141 flowPaths.add(flowPath);
1142 }
1143 */
1144
1145 //conn.endTx(Transaction.COMMIT);
1146
1147 return flowPathsObjArray;
1148 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001149
1150 /**
1151 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1152 *
1153 * @param flowObj the object to extract the Flow Path State from.
1154 * @return the extracted Flow Path State.
1155 */
1156 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001157 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001158
1159 //
1160 // Extract the Flow state
1161 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001162 String flowIdStr = flowObj.getFlowId();
1163 String installerIdStr = flowObj.getInstallerId();
1164 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001165 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001166 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001167 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001168
1169 if ((flowIdStr == null) ||
1170 (installerIdStr == null) ||
1171 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001172 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001173 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001174 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001175 // TODO: A work-around, becauuse of some bogus database objects
1176 return null;
1177 }
1178
1179 flowPath.setFlowId(new FlowId(flowIdStr));
1180 flowPath.setInstallerId(new CallerId(installerIdStr));
1181 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001182 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001183 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001184 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001185 //
1186 // Extract the match conditions common for all Flow Entries
1187 //
1188 {
1189 FlowEntryMatch match = new FlowEntryMatch();
1190 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1191 if (matchEthernetFrameType != null)
1192 match.enableEthernetFrameType(matchEthernetFrameType);
1193 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1194 if (matchSrcIPv4Net != null)
1195 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1196 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1197 if (matchDstIPv4Net != null)
1198 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1199 String matchSrcMac = flowObj.getMatchSrcMac();
1200 if (matchSrcMac != null)
1201 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1202 String matchDstMac = flowObj.getMatchDstMac();
1203 if (matchDstMac != null)
1204 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1205 flowPath.setFlowEntryMatch(match);
1206 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001207
1208 //
1209 // Extract all Flow Entries
1210 //
1211 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1212 for (IFlowEntry flowEntryObj : flowEntries) {
1213 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001214 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1215 String switchDpidStr = flowEntryObj.getSwitchDpid();
1216 String userState = flowEntryObj.getUserState();
1217 String switchState = flowEntryObj.getSwitchState();
1218
1219 if ((flowEntryIdStr == null) ||
1220 (switchDpidStr == null) ||
1221 (userState == null) ||
1222 (switchState == null)) {
1223 // TODO: A work-around, becauuse of some bogus database objects
1224 continue;
1225 }
1226 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1227 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001228
1229 //
1230 // Extract the match conditions
1231 //
1232 FlowEntryMatch match = new FlowEntryMatch();
1233 Short matchInPort = flowEntryObj.getMatchInPort();
1234 if (matchInPort != null)
1235 match.enableInPort(new Port(matchInPort));
1236 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1237 if (matchEthernetFrameType != null)
1238 match.enableEthernetFrameType(matchEthernetFrameType);
1239 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1240 if (matchSrcIPv4Net != null)
1241 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1242 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1243 if (matchDstIPv4Net != null)
1244 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1245 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1246 if (matchSrcMac != null)
1247 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1248 String matchDstMac = flowEntryObj.getMatchDstMac();
1249 if (matchDstMac != null)
1250 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1251 flowEntry.setFlowEntryMatch(match);
1252
1253 //
1254 // Extract the actions
1255 //
1256 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1257 Short actionOutputPort = flowEntryObj.getActionOutput();
1258 if (actionOutputPort != null) {
1259 FlowEntryAction action = new FlowEntryAction();
1260 action.setActionOutput(new Port(actionOutputPort));
1261 actions.add(action);
1262 }
1263 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001264 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001265 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1266 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001267 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001268 // and FlowEntryErrorState.
1269 //
1270 flowPath.dataPath().flowEntries().add(flowEntry);
1271 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001272
1273 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001274 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001275
1276 /**
1277 * Add and maintain a shortest-path flow.
1278 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001279 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001280 *
1281 * @param flowPath the Flow Path with the endpoints and the match
1282 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001283 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001284 */
1285 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001286 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001287 String dataPathSummaryStr = null;
1288
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001289 //
1290 // Do the shortest path computation
1291 //
1292 DataPath dataPath =
1293 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1294 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001295 if (dataPath == null) {
1296 // We need the DataPath to populate the Network MAP
1297 dataPath = new DataPath();
1298 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1299 dataPath.setDstPort(flowPath.dataPath().dstPort());
1300 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001301
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001302 // Compute the Data Path summary
1303 dataPathSummaryStr = dataPath.dataPathSummary();
1304
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001305 //
1306 // Set the incoming port matching and the outgoing port output
1307 // actions for each flow entry.
1308 //
1309 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1310 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001311 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001312 flowEntry.setFlowEntryMatch(flowEntryMatch);
1313 flowEntryMatch.enableInPort(flowEntry.inPort());
1314
1315 // Set the outgoing port output action
1316 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1317 if (flowEntryActions == null) {
1318 flowEntryActions = new ArrayList<FlowEntryAction>();
1319 flowEntry.setFlowEntryActions(flowEntryActions);
1320 }
1321 FlowEntryAction flowEntryAction = new FlowEntryAction();
1322 flowEntryAction.setActionOutput(flowEntry.outPort());
1323 flowEntryActions.add(flowEntryAction);
1324 }
1325
1326 //
1327 // Prepare the computed Flow Path
1328 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001329 FlowPath computedFlowPath = new FlowPath();
1330 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1331 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1332 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001333 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001334
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001335 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001336 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001337 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001338
1339 // TODO: Mark the flow for maintenance purpose
1340
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001341 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001342 }
1343
1344 /**
1345 * Create a Flow from port to port.
1346 *
1347 * TODO: We don't need it for now.
1348 *
1349 * @param src_port the source port.
1350 * @param dest_port the destination port.
1351 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001352 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001353 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1354 // TODO: We don't need it for now.
1355 }
1356
1357 /**
1358 * Get all Flows matching a source and a destination port.
1359 *
1360 * TODO: Pankaj might be implementing it later.
1361 *
1362 * @param src_port the source port to match.
1363 * @param dest_port the destination port to match.
1364 * @return all flows matching the source and the destination port.
1365 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001366 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001367 public Iterable<FlowPath> getFlows(IPortObject src_port,
1368 IPortObject dest_port) {
1369 // TODO: Pankaj might be implementing it later.
1370 return null;
1371 }
1372
1373 /**
1374 * Get all Flows going out from a port.
1375 *
1376 * TODO: We need it now: Pankaj
1377 *
1378 * @param port the port to match.
1379 * @return the list of flows that are going out from the port.
1380 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001381 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001382 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001383 // TODO: We need it now: Pankaj
1384 return null;
1385 }
1386
1387 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001388 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001389 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001390 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001391 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001392 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001393 public void reconcileFlows(IPortObject portObject) {
1394 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1395 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001396
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001397 //
1398 // Collect all affected Flow IDs from the affected flow entries
1399 //
1400 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1401 for (IFlowEntry flowEntryObj: inFlowEntries) {
1402 IFlowPath flowObj = flowEntryObj.getFlow();
1403 if (flowObj != null)
1404 flowObjSet.add(flowObj);
1405 }
1406 for (IFlowEntry flowEntryObj: outFlowEntries) {
1407 IFlowPath flowObj = flowEntryObj.getFlow();
1408 if (flowObj != null)
1409 flowObjSet.add(flowObj);
1410 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001411
1412 // Reconcile the affected flows
1413 reconcileFlows(flowObjSet);
1414 }
1415
1416 /**
1417 * Reconcile all flows in a set.
1418 *
1419 * @param flowObjSet the set of flows that need to be reconciliated.
1420 */
1421 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1422 if (! flowObjSet.iterator().hasNext())
1423 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001424
1425 //
1426 // Remove the old Flow Entries, and add the new Flow Entries
1427 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001428
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001429 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001430 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001431 for (IFlowPath flowObj : flowObjSet) {
1432 FlowPath flowPath = extractFlowPath(flowObj);
1433 if (flowPath == null)
1434 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001435 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001436
1437 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001438 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001439 //
1440 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001441 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001442 for (IFlowEntry flowEntryObj : flowEntries) {
1443 String dpidStr = flowEntryObj.getSwitchDpid();
1444 if (dpidStr == null)
1445 continue;
1446 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001447 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001448 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1449 if (mySwitch == null)
1450 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001451 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001452 deleteFlowEntries.add(flowEntryObj);
1453 }
1454 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001455 flowObj.removeFlowEntry(flowEntryObj);
1456 conn.utils().removeFlowEntry(conn, flowEntryObj);
1457 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001458 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001459
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001460 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001461 //
1462 // Delete the flow entries from the switches
1463 //
1464 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1465 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001466 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1467 if (mySwitch == null) {
1468 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001469 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001470 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001471 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001472 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001473 }
1474
1475 //
1476 // Calculate the new shortest path and install it in the
1477 // Network MAP.
1478 //
1479 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1480 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001481 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001482 flowPath.dataPath().srcPort().toString(),
1483 flowPath.dataPath().dstPort().toString());
1484 continue;
1485 }
1486
1487 //
1488 // Add the flow entries to the switches
1489 //
1490 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1491 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001492 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1493 if (mySwitch == null) {
1494 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001495 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001496 continue;
1497 }
1498
1499 IFlowEntry flowEntryObj =
1500 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1501 if (flowEntryObj == null) {
1502 //
1503 // TODO: Remove the "new Object[] wrapper in the statement
1504 // below after the SLF4J logger is upgraded to
1505 // Version 1.7.5
1506 //
1507 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1508 new Object[] {
1509 flowEntry.dpid(),
1510 flowPath.dataPath().srcPort(),
1511 flowPath.dataPath().dstPort()
1512 });
1513 continue;
1514 }
1515 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001516 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001517 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1518 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001519 }
1520 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001521 }
1522
1523 /**
1524 * Reconcile all flows between a source and a destination port.
1525 *
1526 * TODO: We don't need it for now.
1527 *
1528 * @param src_port the source port.
1529 * @param dest_port the destination port.
1530 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001531 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001532 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1533 // TODO: We don't need it for now.
1534 }
1535
1536 /**
1537 * Compute the shortest path between a source and a destination ports.
1538 *
1539 * @param src_port the source port.
1540 * @param dest_port the destination port.
1541 * @return the computed shortest path between the source and the
1542 * destination ports. The flow entries in the path itself would
1543 * contain the incoming port matching and the outgoing port output
1544 * actions set. However, the path itself will NOT have the Flow ID,
1545 * Installer ID, and any additional matching conditions for the
1546 * flow entries (e.g., source or destination MAC address, etc).
1547 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001548 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001549 public FlowPath computeFlowPath(IPortObject src_port,
1550 IPortObject dest_port) {
1551 //
1552 // Prepare the arguments
1553 //
1554 String dpidStr = src_port.getSwitch().getDPID();
1555 Dpid srcDpid = new Dpid(dpidStr);
1556 Port srcPort = new Port(src_port.getNumber());
1557
1558 dpidStr = dest_port.getSwitch().getDPID();
1559 Dpid dstDpid = new Dpid(dpidStr);
1560 Port dstPort = new Port(dest_port.getNumber());
1561
1562 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1563 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1564
1565 //
1566 // Do the shortest path computation
1567 //
1568 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1569 if (dataPath == null)
1570 return null;
1571
1572 //
1573 // Set the incoming port matching and the outgoing port output
1574 // actions for each flow entry.
1575 //
1576 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1577 // Set the incoming port matching
1578 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1579 if (flowEntryMatch == null) {
1580 flowEntryMatch = new FlowEntryMatch();
1581 flowEntry.setFlowEntryMatch(flowEntryMatch);
1582 }
1583 flowEntryMatch.enableInPort(flowEntry.inPort());
1584
1585 // Set the outgoing port output action
1586 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1587 if (flowEntryActions == null) {
1588 flowEntryActions = new ArrayList<FlowEntryAction>();
1589 flowEntry.setFlowEntryActions(flowEntryActions);
1590 }
1591 FlowEntryAction flowEntryAction = new FlowEntryAction();
1592 flowEntryAction.setActionOutput(flowEntry.outPort());
1593 flowEntryActions.add(flowEntryAction);
1594 }
1595
1596 //
1597 // Prepare the return result
1598 //
1599 FlowPath flowPath = new FlowPath();
1600 flowPath.setDataPath(dataPath);
1601
1602 return flowPath;
1603 }
1604
1605 /**
1606 * Get all Flow Entries of a Flow.
1607 *
1608 * @param flow the flow whose flow entries should be returned.
1609 * @return the flow entries of the flow.
1610 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001611 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001612 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1613 return flow.dataPath().flowEntries();
1614 }
1615
1616 /**
1617 * Install a Flow Entry on a switch.
1618 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001619 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001620 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001621 * @param flowEntry the flow entry to install.
1622 * @return true on success, otherwise false.
1623 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001624 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001625 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1626 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001627 //
1628 // Create the OpenFlow Flow Modification Entry to push
1629 //
1630 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1631 .getMessage(OFType.FLOW_MOD);
1632 long cookie = flowEntry.flowEntryId().value();
1633
1634 short flowModCommand = OFFlowMod.OFPFC_ADD;
1635 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1636 flowModCommand = OFFlowMod.OFPFC_ADD;
1637 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1638 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1639 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1640 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1641 } else {
1642 // Unknown user state. Ignore the entry
1643 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1644 flowEntry.flowEntryId().toString(),
1645 flowEntry.flowEntryUserState());
1646 return false;
1647 }
1648
1649 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001650 // Fetch the match conditions.
1651 //
1652 // NOTE: The Flow matching conditions common for all Flow Entries are
1653 // used ONLY if a Flow Entry does NOT have the corresponding matching
1654 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001655 //
1656 OFMatch match = new OFMatch();
1657 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001658 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1659 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1660
1661 // Match the Incoming Port
1662 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001663 if (matchInPort != null) {
1664 match.setInputPort(matchInPort.value());
1665 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1666 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001667
1668 // Match the Ethernet Frame Type
1669 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1670 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1671 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1672 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001673 if (matchEthernetFrameType != null) {
1674 match.setDataLayerType(matchEthernetFrameType);
1675 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1676 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001677
1678 // Match the Source IPv4 Network prefix
1679 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1680 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1681 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1682 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001683 if (matchSrcIPv4Net != null) {
1684 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1685 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001686
1687 // Natch the Destination IPv4 Network prefix
1688 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1689 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1690 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1691 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001692 if (matchDstIPv4Net != null) {
1693 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1694 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001695
1696 // Match the Source MAC address
1697 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1698 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1699 matchSrcMac = flowPathMatch.srcMac();
1700 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001701 if (matchSrcMac != null) {
1702 match.setDataLayerSource(matchSrcMac.toString());
1703 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1704 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001705
1706 // Match the Destination MAC address
1707 MACAddress matchDstMac = flowEntryMatch.dstMac();
1708 if ((matchDstMac == null) && (flowPathMatch != null)) {
1709 matchDstMac = flowPathMatch.dstMac();
1710 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001711 if (matchDstMac != null) {
1712 match.setDataLayerDestination(matchDstMac.toString());
1713 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1714 }
1715
1716 //
1717 // Fetch the actions
1718 //
1719 // TODO: For now we support only the "OUTPUT" actions.
1720 //
1721 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1722 List<OFAction> actions = new ArrayList<OFAction>();
1723 ArrayList<FlowEntryAction> flowEntryActions =
1724 flowEntry.flowEntryActions();
1725 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1726 FlowEntryAction.ActionOutput actionOutput =
1727 flowEntryAction.actionOutput();
1728 if (actionOutput != null) {
1729 short actionOutputPort = actionOutput.port().value();
1730 OFActionOutput action = new OFActionOutput();
1731 // XXX: The max length is hard-coded for now
1732 action.setMaxLength((short)0xffff);
1733 action.setPort(actionOutputPort);
1734 actions.add(action);
1735 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1736 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1737 fm.setOutPort(actionOutputPort);
1738 }
1739 }
1740 }
1741
1742 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1743 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1744 .setPriority(PRIORITY_DEFAULT)
1745 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1746 .setCookie(cookie)
1747 .setCommand(flowModCommand)
1748 .setMatch(match)
1749 .setActions(actions)
1750 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1751
1752 //
1753 // TODO: Set the following flag
1754 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1755 // See method ForwardingBase::pushRoute()
1756 //
1757
1758 //
1759 // Write the message to the switch
1760 //
1761 try {
1762 messageDamper.write(mySwitch, fm, null);
1763 mySwitch.flush();
1764 } catch (IOException e) {
1765 log.error("Failure writing flow mod from network map", e);
1766 return false;
1767 }
1768 return true;
1769 }
1770
1771 /**
1772 * Remove a Flow Entry from a switch.
1773 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001774 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001775 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001776 * @param flowEntry the flow entry to remove.
1777 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001778 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001779 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001780 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1781 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001782 //
1783 // The installFlowEntry() method implements both installation
1784 // and removal of flow entries.
1785 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001786 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001787 }
1788
1789 /**
1790 * Install a Flow Entry on a remote controller.
1791 *
1792 * TODO: We need it now: Jono
1793 * - For now it will make a REST call to the remote controller.
1794 * - Internally, it needs to know the name of the remote controller.
1795 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001796 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001797 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001798 * @return true on success, otherwise false.
1799 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001800 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001801 public boolean installRemoteFlowEntry(FlowPath flowPath,
1802 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001803 // TODO: We need it now: Jono
1804 // - For now it will make a REST call to the remote controller.
1805 // - Internally, it needs to know the name of the remote controller.
1806 return true;
1807 }
1808
1809 /**
1810 * Remove a flow entry on a remote controller.
1811 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001812 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001813 * @param flowEntry the flow entry to remove.
1814 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001815 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001816 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001817 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1818 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001819 //
1820 // The installRemoteFlowEntry() method implements both installation
1821 // and removal of flow entries.
1822 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001823 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001824 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001825}