blob: 15aed60551ce29164104c714aa0c6aab733dfcc6 [file] [log] [blame]
Jonathan Hart0961fe82014-04-03 09:56:25 -07001package net.onrc.onos.apps.forwarding;
Jonathan Hart1caaa932013-11-04 15:28:28 -08002
Jonathan Hart41d1e912013-11-24 16:50:25 -08003import java.util.ArrayList;
Jonathan Harte93aed42013-12-05 18:39:50 -08004import java.util.Collection;
Jonathan Hartd33a6cf2013-12-10 14:29:08 -08005import java.util.HashMap;
Jonathan Hart1caaa932013-11-04 15:28:28 -08006import java.util.Iterator;
Jonathan Hart41d1e912013-11-24 16:50:25 -08007import java.util.List;
Jonathan Harte93aed42013-12-05 18:39:50 -08008import java.util.Map;
TeruU7feef8a2014-04-03 00:15:49 -07009import java.util.Map.Entry;
TeruU417fe022014-02-04 12:59:30 -080010import java.util.concurrent.Executors;
11import java.util.concurrent.ScheduledExecutorService;
12import java.util.concurrent.TimeUnit;
Jonathan Hart1caaa932013-11-04 15:28:28 -080013
14import net.floodlightcontroller.core.FloodlightContext;
15import net.floodlightcontroller.core.IFloodlightProviderService;
16import net.floodlightcontroller.core.IOFMessageListener;
17import net.floodlightcontroller.core.IOFSwitch;
Jonathan Harte93aed42013-12-05 18:39:50 -080018import net.floodlightcontroller.core.module.FloodlightModuleContext;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080021import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0961fe82014-04-03 09:56:25 -070022import net.onrc.onos.apps.proxyarp.BroadcastPacketOutNotification;
23import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart6df90172014-04-03 10:13:11 -070024import net.onrc.onos.core.datagrid.IDatagridService;
25import net.onrc.onos.core.datagrid.IEventChannel;
26import net.onrc.onos.core.datagrid.IEventChannelListener;
Jonathan Hart23701d12014-04-03 10:45:48 -070027import net.onrc.onos.core.devicemanager.IOnosDeviceService;
28import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Jonathan Hartaa380972014-04-03 10:24:46 -070029import net.onrc.onos.core.intent.Intent;
Jonathan Harta99ec672014-04-03 11:30:34 -070030import net.onrc.onos.core.intent.Intent.IntentState;
Jonathan Hartaa380972014-04-03 10:24:46 -070031import net.onrc.onos.core.intent.IntentMap;
32import net.onrc.onos.core.intent.IntentOperation;
33import net.onrc.onos.core.intent.IntentOperationList;
34import net.onrc.onos.core.intent.PathIntent;
35import net.onrc.onos.core.intent.ShortestPathIntent;
Jonathan Hartaa380972014-04-03 10:24:46 -070036import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
37import net.onrc.onos.core.intent.runtime.IntentStateList;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070038import net.onrc.onos.core.packet.Ethernet;
39import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart472062d2014-04-03 10:56:48 -070040import net.onrc.onos.core.topology.Device;
41import net.onrc.onos.core.topology.INetworkGraphService;
42import net.onrc.onos.core.topology.LinkEvent;
43import net.onrc.onos.core.topology.NetworkGraph;
44import net.onrc.onos.core.topology.Switch;
Jonathan Hart23701d12014-04-03 10:45:48 -070045import net.onrc.onos.core.util.Dpid;
46import net.onrc.onos.core.util.FlowPath;
47import net.onrc.onos.core.util.Port;
48import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart1caaa932013-11-04 15:28:28 -080049
50import org.openflow.protocol.OFMessage;
51import org.openflow.protocol.OFPacketIn;
Jonathan Hart41d1e912013-11-24 16:50:25 -080052import org.openflow.protocol.OFPacketOut;
53import org.openflow.protocol.OFPort;
Jonathan Hart1caaa932013-11-04 15:28:28 -080054import org.openflow.protocol.OFType;
Jonathan Hart41d1e912013-11-24 16:50:25 -080055import org.openflow.protocol.action.OFAction;
56import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1caaa932013-11-04 15:28:28 -080057import org.openflow.util.HexString;
58import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
60
Jonathan Hartd857ad62013-12-14 18:08:17 -080061import com.google.common.collect.LinkedListMultimap;
62import com.google.common.collect.ListMultimap;
Jonathan Hart5e448782013-12-10 12:36:35 -080063
64public class Forwarding implements IOFMessageListener, IFloodlightModule,
Ray Milkey269ffb92014-04-03 14:43:30 -070065 IForwardingService, IEventChannelListener<Long, IntentStateList> {
Ray Milkeyec838942014-04-09 11:28:43 -070066 private static final Logger log = LoggerFactory.getLogger(Forwarding.class);
TeruU7feef8a2014-04-03 00:15:49 -070067
Ray Milkey2476cac2014-04-08 11:03:21 -070068 private static final int SLEEP_TIME_FOR_DB_DEVICE_INSTALLED = 100; // milliseconds
Ray Milkeyec838942014-04-09 11:28:43 -070069 private static final int NUMBER_OF_THREAD_FOR_EXECUTOR = 1;
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070070
Ray Milkeyec838942014-04-09 11:28:43 -070071 private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(NUMBER_OF_THREAD_FOR_EXECUTOR);
Jonathan Harte93aed42013-12-05 18:39:50 -080072
Ray Milkey269ffb92014-04-03 14:43:30 -070073 private final String callerId = "Forwarding";
Jonathan Harte93aed42013-12-05 18:39:50 -080074
Ray Milkey269ffb92014-04-03 14:43:30 -070075 private IFloodlightProviderService floodlightProvider;
76 private IFlowPusherService flowPusher;
77 private IDatagridService datagrid;
78
79 private IEventChannel<Long, BroadcastPacketOutNotification> eventChannel;
80 private static final String SINGLE_PACKET_OUT_CHANNEL_NAME = "onos.forwarding.packet_out";
81
82 private IControllerRegistryService controllerRegistryService;
83
84 private INetworkGraphService networkGraphService;
85 private NetworkGraph networkGraph;
86 private IPathCalcRuntimeService pathRuntime;
87 private IntentMap intentMap;
88
89 // TODO it seems there is a Guava collection that will time out entries.
90 // We should see if this will work here.
91 private Map<Path, PushedFlow> pendingFlows;
92 private ListMultimap<String, PacketToPush> waitingPackets;
93
94 private final Object lock = new Object();
95
Jonathan Hart8ed69c52014-04-09 13:29:16 -070096 private static class PacketToPush {
Ray Milkey269ffb92014-04-03 14:43:30 -070097 public final OFPacketOut packet;
98 public final long dpid;
99
100 public PacketToPush(OFPacketOut packet, long dpid) {
101 this.packet = packet;
102 this.dpid = dpid;
103 }
104 }
105
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700106 private static class PushedFlow {
Ray Milkey269ffb92014-04-03 14:43:30 -0700107 public final String intentId;
108 public boolean installed = false;
109 public short firstOutPort;
110
111 public PushedFlow(String flowId) {
112 this.intentId = flowId;
113 }
114 }
115
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700116 private static final class Path {
Ray Milkey269ffb92014-04-03 14:43:30 -0700117 public final MACAddress srcMac;
118 public final MACAddress dstMac;
119
120 public Path(MACAddress srcMac, MACAddress dstMac) {
121 this.srcMac = srcMac;
122 this.dstMac = dstMac;
123 }
124
125 @Override
126 public boolean equals(Object other) {
127 if (!(other instanceof Path)) {
128 return false;
129 }
130
131 Path otherPath = (Path) other;
132 return srcMac.equals(otherPath.srcMac) &&
133 dstMac.equals(otherPath.dstMac);
134 }
135
136 @Override
137 public int hashCode() {
138 int hash = 17;
139 hash = 31 * hash + srcMac.hashCode();
140 hash = 31 * hash + dstMac.hashCode();
141 return hash;
142 }
143
144 @Override
145 public String toString() {
146 return "(" + srcMac + ") => (" + dstMac + ")";
147 }
148 }
149
150 @Override
151 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
152 List<Class<? extends IFloodlightService>> services =
153 new ArrayList<Class<? extends IFloodlightService>>(1);
154 services.add(IForwardingService.class);
155 return services;
156 }
157
158 @Override
159 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
160 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
161 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(1);
162 impls.put(IForwardingService.class, this);
163 return impls;
164 }
165
166 @Override
167 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
168 List<Class<? extends IFloodlightService>> dependencies =
169 new ArrayList<Class<? extends IFloodlightService>>();
170 dependencies.add(IFloodlightProviderService.class);
171 dependencies.add(IFlowPusherService.class);
172 dependencies.add(IControllerRegistryService.class);
173 dependencies.add(IOnosDeviceService.class);
174 dependencies.add(IDatagridService.class);
175 dependencies.add(INetworkGraphService.class);
176 dependencies.add(IPathCalcRuntimeService.class);
177 // We don't use the IProxyArpService directly, but reactive forwarding
178 // requires it to be loaded and answering ARP requests
179 dependencies.add(IProxyArpService.class);
180 return dependencies;
181 }
182
183 @Override
184 public void init(FloodlightModuleContext context) {
185 floodlightProvider =
186 context.getServiceImpl(IFloodlightProviderService.class);
187 flowPusher = context.getServiceImpl(IFlowPusherService.class);
188 datagrid = context.getServiceImpl(IDatagridService.class);
189 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
190 networkGraphService = context.getServiceImpl(INetworkGraphService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700191 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hart0444d932014-01-22 15:06:17 -0800192
Ray Milkey269ffb92014-04-03 14:43:30 -0700193 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
TeruU7feef8a2014-04-03 00:15:49 -0700194
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 pendingFlows = new HashMap<Path, PushedFlow>();
196 waitingPackets = LinkedListMultimap.create();
197 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800198
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 @Override
200 public void startUp(FloodlightModuleContext context) {
Jonathan Hart1caaa932013-11-04 15:28:28 -0800201
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 eventChannel = datagrid.createChannel(SINGLE_PACKET_OUT_CHANNEL_NAME,
203 Long.class,
204 BroadcastPacketOutNotification.class);
205 networkGraph = networkGraphService.getNetworkGraph();
206 intentMap = pathRuntime.getPathIntents();
207 datagrid.addListener("onos.pathintent_state", this, Long.class, IntentStateList.class);
208 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800209
Ray Milkey269ffb92014-04-03 14:43:30 -0700210 @Override
211 public String getName() {
212 return "onosforwarding";
213 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800214
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 @Override
216 public boolean isCallbackOrderingPrereq(OFType type, String name) {
217 return (type == OFType.PACKET_IN) &&
218 (name.equals("devicemanager") || name.equals("proxyarpmanager")
219 || name.equals("onosdevicemanager"));
220 }
Jonathan Hart7804bea2014-01-07 10:50:52 -0800221
Ray Milkey269ffb92014-04-03 14:43:30 -0700222 @Override
223 public boolean isCallbackOrderingPostreq(OFType type, String name) {
224 return false;
225 }
TeruU417fe022014-02-04 12:59:30 -0800226
Ray Milkey269ffb92014-04-03 14:43:30 -0700227 @Override
228 public Command receive(
229 IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
TeruUd1ba0e22014-02-10 11:44:15 -0800230
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700231 if (msg.getType() != OFType.PACKET_IN || !(msg instanceof OFPacketIn)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 return Command.CONTINUE;
233 }
TeruUd1ba0e22014-02-10 11:44:15 -0800234
Ray Milkey269ffb92014-04-03 14:43:30 -0700235 OFPacketIn pi = (OFPacketIn) msg;
TeruU7feef8a2014-04-03 00:15:49 -0700236
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 Ethernet eth = IFloodlightProviderService.bcStore.
238 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
TeruU417fe022014-02-04 12:59:30 -0800239
Ray Milkey269ffb92014-04-03 14:43:30 -0700240 log.debug("Receive PACKET_IN swId {}, portId {}", sw.getId(), pi.getInPort());
TeruU417fe022014-02-04 12:59:30 -0800241
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700242 if (eth.getEtherType() != Ethernet.TYPE_IPV4) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 return Command.CONTINUE;
244 }
TeruU417fe022014-02-04 12:59:30 -0800245
Ray Milkey269ffb92014-04-03 14:43:30 -0700246 if (eth.isBroadcast() || eth.isMulticast()) {
247 handleBroadcast(sw, pi, eth);
248 } else {
249 // Unicast
250 handlePacketIn(sw, pi, eth);
251 }
TeruU417fe022014-02-04 12:59:30 -0800252
Ray Milkey269ffb92014-04-03 14:43:30 -0700253 return Command.STOP;
254 }
TeruU417fe022014-02-04 12:59:30 -0800255
Ray Milkey269ffb92014-04-03 14:43:30 -0700256 private void handleBroadcast(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
257 if (log.isTraceEnabled()) {
258 log.trace("Sending broadcast packet to other ONOS instances");
259 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800260
Ray Milkey269ffb92014-04-03 14:43:30 -0700261 //We don't use address information, so 0 is put into the third argument.
262 BroadcastPacketOutNotification key =
263 new BroadcastPacketOutNotification(
264 eth.serialize(),
265 0, sw.getId(),
266 pi.getInPort());
267 eventChannel.addTransientEntry(eth.getDestinationMAC().toLong(), key);
268 }
Pavlin Radoslavova3818db2014-03-20 19:26:08 -0700269
Ray Milkey269ffb92014-04-03 14:43:30 -0700270 private void handlePacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
271 log.debug("Start handlePacketIn swId {}, portId {}", sw.getId(), pi.getInPort());
TeruU7feef8a2014-04-03 00:15:49 -0700272
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 String destinationMac =
274 HexString.toHexString(eth.getDestinationMACAddress());
Jonathan Hart0444d932014-01-22 15:06:17 -0800275
Ray Milkey269ffb92014-04-03 14:43:30 -0700276 //FIXME getDeviceByMac() is a blocking call, so it may be better way to handle it to avoid the condition.
277 Device deviceObject = networkGraph.getDeviceByMac(MACAddress.valueOf(destinationMac));
TeruU6464af02014-02-06 21:38:45 -0800278
Ray Milkey269ffb92014-04-03 14:43:30 -0700279 if (deviceObject == null) {
280 log.debug("No device entry found for {}",
281 destinationMac);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800282
Ray Milkey269ffb92014-04-03 14:43:30 -0700283 //Device is not in the DB, so wait it until the device is added.
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700284 EXECUTOR_SERVICE.schedule(new WaitDeviceArp(sw, pi, eth), SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, TimeUnit.MILLISECONDS);
Ray Milkey269ffb92014-04-03 14:43:30 -0700285 return;
286 }
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800287
Ray Milkey269ffb92014-04-03 14:43:30 -0700288 continueHandlePacketIn(sw, pi, eth, deviceObject);
289 }
TeruU417fe022014-02-04 12:59:30 -0800290
Ray Milkey269ffb92014-04-03 14:43:30 -0700291 private class WaitDeviceArp implements Runnable {
292 IOFSwitch sw;
293 OFPacketIn pi;
294 Ethernet eth;
TeruU417fe022014-02-04 12:59:30 -0800295
Ray Milkey269ffb92014-04-03 14:43:30 -0700296 public WaitDeviceArp(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
297 super();
298 this.sw = sw;
299 this.pi = pi;
300 this.eth = eth;
301 }
TeruU417fe022014-02-04 12:59:30 -0800302
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 @Override
304 public void run() {
305 Device deviceObject = networkGraph.getDeviceByMac(MACAddress.valueOf(eth.getDestinationMACAddress()));
306 if (deviceObject == null) {
307 log.debug("wait {}ms and device was not found. Send broadcast packet and the thread finish.", SLEEP_TIME_FOR_DB_DEVICE_INSTALLED);
308 handleBroadcast(sw, pi, eth);
309 return;
310 }
311 log.debug("wait {}ms and device {} was found, continue", SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, deviceObject.getMacAddress());
312 continueHandlePacketIn(sw, pi, eth, deviceObject);
313 }
314 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800315
Ray Milkey269ffb92014-04-03 14:43:30 -0700316 private void continueHandlePacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth, Device deviceObject) {
TeruU7feef8a2014-04-03 00:15:49 -0700317
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 log.debug("Start continuehandlePacketIn");
TeruU7feef8a2014-04-03 00:15:49 -0700319
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 //Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
321 Iterator<net.onrc.onos.core.topology.Port> ports = deviceObject.getAttachmentPoints().iterator();
322 if (!ports.hasNext()) {
323 log.debug("No attachment point found for device {} - broadcasting packet",
324 deviceObject.getMacAddress());
325 handleBroadcast(sw, pi, eth);
326 return;
327 }
TeruU7feef8a2014-04-03 00:15:49 -0700328
Ray Milkey269ffb92014-04-03 14:43:30 -0700329 //This code assumes the device has only one port. It should be problem.
330 net.onrc.onos.core.topology.Port portObject = ports.next();
331 short destinationPort = portObject.getNumber().shortValue();
332 Switch switchObject = portObject.getSwitch();
333 long destinationDpid = switchObject.getDpid();
334
335 // TODO SwitchPort, Dpid and Port should probably be immutable
336 SwitchPort srcSwitchPort = new SwitchPort(
337 new Dpid(sw.getId()), new Port(pi.getInPort()));
338 SwitchPort dstSwitchPort = new SwitchPort(
339 new Dpid(destinationDpid), new Port(destinationPort));
340
341 MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
342 MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
343
344 synchronized (lock) {
345 //TODO check concurrency
346 Path pathspec = new Path(srcMacAddress, dstMacAddress);
347 PushedFlow existingFlow = pendingFlows.get(pathspec);
348
349 //A path is installed side by side to reduce a path timeout and a wrong state.
350 if (existingFlow != null) {
351 // We've already start to install a flow for this pair of MAC addresses
352 if (log.isDebugEnabled()) {
353 log.debug("Found existing the same pathspec {}, intent ID is {}",
354 pathspec,
355 existingFlow.intentId);
356 }
357
358 OFPacketOut po = constructPacketOut(pi, sw);
359
360 // Find the correct port here. We just assume the PI is from
361 // the first hop switch, but this is definitely not always
362 // the case. We'll have to retrieve the flow from HZ every time
363 // because it could change (be rerouted) sometimes.
364 if (existingFlow.installed) {
365 // Flow has been sent to the switches so it is safe to
366 // send a packet out now
367
368 Intent intent = intentMap.getIntent(existingFlow.intentId);
369 PathIntent pathIntent = null;
370 if (intent instanceof PathIntent) {
371 pathIntent = (PathIntent) intent;
372 } else {
373 log.debug("Intent {} is not PathIntent. Return.", intent.getId());
374 return;
375 }
376
377 Boolean isflowEntryForThisSwitch = false;
378 net.onrc.onos.core.topology.Path path = pathIntent.getPath();
379
Ray Milkey7f1567c2014-04-08 13:53:32 -0700380 for (Iterator<LinkEvent> i = path.iterator(); i.hasNext();) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700381 LinkEvent le = (LinkEvent) i.next();
382 if (le.getSrc().dpid == sw.getId()) {
383 log.debug("src {} dst {}", le.getSrc(), le.getDst());
384 isflowEntryForThisSwitch = true;
385 break;
386 }
387 }
388
389 if (isflowEntryForThisSwitch == false) {
390 // If we don't find a flow entry for that switch, then we're
391 // in the middle of a rerouting (or something's gone wrong).
392 // This packet will be dropped as a victim of the rerouting.
393 log.debug("Dropping packet on flow {} between {}-{}",
394 existingFlow.intentId,
395 srcMacAddress, dstMacAddress);
396 } else {
397 log.debug("Sending packet out from sw {}, outport{}", sw, existingFlow.firstOutPort);
398 sendPacketOut(sw, po, existingFlow.firstOutPort);
399 }
400 } else {
401 // Flow path has not yet been installed to switches so save the
402 // packet out for later
403 log.debug("Put a packet into the waitng list. flowId {}", existingFlow.intentId);
404 waitingPackets.put(existingFlow.intentId, new PacketToPush(po, sw.getId()));
405 }
406 return;
407 }
408
409 log.debug("Adding new flow between {} at {} and {} at {}",
410 new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
411
412 String intentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
413 IntentOperationList operations = new IntentOperationList();
414 ShortestPathIntent intent = new ShortestPathIntent(intentId,
415 sw.getId(), pi.getInPort(), srcMacAddress.toLong(),
416 destinationDpid, destinationPort, dstMacAddress.toLong());
417 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
418 operations.add(operator, intent);
419 pathRuntime.executeIntentOperations(operations);
420
421 OFPacketOut po = constructPacketOut(pi, sw);
422
423 // Add to waiting lists
424 pendingFlows.put(pathspec, new PushedFlow(intentId));
425 log.debug("Put a Path {} in the pending flow, intent ID {}", pathspec, intentId);
426 waitingPackets.put(intentId, new PacketToPush(po, sw.getId()));
427 log.debug("Put a Packet in the wating list. related pathspec {}", pathspec);
428
429 }
430 }
431
432 private OFPacketOut constructPacketOut(OFPacketIn pi, IOFSwitch sw) {
433 OFPacketOut po = new OFPacketOut();
434 po.setInPort(OFPort.OFPP_NONE)
435 .setInPort(pi.getInPort())
436 .setActions(new ArrayList<OFAction>())
437 .setLengthU(OFPacketOut.MINIMUM_LENGTH);
438
439 if (sw.getBuffers() == 0) {
440 po.setBufferId(OFPacketOut.BUFFER_ID_NONE)
441 .setPacketData(pi.getPacketData())
442 .setLengthU(po.getLengthU() + po.getPacketData().length);
443 } else {
444 po.setBufferId(pi.getBufferId());
445 }
446
447 return po;
448 }
449
450 @Override
451 public void flowsInstalled(Collection<FlowPath> installedFlowPaths) {
452 }
453
454 @Override
455 public void flowRemoved(FlowPath removedFlowPath) {
456 }
457
458 public void flowRemoved(PathIntent removedIntent) {
459 if (log.isTraceEnabled()) {
460 log.trace("Path {} was removed", removedIntent.getParentIntent().getId());
461 }
462
463 ShortestPathIntent spfIntent = (ShortestPathIntent) removedIntent.getParentIntent();
464 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
465 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
466 Path removedPath = new Path(srcMacAddress, dstMacAddress);
467
468 synchronized (lock) {
469 // There *shouldn't* be any packets queued if the flow has
470 // just been removed.
471 List<PacketToPush> packets = waitingPackets.removeAll(spfIntent.getId());
472 if (!packets.isEmpty()) {
473 log.warn("Removed flow {} has packets queued.", spfIntent.getId());
474 }
475 pendingFlows.remove(removedPath);
476 log.debug("Removed from the pendingFlow: Path {}, Flow ID {}", removedPath, spfIntent.getId());
477 }
478 }
479
480 private void flowInstalled(PathIntent installedPath) {
481 if (log.isTraceEnabled()) {
482 log.trace("Path {} was installed", installedPath.getParentIntent().getId());
483 }
484
485 ShortestPathIntent spfIntent = (ShortestPathIntent) installedPath.getParentIntent();
486 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
487 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
488 Path path = new Path(srcMacAddress, dstMacAddress);
489 log.debug("Path spec {}", path);
490
491 // TODO waiting packets should time out. We could request a path that
492 // can't be installed right now because of a network partition. The path
493 // may eventually be installed, but we may have received thousands of
494 // packets in the meantime and probably don't want to send very old packets.
495
496 List<PacketToPush> packets = null;
497 net.onrc.onos.core.topology.Path graphPath = installedPath.getPath();
498
499 log.debug("path{}", graphPath);
500 Short outPort = graphPath.get(0).getSrc().getNumber().shortValue();
501
502 PushedFlow existingFlow = null;
503
504 synchronized (lock) {
505 existingFlow = pendingFlows.get(path);
506
507 if (existingFlow != null) {
508 existingFlow.installed = true;
509 existingFlow.firstOutPort = outPort;
510 } else {
511 log.debug("ExistingFlow {} is null", path);
512 return;
513 }
514
515 //Check both existing flow are installed status.
516 if (existingFlow.installed) {
517 packets = waitingPackets.removeAll(existingFlow.intentId);
518 if (log.isDebugEnabled()) {
519 log.debug("removed my packets {} to push from waitingPackets. outPort {} size {}",
520 existingFlow.intentId, existingFlow.firstOutPort, packets.size());
521 }
522 } else {
523 log.debug("Forward or reverse flows hasn't been pushed yet. return");
524 return;
525 }
526 }
527
528 for (PacketToPush packet : packets) {
529 log.debug("Start packetToPush to sw {}, outPort {}, path {}", packet.dpid, existingFlow.firstOutPort, path);
530 IOFSwitch sw = floodlightProvider.getSwitches().get(packet.dpid);
531 sendPacketOut(sw, packet.packet, existingFlow.firstOutPort);
532 }
533 }
534
535 private void sendPacketOut(IOFSwitch sw, OFPacketOut po, short outPort) {
536 po.getActions().add(new OFActionOutput(outPort));
537 po.setActionsLength((short)
538 (po.getActionsLength() + OFActionOutput.MINIMUM_LENGTH));
539 po.setLengthU(po.getLengthU() + OFActionOutput.MINIMUM_LENGTH);
540
541 flowPusher.add(sw, po);
542 }
543
544 @Override
545 public void entryAdded(IntentStateList value) {
546 entryUpdated(value);
547
548 }
549
550 @Override
551 public void entryRemoved(IntentStateList value) {
552 //no-op
553 }
554
555 @Override
556 public void entryUpdated(IntentStateList value) {
557 for (Entry<String, IntentState> entry : value.entrySet()) {
558 log.debug("path intent key {}, value {}", entry.getKey(), entry.getValue());
559 PathIntent pathIntent = (PathIntent) intentMap.getIntent(entry.getKey());
560 if (pathIntent == null)
561 continue;
562
563 if (!(pathIntent.getParentIntent() instanceof ShortestPathIntent))
564 continue;
565
566 IntentState state = entry.getValue();
567 switch (state) {
568 case INST_REQ:
569 break;
570 case INST_ACK:
571 flowInstalled(pathIntent);
572 break;
573 case INST_NACK:
574 break;
575 case DEL_REQ:
576 break;
577 case DEL_ACK:
578 flowRemoved(pathIntent);
579 break;
580 case DEL_PENDING:
581 break;
582 default:
583 break;
584 }
585 }
586 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800587}