blob: e84a3e8195ae0628daf03f2f25ed1aa8a5275908 [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 Radoslavov0b22d0e2013-04-02 01:12:46 +00006import java.util.Collections;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08007import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.HashMap;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07009import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000010import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080012import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000013import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070014import java.util.TreeMap;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070015import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070017import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070020import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080022
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080023import net.floodlightcontroller.core.IFloodlightProviderService;
24import net.floodlightcontroller.core.INetMapStorage;
25import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
26import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070027import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070028import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070029import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080030import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080031import net.floodlightcontroller.core.module.FloodlightModuleContext;
32import net.floodlightcontroller.core.module.FloodlightModuleException;
33import net.floodlightcontroller.core.module.IFloodlightModule;
34import net.floodlightcontroller.core.module.IFloodlightService;
35import net.floodlightcontroller.flowcache.IFlowService;
36import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
37import net.floodlightcontroller.restserver.IRestApiService;
38import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.DataPath;
40import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080041import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070043import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080044import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070045import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.FlowEntrySwitchState;
47import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080048import net.floodlightcontroller.util.FlowId;
49import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070050import net.floodlightcontroller.util.IPv4Net;
51import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052import net.floodlightcontroller.util.OFMessageDamper;
53import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070054import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070055import net.onrc.onos.flow.IFlowManager;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080056import net.onrc.onos.util.GraphDBConnection;
57import net.onrc.onos.util.GraphDBConnection.Transaction;
58
59import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
61import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070062import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080063import org.openflow.protocol.OFType;
64import org.openflow.protocol.action.OFAction;
65import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080066
67import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070070public class FlowManager implements IFloodlightModule, IFlowService, IFlowManager, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
72 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080073
74 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070076 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070077 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080078
79 protected OFMessageDamper messageDamper;
80
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070081 //
82 // TODO: Values copied from elsewhere (class LearningSwitch).
83 // The local copy should go away!
84 //
85 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
86 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
87 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
88 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
89 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080090
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000091 // Flow Entry ID generation state
92 private static Random randomGenerator = new Random();
93 private static int nextFlowEntryIdPrefix = 0;
94 private static int nextFlowEntryIdSuffix = 0;
95 private static long nextFlowEntryId = 0;
96
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070097 private static long measurementFlowId = 100000;
98 private static String measurementFlowIdStr = "0x186a0"; // 100000
99 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700100
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800101 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
103
104 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700105 private final ScheduledExecutorService mapReaderScheduler =
106 Executors.newScheduledThreadPool(1);
107
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700108 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800109 public void run() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700110 long startTime = System.nanoTime();
111 int counterAllFlowEntries = 0;
112 int counterMyNotUpdatedFlowEntries = 0;
113 int counterAllFlowPaths = 0;
114 int counterMyFlowPaths = 0;
115
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800116 if (floodlightProvider == null) {
117 log.debug("FloodlightProvider service not found!");
118 return;
119 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000120 Map<Long, IOFSwitch> mySwitches =
121 floodlightProvider.getSwitches();
122 Map<Long, IFlowEntry> myFlowEntries =
123 new TreeMap<Long, IFlowEntry>();
124 LinkedList<IFlowEntry> deleteFlowEntries =
125 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700126
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700127
128 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700129 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700130 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700131 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000132 Iterable<IFlowEntry> allFlowEntries =
133 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700134 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700135 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000136 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700137 String userState = flowEntryObj.getUserState();
138 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000139 String dpidStr = flowEntryObj.getSwitchDpid();
140 if ((flowEntryIdStr == null) ||
141 (userState == null) ||
142 (switchState == null) ||
143 (dpidStr == null)) {
144 log.debug("IGNORING Flow Entry entry with null fields");
145 continue;
146 }
147 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
148 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800149
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000150 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
151 continue; // Ignore the entry: nothing to do
152
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800153 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000154 if (mySwitch == null)
155 continue; // Ignore the entry: not my switch
156
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700157 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
158 }
159
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700160 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
161 myFlowEntries.size());
162
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700163 //
164 // Process my Flow Entries
165 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700166 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700167 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700168 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700169 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700170 IFlowPath flowObj =
171 conn.utils().getFlowPathByFlowEntry(conn,
172 flowEntryObj);
173 if (flowObj == null)
174 continue; // Should NOT happen
175
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700176 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700177 // TODO: Commented-out for now
178 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700180 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700181 processed_measurement_flow = true;
182 }
183 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700184 */
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700185
186 //
187 // TODO: Eliminate the re-fetching of flowEntryId,
188 // userState, switchState, and dpid from the flowEntryObj.
189 //
190 FlowEntryId flowEntryId =
191 new FlowEntryId(flowEntryObj.getFlowEntryId());
192 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
193 String userState = flowEntryObj.getUserState();
194 String switchState = flowEntryObj.getSwitchState();
195 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000196 if (mySwitch == null)
197 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800198
199 //
200 // Create the Open Flow Flow Modification Entry to push
201 //
202 OFFlowMod fm =
203 (OFFlowMod) floodlightProvider.getOFMessageFactory()
204 .getMessage(OFType.FLOW_MOD);
205 long cookie = flowEntryId.value();
206
207 short flowModCommand = OFFlowMod.OFPFC_ADD;
208 if (userState.equals("FE_USER_ADD")) {
209 flowModCommand = OFFlowMod.OFPFC_ADD;
210 } else if (userState.equals("FE_USER_MODIFY")) {
211 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
212 } else if (userState.equals("FE_USER_DELETE")) {
213 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
214 } else {
215 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700216 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
217 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800218 continue;
219 }
220
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700221 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700222 // Fetch the match conditions.
223 //
224 // NOTE: The Flow matching conditions common for all
225 // Flow Entries are used ONLY if a Flow Entry does NOT
226 // have the corresponding matching condition set.
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700227 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800228 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700229 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700230 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700231 Short matchInPort = flowEntryObj.getMatchInPort();
232 if (matchInPort != null) {
233 match.setInputPort(matchInPort);
234 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
235 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700236 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700237 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700238 if (matchEthernetFrameType == null)
239 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700240 if (matchEthernetFrameType != null) {
241 match.setDataLayerType(matchEthernetFrameType);
242 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
243 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700244 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700245 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700246 if (matchSrcIPv4Net == null)
247 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700248 if (matchSrcIPv4Net != null) {
249 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
250 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700251 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700252 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700253 if (matchDstIPv4Net == null)
254 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700255 if (matchDstIPv4Net != null) {
256 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
257 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700258 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700259 String matchSrcMac = flowEntryObj.getMatchSrcMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700260 if (matchSrcMac == null)
261 matchSrcMac = flowObj.getMatchSrcMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700262 if (matchSrcMac != null) {
263 match.setDataLayerSource(matchSrcMac);
264 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
265 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700266 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700267 String matchDstMac = flowEntryObj.getMatchDstMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700268 if (matchDstMac == null)
269 matchDstMac = flowObj.getMatchDstMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700270 if (matchDstMac != null) {
271 match.setDataLayerDestination(matchDstMac);
272 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
273 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700274
275 //
276 // Fetch the actions
277 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800278 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700279 Short actionOutputPort = flowEntryObj.getActionOutput();
280 if (actionOutputPort != null) {
281 OFActionOutput action = new OFActionOutput();
282 // XXX: The max length is hard-coded for now
283 action.setMaxLength((short)0xffff);
284 action.setPort(actionOutputPort);
285 actions.add(action);
286 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800287
288 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
289 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700290 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800291 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
292 .setCookie(cookie)
293 .setCommand(flowModCommand)
294 .setMatch(match)
295 .setActions(actions)
296 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700297 fm.setOutPort(OFPort.OFPP_NONE.getValue());
298 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
299 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
300 if (actionOutputPort != null)
301 fm.setOutPort(actionOutputPort);
302 }
303
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800304 //
305 // TODO: Set the following flag
306 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
307 // See method ForwardingBase::pushRoute()
308 //
309 try {
310 messageDamper.write(mySwitch, fm, null);
311 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000312 //
313 // TODO: We should use the OpenFlow Barrier mechanism
314 // to check for errors, and update the SwitchState
315 // for a flow entry after the Barrier message is
316 // is received.
317 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800318 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
319 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000320 // An entry that needs to be deleted.
321 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800322 }
323 } catch (IOException e) {
324 log.error("Failure writing flow mod from network map", e);
325 }
326 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000327
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700328 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
329 deleteFlowEntries.size());
330
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000331 //
332 // Delete all entries marked for deletion
333 //
334 // TODO: We should use the OpenFlow Barrier mechanism
335 // to check for errors, and delete the Flow Entries after the
336 // Barrier message is received.
337 //
338 while (! deleteFlowEntries.isEmpty()) {
339 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
340 IFlowPath flowObj =
341 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
342 if (flowObj == null) {
343 log.debug("Did not find FlowPath to be deleted");
344 continue;
345 }
346 flowObj.removeFlowEntry(flowEntryObj);
347 conn.utils().removeFlowEntry(conn, flowEntryObj);
348
349 // Test whether the last flow entry
350 Iterable<IFlowEntry> tmpflowEntries =
351 flowObj.getFlowEntries();
352 boolean found = false;
353 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
354 found = true;
355 break;
356 }
357 if (! found) {
358 // Remove the Flow Path as well
359 conn.utils().removeFlowPath(conn, flowObj);
360 }
361 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700362
363
364 //
365 // Fetch and recompute the Shortest Path for those
366 // Flow Paths this controller is responsible for.
367 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700368 topoRouteService.prepareShortestPathTopo();
369 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
370 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
371 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700372 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700373 if (flowPathObj == null)
374 continue;
375 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
376 if (dataPathSummaryStr == null)
377 continue; // Could be invalid entry?
378 if (dataPathSummaryStr.isEmpty())
379 continue; // No need to maintain this flow
380
381 // Fetch the fields needed to recompute the shortest path
382 String flowIdStr = flowPathObj.getFlowId();
383 String srcDpidStr = flowPathObj.getSrcSwitch();
384 Short srcPortShort = flowPathObj.getSrcPort();
385 String dstDpidStr = flowPathObj.getDstSwitch();
386 Short dstPortShort = flowPathObj.getDstPort();
387 if ((flowIdStr == null) ||
388 (srcDpidStr == null) ||
389 (srcPortShort == null) ||
390 (dstDpidStr == null) ||
391 (dstPortShort == null)) {
392 log.debug("IGNORING Flow Path entry with null fields");
393 continue;
394 }
395
396 FlowId flowId = new FlowId(flowIdStr);
397 Dpid srcDpid = new Dpid(srcDpidStr);
398 Port srcPort = new Port(srcPortShort);
399 Dpid dstDpid = new Dpid(dstDpidStr);
400 Port dstPort = new Port(dstPortShort);
401 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
402 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700403
404 //
405 // Use the source DPID as a heuristic to decide
406 // which controller is responsible for maintaining the
407 // shortest path.
408 // NOTE: This heuristic is error-prone: if the switch
409 // goes away and no controller is responsible for that
410 // switch, then the original Flow Path is not cleaned-up
411 //
412 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
413 if (mySwitch == null)
414 continue; // Ignore: not my responsibility
415
416 counterMyFlowPaths++;
417
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700418 //
419 // NOTE: Using here the regular getShortestPath() method
420 // won't work here, because that method calls internally
421 // "conn.endTx(Transaction.COMMIT)", and that will
422 // invalidate all handlers to the Titan database.
423 // If we want to experiment with calling here
424 // getShortestPath(), we need to refactor that code
425 // to avoid closing the transaction.
426 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700427 DataPath dataPath =
428 topoRouteService.getTopoShortestPath(srcSwitchPort,
429 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000430 if (dataPath == null) {
431 // We need the DataPath to compare the paths
432 dataPath = new DataPath();
433 dataPath.setSrcPort(srcSwitchPort);
434 dataPath.setDstPort(dstSwitchPort);
435 }
436
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700437 String newDataPathSummaryStr = dataPath.dataPathSummary();
438 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
439 continue; // Nothing changed
440
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700441 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
442 flowId.toString());
443 flowObjSet.add(flowPathObj);
444 }
Pavlin Radoslavov53a3a8c2013-04-04 04:34:50 -0700445 log.debug("MEASUREMENT: Found {} Flows to reconcile",
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700446 flowObjSet.size());
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700447 reconcileFlows(flowObjSet);
448 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700449
450
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800451 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700452
453 if (processed_measurement_flow) {
454 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
455 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
456 (double)estimatedTime / 1000000000 + " sec";
457 log.debug(logMsg);
458 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700459
460 long estimatedTime = System.nanoTime() - startTime;
461 double rate = (estimatedTime > 0)? ((double)counterAllFlowPaths * 1000000000) / estimatedTime: 0.0;
462 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " + counterAllFlowEntries + " MyNotUpdatedFlowEntries: " + counterMyNotUpdatedFlowEntries + " AllFlowPaths: " + counterAllFlowPaths + " MyFlowPaths: " + counterMyFlowPaths + " in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " paths/s";
463 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800464 }
465 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700466
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700467 final ScheduledFuture<?> mapReaderHandle =
468 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800469
470 @Override
471 public void init(String conf) {
472 conn = GraphDBConnection.getInstance(conf);
473 }
474
475 public void finalize() {
476 close();
477 }
478
479 @Override
480 public void close() {
481 conn.close();
482 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800483
484 @Override
485 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
486 Collection<Class<? extends IFloodlightService>> l =
487 new ArrayList<Class<? extends IFloodlightService>>();
488 l.add(IFlowService.class);
489 return l;
490 }
491
492 @Override
493 public Map<Class<? extends IFloodlightService>, IFloodlightService>
494 getServiceImpls() {
495 Map<Class<? extends IFloodlightService>,
496 IFloodlightService> m =
497 new HashMap<Class<? extends IFloodlightService>,
498 IFloodlightService>();
499 m.put(IFlowService.class, this);
500 return m;
501 }
502
503 @Override
504 public Collection<Class<? extends IFloodlightService>>
505 getModuleDependencies() {
506 Collection<Class<? extends IFloodlightService>> l =
507 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800508 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700509 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800510 l.add(IRestApiService.class);
511 return l;
512 }
513
514 @Override
515 public void init(FloodlightModuleContext context)
516 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700517 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800518 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700519 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800520 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800521 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
522 EnumSet.of(OFType.FLOW_MOD),
523 OFMESSAGE_DAMPER_TIMEOUT);
524 // TODO: An ugly hack!
525 String conf = "/tmp/cassandra.titan";
526 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800527 }
528
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000529 private long getNextFlowEntryId() {
530 //
531 // Generate the next Flow Entry ID.
532 // NOTE: For now, the higher 32 bits are random, and
533 // the lower 32 bits are sequential.
534 // In the future, we need a better allocation mechanism.
535 //
536 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
537 nextFlowEntryIdPrefix = randomGenerator.nextInt();
538 nextFlowEntryIdSuffix = 0;
539 } else {
540 nextFlowEntryIdSuffix++;
541 }
542 long result = (long)nextFlowEntryIdPrefix << 32;
543 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
544 return result;
545 }
546
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800547 @Override
548 public void startUp(FloodlightModuleContext context) {
549 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700550
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000551 // Initialize the Flow Entry ID generator
552 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800553 }
554
555 /**
556 * Add a flow.
557 *
558 * Internally, ONOS will automatically register the installer for
559 * receiving Flow Path Notifications for that path.
560 *
561 * @param flowPath the Flow Path to install.
562 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700563 * @param dataPathSummaryStr the data path summary string if the added
564 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800565 * @return true on success, otherwise false.
566 */
567 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700568 public boolean addFlow(FlowPath flowPath, FlowId flowId,
569 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700570 /*
571 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700572 if (flowPath.flowId().value() == measurementFlowId) {
573 modifiedMeasurementFlowTime = System.nanoTime();
574 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700575 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800576
577 //
578 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700579 // Right now every new flow entry gets a new flow entry ID
580 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800581 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800582 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000583 long id = getNextFlowEntryId();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800584 flowEntry.setFlowEntryId(new FlowEntryId(id));
585 }
586
587 IFlowPath flowObj = null;
588 try {
589 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
590 != null) {
591 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
592 flowPath.flowId().toString());
593 } else {
594 flowObj = conn.utils().newFlowPath(conn);
595 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
596 flowPath.flowId().toString());
597 }
598 } catch (Exception e) {
599 // TODO: handle exceptions
600 conn.endTx(Transaction.ROLLBACK);
601 log.error(":addFlow FlowId:{} failed",
602 flowPath.flowId().toString());
603 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700604 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000605 log.error(":addFlow FlowId:{} failed: Flow object not created",
606 flowPath.flowId().toString());
607 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800608 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700609 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800610
611 //
612 // Set the Flow key:
613 // - flowId
614 //
615 flowObj.setFlowId(flowPath.flowId().toString());
616 flowObj.setType("flow");
617
618 //
619 // Set the Flow attributes:
620 // - flowPath.installerId()
621 // - flowPath.dataPath().srcPort()
622 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700623 // - flowPath.matchEthernetFrameType()
624 // - flowPath.matchSrcIPv4Net()
625 // - flowPath.matchDstIPv4Net()
626 // - flowPath.matchSrcMac()
627 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800628 //
629 flowObj.setInstallerId(flowPath.installerId().toString());
630 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
631 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
632 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
633 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700634 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
635 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
636 }
637 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
638 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
639 }
640 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
641 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
642 }
643 if (flowPath.flowEntryMatch().matchSrcMac()) {
644 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
645 }
646 if (flowPath.flowEntryMatch().matchDstMac()) {
647 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
648 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800649
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700650 if (dataPathSummaryStr != null) {
651 flowObj.setDataPathSummary(dataPathSummaryStr);
652 } else {
653 flowObj.setDataPathSummary("");
654 }
655
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800656 // Flow edges:
657 // HeadFE
658
659
660 //
661 // Flow Entries:
662 // flowPath.dataPath().flowEntries()
663 //
664 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
665 IFlowEntry flowEntryObj = null;
666 boolean found = false;
667 try {
668 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
669 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
670 flowEntry.flowEntryId().toString());
671 found = true;
672 } else {
673 flowEntryObj = conn.utils().newFlowEntry(conn);
674 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
675 flowEntry.flowEntryId().toString());
676 }
677 } catch (Exception e) {
678 // TODO: handle exceptions
679 conn.endTx(Transaction.ROLLBACK);
680 log.error(":addFlow FlowEntryId:{} failed",
681 flowEntry.flowEntryId().toString());
682 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700683 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000684 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
685 flowEntry.flowEntryId().toString());
686 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800687 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700688 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800689
690 //
691 // Set the Flow Entry key:
692 // - flowEntry.flowEntryId()
693 //
694 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
695 flowEntryObj.setType("flow_entry");
696
697 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700698 // Set the Flow Entry Edges and attributes:
699 // - Switch edge
700 // - InPort edge
701 // - OutPort edge
702 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800703 // - flowEntry.flowEntryMatch()
704 // - flowEntry.flowEntryActions()
705 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800706 // - flowEntry.flowEntryUserState()
707 // - flowEntry.flowEntrySwitchState()
708 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700709 // - flowEntry.matchInPort()
710 // - flowEntry.matchEthernetFrameType()
711 // - flowEntry.matchSrcIPv4Net()
712 // - flowEntry.matchDstIPv4Net()
713 // - flowEntry.matchSrcMac()
714 // - flowEntry.matchDstMac()
715 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800716 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700717 ISwitchObject sw =
718 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800719 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700720 flowEntryObj.setSwitch(sw);
721 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700722 IPortObject inport =
723 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
724 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700725 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
726 flowEntryObj.setInPort(inport);
727 }
728 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
729 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
730 }
731 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
732 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
733 }
734 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
735 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
736 }
737 if (flowEntry.flowEntryMatch().matchSrcMac()) {
738 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
739 }
740 if (flowEntry.flowEntryMatch().matchDstMac()) {
741 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
742 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700743
744 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700745 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700746 IPortObject outport =
747 conn.utils().searchPort(conn,
748 flowEntry.dpid().toString(),
749 fa.actionOutput().port().value());
750 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
751 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700752 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700753 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800754 // TODO: Hacks with hard-coded state names!
755 if (found)
756 flowEntryObj.setUserState("FE_USER_MODIFY");
757 else
758 flowEntryObj.setUserState("FE_USER_ADD");
759 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
760 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700761 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800762 //
763
764 // Flow Entries edges:
765 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700766 // NextFE (TODO)
767 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800768 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700769 flowEntryObj.setFlow(flowObj);
770 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800771 }
772 conn.endTx(Transaction.COMMIT);
773
774 //
775 // TODO: We need a proper Flow ID allocation mechanism.
776 //
777 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700778
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800779 return true;
780 }
781
782 /**
783 * Delete a previously added flow.
784 *
785 * @param flowId the Flow ID of the flow to delete.
786 * @return true on success, otherwise false.
787 */
788 @Override
789 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700790 /*
791 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700792 if (flowId.value() == measurementFlowId) {
793 modifiedMeasurementFlowTime = System.nanoTime();
794 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700795 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700796
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800797 IFlowPath flowObj = null;
798 //
799 // We just mark the entries for deletion,
800 // and let the switches remove each individual entry after
801 // it has been removed from the switches.
802 //
803 try {
804 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
805 != null) {
806 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
807 flowId.toString());
808 } else {
809 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
810 flowId.toString());
811 }
812 } catch (Exception e) {
813 // TODO: handle exceptions
814 conn.endTx(Transaction.ROLLBACK);
815 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
816 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700817 if (flowObj == null) {
818 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800819 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700820 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800821
822 //
823 // Find and mark for deletion all Flow Entries
824 //
825 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
826 boolean empty = true; // TODO: an ugly hack
827 for (IFlowEntry flowEntryObj : flowEntries) {
828 empty = false;
829 // flowObj.removeFlowEntry(flowEntryObj);
830 // conn.utils().removeFlowEntry(conn, flowEntryObj);
831 flowEntryObj.setUserState("FE_USER_DELETE");
832 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
833 }
834 // Remove from the database empty flows
835 if (empty)
836 conn.utils().removeFlowPath(conn, flowObj);
837 conn.endTx(Transaction.COMMIT);
838
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800839 return true;
840 }
841
842 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700843 * Clear the state for a previously added flow.
844 *
845 * @param flowId the Flow ID of the flow to clear.
846 * @return true on success, otherwise false.
847 */
848 @Override
849 public boolean clearFlow(FlowId flowId) {
850 IFlowPath flowObj = null;
851 try {
852 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
853 != null) {
854 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
855 flowId.toString());
856 } else {
857 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
858 flowId.toString());
859 }
860 } catch (Exception e) {
861 // TODO: handle exceptions
862 conn.endTx(Transaction.ROLLBACK);
863 log.error(":clearFlow FlowId:{} failed", flowId.toString());
864 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700865 if (flowObj == null) {
866 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700867 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700868 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700869
870 //
871 // Remove all Flow Entries
872 //
873 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
874 for (IFlowEntry flowEntryObj : flowEntries) {
875 flowObj.removeFlowEntry(flowEntryObj);
876 conn.utils().removeFlowEntry(conn, flowEntryObj);
877 }
878 // Remove the Flow itself
879 conn.utils().removeFlowPath(conn, flowObj);
880 conn.endTx(Transaction.COMMIT);
881
882 return true;
883 }
884
885 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800886 * Get a previously added flow.
887 *
888 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800889 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800890 */
891 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800892 public FlowPath getFlow(FlowId flowId) {
893 IFlowPath flowObj = null;
894 try {
895 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
896 != null) {
897 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
898 flowId.toString());
899 } else {
900 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
901 flowId.toString());
902 }
903 } catch (Exception e) {
904 // TODO: handle exceptions
905 conn.endTx(Transaction.ROLLBACK);
906 log.error(":getFlow FlowId:{} failed", flowId.toString());
907 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700908 if (flowObj == null) {
909 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800910 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700911 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800912
913 //
914 // Extract the Flow state
915 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800916 FlowPath flowPath = extractFlowPath(flowObj);
917 conn.endTx(Transaction.COMMIT);
918
919 return flowPath;
920 }
921
922 /**
923 * Get all previously added flows by a specific installer for a given
924 * data path endpoints.
925 *
926 * @param installerId the Caller ID of the installer of the flow to get.
927 * @param dataPathEndpoints the data path endpoints of the flow to get.
928 * @return the Flow Paths if found, otherwise null.
929 */
930 @Override
931 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
932 DataPathEndpoints dataPathEndpoints) {
933 //
934 // TODO: The implementation below is not optimal:
935 // We fetch all flows, and then return only the subset that match
936 // the query conditions.
937 // We should use the appropriate Titan/Gremlin query to filter-out
938 // the flows as appropriate.
939 //
940 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700941 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800942
943 if (allFlows == null) {
944 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700945 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800946 }
947
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800948 for (FlowPath flow : allFlows) {
949 //
950 // TODO: String-based comparison is sub-optimal.
951 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800952 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800953 //
954 if (! flow.installerId().toString().equals(installerId.toString()))
955 continue;
956 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
957 continue;
958 }
959 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
960 continue;
961 }
962 flowPaths.add(flow);
963 }
964
965 if (flowPaths.isEmpty()) {
966 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800967 } else {
968 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
969 }
970
971 return flowPaths;
972 }
973
974 /**
975 * Get all installed flows by all installers for given data path endpoints.
976 *
977 * @param dataPathEndpoints the data path endpoints of the flows to get.
978 * @return the Flow Paths if found, otherwise null.
979 */
980 @Override
981 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
982 //
983 // TODO: The implementation below is not optimal:
984 // We fetch all flows, and then return only the subset that match
985 // the query conditions.
986 // We should use the appropriate Titan/Gremlin query to filter-out
987 // the flows as appropriate.
988 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700989 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
990 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800991
992 if (allFlows == null) {
993 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700994 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800995 }
996
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800997 for (FlowPath flow : allFlows) {
998 //
999 // TODO: String-based comparison is sub-optimal.
1000 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001001 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001002 //
1003 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1004 continue;
1005 }
1006 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1007 continue;
1008 }
1009 flowPaths.add(flow);
1010 }
1011
1012 if (flowPaths.isEmpty()) {
1013 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001014 } else {
1015 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1016 }
1017
1018 return flowPaths;
1019 }
1020
1021 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001022 * Get summary of all installed flows by all installers in a given range
1023 *
1024 * @param flowId the data path endpoints of the flows to get.
1025 * @param maxFlows: the maximum number of flows to be returned
1026 * @return the Flow Paths if found, otherwise null.
1027 */
1028 @Override
1029 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1030 //
1031 // TODO: The implementation below is not optimal:
1032 // We fetch all flows, and then return only the subset that match
1033 // the query conditions.
1034 // We should use the appropriate Titan/Gremlin query to filter-out
1035 // the flows as appropriate.
1036 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001037 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1038
1039 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001040
1041 if (allFlows == null) {
1042 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001043 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001044 }
1045
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001046 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001047
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001048 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001049 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001050
1051 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001052 //if (flow.flowId().value() < flowId.value()) {
1053 // continue;
1054 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001055
1056 // Summarize by making null flow entry fields that are not relevant to report
1057 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1058 flowEntry.setFlowEntryActions(null);
1059 flowEntry.setFlowEntryMatch(null);
1060 }
1061
1062 flowPaths.add(flow);
1063 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1064 break;
1065 }
1066 }
1067
1068 if (flowPaths.isEmpty()) {
1069 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001070 } else {
1071 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1072 }
1073
1074 return flowPaths;
1075 }
1076
1077 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001078 * Get all installed flows by all installers.
1079 *
1080 * @return the Flow Paths if found, otherwise null.
1081 */
1082 @Override
1083 public ArrayList<FlowPath> getAllFlows() {
1084 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001085 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001086
1087 try {
1088 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1089 log.debug("Get all FlowPaths: found FlowPaths");
1090 } else {
1091 log.debug("Get all FlowPaths: no FlowPaths found");
1092 }
1093 } catch (Exception e) {
1094 // TODO: handle exceptions
1095 conn.endTx(Transaction.ROLLBACK);
1096 log.error(":getAllFlowPaths failed");
1097 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001098 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1099 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001100 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001101 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001102
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001103 for (IFlowPath flowObj : flowPathsObj) {
1104 //
1105 // Extract the Flow state
1106 //
1107 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001108 if (flowPath != null)
1109 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001110 }
1111
1112 conn.endTx(Transaction.COMMIT);
1113
1114 return flowPaths;
1115 }
1116
1117 /**
1118 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1119 *
1120 * @param flowObj the object to extract the Flow Path State from.
1121 * @return the extracted Flow Path State.
1122 */
1123 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001124 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001125
1126 //
1127 // Extract the Flow state
1128 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001129 String flowIdStr = flowObj.getFlowId();
1130 String installerIdStr = flowObj.getInstallerId();
1131 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001132 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001133 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001134 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001135
1136 if ((flowIdStr == null) ||
1137 (installerIdStr == null) ||
1138 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001139 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001140 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001141 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001142 // TODO: A work-around, becauuse of some bogus database objects
1143 return null;
1144 }
1145
1146 flowPath.setFlowId(new FlowId(flowIdStr));
1147 flowPath.setInstallerId(new CallerId(installerIdStr));
1148 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001149 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001150 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001151 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001152 //
1153 // Extract the match conditions common for all Flow Entries
1154 //
1155 {
1156 FlowEntryMatch match = new FlowEntryMatch();
1157 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1158 if (matchEthernetFrameType != null)
1159 match.enableEthernetFrameType(matchEthernetFrameType);
1160 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1161 if (matchSrcIPv4Net != null)
1162 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1163 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1164 if (matchDstIPv4Net != null)
1165 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1166 String matchSrcMac = flowObj.getMatchSrcMac();
1167 if (matchSrcMac != null)
1168 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1169 String matchDstMac = flowObj.getMatchDstMac();
1170 if (matchDstMac != null)
1171 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1172 flowPath.setFlowEntryMatch(match);
1173 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001174
1175 //
1176 // Extract all Flow Entries
1177 //
1178 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1179 for (IFlowEntry flowEntryObj : flowEntries) {
1180 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001181 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1182 String switchDpidStr = flowEntryObj.getSwitchDpid();
1183 String userState = flowEntryObj.getUserState();
1184 String switchState = flowEntryObj.getSwitchState();
1185
1186 if ((flowEntryIdStr == null) ||
1187 (switchDpidStr == null) ||
1188 (userState == null) ||
1189 (switchState == null)) {
1190 // TODO: A work-around, becauuse of some bogus database objects
1191 continue;
1192 }
1193 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1194 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001195
1196 //
1197 // Extract the match conditions
1198 //
1199 FlowEntryMatch match = new FlowEntryMatch();
1200 Short matchInPort = flowEntryObj.getMatchInPort();
1201 if (matchInPort != null)
1202 match.enableInPort(new Port(matchInPort));
1203 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1204 if (matchEthernetFrameType != null)
1205 match.enableEthernetFrameType(matchEthernetFrameType);
1206 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1207 if (matchSrcIPv4Net != null)
1208 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1209 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1210 if (matchDstIPv4Net != null)
1211 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1212 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1213 if (matchSrcMac != null)
1214 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1215 String matchDstMac = flowEntryObj.getMatchDstMac();
1216 if (matchDstMac != null)
1217 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1218 flowEntry.setFlowEntryMatch(match);
1219
1220 //
1221 // Extract the actions
1222 //
1223 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1224 Short actionOutputPort = flowEntryObj.getActionOutput();
1225 if (actionOutputPort != null) {
1226 FlowEntryAction action = new FlowEntryAction();
1227 action.setActionOutput(new Port(actionOutputPort));
1228 actions.add(action);
1229 }
1230 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001231 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001232 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1233 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001234 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001235 // and FlowEntryErrorState.
1236 //
1237 flowPath.dataPath().flowEntries().add(flowEntry);
1238 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001239
1240 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001241 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001242
1243 /**
1244 * Add and maintain a shortest-path flow.
1245 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001246 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001247 *
1248 * @param flowPath the Flow Path with the endpoints and the match
1249 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001250 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001251 */
1252 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001253 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001254 String dataPathSummaryStr = null;
1255
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001256 //
1257 // Do the shortest path computation
1258 //
1259 DataPath dataPath =
1260 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1261 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001262 if (dataPath == null) {
1263 // We need the DataPath to populate the Network MAP
1264 dataPath = new DataPath();
1265 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1266 dataPath.setDstPort(flowPath.dataPath().dstPort());
1267 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001268
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001269 // Compute the Data Path summary
1270 dataPathSummaryStr = dataPath.dataPathSummary();
1271
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001272 //
1273 // Set the incoming port matching and the outgoing port output
1274 // actions for each flow entry.
1275 //
1276 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1277 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001278 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001279 flowEntry.setFlowEntryMatch(flowEntryMatch);
1280 flowEntryMatch.enableInPort(flowEntry.inPort());
1281
1282 // Set the outgoing port output action
1283 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1284 if (flowEntryActions == null) {
1285 flowEntryActions = new ArrayList<FlowEntryAction>();
1286 flowEntry.setFlowEntryActions(flowEntryActions);
1287 }
1288 FlowEntryAction flowEntryAction = new FlowEntryAction();
1289 flowEntryAction.setActionOutput(flowEntry.outPort());
1290 flowEntryActions.add(flowEntryAction);
1291 }
1292
1293 //
1294 // Prepare the computed Flow Path
1295 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001296 FlowPath computedFlowPath = new FlowPath();
1297 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1298 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1299 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001300 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001301
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001302 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001303 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001304 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001305
1306 // TODO: Mark the flow for maintenance purpose
1307
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001308 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001309 }
1310
1311 /**
1312 * Create a Flow from port to port.
1313 *
1314 * TODO: We don't need it for now.
1315 *
1316 * @param src_port the source port.
1317 * @param dest_port the destination port.
1318 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001319 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001320 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1321 // TODO: We don't need it for now.
1322 }
1323
1324 /**
1325 * Get all Flows matching a source and a destination port.
1326 *
1327 * TODO: Pankaj might be implementing it later.
1328 *
1329 * @param src_port the source port to match.
1330 * @param dest_port the destination port to match.
1331 * @return all flows matching the source and the destination port.
1332 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001333 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001334 public Iterable<FlowPath> getFlows(IPortObject src_port,
1335 IPortObject dest_port) {
1336 // TODO: Pankaj might be implementing it later.
1337 return null;
1338 }
1339
1340 /**
1341 * Get all Flows going out from a port.
1342 *
1343 * TODO: We need it now: Pankaj
1344 *
1345 * @param port the port to match.
1346 * @return the list of flows that are going out from the port.
1347 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001348 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001349 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001350 // TODO: We need it now: Pankaj
1351 return null;
1352 }
1353
1354 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001355 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001356 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001357 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001358 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001359 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001360 public void reconcileFlows(IPortObject portObject) {
1361 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1362 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001363
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001364 //
1365 // Collect all affected Flow IDs from the affected flow entries
1366 //
1367 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1368 for (IFlowEntry flowEntryObj: inFlowEntries) {
1369 IFlowPath flowObj = flowEntryObj.getFlow();
1370 if (flowObj != null)
1371 flowObjSet.add(flowObj);
1372 }
1373 for (IFlowEntry flowEntryObj: outFlowEntries) {
1374 IFlowPath flowObj = flowEntryObj.getFlow();
1375 if (flowObj != null)
1376 flowObjSet.add(flowObj);
1377 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001378
1379 // Reconcile the affected flows
1380 reconcileFlows(flowObjSet);
1381 }
1382
1383 /**
1384 * Reconcile all flows in a set.
1385 *
1386 * @param flowObjSet the set of flows that need to be reconciliated.
1387 */
1388 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1389 if (! flowObjSet.iterator().hasNext())
1390 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001391
1392 //
1393 // Remove the old Flow Entries, and add the new Flow Entries
1394 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001395
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001396 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001397 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001398 for (IFlowPath flowObj : flowObjSet) {
1399 FlowPath flowPath = extractFlowPath(flowObj);
1400 if (flowPath == null)
1401 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001402 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001403
1404 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001405 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001406 //
1407 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001408 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001409 for (IFlowEntry flowEntryObj : flowEntries) {
1410 String dpidStr = flowEntryObj.getSwitchDpid();
1411 if (dpidStr == null)
1412 continue;
1413 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001414 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001415 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1416 if (mySwitch == null)
1417 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001418 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001419 deleteFlowEntries.add(flowEntryObj);
1420 }
1421 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001422 flowObj.removeFlowEntry(flowEntryObj);
1423 conn.utils().removeFlowEntry(conn, flowEntryObj);
1424 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001425 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001426
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001427 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001428 //
1429 // Delete the flow entries from the switches
1430 //
1431 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1432 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001433 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1434 if (mySwitch == null) {
1435 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001436 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001437 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001438 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001439 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001440 }
1441
1442 //
1443 // Calculate the new shortest path and install it in the
1444 // Network MAP.
1445 //
1446 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1447 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001448 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001449 flowPath.dataPath().srcPort().toString(),
1450 flowPath.dataPath().dstPort().toString());
1451 continue;
1452 }
1453
1454 //
1455 // Add the flow entries to the switches
1456 //
1457 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1458 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001459 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1460 if (mySwitch == null) {
1461 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001462 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001463 continue;
1464 }
1465
1466 IFlowEntry flowEntryObj =
1467 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1468 if (flowEntryObj == null) {
1469 //
1470 // TODO: Remove the "new Object[] wrapper in the statement
1471 // below after the SLF4J logger is upgraded to
1472 // Version 1.7.5
1473 //
1474 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1475 new Object[] {
1476 flowEntry.dpid(),
1477 flowPath.dataPath().srcPort(),
1478 flowPath.dataPath().dstPort()
1479 });
1480 continue;
1481 }
1482 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001483 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001484 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1485 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001486 }
1487 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001488 }
1489
1490 /**
1491 * Reconcile all flows between a source and a destination port.
1492 *
1493 * TODO: We don't need it for now.
1494 *
1495 * @param src_port the source port.
1496 * @param dest_port the destination port.
1497 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001498 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001499 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1500 // TODO: We don't need it for now.
1501 }
1502
1503 /**
1504 * Compute the shortest path between a source and a destination ports.
1505 *
1506 * @param src_port the source port.
1507 * @param dest_port the destination port.
1508 * @return the computed shortest path between the source and the
1509 * destination ports. The flow entries in the path itself would
1510 * contain the incoming port matching and the outgoing port output
1511 * actions set. However, the path itself will NOT have the Flow ID,
1512 * Installer ID, and any additional matching conditions for the
1513 * flow entries (e.g., source or destination MAC address, etc).
1514 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001515 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001516 public FlowPath computeFlowPath(IPortObject src_port,
1517 IPortObject dest_port) {
1518 //
1519 // Prepare the arguments
1520 //
1521 String dpidStr = src_port.getSwitch().getDPID();
1522 Dpid srcDpid = new Dpid(dpidStr);
1523 Port srcPort = new Port(src_port.getNumber());
1524
1525 dpidStr = dest_port.getSwitch().getDPID();
1526 Dpid dstDpid = new Dpid(dpidStr);
1527 Port dstPort = new Port(dest_port.getNumber());
1528
1529 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1530 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1531
1532 //
1533 // Do the shortest path computation
1534 //
1535 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1536 if (dataPath == null)
1537 return null;
1538
1539 //
1540 // Set the incoming port matching and the outgoing port output
1541 // actions for each flow entry.
1542 //
1543 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1544 // Set the incoming port matching
1545 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1546 if (flowEntryMatch == null) {
1547 flowEntryMatch = new FlowEntryMatch();
1548 flowEntry.setFlowEntryMatch(flowEntryMatch);
1549 }
1550 flowEntryMatch.enableInPort(flowEntry.inPort());
1551
1552 // Set the outgoing port output action
1553 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1554 if (flowEntryActions == null) {
1555 flowEntryActions = new ArrayList<FlowEntryAction>();
1556 flowEntry.setFlowEntryActions(flowEntryActions);
1557 }
1558 FlowEntryAction flowEntryAction = new FlowEntryAction();
1559 flowEntryAction.setActionOutput(flowEntry.outPort());
1560 flowEntryActions.add(flowEntryAction);
1561 }
1562
1563 //
1564 // Prepare the return result
1565 //
1566 FlowPath flowPath = new FlowPath();
1567 flowPath.setDataPath(dataPath);
1568
1569 return flowPath;
1570 }
1571
1572 /**
1573 * Get all Flow Entries of a Flow.
1574 *
1575 * @param flow the flow whose flow entries should be returned.
1576 * @return the flow entries of the flow.
1577 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001578 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001579 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1580 return flow.dataPath().flowEntries();
1581 }
1582
1583 /**
1584 * Install a Flow Entry on a switch.
1585 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001586 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001587 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001588 * @param flowEntry the flow entry to install.
1589 * @return true on success, otherwise false.
1590 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001591 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001592 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1593 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001594 //
1595 // Create the OpenFlow Flow Modification Entry to push
1596 //
1597 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1598 .getMessage(OFType.FLOW_MOD);
1599 long cookie = flowEntry.flowEntryId().value();
1600
1601 short flowModCommand = OFFlowMod.OFPFC_ADD;
1602 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1603 flowModCommand = OFFlowMod.OFPFC_ADD;
1604 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1605 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1606 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1607 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1608 } else {
1609 // Unknown user state. Ignore the entry
1610 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1611 flowEntry.flowEntryId().toString(),
1612 flowEntry.flowEntryUserState());
1613 return false;
1614 }
1615
1616 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001617 // Fetch the match conditions.
1618 //
1619 // NOTE: The Flow matching conditions common for all Flow Entries are
1620 // used ONLY if a Flow Entry does NOT have the corresponding matching
1621 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001622 //
1623 OFMatch match = new OFMatch();
1624 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001625 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1626 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1627
1628 // Match the Incoming Port
1629 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001630 if (matchInPort != null) {
1631 match.setInputPort(matchInPort.value());
1632 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1633 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001634
1635 // Match the Ethernet Frame Type
1636 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1637 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1638 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1639 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001640 if (matchEthernetFrameType != null) {
1641 match.setDataLayerType(matchEthernetFrameType);
1642 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1643 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001644
1645 // Match the Source IPv4 Network prefix
1646 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1647 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1648 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1649 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001650 if (matchSrcIPv4Net != null) {
1651 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1652 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001653
1654 // Natch the Destination IPv4 Network prefix
1655 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1656 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1657 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1658 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001659 if (matchDstIPv4Net != null) {
1660 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1661 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001662
1663 // Match the Source MAC address
1664 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1665 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1666 matchSrcMac = flowPathMatch.srcMac();
1667 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001668 if (matchSrcMac != null) {
1669 match.setDataLayerSource(matchSrcMac.toString());
1670 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1671 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001672
1673 // Match the Destination MAC address
1674 MACAddress matchDstMac = flowEntryMatch.dstMac();
1675 if ((matchDstMac == null) && (flowPathMatch != null)) {
1676 matchDstMac = flowPathMatch.dstMac();
1677 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001678 if (matchDstMac != null) {
1679 match.setDataLayerDestination(matchDstMac.toString());
1680 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1681 }
1682
1683 //
1684 // Fetch the actions
1685 //
1686 // TODO: For now we support only the "OUTPUT" actions.
1687 //
1688 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1689 List<OFAction> actions = new ArrayList<OFAction>();
1690 ArrayList<FlowEntryAction> flowEntryActions =
1691 flowEntry.flowEntryActions();
1692 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1693 FlowEntryAction.ActionOutput actionOutput =
1694 flowEntryAction.actionOutput();
1695 if (actionOutput != null) {
1696 short actionOutputPort = actionOutput.port().value();
1697 OFActionOutput action = new OFActionOutput();
1698 // XXX: The max length is hard-coded for now
1699 action.setMaxLength((short)0xffff);
1700 action.setPort(actionOutputPort);
1701 actions.add(action);
1702 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1703 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1704 fm.setOutPort(actionOutputPort);
1705 }
1706 }
1707 }
1708
1709 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1710 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1711 .setPriority(PRIORITY_DEFAULT)
1712 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1713 .setCookie(cookie)
1714 .setCommand(flowModCommand)
1715 .setMatch(match)
1716 .setActions(actions)
1717 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1718
1719 //
1720 // TODO: Set the following flag
1721 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1722 // See method ForwardingBase::pushRoute()
1723 //
1724
1725 //
1726 // Write the message to the switch
1727 //
1728 try {
1729 messageDamper.write(mySwitch, fm, null);
1730 mySwitch.flush();
1731 } catch (IOException e) {
1732 log.error("Failure writing flow mod from network map", e);
1733 return false;
1734 }
1735 return true;
1736 }
1737
1738 /**
1739 * Remove a Flow Entry from a switch.
1740 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001741 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001742 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001743 * @param flowEntry the flow entry to remove.
1744 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001745 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001746 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001747 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1748 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001749 //
1750 // The installFlowEntry() method implements both installation
1751 // and removal of flow entries.
1752 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001753 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001754 }
1755
1756 /**
1757 * Install a Flow Entry on a remote controller.
1758 *
1759 * TODO: We need it now: Jono
1760 * - For now it will make a REST call to the remote controller.
1761 * - Internally, it needs to know the name of the remote controller.
1762 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001763 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001764 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001765 * @return true on success, otherwise false.
1766 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001767 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001768 public boolean installRemoteFlowEntry(FlowPath flowPath,
1769 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001770 // TODO: We need it now: Jono
1771 // - For now it will make a REST call to the remote controller.
1772 // - Internally, it needs to know the name of the remote controller.
1773 return true;
1774 }
1775
1776 /**
1777 * Remove a flow entry on a remote controller.
1778 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001779 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001780 * @param flowEntry the flow entry to remove.
1781 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001782 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001783 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001784 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1785 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001786 //
1787 // The installRemoteFlowEntry() method implements both installation
1788 // and removal of flow entries.
1789 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001790 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001791 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001792}