blob: 939b62819f461f5a5f5b44796ec906bcd590c1c9 [file] [log] [blame]
Hyunsun Moon0d457362017-06-27 17:19:41 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon0d457362017-06-27 17:19:41 +09003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknode.impl;
17
Hyunsun Moon0d457362017-06-27 17:19:41 +090018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Modified;
22import org.apache.felix.scr.annotations.Property;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.packet.IpAddress;
26import org.onlab.util.Tools;
27import org.onosproject.cfg.ComponentConfigService;
28import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.ControllerNode;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090034import org.onosproject.net.Device;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.Port;
37import org.onosproject.net.behaviour.BridgeConfig;
38import org.onosproject.net.behaviour.BridgeDescription;
39import org.onosproject.net.behaviour.BridgeName;
40import org.onosproject.net.behaviour.ControllerInfo;
41import org.onosproject.net.behaviour.DefaultBridgeDescription;
Hyunsun Moon0d457362017-06-27 17:19:41 +090042import org.onosproject.net.behaviour.DefaultTunnelDescription;
43import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
44import org.onosproject.net.behaviour.InterfaceConfig;
Hyunsun Moon0d457362017-06-27 17:19:41 +090045import org.onosproject.net.behaviour.TunnelDescription;
46import org.onosproject.net.behaviour.TunnelEndPoints;
47import org.onosproject.net.behaviour.TunnelKeys;
48import org.onosproject.net.device.DeviceAdminService;
49import org.onosproject.net.device.DeviceEvent;
50import org.onosproject.net.device.DeviceListener;
51import org.onosproject.net.device.DeviceService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090052import org.onosproject.net.flow.instructions.ExtensionPropertyException;
53import org.onosproject.net.flow.instructions.ExtensionTreatment;
daniel parkb18424c2018-02-05 15:43:43 +090054
Hyunsun Moon0d457362017-06-27 17:19:41 +090055import org.onosproject.openstacknode.api.NodeState;
56import org.onosproject.openstacknode.api.OpenstackNode;
Hyunsun Moon0d457362017-06-27 17:19:41 +090057import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
58import org.onosproject.openstacknode.api.OpenstackNodeEvent;
59import org.onosproject.openstacknode.api.OpenstackNodeHandler;
60import org.onosproject.openstacknode.api.OpenstackNodeListener;
61import org.onosproject.openstacknode.api.OpenstackNodeService;
62import org.onosproject.ovsdb.controller.OvsdbClientService;
63import org.onosproject.ovsdb.controller.OvsdbController;
64import org.onosproject.ovsdb.controller.OvsdbNodeId;
65import org.osgi.service.component.ComponentContext;
66import org.slf4j.Logger;
67
68import java.util.Dictionary;
69import java.util.List;
70import java.util.Objects;
71import java.util.Set;
72import java.util.concurrent.ExecutorService;
73import java.util.stream.Collectors;
74
Hyunsun Moon0d457362017-06-27 17:19:41 +090075import static java.util.concurrent.Executors.newSingleThreadExecutor;
76import static org.onlab.packet.TpPort.tpPort;
77import static org.onlab.util.Tools.groupedThreads;
78import static org.onosproject.net.AnnotationKeys.PORT_NAME;
79import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Jian Li5afbea42018-02-28 10:37:03 +090080import static org.onosproject.openstacknode.api.Constants.DEFAULT_TUNNEL;
81import static org.onosproject.openstacknode.api.Constants.INTEGRATION_BRIDGE;
82import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
83import static org.onosproject.openstacknode.api.NodeState.DEVICE_CREATED;
84import static org.onosproject.openstacknode.api.NodeState.INCOMPLETE;
Hyunsun Moon0d457362017-06-27 17:19:41 +090085import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
86import static org.onosproject.openstacknode.api.OpenstackNodeService.APP_ID;
87import static org.slf4j.LoggerFactory.getLogger;
88
89/**
90 * Service bootstraps openstack node based on its type.
91 */
92@Component(immediate = true)
93public class DefaultOpenstackNodeHandler implements OpenstackNodeHandler {
94
Jian Li5afbea42018-02-28 10:37:03 +090095 private final Logger log = getLogger(getClass());
Hyunsun Moon0d457362017-06-27 17:19:41 +090096
97 private static final String OVSDB_PORT = "ovsdbPortNum";
98 private static final int DEFAULT_OVSDB_PORT = 6640;
99 private static final String DEFAULT_OF_PROTO = "tcp";
100 private static final int DEFAULT_OFPORT = 6653;
101 private static final int DPID_BEGIN = 3;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected CoreService coreService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected LeadershipService leadershipService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected ClusterService clusterService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected DeviceService deviceService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected DeviceAdminService deviceAdminService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected OvsdbController ovsdbController;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900122 protected OpenstackNodeService osNodeService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected OpenstackNodeAdminService osNodeAdminService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected ComponentConfigService componentConfigService;
129
130 @Property(name = OVSDB_PORT, intValue = DEFAULT_OVSDB_PORT,
131 label = "OVSDB server listen port")
132 private int ovsdbPort = DEFAULT_OVSDB_PORT;
133
134 private final ExecutorService eventExecutor = newSingleThreadExecutor(
135 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
136
137 private final DeviceListener ovsdbListener = new InternalOvsdbListener();
138 private final DeviceListener bridgeListener = new InternalBridgeListener();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900139 private final OpenstackNodeListener osNodeListener = new InternalOpenstackNodeListener();
140
141 private ApplicationId appId;
142 private NodeId localNode;
143
144 @Activate
145 protected void activate() {
146 appId = coreService.getAppId(APP_ID);
147 localNode = clusterService.getLocalNode().id();
148
149 componentConfigService.registerProperties(getClass());
150 leadershipService.runForLeadership(appId.name());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900151 deviceService.addListener(ovsdbListener);
152 deviceService.addListener(bridgeListener);
153 osNodeService.addListener(osNodeListener);
154
155 log.info("Started");
156 }
157
158 @Deactivate
159 protected void deactivate() {
160 osNodeService.removeListener(osNodeListener);
161 deviceService.removeListener(bridgeListener);
162 deviceService.removeListener(ovsdbListener);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900163 componentConfigService.unregisterProperties(getClass(), false);
164 leadershipService.withdraw(appId.name());
165 eventExecutor.shutdown();
166
167 log.info("Stopped");
168 }
169
170 @Modified
171 protected void modified(ComponentContext context) {
172 Dictionary<?, ?> properties = context.getProperties();
173 int updatedOvsdbPort = Tools.getIntegerProperty(properties, OVSDB_PORT);
174 if (!Objects.equals(updatedOvsdbPort, ovsdbPort)) {
175 ovsdbPort = updatedOvsdbPort;
176 }
177
178 log.info("Modified");
179 }
180
181 @Override
182 public void processInitState(OpenstackNode osNode) {
183 if (!isOvsdbConnected(osNode)) {
184 ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPort));
185 return;
186 }
187 if (!deviceService.isAvailable(osNode.intgBridge())) {
188 createBridge(osNode, INTEGRATION_BRIDGE, osNode.intgBridge());
189 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900190 }
191
192 @Override
193 public void processDeviceCreatedState(OpenstackNode osNode) {
daniel parkb18424c2018-02-05 15:43:43 +0900194 try {
195 if (!isOvsdbConnected(osNode)) {
196 ovsdbController.connect(osNode.managementIp(), tpPort(ovsdbPort));
197 return;
198 }
Hyunsun Moon0d457362017-06-27 17:19:41 +0900199
daniel parkb18424c2018-02-05 15:43:43 +0900200 if (osNode.type() == GATEWAY) {
201 addSystemInterface(osNode, INTEGRATION_BRIDGE, osNode.uplinkPort());
202 }
203
204 if (osNode.dataIp() != null &&
205 !isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
206 createTunnelInterface(osNode);
207 }
208
209 if (osNode.vlanIntf() != null &&
210 !isIntfEnabled(osNode, osNode.vlanIntf())) {
211 addSystemInterface(osNode, INTEGRATION_BRIDGE, osNode.vlanIntf());
212 }
213 } catch (Exception e) {
Jian Li340165f2018-02-27 10:38:17 +0900214 log.error("Exception occurred because of {}", e.toString());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900215 }
216 }
217
218 @Override
219 public void processCompleteState(OpenstackNode osNode) {
220 OvsdbClientService ovsdbClient = ovsdbController.getOvsdbClient(
221 new OvsdbNodeId(osNode.managementIp(), DEFAULT_OVSDB_PORT));
222 if (ovsdbClient != null && ovsdbClient.isConnected()) {
223 ovsdbClient.disconnect();
224 }
225 }
226
227 @Override
228 public void processIncompleteState(OpenstackNode osNode) {
daniel parkb18424c2018-02-05 15:43:43 +0900229 //TODO
Hyunsun Moon0d457362017-06-27 17:19:41 +0900230 }
231
Jian Li340165f2018-02-27 10:38:17 +0900232 /**
233 * Checks whether the controller has a connection with an OVSDB that resides
234 * inside the given openstack node.
235 *
236 * @param osNode openstack node
237 * @return true if the controller is connected to the OVSDB, false otherwise
238 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900239 private boolean isOvsdbConnected(OpenstackNode osNode) {
240 OvsdbNodeId ovsdb = new OvsdbNodeId(osNode.managementIp(), ovsdbPort);
241 OvsdbClientService client = ovsdbController.getOvsdbClient(ovsdb);
242 return deviceService.isAvailable(osNode.ovsdb()) &&
243 client != null &&
244 client.isConnected();
245 }
246
Jian Li340165f2018-02-27 10:38:17 +0900247 /**
248 * Creates a bridge with a given name on a given openstack node.
249 *
250 * @param osNode openstack node
251 * @param bridgeName bridge name
252 * @param deviceId device identifier
253 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900254 private void createBridge(OpenstackNode osNode, String bridgeName, DeviceId deviceId) {
255 Device device = deviceService.getDevice(osNode.ovsdb());
256 if (device == null || !device.is(BridgeConfig.class)) {
257 log.error("Failed to create integration bridge on {}", osNode.ovsdb());
258 return;
259 }
260
daniel parkb18424c2018-02-05 15:43:43 +0900261 Set<IpAddress> controllerIps = clusterService.getNodes().stream()
Hyunsun Moon0d457362017-06-27 17:19:41 +0900262 .map(ControllerNode::ip)
263 .collect(Collectors.toSet());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900264
265 List<ControllerInfo> controllers = controllerIps.stream()
266 .map(ip -> new ControllerInfo(ip, DEFAULT_OFPORT, DEFAULT_OF_PROTO))
267 .collect(Collectors.toList());
268
269 String dpid = deviceId.toString().substring(DPID_BEGIN);
daniel parkb18424c2018-02-05 15:43:43 +0900270
Hyunsun Moon0d457362017-06-27 17:19:41 +0900271 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
272 .name(bridgeName)
273 .failMode(BridgeDescription.FailMode.SECURE)
274 .datapathId(dpid)
275 .disableInBand()
276 .controllers(controllers)
277 .build();
278
279 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
280 bridgeConfig.addBridge(bridgeDesc);
281 }
282
Jian Li340165f2018-02-27 10:38:17 +0900283 /**
284 * Adds a network interface (aka port) into a given bridge of openstack node.
285 *
286 * @param osNode openstack node
287 * @param bridgeName bridge name
288 * @param intfName interface name
289 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900290 private void addSystemInterface(OpenstackNode osNode, String bridgeName, String intfName) {
291 Device device = deviceService.getDevice(osNode.ovsdb());
292 if (device == null || !device.is(BridgeConfig.class)) {
293 return;
294 }
295 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
296 bridgeConfig.addPort(BridgeName.bridgeName(bridgeName), intfName);
297 }
298
Jian Li340165f2018-02-27 10:38:17 +0900299 /**
300 * Creates a tunnel interface in a given openstack node.
301 *
302 * @param osNode openstack node
303 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900304 private void createTunnelInterface(OpenstackNode osNode) {
305 if (isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
306 return;
307 }
308
309 Device device = deviceService.getDevice(osNode.ovsdb());
310 if (device == null || !device.is(InterfaceConfig.class)) {
311 log.error("Failed to create tunnel interface on {}", osNode.ovsdb());
312 return;
313 }
314
315 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
316 .deviceId(INTEGRATION_BRIDGE)
317 .ifaceName(DEFAULT_TUNNEL)
318 .type(TunnelDescription.Type.VXLAN)
319 .remote(TunnelEndPoints.flowTunnelEndpoint())
320 .key(TunnelKeys.flowTunnelKey())
321 .build();
322
323 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
324 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
325 }
326
Hyunsun Moon0d457362017-06-27 17:19:41 +0900327 private ExtensionTreatment tunnelDstTreatment(DeviceId deviceId, IpAddress remoteIp) {
328 Device device = deviceService.getDevice(deviceId);
329 if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
330 log.error("The extension treatment is not supported");
331 return null;
332 }
333
Ray Milkey74e59132018-01-17 15:24:52 -0800334 if (device == null) {
335 return null;
336 }
337
Hyunsun Moon0d457362017-06-27 17:19:41 +0900338 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
339 ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
340 try {
341 treatment.setPropertyValue("tunnelDst", remoteIp.getIp4Address());
342 return treatment;
343 } catch (ExtensionPropertyException e) {
344 log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
345 return null;
346 }
347 }
348
Jian Li340165f2018-02-27 10:38:17 +0900349 /**
350 * Checks whether a given network interface in a given openstack node is enabled or not.
351 *
352 * @param osNode openstack node
353 * @param intf network interface name
354 * @return true if the given interface is enabled, false otherwise
355 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900356 private boolean isIntfEnabled(OpenstackNode osNode, String intf) {
Jian Li5afbea42018-02-28 10:37:03 +0900357 return deviceService.isAvailable(osNode.intgBridge()) &&
358 deviceService.getPorts(osNode.intgBridge()).stream()
359 .anyMatch(port -> Objects.equals(
360 port.annotations().value(PORT_NAME), intf) &&
361 port.isEnabled());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900362 }
363
Jian Li340165f2018-02-27 10:38:17 +0900364 /**
365 * Checks whether all requirements for this state are fulfilled or not.
366 *
367 * @param osNode openstack node
368 * @return true if all requirements are fulfilled, false otherwise
369 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900370 private boolean isCurrentStateDone(OpenstackNode osNode) {
371 switch (osNode.state()) {
372 case INIT:
Jian Li5afbea42018-02-28 10:37:03 +0900373 return deviceService.isAvailable(osNode.intgBridge());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900374 case DEVICE_CREATED:
375 if (osNode.dataIp() != null &&
376 !isIntfEnabled(osNode, DEFAULT_TUNNEL)) {
377 return false;
378 }
379 if (osNode.vlanIntf() != null &&
380 !isIntfEnabled(osNode, osNode.vlanIntf())) {
381 return false;
382 }
daniel parkb18424c2018-02-05 15:43:43 +0900383 if (osNode.type() == GATEWAY &&
384 !isIntfEnabled(osNode, osNode.uplinkPort())) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900385 return false;
386 }
387 return true;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900388 case COMPLETE:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900389 case INCOMPLETE:
390 // always return false
391 // run init CLI to re-trigger node bootstrap
392 return false;
393 default:
394 return true;
395 }
396 }
397
Jian Li340165f2018-02-27 10:38:17 +0900398 /**
399 * Configures the openstack node with new state.
400 *
401 * @param osNode openstack node
402 * @param newState a new state
403 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900404 private void setState(OpenstackNode osNode, NodeState newState) {
405 if (osNode.state() == newState) {
406 return;
407 }
408 OpenstackNode updated = osNode.updateState(newState);
409 osNodeAdminService.updateNode(updated);
410 log.info("Changed {} state: {}", osNode.hostname(), newState);
411 }
412
Jian Li340165f2018-02-27 10:38:17 +0900413 /**
414 * Bootstraps a new openstack node.
415 *
416 * @param osNode openstack node
417 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900418 private void bootstrapNode(OpenstackNode osNode) {
419 if (isCurrentStateDone(osNode)) {
420 setState(osNode, osNode.state().nextState());
421 } else {
422 log.trace("Processing {} state for {}", osNode.state(), osNode.hostname());
423 osNode.state().process(this, osNode);
424 }
425 }
426
Jian Li340165f2018-02-27 10:38:17 +0900427 /**
428 * An internal OVSDB listener. This listener is used for listening the
429 * network facing events from OVSDB device. If a new OVSDB device is detected,
430 * ONOS tries to bootstrap the openstack node.
431 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900432 private class InternalOvsdbListener implements DeviceListener {
433
434 @Override
435 public boolean isRelevant(DeviceEvent event) {
436 NodeId leader = leadershipService.getLeader(appId.name());
437 return Objects.equals(localNode, leader) &&
438 event.subject().type() == Device.Type.CONTROLLER &&
439 osNodeService.node(event.subject().id()) != null;
440 }
441
442 @Override
443 public void event(DeviceEvent event) {
444 Device device = event.subject();
445 OpenstackNode osNode = osNodeService.node(device.id());
446
447 switch (event.type()) {
448 case DEVICE_AVAILABILITY_CHANGED:
449 case DEVICE_ADDED:
450 eventExecutor.execute(() -> {
451 if (deviceService.isAvailable(device.id())) {
452 log.debug("OVSDB {} detected", device.id());
453 bootstrapNode(osNode);
454 } else if (osNode.state() == COMPLETE) {
455 log.debug("Removing OVSDB {}", device.id());
456 deviceAdminService.removeDevice(device.id());
457 }
458 });
459 break;
460 case PORT_ADDED:
461 case PORT_REMOVED:
462 case DEVICE_REMOVED:
463 default:
464 // do nothing
465 break;
466 }
467 }
468 }
469
Jian Li340165f2018-02-27 10:38:17 +0900470 /**
471 * An internal integration bridge listener. This listener is used for
472 * listening the events from integration bridge. To listen the events from
473 * other types of bridge such as provider bridge or tunnel bridge, we need
474 * to augment OpenstackNodeService.node() method.
475 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900476 private class InternalBridgeListener implements DeviceListener {
477
478 @Override
479 public boolean isRelevant(DeviceEvent event) {
480 NodeId leader = leadershipService.getLeader(appId.name());
481 return Objects.equals(localNode, leader) &&
482 event.subject().type() == Device.Type.SWITCH &&
483 osNodeService.node(event.subject().id()) != null;
484 }
485
486 @Override
487 public void event(DeviceEvent event) {
488 Device device = event.subject();
489 OpenstackNode osNode = osNodeService.node(device.id());
490
491 switch (event.type()) {
492 case DEVICE_AVAILABILITY_CHANGED:
493 case DEVICE_ADDED:
494 eventExecutor.execute(() -> {
495 if (deviceService.isAvailable(device.id())) {
496 log.debug("Integration bridge created on {}", osNode.hostname());
497 bootstrapNode(osNode);
498 } else if (osNode.state() == COMPLETE) {
499 log.warn("Device {} disconnected", device.id());
500 setState(osNode, INCOMPLETE);
501 }
502 });
503 break;
504 case PORT_ADDED:
505 eventExecutor.execute(() -> {
506 Port port = event.port();
507 String portName = port.annotations().value(PORT_NAME);
508 if (osNode.state() == DEVICE_CREATED && (
509 Objects.equals(portName, DEFAULT_TUNNEL) ||
510 Objects.equals(portName, osNode.vlanIntf()) ||
daniel parkb18424c2018-02-05 15:43:43 +0900511 Objects.equals(portName, osNode.uplinkPort()))) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900512 log.debug("Interface {} added to {}", portName, event.subject().id());
513 bootstrapNode(osNode);
514 }
515 });
516 break;
517 case PORT_REMOVED:
518 eventExecutor.execute(() -> {
519 Port port = event.port();
520 String portName = port.annotations().value(PORT_NAME);
521 if (osNode.state() == COMPLETE && (
522 Objects.equals(portName, DEFAULT_TUNNEL) ||
523 Objects.equals(portName, osNode.vlanIntf()) ||
daniel parkb18424c2018-02-05 15:43:43 +0900524 Objects.equals(portName, osNode.uplinkPort()))) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900525 log.warn("Interface {} removed from {}", portName, event.subject().id());
526 setState(osNode, INCOMPLETE);
527 }
528 });
529 break;
530 case PORT_UPDATED:
531 case DEVICE_REMOVED:
532 default:
533 // do nothing
534 break;
535 }
536 }
537 }
538
Jian Li340165f2018-02-27 10:38:17 +0900539 /**
540 * An internal openstack node listener.
541 * The notification is triggered by OpenstackNodeStore.
542 */
Hyunsun Moon0d457362017-06-27 17:19:41 +0900543 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
544
545 @Override
546 public boolean isRelevant(OpenstackNodeEvent event) {
547 NodeId leader = leadershipService.getLeader(appId.name());
548 return Objects.equals(localNode, leader);
549 }
550
551 @Override
552 public void event(OpenstackNodeEvent event) {
553 switch (event.type()) {
554 case OPENSTACK_NODE_CREATED:
555 case OPENSTACK_NODE_UPDATED:
Jian Li5afbea42018-02-28 10:37:03 +0900556 eventExecutor.execute(() -> bootstrapNode(event.subject()));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900557 break;
558 case OPENSTACK_NODE_COMPLETE:
559 break;
560 case OPENSTACK_NODE_REMOVED:
561 break;
562 default:
563 break;
564 }
565 }
566 }
567}