blob: a4126f6c55cc9c1ff364c190bebb82edccf8364b [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;
TeruUf9111652014-05-14 23:10:35 -07007import java.util.LinkedList;
Jonathan Hart41d1e912013-11-24 16:50:25 -08008import java.util.List;
Jonathan Harte93aed42013-12-05 18:39:50 -08009import java.util.Map;
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
Jonathan Harte93aed42013-12-05 18:39:50 -080014import net.floodlightcontroller.core.module.FloodlightModuleContext;
15import net.floodlightcontroller.core.module.IFloodlightModule;
16import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080017import net.floodlightcontroller.util.MACAddress;
Jonathan Hartf5bd2582014-04-09 17:43:41 -070018import net.onrc.onos.api.packet.IPacketListener;
19import net.onrc.onos.api.packet.IPacketService;
Jonathan Hart0961fe82014-04-03 09:56:25 -070020import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart23701d12014-04-03 10:45:48 -070021import net.onrc.onos.core.devicemanager.IOnosDeviceService;
Jonathan Hartaa380972014-04-03 10:24:46 -070022import net.onrc.onos.core.intent.Intent;
Jonathan Harta99ec672014-04-03 11:30:34 -070023import net.onrc.onos.core.intent.Intent.IntentState;
Jonathan Hartaa380972014-04-03 10:24:46 -070024import net.onrc.onos.core.intent.IntentMap;
TeruUf9111652014-05-14 23:10:35 -070025import net.onrc.onos.core.intent.IntentMap.ChangedEvent;
26import net.onrc.onos.core.intent.IntentMap.ChangedListener;
Jonathan Hartaa380972014-04-03 10:24:46 -070027import net.onrc.onos.core.intent.IntentOperation;
28import net.onrc.onos.core.intent.IntentOperationList;
29import net.onrc.onos.core.intent.PathIntent;
30import net.onrc.onos.core.intent.ShortestPathIntent;
Jonathan Hartaa380972014-04-03 10:24:46 -070031import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070032import net.onrc.onos.core.packet.Ethernet;
33import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart472062d2014-04-03 10:56:48 -070034import net.onrc.onos.core.topology.Device;
Jonathan Harte37e4e22014-05-13 19:12:02 -070035import net.onrc.onos.core.topology.ITopologyService;
Jonathan Hart472062d2014-04-03 10:56:48 -070036import net.onrc.onos.core.topology.LinkEvent;
Jonathan Hartf5bd2582014-04-09 17:43:41 -070037import net.onrc.onos.core.topology.Port;
Jonathan Hart472062d2014-04-03 10:56:48 -070038import net.onrc.onos.core.topology.Switch;
TeruUf9111652014-05-14 23:10:35 -070039import net.onrc.onos.core.topology.Topology;
Jonathan Hart23701d12014-04-03 10:45:48 -070040import net.onrc.onos.core.util.Dpid;
41import net.onrc.onos.core.util.FlowPath;
Jonathan Hart23701d12014-04-03 10:45:48 -070042import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart1caaa932013-11-04 15:28:28 -080043
Jonathan Hart1caaa932013-11-04 15:28:28 -080044import org.openflow.util.HexString;
45import org.slf4j.Logger;
46import org.slf4j.LoggerFactory;
47
Jonathan Hartd857ad62013-12-14 18:08:17 -080048import com.google.common.collect.LinkedListMultimap;
49import com.google.common.collect.ListMultimap;
Jonathan Hart5e448782013-12-10 12:36:35 -080050
Jonathan Hartf5bd2582014-04-09 17:43:41 -070051public class Forwarding implements /*IOFMessageListener,*/ IFloodlightModule,
TeruUf9111652014-05-14 23:10:35 -070052 IForwardingService, IPacketListener, ChangedListener {
Ray Milkeyec838942014-04-09 11:28:43 -070053 private static final Logger log = LoggerFactory.getLogger(Forwarding.class);
TeruU7feef8a2014-04-03 00:15:49 -070054
Ray Milkey2476cac2014-04-08 11:03:21 -070055 private static final int SLEEP_TIME_FOR_DB_DEVICE_INSTALLED = 100; // milliseconds
Ray Milkeyec838942014-04-09 11:28:43 -070056 private static final int NUMBER_OF_THREAD_FOR_EXECUTOR = 1;
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070057
Ray Milkeyec838942014-04-09 11:28:43 -070058 private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(NUMBER_OF_THREAD_FOR_EXECUTOR);
Jonathan Harte93aed42013-12-05 18:39:50 -080059
Ray Milkey269ffb92014-04-03 14:43:30 -070060 private final String callerId = "Forwarding";
Jonathan Harte93aed42013-12-05 18:39:50 -080061
Jonathan Hartf5bd2582014-04-09 17:43:41 -070062 private IPacketService packetService;
Ray Milkey269ffb92014-04-03 14:43:30 -070063 private IControllerRegistryService controllerRegistryService;
64
Jonathan Harte37e4e22014-05-13 19:12:02 -070065 private ITopologyService topologyService;
66 private Topology topology;
Ray Milkey269ffb92014-04-03 14:43:30 -070067 private IPathCalcRuntimeService pathRuntime;
68 private IntentMap intentMap;
69
70 // TODO it seems there is a Guava collection that will time out entries.
71 // We should see if this will work here.
72 private Map<Path, PushedFlow> pendingFlows;
73 private ListMultimap<String, PacketToPush> waitingPackets;
74
75 private final Object lock = new Object();
76
Jonathan Hart8ed69c52014-04-09 13:29:16 -070077 private static class PacketToPush {
Jonathan Hartf5bd2582014-04-09 17:43:41 -070078 public final Ethernet eth;
Ray Milkey269ffb92014-04-03 14:43:30 -070079 public final long dpid;
80
Jonathan Hartf5bd2582014-04-09 17:43:41 -070081 public PacketToPush(Ethernet eth, long dpid) {
82 this.eth = eth;
Ray Milkey269ffb92014-04-03 14:43:30 -070083 this.dpid = dpid;
84 }
85 }
86
Jonathan Hart8ed69c52014-04-09 13:29:16 -070087 private static class PushedFlow {
Ray Milkey269ffb92014-04-03 14:43:30 -070088 public final String intentId;
89 public boolean installed = false;
90 public short firstOutPort;
91
92 public PushedFlow(String flowId) {
93 this.intentId = flowId;
94 }
95 }
96
Jonathan Hart8ed69c52014-04-09 13:29:16 -070097 private static final class Path {
Ray Milkey269ffb92014-04-03 14:43:30 -070098 public final MACAddress srcMac;
99 public final MACAddress dstMac;
100
101 public Path(MACAddress srcMac, MACAddress dstMac) {
102 this.srcMac = srcMac;
103 this.dstMac = dstMac;
104 }
105
106 @Override
107 public boolean equals(Object other) {
108 if (!(other instanceof Path)) {
109 return false;
110 }
111
112 Path otherPath = (Path) other;
113 return srcMac.equals(otherPath.srcMac) &&
114 dstMac.equals(otherPath.dstMac);
115 }
116
117 @Override
118 public int hashCode() {
119 int hash = 17;
120 hash = 31 * hash + srcMac.hashCode();
121 hash = 31 * hash + dstMac.hashCode();
122 return hash;
123 }
124
125 @Override
126 public String toString() {
127 return "(" + srcMac + ") => (" + dstMac + ")";
128 }
129 }
130
131 @Override
132 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
133 List<Class<? extends IFloodlightService>> services =
134 new ArrayList<Class<? extends IFloodlightService>>(1);
135 services.add(IForwardingService.class);
136 return services;
137 }
138
139 @Override
140 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
141 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
142 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(1);
143 impls.put(IForwardingService.class, this);
144 return impls;
145 }
146
147 @Override
148 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
149 List<Class<? extends IFloodlightService>> dependencies =
150 new ArrayList<Class<? extends IFloodlightService>>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 dependencies.add(IControllerRegistryService.class);
152 dependencies.add(IOnosDeviceService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700153 dependencies.add(ITopologyService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 dependencies.add(IPathCalcRuntimeService.class);
155 // We don't use the IProxyArpService directly, but reactive forwarding
156 // requires it to be loaded and answering ARP requests
157 dependencies.add(IProxyArpService.class);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700158 dependencies.add(IPacketService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 return dependencies;
160 }
161
162 @Override
163 public void init(FloodlightModuleContext context) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700165 topologyService = context.getServiceImpl(ITopologyService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700166 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700167 packetService = context.getServiceImpl(IPacketService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700168
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 pendingFlows = new HashMap<Path, PushedFlow>();
170 waitingPackets = LinkedListMultimap.create();
171 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800172
Ray Milkey269ffb92014-04-03 14:43:30 -0700173 @Override
174 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700175 packetService.registerPacketListener(this);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800176
Jonathan Harte37e4e22014-05-13 19:12:02 -0700177 topology = topologyService.getTopology();
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 intentMap = pathRuntime.getPathIntents();
TeruUf9111652014-05-14 23:10:35 -0700179 intentMap.addChangeListener(this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700180 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800181
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 @Override
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700183 public void receive(Switch sw, Port inPort, Ethernet eth) {
TeruUf9111652014-05-14 23:10:35 -0700184 if (log.isTraceEnabled()) {
185 log.trace("Receive PACKET_IN swId {}, portId {}", sw.getDpid(), inPort.getNumber());
186 }
TeruU417fe022014-02-04 12:59:30 -0800187
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700188 if (eth.getEtherType() != Ethernet.TYPE_IPV4) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700189 // Only handle IPv4 packets right now
190 return;
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 }
TeruU417fe022014-02-04 12:59:30 -0800192
Ray Milkey269ffb92014-04-03 14:43:30 -0700193 if (eth.isBroadcast() || eth.isMulticast()) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700194 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 } else {
196 // Unicast
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700197 handlePacketIn(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 }
TeruU417fe022014-02-04 12:59:30 -0800200
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700201 private void handleBroadcast(Switch sw, Port inPort, Ethernet eth) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 if (log.isTraceEnabled()) {
203 log.trace("Sending broadcast packet to other ONOS instances");
204 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800205
Jonathan Harte3702f22014-04-29 02:56:56 -0700206 packetService.broadcastPacketOutEdge(eth,
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700207 new SwitchPort(sw.getDpid(), inPort.getNumber().shortValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 }
Pavlin Radoslavova3818db2014-03-20 19:26:08 -0700209
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700210 private void handlePacketIn(Switch sw, Port inPort, Ethernet eth) {
TeruUf9111652014-05-14 23:10:35 -0700211 if (log.isTraceEnabled()) {
212 log.trace("Start handlePacketIn swId {}, portId {}", sw.getDpid(), inPort.getNumber());
213 }
TeruU7feef8a2014-04-03 00:15:49 -0700214
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 String destinationMac =
216 HexString.toHexString(eth.getDestinationMACAddress());
Jonathan Hart0444d932014-01-22 15:06:17 -0800217
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 //FIXME getDeviceByMac() is a blocking call, so it may be better way to handle it to avoid the condition.
Jonathan Harte37e4e22014-05-13 19:12:02 -0700219 Device deviceObject = topology.getDeviceByMac(MACAddress.valueOf(destinationMac));
TeruU6464af02014-02-06 21:38:45 -0800220
Ray Milkey269ffb92014-04-03 14:43:30 -0700221 if (deviceObject == null) {
222 log.debug("No device entry found for {}",
223 destinationMac);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800224
Ray Milkey269ffb92014-04-03 14:43:30 -0700225 //Device is not in the DB, so wait it until the device is added.
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700226 EXECUTOR_SERVICE.schedule(new WaitDeviceArp(sw, inPort, eth), SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, TimeUnit.MILLISECONDS);
Ray Milkey269ffb92014-04-03 14:43:30 -0700227 return;
228 }
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800229
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700230 continueHandlePacketIn(sw, inPort, eth, deviceObject);
Ray Milkey269ffb92014-04-03 14:43:30 -0700231 }
TeruU417fe022014-02-04 12:59:30 -0800232
Ray Milkey269ffb92014-04-03 14:43:30 -0700233 private class WaitDeviceArp implements Runnable {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700234 Switch sw;
235 Port inPort;
Ray Milkey269ffb92014-04-03 14:43:30 -0700236 Ethernet eth;
TeruU417fe022014-02-04 12:59:30 -0800237
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700238 public WaitDeviceArp(Switch sw, Port inPort, Ethernet eth) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700239 super();
240 this.sw = sw;
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700241 this.inPort = inPort;
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 this.eth = eth;
243 }
TeruU417fe022014-02-04 12:59:30 -0800244
Ray Milkey269ffb92014-04-03 14:43:30 -0700245 @Override
246 public void run() {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700247 Device deviceObject = topology.getDeviceByMac(MACAddress.valueOf(eth.getDestinationMACAddress()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700248 if (deviceObject == null) {
249 log.debug("wait {}ms and device was not found. Send broadcast packet and the thread finish.", SLEEP_TIME_FOR_DB_DEVICE_INSTALLED);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700250 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 return;
252 }
253 log.debug("wait {}ms and device {} was found, continue", SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, deviceObject.getMacAddress());
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700254 continueHandlePacketIn(sw, inPort, eth, deviceObject);
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 }
256 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800257
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700258 private void continueHandlePacketIn(Switch sw, Port inPort, Ethernet eth, Device deviceObject) {
TeruU7feef8a2014-04-03 00:15:49 -0700259
Ray Milkey269ffb92014-04-03 14:43:30 -0700260 log.debug("Start continuehandlePacketIn");
TeruU7feef8a2014-04-03 00:15:49 -0700261
Ray Milkey269ffb92014-04-03 14:43:30 -0700262 //Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
263 Iterator<net.onrc.onos.core.topology.Port> ports = deviceObject.getAttachmentPoints().iterator();
264 if (!ports.hasNext()) {
265 log.debug("No attachment point found for device {} - broadcasting packet",
266 deviceObject.getMacAddress());
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700267 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 return;
269 }
TeruU7feef8a2014-04-03 00:15:49 -0700270
Ray Milkey269ffb92014-04-03 14:43:30 -0700271 //This code assumes the device has only one port. It should be problem.
272 net.onrc.onos.core.topology.Port portObject = ports.next();
273 short destinationPort = portObject.getNumber().shortValue();
274 Switch switchObject = portObject.getSwitch();
275 long destinationDpid = switchObject.getDpid();
276
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700277 // TODO eliminate cast
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 SwitchPort srcSwitchPort = new SwitchPort(
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700279 new Dpid(sw.getDpid()),
280 new net.onrc.onos.core.util.Port((short) inPort.getNumber().longValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700281 SwitchPort dstSwitchPort = new SwitchPort(
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700282 new Dpid(destinationDpid),
283 new net.onrc.onos.core.util.Port(destinationPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700284
285 MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
286 MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
287
288 synchronized (lock) {
289 //TODO check concurrency
290 Path pathspec = new Path(srcMacAddress, dstMacAddress);
291 PushedFlow existingFlow = pendingFlows.get(pathspec);
292
293 //A path is installed side by side to reduce a path timeout and a wrong state.
294 if (existingFlow != null) {
295 // We've already start to install a flow for this pair of MAC addresses
296 if (log.isDebugEnabled()) {
297 log.debug("Found existing the same pathspec {}, intent ID is {}",
298 pathspec,
299 existingFlow.intentId);
300 }
301
Ray Milkey269ffb92014-04-03 14:43:30 -0700302 // Find the correct port here. We just assume the PI is from
303 // the first hop switch, but this is definitely not always
304 // the case. We'll have to retrieve the flow from HZ every time
305 // because it could change (be rerouted) sometimes.
306 if (existingFlow.installed) {
307 // Flow has been sent to the switches so it is safe to
308 // send a packet out now
309
310 Intent intent = intentMap.getIntent(existingFlow.intentId);
311 PathIntent pathIntent = null;
312 if (intent instanceof PathIntent) {
313 pathIntent = (PathIntent) intent;
314 } else {
TeruUf9111652014-05-14 23:10:35 -0700315 log.debug("Intent ID {} is not PathIntent or null. return.", existingFlow.intentId);
Ray Milkey269ffb92014-04-03 14:43:30 -0700316 return;
317 }
318
319 Boolean isflowEntryForThisSwitch = false;
Yuta HIGUCHI1fc395e2014-05-13 14:06:28 -0700320 net.onrc.onos.core.intent.Path path = pathIntent.getPath();
Ray Milkey269ffb92014-04-03 14:43:30 -0700321
Ray Milkey7f1567c2014-04-08 13:53:32 -0700322 for (Iterator<LinkEvent> i = path.iterator(); i.hasNext();) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700323 LinkEvent le = (LinkEvent) i.next();
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700324 if (le.getSrc().dpid.equals(sw.getDpid())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 log.debug("src {} dst {}", le.getSrc(), le.getDst());
326 isflowEntryForThisSwitch = true;
327 break;
328 }
329 }
330
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700331 if (!isflowEntryForThisSwitch) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700332 // If we don't find a flow entry for that switch, then we're
333 // in the middle of a rerouting (or something's gone wrong).
334 // This packet will be dropped as a victim of the rerouting.
335 log.debug("Dropping packet on flow {} between {}-{}",
336 existingFlow.intentId,
337 srcMacAddress, dstMacAddress);
338 } else {
339 log.debug("Sending packet out from sw {}, outport{}", sw, existingFlow.firstOutPort);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700340
Jonathan Harte3702f22014-04-29 02:56:56 -0700341 packetService.sendPacket(eth, new SwitchPort(
342 sw.getDpid(), existingFlow.firstOutPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700343 }
344 } else {
345 // Flow path has not yet been installed to switches so save the
346 // packet out for later
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700347 log.debug("Put a packet into the waiting list. flowId {}", existingFlow.intentId);
348 waitingPackets.put(existingFlow.intentId, new PacketToPush(eth, sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700349 }
350 return;
351 }
352
353 log.debug("Adding new flow between {} at {} and {} at {}",
354 new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
355
356 String intentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
357 IntentOperationList operations = new IntentOperationList();
358 ShortestPathIntent intent = new ShortestPathIntent(intentId,
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700359 sw.getDpid(), inPort.getNumber(), srcMacAddress.toLong(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700360 destinationDpid, destinationPort, dstMacAddress.toLong());
361 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
362 operations.add(operator, intent);
363 pathRuntime.executeIntentOperations(operations);
364
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 // Add to waiting lists
366 pendingFlows.put(pathspec, new PushedFlow(intentId));
367 log.debug("Put a Path {} in the pending flow, intent ID {}", pathspec, intentId);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700368 waitingPackets.put(intentId, new PacketToPush(eth, sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700369 log.debug("Put a Packet in the wating list. related pathspec {}", pathspec);
370
371 }
372 }
373
Ray Milkey269ffb92014-04-03 14:43:30 -0700374 @Override
375 public void flowsInstalled(Collection<FlowPath> installedFlowPaths) {
376 }
377
378 @Override
379 public void flowRemoved(FlowPath removedFlowPath) {
380 }
381
382 public void flowRemoved(PathIntent removedIntent) {
383 if (log.isTraceEnabled()) {
384 log.trace("Path {} was removed", removedIntent.getParentIntent().getId());
385 }
386
387 ShortestPathIntent spfIntent = (ShortestPathIntent) removedIntent.getParentIntent();
388 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
389 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
390 Path removedPath = new Path(srcMacAddress, dstMacAddress);
391
392 synchronized (lock) {
393 // There *shouldn't* be any packets queued if the flow has
394 // just been removed.
395 List<PacketToPush> packets = waitingPackets.removeAll(spfIntent.getId());
396 if (!packets.isEmpty()) {
397 log.warn("Removed flow {} has packets queued.", spfIntent.getId());
398 }
399 pendingFlows.remove(removedPath);
400 log.debug("Removed from the pendingFlow: Path {}, Flow ID {}", removedPath, spfIntent.getId());
401 }
402 }
403
404 private void flowInstalled(PathIntent installedPath) {
405 if (log.isTraceEnabled()) {
TeruUf9111652014-05-14 23:10:35 -0700406 log.trace("Installed intent ID {}, path {}", installedPath.getParentIntent().getId(), installedPath.getPath());
Ray Milkey269ffb92014-04-03 14:43:30 -0700407 }
408
409 ShortestPathIntent spfIntent = (ShortestPathIntent) installedPath.getParentIntent();
410 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
411 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
412 Path path = new Path(srcMacAddress, dstMacAddress);
413 log.debug("Path spec {}", path);
414
415 // TODO waiting packets should time out. We could request a path that
416 // can't be installed right now because of a network partition. The path
417 // may eventually be installed, but we may have received thousands of
418 // packets in the meantime and probably don't want to send very old packets.
419
420 List<PacketToPush> packets = null;
Yuta HIGUCHI1fc395e2014-05-13 14:06:28 -0700421 net.onrc.onos.core.intent.Path graphPath = installedPath.getPath();
Ray Milkey269ffb92014-04-03 14:43:30 -0700422
TeruU220c45e2014-04-10 18:56:26 -0700423 short outPort;
424 if (graphPath.isEmpty()) {
425 outPort = (short) spfIntent.getDstPortNumber();
426 log.debug("Path is empty. Maybe devices on the same switch. outPort {}", outPort);
427 } else {
428 outPort = graphPath.get(0).getSrc().getNumber().shortValue();
429 log.debug("path{}, outPort {}", graphPath, outPort);
430 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700431
432 PushedFlow existingFlow = null;
433
434 synchronized (lock) {
435 existingFlow = pendingFlows.get(path);
436
437 if (existingFlow != null) {
438 existingFlow.installed = true;
439 existingFlow.firstOutPort = outPort;
440 } else {
441 log.debug("ExistingFlow {} is null", path);
442 return;
443 }
444
445 //Check both existing flow are installed status.
446 if (existingFlow.installed) {
447 packets = waitingPackets.removeAll(existingFlow.intentId);
448 if (log.isDebugEnabled()) {
449 log.debug("removed my packets {} to push from waitingPackets. outPort {} size {}",
450 existingFlow.intentId, existingFlow.firstOutPort, packets.size());
451 }
452 } else {
453 log.debug("Forward or reverse flows hasn't been pushed yet. return");
454 return;
455 }
456 }
457
458 for (PacketToPush packet : packets) {
459 log.debug("Start packetToPush to sw {}, outPort {}, path {}", packet.dpid, existingFlow.firstOutPort, path);
Jonathan Harte3702f22014-04-29 02:56:56 -0700460 packetService.sendPacket(packet.eth, new SwitchPort(
461 packet.dpid, existingFlow.firstOutPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700462 }
463 }
464
Ray Milkey269ffb92014-04-03 14:43:30 -0700465 @Override
TeruUf9111652014-05-14 23:10:35 -0700466 public void intentsChange(LinkedList<ChangedEvent> events) {
467 for (ChangedEvent event : events) {
468 log.debug("path intent ID {}, eventType {}", event.intent.getId() , event.eventType);
469 PathIntent pathIntent = (PathIntent) intentMap.getIntent(event.intent.getId());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700470 if (pathIntent == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700471 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700472 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700473
Ray Milkeyb29e6262014-04-09 16:02:14 -0700474 if (!(pathIntent.getParentIntent() instanceof ShortestPathIntent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700475 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700476 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700477
TeruUf9111652014-05-14 23:10:35 -0700478 switch(event.eventType) {
479 case ADDED:
Ray Milkey269ffb92014-04-03 14:43:30 -0700480 break;
TeruUf9111652014-05-14 23:10:35 -0700481 case REMOVED:
Ray Milkey269ffb92014-04-03 14:43:30 -0700482 break;
TeruUf9111652014-05-14 23:10:35 -0700483 case STATE_CHANGED:
484 IntentState state = pathIntent.getState();
485 switch (state) {
486 case INST_REQ:
487 break;
488 case INST_ACK:
489 flowInstalled(pathIntent);
490 break;
491 case INST_NACK:
492 break;
493 case DEL_REQ:
494 break;
495 case DEL_ACK:
496 flowRemoved(pathIntent);
497 break;
498 case DEL_PENDING:
499 break;
500 default:
501 break;
502 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700503 default:
504 break;
505 }
506 }
507 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800508}