blob: 7675aaea2595c51045ca40ae4e173a16dbf4d220 [file] [log] [blame]
Jonathan Hart472062d2014-04-03 10:56:48 -07001package net.onrc.onos.core.topology;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08002
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -07003import java.nio.ByteBuffer;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -07006import java.util.LinkedList;
Jonathan Hart369875b2014-02-13 10:00:31 -08007import java.util.List;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08008import java.util.Map;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -07009import java.util.concurrent.ConcurrentHashMap;
10import java.util.concurrent.ConcurrentMap;
Jonathan Hart369875b2014-02-13 10:00:31 -080011import java.util.concurrent.TimeUnit;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080012
13import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -070014import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080015import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070016import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
17import net.floodlightcontroller.core.IOFSwitchListener;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080018import net.floodlightcontroller.core.module.FloodlightModuleContext;
19import net.floodlightcontroller.core.module.FloodlightModuleException;
20import net.floodlightcontroller.core.module.IFloodlightModule;
21import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart369875b2014-02-13 10:00:31 -080022import net.floodlightcontroller.core.util.SingletonTask;
23import net.floodlightcontroller.threadpool.IThreadPoolService;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070024import net.onrc.onos.core.datagrid.IDatagridService;
25import net.onrc.onos.core.datagrid.IEventChannel;
Jonathan Hart03102132014-07-01 23:22:04 -070026import net.onrc.onos.core.hostmanager.Host;
27import net.onrc.onos.core.hostmanager.IHostListener;
28import net.onrc.onos.core.hostmanager.IHostService;
Jonathan Hart23701d12014-04-03 10:45:48 -070029import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
30import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart284e70f2014-07-05 12:32:51 -070031import net.onrc.onos.core.linkdiscovery.Link;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070032import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070033import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070034import net.onrc.onos.core.registry.RegistryException;
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -070035import net.onrc.onos.core.util.Dpid;
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070036import net.onrc.onos.core.util.OnosInstanceId;
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -070037import net.onrc.onos.core.util.PortNumberUtils;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070038import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080039
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070040import org.apache.commons.lang3.concurrent.ConcurrentUtils;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070041import org.projectfloodlight.openflow.protocol.OFPortDesc;
42import org.projectfloodlight.openflow.util.HexString;
Toshio Koide2f570c12014-02-06 16:55:32 -080043import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080045
Jonathan Hart88770672014-04-02 18:08:30 -070046/**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070047 * Class for publishing topology-related events.
48 *
49 * The events are received from the discovery modules, reformatted and
50 * published to the other ONOS instances.
51 *
52 * TODO: Add a synchronization mechanism when publishing the events to
53 * preserve the ordering and to avoid mismatch in the local "published" state,
54 * because each of the caller (the discovery modules) might be running
55 * on a different thread.
Jonathan Hart88770672014-04-02 18:08:30 -070056 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070057public class TopologyPublisher implements IOFSwitchListener,
Ray Milkey269ffb92014-04-03 14:43:30 -070058 ILinkDiscoveryListener,
59 IFloodlightModule,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070060 IHostListener {
Jonathan Hart88770672014-04-02 18:08:30 -070061 private static final Logger log =
Jonathan Harte37e4e22014-05-13 19:12:02 -070062 LoggerFactory.getLogger(TopologyPublisher.class);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080063
Jonathan Hart88770672014-04-02 18:08:30 -070064 private IFloodlightProviderService floodlightProvider;
65 private ILinkDiscoveryService linkDiscovery;
66 private IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070067 private ITopologyService topologyService;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070068 private IDatagridService datagridService;
Toshio Koide2f570c12014-02-06 16:55:32 -080069
Jonathan Hart03102132014-07-01 23:22:04 -070070 private IHostService hostService;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070071
Jonathan Harte37e4e22014-05-13 19:12:02 -070072 private Topology topology;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070073
Jonathan Hart88770672014-04-02 18:08:30 -070074 private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
75 private boolean cleanupEnabled = true;
76 private static final int CLEANUP_TASK_INTERVAL = 60; // in seconds
77 private SingletonTask cleanupTask;
Toshio Koide2f570c12014-02-06 16:55:32 -080078
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070079 private IEventChannel<byte[], TopologyEvent> eventChannel;
80
81 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070082 // Local state for keeping track of locally published events so we can
83 // cleanup properly when an entry is removed.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070084 //
85 // We keep all Port, (incoming) Link and Host events per Switch DPID:
86 // - If a switch goes down, we remove all corresponding Port, Link and
87 // Host events.
88 // - If a port on a switch goes down, we remove all corresponding Link
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070089 // and Host events attached to this port.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070090 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070091 // TODO: What to do if the Mastership changes?
92 // - Cleanup state from publishedFoo maps, but do not send REMOVE events?
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070093 //
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -070094 private ConcurrentMap<Dpid, MastershipEvent> publishedMastershipEvents =
95 new ConcurrentHashMap<>();
96 private ConcurrentMap<Dpid, SwitchEvent> publishedSwitchEvents =
97 new ConcurrentHashMap<>();
98 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, PortEvent>>
99 publishedPortEvents = new ConcurrentHashMap<>();
100 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, LinkEvent>>
101 publishedLinkEvents = new ConcurrentHashMap<>();
102 private ConcurrentMap<Dpid, ConcurrentMap<ByteBuffer, HostEvent>>
103 publishedHostEvents = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700104
105
Jonathan Hart369875b2014-02-13 10:00:31 -0800106 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700107 * Gets the ONOS Instance ID.
108 *
109 * @return the ONOS Instance ID.
110 */
111 private OnosInstanceId getOnosInstanceId() {
112 return registryService.getOnosInstanceId();
113 }
114
115 /**
116 * Cleanup old switches from the topology. Old switches are those which
117 * have no controller in the registry.
118 *
119 * TODO: The overall switch cleanup mechanism needs refactoring/redesign.
Jonathan Hart369875b2014-02-13 10:00:31 -0800120 */
121 private class SwitchCleanup implements ControlChangeCallback, Runnable {
122 @Override
123 public void run() {
124 String old = Thread.currentThread().getName();
125 Thread.currentThread().setName("SwitchCleanup@" + old);
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700126
Jonathan Hart369875b2014-02-13 10:00:31 -0800127 try {
Jonathan Hart88770672014-04-02 18:08:30 -0700128 if (log.isTraceEnabled()) {
129 log.trace("Running cleanup thread");
130 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800131 switchCleanup();
Jonathan Hart369875b2014-02-13 10:00:31 -0800132 } finally {
133 cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
Jonathan Hart88770672014-04-02 18:08:30 -0700134 TimeUnit.SECONDS);
Jonathan Hart369875b2014-02-13 10:00:31 -0800135 Thread.currentThread().setName(old);
136 }
137 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700138
Jonathan Hart88770672014-04-02 18:08:30 -0700139 /**
140 * First half of the switch cleanup operation. This method will attempt
141 * to get control of any switch it sees without a controller via the
142 * registry.
143 */
Jonathan Hart369875b2014-02-13 10:00:31 -0800144 private void switchCleanup() {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700145 Iterable<Switch> switches = topology.getSwitches();
Jonathan Hart369875b2014-02-13 10:00:31 -0800146
Jonathan Hart88770672014-04-02 18:08:30 -0700147 if (log.isTraceEnabled()) {
148 log.trace("Checking for inactive switches");
149 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700150 // For each switch check if a controller exists in controller
151 // registry
Ray Milkey269ffb92014-04-03 14:43:30 -0700152 for (Switch sw : switches) {
Praseed Balakrishnane82adc62014-08-04 10:59:24 -0700153 // FIXME How to handle case where Switch has never been
154 // registered to ZK
155 if (sw.getConfigState() == ConfigState.CONFIGURED) {
156 continue;
157 }
Jonathan Hart88770672014-04-02 18:08:30 -0700158 try {
159 String controller =
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700160 registryService.getControllerForSwitch(sw.getDpid().value());
Jonathan Hart88770672014-04-02 18:08:30 -0700161 if (controller == null) {
162 log.debug("Requesting control to set switch {} INACTIVE",
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700163 sw.getDpid());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700164 registryService.requestControl(sw.getDpid().value(),
165 this);
Jonathan Hart88770672014-04-02 18:08:30 -0700166 }
167 } catch (RegistryException e) {
168 log.error("Caught RegistryException in cleanup thread", e);
169 }
170 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800171 }
172
Jonathan Hart88770672014-04-02 18:08:30 -0700173 /**
174 * Second half of the switch cleanup operation. If the registry grants
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700175 * control of a switch, we can be sure no other instance is writing
176 * this switch to the topology, so we can remove it now.
177 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700178 * @param dpid the dpid of the switch we requested control for
Jonathan Hart88770672014-04-02 18:08:30 -0700179 * @param hasControl whether we got control or not
180 */
181 @Override
182 public void controlChanged(long dpid, boolean hasControl) {
183 if (hasControl) {
184 log.debug("Got control to set switch {} INACTIVE",
185 HexString.toHexString(dpid));
Jonathan Harte02cf542014-04-02 16:24:44 -0700186
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -0700187 SwitchEvent switchEvent = new SwitchEvent(new Dpid(dpid));
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700188 publishRemoveSwitchEvent(switchEvent);
Jonathan Hart88770672014-04-02 18:08:30 -0700189 registryService.releaseControl(dpid);
190 }
191 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800192 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800193
Jonathan Hart88770672014-04-02 18:08:30 -0700194 @Override
Jonathan Hart284e70f2014-07-05 12:32:51 -0700195 public void linkAdded(Link link) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700196 LinkEvent linkEvent = new LinkEvent(
Jonathan Hart284e70f2014-07-05 12:32:51 -0700197 new SwitchPort(link.getSrc(), link.getSrcPort()),
198 new SwitchPort(link.getDst(), link.getDstPort()));
199
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700200 // FIXME should be merging, with existing attrs, etc..
201 // TODO define attr name as constant somewhere.
202 // TODO populate appropriate attributes.
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700203 linkEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700204 TopologyElement.TYPE_PACKET_LAYER);
Praseed Balakrishnan2aa6c0b2014-07-17 11:42:05 -0700205 linkEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
206 ConfigState.NOT_CONFIGURED.toString());
207 linkEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
208 AdminStatus.ACTIVE.toString());
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700209 linkEvent.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700210
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700211 publishAddLinkEvent(linkEvent);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700212 }
213
214 @Override
215 public void linkRemoved(Link link) {
216 LinkEvent linkEvent = new LinkEvent(
217 new SwitchPort(link.getSrc(), link.getSrcPort()),
218 new SwitchPort(link.getDst(), link.getDstPort()));
219
220 // FIXME should be merging, with existing attrs, etc..
221 // TODO define attr name as constant somewhere.
222 // TODO populate appropriate attributes.
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700223 linkEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700224 TopologyElement.TYPE_PACKET_LAYER);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700225 linkEvent.freeze();
226
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700227 publishRemoveLinkEvent(linkEvent);
Jonathan Hart88770672014-04-02 18:08:30 -0700228 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800229
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700230 /* *****************
231 * IOFSwitchListener
232 * *****************/
233
Jonathan Hart88770672014-04-02 18:08:30 -0700234 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700235 public void switchActivatedMaster(long swId) {
236 IOFSwitch sw = floodlightProvider.getSwitch(swId);
237 final Dpid dpid = new Dpid(swId);
238 if (sw == null) {
239 log.warn("Added switch not available {} ", dpid);
240 return;
241 }
242
243 controllerRoleChanged(dpid, Role.MASTER);
244
245 SwitchEvent switchEvent = new SwitchEvent(dpid);
246 // FIXME should be merging, with existing attrs, etc..
247 // TODO define attr name as constant somewhere.
248 // TODO populate appropriate attributes.
249 switchEvent.createStringAttribute(TopologyElement.TYPE,
250 TopologyElement.TYPE_PACKET_LAYER);
251 switchEvent.createStringAttribute("ConnectedSince",
252 sw.getConnectedSince().toString());
253 switchEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
254 ConfigState.NOT_CONFIGURED.toString());
255 switchEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
256 AdminStatus.ACTIVE.toString());
257 switchEvent.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700258 // The Port events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700259 List<PortEvent> portEvents = new ArrayList<PortEvent>();
260 for (OFPortDesc port : sw.getPorts()) {
261 PortEvent portEvent = new PortEvent(dpid,
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700262 PortNumberUtils.openFlow(port));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700263 // FIXME should be merging, with existing attrs, etc..
264 // TODO define attr name as constant somewhere.
265 // TODO populate appropriate attributes.
266 portEvent.createStringAttribute("name", port.getName());
267 portEvent.createStringAttribute(TopologyElement.TYPE,
268 TopologyElement.TYPE_PACKET_LAYER);
269 portEvent.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
270 ConfigState.NOT_CONFIGURED.toString());
271 portEvent.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
272 AdminStatus.ACTIVE.toString());
273
274 portEvent.freeze();
275 portEvents.add(portEvent);
276 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700277 publishAddSwitchEvent(switchEvent, portEvents);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700278 }
279
280 @Override
281 public void switchActivatedEqual(long swId) {
282 final Dpid dpid = new Dpid(swId);
283 controllerRoleChanged(dpid, Role.EQUAL);
284 }
285
286 @Override
287 public void switchMasterToEqual(long swId) {
288 final Dpid dpid = new Dpid(swId);
289 controllerRoleChanged(dpid, Role.EQUAL);
290 }
291
292 @Override
293 public void switchEqualToMaster(long swId) {
294 // for now treat as switchActivatedMaster
295 switchActivatedMaster(swId);
296 }
297
298 @Override
299 public void switchDisconnected(long swId) {
300 final Dpid dpid = new Dpid(swId);
301
302 log.debug("Local switch disconnected: dpid = {} role = {}", dpid);
303
304 Role role = Role.SLAVE; // TODO: Should be Role.UNKNOWN
305
306 MastershipEvent mastershipEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700307 new MastershipEvent(dpid, getOnosInstanceId(), role);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700308 // FIXME should be merging, with existing attrs, etc..
309 // TODO define attr name as constant somewhere.
310 // TODO populate appropriate attributes.
311 mastershipEvent.createStringAttribute(TopologyElement.TYPE,
312 TopologyElement.TYPE_ALL_LAYERS);
313 mastershipEvent.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700314 publishRemoveSwitchMastershipEvent(mastershipEvent);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700315 }
316
317 @Override
318 public void switchPortChanged(long swId, OFPortDesc port,
319 PortChangeType changeType) {
320 switch (changeType) {
321 case ADD:
322 switchPortAdded(swId, port);
323 break;
324 case DELETE:
325 switchPortRemoved(swId, port);
326 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700327 case UP:
Pavlin Radoslavov7946c612014-08-13 15:06:00 -0700328 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
329 switchPortAdded(swId, port);
330 break;
331 case DOWN:
332 // NOTE: Currently, we treat Port UP/DOWN same as Port ADD/DELETE
333 switchPortRemoved(swId, port);
334 break;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700335 case OTHER_UPDATE:
336 default:
337 // XXX S what is the right set of port change handlers?
338 log.debug("Topology publisher does not handle these port updates: {}",
339 changeType);
340 }
341 }
342
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700343 /**
344 * Prepares an event for adding a port on a switch.
345 *
346 * @param switchId the switch ID (DPID)
347 * @param port the port to add
348 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700349 private void switchPortAdded(long switchId, OFPortDesc port) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700350 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700351 final PortEvent portEvent = new PortEvent(dpid,
352 PortNumberUtils.openFlow(port));
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700353 // FIXME should be merging, with existing attrs, etc..
354 // TODO define attr name as constant somewhere.
355 // TODO populate appropriate attributes.
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700356 portEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700357 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700358 portEvent.createStringAttribute("name", port.getName());
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700359 portEvent.freeze();
360
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700361 publishAddPortEvent(portEvent);
Jonathan Hart88770672014-04-02 18:08:30 -0700362 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800363
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700364 /**
365 * Prepares an event for removing a port on a switch.
366 *
367 * @param switchId the switch ID (DPID)
368 * @param port the port to remove
369 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700370 private void switchPortRemoved(long switchId, OFPortDesc port) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -0700371 final Dpid dpid = new Dpid(switchId);
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700372
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700373 final PortEvent portEvent = new PortEvent(dpid,
374 PortNumberUtils.openFlow(port));
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700375 // FIXME should be merging, with existing attrs, etc..
376 // TODO define attr name as constant somewhere.
377 // TODO populate appropriate attributes.
378 portEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700379 TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700380 portEvent.createStringAttribute("name", port.getName());
Yuta HIGUCHI1222ac52014-07-09 16:50:28 -0700381 portEvent.freeze();
382
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700383 publishRemovePortEvent(portEvent);
Jonathan Hart88770672014-04-02 18:08:30 -0700384 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800385
Jonathan Hart88770672014-04-02 18:08:30 -0700386 @Override
Jonathan Hart88770672014-04-02 18:08:30 -0700387 public String getName() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700388 return "topologyPublisher";
Jonathan Hart88770672014-04-02 18:08:30 -0700389 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800390
Jonathan Hart88770672014-04-02 18:08:30 -0700391 /* *****************
392 * IFloodlightModule
393 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800394
Jonathan Hart88770672014-04-02 18:08:30 -0700395 @Override
396 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
397 return null;
398 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800399
Jonathan Hart88770672014-04-02 18:08:30 -0700400 @Override
401 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700402 getServiceImpls() {
Jonathan Hart88770672014-04-02 18:08:30 -0700403 return null;
404 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800405
Jonathan Hart88770672014-04-02 18:08:30 -0700406 @Override
407 public Collection<Class<? extends IFloodlightService>>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700408 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700409 Collection<Class<? extends IFloodlightService>> l =
410 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800411 l.add(IFloodlightProviderService.class);
412 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800413 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800414 l.add(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700415 l.add(IDatagridService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700416 l.add(ITopologyService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700417 l.add(IHostService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800418 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700419 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800420
Jonathan Hart88770672014-04-02 18:08:30 -0700421 @Override
422 public void init(FloodlightModuleContext context)
423 throws FloodlightModuleException {
424 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
425 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
426 registryService = context.getServiceImpl(IControllerRegistryService.class);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700427 datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Hart03102132014-07-01 23:22:04 -0700428 hostService = context.getServiceImpl(IHostService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700429 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700430 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800431
Jonathan Hart88770672014-04-02 18:08:30 -0700432 @Override
433 public void startUp(FloodlightModuleContext context) {
434 floodlightProvider.addOFSwitchListener(this);
435 linkDiscovery.addListener(this);
Jonathan Hart03102132014-07-01 23:22:04 -0700436 hostService.addHostListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800437
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700438 eventChannel = datagridService.createChannel(
439 TopologyManager.EVENT_CHANNEL_NAME,
440 byte[].class,
441 TopologyEvent.class);
442
Jonathan Harte37e4e22014-05-13 19:12:02 -0700443 topology = topologyService.getTopology();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700444
Jonathan Hart88770672014-04-02 18:08:30 -0700445 // Run the cleanup thread
446 String enableCleanup =
447 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
448 if (enableCleanup != null
449 && enableCleanup.equalsIgnoreCase("false")) {
450 cleanupEnabled = false;
451 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700452
Jonathan Hart88770672014-04-02 18:08:30 -0700453 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700454
Jonathan Hart88770672014-04-02 18:08:30 -0700455 if (cleanupEnabled) {
456 IThreadPoolService threadPool =
457 context.getServiceImpl(IThreadPoolService.class);
458 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
459 new SwitchCleanup());
460 // Run the cleanup task immediately on startup
461 cleanupTask.reschedule(0, TimeUnit.SECONDS);
462 }
463 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700464
Jonathan Hart88770672014-04-02 18:08:30 -0700465 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700466 public void hostAdded(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700467 log.debug("Host added with MAC {}", host.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700468
Jonathan Hart03102132014-07-01 23:22:04 -0700469 SwitchPort sp = new SwitchPort(host.getSwitchDPID(), host.getSwitchPort());
Jonathan Hart88770672014-04-02 18:08:30 -0700470 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
471 spLists.add(sp);
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700472 HostEvent event = new HostEvent(host.getMacAddress());
Jonathan Hart88770672014-04-02 18:08:30 -0700473 event.setAttachmentPoints(spLists);
Jonathan Hart03102132014-07-01 23:22:04 -0700474 event.setLastSeenTime(host.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700475 // Does not use vlan info now.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700476 event.freeze();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700477
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700478 publishAddHostEvent(event);
Jonathan Hart88770672014-04-02 18:08:30 -0700479 }
TeruUd1c5b652014-03-24 13:58:46 -0700480
Jonathan Hart88770672014-04-02 18:08:30 -0700481 @Override
Jonathan Hart03102132014-07-01 23:22:04 -0700482 public void hostRemoved(Host host) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700483 log.debug("Host removed with MAC {}", host.getMacAddress());
484
485 //
486 // Remove all previously added HostEvent for this MAC address
487 //
488 // TODO: Currently, the caller of hostRemoved() might not include
489 // the correct set of Attachment Points in the HostEvent entry itself.
490 // Also, we might have multiple HostEvent entries for the same
491 // host (MAC address), each containing a single (different) Attachment
492 // Point.
493 // Hence, here we have to cleanup all HostEvent entries for this
494 // particular host, based on its MAC address.
495 //
496 List<HostEvent> removeHostEvents = new LinkedList<>();
497 for (ConcurrentMap<ByteBuffer, HostEvent> cm : publishedHostEvents.values()) {
498 for (HostEvent hostEvent : cm.values()) {
499 if (hostEvent.getMac().equals(host.getMacAddress())) {
500 removeHostEvents.add(hostEvent);
501 }
502 }
503 }
504 for (HostEvent event : removeHostEvents) {
505 publishRemoveHostEvent(event);
506 }
Jonathan Hart88770672014-04-02 18:08:30 -0700507 }
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700508
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700509 /**
510 * Prepares the Controller role changed event for a switch.
511 *
512 * @param dpid the switch DPID
513 * @param role the new role of the controller
514 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700515 private void controllerRoleChanged(Dpid dpid, Role role) {
516 log.debug("Local switch controller mastership role changed: dpid = {} role = {}",
517 dpid, role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700518 MastershipEvent mastershipEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700519 new MastershipEvent(dpid, getOnosInstanceId(), role);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700520 // FIXME should be merging, with existing attrs, etc..
521 // TODO define attr name as constant somewhere.
522 // TODO populate appropriate attributes.
523 mastershipEvent.createStringAttribute(TopologyElement.TYPE,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700524 TopologyElement.TYPE_ALL_LAYERS);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700525 mastershipEvent.freeze();
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700526 publishAddSwitchMastershipEvent(mastershipEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700527 }
528
529 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700530 * Publishes ADD Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700531 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700532 * @param mastershipEvent the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700533 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700534 private void publishAddSwitchMastershipEvent(
535 MastershipEvent mastershipEvent) {
536 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700537 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700538 new TopologyEvent(mastershipEvent, getOnosInstanceId());
539 log.debug("Publishing add mastership: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700540 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700541 publishedMastershipEvents.put(mastershipEvent.getDpid(),
542 mastershipEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700543 }
544
545 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700546 * Publishes REMOVE Mastership Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700547 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700548 * @param mastershipEvent the mastership event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700549 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700550 private void publishRemoveSwitchMastershipEvent(
551 MastershipEvent mastershipEvent) {
552 if (publishedMastershipEvents.get(mastershipEvent.getDpid()) == null) {
553 return; // Nothing to do
554 }
555
556 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700557 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700558 new TopologyEvent(mastershipEvent, getOnosInstanceId());
559 log.debug("Publishing remove mastership: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700560 eventChannel.removeEntry(topologyEvent.getID());
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700561 publishedMastershipEvents.remove(mastershipEvent.getDpid());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700562 }
563
564 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700565 * Publishes ADD Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700566 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700567 * @param switchEvent the switch event to publish
568 * @param portEvents the corresponding port events for the switch to
569 * publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700570 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700571 private void publishAddSwitchEvent(SwitchEvent switchEvent,
572 Collection<PortEvent> portEvents) {
573 if (!registryService.hasControl(switchEvent.getOriginDpid().value())) {
574 log.debug("Not the master for switch {}. Suppressed switch add event {}.",
575 switchEvent.getOriginDpid(), switchEvent);
576 return;
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700577 }
578
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700579 // Keep track of the old Port Events that should be removed
580 ConcurrentMap<ByteBuffer, PortEvent> oldPortEvents =
581 publishedPortEvents.get(switchEvent.getDpid());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700582 if (oldPortEvents == null) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700583 oldPortEvents = new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700584 }
585
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700586 // Publish the information for the switch
587 TopologyEvent topologyEvent =
588 new TopologyEvent(switchEvent, getOnosInstanceId());
589 log.debug("Publishing add switch: {}", topologyEvent);
590 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
591 publishedSwitchEvents.put(switchEvent.getDpid(), switchEvent);
592
593 // Publish the information for each port
594 ConcurrentMap<ByteBuffer, PortEvent> newPortEvents =
595 new ConcurrentHashMap<>();
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700596 for (PortEvent portEvent : portEvents) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700597 topologyEvent =
598 new TopologyEvent(portEvent, getOnosInstanceId());
599 log.debug("Publishing add port: {}", topologyEvent);
600 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
601
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700602 ByteBuffer id = portEvent.getIDasByteBuffer();
603 newPortEvents.put(id, portEvent);
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700604 oldPortEvents.remove(id);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700605 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700606 publishedPortEvents.put(switchEvent.getDpid(), newPortEvents);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700607
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700608 // Cleanup for each of the old removed port
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700609 for (PortEvent portEvent : oldPortEvents.values()) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700610 publishRemovePortEvent(portEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700611 }
612 }
613
614 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700615 * Publishes REMOVE Switch Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700616 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700617 * @param switchEvent the switch event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700618 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700619 private void publishRemoveSwitchEvent(SwitchEvent switchEvent) {
620 //
621 // TODO: Removed the check for now, because currently this method is
622 // also called by the SwitchCleanup thread, and in that case
623 // the Switch Event was published by some other ONOS instance.
624 //
625 /*
626 if (publishedSwitchEvents.get(switchEvent.getDpid()) == null) {
627 return; // Nothing to do
628 }
629 */
630
631 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700632 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700633 new TopologyEvent(switchEvent, getOnosInstanceId());
634 log.debug("Publishing remove switch: {}", topologyEvent);
635 eventChannel.removeEntry(topologyEvent.getID());
636 publishedSwitchEvents.remove(switchEvent.getDpid());
637
638 // Cleanup for each port
639 ConcurrentMap<ByteBuffer, PortEvent> portEvents =
640 publishedPortEvents.get(switchEvent.getDpid());
641 if (portEvents != null) {
642 for (PortEvent portEvent : portEvents.values()) {
643 publishRemovePortEvent(portEvent);
644 }
645 }
646
647 publishedPortEvents.remove(switchEvent.getDpid());
648 publishedLinkEvents.remove(switchEvent.getDpid());
649 publishedHostEvents.remove(switchEvent.getDpid());
650 }
651
652 /**
653 * Publishes ADD Port Event.
654 *
655 * @param portEvent the port event to publish
656 */
657 private void publishAddPortEvent(PortEvent portEvent) {
658 if (!registryService.hasControl(portEvent.getOriginDpid().value())) {
659 log.debug("Not the master for switch {}. Suppressed port add event {}.",
660 portEvent.getOriginDpid(), portEvent);
661 return;
662 }
663
664 // Publish the information
665 TopologyEvent topologyEvent =
666 new TopologyEvent(portEvent, getOnosInstanceId());
667 log.debug("Publishing add port: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700668 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
669
670 // Store the new Port Event in the local cache
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700671 ConcurrentMap<ByteBuffer, PortEvent> portEvents =
672 ConcurrentUtils.putIfAbsent(publishedPortEvents,
673 portEvent.getDpid(),
674 new ConcurrentHashMap<ByteBuffer, PortEvent>());
675 portEvents.put(portEvent.getIDasByteBuffer(), portEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700676 }
677
678 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700679 * Publishes REMOVE Port Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700680 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700681 * @param portEvent the port event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700682 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700683 private void publishRemovePortEvent(PortEvent portEvent) {
684 ConcurrentMap<ByteBuffer, PortEvent> portEvents =
685 publishedPortEvents.get(portEvent.getDpid());
686 if (portEvents == null) {
687 return; // Nothing to do
688 }
689 if (portEvents.get(portEvent.getIDasByteBuffer()) == null) {
690 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700691 }
692
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700693 // Publish the information
694 TopologyEvent topologyEvent =
695 new TopologyEvent(portEvent, getOnosInstanceId());
696 log.debug("Publishing remove port: {}", topologyEvent);
697 eventChannel.removeEntry(topologyEvent.getID());
698
699 // Cleanup for the incoming link(s)
700 ConcurrentMap<ByteBuffer, LinkEvent> linkEvents =
701 publishedLinkEvents.get(portEvent.getDpid());
702 if (linkEvents != null) {
703 for (LinkEvent linkEvent : linkEvents.values()) {
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700704 if (linkEvent.getDst().equals(portEvent.getSwitchPort())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700705 publishRemoveLinkEvent(linkEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700706 }
707 }
708 }
709
710 // Cleanup for the connected hosts
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700711 ConcurrentMap<ByteBuffer, HostEvent> hostEvents =
712 publishedHostEvents.get(portEvent.getDpid());
713 if (hostEvents != null) {
714 for (HostEvent hostEvent : hostEvents.values()) {
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700715 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
716 if (swp.equals(portEvent.getSwitchPort())) {
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700717 publishRemoveHostEvent(hostEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700718 }
719 }
720 }
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700721 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700722
723 portEvents.remove(portEvent.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700724 }
725
726 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700727 * Publishes ADD Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700728 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700729 * @param linkEvent the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700730 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700731 private void publishAddLinkEvent(LinkEvent linkEvent) {
732 if (!registryService.hasControl(linkEvent.getOriginDpid().value())) {
733 log.debug("Not the master for dst switch {}. Suppressed link add event {}.",
734 linkEvent.getOriginDpid(), linkEvent);
735 return;
736 }
737
738 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700739 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700740 new TopologyEvent(linkEvent, getOnosInstanceId());
741 log.debug("Publishing add link: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700742 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
743
744 // Store the new Link Event in the local cache
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700745 ConcurrentMap<ByteBuffer, LinkEvent> linkEvents =
746 ConcurrentUtils.putIfAbsent(publishedLinkEvents,
747 linkEvent.getDst().getDpid(),
748 new ConcurrentHashMap<ByteBuffer, LinkEvent>());
749 linkEvents.put(linkEvent.getIDasByteBuffer(), linkEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700750 }
751
752 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700753 * Publishes REMOVE Link Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700754 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700755 * @param linkEvent the link event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700756 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700757 private void publishRemoveLinkEvent(LinkEvent linkEvent) {
758 ConcurrentMap<ByteBuffer, LinkEvent> linkEvents =
759 publishedLinkEvents.get(linkEvent.getDst().getDpid());
760 if (linkEvents == null) {
761 return; // Nothing to do
762 }
763 if (linkEvents.get(linkEvent.getIDasByteBuffer()) == null) {
764 return; // Nothing to do
765 }
766
767 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700768 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700769 new TopologyEvent(linkEvent, getOnosInstanceId());
770 log.debug("Publishing remove link: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700771 eventChannel.removeEntry(topologyEvent.getID());
772
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700773 linkEvents.remove(linkEvent.getIDasByteBuffer());
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700774 }
775
776 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700777 * Publishes ADD Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700778 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700779 * @param hostEvent the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700780 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700781 private void publishAddHostEvent(HostEvent hostEvent) {
782 //
783 // NOTE: The implementation below assumes that there is just one
784 // attachment point stored in hostEvent. Currently, this assumption
785 // is true based on the existing implementation of the caller
786 // hostAdded().
787 //
788
789 if (!registryService.hasControl(hostEvent.getOriginDpid().value())) {
790 log.debug("Not the master for attachment switch {}. Suppressed host add event {}.",
791 hostEvent.getOriginDpid(), hostEvent);
792 return;
793 }
794
795 // Publish the information
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700796 TopologyEvent topologyEvent =
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700797 new TopologyEvent(hostEvent, getOnosInstanceId());
798 log.debug("Publishing add host: {}", topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700799 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700800
801 // Store the new Host Event in the local cache
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700802 ConcurrentMap<ByteBuffer, HostEvent> hostEvents =
803 ConcurrentUtils.putIfAbsent(publishedHostEvents,
804 hostEvent.getOriginDpid(),
805 new ConcurrentHashMap<ByteBuffer, HostEvent>());
806 hostEvents.put(hostEvent.getIDasByteBuffer(), hostEvent);
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700807 }
808
809 /**
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700810 * Publishes REMOVE Host Event.
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700811 *
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700812 * @param hostEvent the host event to publish
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700813 */
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700814 private void publishRemoveHostEvent(HostEvent hostEvent) {
815 ConcurrentMap<ByteBuffer, HostEvent> hostEvents =
816 publishedHostEvents.get(hostEvent.getOriginDpid());
817 if (hostEvents == null) {
818 return; // Nothing to do
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700819 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700820 if (hostEvents.get(hostEvent.getIDasByteBuffer()) == null) {
821 return; // Nothing to do
822 }
823
824 // Publish the information
825 TopologyEvent topologyEvent =
826 new TopologyEvent(hostEvent, getOnosInstanceId());
827 log.debug("Publishing remove host: {}", topologyEvent);
828 eventChannel.removeEntry(topologyEvent.getID());
829
830 hostEvents.remove(hostEvent.getIDasByteBuffer());
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700831 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800832}