blob: 279e4c37650998fbf74b38b54a46fcaab8a87fee [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
Ray Milkeyb41100a2014-04-10 10:42:15 -0700104 * critical sections.
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 * -portLinks contains LinkTuples where one of the src or dst
Ray Milkeyb41100a2014-04-10 10:42:15 -0700106 * SwitchPortTuple matches the map key.
Ray Milkey269ffb92014-04-03 14:43:30 -0700107 * -switchLinks contains LinkTuples where one of the src or dst
Ray Milkeyb41100a2014-04-10 10:42:15 -0700108 * SwitchPortTuple's id matches the switch id.
Ray Milkey269ffb92014-04-03 14:43:30 -0700109 * -Each LinkTuple will be indexed into switchLinks for both
Ray Milkeyb41100a2014-04-10 10:42:15 -0700110 * 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 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700184 * Map from link to the most recent time it was verified functioning.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800185 */
186 protected Map<Link, LinkInfo> links;
187
188 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700189 * Map from switch id to a set of all links with it as an endpoint.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800190 */
191 protected Map<Long, Set<Link>> switchLinks;
192
193 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700194 * Map from a id:port to the set of links containing it as an endpoint.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800195 */
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
Ray Milkeyb41100a2014-04-10 10:42:15 -0700206 /**
207 * Topology aware components are called in the order they were added to the
208 * the array.
209 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800210 protected ArrayList<ILinkDiscoveryListener> linkDiscoveryAware;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800211
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700212 protected class LinkUpdate extends LDUpdate {
213
Ray Milkey269ffb92014-04-03 14:43:30 -0700214 public LinkUpdate(LDUpdate old) {
215 super(old);
216 }
217
218 @LogMessageDoc(level = "ERROR",
219 message = "Error in link discovery updates loop",
220 explanation = "An unknown error occured while dispatching " +
221 "link update notifications",
222 recommendation = LogMessageDoc.GENERIC_ACTION)
223 @Override
224 public void dispatch() {
225 if (linkDiscoveryAware != null) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800226 if (log.isTraceEnabled()) {
227 log.trace("Dispatching link discovery update {} {} {} {} {} for {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 new Object[]{this.getOperation(),
229 HexString.toHexString(this.getSrc()), this.getSrcPort(),
230 HexString.toHexString(this.getDst()), this.getDstPort(),
231 linkDiscoveryAware});
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800232 }
233 try {
234 for (ILinkDiscoveryListener lda : linkDiscoveryAware) { // order maintained
235 lda.linkDiscoveryUpdate(this);
236 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 } catch (Exception e) {
Jonathan Hartb0904bf2013-11-26 14:41:11 -0800238 log.error("Error in link discovery updates loop", e);
239 }
240 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700241 }
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700242 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800243
244 /**
245 * List of ports through which LLDP/BDDPs are not sent.
246 */
247 protected Set<NodePortTuple> suppressLinkDiscovery;
248
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 /**
250 * A list of ports that are quarantined for discovering links through
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800251 * them. Data traffic from these ports are not allowed until the ports
252 * are released from quarantine.
253 */
254 protected LinkedBlockingQueue<NodePortTuple> quarantineQueue;
255 protected LinkedBlockingQueue<NodePortTuple> maintenanceQueue;
256 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700257 * Quarantine task.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800258 */
259 protected SingletonTask bddpTask;
Ray Milkey2476cac2014-04-08 11:03:21 -0700260 protected static final int BDDP_TASK_INTERVAL = 100; // 100 ms.
261 protected static final int BDDP_TASK_SIZE = 5; // # of ports per iteration
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800262
263 /**
264 * Map of broadcast domain ports and the last time a BDDP was either
265 * sent or received on that port.
266 */
267 protected Map<NodePortTuple, Long> broadcastDomainPortTimeMap;
268
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800269 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800270 * Get the LLDP sending period in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700271 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800272 * @return LLDP sending period in seconds.
273 */
274 public int getLldpFrequency() {
275 return LLDP_TO_KNOWN_INTERVAL;
276 }
277
278 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700279 * Get the LLDP timeout value in seconds.
Ray Milkey269ffb92014-04-03 14:43:30 -0700280 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800281 * @return LLDP timeout value in seconds
282 */
283 public int getLldpTimeout() {
284 return LINK_TIMEOUT;
285 }
286
287 public Map<NodePortTuple, Set<Link>> getPortLinks() {
288 return portLinks;
289 }
290
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800291 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800292 public Set<NodePortTuple> getSuppressLLDPsInfo() {
293 return suppressLinkDiscovery;
294 }
295
296 /**
297 * Add a switch port to the suppressed LLDP list.
298 * Remove any known links on the switch port.
299 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800300 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700301 public void addToSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800302 NodePortTuple npt = new NodePortTuple(sw, port);
303 this.suppressLinkDiscovery.add(npt);
304 deleteLinksOnPort(npt, "LLDP suppressed.");
305 }
306
307 /**
308 * Remove a switch port from the suppressed LLDP list.
309 * Discover links on that switchport.
310 */
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800311 @Override
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700312 public void removeFromSuppressLLDPs(long sw, short port) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800313 NodePortTuple npt = new NodePortTuple(sw, port);
314 this.suppressLinkDiscovery.remove(npt);
315 discover(npt);
316 }
317
318 public boolean isShuttingDown() {
319 return shuttingDown;
320 }
321
322 public boolean isFastPort(long sw, short port) {
323 return false;
324 }
325
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800326 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800327 public ILinkDiscovery.LinkType getLinkType(Link lt, LinkInfo info) {
328 if (info.getUnicastValidTime() != null) {
329 return ILinkDiscovery.LinkType.DIRECT_LINK;
330 } else if (info.getMulticastValidTime() != null) {
331 return ILinkDiscovery.LinkType.MULTIHOP_LINK;
332 }
333 return ILinkDiscovery.LinkType.INVALID_LINK;
334 }
335
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800336
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800337 private boolean isLinkDiscoverySuppressed(long sw, short portNumber) {
338 return this.suppressLinkDiscovery.contains(new NodePortTuple(sw, portNumber));
339 }
340
341 protected void discoverLinks() {
342
343 // timeout known links.
344 timeoutLinks();
345
346 //increment LLDP clock
Ray Milkey269ffb92014-04-03 14:43:30 -0700347 lldpClock = (lldpClock + 1) % LLDP_TO_ALL_INTERVAL;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800348
349 if (lldpClock == 0) {
350 log.debug("Sending LLDP out on all ports.");
351 discoverOnAllPorts();
352 }
353 }
354
355
356 /**
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 * Quarantine Ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800358 */
359 protected class QuarantineWorker implements Runnable {
360 @Override
361 public void run() {
362 try {
363 processBDDPLists();
Ray Milkey269ffb92014-04-03 14:43:30 -0700364 } catch (Exception e) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800365 log.error("Error in quarantine worker thread", e);
366 } finally {
Ray Milkey269ffb92014-04-03 14:43:30 -0700367 bddpTask.reschedule(BDDP_TASK_INTERVAL,
368 TimeUnit.MILLISECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800369 }
370 }
371 }
372
373 /**
374 * Add a switch port to the quarantine queue. Schedule the
375 * quarantine task if the quarantine queue was empty before adding
376 * this switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -0700377 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800378 * @param npt
379 */
380 protected void addToQuarantineQueue(NodePortTuple npt) {
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700381 if (!quarantineQueue.contains(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800382 quarantineQueue.add(npt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700383 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800384 }
385
386 /**
387 * Remove a switch port from the quarantine queue.
388 */
389 protected void removeFromQuarantineQueue(NodePortTuple npt) {
390 // Remove all occurrences of the node port tuple from the list.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700391 boolean removedSomething;
392
393 do {
394 removedSomething = quarantineQueue.remove(npt);
395 } while (removedSomething);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800396 }
397
398 /**
399 * Add a switch port to maintenance queue.
Ray Milkey269ffb92014-04-03 14:43:30 -0700400 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800401 * @param npt
402 */
403 protected void addToMaintenanceQueue(NodePortTuple npt) {
404 // TODO We are not checking if the switch port tuple is already
405 // in the maintenance list or not. This will be an issue for
406 // really large number of switch ports in the network.
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700407 if (!maintenanceQueue.contains(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800408 maintenanceQueue.add(npt);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700409 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800410 }
411
412 /**
413 * Remove a switch port from maintenance queue.
Ray Milkey269ffb92014-04-03 14:43:30 -0700414 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800415 * @param npt
416 */
417 protected void removeFromMaintenanceQueue(NodePortTuple npt) {
418 // Remove all occurrences of the node port tuple from the queue.
Ray Milkey1aa71f82014-04-08 16:23:24 -0700419 boolean removedSomething;
420 do {
421 removedSomething = maintenanceQueue.remove(npt);
422 } while (removedSomething);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800423 }
424
425 /**
Ray Milkey269ffb92014-04-03 14:43:30 -0700426 * This method processes the quarantine list in bursts. The task is
427 * at most once per BDDP_TASK_INTERVAL.
428 * One each call, BDDP_TASK_SIZE number of switch ports are processed.
429 * Once the BDDP packets are sent out through the switch ports, the ports
430 * are removed from the quarantine list.
431 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800432
433 protected void processBDDPLists() {
434 int count = 0;
435 Set<NodePortTuple> nptList = new HashSet<NodePortTuple>();
436
Ray Milkey269ffb92014-04-03 14:43:30 -0700437 while (count < BDDP_TASK_SIZE && quarantineQueue.peek() != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800438 NodePortTuple npt;
439 npt = quarantineQueue.remove();
440 sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
441 nptList.add(npt);
442 count++;
443 }
444
445 count = 0;
446 while (count < BDDP_TASK_SIZE && maintenanceQueue.peek() != null) {
447 NodePortTuple npt;
448 npt = maintenanceQueue.remove();
449 sendDiscoveryMessage(npt.getNodeId(), npt.getPortId(), false, false);
450 count++;
451 }
452
Ray Milkey269ffb92014-04-03 14:43:30 -0700453 for (NodePortTuple npt : nptList) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800454 generateSwitchPortStatusUpdate(npt.getNodeId(), npt.getPortId());
455 }
456 }
457
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800458 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800459 public Set<Short> getQuarantinedPorts(long sw) {
460 Set<Short> qPorts = new HashSet<Short>();
461
462 Iterator<NodePortTuple> iter = quarantineQueue.iterator();
463 while (iter.hasNext()) {
464 NodePortTuple npt = iter.next();
465 if (npt.getNodeId() == sw) {
466 qPorts.add(npt.getPortId());
467 }
468 }
469 return qPorts;
470 }
471
472 private void generateSwitchPortStatusUpdate(long sw, short port) {
473 UpdateOperation operation;
474
475 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700476 if (iofSwitch == null) {
477 return;
478 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800479
480 OFPhysicalPort ofp = iofSwitch.getPort(port);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700481 if (ofp == null) {
482 return;
483 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800484
485 int srcPortState = ofp.getState();
486 boolean portUp = ((srcPortState &
487 OFPortState.OFPPS_STP_MASK.getValue()) !=
488 OFPortState.OFPPS_STP_BLOCK.getValue());
489
Ray Milkeyb29e6262014-04-09 16:02:14 -0700490 if (portUp) {
491 operation = UpdateOperation.PORT_UP;
492 } else {
493 operation = UpdateOperation.PORT_DOWN;
494 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800495
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700496 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800497
498
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700499 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800500 }
501
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800502 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700503 * Send LLDP on known ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800504 */
505 protected void discoverOnKnownLinkPorts() {
506 // Copy the port set.
507 Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
508 nptSet.addAll(portLinks.keySet());
509
510 // Send LLDP from each of them.
Ray Milkey269ffb92014-04-03 14:43:30 -0700511 for (NodePortTuple npt : nptSet) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800512 discover(npt);
513 }
514 }
515
516 protected void discover(NodePortTuple npt) {
517 discover(npt.getNodeId(), npt.getPortId());
518 }
519
520 protected void discover(long sw, short port) {
521 sendDiscoveryMessage(sw, port, true, false);
522 }
523
524 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700525 * Learn remote switches when running as a distributed controller ONOS.
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800526 */
527 protected IOFSwitch addRemoteSwitch(long sw, short port) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 IOnosRemoteSwitch remotesw = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800529
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 // add a switch if we have not seen it before
531 remotesw = remoteSwitches.get(sw);
Jonathan Harte7231052013-01-25 00:01:14 -0800532
Ray Milkey269ffb92014-04-03 14:43:30 -0700533 if (remotesw == null) {
534 remotesw = new OFSwitchImpl();
535 remotesw.setupRemoteSwitch(sw);
536 remoteSwitches.put(remotesw.getId(), remotesw);
537 log.debug("addRemoteSwitch(): added fake remote sw {}", remotesw);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800538 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800539
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800540 // add the port if we have not seen it before
Umesh Krishnaswamy68c118c2013-01-25 11:07:09 -0800541 if (remotesw.getPort(port) == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 OFPhysicalPort remoteport = new OFPhysicalPort();
543 remoteport.setPortNumber(port);
544 remoteport.setName("fake_" + port);
545 remoteport.setConfig(0);
546 remoteport.setState(0);
547 remotesw.setPort(remoteport);
548 log.debug("addRemoteSwitch(): added fake remote port {} to sw {}", remoteport, remotesw.getId());
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800549 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800550
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800551 return remotesw;
552 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800553
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800554 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800555 * Send link discovery message out of a given switch port.
556 * The discovery message may be a standard LLDP or a modified
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800557 * LLDP, where the dst mac address is set to :ff.
Ray Milkey269ffb92014-04-03 14:43:30 -0700558 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800559 * TODO: The modified LLDP will updated in the future and may
560 * use a different eth-type.
Ray Milkey269ffb92014-04-03 14:43:30 -0700561 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800562 * @param sw
563 * @param port
Ray Milkey269ffb92014-04-03 14:43:30 -0700564 * @param isStandard indicates standard or modified LLDP
565 * @param isReverse indicates whether the LLDP was sent as a response
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800566 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700567 @LogMessageDoc(level = "ERROR",
568 message = "Failure sending LLDP out port {port} on switch {switch}",
569 explanation = "An I/O error occured while sending LLDP message " +
570 "to the switch.",
571 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800572 protected void sendDiscoveryMessage(long sw, short port,
Ray Milkey269ffb92014-04-03 14:43:30 -0700573 boolean isStandard,
574 boolean isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800575
576 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
577 if (iofSwitch == null) {
578 return;
579 }
580
Ray Milkeyb29e6262014-04-09 16:02:14 -0700581 if (port == OFPort.OFPP_LOCAL.getValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800582 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700583 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800584
585 OFPhysicalPort ofpPort = iofSwitch.getPort(port);
586
587 if (ofpPort == null) {
588 if (log.isTraceEnabled()) {
589 log.trace("Null physical port. sw={}, port={}", sw, port);
590 }
591 return;
592 }
593
594 if (isLinkDiscoverySuppressed(sw, port)) {
595 /* Dont send LLDPs out of this port as suppressLLDPs set
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800596 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800597 */
598 return;
599 }
600
601 // For fast ports, do not send forward LLDPs or BDDPs.
Ray Milkeyb29e6262014-04-09 16:02:14 -0700602 if (!isReverse && autoPortFastFeature && isFastPort(sw, port)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800603 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700604 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800605
606 if (log.isTraceEnabled()) {
607 log.trace("Sending LLDP packet out of swich: {}, port: {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700608 sw, port);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800609 }
610
611 // using "nearest customer bridge" MAC address for broadest possible propagation
612 // through provider and TPMR bridges (see IEEE 802.1AB-2009 and 802.1Q-2011),
613 // in particular the Linux bridge which behaves mostly like a provider bridge
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 byte[] chassisId = new byte[]{4, 0, 0, 0, 0, 0, 0}; // filled in later
615 byte[] portId = new byte[]{2, 0, 0}; // filled in later
616 byte[] ttlValue = new byte[]{0, 0x78};
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800617 // OpenFlow OUI - 00-26-E1
Ray Milkey269ffb92014-04-03 14:43:30 -0700618 byte[] dpidTLVValue = new byte[]{0x0, 0x26, (byte) 0xe1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800619
620 byte[] dpidArray = new byte[8];
621 ByteBuffer dpidBB = ByteBuffer.wrap(dpidArray);
622 ByteBuffer portBB = ByteBuffer.wrap(portId, 1, 2);
623
624 Long dpid = sw;
625 dpidBB.putLong(dpid);
626 // set the ethernet source mac to last 6 bytes of dpid
Jonathan Hart1f6c7a22014-04-16 16:06:27 -0700627 byte[] hardwareAddress = new byte[6];
628 System.arraycopy(dpidArray, 2, hardwareAddress, 0, 6);
629 ofpPort.setHardwareAddress(hardwareAddress);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800630 // set the chassis id's value to last 6 bytes of dpid
631 System.arraycopy(dpidArray, 2, chassisId, 1, 6);
632 // set the optional tlv to the full dpid
633 System.arraycopy(dpidArray, 0, dpidTLVValue, 4, 8);
Jonathan Hart1f6c7a22014-04-16 16:06:27 -0700634 LLDPTLV dpidTLV = new LLDPTLV().setType((byte) 127)
635 .setLength((short) dpidTLVValue.length).setValue(dpidTLVValue);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800636
637 // set the portId to the outgoing port
638 portBB.putShort(port);
639 if (log.isTraceEnabled()) {
640 log.trace("Sending LLDP out of interface: {}/{}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700641 HexString.toHexString(sw), port);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800642 }
643
644 LLDP lldp = new LLDP();
645 lldp.setChassisId(new LLDPTLV().setType((byte) 1).setLength((short) chassisId.length).setValue(chassisId));
646 lldp.setPortId(new LLDPTLV().setType((byte) 2).setLength((short) portId.length).setValue(portId));
647 lldp.setTtl(new LLDPTLV().setType((byte) 3).setLength((short) ttlValue.length).setValue(ttlValue));
648 lldp.getOptionalTLVList().add(dpidTLV);
649
650 // Add the controller identifier to the TLV value.
651 lldp.getOptionalTLVList().add(controllerTLV);
652 if (isReverse) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700653 lldp.getOptionalTLVList().add(REVERSE_TLV);
Ray Milkey269ffb92014-04-03 14:43:30 -0700654 } else {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700655 lldp.getOptionalTLVList().add(FORWARD_TLV);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800656 }
657
658 Ethernet ethernet;
659 if (isStandard) {
660 ethernet = new Ethernet()
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 .setSourceMACAddress(ofpPort.getHardwareAddress())
662 .setDestinationMACAddress(LLDP_STANDARD_DST_MAC_STRING)
663 .setEtherType(Ethernet.TYPE_LLDP);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800664 ethernet.setPayload(lldp);
665 } else {
666 BSN bsn = new BSN(BSN.BSN_TYPE_BDDP);
667 bsn.setPayload(lldp);
668
669 ethernet = new Ethernet()
Ray Milkey269ffb92014-04-03 14:43:30 -0700670 .setSourceMACAddress(ofpPort.getHardwareAddress())
671 .setDestinationMACAddress(LLDP_BSN_DST_MAC_STRING)
672 .setEtherType(Ethernet.TYPE_BSN);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800673 ethernet.setPayload(bsn);
674 }
675
676
677 // serialize and wrap in a packet out
678 byte[] data = ethernet.serialize();
679 OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
680 po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
681 po.setInPort(OFPort.OFPP_NONE);
682
683 // set actions
684 List<OFAction> actions = new ArrayList<OFAction>();
685 actions.add(new OFActionOutput(port, (short) 0));
686 po.setActions(actions);
687 po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
688
689 // set data
690 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + po.getActionsLength() + data.length);
691 po.setPacketData(data);
692
693 // send
694 try {
695 iofSwitch.write(po, null);
696 iofSwitch.flush();
697 } catch (IOException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700698 log.error("Failure sending LLDP out port " + port + " on switch " + iofSwitch.getStringId(), e);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800699 }
700
701 }
702
703 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700704 * Send LLDPs to all switch-ports.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800705 */
706 protected void discoverOnAllPorts() {
707 if (log.isTraceEnabled()) {
Yuta HIGUCHI5302ddf2014-01-06 12:53:35 -0800708 log.trace("Sending LLDP packets out of all the enabled ports on switch");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800709 }
710 Set<Long> switches = floodlightProvider.getSwitches().keySet();
711 // Send standard LLDPs
Ray Milkey269ffb92014-04-03 14:43:30 -0700712 for (long sw : switches) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800713 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700714 if (iofSwitch == null) {
715 continue;
716 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800717 if (iofSwitch.getEnabledPorts() != null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 for (OFPhysicalPort ofp : iofSwitch.getEnabledPorts()) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700719 if (isLinkDiscoverySuppressed(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800720 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700721 }
722 if (autoPortFastFeature && isFastPort(sw, ofp.getPortNumber())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800723 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700724 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800725
726 // sends forward LLDP only non-fastports.
727 sendDiscoveryMessage(sw, ofp.getPortNumber(), true, false);
728
729 // If the switch port is not alreayd in the maintenance
730 // queue, add it.
731 NodePortTuple npt = new NodePortTuple(sw, ofp.getPortNumber());
732 addToMaintenanceQueue(npt);
733 }
734 }
735 }
736 }
737
738 protected void setControllerTLV() {
739 //Setting the controllerTLVValue based on current nano time,
740 //controller's IP address, and the network interface object hash
741 //the corresponding IP address.
742
743 final int prime = 7867;
744 InetAddress localIPAddress = null;
745 NetworkInterface localInterface = null;
746
Ray Milkey269ffb92014-04-03 14:43:30 -0700747 byte[] controllerTLVValue = new byte[]{0, 0, 0, 0, 0, 0, 0, 0}; // 8 byte value.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800748 ByteBuffer bb = ByteBuffer.allocate(10);
749
Ray Milkey269ffb92014-04-03 14:43:30 -0700750 try {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800751 localIPAddress = java.net.InetAddress.getLocalHost();
752 localInterface = NetworkInterface.getByInetAddress(localIPAddress);
753 } catch (Exception e) {
754 e.printStackTrace();
755 }
756
757 long result = System.nanoTime();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700758 if (localIPAddress != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800759 result = result * prime + IPv4.toIPv4Address(localIPAddress.getHostAddress());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700760 }
761 if (localInterface != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800762 result = result * prime + localInterface.hashCode();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700763 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800764 // set the first 4 bits to 0.
765 result = result & (0x0fffffffffffffffL);
766
767 bb.putLong(result);
768
769 bb.rewind();
770 bb.get(controllerTLVValue, 0, 8);
771
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700772 this.controllerTLV = new LLDPTLV()
773 .setType((byte) 0x0c)
774 .setLength((short) controllerTLVValue.length)
775 .setValue(controllerTLVValue);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800776 }
777
778 @Override
779 public String getName() {
780 return "linkdiscovery";
781 }
782
783 @Override
784 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
785 switch (msg.getType()) {
786 case PACKET_IN:
Pavlin Radoslavov0b88a262014-04-10 15:43:27 -0700787 if (msg instanceof OFPacketIn) {
788 return this.handlePacketIn(sw.getId(), (OFPacketIn) msg,
789 cntx);
790 }
791 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800792 case PORT_STATUS:
Pavlin Radoslavov0b88a262014-04-10 15:43:27 -0700793 if (msg instanceof OFPortStatus) {
794 return this.handlePortStatus(sw.getId(), (OFPortStatus) msg);
795 }
796 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800797 default:
798 break;
799 }
800 return Command.CONTINUE;
801 }
802
803 private Command handleLldp(LLDP lldp, long sw, OFPacketIn pi, boolean isStandard, FloodlightContext cntx) {
804 // If LLDP is suppressed on this port, ignore received packet as well
805 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
806 if (iofSwitch == null) {
807 return Command.STOP;
808 }
809
Ray Milkeyb29e6262014-04-09 16:02:14 -0700810 if (isLinkDiscoverySuppressed(sw, pi.getInPort())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800811 return Command.STOP;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700812 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800813
814 // If this is a malformed LLDP, or not from us, exit
Ray Milkeyb29e6262014-04-09 16:02:14 -0700815 if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800816 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700817 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800818
819 long myId = ByteBuffer.wrap(controllerTLV.getValue()).getLong();
820 long otherId = 0;
821 boolean myLLDP = false;
822 Boolean isReverse = null;
823
824 ByteBuffer portBB = ByteBuffer.wrap(lldp.getPortId().getValue());
825 portBB.position(1);
826
827 Short remotePort = portBB.getShort();
828 IOFSwitch remoteSwitch = null;
829
830 // Verify this LLDP packet matches what we're looking for
831 for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
832 if (lldptlv.getType() == 127 && lldptlv.getLength() == 12 &&
833 lldptlv.getValue()[0] == 0x0 && lldptlv.getValue()[1] == 0x26 &&
Ray Milkey269ffb92014-04-03 14:43:30 -0700834 lldptlv.getValue()[2] == (byte) 0xe1 && lldptlv.getValue()[3] == 0x0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800835 ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
836 remoteSwitch = floodlightProvider.getSwitches().get(dpidBB.getLong(4));
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800837 if (remoteSwitch == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700838 // Added by ONOS
839 // floodlight LLDP coming from a remote switch connected to a different controller
840 // add it to our cache of unconnected remote switches
841 remoteSwitch = addRemoteSwitch(dpidBB.getLong(4), remotePort);
Umesh Krishnaswamyf962d642013-01-23 19:04:23 -0800842 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700843 } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800844 otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700845 if (myId == otherId) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800846 myLLDP = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700847 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800848 } else if (lldptlv.getType() == TLV_DIRECTION_TYPE &&
849 lldptlv.getLength() == TLV_DIRECTION_LENGTH) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700850 if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_FORWARD[0]) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800851 isReverse = false;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700852 } else if (lldptlv.getValue()[0] == TLV_DIRECTION_VALUE_REVERSE[0]) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800853 isReverse = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700854 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800855 }
856 }
857
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700858 if (!myLLDP) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800859 // This is not the LLDP sent by this controller.
860 // If the LLDP message has multicast bit set, then we need to broadcast
861 // the packet as a regular packet.
862 if (isStandard) {
863 if (log.isTraceEnabled()) {
864 log.trace("Getting standard LLDP from a different controller and quelching it.");
865 }
866 return Command.STOP;
Jonathan Hart121a0242014-06-06 15:53:42 -0700867 }
868 // XXX ONOS: Don't disregard any BDDP messages from other
869 // controllers because they're used for inter-instance link detection
870
871 /*else if (sw <= remoteSwitch.getId()) {
Teru Ub7246af2014-01-13 13:24:38 -0800872 if (log.isTraceEnabled()) {
873 log.trace("Getting BBDP from a different controller. myId {}: remoteId {}", myId, otherId);
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700874 log.trace("and my controller id is smaller than the other, so quelching it. myPort {}: rPort {}",
875 pi.getInPort(), remotePort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700876 }
877 //XXX ONOS: Fix the BDDP broadcast issue
878 //return Command.CONTINUE;
879 return Command.STOP;
Jonathan Hart121a0242014-06-06 15:53:42 -0700880 }*/
Teru Ub7246af2014-01-13 13:24:38 -0800881 /*
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800882 else if (myId < otherId) {
883 if (log.isTraceEnabled()) {
884 log.trace("Getting BDDP packets from a different controller" +
885 "and letting it go through normal processing chain.");
886 }
HIGUCHI Yuta30d03302013-06-14 13:47:36 -0700887 //XXX ONOS: Fix the BDDP broadcast issue
Jonathan Hart0b2c76a2013-02-27 17:09:33 -0800888 //return Command.CONTINUE;
889 return Command.STOP;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800890 }
Teru Ub7246af2014-01-13 13:24:38 -0800891 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800892 }
893
894
895 if (remoteSwitch == null) {
896 // Ignore LLDPs not generated by Floodlight, or from a switch that has recently
897 // disconnected, or from a switch connected to another Floodlight instance
898 if (log.isTraceEnabled()) {
899 log.trace("Received LLDP from remote switch not connected to the controller");
900 }
901 return Command.STOP;
902 }
903
904 if (!remoteSwitch.portEnabled(remotePort)) {
905 if (log.isTraceEnabled()) {
906 log.trace("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
907 }
908 return Command.STOP;
909 }
910 if (suppressLinkDiscovery.contains(new NodePortTuple(remoteSwitch.getId(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700911 remotePort))) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800912 if (log.isTraceEnabled()) {
913 log.trace("Ignoring link with suppressed src port: switch {} port {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700914 remoteSwitch, remotePort);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800915 }
916 return Command.STOP;
917 }
918 if (!iofSwitch.portEnabled(pi.getInPort())) {
919 if (log.isTraceEnabled()) {
920 log.trace("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
921 }
922 return Command.STOP;
923 }
924
925 OFPhysicalPort physicalPort = remoteSwitch.getPort(remotePort);
926 int srcPortState = (physicalPort != null) ? physicalPort.getState() : 0;
927 physicalPort = iofSwitch.getPort(pi.getInPort());
928 int dstPortState = (physicalPort != null) ? physicalPort.getState() : 0;
929
930 // Store the time of update to this link, and push it out to routingEngine
931 Link lt = new Link(remoteSwitch.getId(), remotePort, iofSwitch.getId(), pi.getInPort());
932
933
934 Long lastLldpTime = null;
935 Long lastBddpTime = null;
936
937 Long firstSeenTime = System.currentTimeMillis();
938
Ray Milkeyb29e6262014-04-09 16:02:14 -0700939 if (isStandard) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800940 lastLldpTime = System.currentTimeMillis();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700941 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800942 lastBddpTime = System.currentTimeMillis();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700943 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800944
945 LinkInfo newLinkInfo =
946 new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
Ray Milkey269ffb92014-04-03 14:43:30 -0700947 srcPortState, dstPortState);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800948
949 addOrUpdateLink(lt, newLinkInfo);
950
Yuta HIGUCHIe8813402014-01-08 13:36:50 -0800951 // Check if reverse link exists.
952 // If it doesn't exist and if the forward link was seen
953 // first seen within a small interval, send probe on the
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800954 // reverse link.
955
956 newLinkInfo = links.get(lt);
Ray Milkey6c4f2fe2014-04-11 09:47:23 -0700957 if (newLinkInfo != null && isStandard && !isReverse) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800958 Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700959 lt.getSrc(), lt.getSrcPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800960 LinkInfo reverseInfo = links.get(reverseLink);
961 if (reverseInfo == null) {
962 // the reverse link does not exist.
963 if (newLinkInfo.getFirstSeenTime() > System.currentTimeMillis() - LINK_TIMEOUT) {
964 this.sendDiscoveryMessage(lt.getDst(), lt.getDstPort(), isStandard, true);
965 }
966 }
967 }
968
Jonathan Hart121a0242014-06-06 15:53:42 -0700969 // XXX ONOS: Don't do this:
970 // If the received packet is a BDDP packet, then create a reverse BDDP
971 // link as well.
972 // We want to preserve our semantic of the instance that controls the
973 // destination switch is the one who adds the link to the database.
974 /*
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800975 if (!isStandard) {
976 Link reverseLink = new Link(lt.getDst(), lt.getDstPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700977 lt.getSrc(), lt.getSrcPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800978
979 // srcPortState and dstPort state are reversed.
980 LinkInfo reverseInfo =
981 new LinkInfo(firstSeenTime, lastLldpTime, lastBddpTime,
Ray Milkey269ffb92014-04-03 14:43:30 -0700982 dstPortState, srcPortState);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800983
984 addOrUpdateLink(reverseLink, reverseInfo);
985 }
Jonathan Hart121a0242014-06-06 15:53:42 -0700986 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800987
988 // Remove the node ports from the quarantine and maintenance queues.
989 NodePortTuple nptSrc = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
990 NodePortTuple nptDst = new NodePortTuple(lt.getDst(), lt.getDstPort());
991 removeFromQuarantineQueue(nptSrc);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800992 removeFromQuarantineQueue(nptDst);
Jonathan Hart5337fb82014-06-11 17:31:50 -0700993
994 // XXX ONOS: Don't remove the port from the maintenance queue here
995 // because it sometimes prevents BDDPs from being sent and causes
996 // links to flap
997 // removeFromMaintenanceQueue(nptSrc);
998 // removeFromMaintenanceQueue(nptDst);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800999
1000 // Consume this message
1001 return Command.STOP;
1002 }
1003
1004 protected Command handlePacketIn(long sw, OFPacketIn pi,
1005 FloodlightContext cntx) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001006 Ethernet eth =
1007 IFloodlightProviderService.bcStore.get(cntx,
Ray Milkey269ffb92014-04-03 14:43:30 -07001008 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001009
Ray Milkey269ffb92014-04-03 14:43:30 -07001010 if (eth.getEtherType() == Ethernet.TYPE_BSN) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001011 BSN bsn = (BSN) eth.getPayload();
Ray Milkeyb29e6262014-04-09 16:02:14 -07001012 if (bsn == null) {
1013 return Command.STOP;
1014 }
1015 if (bsn.getPayload() == null) {
1016 return Command.STOP;
1017 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001018 // It could be a packet other than BSN LLDP, therefore
1019 // continue with the regular processing.
Ray Milkey6c4f2fe2014-04-11 09:47:23 -07001020 if (!(bsn.getPayload() instanceof LLDP)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001021 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001022 }
Ubuntu9cbb4ca2013-02-07 17:19:59 +00001023 return handleLldp((LLDP) bsn.getPayload(), sw, pi, false, cntx);
Ray Milkey269ffb92014-04-03 14:43:30 -07001024 } else if (eth.getEtherType() == Ethernet.TYPE_LLDP) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001025 return handleLldp((LLDP) eth.getPayload(), sw, pi, true, cntx);
1026 } else if (eth.getEtherType() < 1500) {
1027 long destMac = eth.getDestinationMAC().toLong();
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 if ((destMac & LINK_LOCAL_MASK) == LINK_LOCAL_VALUE) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001029 if (log.isTraceEnabled()) {
1030 log.trace("Ignoring packet addressed to 802.1D/Q " +
1031 "reserved address.");
1032 }
1033 return Command.STOP;
1034 }
1035 }
1036
1037 // If packet-in is from a quarantine port, stop processing.
1038 NodePortTuple npt = new NodePortTuple(sw, pi.getInPort());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001039 if (quarantineQueue.contains(npt)) {
1040 return Command.STOP;
1041 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001042
1043 return Command.CONTINUE;
1044 }
1045
1046 protected UpdateOperation getUpdateOperation(int srcPortState,
1047 int dstPortState) {
1048 boolean added =
1049 (((srcPortState &
Ray Milkey269ffb92014-04-03 14:43:30 -07001050 OFPortState.OFPPS_STP_MASK.getValue()) !=
1051 OFPortState.OFPPS_STP_BLOCK.getValue()) &&
1052 ((dstPortState &
1053 OFPortState.OFPPS_STP_MASK.getValue()) !=
1054 OFPortState.OFPPS_STP_BLOCK.getValue()));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001055
Ray Milkeyb29e6262014-04-09 16:02:14 -07001056 if (added) {
1057 return UpdateOperation.LINK_UPDATED;
1058 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001059 return UpdateOperation.LINK_REMOVED;
1060 }
1061
1062
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001063 protected UpdateOperation getUpdateOperation(int srcPortState) {
1064 boolean portUp = ((srcPortState &
1065 OFPortState.OFPPS_STP_MASK.getValue()) !=
1066 OFPortState.OFPPS_STP_BLOCK.getValue());
1067
Ray Milkeyb29e6262014-04-09 16:02:14 -07001068 if (portUp) {
1069 return UpdateOperation.PORT_UP;
1070 } else {
1071 return UpdateOperation.PORT_DOWN;
1072 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001073 }
1074
1075 protected boolean addOrUpdateLink(Link lt, LinkInfo newInfo) {
1076
1077 NodePortTuple srcNpt, dstNpt;
1078 boolean linkChanged = false;
1079
1080 lock.writeLock().lock();
1081 try {
1082 // put the new info. if an old info exists, it will be returned.
1083 LinkInfo oldInfo = links.put(lt, newInfo);
1084 if (oldInfo != null &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001085 oldInfo.getFirstSeenTime() < newInfo.getFirstSeenTime()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001086 newInfo.setFirstSeenTime(oldInfo.getFirstSeenTime());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001087 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001088
1089 if (log.isTraceEnabled()) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001090 log.trace("addOrUpdateLink: {} {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001091 lt,
1092 (newInfo.getMulticastValidTime() != null) ? "multicast" : "unicast");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001093 }
1094
1095 UpdateOperation updateOperation = null;
1096 linkChanged = false;
1097
1098 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1099 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1100
1101 if (oldInfo == null) {
1102 // index it by switch source
Ray Milkeyb29e6262014-04-09 16:02:14 -07001103 if (!switchLinks.containsKey(lt.getSrc())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001104 switchLinks.put(lt.getSrc(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001105 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001106 switchLinks.get(lt.getSrc()).add(lt);
1107
1108 // index it by switch dest
Ray Milkeyb29e6262014-04-09 16:02:14 -07001109 if (!switchLinks.containsKey(lt.getDst())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001110 switchLinks.put(lt.getDst(), new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001111 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001112 switchLinks.get(lt.getDst()).add(lt);
1113
1114 // index both ends by switch:port
Ray Milkeyb29e6262014-04-09 16:02:14 -07001115 if (!portLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001116 portLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001117 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001118 portLinks.get(srcNpt).add(lt);
1119
Ray Milkeyb29e6262014-04-09 16:02:14 -07001120 if (!portLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001121 portLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001122 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001123 portLinks.get(dstNpt).add(lt);
1124
1125 // Add to portNOFLinks if the unicast valid time is null
Ray Milkeyb29e6262014-04-09 16:02:14 -07001126 if (newInfo.getUnicastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001127 addLinkToBroadcastDomain(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001128 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001129
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001130 // ONOS: Distinguish added event separately from updated event
Pankaj Berdea41016d2013-06-10 21:18:18 -07001131 updateOperation = UpdateOperation.LINK_ADDED;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001132 linkChanged = true;
1133
1134 // Add to event history
1135 evHistTopoLink(lt.getSrc(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001136 lt.getDst(),
1137 lt.getSrcPort(),
1138 lt.getDstPort(),
1139 newInfo.getSrcPortState(), newInfo.getDstPortState(),
1140 getLinkType(lt, newInfo),
1141 EvAction.LINK_ADDED, "LLDP Recvd");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001142 } else {
1143 // Since the link info is already there, we need to
1144 // update the right fields.
1145 if (newInfo.getUnicastValidTime() == null) {
1146 // This is due to a multicast LLDP, so copy the old unicast
1147 // value.
1148 if (oldInfo.getUnicastValidTime() != null) {
1149 newInfo.setUnicastValidTime(oldInfo.getUnicastValidTime());
1150 }
1151 } else if (newInfo.getMulticastValidTime() == null) {
1152 // This is due to a unicast LLDP, so copy the old multicast
1153 // value.
1154 if (oldInfo.getMulticastValidTime() != null) {
1155 newInfo.setMulticastValidTime(oldInfo.getMulticastValidTime());
1156 }
1157 }
1158
1159 Long oldTime = oldInfo.getUnicastValidTime();
1160 Long newTime = newInfo.getUnicastValidTime();
1161 // the link has changed its state between openflow and non-openflow
1162 // if the unicastValidTimes are null or not null
1163 if (oldTime != null & newTime == null) {
1164 // openflow -> non-openflow transition
1165 // we need to add the link tuple to the portNOFLinks
1166 addLinkToBroadcastDomain(lt);
1167 linkChanged = true;
1168 } else if (oldTime == null & newTime != null) {
1169 // non-openflow -> openflow transition
1170 // we need to remove the link from the portNOFLinks
1171 removeLinkFromBroadcastDomain(lt);
1172 linkChanged = true;
1173 }
1174
1175 // Only update the port states if they've changed
1176 if (newInfo.getSrcPortState().intValue() !=
1177 oldInfo.getSrcPortState().intValue() ||
1178 newInfo.getDstPortState().intValue() !=
Ray Milkeyb29e6262014-04-09 16:02:14 -07001179 oldInfo.getDstPortState().intValue()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001180 linkChanged = true;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001181 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001182
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001183 if (linkChanged) {
1184 updateOperation = getUpdateOperation(newInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001185 newInfo.getDstPortState());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001186 if (log.isTraceEnabled()) {
1187 log.trace("Updated link {}", lt);
1188 }
1189 // Add to event history
1190 evHistTopoLink(lt.getSrc(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001191 lt.getDst(),
1192 lt.getSrcPort(),
1193 lt.getDstPort(),
1194 newInfo.getSrcPortState(), newInfo.getDstPortState(),
1195 getLinkType(lt, newInfo),
1196 EvAction.LINK_PORT_STATE_UPDATED,
1197 "LLDP Recvd");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001198 }
1199 }
1200
1201 if (linkChanged) {
1202 // find out if the link was added or removed here.
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001203 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001204 lt.getDst(), lt.getDstPort(),
1205 getLinkType(lt, newInfo),
1206 updateOperation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001207 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001208 }
1209 } finally {
1210 lock.writeLock().unlock();
1211 }
1212
1213 return linkChanged;
1214 }
1215
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001216 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001217 public Map<Long, Set<Link>> getSwitchLinks() {
1218 return this.switchLinks;
1219 }
1220
1221 /**
1222 * Removes links from memory and storage.
Ray Milkey269ffb92014-04-03 14:43:30 -07001223 *
Ray Milkey5df613b2014-04-15 10:50:56 -07001224 * @param linksToDelete The List of @LinkTuple to delete.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001225 */
Ray Milkey5df613b2014-04-15 10:50:56 -07001226 protected void deleteLinks(List<Link> linksToDelete, String reason) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001227 NodePortTuple srcNpt, dstNpt;
1228
1229 lock.writeLock().lock();
1230 try {
Ray Milkey5df613b2014-04-15 10:50:56 -07001231 for (Link lt : linksToDelete) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001232 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001233 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001234
1235 switchLinks.get(lt.getSrc()).remove(lt);
1236 switchLinks.get(lt.getDst()).remove(lt);
1237 if (switchLinks.containsKey(lt.getSrc()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001238 switchLinks.get(lt.getSrc()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001239 this.switchLinks.remove(lt.getSrc());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001240 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001241 if (this.switchLinks.containsKey(lt.getDst()) &&
Ray Milkeyb29e6262014-04-09 16:02:14 -07001242 this.switchLinks.get(lt.getDst()).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001243 this.switchLinks.remove(lt.getDst());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001244 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001245
1246 if (this.portLinks.get(srcNpt) != null) {
1247 this.portLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001248 if (this.portLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001249 this.portLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001250 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001251 }
1252 if (this.portLinks.get(dstNpt) != null) {
1253 this.portLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001254 if (this.portLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001255 this.portLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001256 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001257 }
1258
1259 LinkInfo info = this.links.remove(lt);
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001260 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001261 lt.getDst(), lt.getDstPort(),
1262 getLinkType(lt, info),
1263 UpdateOperation.LINK_REMOVED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001264 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001265
1266 // Update Event History
1267 evHistTopoLink(lt.getSrc(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001268 lt.getDst(),
1269 lt.getSrcPort(),
1270 lt.getDstPort(),
1271 0, 0, // Port states
1272 ILinkDiscovery.LinkType.INVALID_LINK,
1273 EvAction.LINK_DELETED, reason);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001274
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001275 // TODO Whenever link is removed, it has to checked if
1276 // the switchports must be added to quarantine.
1277
1278 if (log.isTraceEnabled()) {
1279 log.trace("Deleted link {}", lt);
1280 }
1281 }
1282 } finally {
1283 lock.writeLock().unlock();
1284 }
1285 }
1286
1287 /**
1288 * Handles an OFPortStatus message from a switch. We will add or
1289 * delete LinkTupes as well re-compute the topology if needed.
Ray Milkey269ffb92014-04-03 14:43:30 -07001290 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001291 * @param sw The IOFSwitch that sent the port status message
1292 * @param ps The OFPortStatus message
1293 * @return The Command to continue or stop after we process this message
1294 */
1295 protected Command handlePortStatus(long sw, OFPortStatus ps) {
1296
1297 IOFSwitch iofSwitch = floodlightProvider.getSwitches().get(sw);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001298 if (iofSwitch == null) {
1299 return Command.CONTINUE;
1300 }
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -07001301
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001302 // ONOS: If we do not control this switch, then we should not process its port status messages
Ray Milkeyb29e6262014-04-09 16:02:14 -07001303 if (!registryService.hasControl(iofSwitch.getId())) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001304 return Command.CONTINUE;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001305 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001306
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001307 if (log.isTraceEnabled()) {
1308 log.trace("handlePortStatus: Switch {} port #{} reason {}; " +
1309 "config is {} state is {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001310 new Object[]{iofSwitch.getStringId(),
1311 ps.getDesc().getPortNumber(),
1312 ps.getReason(),
1313 ps.getDesc().getConfig(),
1314 ps.getDesc().getState()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001315 }
1316
1317 short port = ps.getDesc().getPortNumber();
1318 NodePortTuple npt = new NodePortTuple(sw, port);
Ray Milkey269ffb92014-04-03 14:43:30 -07001319 boolean linkDeleted = false;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001320 boolean linkInfoChanged = false;
1321
1322 lock.writeLock().lock();
1323 try {
1324 // if ps is a delete, or a modify where the port is down or
1325 // configured down
Ray Milkey269ffb92014-04-03 14:43:30 -07001326 if ((byte) OFPortReason.OFPPR_DELETE.ordinal() == ps.getReason() ||
1327 ((byte) OFPortReason.OFPPR_MODIFY.ordinal() ==
1328 ps.getReason() && !portEnabled(ps.getDesc()))) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001329 deleteLinksOnPort(npt, "Port Status Changed");
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001330 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, UpdateOperation.PORT_DOWN));
1331 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001332 linkDeleted = true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001333 } else if (ps.getReason() ==
1334 (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001335 // If ps is a port modification and the port state has changed
1336 // that affects links in the topology
1337
1338 if (this.portLinks.containsKey(npt)) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001339 for (Link lt : this.portLinks.get(npt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001340 LinkInfo linkInfo = links.get(lt);
Ray Milkey269ffb92014-04-03 14:43:30 -07001341 assert (linkInfo != null);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001342 Integer updatedSrcPortState = null;
1343 Integer updatedDstPortState = null;
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001344 if (lt.getSrc() == npt.getNodeId() &&
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001345 lt.getSrcPort() == npt.getPortId() &&
1346 (linkInfo.getSrcPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -07001347 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001348 updatedSrcPortState = ps.getDesc().getState();
1349 linkInfo.setSrcPortState(updatedSrcPortState);
1350 }
1351 if (lt.getDst() == npt.getNodeId() &&
1352 lt.getDstPort() == npt.getPortId() &&
1353 (linkInfo.getDstPortState() !=
Ray Milkey269ffb92014-04-03 14:43:30 -07001354 ps.getDesc().getState())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001355 updatedDstPortState = ps.getDesc().getState();
1356 linkInfo.setDstPortState(updatedDstPortState);
1357 }
1358 if ((updatedSrcPortState != null) ||
1359 (updatedDstPortState != null)) {
1360 // The link is already known to link discovery
1361 // manager and the status has changed, therefore
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001362 // send an LinkUpdate.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001363 UpdateOperation operation =
1364 getUpdateOperation(linkInfo.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001365 linkInfo.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001366 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001367 lt.getDst(), lt.getDstPort(),
1368 getLinkType(lt, linkInfo),
1369 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001370 controller.publishUpdate(update);
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001371
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001372 linkInfoChanged = true;
1373 }
1374 }
1375 }
1376
1377 UpdateOperation operation =
1378 getUpdateOperation(ps.getDesc().getState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001379 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, port, operation));
1380 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001381 }
1382
Ray Milkey269ffb92014-04-03 14:43:30 -07001383 if (!linkDeleted && !linkInfoChanged) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001384 if (log.isTraceEnabled()) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001385 log.trace("handlePortStatus: Switch {} port #{} reason {};" +
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001386 " no links to update/remove",
Ray Milkey269ffb92014-04-03 14:43:30 -07001387 new Object[]{HexString.toHexString(sw),
1388 ps.getDesc().getPortNumber(),
1389 ps.getReason()});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001390 }
1391 }
1392 } finally {
1393 lock.writeLock().unlock();
1394 }
1395
1396 if (!linkDeleted) {
1397 // Send LLDP right away when port state is changed for faster
1398 // cluster-merge. If it is a link delete then there is not need
1399 // to send the LLDPs right away and instead we wait for the LLDPs
1400 // to be sent on the timer as it is normally done
1401 // do it outside the write-lock
1402 // sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
1403 processNewPort(npt.getNodeId(), npt.getPortId());
1404 }
1405 return Command.CONTINUE;
1406 }
1407
1408 /**
1409 * Process a new port.
1410 * If link discovery is disabled on the port, then do nothing.
1411 * If autoportfast feature is enabled and the port is a fast port, then
1412 * do nothing.
1413 * Otherwise, send LLDP message. Add the port to quarantine.
Ray Milkey269ffb92014-04-03 14:43:30 -07001414 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001415 * @param sw
1416 * @param p
1417 */
1418 private void processNewPort(long sw, short p) {
1419 if (isLinkDiscoverySuppressed(sw, p)) {
1420 // Do nothing as link discovery is suppressed.
Ray Milkey1aa71f82014-04-08 16:23:24 -07001421 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001422 } else if (autoPortFastFeature && isFastPort(sw, p)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001423 // Do nothing as the port is a fast port.
Ray Milkey1aa71f82014-04-08 16:23:24 -07001424 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001425 } else {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001426 NodePortTuple npt = new NodePortTuple(sw, p);
1427 discover(sw, p);
1428 // if it is not a fast port, add it to quarantine.
1429 if (!isFastPort(sw, p)) {
1430 addToQuarantineQueue(npt);
1431 } else {
1432 // Add to maintenance queue to ensure that BDDP packets
1433 // are sent out.
1434 addToMaintenanceQueue(npt);
1435 }
1436 }
1437 }
1438
1439 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001440 * We send out LLDP messages when a switch is added to discover the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001441 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001442 * @param sw The IOFSwitch that connected to the controller
1443 */
1444 @Override
1445 public void addedSwitch(IOFSwitch sw) {
1446
1447 if (sw.getEnabledPorts() != null) {
1448 for (Short p : sw.getEnabledPortNumbers()) {
1449 processNewPort(sw.getId(), p);
1450 }
1451 }
1452 // Update event history
1453 evHistTopoSwitch(sw, EvAction.SWITCH_CONNECTED, "None");
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001454 LinkUpdate update = new LinkUpdate(new LDUpdate(sw.getId(), null,
Ray Milkey269ffb92014-04-03 14:43:30 -07001455 UpdateOperation.SWITCH_UPDATED));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001456 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001457 }
1458
1459 /**
1460 * When a switch disconnects we remove any links from our map and notify.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001461 */
1462 @Override
1463 public void removedSwitch(IOFSwitch iofSwitch) {
1464 // Update event history
1465 long sw = iofSwitch.getId();
1466 evHistTopoSwitch(iofSwitch, EvAction.SWITCH_DISCONNECTED, "None");
1467 List<Link> eraseList = new ArrayList<Link>();
1468 lock.writeLock().lock();
1469 try {
1470 if (switchLinks.containsKey(sw)) {
1471 if (log.isTraceEnabled()) {
1472 log.trace("Handle switchRemoved. Switch {}; removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001473 HexString.toHexString(sw), switchLinks.get(sw));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001474 }
1475 // add all tuples with an endpoint on this switch to erase list
1476 eraseList.addAll(switchLinks.get(sw));
HIGUCHI Yutaa89b2842013-06-17 13:54:57 -07001477 deleteLinks(eraseList, "Switch Removed");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001478
1479 // Send a switch removed update
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001480 LinkUpdate update = new LinkUpdate(new LDUpdate(sw, null, UpdateOperation.SWITCH_REMOVED));
1481 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001482 }
1483 } finally {
1484 lock.writeLock().unlock();
1485 }
1486 }
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001487
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001488 /**
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001489 * We don't react the port changed notifications here. we listen for
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001490 * OFPortStatus messages directly. Might consider using this notifier
1491 * instead
1492 */
1493 @Override
1494 public void switchPortChanged(Long switchId) {
1495 // no-op
1496 }
1497
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001498 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001499 * Delete links incident on a given switch port.
Ray Milkey269ffb92014-04-03 14:43:30 -07001500 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001501 * @param npt
1502 * @param reason
1503 */
1504 protected void deleteLinksOnPort(NodePortTuple npt, String reason) {
1505 List<Link> eraseList = new ArrayList<Link>();
1506 if (this.portLinks.containsKey(npt)) {
1507 if (log.isTraceEnabled()) {
1508 log.trace("handlePortStatus: Switch {} port #{} " +
1509 "removing links {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001510 new Object[]{HexString.toHexString(npt.getNodeId()),
1511 npt.getPortId(),
1512 this.portLinks.get(npt)});
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001513 }
1514 eraseList.addAll(this.portLinks.get(npt));
1515 deleteLinks(eraseList, reason);
1516 }
1517 }
1518
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001519 /**
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001520 * Iterates through the list of links and deletes if the
1521 * last discovery message reception time exceeds timeout values.
1522 */
1523 protected void timeoutLinks() {
1524 List<Link> eraseList = new ArrayList<Link>();
1525 Long curTime = System.currentTimeMillis();
1526 boolean linkChanged = false;
1527
1528 // reentrant required here because deleteLink also write locks
1529 lock.writeLock().lock();
1530 try {
1531 Iterator<Entry<Link, LinkInfo>> it =
1532 this.links.entrySet().iterator();
1533 while (it.hasNext()) {
1534 Entry<Link, LinkInfo> entry = it.next();
1535 Link lt = entry.getKey();
1536 LinkInfo info = entry.getValue();
1537
1538 // Timeout the unicast and multicast LLDP valid times
1539 // independently.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001540 if ((info.getUnicastValidTime() != null) &&
Ray Milkey149693c2014-05-20 14:58:53 -07001541 (info.getUnicastValidTime() + (1000L * LINK_TIMEOUT) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001542 info.setUnicastValidTime(null);
1543
Ray Milkeyb29e6262014-04-09 16:02:14 -07001544 if (info.getMulticastValidTime() != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001545 addLinkToBroadcastDomain(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001546 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001547 // Note that even if mTime becomes null later on,
1548 // the link would be deleted, which would trigger updateClusters().
1549 linkChanged = true;
1550 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001551 if ((info.getMulticastValidTime() != null) &&
Ray Milkey149693c2014-05-20 14:58:53 -07001552 (info.getMulticastValidTime() + (1000L * LINK_TIMEOUT) < curTime)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001553 info.setMulticastValidTime(null);
1554 // if uTime is not null, then link will remain as openflow
1555 // link. If uTime is null, it will be deleted. So, we
1556 // don't care about linkChanged flag here.
1557 removeLinkFromBroadcastDomain(lt);
1558 linkChanged = true;
1559 }
1560 // Add to the erase list only if the unicast
1561 // time is null.
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001562 if (info.getUnicastValidTime() == null &&
Ray Milkey269ffb92014-04-03 14:43:30 -07001563 info.getMulticastValidTime() == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001564 eraseList.add(entry.getKey());
1565 } else if (linkChanged) {
1566 UpdateOperation operation;
1567 operation = getUpdateOperation(info.getSrcPortState(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001568 info.getDstPortState());
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001569 LinkUpdate update = new LinkUpdate(new LDUpdate(lt.getSrc(), lt.getSrcPort(),
Ray Milkey269ffb92014-04-03 14:43:30 -07001570 lt.getDst(), lt.getDstPort(),
1571 getLinkType(lt, info),
1572 operation));
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001573 controller.publishUpdate(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001574 }
1575 }
1576
1577 // if any link was deleted or any link was changed.
1578 if ((eraseList.size() > 0) || linkChanged) {
1579 deleteLinks(eraseList, "LLDP timeout");
1580 }
1581 } finally {
1582 lock.writeLock().unlock();
1583 }
1584 }
1585
1586 private boolean portEnabled(OFPhysicalPort port) {
Ray Milkeyb29e6262014-04-09 16:02:14 -07001587 if (port == null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001588 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001589 }
1590 if ((OFPortConfig.OFPPC_PORT_DOWN.getValue() & port.getConfig()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001591 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001592 }
1593 if ((OFPortState.OFPPS_LINK_DOWN.getValue() & port.getState()) > 0) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001594 return false;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001595 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001596 // Port STP state doesn't work with multiple VLANs, so ignore it for now
1597 // if ((port.getState() & OFPortState.OFPPS_STP_MASK.getValue()) == OFPortState.OFPPS_STP_BLOCK.getValue())
1598 // return false;
1599 return true;
1600 }
1601
1602 public Map<NodePortTuple, Set<Link>> getPortBroadcastDomainLinks() {
1603 return portBroadcastDomainLinks;
1604 }
1605
1606 @Override
1607 public Map<Link, LinkInfo> getLinks() {
1608 lock.readLock().lock();
1609 Map<Link, LinkInfo> result;
1610 try {
1611 result = new HashMap<Link, LinkInfo>(links);
1612 } finally {
1613 lock.readLock().unlock();
1614 }
1615 return result;
1616 }
1617
1618 protected void addLinkToBroadcastDomain(Link lt) {
1619
1620 NodePortTuple srcNpt, dstNpt;
1621 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1622 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1623
Ray Milkeyb29e6262014-04-09 16:02:14 -07001624 if (!portBroadcastDomainLinks.containsKey(srcNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001625 portBroadcastDomainLinks.put(srcNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001626 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001627 portBroadcastDomainLinks.get(srcNpt).add(lt);
1628
Ray Milkeyb29e6262014-04-09 16:02:14 -07001629 if (!portBroadcastDomainLinks.containsKey(dstNpt)) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001630 portBroadcastDomainLinks.put(dstNpt, new HashSet<Link>());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001631 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001632 portBroadcastDomainLinks.get(dstNpt).add(lt);
1633 }
1634
1635 protected void removeLinkFromBroadcastDomain(Link lt) {
1636
1637 NodePortTuple srcNpt, dstNpt;
1638 srcNpt = new NodePortTuple(lt.getSrc(), lt.getSrcPort());
1639 dstNpt = new NodePortTuple(lt.getDst(), lt.getDstPort());
1640
1641 if (portBroadcastDomainLinks.containsKey(srcNpt)) {
1642 portBroadcastDomainLinks.get(srcNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001643 if (portBroadcastDomainLinks.get(srcNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001644 portBroadcastDomainLinks.remove(srcNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001645 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001646 }
1647
1648 if (portBroadcastDomainLinks.containsKey(dstNpt)) {
1649 portBroadcastDomainLinks.get(dstNpt).remove(lt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001650 if (portBroadcastDomainLinks.get(dstNpt).isEmpty()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001651 portBroadcastDomainLinks.remove(dstNpt);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001652 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001653 }
1654 }
1655
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001656 @Override
1657 public void addListener(ILinkDiscoveryListener listener) {
1658 linkDiscoveryAware.add(listener);
1659 }
1660
1661 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001662 * Register a link discovery aware component.
Ray Milkey269ffb92014-04-03 14:43:30 -07001663 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001664 * @param linkDiscoveryAwareComponent
1665 */
1666 public void addLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1667 // TODO make this a copy on write set or lock it somehow
1668 this.linkDiscoveryAware.add(linkDiscoveryAwareComponent);
1669 }
1670
1671 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -07001672 * Deregister a link discovery aware component.
Ray Milkey269ffb92014-04-03 14:43:30 -07001673 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001674 * @param linkDiscoveryAwareComponent
1675 */
1676 public void removeLinkDiscoveryAware(ILinkDiscoveryListener linkDiscoveryAwareComponent) {
1677 // TODO make this a copy on write set or lock it somehow
1678 this.linkDiscoveryAware.remove(linkDiscoveryAwareComponent);
1679 }
1680
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001681 @Override
1682 public boolean isCallbackOrderingPrereq(OFType type, String name) {
1683 return false;
1684 }
1685
1686 @Override
1687 public boolean isCallbackOrderingPostreq(OFType type, String name) {
1688 return false;
1689 }
1690
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001691 // IFloodlightModule classes
1692
1693 @Override
1694 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001695 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001696 new ArrayList<Class<? extends IFloodlightService>>();
1697 l.add(ILinkDiscoveryService.class);
1698 //l.add(ITopologyService.class);
1699 return l;
1700 }
1701
1702 @Override
1703 public Map<Class<? extends IFloodlightService>, IFloodlightService>
1704 getServiceImpls() {
1705 Map<Class<? extends IFloodlightService>,
Ray Milkey269ffb92014-04-03 14:43:30 -07001706 IFloodlightService> m =
1707 new HashMap<Class<? extends IFloodlightService>,
1708 IFloodlightService>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001709 // We are the class that implements the service
1710 m.put(ILinkDiscoveryService.class, this);
1711 return m;
1712 }
1713
1714 @Override
1715 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001716 Collection<Class<? extends IFloodlightService>> l =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001717 new ArrayList<Class<? extends IFloodlightService>>();
1718 l.add(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001719 l.add(IThreadPoolService.class);
1720 l.add(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001721 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001722 l.add(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001723 return l;
1724 }
1725
1726 @Override
1727 public void init(FloodlightModuleContext context)
1728 throws FloodlightModuleException {
1729 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001730 threadPool = context.getServiceImpl(IThreadPoolService.class);
1731 restApi = context.getServiceImpl(IRestApiService.class);
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001732 // Added by ONOS
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001733 registryService = context.getServiceImpl(IControllerRegistryService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001734
1735 // Set the autoportfast feature to false.
1736 this.autoPortFastFeature = false;
1737
1738 // We create this here because there is no ordering guarantee
1739 this.linkDiscoveryAware = new ArrayList<ILinkDiscoveryListener>();
1740 this.lock = new ReentrantReadWriteLock();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001741 this.links = new HashMap<Link, LinkInfo>();
1742 this.portLinks = new HashMap<NodePortTuple, Set<Link>>();
1743 this.suppressLinkDiscovery =
1744 Collections.synchronizedSet(new HashSet<NodePortTuple>());
1745 this.portBroadcastDomainLinks = new HashMap<NodePortTuple, Set<Link>>();
1746 this.switchLinks = new HashMap<Long, Set<Link>>();
1747 this.quarantineQueue = new LinkedBlockingQueue<NodePortTuple>();
1748 this.maintenanceQueue = new LinkedBlockingQueue<NodePortTuple>();
HIGUCHI Yuta30d03302013-06-14 13:47:36 -07001749 // Added by ONOS
HIGUCHI Yuta7677a6f2013-06-14 14:13:35 -07001750 this.remoteSwitches = new HashMap<Long, IOnosRemoteSwitch>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001751
1752 this.evHistTopologySwitch =
1753 new EventHistory<EventHistoryTopologySwitch>("Topology: Switch");
1754 this.evHistTopologyLink =
1755 new EventHistory<EventHistoryTopologyLink>("Topology: Link");
1756 this.evHistTopologyCluster =
1757 new EventHistory<EventHistoryTopologyCluster>("Topology: Cluster");
1758 }
1759
1760 @Override
1761 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001762 @LogMessageDoc(level = "ERROR",
1763 message = "No storage source found.",
1764 explanation = "Storage source was not initialized; cannot initialize " +
1765 "link discovery.",
1766 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1767 @LogMessageDoc(level = "ERROR",
1768 message = "Error in installing listener for " +
1769 "switch config table {table}",
1770 explanation = "Failed to install storage notification for the " +
1771 "switch config table",
1772 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1773 @LogMessageDoc(level = "ERROR",
1774 message = "No storage source found.",
1775 explanation = "Storage source was not initialized; cannot initialize " +
1776 "link discovery.",
1777 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG),
1778 @LogMessageDoc(level = "ERROR",
1779 message = "Exception in LLDP send timer.",
1780 explanation = "An unknown error occured while sending LLDP " +
1781 "messages to switches.",
1782 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001783 })
1784 public void startUp(FloodlightModuleContext context) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001785 ScheduledExecutorService ses = threadPool.getScheduledExecutor();
Pankaj Berdedc73bb12013-08-14 13:46:38 -07001786 controller =
1787 context.getServiceImpl(IFloodlightProviderService.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001788
1789 // To be started by the first switch connection
1790 discoveryTask = new SingletonTask(ses, new Runnable() {
1791 @Override
1792 public void run() {
1793 try {
1794 discoverLinks();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001795 } catch (Exception e) {
1796 log.error("Exception in LLDP send timer.", e);
1797 } finally {
1798 if (!shuttingDown) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001799 // Always reschedule link discovery if we're not
1800 // shutting down (no chance of SLAVE role now)
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001801 log.trace("Rescheduling discovery task");
1802 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL,
Ray Milkey269ffb92014-04-03 14:43:30 -07001803 TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001804 }
1805 }
1806 }
1807 });
1808
Jonathan Hartec4f14e2013-12-12 10:46:38 -08001809 // Always reschedule link discovery as we are never in SLAVE role now
1810 discoveryTask.reschedule(DISCOVERY_TASK_INTERVAL, TimeUnit.SECONDS);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001811
1812 // Setup the BDDP task. It is invoked whenever switch port tuples
1813 // are added to the quarantine list.
1814 bddpTask = new SingletonTask(ses, new QuarantineWorker());
1815 bddpTask.reschedule(BDDP_TASK_INTERVAL, TimeUnit.MILLISECONDS);
1816
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001817
1818 // Register for the OpenFlow messages we want to receive
1819 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
1820 floodlightProvider.addOFMessageListener(OFType.PORT_STATUS, this);
1821 // Register for switch updates
1822 floodlightProvider.addOFSwitchListener(this);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001823 if (restApi != null) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001824 restApi.addRestletRoutable(new LinkDiscoveryWebRoutable());
Ray Milkeyb29e6262014-04-09 16:02:14 -07001825 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001826 setControllerTLV();
1827 }
1828
1829 // ****************************************************
1830 // Topology Manager's Event History members and methods
1831 // ****************************************************
1832
1833 // Topology Manager event history
Ray Milkey269ffb92014-04-03 14:43:30 -07001834 public EventHistory<EventHistoryTopologySwitch> evHistTopologySwitch;
1835 public EventHistory<EventHistoryTopologyLink> evHistTopologyLink;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001836 public EventHistory<EventHistoryTopologyCluster> evHistTopologyCluster;
Ray Milkey269ffb92014-04-03 14:43:30 -07001837 public EventHistoryTopologySwitch evTopoSwitch;
1838 public EventHistoryTopologyLink evTopoLink;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001839 public EventHistoryTopologyCluster evTopoCluster;
1840
1841 // Switch Added/Deleted
1842 private void evHistTopoSwitch(IOFSwitch sw, EvAction actn, String reason) {
1843 if (evTopoSwitch == null) {
1844 evTopoSwitch = new EventHistoryTopologySwitch();
1845 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001846 evTopoSwitch.dpid = sw.getId();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001847 if ((sw.getChannel() != null) &&
1848 (SocketAddress.class.isInstance(
Ray Milkey269ffb92014-04-03 14:43:30 -07001849 sw.getChannel().getRemoteAddress()))) {
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001850 evTopoSwitch.ipv4Addr =
Ray Milkey269ffb92014-04-03 14:43:30 -07001851 IPv4.toIPv4Address(((InetSocketAddress) (sw.getChannel().
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001852 getRemoteAddress())).getAddress().getAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -07001853 evTopoSwitch.l4Port =
1854 ((InetSocketAddress) (sw.getChannel().
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001855 getRemoteAddress())).getPort();
1856 } else {
1857 evTopoSwitch.ipv4Addr = 0;
1858 evTopoSwitch.l4Port = 0;
1859 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001860 evTopoSwitch.reason = reason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001861 evTopoSwitch = evHistTopologySwitch.put(evTopoSwitch, actn);
1862 }
1863
Ray Milkeya5450cc2014-04-17 14:31:30 -07001864 // CHECKSTYLE:OFF suppress warning about too many parameters
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001865 private void evHistTopoLink(long srcDpid, long dstDpid, short srcPort,
1866 short dstPort, int srcPortState, int dstPortState,
1867 ILinkDiscovery.LinkType linkType,
1868 EvAction actn, String reason) {
Ray Milkeya5450cc2014-04-17 14:31:30 -07001869 // CHECKSTYLE:ON
1870
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001871 if (evTopoLink == null) {
1872 evTopoLink = new EventHistoryTopologyLink();
1873 }
1874 evTopoLink.srcSwDpid = srcDpid;
1875 evTopoLink.dstSwDpid = dstDpid;
1876 evTopoLink.srcSwport = srcPort & 0xffff;
1877 evTopoLink.dstSwport = dstPort & 0xffff;
1878 evTopoLink.srcPortState = srcPortState;
1879 evTopoLink.dstPortState = dstPortState;
Ray Milkey269ffb92014-04-03 14:43:30 -07001880 evTopoLink.reason = reason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001881 switch (linkType) {
1882 case DIRECT_LINK:
1883 evTopoLink.linkType = "DIRECT_LINK";
1884 break;
1885 case MULTIHOP_LINK:
1886 evTopoLink.linkType = "MULTIHOP_LINK";
1887 break;
1888 case TUNNEL:
1889 evTopoLink.linkType = "TUNNEL";
1890 break;
1891 case INVALID_LINK:
1892 default:
1893 evTopoLink.linkType = "Unknown";
1894 break;
1895 }
1896 evTopoLink = evHistTopologyLink.put(evTopoLink, actn);
1897 }
1898
1899 public void evHistTopoCluster(long dpid, long clusterIdOld,
1900 long clusterIdNew, EvAction action, String reason) {
1901 if (evTopoCluster == null) {
1902 evTopoCluster = new EventHistoryTopologyCluster();
1903 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001904 evTopoCluster.dpid = dpid;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001905 evTopoCluster.clusterIdOld = clusterIdOld;
1906 evTopoCluster.clusterIdNew = clusterIdNew;
Ray Milkey269ffb92014-04-03 14:43:30 -07001907 evTopoCluster.reason = reason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001908 evTopoCluster = evHistTopologyCluster.put(evTopoCluster, action);
1909 }
1910
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001911 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001912 public boolean isAutoPortFastFeature() {
1913 return autoPortFastFeature;
1914 }
1915
Yuta HIGUCHIe8813402014-01-08 13:36:50 -08001916 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001917 public void setAutoPortFastFeature(boolean autoPortFastFeature) {
1918 this.autoPortFastFeature = autoPortFastFeature;
1919 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001920}