blob: 4cb8bc7ad8d101414c79cef2c77896e6d4beb1bd [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2 * Copyright 2011, Big Switch Networks, Inc.
3 * Originally created by David Erickson, Stanford University
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 * not use this file except in compliance with the License. You may obtain
7 * a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 **/
17
Jonathan Hart23701d12014-04-03 10:45:48 -070018package net.onrc.onos.core.linkdiscovery.internal;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080019
20import java.io.IOException;
21import java.net.InetAddress;
22import java.net.InetSocketAddress;
23import java.net.NetworkInterface;
24import java.net.SocketAddress;
25import java.nio.ByteBuffer;
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.Collections;
29import java.util.HashMap;
30import java.util.HashSet;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34import java.util.Map.Entry;
35import java.util.Set;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080036import java.util.concurrent.LinkedBlockingQueue;
37import java.util.concurrent.ScheduledExecutorService;
38import java.util.concurrent.TimeUnit;
39import java.util.concurrent.locks.ReentrantReadWriteLock;
40
41import net.floodlightcontroller.core.FloodlightContext;
42import net.floodlightcontroller.core.IFloodlightProviderService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080043import net.floodlightcontroller.core.IOFMessageListener;
44import net.floodlightcontroller.core.IOFSwitch;
45import net.floodlightcontroller.core.IOFSwitchListener;
46import net.floodlightcontroller.core.annotations.LogMessageCategory;
47import net.floodlightcontroller.core.annotations.LogMessageDoc;
48import net.floodlightcontroller.core.annotations.LogMessageDocs;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070049import net.floodlightcontroller.core.internal.OFSwitchImpl;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080050import net.floodlightcontroller.core.module.FloodlightModuleContext;
51import net.floodlightcontroller.core.module.FloodlightModuleException;
52import net.floodlightcontroller.core.module.IFloodlightModule;
53import net.floodlightcontroller.core.module.IFloodlightService;
54import net.floodlightcontroller.core.util.SingletonTask;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080055import net.floodlightcontroller.restserver.IRestApiService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080056import net.floodlightcontroller.threadpool.IThreadPoolService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080057import net.floodlightcontroller.util.EventHistory;
58import net.floodlightcontroller.util.EventHistory.EvAction;
Jonathan Hart23701d12014-04-03 10:45:48 -070059import net.onrc.onos.core.linkdiscovery.ILinkDiscovery;
Jonathan Harta99ec672014-04-03 11:30:34 -070060import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
61import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.UpdateOperation;
Jonathan Hart23701d12014-04-03 10:45:48 -070062import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
63import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
64import net.onrc.onos.core.linkdiscovery.Link;
65import net.onrc.onos.core.linkdiscovery.LinkInfo;
66import net.onrc.onos.core.linkdiscovery.NodePortTuple;
Jonathan Hart23701d12014-04-03 10:45:48 -070067import net.onrc.onos.core.linkdiscovery.web.LinkDiscoveryWebRoutable;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070068import net.onrc.onos.core.main.IOnosRemoteSwitch;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070069import net.onrc.onos.core.packet.BSN;
70import net.onrc.onos.core.packet.Ethernet;
71import net.onrc.onos.core.packet.IPv4;
72import net.onrc.onos.core.packet.LLDP;
73import net.onrc.onos.core.packet.LLDPTLV;
74import net.onrc.onos.core.registry.IControllerRegistryService;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -070075
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080076import org.openflow.protocol.OFMessage;
77import org.openflow.protocol.OFPacketIn;
78import org.openflow.protocol.OFPacketOut;
79import org.openflow.protocol.OFPhysicalPort;
80import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
81import org.openflow.protocol.OFPhysicalPort.OFPortState;
82import org.openflow.protocol.OFPort;
83import org.openflow.protocol.OFPortStatus;
84import org.openflow.protocol.OFPortStatus.OFPortReason;
85import org.openflow.protocol.OFType;
86import org.openflow.protocol.action.OFAction;
87import org.openflow.protocol.action.OFActionOutput;
88import org.openflow.util.HexString;
89import org.slf4j.Logger;
90import org.slf4j.LoggerFactory;
91
92/**
93 * This class sends out LLDP messages containing the sending switch's datapath
94 * id as well as the outgoing port number. Received LLrescDP messages that
95 * match a known switch cause a new LinkTuple to be created according to the
96 * invariant rules listed below. This new LinkTuple is also passed to routing
97 * if it exists to trigger updates.
Ray Milkey269ffb92014-04-03 14:43:30 -070098 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080099 * This class also handles removing links that are associated to switch ports
100 * that go down, and switches that are disconnected.
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800102 * Invariants:
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 * -portLinks and switchLinks will not contain empty Sets outside of
104 * critical sections
105 * -portLinks contains LinkTuples where one of the src or dst
106 * SwitchPortTuple matches the map key
107 * -switchLinks contains LinkTuples where one of the src or dst
108 * SwitchPortTuple's id matches the switch id
109 * -Each LinkTuple will be indexed into switchLinks for both
110 * src.id and dst.id, and portLinks for each src and dst
111 * -The updates queue is only added to from within a held write lock
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800112 */
113@LogMessageCategory("Network Topology")
114public class LinkDiscoveryManager
Ray Milkey269ffb92014-04-03 14:43:30 -0700115 implements IOFMessageListener, IOFSwitchListener,
116 ILinkDiscoveryService, IFloodlightModule {
117 protected IFloodlightProviderService controller;
Ray Milkeyec838942014-04-09 11:28:43 -0700118 private static final Logger log = LoggerFactory.getLogger(LinkDiscoveryManager.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800119
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800120 protected IFloodlightProviderService floodlightProvider;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800121 protected IThreadPoolService threadPool;
122 protected IRestApiService restApi;
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700123 // Registry Service for ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700124 protected IControllerRegistryService registryService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800125
HIGUCHI Yutae0515e52013-06-14 13:00:40 -0700126
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800127 // LLDP and BDDP fields
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800128 private static final byte[] LLDP_STANDARD_DST_MAC_STRING =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800129 HexString.fromHexString("01:80:c2:00:00:0e");
Ray Milkey269ffb92014-04-03 14:43:30 -0700130 private static final long LINK_LOCAL_MASK = 0xfffffffffff0L;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800131 private static final long LINK_LOCAL_VALUE = 0x0180c2000000L;
132
133 // BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version
Masayoshi Kobayashi71137362013-07-12 15:54:52 -0700134 // private static final String LLDP_BSN_DST_MAC_STRING = "5d:16:c7:00:00:01";
135 private static final String LLDP_BSN_DST_MAC_STRING = "ff:ff:ff:ff:ff:ff";
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800136
137
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800138 // Direction TLVs are used to indicate if the LLDPs were sent
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800139 // periodically or in response to a recieved LLDP
140 private static final byte TLV_DIRECTION_TYPE = 0x73;
141 private static final short TLV_DIRECTION_LENGTH = 1; // 1 byte
Ray Milkey45614c52014-04-07 16:30:54 -0700142 private static final byte[] TLV_DIRECTION_VALUE_FORWARD = {0x01};
143 private static final byte[] TLV_DIRECTION_VALUE_REVERSE = {0x02};
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700144 private static final LLDPTLV FORWARD_TLV
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 = new LLDPTLV().
146 setType(TLV_DIRECTION_TYPE).
147 setLength(TLV_DIRECTION_LENGTH).
148 setValue(TLV_DIRECTION_VALUE_FORWARD);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800149
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700150 private static final LLDPTLV REVERSE_TLV
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 = new LLDPTLV().
152 setType(TLV_DIRECTION_TYPE).
153 setLength(TLV_DIRECTION_LENGTH).
154 setValue(TLV_DIRECTION_VALUE_REVERSE);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800155
156 // Link discovery task details.
157 protected SingletonTask discoveryTask;
Ray Milkey2476cac2014-04-08 11:03:21 -0700158 protected static final int DISCOVERY_TASK_INTERVAL = 1;
159 protected static final int LINK_TIMEOUT = 35; // original 35 secs, aggressive 5 secs
160 protected static final int LLDP_TO_ALL_INTERVAL = 15; //original 15 seconds, aggressive 2 secs.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800161 protected long lldpClock = 0;
162 // This value is intentionally kept higher than LLDP_TO_ALL_INTERVAL.
163 // If we want to identify link failures faster, we could decrease this
164 // value to a small number, say 1 or 2 sec.
Ray Milkey2476cac2014-04-08 11:03:21 -0700165 protected static final int LLDP_TO_KNOWN_INTERVAL = 20; // LLDP frequency for known links
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800166
167 protected LLDPTLV controllerTLV;
168 protected ReentrantReadWriteLock lock;
169 int lldpTimeCount = 0;
HIGUCHI Yutae0515e52013-06-14 13:00:40 -0700170
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800171 /**
172 * Flag to indicate if automatic port fast is enabled or not.
173 * Default is set to false -- Initialized in the init method as well.
174 */
175 boolean autoPortFastFeature = false;
176
177 /**
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800178 * Map of remote switches that are not connected to this controller. This
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700179 * is used to learn remote switches in a distributed controller ONOS.
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800180 */
HIGUCHI Yuta7677a6f2013-06-14 14:13:35 -0700181 protected Map<Long, IOnosRemoteSwitch> remoteSwitches;
HIGUCHI Yuta3d96f652013-06-17 12:07:48 -0700182
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800183 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800184 * Map from link to the most recent time it was verified functioning
185 */
186 protected Map<Link, LinkInfo> links;
187
188 /**
189 * Map from switch id to a set of all links with it as an endpoint
190 */
191 protected Map<Long, Set<Link>> switchLinks;
192
193 /**
194 * Map from a id:port to the set of links containing it as an endpoint
195 */
196 protected Map<NodePortTuple, Set<Link>> portLinks;
197
198 /**
199 * Set of link tuples over which multicast LLDPs are received
200 * and unicast LLDPs are not received.
201 */
202 protected Map<NodePortTuple, Set<Link>> portBroadcastDomainLinks;
203
204 protected volatile boolean shuttingDown = false;
205
206 /* topology aware components are called in the order they were added to the
207 * the array */
208 protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800209
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700210 protected class LinkUpdate extends LDUpdate {
211
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 public LinkUpdate(LDUpdate old) {
213 super(old);
214 }
215
216 @LogMessageDoc(level = "ERROR",
217 message = "Error in link discovery updates loop",
218 explanation = "An unknown error occured while dispatching " +
219 "link update notifications",
220 recommendation = LogMessageDoc.GENERIC_ACTION)
221 @Override
222 public void dispatch() {
223 if (linkDiscoveryAware != null) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800224 if (log.isTraceEnabled()) {
225 log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700226 new Object[]{this.getOperation(),
227 HexString.toHexString(this.getSrc()), this.getSrcPort(),
228 HexString.toHexString(this.getDst()), this.getDstPort(),
229 linkDiscoveryAware});
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800230 }
231 try {
232 for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
233 lda.linkDiscoveryUpdate(this);
234 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700235 } catch (Exception e) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800236 log.error("Error in link discovery updates loop", e);
237 }
238 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700239 }
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700240 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800241
242 /**
243 * List of ports through which LLDP/BDDPs are not sent.
244 */
245 protected Set<NodePortTuple> suppressLinkDiscovery;
246
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 /**
248 * A list of ports that are quarantined for discovering links through
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800249 * them. Data traffic from these ports are not allowed until the ports
250 * are released from quarantine.
251 */
252 protected LinkedBlockingQueue<NodePortTuple> quarantineQueue;
253 protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue;
254 /**
255 * Quarantine task
256 */
257 protected SingletonTask bddpTask;
Ray Milkey2476cac2014-04-08 11:03:21 -0700258 protected static final int BDDP_TASK_INTERVAL = 100; // 100 ms.
259 protected static final int BDDP_TASK_SIZE = 5; // # of ports per iteration
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800260
261 /**
262 * Map of broadcast domain ports and the last time a BDDP was either
263 * sent or received on that port.
264 */
265 protected Map<NodePortTuple, Long> broadcastDomainPortTimeMap;
266
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800267 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800268 * Get the LLDP sending period in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700269 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800270 * @return LLDP sending period in seconds.
271 */
272 public int getLldpFrequency() {
273 return LLDP_TO_KNOWN_INTERVAL;
274 }
275
276 /**
277 * Get the LLDP timeout value in seconds
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800279 * @return LLDP timeout value in seconds
280 */
281 public int getLldpTimeout() {
282 return LINK_TIMEOUT;
283 }
284
285 public Map<NodePortTuple, Set<Link>> getPortLinks() {
286 return portLinks;
287 }
288
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800289 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800290 public Set<NodePortTuple> getSuppressLLDPsInfo() {
291 return suppressLinkDiscovery;
292 }
293
294 /**
295 * Add a switch port to the suppressed LLDP list.
296 * Remove any known links on the switch port.
297 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800298 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700299 public void addToSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800300 NodePortTuple npt = new NodePortTuple(sw, port);
301 this.suppressLinkDiscovery.add(npt);
302 deleteLinksOnPort(npt, "LLDP suppressed.");
303 }
304
305 /**
306 * Remove a switch port from the suppressed LLDP list.
307 * Discover links on that switchport.
308 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800309 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700310 public void removeFromSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800311 NodePortTuple npt = new NodePortTuple(sw, port);
312 this.suppressLinkDiscovery.remove(npt);
313 discover(npt);
314 }
315
316 public boolean isShuttingDown() {
317 return shuttingDown;
318 }
319
320 public boolean isFastPort(long sw, short port) {
321 return false;
322 }
323
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800324 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800325 public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) {
326 if (info.getUnicastValidTime() != null) {
327 return ILinkDiscovery.LinkType.DIRECT_LINK;
328 } else if (info.getMulticastValidTime() != null) {
329 return ILinkDiscovery.LinkType.MULTIHOP_LINK;
330 }
331 return ILinkDiscovery.LinkType.INVALID_LINK;
332 }
333
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800334
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800335 private boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
336 return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber));
337 }
338
339 protected void discoverLinks() {
340
341 // timeout known links.
342 timeoutLinks();
343
344 //increment LLDP clock
Ray Milkey269ffb92014-04-03 14:43:30 -0700345 lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800346
347 if (lldpClock == 0) {
348 log.debug("Sending LLDP out on all ports.");
349 discoverOnAllPorts();
350 }
351 }
352
353
354 /**
Ray Milkey269ffb92014-04-03 14:43:30 -0700355 * Quarantine Ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800356 */
357 protected class QuarantineWorker implements Runnable {
358 @Override
359 public void run() {
360 try {
361 processBDDPLists();
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 } catch (Exception e) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800363 log.error("Error in quarantine worker thread", e);
364 } finally {
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 bddpTask.reschedule(BDDP_TASK_INTERVAL,
366 TimeUnit.MILLISECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800367 }
368 }
369 }
370
371 /**
372 * Add a switch port to the quarantine queue. Schedule the
373 * quarantine task if the quarantine queue was empty before adding
374 * this switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -0700375 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800376 * @param npt
377 */
378 protected void addToQuarantineQueue(NodePortTuple npt) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700379 if (quarantineQueue.contains(npt) == false) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800380 quarantineQueue.add(npt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700381 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800382 }
383
384 /**
385 * Remove a switch port from the quarantine queue.
386 */
387 protected void removeFromQuarantineQueue(NodePortTuple npt) {
388 // Remove all occurrences of the node port tuple from the list.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700389 boolean removedSomething;
390
391 do {
392 removedSomething = quarantineQueue.remove(npt);
393 } while (removedSomething);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800394 }
395
396 /**
397 * Add a switch port to maintenance queue.
Ray Milkey269ffb92014-04-03 14:43:30 -0700398 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800399 * @param npt
400 */
401 protected void addToMaintenanceQueue(NodePortTuple npt) {
402 // TODO We are not checking if the switch port tuple is already
403 // in the maintenance list or not. This will be an issue for
404 // really large number of switch ports in the network.
Ray Milkeyb29e6262014-04-09 16:02:14 -0700405 if (maintenanceQueue.contains(npt) == false) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800406 maintenanceQueue.add(npt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700407 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800408 }
409
410 /**
411 * Remove a switch port from maintenance queue.
Ray Milkey269ffb92014-04-03 14:43:30 -0700412 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800413 * @param npt
414 */
415 protected void removeFromMaintenanceQueue(NodePortTuple npt) {
416 // Remove all occurrences of the node port tuple from the queue.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700417 boolean removedSomething;
418 do {
419 removedSomething = maintenanceQueue.remove(npt);
420 } while (removedSomething);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800421 }
422
423 /**
Ray Milkey269ffb92014-04-03 14:43:30 -0700424 * This method processes the quarantine list in bursts. The task is
425 * at most once per BDDP_TASK_INTERVAL.
426 * One each call, BDDP_TASK_SIZE number of switch ports are processed.
427 * Once the BDDP packets are sent out through the switch ports, the ports
428 * are removed from the quarantine list.
429 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800430
431 protected void processBDDPLists() {
432 int count = 0;
433 Set<NodePortTuple> nptList = new HashSet<NodePortTuple>();
434
Ray Milkey269ffb92014-04-03 14:43:30 -0700435 while (count < BDDP_TASK_SIZE && quarantineQueue.peek() != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800436 NodePortTuple npt;
437 npt = quarantineQueue.remove();
438 sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
439 nptList.add(npt);
440 count++;
441 }
442
443 count = 0;
444 while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) {
445 NodePortTuple npt;
446 npt = maintenanceQueue.remove();
447 sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
448 count++;
449 }
450
Ray Milkey269ffb92014-04-03 14:43:30 -0700451 for (NodePortTuple npt : nptList) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800452 generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId());
453 }
454 }
455
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800456 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800457 public Set<Short> getQuarantinedPorts(long sw) {
458 Set<Short> qPorts = new HashSet<Short>();
459
460 Iterator<NodePortTuple> iter = quarantineQueue.iterator();
461 while (iter.hasNext()) {
462 NodePortTuple npt = iter.next();
463 if (npt.getNodeId() == sw) {
464 qPorts.add(npt.getPortId());
465 }
466 }
467 return qPorts;
468 }
469
470 private void generateSwitchPortStatusUpdate(long sw, short port) {
471 UpdateOperation operation;
472
473 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700474 if (iofSwitch == null) {
475 return;
476 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800477
478 OFPhysicalPort ofp = iofSwitch.getPort(port);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700479 if (ofp == null) {
480 return;
481 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800482
483 int srcPortState = ofp.getState();
484 boolean portUp = ((srcPortState &
485 OFPortState.OFPPS_STP_MASK.getValue()) !=
486 OFPortState.OFPPS_STP_BLOCK.getValue());
487
Ray Milkeyb29e6262014-04-09 16:02:14 -0700488 if (portUp) {
489 operation = UpdateOperation.PORT_UP;
490 } else {
491 operation = UpdateOperation.PORT_DOWN;
492 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800493
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700494 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800495
496
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700497 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800498 }
499
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800500 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800501 * Send LLDP on known ports
502 */
503 protected void discoverOnKnownLinkPorts() {
504 // Copy the port set.
505 Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
506 nptSet.addAll(portLinks.keySet());
507
508 // Send LLDP from each of them.
Ray Milkey269ffb92014-04-03 14:43:30 -0700509 for (NodePortTuple npt : nptSet) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800510 discover(npt);
511 }
512 }
513
514 protected void discover(NodePortTuple npt) {
515 discover(npt.getNodeId(), npt.getPortId());
516 }
517
518 protected void discover(long sw, short port) {
519 sendDiscoveryMessage(sw, port, true, false);
520 }
521
522 /**
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700523 * Learn remote switches when running as a distributed controller ONOS
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800524 */
525 protected IOFSwitch addRemoteSwitch(long sw, short port) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 IOnosRemoteSwitch remotesw = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800527
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 // add a switch if we have not seen it before
529 remotesw = remoteSwitches.get(sw);
Jonathan Harte7231052013-01-25 00:01:14 -0800530
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 if (remotesw == null) {
532 remotesw = new OFSwitchImpl();
533 remotesw.setupRemoteSwitch(sw);
534 remoteSwitches.put(remotesw.getId(), remotesw);
535 log.debug("addRemoteSwitch(): added fake remote sw {}", remotesw);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800536 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800537
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800538 // add the port if we have not seen it before
Umesh Krishnaswamy68c118c2013-01-25 11:07:09 -0800539 if (remotesw.getPort(port) == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700540 OFPhysicalPort remoteport = new OFPhysicalPort();
541 remoteport.setPortNumber(port);
542 remoteport.setName("fake_" + port);
543 remoteport.setConfig(0);
544 remoteport.setState(0);
545 remotesw.setPort(remoteport);
546 log.debug("addRemoteSwitch(): added fake remote port {} to sw {}", remoteport, remotesw.getId());
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800547 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800548
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800549 return remotesw;
550 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800551
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800552 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800553 * Send link discovery message out of a given switch port.
554 * The discovery message may be a standard LLDP or a modified
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800555 * LLDP, where the dst mac address is set to :ff.
Ray Milkey269ffb92014-04-03 14:43:30 -0700556 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800557 * TODO: The modified LLDP will updated in the future and may
558 * use a different eth-type.
Ray Milkey269ffb92014-04-03 14:43:30 -0700559 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800560 * @param sw
561 * @param port
Ray Milkey269ffb92014-04-03 14:43:30 -0700562 * @param isStandard indicates standard or modified LLDP
563 * @param isReverse indicates whether the LLDP was sent as a response
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800564 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700565 @LogMessageDoc(level = "ERROR",
566 message = "Failure sending LLDP out port {port} on switch {switch}",
567 explanation = "An I/O error occured while sending LLDP message " +
568 "to the switch.",
569 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800570 protected void sendDiscoveryMessage(long sw, short port,
Ray Milkey269ffb92014-04-03 14:43:30 -0700571 boolean isStandard,
572 boolean isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800573
574 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
575 if (iofSwitch == null) {
576 return;
577 }
578
Ray Milkeyb29e6262014-04-09 16:02:14 -0700579 if (port == OFPort.OFPP_LOCAL.getValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800580 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700581 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800582
583 OFPhysicalPort ofpPort = iofSwitch.getPort(port);
584
585 if (ofpPort == null) {
586 if (log.isTraceEnabled()) {
587 log.trace("Null physical port. sw={}, port={}", sw, port);
588 }
589 return;
590 }
591
592 if (isLinkDiscoverySuppressed(sw, port)) {
593 /* Dont send LLDPs out of this port as suppressLLDPs set
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800594 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800595 */
596 return;
597 }
598
599 // For fast ports, do not send forward LLDPs or BDDPs.
Ray Milkeyb29e6262014-04-09 16:02:14 -0700600 if (!isReverse && autoPortFastFeature && isFastPort(sw, port)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800601 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700602 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800603
604 if (log.isTraceEnabled()) {
605 log.trace("Sending LLDP packet out of swich: {}, port: {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700606 sw, port);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800607 }
608
609 // using "nearest customer bridge" MAC address for broadest possible propagation
610 // through provider and TPMR bridges (see IEEE 802.1AB-2009 and 802.1Q-2011),
611 // in particular the Linux bridge which behaves mostly like a provider bridge
Ray Milkey269ffb92014-04-03 14:43:30 -0700612 byte[] chassisId = new byte[]{4, 0, 0, 0, 0, 0, 0}; // filled in later
613 byte[] portId = new byte[]{2, 0, 0}; // filled in later
614 byte[] ttlValue = new byte[]{0, 0x78};
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800615 // OpenFlow OUI - 00-26-E1
Ray Milkey269ffb92014-04-03 14:43:30 -0700616 byte[] dpidTLVValue = new byte[]{0x0, 0x26, (byte) 0xe1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800617 LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127).setLength((short) dpidTLVValue.length).setValue(dpidTLVValue);
618
619 byte[] dpidArray = new byte[8];
620 ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray);
621 ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2);
622
623 Long dpid = sw;
624 dpidBB.putLong(dpid);
625 // set the ethernet source mac to last 6 bytes of dpid
626 System.arraycopy(dpidArray, 2, ofpPort.getHardwareAddress(), 0, 6);
627 // set the chassis id's value to last 6 bytes of dpid
628 System.arraycopy(dpidArray, 2, chassisId, 1, 6);
629 // set the optional tlv to the full dpid
630 System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8);
631
632
633 // set the portId to the outgoing port
634 portBB.putShort(port);
635 if (log.isTraceEnabled()) {
636 log.trace("Sending LLDP out of interface: {}/{}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700637 HexString.toHexString(sw), port);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800638 }
639
640 LLDP lldp = new LLDP();
641 lldp.setChassisId(new LLDPTLV().setType((byte) 1).setLength((short) chassisId.length).setValue(chassisId));
642 lldp.setPortId(new LLDPTLV().setType((byte) 2).setLength((short) portId.length).setValue(portId));
643 lldp.setTtl(new LLDPTLV().setType((byte) 3).setLength((short) ttlValue.length).setValue(ttlValue));
644 lldp.getOptionalTLVList().add(dpidTLV);
645
646 // Add the controller identifier to the TLV value.
647 lldp.getOptionalTLVList().add(controllerTLV);
648 if (isReverse) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700649 lldp.getOptionalTLVList().add(REVERSE_TLV);
Ray Milkey269ffb92014-04-03 14:43:30 -0700650 } else {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700651 lldp.getOptionalTLVList().add(FORWARD_TLV);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800652 }
653
654 Ethernet ethernet;
655 if (isStandard) {
656 ethernet = new Ethernet()
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 .setSourceMACAddress(ofpPort.getHardwareAddress())
658 .setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING)
659 .setEtherType(Ethernet.TYPE_LLDP);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800660 ethernet.setPayload(lldp);
661 } else {
662 BSN bsn = new BSN(BSN.BSN_TYPE_BDDP);
663 bsn.setPayload(lldp);
664
665 ethernet = new Ethernet()
Ray Milkey269ffb92014-04-03 14:43:30 -0700666 .setSourceMACAddress(ofpPort.getHardwareAddress())
667 .setDestinationMACAddress(LLDP_BSN_DST_MAC_STRING)
668 .setEtherType(Ethernet.TYPE_BSN);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800669 ethernet.setPayload(bsn);
670 }
671
672
673 // serialize and wrap in a packet out
674 byte[] data = ethernet.serialize();
675 OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
676 po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
677 po.setInPort(OFPort.OFPP_NONE);
678
679 // set actions
680 List<OFAction> actions = new ArrayList<OFAction>();
681 actions.add(new OFActionOutput(port, (short) 0));
682 po.setActions(actions);
683 po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
684
685 // set data
686 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + data.length);
687 po.setPacketData(data);
688
689 // send
690 try {
691 iofSwitch.write(po, null);
692 iofSwitch.flush();
693 } catch (IOException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 log.error("Failure sending LLDP out port " + port + " on switch " + iofSwitch.getStringId(), e);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800695 }
696
697 }
698
699 /**
700 * Send LLDPs to all switch-ports
701 */
702 protected void discoverOnAllPorts() {
703 if (log.isTraceEnabled()) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800704 log.trace("Sending LLDP packets out of all the enabled ports on switch");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800705 }
706 Set<Long> switches = floodlightProvider.getSwitches().keySet();
707 // Send standard LLDPs
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 for (long sw : switches) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800709 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700710 if (iofSwitch == null) {
711 continue;
712 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800713 if (iofSwitch.getEnabledPorts() != null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 for (OFPhysicalPort ofp : iofSwitch.getEnabledPorts()) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700715 if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800716 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700717 }
718 if (autoPortFastFeature && isFastPort(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800719 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700720 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800721
722 // sends forward LLDP only non-fastports.
723 sendDiscoveryMessage(sw, ofp.getPortNumber(), true, false);
724
725 // If the switch port is not alreayd in the maintenance
726 // queue, add it.
727 NodePortTuple npt = new NodePortTuple(sw, ofp.getPortNumber());
728 addToMaintenanceQueue(npt);
729 }
730 }
731 }
732 }
733
734 protected void setControllerTLV() {
735 //Setting the controllerTLVValue based on current nano time,
736 //controller's IP address, and the network interface object hash
737 //the corresponding IP address.
738
739 final int prime = 7867;
740 InetAddress localIPAddress = null;
741 NetworkInterface localInterface = null;
742
Ray Milkey269ffb92014-04-03 14:43:30 -0700743 byte[] controllerTLVValue = new byte[]{0, 0, 0, 0, 0, 0, 0, 0}; // 8 byte value.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800744 ByteBuffer bb = ByteBuffer.allocate(10);
745
Ray Milkey269ffb92014-04-03 14:43:30 -0700746 try {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800747 localIPAddress = java.net.InetAddress.getLocalHost();
748 localInterface = NetworkInterface.getByInetAddress(localIPAddress);
749 } catch (Exception e) {
750 e.printStackTrace();
751 }
752
753 long result = System.nanoTime();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700754 if (localIPAddress != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800755 result = result * prime + IPv4.toIPv4Address(localIPAddress.getHostAddress());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700756 }
757 if (localInterface != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800758 result = result * prime + localInterface.hashCode();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700759 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800760 // set the first 4 bits to 0.
761 result = result & (0x0fffffffffffffffL);
762
763 bb.putLong(result);
764
765 bb.rewind();
766 bb.get(controllerTLVValue, 0, 8);
767
768 this.controllerTLV = new LLDPTLV().setType((byte) 0x0c).setLength((short) controllerTLVValue.length).setValue(controllerTLVValue);
769 }
770
771 @Override
772 public String getName() {
773 return "linkdiscovery";
774 }
775
776 @Override
777 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
778 switch (msg.getType()) {
779 case PACKET_IN:
780 return this.handlePacketIn(sw.getId(), (OFPacketIn) msg, cntx);
781 case PORT_STATUS:
782 return this.handlePortStatus(sw.getId(), (OFPortStatus) msg);
783 default:
784 break;
785 }
786 return Command.CONTINUE;
787 }
788
789 private Command handleLldp(LLDP lldp, long sw, OFPacketIn pi, boolean isStandard, FloodlightContext cntx) {
790 // If LLDP is suppressed on this port, ignore received packet as well
791 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
792 if (iofSwitch == null) {
793 return Command.STOP;
794 }
795
Ray Milkeyb29e6262014-04-09 16:02:14 -0700796 if (isLinkDiscoverySuppressed(sw, pi.getInPort())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800797 return Command.STOP;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700798 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800799
800 // If this is a malformed LLDP, or not from us, exit
Ray Milkeyb29e6262014-04-09 16:02:14 -0700801 if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800802 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700803 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800804
805 long myId = ByteBuffer.wrap(controllerTLV.getValue()).getLong();
806 long otherId = 0;
807 boolean myLLDP = false;
808 Boolean isReverse = null;
809
810 ByteBuffer portBB = ByteBuffer.wrap(lldp.getPortId().getValue());
811 portBB.position(1);
812
813 Short remotePort = portBB.getShort();
814 IOFSwitch remoteSwitch = null;
815
816 // Verify this LLDP packet matches what we're looking for
817 for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
818 if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 &&
819 lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 &&
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 lldptlv.getValue()[2] == (byte) 0xe1 && lldptlv.getValue()[3] == 0x0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800821 ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
822 remoteSwitch = floodlightProvider.getSwitches().get(dpidBB.getLong(4));
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800823 if (remoteSwitch == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700824 // Added by ONOS
825 // floodlight LLDP coming from a remote switch connected to a different controller
826 // add it to our cache of unconnected remote switches
827 remoteSwitch = addRemoteSwitch(dpidBB.getLong(4), remotePort);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800828 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700829 } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800830 otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700831 if (myId == otherId) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800832 myLLDP = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700833 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800834 } else if (lldptlv.getType() == TLV_DIRECTION_TYPE &&
835 lldptlv.getLength() == TLV_DIRECTION_LENGTH) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700836 if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0]) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800837 isReverse = false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700838 } else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0]) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800839 isReverse = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700840 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800841 }
842 }
843
844 if (myLLDP == false) {
845 // This is not the LLDP sent by this controller.
846 // If the LLDP message has multicast bit set, then we need to broadcast
847 // the packet as a regular packet.
848 if (isStandard) {
849 if (log.isTraceEnabled()) {
850 log.trace("Getting standard LLDP from a different controller and quelching it.");
851 }
852 return Command.STOP;
Ray Milkey269ffb92014-04-03 14:43:30 -0700853 } else if (sw <= remoteSwitch.getId()) {
Teru Ub7246af2014-01-13 13:24:38 -0800854 if (log.isTraceEnabled()) {
855 log.trace("Getting BBDP from a different controller. myId {}: remoteId {}", myId, otherId);
856 log.trace("and my controller id is smaller than the other, so quelching it. myPort {}: rPort {}", pi.getInPort(), remotePort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700857 }
858 //XXX ONOS: Fix the BDDP broadcast issue
859 //return Command.CONTINUE;
860 return Command.STOP;
Teru Ub7246af2014-01-13 13:24:38 -0800861 }
862 /*
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800863 else if (myId < otherId) {
864 if (log.isTraceEnabled()) {
865 log.trace("Getting BDDP packets from a different controller" +
866 "and letting it go through normal processing chain.");
867 }
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700868 //XXX ONOS: Fix the BDDP broadcast issue
Jonathan Hart0b2c76a2013-02-27 17:09:33 -0800869 //return Command.CONTINUE;
870 return Command.STOP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800871 }
Teru Ub7246af2014-01-13 13:24:38 -0800872 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800873 }
874
875
876 if (remoteSwitch == null) {
877 // Ignore LLDPs not generated by Floodlight, or from a switch that has recently
878 // disconnected, or from a switch connected to another Floodlight instance
879 if (log.isTraceEnabled()) {
880 log.trace("Received LLDP from remote switch not connected to the controller");
881 }
882 return Command.STOP;
883 }
884
885 if (!remoteSwitch.portEnabled(remotePort)) {
886 if (log.isTraceEnabled()) {
887 log.trace("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
888 }
889 return Command.STOP;
890 }
891 if (suppressLinkDiscovery.contains(new NodePortTuple(remoteSwitch.getId(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700892 remotePort))) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800893 if (log.isTraceEnabled()) {
894 log.trace("Ignoring link with suppressed src port: switch {} port {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700895 remoteSwitch, remotePort);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800896 }
897 return Command.STOP;
898 }
899 if (!iofSwitch.portEnabled(pi.getInPort())) {
900 if (log.isTraceEnabled()) {
901 log.trace("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
902 }
903 return Command.STOP;
904 }
905
906 OFPhysicalPort physicalPort = remoteSwitch.getPort(remotePort);
907 int srcPortState = (physicalPort != null) ? physicalPort.getState() : 0;
908 physicalPort = iofSwitch.getPort(pi.getInPort());
909 int dstPortState = (physicalPort != null) ? physicalPort.getState() : 0;
910
911 // Store the time of update to this link, and push it out to routingEngine
912 Link lt = new Link(remoteSwitch.getId(), remotePort, iofSwitch.getId(), pi.getInPort());
913
914
915 Long lastLldpTime = null;
916 Long lastBddpTime = null;
917
918 Long firstSeenTime = System.currentTimeMillis();
919
Ray Milkeyb29e6262014-04-09 16:02:14 -0700920 if (isStandard) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800921 lastLldpTime = System.currentTimeMillis();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700922 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800923 lastBddpTime = System.currentTimeMillis();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700924 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800925
926 LinkInfo newLinkInfo =
927 new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
Ray Milkey269ffb92014-04-03 14:43:30 -0700928 srcPortState, dstPortState);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800929
930 addOrUpdateLink(lt, newLinkInfo);
931
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800932 // Check if reverse link exists.
933 // If it doesn't exist and if the forward link was seen
934 // first seen within a small interval, send probe on the
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800935 // reverse link.
936
937 newLinkInfo = links.get(lt);
938 if (newLinkInfo != null && isStandard && isReverse == false) {
939 Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700940 lt.getSrc(), lt.getSrcPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800941 LinkInfo reverseInfo = links.get(reverseLink);
942 if (reverseInfo == null) {
943 // the reverse link does not exist.
944 if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis() - LINK_TIMEOUT) {
945 this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), isStandard, true);
946 }
947 }
948 }
949
950 // If the received packet is a BDDP packet, then create a reverse BDDP
951 // link as well.
952 if (!isStandard) {
953 Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 lt.getSrc(), lt.getSrcPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800955
956 // srcPortState and dstPort state are reversed.
957 LinkInfo reverseInfo =
958 new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
Ray Milkey269ffb92014-04-03 14:43:30 -0700959 dstPortState, srcPortState);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800960
961 addOrUpdateLink(reverseLink, reverseInfo);
962 }
963
964 // Remove the node ports from the quarantine and maintenance queues.
965 NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
966 NodePortTuple nptDst = new NodePortTuple(lt.getDst(), lt.getDstPort());
967 removeFromQuarantineQueue(nptSrc);
968 removeFromMaintenanceQueue(nptSrc);
969 removeFromQuarantineQueue(nptDst);
970 removeFromMaintenanceQueue(nptDst);
971
972 // Consume this message
973 return Command.STOP;
974 }
975
976 protected Command handlePacketIn(long sw, OFPacketIn pi,
977 FloodlightContext cntx) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800978 Ethernet eth =
979 IFloodlightProviderService.bcStore.get(cntx,
Ray Milkey269ffb92014-04-03 14:43:30 -0700980 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800981
Ray Milkey269ffb92014-04-03 14:43:30 -0700982 if (eth.getEtherType() == Ethernet.TYPE_BSN) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800983 BSN bsn = (BSN) eth.getPayload();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700984 if (bsn == null) {
985 return Command.STOP;
986 }
987 if (bsn.getPayload() == null) {
988 return Command.STOP;
989 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800990 // It could be a packet other than BSN LLDP, therefore
991 // continue with the regular processing.
Ray Milkeyb29e6262014-04-09 16:02:14 -0700992 if (bsn.getPayload() instanceof LLDP == false) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800993 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700994 }
Ubuntu9cbb4ca2013-02-07 17:19:59 +0000995 return handleLldp((LLDP) bsn.getPayload(), sw, pi, false, cntx);
Ray Milkey269ffb92014-04-03 14:43:30 -0700996 } else if (eth.getEtherType() == Ethernet.TYPE_LLDP) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800997 return handleLldp((LLDP) eth.getPayload(), sw, pi, true, cntx);
998 } else if (eth.getEtherType() < 1500) {
999 long destMac = eth.getDestinationMAC().toLong();
Ray Milkey269ffb92014-04-03 14:43:30 -07001000 if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001001 if (log.isTraceEnabled()) {
1002 log.trace("Ignoring packet addressed to 802.1D/Q " +
1003 "reserved address.");
1004 }
1005 return Command.STOP;
1006 }
1007 }
1008
1009 // If packet-in is from a quarantine port, stop processing.
1010 NodePortTuple npt = new NodePortTuple(sw, pi.getInPort());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001011 if (quarantineQueue.contains(npt)) {
1012 return Command.STOP;
1013 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001014
1015 return Command.CONTINUE;
1016 }
1017
1018 protected UpdateOperation getUpdateOperation(int srcPortState,
1019 int dstPortState) {
1020 boolean added =
1021 (((srcPortState &
Ray Milkey269ffb92014-04-03 14:43:30 -07001022 OFPortState.OFPPS_STP_MASK.getValue()) !=
1023 OFPortState.OFPPS_STP_BLOCK.getValue()) &&
1024 ((dstPortState &
1025 OFPortState.OFPPS_STP_MASK.getValue()) !=
1026 OFPortState.OFPPS_STP_BLOCK.getValue()));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001027
Ray Milkeyb29e6262014-04-09 16:02:14 -07001028 if (added) {
1029 return UpdateOperation.LINK_UPDATED;
1030 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001031 return UpdateOperation.LINK_REMOVED;
1032 }
1033
1034
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001035 protected UpdateOperation getUpdateOperation(int srcPortState) {
1036 boolean portUp = ((srcPortState &
1037 OFPortState.OFPPS_STP_MASK.getValue()) !=
1038 OFPortState.OFPPS_STP_BLOCK.getValue());
1039
Ray Milkeyb29e6262014-04-09 16:02:14 -07001040 if (portUp) {
1041 return UpdateOperation.PORT_UP;
1042 } else {
1043 return UpdateOperation.PORT_DOWN;
1044 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001045 }
1046
1047 protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
1048
1049 NodePortTuple srcNpt, dstNpt;
1050 boolean linkChanged = false;
1051
1052 lock.writeLock().lock();
1053 try {
1054 // put the new info. if an old info exists, it will be returned.
1055 LinkInfo oldInfo = links.put(lt, newInfo);
1056 if (oldInfo != null &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001057 oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001058 newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001059 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001060
1061 if (log.isTraceEnabled()) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001062 log.trace("addOrUpdateLink: {} {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001063 lt,
1064 (newInfo.getMulticastValidTime() != null) ? "multicast" : "unicast");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001065 }
1066
1067 UpdateOperation updateOperation = null;
1068 linkChanged = false;
1069
1070 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1071 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1072
1073 if (oldInfo == null) {
1074 // index it by switch source
Ray Milkeyb29e6262014-04-09 16:02:14 -07001075 if (!switchLinks.containsKey(lt.getSrc())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001076 switchLinks.put(lt.getSrc(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001077 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001078 switchLinks.get(lt.getSrc()).add(lt);
1079
1080 // index it by switch dest
Ray Milkeyb29e6262014-04-09 16:02:14 -07001081 if (!switchLinks.containsKey(lt.getDst())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001082 switchLinks.put(lt.getDst(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001083 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001084 switchLinks.get(lt.getDst()).add(lt);
1085
1086 // index both ends by switch:port
Ray Milkeyb29e6262014-04-09 16:02:14 -07001087 if (!portLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001088 portLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001089 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001090 portLinks.get(srcNpt).add(lt);
1091
Ray Milkeyb29e6262014-04-09 16:02:14 -07001092 if (!portLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001093 portLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001094 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001095 portLinks.get(dstNpt).add(lt);
1096
1097 // Add to portNOFLinks if the unicast valid time is null
Ray Milkeyb29e6262014-04-09 16:02:14 -07001098 if (newInfo.getUnicastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001099 addLinkToBroadcastDomain(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001100 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001101
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001102 // ONOS: Distinguish added event separately from updated event
Pankaj Berdea41016d2013-06-10 21:18:18 -07001103 updateOperation = UpdateOperation.LINK_ADDED;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001104 linkChanged = true;
1105
1106 // Add to event history
1107 evHistTopoLink(lt.getSrc(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001108 lt.getDst(),
1109 lt.getSrcPort(),
1110 lt.getDstPort(),
1111 newInfo.getSrcPortState(), newInfo.getDstPortState(),
1112 getLinkType(lt, newInfo),
1113 EvAction.LINK_ADDED, "LLDP Recvd");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001114 } else {
1115 // Since the link info is already there, we need to
1116 // update the right fields.
1117 if (newInfo.getUnicastValidTime() == null) {
1118 // This is due to a multicast LLDP, so copy the old unicast
1119 // value.
1120 if (oldInfo.getUnicastValidTime() != null) {
1121 newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime());
1122 }
1123 } else if (newInfo.getMulticastValidTime() == null) {
1124 // This is due to a unicast LLDP, so copy the old multicast
1125 // value.
1126 if (oldInfo.getMulticastValidTime() != null) {
1127 newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime());
1128 }
1129 }
1130
1131 Long oldTime = oldInfo.getUnicastValidTime();
1132 Long newTime = newInfo.getUnicastValidTime();
1133 // the link has changed its state between openflow and non-openflow
1134 // if the unicastValidTimes are null or not null
1135 if (oldTime != null & newTime == null) {
1136 // openflow -> non-openflow transition
1137 // we need to add the link tuple to the portNOFLinks
1138 addLinkToBroadcastDomain(lt);
1139 linkChanged = true;
1140 } else if (oldTime == null & newTime != null) {
1141 // non-openflow -> openflow transition
1142 // we need to remove the link from the portNOFLinks
1143 removeLinkFromBroadcastDomain(lt);
1144 linkChanged = true;
1145 }
1146
1147 // Only update the port states if they've changed
1148 if (newInfo.getSrcPortState().intValue() !=
1149 oldInfo.getSrcPortState().intValue() ||
1150 newInfo.getDstPortState().intValue() !=
Ray Milkeyb29e6262014-04-09 16:02:14 -07001151 oldInfo.getDstPortState().intValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001152 linkChanged = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001153 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001154
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001155 if (linkChanged) {
1156 updateOperation = getUpdateOperation(newInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001157 newInfo.getDstPortState());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001158 if (log.isTraceEnabled()) {
1159 log.trace("Updated link {}", lt);
1160 }
1161 // Add to event history
1162 evHistTopoLink(lt.getSrc(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001163 lt.getDst(),
1164 lt.getSrcPort(),
1165 lt.getDstPort(),
1166 newInfo.getSrcPortState(), newInfo.getDstPortState(),
1167 getLinkType(lt, newInfo),
1168 EvAction.LINK_PORT_STATE_UPDATED,
1169 "LLDP Recvd");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001170 }
1171 }
1172
1173 if (linkChanged) {
1174 // find out if the link was added or removed here.
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001175 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001176 lt.getDst(), lt.getDstPort(),
1177 getLinkType(lt, newInfo),
1178 updateOperation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001179 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001180 }
1181 } finally {
1182 lock.writeLock().unlock();
1183 }
1184
1185 return linkChanged;
1186 }
1187
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001188 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001189 public Map<Long, Set<Link>> getSwitchLinks() {
1190 return this.switchLinks;
1191 }
1192
1193 /**
1194 * Removes links from memory and storage.
Ray Milkey269ffb92014-04-03 14:43:30 -07001195 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001196 * @param links The List of @LinkTuple to delete.
1197 */
1198 protected void deleteLinks(List<Link> links, String reason) {
1199 NodePortTuple srcNpt, dstNpt;
1200
1201 lock.writeLock().lock();
1202 try {
1203 for (Link lt : links) {
1204 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001205 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001206
1207 switchLinks.get(lt.getSrc()).remove(lt);
1208 switchLinks.get(lt.getDst()).remove(lt);
1209 if (switchLinks.containsKey(lt.getSrc()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001210 switchLinks.get(lt.getSrc()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001211 this.switchLinks.remove(lt.getSrc());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001212 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001213 if (this.switchLinks.containsKey(lt.getDst()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001214 this.switchLinks.get(lt.getDst()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001215 this.switchLinks.remove(lt.getDst());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001216 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001217
1218 if (this.portLinks.get(srcNpt) != null) {
1219 this.portLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001220 if (this.portLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001221 this.portLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001222 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001223 }
1224 if (this.portLinks.get(dstNpt) != null) {
1225 this.portLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001226 if (this.portLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001227 this.portLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001228 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001229 }
1230
1231 LinkInfo info = this.links.remove(lt);
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001232 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001233 lt.getDst(), lt.getDstPort(),
1234 getLinkType(lt, info),
1235 UpdateOperation.LINK_REMOVED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001236 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001237
1238 // Update Event History
1239 evHistTopoLink(lt.getSrc(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001240 lt.getDst(),
1241 lt.getSrcPort(),
1242 lt.getDstPort(),
1243 0, 0, // Port states
1244 ILinkDiscovery.LinkType.INVALID_LINK,
1245 EvAction.LINK_DELETED, reason);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001246
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001247 // TODO Whenever link is removed, it has to checked if
1248 // the switchports must be added to quarantine.
1249
1250 if (log.isTraceEnabled()) {
1251 log.trace("Deleted link {}", lt);
1252 }
1253 }
1254 } finally {
1255 lock.writeLock().unlock();
1256 }
1257 }
1258
1259 /**
1260 * Handles an OFPortStatus message from a switch. We will add or
1261 * delete LinkTupes as well re-compute the topology if needed.
Ray Milkey269ffb92014-04-03 14:43:30 -07001262 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001263 * @param sw The IOFSwitch that sent the port status message
1264 * @param ps The OFPortStatus message
1265 * @return The Command to continue or stop after we process this message
1266 */
1267 protected Command handlePortStatus(long sw, OFPortStatus ps) {
1268
1269 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001270 if (iofSwitch == null) {
1271 return Command.CONTINUE;
1272 }
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -07001273
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001274 // ONOS: If we do not control this switch, then we should not process its port status messages
Ray Milkeyb29e6262014-04-09 16:02:14 -07001275 if (!registryService.hasControl(iofSwitch.getId())) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001276 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001277 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001278
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001279 if (log.isTraceEnabled()) {
1280 log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
1281 "config is {} state is {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001282 new Object[]{iofSwitch.getStringId(),
1283 ps.getDesc().getPortNumber(),
1284 ps.getReason(),
1285 ps.getDesc().getConfig(),
1286 ps.getDesc().getState()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001287 }
1288
1289 short port = ps.getDesc().getPortNumber();
1290 NodePortTuple npt = new NodePortTuple(sw, port);
Ray Milkey269ffb92014-04-03 14:43:30 -07001291 boolean linkDeleted = false;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001292 boolean linkInfoChanged = false;
1293
1294 lock.writeLock().lock();
1295 try {
1296 // if ps is a delete, or a modify where the port is down or
1297 // configured down
Ray Milkey269ffb92014-04-03 14:43:30 -07001298 if ((byte) OFPortReason.OFPPR_DELETE.ordinal() == ps.getReason() ||
1299 ((byte) OFPortReason.OFPPR_MODIFY.ordinal() ==
1300 ps.getReason() && !portEnabled(ps.getDesc()))) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001301 deleteLinksOnPort(npt, "Port Status Changed");
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001302 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, UpdateOperation.PORT_DOWN));
1303 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001304 linkDeleted = true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001305 } else if (ps.getReason() ==
1306 (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001307 // If ps is a port modification and the port state has changed
1308 // that affects links in the topology
1309
1310 if (this.portLinks.containsKey(npt)) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001311 for (Link lt : this.portLinks.get(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001312 LinkInfo linkInfo = links.get(lt);
Ray Milkey269ffb92014-04-03 14:43:30 -07001313 assert (linkInfo != null);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001314 Integer updatedSrcPortState = null;
1315 Integer updatedDstPortState = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001316 if (lt.getSrc() == npt.getNodeId() &&
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001317 lt.getSrcPort() == npt.getPortId() &&
1318 (linkInfo.getSrcPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -07001319 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001320 updatedSrcPortState = ps.getDesc().getState();
1321 linkInfo.setSrcPortState(updatedSrcPortState);
1322 }
1323 if (lt.getDst() == npt.getNodeId() &&
1324 lt.getDstPort() == npt.getPortId() &&
1325 (linkInfo.getDstPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -07001326 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001327 updatedDstPortState = ps.getDesc().getState();
1328 linkInfo.setDstPortState(updatedDstPortState);
1329 }
1330 if ((updatedSrcPortState != null) ||
1331 (updatedDstPortState != null)) {
1332 // The link is already known to link discovery
1333 // manager and the status has changed, therefore
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001334 // send an LinkUpdate.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001335 UpdateOperation operation =
1336 getUpdateOperation(linkInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001337 linkInfo.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001338 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001339 lt.getDst(), lt.getDstPort(),
1340 getLinkType(lt, linkInfo),
1341 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001342 controller.publishUpdate(update);
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001343
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001344 linkInfoChanged = true;
1345 }
1346 }
1347 }
1348
1349 UpdateOperation operation =
1350 getUpdateOperation(ps.getDesc().getState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001351 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
1352 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001353 }
1354
Ray Milkey269ffb92014-04-03 14:43:30 -07001355 if (!linkDeleted && !linkInfoChanged) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001356 if (log.isTraceEnabled()) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001357 log.trace("handlePortStatus: Switch {} port #{} reason {};" +
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001358 " no links to update/remove",
Ray Milkey269ffb92014-04-03 14:43:30 -07001359 new Object[]{HexString.toHexString(sw),
1360 ps.getDesc().getPortNumber(),
1361 ps.getReason()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001362 }
1363 }
1364 } finally {
1365 lock.writeLock().unlock();
1366 }
1367
1368 if (!linkDeleted) {
1369 // Send LLDP right away when port state is changed for faster
1370 // cluster-merge. If it is a link delete then there is not need
1371 // to send the LLDPs right away and instead we wait for the LLDPs
1372 // to be sent on the timer as it is normally done
1373 // do it outside the write-lock
1374 // sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
1375 processNewPort(npt.getNodeId(), npt.getPortId());
1376 }
1377 return Command.CONTINUE;
1378 }
1379
1380 /**
1381 * Process a new port.
1382 * If link discovery is disabled on the port, then do nothing.
1383 * If autoportfast feature is enabled and the port is a fast port, then
1384 * do nothing.
1385 * Otherwise, send LLDP message. Add the port to quarantine.
Ray Milkey269ffb92014-04-03 14:43:30 -07001386 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001387 * @param sw
1388 * @param p
1389 */
1390 private void processNewPort(long sw, short p) {
1391 if (isLinkDiscoverySuppressed(sw, p)) {
1392 // Do nothing as link discovery is suppressed.
Ray Milkey1aa71f82014-04-08 16:23:24 -07001393 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001394 } else if (autoPortFastFeature && isFastPort(sw, p)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001395 // Do nothing as the port is a fast port.
Ray Milkey1aa71f82014-04-08 16:23:24 -07001396 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001397 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001398 NodePortTuple npt = new NodePortTuple(sw, p);
1399 discover(sw, p);
1400 // if it is not a fast port, add it to quarantine.
1401 if (!isFastPort(sw, p)) {
1402 addToQuarantineQueue(npt);
1403 } else {
1404 // Add to maintenance queue to ensure that BDDP packets
1405 // are sent out.
1406 addToMaintenanceQueue(npt);
1407 }
1408 }
1409 }
1410
1411 /**
1412 * We send out LLDP messages when a switch is added to discover the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001413 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001414 * @param sw The IOFSwitch that connected to the controller
1415 */
1416 @Override
1417 public void addedSwitch(IOFSwitch sw) {
1418
1419 if (sw.getEnabledPorts() != null) {
1420 for (Short p : sw.getEnabledPortNumbers()) {
1421 processNewPort(sw.getId(), p);
1422 }
1423 }
1424 // Update event history
1425 evHistTopoSwitch(sw, EvAction.SWITCH_CONNECTED, "None");
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001426 LinkUpdate update = new LinkUpdate(new LDUpdate(sw.getId(), null,
Ray Milkey269ffb92014-04-03 14:43:30 -07001427 UpdateOperation.SWITCH_UPDATED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001428 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001429 }
1430
1431 /**
1432 * When a switch disconnects we remove any links from our map and notify.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001433 */
1434 @Override
1435 public void removedSwitch(IOFSwitch iofSwitch) {
1436 // Update event history
1437 long sw = iofSwitch.getId();
1438 evHistTopoSwitch(iofSwitch, EvAction.SWITCH_DISCONNECTED, "None");
1439 List<Link> eraseList = new ArrayList<Link>();
1440 lock.writeLock().lock();
1441 try {
1442 if (switchLinks.containsKey(sw)) {
1443 if (log.isTraceEnabled()) {
1444 log.trace("Handle switchRemoved. Switch {}; removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001445 HexString.toHexString(sw), switchLinks.get(sw));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001446 }
1447 // add all tuples with an endpoint on this switch to erase list
1448 eraseList.addAll(switchLinks.get(sw));
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -07001449 deleteLinks(eraseList, "Switch Removed");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001450
1451 // Send a switch removed update
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001452 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED));
1453 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001454 }
1455 } finally {
1456 lock.writeLock().unlock();
1457 }
1458 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001459
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001460 /**
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001461 * We don't react the port changed notifications here. we listen for
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001462 * OFPortStatus messages directly. Might consider using this notifier
1463 * instead
1464 */
1465 @Override
1466 public void switchPortChanged(Long switchId) {
1467 // no-op
1468 }
1469
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001470 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001471 * Delete links incident on a given switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -07001472 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001473 * @param npt
1474 * @param reason
1475 */
1476 protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
1477 List<Link> eraseList = new ArrayList<Link>();
1478 if (this.portLinks.containsKey(npt)) {
1479 if (log.isTraceEnabled()) {
1480 log.trace("handlePortStatus: Switch {} port #{} " +
1481 "removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001482 new Object[]{HexString.toHexString(npt.getNodeId()),
1483 npt.getPortId(),
1484 this.portLinks.get(npt)});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001485 }
1486 eraseList.addAll(this.portLinks.get(npt));
1487 deleteLinks(eraseList, reason);
1488 }
1489 }
1490
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001491 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001492 * Iterates through the list of links and deletes if the
1493 * last discovery message reception time exceeds timeout values.
1494 */
1495 protected void timeoutLinks() {
1496 List<Link> eraseList = new ArrayList<Link>();
1497 Long curTime = System.currentTimeMillis();
1498 boolean linkChanged = false;
1499
1500 // reentrant required here because deleteLink also write locks
1501 lock.writeLock().lock();
1502 try {
1503 Iterator<Entry<Link, LinkInfo>> it =
1504 this.links.entrySet().iterator();
1505 while (it.hasNext()) {
1506 Entry<Link, LinkInfo> entry = it.next();
1507 Link lt = entry.getKey();
1508 LinkInfo info = entry.getValue();
1509
1510 // Timeout the unicast and multicast LLDP valid times
1511 // independently.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001512 if ((info.getUnicastValidTime() != null) &&
Ray Milkey269ffb92014-04-03 14:43:30 -07001513 (info.getUnicastValidTime() + (this.LINK_TIMEOUT * 1000) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001514 info.setUnicastValidTime(null);
1515
Ray Milkeyb29e6262014-04-09 16:02:14 -07001516 if (info.getMulticastValidTime() != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001517 addLinkToBroadcastDomain(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001518 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001519 // Note that even if mTime becomes null later on,
1520 // the link would be deleted, which would trigger updateClusters().
1521 linkChanged = true;
1522 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001523 if ((info.getMulticastValidTime() != null) &&
1524 (info.getMulticastValidTime() + (this.LINK_TIMEOUT * 1000) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001525 info.setMulticastValidTime(null);
1526 // if uTime is not null, then link will remain as openflow
1527 // link. If uTime is null, it will be deleted. So, we
1528 // don't care about linkChanged flag here.
1529 removeLinkFromBroadcastDomain(lt);
1530 linkChanged = true;
1531 }
1532 // Add to the erase list only if the unicast
1533 // time is null.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001534 if (info.getUnicastValidTime() == null &&
Ray Milkey269ffb92014-04-03 14:43:30 -07001535 info.getMulticastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001536 eraseList.add(entry.getKey());
1537 } else if (linkChanged) {
1538 UpdateOperation operation;
1539 operation = getUpdateOperation(info.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001540 info.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001541 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001542 lt.getDst(), lt.getDstPort(),
1543 getLinkType(lt, info),
1544 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001545 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001546 }
1547 }
1548
1549 // if any link was deleted or any link was changed.
1550 if ((eraseList.size() > 0) || linkChanged) {
1551 deleteLinks(eraseList, "LLDP timeout");
1552 }
1553 } finally {
1554 lock.writeLock().unlock();
1555 }
1556 }
1557
1558 private boolean portEnabled(OFPhysicalPort port) {
Ray Milkeyb29e6262014-04-09 16:02:14 -07001559 if (port == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001560 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001561 }
1562 if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001563 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001564 }
1565 if ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001566 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001567 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001568 // Port STP state doesn't work with multiple VLANs, so ignore it for now
1569 // if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
1570 // return false;
1571 return true;
1572 }
1573
1574 public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() {
1575 return portBroadcastDomainLinks;
1576 }
1577
1578 @Override
1579 public Map<Link, LinkInfo> getLinks() {
1580 lock.readLock().lock();
1581 Map<Link, LinkInfo> result;
1582 try {
1583 result = new HashMap<Link, LinkInfo>(links);
1584 } finally {
1585 lock.readLock().unlock();
1586 }
1587 return result;
1588 }
1589
1590 protected void addLinkToBroadcastDomain(Link lt) {
1591
1592 NodePortTuple srcNpt, dstNpt;
1593 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1594 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1595
Ray Milkeyb29e6262014-04-09 16:02:14 -07001596 if (!portBroadcastDomainLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001597 portBroadcastDomainLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001598 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001599 portBroadcastDomainLinks.get(srcNpt).add(lt);
1600
Ray Milkeyb29e6262014-04-09 16:02:14 -07001601 if (!portBroadcastDomainLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001602 portBroadcastDomainLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001603 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001604 portBroadcastDomainLinks.get(dstNpt).add(lt);
1605 }
1606
1607 protected void removeLinkFromBroadcastDomain(Link lt) {
1608
1609 NodePortTuple srcNpt, dstNpt;
1610 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1611 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1612
1613 if (portBroadcastDomainLinks.containsKey(srcNpt)) {
1614 portBroadcastDomainLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001615 if (portBroadcastDomainLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001616 portBroadcastDomainLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001617 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001618 }
1619
1620 if (portBroadcastDomainLinks.containsKey(dstNpt)) {
1621 portBroadcastDomainLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001622 if (portBroadcastDomainLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001623 portBroadcastDomainLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001624 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001625 }
1626 }
1627
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001628 @Override
1629 public void addListener(ILinkDiscoveryListener listener) {
1630 linkDiscoveryAware.add(listener);
1631 }
1632
1633 /**
1634 * Register a link discovery aware component
Ray Milkey269ffb92014-04-03 14:43:30 -07001635 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001636 * @param linkDiscoveryAwareComponent
1637 */
1638 public void addLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1639 // TODO make this a copy on write set or lock it somehow
1640 this.linkDiscoveryAware.add(linkDiscoveryAwareComponent);
1641 }
1642
1643 /**
1644 * Deregister a link discovery aware component
Ray Milkey269ffb92014-04-03 14:43:30 -07001645 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001646 * @param linkDiscoveryAwareComponent
1647 */
1648 public void removeLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1649 // TODO make this a copy on write set or lock it somehow
1650 this.linkDiscoveryAware.remove(linkDiscoveryAwareComponent);
1651 }
1652
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001653 @Override
1654 public boolean isCallbackOrderingPrereq(OFType type, String name) {
1655 return false;
1656 }
1657
1658 @Override
1659 public boolean isCallbackOrderingPostreq(OFType type, String name) {
1660 return false;
1661 }
1662
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001663 // IFloodlightModule classes
1664
1665 @Override
1666 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001667 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001668 new ArrayList<Class<? extends IFloodlightService>>();
1669 l.add(ILinkDiscoveryService.class);
1670 //l.add(ITopologyService.class);
1671 return l;
1672 }
1673
1674 @Override
1675 public Map<Class<? extends IFloodlightService>, IFloodlightService>
1676 getServiceImpls() {
1677 Map<Class<? extends IFloodlightService>,
Ray Milkey269ffb92014-04-03 14:43:30 -07001678 IFloodlightService> m =
1679 new HashMap<Class<? extends IFloodlightService>,
1680 IFloodlightService>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001681 // We are the class that implements the service
1682 m.put(ILinkDiscoveryService.class, this);
1683 return m;
1684 }
1685
1686 @Override
1687 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001688 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001689 new ArrayList<Class<? extends IFloodlightService>>();
1690 l.add(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001691 l.add(IThreadPoolService.class);
1692 l.add(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001693 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001694 l.add(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001695 return l;
1696 }
1697
1698 @Override
1699 public void init(FloodlightModuleContext context)
1700 throws FloodlightModuleException {
1701 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001702 threadPool = context.getServiceImpl(IThreadPoolService.class);
1703 restApi = context.getServiceImpl(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001704 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001705 registryService = context.getServiceImpl(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001706
1707 // Set the autoportfast feature to false.
1708 this.autoPortFastFeature = false;
1709
1710 // We create this here because there is no ordering guarantee
1711 this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
1712 this.lock = new ReentrantReadWriteLock();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001713 this.links = new HashMap<Link, LinkInfo>();
1714 this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
1715 this.suppressLinkDiscovery =
1716 Collections.synchronizedSet(new HashSet<NodePortTuple>());
1717 this.portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
1718 this.switchLinks = new HashMap<Long, Set<Link>>();
1719 this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>();
1720 this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>();
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001721 // Added by ONOS
HIGUCHI Yuta7677a6f2013-06-14 14:13:35 -07001722 this.remoteSwitches = new HashMap<Long, IOnosRemoteSwitch>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001723
1724 this.evHistTopologySwitch =
1725 new EventHistory<EventHistoryTopologySwitch>("Topology: Switch");
1726 this.evHistTopologyLink =
1727 new EventHistory<EventHistoryTopologyLink>("Topology: Link");
1728 this.evHistTopologyCluster =
1729 new EventHistory<EventHistoryTopologyCluster>("Topology: Cluster");
1730 }
1731
1732 @Override
1733 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001734 @LogMessageDoc(level = "ERROR",
1735 message = "No storage source found.",
1736 explanation = "Storage source was not initialized; cannot initialize " +
1737 "link discovery.",
1738 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1739 @LogMessageDoc(level = "ERROR",
1740 message = "Error in installing listener for " +
1741 "switch config table {table}",
1742 explanation = "Failed to install storage notification for the " +
1743 "switch config table",
1744 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1745 @LogMessageDoc(level = "ERROR",
1746 message = "No storage source found.",
1747 explanation = "Storage source was not initialized; cannot initialize " +
1748 "link discovery.",
1749 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1750 @LogMessageDoc(level = "ERROR",
1751 message = "Exception in LLDP send timer.",
1752 explanation = "An unknown error occured while sending LLDP " +
1753 "messages to switches.",
1754 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001755 })
1756 public void startUp(FloodlightModuleContext context) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001757 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001758 controller =
1759 context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001760
1761 // To be started by the first switch connection
1762 discoveryTask = new SingletonTask(ses, new Runnable() {
1763 @Override
1764 public void run() {
1765 try {
1766 discoverLinks();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001767 } catch (Exception e) {
1768 log.error("Exception in LLDP send timer.", e);
1769 } finally {
1770 if (!shuttingDown) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001771 // Always reschedule link discovery if we're not
1772 // shutting down (no chance of SLAVE role now)
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001773 log.trace("Rescheduling discovery task");
1774 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
Ray Milkey269ffb92014-04-03 14:43:30 -07001775 TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001776 }
1777 }
1778 }
1779 });
1780
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001781 // Always reschedule link discovery as we are never in SLAVE role now
1782 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001783
1784 // Setup the BDDP task. It is invoked whenever switch port tuples
1785 // are added to the quarantine list.
1786 bddpTask = new SingletonTask(ses, new QuarantineWorker());
1787 bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
1788
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001789
1790 // Register for the OpenFlow messages we want to receive
1791 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
1792 floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
1793 // Register for switch updates
1794 floodlightProvider.addOFSwitchListener(this);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001795 if (restApi != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001796 restApi.addRestletRoutable(new LinkDiscoveryWebRoutable());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001797 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001798 setControllerTLV();
1799 }
1800
1801 // ****************************************************
1802 // Topology Manager's Event History members and methods
1803 // ****************************************************
1804
1805 // Topology Manager event history
Ray Milkey269ffb92014-04-03 14:43:30 -07001806 public EventHistory<EventHistoryTopologySwitch> evHistTopologySwitch;
1807 public EventHistory<EventHistoryTopologyLink> evHistTopologyLink;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001808 public EventHistory<EventHistoryTopologyCluster> evHistTopologyCluster;
Ray Milkey269ffb92014-04-03 14:43:30 -07001809 public EventHistoryTopologySwitch evTopoSwitch;
1810 public EventHistoryTopologyLink evTopoLink;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001811 public EventHistoryTopologyCluster evTopoCluster;
1812
1813 // Switch Added/Deleted
1814 private void evHistTopoSwitch(IOFSwitch sw, EvAction actn, String reason) {
1815 if (evTopoSwitch == null) {
1816 evTopoSwitch = new EventHistoryTopologySwitch();
1817 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001818 evTopoSwitch.dpid = sw.getId();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001819 if ((sw.getChannel() != null) &&
1820 (SocketAddress.class.isInstance(
Ray Milkey269ffb92014-04-03 14:43:30 -07001821 sw.getChannel().getRemoteAddress()))) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001822 evTopoSwitch.ipv4Addr =
Ray Milkey269ffb92014-04-03 14:43:30 -07001823 IPv4.toIPv4Address(((InetSocketAddress) (sw.getChannel().
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001824 getRemoteAddress())).getAddress().getAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -07001825 evTopoSwitch.l4Port =
1826 ((InetSocketAddress) (sw.getChannel().
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001827 getRemoteAddress())).getPort();
1828 } else {
1829 evTopoSwitch.ipv4Addr = 0;
1830 evTopoSwitch.l4Port = 0;
1831 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001832 evTopoSwitch.reason = reason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001833 evTopoSwitch = evHistTopologySwitch.put(evTopoSwitch, actn);
1834 }
1835
1836 private void evHistTopoLink(long srcDpid, long dstDpid, short srcPort,
1837 short dstPort, int srcPortState, int dstPortState,
1838 ILinkDiscovery.LinkType linkType,
1839 EvAction actn, String reason) {
1840 if (evTopoLink == null) {
1841 evTopoLink = new EventHistoryTopologyLink();
1842 }
1843 evTopoLink.srcSwDpid = srcDpid;
1844 evTopoLink.dstSwDpid = dstDpid;
1845 evTopoLink.srcSwport = srcPort & 0xffff;
1846 evTopoLink.dstSwport = dstPort & 0xffff;
1847 evTopoLink.srcPortState = srcPortState;
1848 evTopoLink.dstPortState = dstPortState;
Ray Milkey269ffb92014-04-03 14:43:30 -07001849 evTopoLink.reason = reason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001850 switch (linkType) {
1851 case DIRECT_LINK:
1852 evTopoLink.linkType = "DIRECT_LINK";
1853 break;
1854 case MULTIHOP_LINK:
1855 evTopoLink.linkType = "MULTIHOP_LINK";
1856 break;
1857 case TUNNEL:
1858 evTopoLink.linkType = "TUNNEL";
1859 break;
1860 case INVALID_LINK:
1861 default:
1862 evTopoLink.linkType = "Unknown";
1863 break;
1864 }
1865 evTopoLink = evHistTopologyLink.put(evTopoLink, actn);
1866 }
1867
1868 public void evHistTopoCluster(long dpid, long clusterIdOld,
1869 long clusterIdNew, EvAction action, String reason) {
1870 if (evTopoCluster == null) {
1871 evTopoCluster = new EventHistoryTopologyCluster();
1872 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001873 evTopoCluster.dpid = dpid;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001874 evTopoCluster.clusterIdOld = clusterIdOld;
1875 evTopoCluster.clusterIdNew = clusterIdNew;
Ray Milkey269ffb92014-04-03 14:43:30 -07001876 evTopoCluster.reason = reason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001877 evTopoCluster = evHistTopologyCluster.put(evTopoCluster, action);
1878 }
1879
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001880 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001881 public boolean isAutoPortFastFeature() {
1882 return autoPortFastFeature;
1883 }
1884
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001885 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001886 public void setAutoPortFastFeature(boolean autoPortFastFeature) {
1887 this.autoPortFastFeature = autoPortFastFeature;
1888 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001889}