blob: 0a2ed3909d05d362bc7f117984a3714d4691a700 [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;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070042import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070043import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart1caaa932013-11-04 15:28:28 -080044
Jonathan Hart1caaa932013-11-04 15:28:28 -080045import org.openflow.util.HexString;
46import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
Jonathan Hartd857ad62013-12-14 18:08:17 -080049import com.google.common.collect.LinkedListMultimap;
50import com.google.common.collect.ListMultimap;
Jonathan Hart5e448782013-12-10 12:36:35 -080051
Jonathan Hartf5bd2582014-04-09 17:43:41 -070052public class Forwarding implements /*IOFMessageListener,*/ IFloodlightModule,
TeruUf9111652014-05-14 23:10:35 -070053 IForwardingService, IPacketListener, ChangedListener {
Ray Milkeyec838942014-04-09 11:28:43 -070054 private static final Logger log = LoggerFactory.getLogger(Forwarding.class);
TeruU7feef8a2014-04-03 00:15:49 -070055
Ray Milkey2476cac2014-04-08 11:03:21 -070056 private static final int SLEEP_TIME_FOR_DB_DEVICE_INSTALLED = 100; // milliseconds
Ray Milkeyec838942014-04-09 11:28:43 -070057 private static final int NUMBER_OF_THREAD_FOR_EXECUTOR = 1;
TeruU30c0c932014-05-15 16:47:41 -070058 private static final int SRC_SWITCH_TIMEOUT_ADJUST_SECOND = 2;
59 private static final int DEFAULT_IDLE_TIMEOUT = 5;
60 private int idleTimeout = DEFAULT_IDLE_TIMEOUT;
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070061
Jonathan Hartc00f5c22014-06-10 15:14:40 -070062 private static final ScheduledExecutorService EXECUTOR_SERVICE =
63 Executors.newScheduledThreadPool(NUMBER_OF_THREAD_FOR_EXECUTOR);
Jonathan Harte93aed42013-12-05 18:39:50 -080064
Ray Milkey269ffb92014-04-03 14:43:30 -070065 private final String callerId = "Forwarding";
Jonathan Harte93aed42013-12-05 18:39:50 -080066
TeruU435df322014-06-16 23:45:13 -070067 private final HighLevelIntentChangedHandler highLevelIntentChangedHandler =
68 new HighLevelIntentChangedHandler();
69
Jonathan Hartf5bd2582014-04-09 17:43:41 -070070 private IPacketService packetService;
Ray Milkey269ffb92014-04-03 14:43:30 -070071 private IControllerRegistryService controllerRegistryService;
72
Jonathan Harte37e4e22014-05-13 19:12:02 -070073 private ITopologyService topologyService;
74 private Topology topology;
Ray Milkey269ffb92014-04-03 14:43:30 -070075 private IPathCalcRuntimeService pathRuntime;
TeruU9e530662014-05-18 11:49:37 -070076 private IntentMap pathIntentMap;
77 private IntentMap highLevelIntentMap;
Ray Milkey269ffb92014-04-03 14:43:30 -070078
79 // TODO it seems there is a Guava collection that will time out entries.
80 // We should see if this will work here.
81 private Map<Path, PushedFlow> pendingFlows;
82 private ListMultimap<String, PacketToPush> waitingPackets;
83
84 private final Object lock = new Object();
85
TeruU435df322014-06-16 23:45:13 -070086 private class HighLevelIntentChangedHandler implements ChangedListener {
87
88 @Override
89 public void intentsChange(LinkedList<ChangedEvent> events) {
90 for (ChangedEvent event : events) {
91 ShortestPathIntent spfIntent = null;
92 if (event.intent instanceof ShortestPathIntent) {
93 spfIntent = (ShortestPathIntent) event.intent;
94 log.trace("ShortestPathIntent {}", spfIntent);
95 }
96
97 if (spfIntent == null) {
98 log.trace("ShortestPathIntent is null. Skip.");
99 continue;
100 }
101
102 switch(event.eventType) {
103 case ADDED:
104 break;
105 case REMOVED:
106 break;
107 case STATE_CHANGED:
108 if (spfIntent.getState() == IntentState.INST_NACK) {
109 flowRemoved(spfIntent);
110 }
111 break;
112 default:
113 break;
114 }
115 }
116 }
117
118 }
119
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700120 private static class PacketToPush {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700121 public final Ethernet eth;
Ray Milkey269ffb92014-04-03 14:43:30 -0700122 public final long dpid;
123
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700124 public PacketToPush(Ethernet eth, long dpid) {
125 this.eth = eth;
Ray Milkey269ffb92014-04-03 14:43:30 -0700126 this.dpid = dpid;
127 }
128 }
129
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700130 private static class PushedFlow {
Ray Milkey269ffb92014-04-03 14:43:30 -0700131 public final String intentId;
132 public boolean installed = false;
133 public short firstOutPort;
134
135 public PushedFlow(String flowId) {
136 this.intentId = flowId;
137 }
138 }
139
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700140 private static final class Path {
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 public final MACAddress srcMac;
142 public final MACAddress dstMac;
143
144 public Path(MACAddress srcMac, MACAddress dstMac) {
145 this.srcMac = srcMac;
146 this.dstMac = dstMac;
147 }
148
149 @Override
150 public boolean equals(Object other) {
151 if (!(other instanceof Path)) {
152 return false;
153 }
154
155 Path otherPath = (Path) other;
156 return srcMac.equals(otherPath.srcMac) &&
157 dstMac.equals(otherPath.dstMac);
158 }
159
160 @Override
161 public int hashCode() {
162 int hash = 17;
163 hash = 31 * hash + srcMac.hashCode();
164 hash = 31 * hash + dstMac.hashCode();
165 return hash;
166 }
167
168 @Override
169 public String toString() {
170 return "(" + srcMac + ") => (" + dstMac + ")";
171 }
172 }
173
174 @Override
175 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
176 List<Class<? extends IFloodlightService>> services =
177 new ArrayList<Class<? extends IFloodlightService>>(1);
178 services.add(IForwardingService.class);
179 return services;
180 }
181
182 @Override
183 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
184 Map<Class<? extends IFloodlightService>, IFloodlightService> impls =
185 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(1);
186 impls.put(IForwardingService.class, this);
187 return impls;
188 }
189
190 @Override
191 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
192 List<Class<? extends IFloodlightService>> dependencies =
193 new ArrayList<Class<? extends IFloodlightService>>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 dependencies.add(IControllerRegistryService.class);
195 dependencies.add(IOnosDeviceService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700196 dependencies.add(ITopologyService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700197 dependencies.add(IPathCalcRuntimeService.class);
198 // We don't use the IProxyArpService directly, but reactive forwarding
199 // requires it to be loaded and answering ARP requests
200 dependencies.add(IProxyArpService.class);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700201 dependencies.add(IPacketService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 return dependencies;
203 }
204
205 @Override
206 public void init(FloodlightModuleContext context) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700207 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700208 topologyService = context.getServiceImpl(ITopologyService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700209 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700210 packetService = context.getServiceImpl(IPacketService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700211
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 pendingFlows = new HashMap<Path, PushedFlow>();
213 waitingPackets = LinkedListMultimap.create();
214 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800215
Ray Milkey269ffb92014-04-03 14:43:30 -0700216 @Override
217 public void startUp(FloodlightModuleContext context) {
TeruU30c0c932014-05-15 16:47:41 -0700218 Map<String, String> configOptions = context.getConfigParams(this);
219
220 try {
221 if (Integer.parseInt(configOptions.get("idletimeout")) > 0) {
222 idleTimeout = Integer.parseInt(configOptions.get("idletimeout"));
223 log.info("idle_timeout for Forwarding is set to {}.", idleTimeout);
224 } else {
225 log.info("idle_timeout for Forwarding is less than 0. Use default {}.", idleTimeout);
226 }
227 } catch (NumberFormatException e) {
228 log.info("idle_timeout related config options were not set. Use default.");
229 }
230
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700231 packetService.registerPacketListener(this);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800232
Jonathan Harte37e4e22014-05-13 19:12:02 -0700233 topology = topologyService.getTopology();
TeruU9e530662014-05-18 11:49:37 -0700234 highLevelIntentMap = pathRuntime.getHighLevelIntents();
TeruU435df322014-06-16 23:45:13 -0700235 highLevelIntentMap.addChangeListener(highLevelIntentChangedHandler);
TeruU9e530662014-05-18 11:49:37 -0700236 pathIntentMap = pathRuntime.getPathIntents();
237 pathIntentMap.addChangeListener(this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700238 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800239
Ray Milkey269ffb92014-04-03 14:43:30 -0700240 @Override
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700241 public void receive(Switch sw, Port inPort, Ethernet eth) {
TeruUf9111652014-05-14 23:10:35 -0700242 if (log.isTraceEnabled()) {
243 log.trace("Receive PACKET_IN swId {}, portId {}", sw.getDpid(), inPort.getNumber());
244 }
TeruU417fe022014-02-04 12:59:30 -0800245
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700246 if (eth.getEtherType() != Ethernet.TYPE_IPV4) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700247 // Only handle IPv4 packets right now
248 return;
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 }
TeruU417fe022014-02-04 12:59:30 -0800250
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 if (eth.isBroadcast() || eth.isMulticast()) {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700252 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700253 } else {
254 // Unicast
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700255 handlePacketIn(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700256 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700257 }
TeruU417fe022014-02-04 12:59:30 -0800258
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700259 private void handleBroadcast(Switch sw, Port inPort, Ethernet eth) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700260 if (log.isTraceEnabled()) {
261 log.trace("Sending broadcast packet to other ONOS instances");
262 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800263
Jonathan Harte3702f22014-04-29 02:56:56 -0700264 packetService.broadcastPacketOutEdge(eth,
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700265 new SwitchPort(sw.getDpid(), inPort.getNumber()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700266 }
Pavlin Radoslavova3818db2014-03-20 19:26:08 -0700267
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700268 private void handlePacketIn(Switch sw, Port inPort, Ethernet eth) {
TeruUf9111652014-05-14 23:10:35 -0700269 if (log.isTraceEnabled()) {
270 log.trace("Start handlePacketIn swId {}, portId {}", sw.getDpid(), inPort.getNumber());
271 }
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
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700276 // FIXME getDeviceByMac() is a blocking call, so it may be better way
277 // to handle it to avoid the condition.
278 Device deviceObject = topology.getDeviceByMac(
279 MACAddress.valueOf(destinationMac));
TeruU6464af02014-02-06 21:38:45 -0800280
Ray Milkey269ffb92014-04-03 14:43:30 -0700281 if (deviceObject == null) {
282 log.debug("No device entry found for {}",
283 destinationMac);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800284
Ray Milkey269ffb92014-04-03 14:43:30 -0700285 //Device is not in the DB, so wait it until the device is added.
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700286 EXECUTOR_SERVICE.schedule(new WaitDeviceArp(sw, inPort, eth),
287 SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, TimeUnit.MILLISECONDS);
Ray Milkey269ffb92014-04-03 14:43:30 -0700288 return;
289 }
Pavlin Radoslavov7208e9a2013-12-11 14:31:07 -0800290
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700291 continueHandlePacketIn(sw, inPort, eth, deviceObject);
Ray Milkey269ffb92014-04-03 14:43:30 -0700292 }
TeruU417fe022014-02-04 12:59:30 -0800293
Ray Milkey269ffb92014-04-03 14:43:30 -0700294 private class WaitDeviceArp implements Runnable {
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700295 Switch sw;
296 Port inPort;
Ray Milkey269ffb92014-04-03 14:43:30 -0700297 Ethernet eth;
TeruU417fe022014-02-04 12:59:30 -0800298
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700299 public WaitDeviceArp(Switch sw, Port inPort, Ethernet eth) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700300 super();
301 this.sw = sw;
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700302 this.inPort = inPort;
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 this.eth = eth;
304 }
TeruU417fe022014-02-04 12:59:30 -0800305
Ray Milkey269ffb92014-04-03 14:43:30 -0700306 @Override
307 public void run() {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700308 Device deviceObject = topology.getDeviceByMac(MACAddress.valueOf(eth.getDestinationMACAddress()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700309 if (deviceObject == null) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700310 log.debug("wait {}ms and device was not found. " +
311 "Send broadcast packet and the thread finish.",
312 SLEEP_TIME_FOR_DB_DEVICE_INSTALLED);
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700313 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 return;
315 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700316 log.debug("wait {}ms and device {} was found, continue",
317 SLEEP_TIME_FOR_DB_DEVICE_INSTALLED, deviceObject.getMacAddress());
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700318 continueHandlePacketIn(sw, inPort, eth, deviceObject);
Ray Milkey269ffb92014-04-03 14:43:30 -0700319 }
320 }
Jonathan Hart0444d932014-01-22 15:06:17 -0800321
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700322 private void continueHandlePacketIn(Switch sw, Port inPort, Ethernet eth, Device deviceObject) {
TeruU7feef8a2014-04-03 00:15:49 -0700323
TeruU9e530662014-05-18 11:49:37 -0700324 log.trace("Start continuehandlePacketIn");
TeruU7feef8a2014-04-03 00:15:49 -0700325
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 //Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
327 Iterator<net.onrc.onos.core.topology.Port> ports = deviceObject.getAttachmentPoints().iterator();
328 if (!ports.hasNext()) {
329 log.debug("No attachment point found for device {} - broadcasting packet",
330 deviceObject.getMacAddress());
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700331 handleBroadcast(sw, inPort, eth);
Ray Milkey269ffb92014-04-03 14:43:30 -0700332 return;
333 }
TeruU7feef8a2014-04-03 00:15:49 -0700334
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 //This code assumes the device has only one port. It should be problem.
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700336 Port destinationPort = ports.next();
337 short destinationPortNum = destinationPort.getNumber().value();
338 Switch destinationSw = destinationPort.getSwitch();
339 long destinationDpid = destinationSw.getDpid().value();
Ray Milkey269ffb92014-04-03 14:43:30 -0700340
Ray Milkey269ffb92014-04-03 14:43:30 -0700341 SwitchPort srcSwitchPort = new SwitchPort(
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700342 sw.getDpid(),
343 inPort.getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 SwitchPort dstSwitchPort = new SwitchPort(
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700345 destinationSw.getDpid(),
346 destinationPort.getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700347
348 MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
349 MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
TeruU9e530662014-05-18 11:49:37 -0700350 Path pathspec = new Path(srcMacAddress, dstMacAddress);
351 IntentOperationList operations = new IntentOperationList();
Ray Milkey269ffb92014-04-03 14:43:30 -0700352
353 synchronized (lock) {
354 //TODO check concurrency
TeruU9e530662014-05-18 11:49:37 -0700355
Ray Milkey269ffb92014-04-03 14:43:30 -0700356 PushedFlow existingFlow = pendingFlows.get(pathspec);
357
358 //A path is installed side by side to reduce a path timeout and a wrong state.
359 if (existingFlow != null) {
360 // We've already start to install a flow for this pair of MAC addresses
361 if (log.isDebugEnabled()) {
362 log.debug("Found existing the same pathspec {}, intent ID is {}",
363 pathspec,
364 existingFlow.intentId);
365 }
366
Ray Milkey269ffb92014-04-03 14:43:30 -0700367 // Find the correct port here. We just assume the PI is from
368 // the first hop switch, but this is definitely not always
369 // the case. We'll have to retrieve the flow from HZ every time
370 // because it could change (be rerouted) sometimes.
371 if (existingFlow.installed) {
372 // Flow has been sent to the switches so it is safe to
373 // send a packet out now
374
TeruU9e530662014-05-18 11:49:37 -0700375 // TODO Here highLevelIntentMap and pathIntentMap would be problem,
376 // because it doesn't have global information as of May 2014.
377 // However usually these lines here is used when we got packet-in and this class think
378 // the path for the packet is installed already, so it is pretty rare.
379 // I will leave it for now, and will work in the next step.
380 Intent highLevelIntent = highLevelIntentMap.getIntent(existingFlow.intentId);
381 if (highLevelIntent == null) {
382 log.debug("Intent ID {} is null in HighLevelIntentMap. return.", existingFlow.intentId);
383 return;
384 }
385
386 if (highLevelIntent.getState() != IntentState.INST_ACK) {
387 log.debug("Intent ID {}'s state is not INST_ACK. return.", existingFlow.intentId);
388 return;
389 }
390
391 ShortestPathIntent spfIntent = null;
392 if (highLevelIntent instanceof ShortestPathIntent) {
393 spfIntent = (ShortestPathIntent) highLevelIntent;
Ray Milkey269ffb92014-04-03 14:43:30 -0700394 } else {
TeruUf9111652014-05-14 23:10:35 -0700395 log.debug("Intent ID {} is not PathIntent or null. return.", existingFlow.intentId);
Ray Milkey269ffb92014-04-03 14:43:30 -0700396 return;
397 }
398
TeruU9e530662014-05-18 11:49:37 -0700399 PathIntent pathIntent = (PathIntent) pathIntentMap.getIntent(spfIntent.getPathIntentId());
400 if (pathIntent == null) {
401 log.debug("PathIntent ID {} is null in PathIntentMap. return.", existingFlow.intentId);
402 return;
403 }
404
405 if (pathIntent.getState() != IntentState.INST_ACK) {
406 log.debug("Intent ID {}'s state is not INST_ACK. return.", existingFlow.intentId);
407 return;
408 }
409
410 boolean isflowEntryForThisSwitch = false;
Yuta HIGUCHI1fc395e2014-05-13 14:06:28 -0700411 net.onrc.onos.core.intent.Path path = pathIntent.getPath();
TeruU9e530662014-05-18 11:49:37 -0700412 long outPort = -1;
413
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700414 if (spfIntent.getDstSwitchDpid() == sw.getDpid().value()) {
TeruU9e530662014-05-18 11:49:37 -0700415 log.trace("The packet-in sw dpid {} is on the path.", sw.getDpid());
416 isflowEntryForThisSwitch = true;
417 outPort = spfIntent.getDstPortNumber();
418 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700419
Ray Milkey7f1567c2014-04-08 13:53:32 -0700420 for (Iterator<LinkEvent> i = path.iterator(); i.hasNext();) {
Ray Milkey149693c2014-05-20 14:58:53 -0700421 LinkEvent le = i.next();
TeruU9e530662014-05-18 11:49:37 -0700422
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700423 if (new Dpid(le.getSrc().dpid).equals(sw.getDpid())) {
TeruU9e530662014-05-18 11:49:37 -0700424 log.trace("The packet-in sw dpid {} is on the path.", sw.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700425 isflowEntryForThisSwitch = true;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700426 outPort = le.getSrc().getNumber().value();
Ray Milkey269ffb92014-04-03 14:43:30 -0700427 break;
428 }
429 }
430
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700431 if (!isflowEntryForThisSwitch) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700432 // If we don't find a flow entry for that switch, then we're
433 // in the middle of a rerouting (or something's gone wrong).
434 // This packet will be dropped as a victim of the rerouting.
435 log.debug("Dropping packet on flow {} between {}-{}",
436 existingFlow.intentId,
437 srcMacAddress, dstMacAddress);
438 } else {
TeruU9e530662014-05-18 11:49:37 -0700439 if (outPort < 0) {
440 outPort = existingFlow.firstOutPort;
441 }
Jonathan Hartf5bd2582014-04-09 17:43:41 -0700442
TeruU9e530662014-05-18 11:49:37 -0700443 log.debug("Sending packet out from sw {}, outport{}", sw.getDpid(), outPort);
Jonathan Harte3702f22014-04-29 02:56:56 -0700444 packetService.sendPacket(eth, new SwitchPort(
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700445 sw.getDpid(), new PortNumber((short) outPort)));
Ray Milkey269ffb92014-04-03 14:43:30 -0700446 }
447 } else {
448 // Flow path has not yet been installed to switches so save the
449 // packet out for later
TeruU9e530662014-05-18 11:49:37 -0700450 log.trace("Put a packet into the waiting list. flowId {}", existingFlow.intentId);
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700451 waitingPackets.put(existingFlow.intentId, new PacketToPush(eth, sw.getDpid().value()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700452 }
453 return;
454 }
455
TeruU9e530662014-05-18 11:49:37 -0700456 String intentId = Long.toString(controllerRegistryService.getNextUniqueId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700457 ShortestPathIntent intent = new ShortestPathIntent(intentId,
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700458 sw.getDpid().value(), inPort.getNumber().value(), srcMacAddress.toLong(),
459 destinationDpid, destinationPortNum, dstMacAddress.toLong());
Ray Milkeyff735142014-05-22 19:06:02 -0700460
TeruU30c0c932014-05-15 16:47:41 -0700461 intent.setIdleTimeout(idleTimeout + SRC_SWITCH_TIMEOUT_ADJUST_SECOND);
462 intent.setFirstSwitchIdleTimeout(idleTimeout);
Ray Milkey269ffb92014-04-03 14:43:30 -0700463 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
464 operations.add(operator, intent);
TeruU9e530662014-05-18 11:49:37 -0700465 log.debug("Adding new flow between {} at {} and {} at {}",
466 new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
Ray Milkey269ffb92014-04-03 14:43:30 -0700467
TeruU9e530662014-05-18 11:49:37 -0700468 // Add to waiting lists
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700469 waitingPackets.put(intentId, new PacketToPush(eth, sw.getDpid().value()));
TeruU9e530662014-05-18 11:49:37 -0700470 log.trace("Put a Packet in the wating list. intent ID {}, related pathspec {}", intentId, pathspec);
471 pendingFlows.put(pathspec, new PushedFlow(intentId));
472 log.trace("Put a Path {} in the pending flow, intent ID {}", pathspec, intentId);
Ray Milkey269ffb92014-04-03 14:43:30 -0700473 }
TeruU9e530662014-05-18 11:49:37 -0700474 pathRuntime.executeIntentOperations(operations);
Ray Milkey269ffb92014-04-03 14:43:30 -0700475 }
476
Ray Milkey269ffb92014-04-03 14:43:30 -0700477 @Override
478 public void flowsInstalled(Collection<FlowPath> installedFlowPaths) {
479 }
480
481 @Override
482 public void flowRemoved(FlowPath removedFlowPath) {
483 }
484
TeruU435df322014-06-16 23:45:13 -0700485 public void flowRemoved(ShortestPathIntent spfIntent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700486 if (log.isTraceEnabled()) {
TeruU435df322014-06-16 23:45:13 -0700487 log.trace("ShortestPathIntent {} was removed", spfIntent.getId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700488 }
489
Ray Milkey269ffb92014-04-03 14:43:30 -0700490 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
491 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
492 Path removedPath = new Path(srcMacAddress, dstMacAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700493 synchronized (lock) {
494 // There *shouldn't* be any packets queued if the flow has
495 // just been removed.
496 List<PacketToPush> packets = waitingPackets.removeAll(spfIntent.getId());
497 if (!packets.isEmpty()) {
498 log.warn("Removed flow {} has packets queued.", spfIntent.getId());
499 }
TeruU9e530662014-05-18 11:49:37 -0700500
Ray Milkey269ffb92014-04-03 14:43:30 -0700501 pendingFlows.remove(removedPath);
502 log.debug("Removed from the pendingFlow: Path {}, Flow ID {}", removedPath, spfIntent.getId());
503 }
504 }
505
506 private void flowInstalled(PathIntent installedPath) {
507 if (log.isTraceEnabled()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700508 log.trace("Installed intent ID {}, path {}",
509 installedPath.getParentIntent().getId(), installedPath.getPath());
Ray Milkey269ffb92014-04-03 14:43:30 -0700510 }
511
512 ShortestPathIntent spfIntent = (ShortestPathIntent) installedPath.getParentIntent();
513 MACAddress srcMacAddress = MACAddress.valueOf(spfIntent.getSrcMac());
514 MACAddress dstMacAddress = MACAddress.valueOf(spfIntent.getDstMac());
515 Path path = new Path(srcMacAddress, dstMacAddress);
516 log.debug("Path spec {}", path);
517
518 // TODO waiting packets should time out. We could request a path that
519 // can't be installed right now because of a network partition. The path
520 // may eventually be installed, but we may have received thousands of
521 // packets in the meantime and probably don't want to send very old packets.
522
523 List<PacketToPush> packets = null;
Yuta HIGUCHI1fc395e2014-05-13 14:06:28 -0700524 net.onrc.onos.core.intent.Path graphPath = installedPath.getPath();
Ray Milkey269ffb92014-04-03 14:43:30 -0700525
TeruU220c45e2014-04-10 18:56:26 -0700526 short outPort;
527 if (graphPath.isEmpty()) {
528 outPort = (short) spfIntent.getDstPortNumber();
529 log.debug("Path is empty. Maybe devices on the same switch. outPort {}", outPort);
530 } else {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700531 outPort = graphPath.get(0).getSrc().getNumber().value();
TeruU220c45e2014-04-10 18:56:26 -0700532 log.debug("path{}, outPort {}", graphPath, outPort);
533 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700534
535 PushedFlow existingFlow = null;
536
537 synchronized (lock) {
538 existingFlow = pendingFlows.get(path);
539
540 if (existingFlow != null) {
541 existingFlow.installed = true;
542 existingFlow.firstOutPort = outPort;
543 } else {
544 log.debug("ExistingFlow {} is null", path);
545 return;
546 }
547
548 //Check both existing flow are installed status.
549 if (existingFlow.installed) {
550 packets = waitingPackets.removeAll(existingFlow.intentId);
551 if (log.isDebugEnabled()) {
552 log.debug("removed my packets {} to push from waitingPackets. outPort {} size {}",
553 existingFlow.intentId, existingFlow.firstOutPort, packets.size());
554 }
555 } else {
556 log.debug("Forward or reverse flows hasn't been pushed yet. return");
557 return;
558 }
559 }
560
561 for (PacketToPush packet : packets) {
TeruUbd5b90e2014-06-16 14:29:33 -0700562 log.debug("Start packetToPush to sw {}, outPort {}, path {}",
563 packet.dpid, existingFlow.firstOutPort, path);
Jonathan Harte3702f22014-04-29 02:56:56 -0700564 packetService.sendPacket(packet.eth, new SwitchPort(
565 packet.dpid, existingFlow.firstOutPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700566 }
567 }
568
Ray Milkey269ffb92014-04-03 14:43:30 -0700569 @Override
TeruUf9111652014-05-14 23:10:35 -0700570 public void intentsChange(LinkedList<ChangedEvent> events) {
571 for (ChangedEvent event : events) {
572 log.debug("path intent ID {}, eventType {}", event.intent.getId() , event.eventType);
TeruUbd5b90e2014-06-16 14:29:33 -0700573
574 PathIntent pathIntent = null;
575 if (event.intent instanceof PathIntent) {
576 pathIntent = (PathIntent) event.intent;
577 log.trace("pathIntent {}", pathIntent);
578 }
579
Ray Milkeyb29e6262014-04-09 16:02:14 -0700580 if (pathIntent == null) {
TeruU435df322014-06-16 23:45:13 -0700581 log.trace("pathIntent is null. Skip.");
Ray Milkey269ffb92014-04-03 14:43:30 -0700582 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700583 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700584
Ray Milkeyb29e6262014-04-09 16:02:14 -0700585 if (!(pathIntent.getParentIntent() instanceof ShortestPathIntent)) {
TeruU435df322014-06-16 23:45:13 -0700586 log.trace("parentIntent is not ShortestPathIntent. Skip.");
Ray Milkey269ffb92014-04-03 14:43:30 -0700587 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700588 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700589
TeruUf9111652014-05-14 23:10:35 -0700590 switch(event.eventType) {
591 case ADDED:
Ray Milkey269ffb92014-04-03 14:43:30 -0700592 break;
TeruUf9111652014-05-14 23:10:35 -0700593 case REMOVED:
TeruU435df322014-06-16 23:45:13 -0700594 flowRemoved((ShortestPathIntent) pathIntent.getParentIntent());
Ray Milkey269ffb92014-04-03 14:43:30 -0700595 break;
TeruUf9111652014-05-14 23:10:35 -0700596 case STATE_CHANGED:
597 IntentState state = pathIntent.getState();
TeruU5d2c9392014-06-09 20:02:02 -0700598 log.debug("This is STATE_CHANGED. intent id {} is now state {}",
599 pathIntent.getId() , state);
TeruUf9111652014-05-14 23:10:35 -0700600 switch (state) {
601 case INST_REQ:
602 break;
603 case INST_ACK:
604 flowInstalled(pathIntent);
605 break;
606 case INST_NACK:
TeruU435df322014-06-16 23:45:13 -0700607 flowRemoved((ShortestPathIntent) pathIntent.getParentIntent());
TeruUf9111652014-05-14 23:10:35 -0700608 break;
609 case DEL_REQ:
610 break;
611 case DEL_ACK:
TeruU435df322014-06-16 23:45:13 -0700612 flowRemoved((ShortestPathIntent) pathIntent.getParentIntent());
TeruUf9111652014-05-14 23:10:35 -0700613 break;
614 case DEL_PENDING:
615 break;
TeruUbd5b90e2014-06-16 14:29:33 -0700616 case REROUTE_REQ:
617 break;
TeruUf9111652014-05-14 23:10:35 -0700618 default:
619 break;
620 }
Ray Milkey149693c2014-05-20 14:58:53 -0700621 break;
Ray Milkey269ffb92014-04-03 14:43:30 -0700622 default:
623 break;
624 }
625 }
626 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800627}