blob: 8729ee4967a9ed26c210ad082bfcff3204d71c0a [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 Radoslavov706df052013-03-06 10:49:07 -08001124 //
1125 // Extract the Flow state
1126 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001127 String flowIdStr = flowObj.getFlowId();
1128 String installerIdStr = flowObj.getInstallerId();
1129 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001130 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001131 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001132 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001133
1134 if ((flowIdStr == null) ||
1135 (installerIdStr == null) ||
1136 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001137 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001138 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001139 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001140 // TODO: A work-around, becauuse of some bogus database objects
1141 return null;
1142 }
1143
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001144 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001145 flowPath.setFlowId(new FlowId(flowIdStr));
1146 flowPath.setInstallerId(new CallerId(installerIdStr));
1147 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001148 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001149 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001150 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001151 //
1152 // Extract the match conditions common for all Flow Entries
1153 //
1154 {
1155 FlowEntryMatch match = new FlowEntryMatch();
1156 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1157 if (matchEthernetFrameType != null)
1158 match.enableEthernetFrameType(matchEthernetFrameType);
1159 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1160 if (matchSrcIPv4Net != null)
1161 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1162 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1163 if (matchDstIPv4Net != null)
1164 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1165 String matchSrcMac = flowObj.getMatchSrcMac();
1166 if (matchSrcMac != null)
1167 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1168 String matchDstMac = flowObj.getMatchDstMac();
1169 if (matchDstMac != null)
1170 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1171 flowPath.setFlowEntryMatch(match);
1172 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001173
1174 //
1175 // Extract all Flow Entries
1176 //
1177 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1178 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001179 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1180 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001181 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001182 flowPath.dataPath().flowEntries().add(flowEntry);
1183 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001184
1185 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001186 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001187
1188 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001189 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1190 *
1191 * @param flowEntryObj the object to extract the Flow Entry State from.
1192 * @return the extracted Flow Entry State.
1193 */
1194 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1195 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1196 String switchDpidStr = flowEntryObj.getSwitchDpid();
1197 String userState = flowEntryObj.getUserState();
1198 String switchState = flowEntryObj.getSwitchState();
1199
1200 if ((flowEntryIdStr == null) ||
1201 (switchDpidStr == null) ||
1202 (userState == null) ||
1203 (switchState == null)) {
1204 // TODO: A work-around, becauuse of some bogus database objects
1205 return null;
1206 }
1207
1208 FlowEntry flowEntry = new FlowEntry();
1209 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1210 flowEntry.setDpid(new Dpid(switchDpidStr));
1211
1212 //
1213 // Extract the match conditions
1214 //
1215 FlowEntryMatch match = new FlowEntryMatch();
1216 Short matchInPort = flowEntryObj.getMatchInPort();
1217 if (matchInPort != null)
1218 match.enableInPort(new Port(matchInPort));
1219 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1220 if (matchEthernetFrameType != null)
1221 match.enableEthernetFrameType(matchEthernetFrameType);
1222 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1223 if (matchSrcIPv4Net != null)
1224 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1225 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1226 if (matchDstIPv4Net != null)
1227 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1228 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1229 if (matchSrcMac != null)
1230 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1231 String matchDstMac = flowEntryObj.getMatchDstMac();
1232 if (matchDstMac != null)
1233 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1234 flowEntry.setFlowEntryMatch(match);
1235
1236 //
1237 // Extract the actions
1238 //
1239 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1240 Short actionOutputPort = flowEntryObj.getActionOutput();
1241 if (actionOutputPort != null) {
1242 FlowEntryAction action = new FlowEntryAction();
1243 action.setActionOutput(new Port(actionOutputPort));
1244 actions.add(action);
1245 }
1246 flowEntry.setFlowEntryActions(actions);
1247 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1248 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1249 //
1250 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1251 // and FlowEntryErrorState.
1252 //
1253 return flowEntry;
1254 }
1255
1256 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001257 * Add and maintain a shortest-path flow.
1258 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001259 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001260 *
1261 * @param flowPath the Flow Path with the endpoints and the match
1262 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001263 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001264 */
1265 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001266 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001267 String dataPathSummaryStr = null;
1268
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001269 //
1270 // Do the shortest path computation
1271 //
1272 DataPath dataPath =
1273 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1274 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001275 if (dataPath == null) {
1276 // We need the DataPath to populate the Network MAP
1277 dataPath = new DataPath();
1278 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1279 dataPath.setDstPort(flowPath.dataPath().dstPort());
1280 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001281
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001282 // Compute the Data Path summary
1283 dataPathSummaryStr = dataPath.dataPathSummary();
1284
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001285 //
1286 // Set the incoming port matching and the outgoing port output
1287 // actions for each flow entry.
1288 //
1289 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1290 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001291 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001292 flowEntry.setFlowEntryMatch(flowEntryMatch);
1293 flowEntryMatch.enableInPort(flowEntry.inPort());
1294
1295 // Set the outgoing port output action
1296 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1297 if (flowEntryActions == null) {
1298 flowEntryActions = new ArrayList<FlowEntryAction>();
1299 flowEntry.setFlowEntryActions(flowEntryActions);
1300 }
1301 FlowEntryAction flowEntryAction = new FlowEntryAction();
1302 flowEntryAction.setActionOutput(flowEntry.outPort());
1303 flowEntryActions.add(flowEntryAction);
1304 }
1305
1306 //
1307 // Prepare the computed Flow Path
1308 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001309 FlowPath computedFlowPath = new FlowPath();
1310 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1311 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1312 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001313 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001314
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001315 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001316 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001317 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001318
1319 // TODO: Mark the flow for maintenance purpose
1320
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001321 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001322 }
1323
1324 /**
1325 * Create a Flow from port to port.
1326 *
1327 * TODO: We don't need it for now.
1328 *
1329 * @param src_port the source port.
1330 * @param dest_port the destination port.
1331 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001332 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001333 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1334 // TODO: We don't need it for now.
1335 }
1336
1337 /**
1338 * Get all Flows matching a source and a destination port.
1339 *
1340 * TODO: Pankaj might be implementing it later.
1341 *
1342 * @param src_port the source port to match.
1343 * @param dest_port the destination port to match.
1344 * @return all flows matching the source and the destination port.
1345 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001346 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001347 public Iterable<FlowPath> getFlows(IPortObject src_port,
1348 IPortObject dest_port) {
1349 // TODO: Pankaj might be implementing it later.
1350 return null;
1351 }
1352
1353 /**
1354 * Get all Flows going out from a port.
1355 *
1356 * TODO: We need it now: Pankaj
1357 *
1358 * @param port the port to match.
1359 * @return the list of flows that are going out from the port.
1360 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001361 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001362 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001363 // TODO: We need it now: Pankaj
1364 return null;
1365 }
1366
1367 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001368 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001369 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001370 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001371 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001372 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001373 public void reconcileFlows(IPortObject portObject) {
1374 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1375 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001376
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001377 //
1378 // Collect all affected Flow IDs from the affected flow entries
1379 //
1380 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1381 for (IFlowEntry flowEntryObj: inFlowEntries) {
1382 IFlowPath flowObj = flowEntryObj.getFlow();
1383 if (flowObj != null)
1384 flowObjSet.add(flowObj);
1385 }
1386 for (IFlowEntry flowEntryObj: outFlowEntries) {
1387 IFlowPath flowObj = flowEntryObj.getFlow();
1388 if (flowObj != null)
1389 flowObjSet.add(flowObj);
1390 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001391
1392 // Reconcile the affected flows
1393 reconcileFlows(flowObjSet);
1394 }
1395
1396 /**
1397 * Reconcile all flows in a set.
1398 *
1399 * @param flowObjSet the set of flows that need to be reconciliated.
1400 */
1401 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1402 if (! flowObjSet.iterator().hasNext())
1403 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001404
1405 //
1406 // Remove the old Flow Entries, and add the new Flow Entries
1407 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001408
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001409 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001410 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001411 for (IFlowPath flowObj : flowObjSet) {
1412 FlowPath flowPath = extractFlowPath(flowObj);
1413 if (flowPath == null)
1414 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001415 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001416
1417 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001418 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001419 //
1420 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001421 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001422 for (IFlowEntry flowEntryObj : flowEntries) {
1423 String dpidStr = flowEntryObj.getSwitchDpid();
1424 if (dpidStr == null)
1425 continue;
1426 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001427 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001428 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1429 if (mySwitch == null)
1430 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001431 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001432 deleteFlowEntries.add(flowEntryObj);
1433 }
1434 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001435 flowObj.removeFlowEntry(flowEntryObj);
1436 conn.utils().removeFlowEntry(conn, flowEntryObj);
1437 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001438 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001439
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001440 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001441 //
1442 // Delete the flow entries from the switches
1443 //
1444 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1445 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001446 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1447 if (mySwitch == null) {
1448 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001449 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001450 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001451 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001452 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001453 }
1454
1455 //
1456 // Calculate the new shortest path and install it in the
1457 // Network MAP.
1458 //
1459 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1460 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001461 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001462 flowPath.dataPath().srcPort().toString(),
1463 flowPath.dataPath().dstPort().toString());
1464 continue;
1465 }
1466
1467 //
1468 // Add the flow entries to the switches
1469 //
1470 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1471 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001472 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1473 if (mySwitch == null) {
1474 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001475 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001476 continue;
1477 }
1478
1479 IFlowEntry flowEntryObj =
1480 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1481 if (flowEntryObj == null) {
1482 //
1483 // TODO: Remove the "new Object[] wrapper in the statement
1484 // below after the SLF4J logger is upgraded to
1485 // Version 1.7.5
1486 //
1487 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1488 new Object[] {
1489 flowEntry.dpid(),
1490 flowPath.dataPath().srcPort(),
1491 flowPath.dataPath().dstPort()
1492 });
1493 continue;
1494 }
1495 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001496 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001497 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1498 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001499 }
1500 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001501 }
1502
1503 /**
1504 * Reconcile all flows between a source and a destination port.
1505 *
1506 * TODO: We don't need it for now.
1507 *
1508 * @param src_port the source port.
1509 * @param dest_port the destination port.
1510 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001511 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001512 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1513 // TODO: We don't need it for now.
1514 }
1515
1516 /**
1517 * Compute the shortest path between a source and a destination ports.
1518 *
1519 * @param src_port the source port.
1520 * @param dest_port the destination port.
1521 * @return the computed shortest path between the source and the
1522 * destination ports. The flow entries in the path itself would
1523 * contain the incoming port matching and the outgoing port output
1524 * actions set. However, the path itself will NOT have the Flow ID,
1525 * Installer ID, and any additional matching conditions for the
1526 * flow entries (e.g., source or destination MAC address, etc).
1527 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001528 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001529 public FlowPath computeFlowPath(IPortObject src_port,
1530 IPortObject dest_port) {
1531 //
1532 // Prepare the arguments
1533 //
1534 String dpidStr = src_port.getSwitch().getDPID();
1535 Dpid srcDpid = new Dpid(dpidStr);
1536 Port srcPort = new Port(src_port.getNumber());
1537
1538 dpidStr = dest_port.getSwitch().getDPID();
1539 Dpid dstDpid = new Dpid(dpidStr);
1540 Port dstPort = new Port(dest_port.getNumber());
1541
1542 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1543 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1544
1545 //
1546 // Do the shortest path computation
1547 //
1548 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1549 if (dataPath == null)
1550 return null;
1551
1552 //
1553 // Set the incoming port matching and the outgoing port output
1554 // actions for each flow entry.
1555 //
1556 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1557 // Set the incoming port matching
1558 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1559 if (flowEntryMatch == null) {
1560 flowEntryMatch = new FlowEntryMatch();
1561 flowEntry.setFlowEntryMatch(flowEntryMatch);
1562 }
1563 flowEntryMatch.enableInPort(flowEntry.inPort());
1564
1565 // Set the outgoing port output action
1566 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1567 if (flowEntryActions == null) {
1568 flowEntryActions = new ArrayList<FlowEntryAction>();
1569 flowEntry.setFlowEntryActions(flowEntryActions);
1570 }
1571 FlowEntryAction flowEntryAction = new FlowEntryAction();
1572 flowEntryAction.setActionOutput(flowEntry.outPort());
1573 flowEntryActions.add(flowEntryAction);
1574 }
1575
1576 //
1577 // Prepare the return result
1578 //
1579 FlowPath flowPath = new FlowPath();
1580 flowPath.setDataPath(dataPath);
1581
1582 return flowPath;
1583 }
1584
1585 /**
1586 * Get all Flow Entries of a Flow.
1587 *
1588 * @param flow the flow whose flow entries should be returned.
1589 * @return the flow entries of the flow.
1590 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001591 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001592 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1593 return flow.dataPath().flowEntries();
1594 }
1595
1596 /**
1597 * Install a Flow Entry on a switch.
1598 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001599 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001600 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001601 * @param flowEntry the flow entry to install.
1602 * @return true on success, otherwise false.
1603 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001604 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001605 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1606 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001607 //
1608 // Create the OpenFlow Flow Modification Entry to push
1609 //
1610 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1611 .getMessage(OFType.FLOW_MOD);
1612 long cookie = flowEntry.flowEntryId().value();
1613
1614 short flowModCommand = OFFlowMod.OFPFC_ADD;
1615 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1616 flowModCommand = OFFlowMod.OFPFC_ADD;
1617 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1618 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1619 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1620 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1621 } else {
1622 // Unknown user state. Ignore the entry
1623 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1624 flowEntry.flowEntryId().toString(),
1625 flowEntry.flowEntryUserState());
1626 return false;
1627 }
1628
1629 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001630 // Fetch the match conditions.
1631 //
1632 // NOTE: The Flow matching conditions common for all Flow Entries are
1633 // used ONLY if a Flow Entry does NOT have the corresponding matching
1634 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001635 //
1636 OFMatch match = new OFMatch();
1637 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001638 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1639 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1640
1641 // Match the Incoming Port
1642 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001643 if (matchInPort != null) {
1644 match.setInputPort(matchInPort.value());
1645 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1646 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001647
1648 // Match the Ethernet Frame Type
1649 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1650 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1651 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1652 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001653 if (matchEthernetFrameType != null) {
1654 match.setDataLayerType(matchEthernetFrameType);
1655 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1656 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001657
1658 // Match the Source IPv4 Network prefix
1659 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1660 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1661 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1662 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001663 if (matchSrcIPv4Net != null) {
1664 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1665 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001666
1667 // Natch the Destination IPv4 Network prefix
1668 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1669 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1670 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1671 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001672 if (matchDstIPv4Net != null) {
1673 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1674 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001675
1676 // Match the Source MAC address
1677 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1678 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1679 matchSrcMac = flowPathMatch.srcMac();
1680 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001681 if (matchSrcMac != null) {
1682 match.setDataLayerSource(matchSrcMac.toString());
1683 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1684 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001685
1686 // Match the Destination MAC address
1687 MACAddress matchDstMac = flowEntryMatch.dstMac();
1688 if ((matchDstMac == null) && (flowPathMatch != null)) {
1689 matchDstMac = flowPathMatch.dstMac();
1690 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001691 if (matchDstMac != null) {
1692 match.setDataLayerDestination(matchDstMac.toString());
1693 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1694 }
1695
1696 //
1697 // Fetch the actions
1698 //
1699 // TODO: For now we support only the "OUTPUT" actions.
1700 //
1701 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1702 List<OFAction> actions = new ArrayList<OFAction>();
1703 ArrayList<FlowEntryAction> flowEntryActions =
1704 flowEntry.flowEntryActions();
1705 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1706 FlowEntryAction.ActionOutput actionOutput =
1707 flowEntryAction.actionOutput();
1708 if (actionOutput != null) {
1709 short actionOutputPort = actionOutput.port().value();
1710 OFActionOutput action = new OFActionOutput();
1711 // XXX: The max length is hard-coded for now
1712 action.setMaxLength((short)0xffff);
1713 action.setPort(actionOutputPort);
1714 actions.add(action);
1715 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1716 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1717 fm.setOutPort(actionOutputPort);
1718 }
1719 }
1720 }
1721
1722 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1723 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1724 .setPriority(PRIORITY_DEFAULT)
1725 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1726 .setCookie(cookie)
1727 .setCommand(flowModCommand)
1728 .setMatch(match)
1729 .setActions(actions)
1730 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1731
1732 //
1733 // TODO: Set the following flag
1734 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1735 // See method ForwardingBase::pushRoute()
1736 //
1737
1738 //
1739 // Write the message to the switch
1740 //
1741 try {
1742 messageDamper.write(mySwitch, fm, null);
1743 mySwitch.flush();
1744 } catch (IOException e) {
1745 log.error("Failure writing flow mod from network map", e);
1746 return false;
1747 }
1748 return true;
1749 }
1750
1751 /**
1752 * Remove a Flow Entry from a switch.
1753 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001754 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001755 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001756 * @param flowEntry the flow entry to remove.
1757 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001758 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001759 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001760 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1761 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001762 //
1763 // The installFlowEntry() method implements both installation
1764 // and removal of flow entries.
1765 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001766 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001767 }
1768
1769 /**
1770 * Install a Flow Entry on a remote controller.
1771 *
1772 * TODO: We need it now: Jono
1773 * - For now it will make a REST call to the remote controller.
1774 * - Internally, it needs to know the name of the remote controller.
1775 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001776 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001777 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001778 * @return true on success, otherwise false.
1779 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001780 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001781 public boolean installRemoteFlowEntry(FlowPath flowPath,
1782 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001783 // TODO: We need it now: Jono
1784 // - For now it will make a REST call to the remote controller.
1785 // - Internally, it needs to know the name of the remote controller.
1786 return true;
1787 }
1788
1789 /**
1790 * Remove a flow entry on a remote controller.
1791 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001792 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001793 * @param flowEntry the flow entry to remove.
1794 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001795 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001796 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001797 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1798 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001799 //
1800 // The installRemoteFlowEntry() method implements both installation
1801 // and removal of flow entries.
1802 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001803 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001804 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001805}