blob: 82bb0a9935abed8bf3dc45fd25e3fdea4eb4c012 [file] [log] [blame]
Hyunsun Mooncb799442016-01-15 20:03:18 -08001/*
Brian O'Connor8e57fd52016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Hyunsun Mooncb799442016-01-15 20:03:18 -08003 *
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 */
alshabibb4d31712016-06-01 18:51:03 -070016package org.opencord.cordvtn.impl;
Hyunsun Mooncb799442016-01-15 20:03:18 -080017
Hyunsun Moon81a13562016-08-04 13:48:08 -070018import com.google.common.base.Strings;
Hyunsun Moon126171d2016-02-09 01:55:48 -080019import com.jcraft.jsch.Session;
Hyunsun Mooncb799442016-01-15 20:03:18 -080020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
Hyunsun Moon126171d2016-02-09 01:55:48 -080026import org.onlab.packet.IpAddress;
Hyunsun Mooncb799442016-01-15 20:03:18 -080027import org.onlab.util.KryoNamespace;
28import org.onosproject.cluster.ClusterService;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080029import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070031import org.onosproject.net.AnnotationKeys;
Hyunsun Moon81a13562016-08-04 13:48:08 -070032import org.onosproject.net.behaviour.BridgeDescription;
33import org.onosproject.net.behaviour.DefaultBridgeDescription;
34import org.onosproject.net.behaviour.InterfaceConfig;
35import org.onosproject.net.behaviour.TunnelEndPoints;
36import org.onosproject.net.behaviour.TunnelKeys;
alshabibb4d31712016-06-01 18:51:03 -070037import org.opencord.cordvtn.api.ConnectionHandler;
38import org.opencord.cordvtn.api.CordVtnConfig;
39import org.opencord.cordvtn.api.CordVtnNode;
40import org.opencord.cordvtn.api.CordVtnNodeState;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070041import org.opencord.cordvtn.api.InstanceService;
alshabibb4d31712016-06-01 18:51:03 -070042import org.opencord.cordvtn.api.NetworkAddress;
43import org.opencord.cordvtn.api.SshAccessInfo;
Hyunsun Mooncb799442016-01-15 20:03:18 -080044import org.onosproject.core.ApplicationId;
45import org.onosproject.core.CoreService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080046import org.onosproject.net.ConnectPoint;
Hyunsun Mooncb799442016-01-15 20:03:18 -080047import org.onosproject.net.Device;
48import org.onosproject.net.DeviceId;
Hyunsun Mooncb799442016-01-15 20:03:18 -080049import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070050import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080051import org.onosproject.net.behaviour.BridgeConfig;
52import org.onosproject.net.behaviour.BridgeName;
53import org.onosproject.net.behaviour.ControllerInfo;
54import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080055import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080056import org.onosproject.net.config.NetworkConfigEvent;
57import org.onosproject.net.config.NetworkConfigListener;
58import org.onosproject.net.config.NetworkConfigRegistry;
59import org.onosproject.net.config.NetworkConfigService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080060import org.onosproject.net.device.DeviceAdminService;
61import org.onosproject.net.device.DeviceEvent;
62import org.onosproject.net.device.DeviceListener;
63import org.onosproject.net.device.DeviceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080064import org.onosproject.net.host.HostService;
65import org.onosproject.ovsdb.controller.OvsdbClientService;
66import org.onosproject.ovsdb.controller.OvsdbController;
67import org.onosproject.ovsdb.controller.OvsdbNodeId;
68import org.onosproject.store.serializers.KryoNamespaces;
69import org.onosproject.store.service.ConsistentMap;
Hyunsun Moonff55e812016-03-10 12:40:16 -080070import org.onosproject.store.service.MapEvent;
71import org.onosproject.store.service.MapEventListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080072import org.onosproject.store.service.Serializer;
73import org.onosproject.store.service.StorageService;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080074import org.onosproject.store.service.Versioned;
Hyunsun Mooncb799442016-01-15 20:03:18 -080075import org.slf4j.Logger;
76
Hyunsun Mooncb799442016-01-15 20:03:18 -080077import java.util.List;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080078import java.util.Objects;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070079import java.util.Optional;
Hyunsun Moon126171d2016-02-09 01:55:48 -080080import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080081import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080082import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080083
84import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon537018f2016-07-27 18:51:00 -070085import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Mooncb799442016-01-15 20:03:18 -080086import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon81a13562016-08-04 13:48:08 -070087import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Mooncb799442016-01-15 20:03:18 -080088import static org.onosproject.net.Device.Type.SWITCH;
89import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070090import static org.opencord.cordvtn.api.Constants.*;
alshabibb4d31712016-06-01 18:51:03 -070091import static org.opencord.cordvtn.impl.RemoteIpCommandUtil.*;
Hyunsun Mooncb799442016-01-15 20:03:18 -080092import static org.slf4j.LoggerFactory.getLogger;
93
94/**
95 * Reads node information from the network config file and handles the config
96 * update events.
97 * Only a leader controller performs the node addition or deletion.
98 */
99@Component(immediate = true)
100@Service(value = CordVtnNodeManager.class)
101public class CordVtnNodeManager {
102
103 protected final Logger log = getLogger(getClass());
104
105 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
106 .register(KryoNamespaces.API)
107 .register(CordVtnNode.class)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800108 .register(NodeState.class)
109 .register(SshAccessInfo.class)
110 .register(NetworkAddress.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800111
Hyunsun Mooncb799442016-01-15 20:03:18 -0800112 private static final int DPID_BEGIN = 3;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected NetworkConfigRegistry configRegistry;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected NetworkConfigService configService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected StorageService storageService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected DeviceAdminService adminService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700130 protected OvsdbController ovsdbController;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected ClusterService clusterService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800136 protected DeviceService deviceService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected HostService hostService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800142 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700145 protected InstanceService instanceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700148 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800149
Hyunsun Mooncb799442016-01-15 20:03:18 -0800150 private final ExecutorService eventExecutor =
Hyunsun Moon537018f2016-07-27 18:51:00 -0700151 newSingleThreadExecutor(groupedThreads("onos/cordvtn-node", "event-handler", log));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800152
153 private final NetworkConfigListener configListener = new InternalConfigListener();
154 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800155 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800156
157 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
158 private final BridgeHandler bridgeHandler = new BridgeHandler();
159
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800160 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800161 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800162 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800163
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800164 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800165
166 INIT {
167 @Override
168 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700169 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800170 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800171 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700172 return;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800173 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700174 nodeManager.createIntegrationBridge(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800175 }
176 },
177 BRIDGE_CREATED {
178 @Override
179 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700180 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800181 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800182 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700183 return;
184 }
185
186 nodeManager.createTunnelInterface(node);
187 nodeManager.addSystemInterface(node, node.dataIface());
188 if (node.hostMgmtIface().isPresent()) {
189 nodeManager.addSystemInterface(node, node.hostMgmtIface().get());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800190 }
191 }
192 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800193 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800194 @Override
195 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800196 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800197 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800198 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800199 COMPLETE {
200 @Override
201 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
202 nodeManager.postInit(node);
203 }
204 },
205 INCOMPLETE {
206 @Override
207 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
208 }
209 };
210
Hyunsun Mooncb799442016-01-15 20:03:18 -0800211 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
212 }
213
214 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700215 protected void activate() {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700216 appId = coreService.getAppId(CORDVTN_APP_ID);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700217
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800218 localNodeId = clusterService.getLocalNode().id();
219 leadershipService.runForLeadership(appId.name());
220
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800221 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800222 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
223 .withName("cordvtn-nodestore")
224 .withApplicationId(appId)
225 .build();
226
Hyunsun Moonff55e812016-03-10 12:40:16 -0800227 nodeStore.addListener(nodeStoreListener);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800228 deviceService.addListener(deviceListener);
229 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700230
231 log.info("Started");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800232 }
233
234 @Deactivate
235 protected void deactivate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800236 configService.removeListener(configListener);
237 deviceService.removeListener(deviceListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800238 nodeStore.removeListener(nodeStoreListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800239
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800240 leadershipService.withdraw(appId.name());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800241 eventExecutor.shutdown();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700242
243 log.info("Stopped");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800244 }
245
246 /**
Hyunsun Moonff55e812016-03-10 12:40:16 -0800247 * Adds or updates a new node to the service.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800248 *
249 * @param node cordvtn node
250 */
Hyunsun Moonff55e812016-03-10 12:40:16 -0800251 public void addOrUpdateNode(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800252 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800253 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800254 }
255
256 /**
257 * Deletes a node from the service.
258 *
259 * @param node cordvtn node
260 */
261 public void deleteNode(CordVtnNode node) {
262 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700263 OvsdbClientService ovsdbClient = getOvsdbClient(node);
264 if (ovsdbClient != null && ovsdbClient.isConnected()) {
265 ovsdbClient.disconnect();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800266 }
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800267 nodeStore.remove(node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800268 }
269
270 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800271 * Returns node initialization state.
272 *
273 * @param node cordvtn node
274 * @return true if initial node setup is completed, otherwise false
275 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800276 public boolean isNodeInitComplete(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800277 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700278 return getNodeState(node).equals(NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800279 }
280
281 /**
282 * Returns the number of the nodes known to the service.
283 *
284 * @return number of nodes
285 */
286 public int getNodeCount() {
287 return nodeStore.size();
288 }
289
290 /**
291 * Returns all nodes known to the service.
292 *
293 * @return list of nodes
294 */
295 public List<CordVtnNode> getNodes() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700296 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800297 }
298
299 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700300 * Returns all nodes in complete state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800301 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700302 * @return set of nodes
Hyunsun Mooncb799442016-01-15 20:03:18 -0800303 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700304 public Set<CordVtnNode> completeNodes() {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700305 return getNodes().stream().filter(this::isNodeStateComplete)
306 .collect(Collectors.toSet());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800307 }
308
309 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700310 * Returns physical data plane port number of a given device.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800311 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700312 * @param deviceId integration bridge device id
313 * @return port number; null otherwise
Hyunsun Mooncb799442016-01-15 20:03:18 -0800314 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700315 public PortNumber dataPort(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700316 CordVtnNode node = nodeByBridgeId(deviceId);
317 if (node == null) {
318 log.warn("Failed to get node for {}", deviceId);
319 return null;
320 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700321
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700322 Optional<PortNumber> port = getPortNumber(deviceId, node.dataIface());
323 return port.isPresent() ? port.get() : null;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700324 }
325
326 /**
327 * Returns physical data plane IP address of a given device.
328 *
329 * @param deviceId integration bridge device id
330 * @return ip address; null otherwise
331 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700332 public IpAddress dataIp(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700333 CordVtnNode node = nodeByBridgeId(deviceId);
334 if (node == null) {
335 log.warn("Failed to get node for {}", deviceId);
336 return null;
337 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700338 return node.dataIp().ip();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700339 }
340
341 /**
342 * Returns tunnel port number of a given device.
343 *
344 * @param deviceId integration bridge device id
345 * @return port number
346 */
347 public PortNumber tunnelPort(DeviceId deviceId) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700348 Optional<PortNumber> port = getPortNumber(deviceId, DEFAULT_TUNNEL);
349 return port.isPresent() ? port.get() : null;
350 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700351
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700352 /**
353 * Returns host management interface port number if exists.
354 *
355 * @param deviceId integration bridge device id
356 * @return port number; null if it does not exist
357 */
358 public PortNumber hostManagementPort(DeviceId deviceId) {
359 CordVtnNode node = nodeByBridgeId(deviceId);
360 if (node == null) {
361 log.warn("Failed to get node for {}", deviceId);
362 return null;
363 }
364
365 if (node.hostMgmtIface().isPresent()) {
366 Optional<PortNumber> port = getPortNumber(deviceId, node.hostMgmtIface().get());
367 return port.isPresent() ? port.get() : null;
368 } else {
369 return null;
370 }
371 }
372
373 private Optional<PortNumber> getPortNumber(DeviceId deviceId, String portName) {
374 PortNumber port = deviceService.getPorts(deviceId).stream()
375 .filter(p -> p.annotations().value(AnnotationKeys.PORT_NAME).equals(portName) &&
376 p.isEnabled())
377 .map(Port::number)
378 .findAny()
379 .orElse(null);
380 return Optional.ofNullable(port);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700381 }
382
383 /**
384 * Returns if current node state saved in nodeStore is COMPLETE or not.
385 *
386 * @param node cordvtn node
387 * @return true if it's complete state, otherwise false
388 */
389 private boolean isNodeStateComplete(CordVtnNode node) {
390 checkNotNull(node);
391
392 // the state saved in nodeStore can be wrong if IP address settings are changed
393 // after the node init has been completed since there's no way to detect it
394 // getNodeState and checkNodeInitState always return correct answer but can be slow
395 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
396 CordVtnNodeState state = versionedNode.value().state();
397 return state != null && state.equals(NodeState.COMPLETE);
398 }
399
400 /**
401 * Initiates node to serve virtual tenant network.
402 *
403 * @param node cordvtn node
404 */
405 private void initNode(CordVtnNode node) {
406 checkNotNull(node);
407
408 NodeState state = (NodeState) node.state();
409 log.debug("Processing node: {} state: {}", node.hostname(), state);
410
411 state.process(this, node);
412 }
413
414 /**
415 * Performs tasks after node initialization.
416 * It disconnects unnecessary OVSDB connection and installs initial flow
417 * rules on the device.
418 *
419 * @param node cordvtn node
420 */
421 private void postInit(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700422 checkNotNull(node);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700423
Hyunsun Moon81a13562016-08-04 13:48:08 -0700424 // disconnect OVSDB session once the node bootstrap is done
425 OvsdbClientService ovsdbClient = getOvsdbClient(node);
426 if (ovsdbClient != null && ovsdbClient.isConnected()) {
427 ovsdbClient.disconnect();
428 }
429
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700430 pipeline.initPipeline(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700431
432 // adds existing instances to the host list
433 deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700434 .filter(port -> !node.systemIfaces().contains(portName(port)) &&
435 !port.number().equals(PortNumber.LOCAL) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700436 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700437 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700438
Hyunsun Moon81a13562016-08-04 13:48:08 -0700439 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700440 hostService.getHosts().forEach(host -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700441 if (deviceService.getPort(
442 host.location().deviceId(),
443 host.location().port()) == null) {
444 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700445 }
446 });
447
448 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800449 }
450
451 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800452 * Sets a new state for a given cordvtn node.
453 *
454 * @param node cordvtn node
455 * @param newState new node state
456 */
457 private void setNodeState(CordVtnNode node, NodeState newState) {
458 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800459 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800460 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800461 }
462
463 /**
464 * Checks current state of a given cordvtn node and returns it.
465 *
466 * @param node cordvtn node
467 * @return node state
468 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800469 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800470 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700471 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800472 return NodeState.INIT;
473 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700474 for (String iface : node.systemIfaces()) {
475 if (!isIfaceCreated(node, iface)) {
476 return NodeState.BRIDGE_CREATED;
477 }
478 }
479 if (!isIpAddressSet(node)) {
480 return NodeState.PORTS_ADDED;
481 }
482 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800483 }
484
485 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800486 * Returns connection state of OVSDB server for a given node.
487 *
488 * @param node cordvtn node
489 * @return true if it is connected, false otherwise
490 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800491 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800492 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800493 OvsdbClientService ovsdbClient = getOvsdbClient(node);
494 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700495 ovsdbClient != null &&
496 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800497 }
498
499 /**
500 * Connects to OVSDB server for a given node.
501 *
502 * @param node cordvtn node
503 */
504 private void connectOvsdb(CordVtnNode node) {
505 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700506 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800507 }
508
509 /**
510 * Returns OVSDB client for a given node.
511 *
512 * @param node cordvtn node
Hyunsun Moon81a13562016-08-04 13:48:08 -0700513 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800514 */
515 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
516 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700517 OvsdbNodeId ovsdb = new OvsdbNodeId(
518 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
519 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800520 }
521
Hyunsun Mooncb799442016-01-15 20:03:18 -0800522 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700523 Device device = deviceService.getDevice(node.ovsdbId());
524 if (device == null || !device.is(BridgeConfig.class)) {
525 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800526 return;
527 }
528
Hyunsun Moon81a13562016-08-04 13:48:08 -0700529 List<ControllerInfo> controllers = clusterService.getNodes().stream()
530 .map(controller -> new ControllerInfo(controller.ip(), OF_PORT, "tcp"))
531 .collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800532
Hyunsun Moon81a13562016-08-04 13:48:08 -0700533 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
534 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
535 .name(INTEGRATION_BRIDGE)
536 .failMode(BridgeDescription.FailMode.SECURE)
537 .datapathId(dpid)
538 .disableInBand()
539 .controllers(controllers)
540 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800541
Hyunsun Moon81a13562016-08-04 13:48:08 -0700542 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
543 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800544 }
545
Hyunsun Mooncb799442016-01-15 20:03:18 -0800546 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700547 Device device = deviceService.getDevice(node.ovsdbId());
548 if (device == null || !device.is(InterfaceConfig.class)) {
549 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800550 return;
551 }
552
Hyunsun Moon81a13562016-08-04 13:48:08 -0700553 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
554 .deviceId(INTEGRATION_BRIDGE)
555 .ifaceName(DEFAULT_TUNNEL)
556 .type(VXLAN)
557 .remote(TunnelEndPoints.flowTunnelEndpoint())
558 .key(TunnelKeys.flowTunnelKey())
559 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800560
Hyunsun Moon81a13562016-08-04 13:48:08 -0700561 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
562 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800563 }
564
Hyunsun Moon81a13562016-08-04 13:48:08 -0700565 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700566 Session session = connect(node.sshInfo());
Hyunsun Moon81a13562016-08-04 13:48:08 -0700567 if (session == null || !isInterfaceUp(session, ifaceName)) {
568 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
569 disconnect(session);
570 return;
571 } else {
572 disconnect(session);
573 }
574
575 Device device = deviceService.getDevice(node.ovsdbId());
576 if (!device.is(BridgeConfig.class)) {
577 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700578 return;
579 }
580
Hyunsun Moon81a13562016-08-04 13:48:08 -0700581 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
582 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800583 }
584
585 /**
586 * Flushes IP address from data plane interface and adds data plane IP address
587 * to integration bridge.
588 *
589 * @param node cordvtn node
590 */
591 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700592 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800593 if (session == null) {
594 log.debug("Failed to SSH to {}", node.hostname());
595 return;
596 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700597 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700598 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700599 .filter(ip -> !ip.equals(node.dataIp().ip()))
600 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700601
Hyunsun Moon81a13562016-08-04 13:48:08 -0700602 boolean result = flushIp(session, node.dataIface()) &&
603 setInterfaceUp(session, node.dataIface()) &&
604 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
605 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
606 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800607
Hyunsun Moon479b7752016-05-06 20:13:28 -0700608 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800609 if (result) {
610 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800611 }
612 }
613
Hyunsun Moon81a13562016-08-04 13:48:08 -0700614 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
615 return deviceService.getDevice(node.integrationBridgeId()) != null &&
616 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800617 }
618
Hyunsun Moon81a13562016-08-04 13:48:08 -0700619 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
620 if (Strings.isNullOrEmpty(ifaceName)) {
621 return false;
622 }
623 return deviceService.getPorts(node.integrationBridgeId()).stream()
624 .filter(p -> portName(p).contains(ifaceName) &&
625 p.isEnabled())
626 .findAny()
627 .isPresent();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800628 }
629
630 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800631 * Checks if the IP addresses are correctly set.
632 *
633 * @param node cordvtn node
634 * @return true if the IP is set, false otherwise
635 */
636 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700637 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800638 if (session == null) {
639 log.debug("Failed to SSH to {}", node.hostname());
640 return false;
641 }
642
Hyunsun Moon81a13562016-08-04 13:48:08 -0700643 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
644 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
645 isInterfaceUp(session, node.dataIface()) &&
646 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800647 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700648 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800649
Hyunsun Moon479b7752016-05-06 20:13:28 -0700650 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800651 return result;
652 }
653
654 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800655 * Returns connect point of a given port.
656 *
657 * @param port port
658 * @return connect point
659 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700660 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800661 return new ConnectPoint(port.element().id(), port.number());
662 }
663
664 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700665 * Returns cordvtn node associated with a given OVSDB device.
666 *
667 * @param ovsdbId OVSDB device id
668 * @return cordvtn node, null if it fails to find the node
669 */
670 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
671 return getNodes().stream()
672 .filter(node -> node.ovsdbId().equals(ovsdbId))
673 .findFirst().orElse(null);
674 }
675
676 /**
677 * Returns cordvtn node associated with a given integration bridge.
678 *
679 * @param bridgeId device id of integration bridge
680 * @return cordvtn node, null if it fails to find the node
681 */
682 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
683 return getNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700684 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700685 .findFirst().orElse(null);
686 }
687
688 /**
689 * Returns port name.
690 *
691 * @param port port
692 * @return port name
693 */
694 private String portName(Port port) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700695 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700696 }
697
Hyunsun Mooncb799442016-01-15 20:03:18 -0800698 private class OvsdbHandler implements ConnectionHandler<Device> {
699
700 @Override
701 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700702 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800703 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800704 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800705 } else {
706 log.debug("{} is detected on unregistered node, ignore it.", device.id());
707 }
708 }
709
710 @Override
711 public void disconnected(Device device) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700712 log.debug("Device {} is disconnected", device.id());
713 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800714 }
715 }
716
717 private class BridgeHandler implements ConnectionHandler<Device> {
718
719 @Override
720 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700721 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800722 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800723 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800724 } else {
725 log.debug("{} is detected on unregistered node, ignore it.", device.id());
726 }
727 }
728
729 @Override
730 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700731 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800732 if (node != null) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700733 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800734 setNodeState(node, NodeState.INCOMPLETE);
735 }
736 }
737
738 /**
739 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800740 * If the added port is tunnel or data plane interface, proceed to the remaining
741 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800742 *
743 * @param port port
744 */
745 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700746 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
747 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800748
749 if (node == null) {
750 log.debug("{} is added to unregistered node, ignore it.", portName);
751 return;
752 }
753
Hyunsun Moonff55e812016-03-10 12:40:16 -0800754 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800755
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700756 if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800757 setNodeState(node, getNodeState(node));
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700758 } else if (isNodeStateComplete(node)) {
759 instanceService.addInstance(connectPoint(port));
760 } else {
761 log.warn("Instance is detected on incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800762 }
763 }
764
765 /**
766 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800767 * If the removed port is tunnel or data plane interface, proceed to the remaining
768 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800769 *
770 * @param port port
771 */
772 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700773 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
774 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800775
776 if (node == null) {
777 return;
778 }
779
Hyunsun Moonff55e812016-03-10 12:40:16 -0800780 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800781
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700782 if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800783 setNodeState(node, NodeState.INCOMPLETE);
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700784 } else if (isNodeStateComplete(node)) {
785 instanceService.removeInstance(connectPoint(port));
786 } else {
787 log.warn("VM is vanished from incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800788 }
789 }
790 }
791
792 private class InternalDeviceListener implements DeviceListener {
793
794 @Override
795 public void event(DeviceEvent event) {
796
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800797 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
798 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800799 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800800 return;
801 }
802
Hyunsun Mooncb799442016-01-15 20:03:18 -0800803 Device device = event.subject();
804 ConnectionHandler<Device> handler =
805 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
806
807 switch (event.type()) {
808 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800809 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800810 break;
811 case PORT_UPDATED:
812 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800813 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800814 }
815 break;
816 case DEVICE_ADDED:
817 case DEVICE_AVAILABILITY_CHANGED:
818 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800819 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800820 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800821 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800822 }
823 break;
824 default:
825 break;
826 }
827 }
828 }
829
830 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800831 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800832 */
833 private void readConfiguration() {
834 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800835 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800836 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800837 return;
838 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800839 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800840 }
841
842 private class InternalConfigListener implements NetworkConfigListener {
843
844 @Override
845 public void event(NetworkConfigEvent event) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800846 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
847 if (!Objects.equals(localNodeId, leaderNodeId)) {
848 // do not allow to proceed without leadership
849 return;
850 }
851
Hyunsun Mooncb799442016-01-15 20:03:18 -0800852 if (!event.configClass().equals(CordVtnConfig.class)) {
853 return;
854 }
855
856 switch (event.type()) {
857 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800858 case CONFIG_UPDATED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800859 eventExecutor.execute(CordVtnNodeManager.this::readConfiguration);
860 break;
861 default:
862 break;
863 }
864 }
865 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800866
867 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
868
869 @Override
870 public void event(MapEvent<String, CordVtnNode> event) {
871 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
872 if (!Objects.equals(localNodeId, leaderNodeId)) {
873 // do not allow to proceed without leadership
874 return;
875 }
876
877 CordVtnNode oldNode;
878 CordVtnNode newNode;
879
880 switch (event.type()) {
881 case UPDATE:
882 oldNode = event.oldValue().value();
883 newNode = event.newValue().value();
884
Hyunsun Moon479b7752016-05-06 20:13:28 -0700885 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800886 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800887 log.debug("New node: {}", newNode);
888 }
Hyunsun Moon479b7752016-05-06 20:13:28 -0700889 // performs init procedure even if the node is not changed
890 // for robustness since it's no harm to run init procedure
891 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -0800892 eventExecutor.execute(() -> initNode(newNode));
893 break;
894 case INSERT:
895 newNode = event.newValue().value();
896 log.info("Added {}", newNode.hostname());
897 eventExecutor.execute(() -> initNode(newNode));
898 break;
899 case REMOVE:
900 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700901 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800902 break;
903 default:
904 break;
905 }
906 }
907 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800908}