blob: 1926f03aeed11c2c23ba8f22cd0ea7e645e5575f [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 Moonfb417942016-06-23 14:48:20 -0700434 .filter(port -> portName(port).startsWith(VPORT_PREFIX) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700435 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700436 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700437
Hyunsun Moon81a13562016-08-04 13:48:08 -0700438 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700439 hostService.getHosts().forEach(host -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700440 if (deviceService.getPort(
441 host.location().deviceId(),
442 host.location().port()) == null) {
443 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700444 }
445 });
446
447 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800448 }
449
450 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800451 * Sets a new state for a given cordvtn node.
452 *
453 * @param node cordvtn node
454 * @param newState new node state
455 */
456 private void setNodeState(CordVtnNode node, NodeState newState) {
457 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800458 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800459 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800460 }
461
462 /**
463 * Checks current state of a given cordvtn node and returns it.
464 *
465 * @param node cordvtn node
466 * @return node state
467 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800468 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800469 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700470 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800471 return NodeState.INIT;
472 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700473 for (String iface : node.systemIfaces()) {
474 if (!isIfaceCreated(node, iface)) {
475 return NodeState.BRIDGE_CREATED;
476 }
477 }
478 if (!isIpAddressSet(node)) {
479 return NodeState.PORTS_ADDED;
480 }
481 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800482 }
483
484 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800485 * Returns connection state of OVSDB server for a given node.
486 *
487 * @param node cordvtn node
488 * @return true if it is connected, false otherwise
489 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800490 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800491 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800492 OvsdbClientService ovsdbClient = getOvsdbClient(node);
493 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700494 ovsdbClient != null &&
495 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800496 }
497
498 /**
499 * Connects to OVSDB server for a given node.
500 *
501 * @param node cordvtn node
502 */
503 private void connectOvsdb(CordVtnNode node) {
504 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700505 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800506 }
507
508 /**
509 * Returns OVSDB client for a given node.
510 *
511 * @param node cordvtn node
Hyunsun Moon81a13562016-08-04 13:48:08 -0700512 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800513 */
514 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
515 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700516 OvsdbNodeId ovsdb = new OvsdbNodeId(
517 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
518 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800519 }
520
Hyunsun Mooncb799442016-01-15 20:03:18 -0800521 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700522 Device device = deviceService.getDevice(node.ovsdbId());
523 if (device == null || !device.is(BridgeConfig.class)) {
524 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800525 return;
526 }
527
Hyunsun Moon81a13562016-08-04 13:48:08 -0700528 List<ControllerInfo> controllers = clusterService.getNodes().stream()
529 .map(controller -> new ControllerInfo(controller.ip(), OF_PORT, "tcp"))
530 .collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800531
Hyunsun Moon81a13562016-08-04 13:48:08 -0700532 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
533 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
534 .name(INTEGRATION_BRIDGE)
535 .failMode(BridgeDescription.FailMode.SECURE)
536 .datapathId(dpid)
537 .disableInBand()
538 .controllers(controllers)
539 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800540
Hyunsun Moon81a13562016-08-04 13:48:08 -0700541 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
542 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800543 }
544
Hyunsun Mooncb799442016-01-15 20:03:18 -0800545 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700546 Device device = deviceService.getDevice(node.ovsdbId());
547 if (device == null || !device.is(InterfaceConfig.class)) {
548 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800549 return;
550 }
551
Hyunsun Moon81a13562016-08-04 13:48:08 -0700552 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
553 .deviceId(INTEGRATION_BRIDGE)
554 .ifaceName(DEFAULT_TUNNEL)
555 .type(VXLAN)
556 .remote(TunnelEndPoints.flowTunnelEndpoint())
557 .key(TunnelKeys.flowTunnelKey())
558 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800559
Hyunsun Moon81a13562016-08-04 13:48:08 -0700560 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
561 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800562 }
563
Hyunsun Moon81a13562016-08-04 13:48:08 -0700564 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700565 Session session = connect(node.sshInfo());
Hyunsun Moon81a13562016-08-04 13:48:08 -0700566 if (session == null || !isInterfaceUp(session, ifaceName)) {
567 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
568 disconnect(session);
569 return;
570 } else {
571 disconnect(session);
572 }
573
574 Device device = deviceService.getDevice(node.ovsdbId());
575 if (!device.is(BridgeConfig.class)) {
576 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700577 return;
578 }
579
Hyunsun Moon81a13562016-08-04 13:48:08 -0700580 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
581 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800582 }
583
584 /**
585 * Flushes IP address from data plane interface and adds data plane IP address
586 * to integration bridge.
587 *
588 * @param node cordvtn node
589 */
590 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700591 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800592 if (session == null) {
593 log.debug("Failed to SSH to {}", node.hostname());
594 return;
595 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700596 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700597 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700598 .filter(ip -> !ip.equals(node.dataIp().ip()))
599 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700600
Hyunsun Moon81a13562016-08-04 13:48:08 -0700601 boolean result = flushIp(session, node.dataIface()) &&
602 setInterfaceUp(session, node.dataIface()) &&
603 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
604 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
605 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800606
Hyunsun Moon479b7752016-05-06 20:13:28 -0700607 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800608 if (result) {
609 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800610 }
611 }
612
Hyunsun Moon81a13562016-08-04 13:48:08 -0700613 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
614 return deviceService.getDevice(node.integrationBridgeId()) != null &&
615 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800616 }
617
Hyunsun Moon81a13562016-08-04 13:48:08 -0700618 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
619 if (Strings.isNullOrEmpty(ifaceName)) {
620 return false;
621 }
622 return deviceService.getPorts(node.integrationBridgeId()).stream()
623 .filter(p -> portName(p).contains(ifaceName) &&
624 p.isEnabled())
625 .findAny()
626 .isPresent();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800627 }
628
629 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800630 * Checks if the IP addresses are correctly set.
631 *
632 * @param node cordvtn node
633 * @return true if the IP is set, false otherwise
634 */
635 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700636 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800637 if (session == null) {
638 log.debug("Failed to SSH to {}", node.hostname());
639 return false;
640 }
641
Hyunsun Moon81a13562016-08-04 13:48:08 -0700642 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
643 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
644 isInterfaceUp(session, node.dataIface()) &&
645 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800646 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700647 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800648
Hyunsun Moon479b7752016-05-06 20:13:28 -0700649 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800650 return result;
651 }
652
653 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800654 * Returns connect point of a given port.
655 *
656 * @param port port
657 * @return connect point
658 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700659 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800660 return new ConnectPoint(port.element().id(), port.number());
661 }
662
663 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700664 * Returns cordvtn node associated with a given OVSDB device.
665 *
666 * @param ovsdbId OVSDB device id
667 * @return cordvtn node, null if it fails to find the node
668 */
669 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
670 return getNodes().stream()
671 .filter(node -> node.ovsdbId().equals(ovsdbId))
672 .findFirst().orElse(null);
673 }
674
675 /**
676 * Returns cordvtn node associated with a given integration bridge.
677 *
678 * @param bridgeId device id of integration bridge
679 * @return cordvtn node, null if it fails to find the node
680 */
681 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
682 return getNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700683 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700684 .findFirst().orElse(null);
685 }
686
687 /**
688 * Returns port name.
689 *
690 * @param port port
691 * @return port name
692 */
693 private String portName(Port port) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700694 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700695 }
696
Hyunsun Mooncb799442016-01-15 20:03:18 -0800697 private class OvsdbHandler implements ConnectionHandler<Device> {
698
699 @Override
700 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700701 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800702 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800703 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800704 } else {
705 log.debug("{} is detected on unregistered node, ignore it.", device.id());
706 }
707 }
708
709 @Override
710 public void disconnected(Device device) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700711 log.debug("Device {} is disconnected", device.id());
712 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800713 }
714 }
715
716 private class BridgeHandler implements ConnectionHandler<Device> {
717
718 @Override
719 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700720 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800721 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800722 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800723 } else {
724 log.debug("{} is detected on unregistered node, ignore it.", device.id());
725 }
726 }
727
728 @Override
729 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700730 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800731 if (node != null) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700732 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800733 setNodeState(node, NodeState.INCOMPLETE);
734 }
735 }
736
737 /**
738 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800739 * If the added port is tunnel or data plane interface, proceed to the remaining
740 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800741 *
742 * @param port port
743 */
744 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700745 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
746 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800747
748 if (node == null) {
749 log.debug("{} is added to unregistered node, ignore it.", portName);
750 return;
751 }
752
Hyunsun Moonff55e812016-03-10 12:40:16 -0800753 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800754
Hyunsun Moonfb417942016-06-23 14:48:20 -0700755 if (portName.startsWith(VPORT_PREFIX)) {
756 if (isNodeStateComplete(node)) {
757 instanceService.addInstance(connectPoint(port));
758 } else {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700759 log.warn("VM is detected on incomplete node, ignore it.", portName);
Hyunsun Moonfb417942016-06-23 14:48:20 -0700760 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700761 } else if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800762 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800763 }
764 }
765
766 /**
767 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800768 * If the removed port is tunnel or data plane interface, proceed to the remaining
769 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800770 *
771 * @param port port
772 */
773 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700774 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
775 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800776
777 if (node == null) {
778 return;
779 }
780
Hyunsun Moonff55e812016-03-10 12:40:16 -0800781 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800782
Hyunsun Moonfb417942016-06-23 14:48:20 -0700783 if (portName.startsWith(VPORT_PREFIX)) {
784 if (isNodeStateComplete(node)) {
785 instanceService.removeInstance(connectPoint(port));
786 } else {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700787 log.warn("VM is vanished from incomplete node, ignore it.", portName);
Hyunsun Moonfb417942016-06-23 14:48:20 -0700788 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700789 } else if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800790 setNodeState(node, NodeState.INCOMPLETE);
791 }
792 }
793 }
794
795 private class InternalDeviceListener implements DeviceListener {
796
797 @Override
798 public void event(DeviceEvent event) {
799
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800800 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
801 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800802 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800803 return;
804 }
805
Hyunsun Mooncb799442016-01-15 20:03:18 -0800806 Device device = event.subject();
807 ConnectionHandler<Device> handler =
808 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
809
810 switch (event.type()) {
811 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800812 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800813 break;
814 case PORT_UPDATED:
815 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800816 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800817 }
818 break;
819 case DEVICE_ADDED:
820 case DEVICE_AVAILABILITY_CHANGED:
821 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800822 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800823 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800824 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800825 }
826 break;
827 default:
828 break;
829 }
830 }
831 }
832
833 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800834 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800835 */
836 private void readConfiguration() {
837 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800838 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800839 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800840 return;
841 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800842 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800843 }
844
845 private class InternalConfigListener implements NetworkConfigListener {
846
847 @Override
848 public void event(NetworkConfigEvent event) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800849 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
850 if (!Objects.equals(localNodeId, leaderNodeId)) {
851 // do not allow to proceed without leadership
852 return;
853 }
854
Hyunsun Mooncb799442016-01-15 20:03:18 -0800855 if (!event.configClass().equals(CordVtnConfig.class)) {
856 return;
857 }
858
859 switch (event.type()) {
860 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800861 case CONFIG_UPDATED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800862 eventExecutor.execute(CordVtnNodeManager.this::readConfiguration);
863 break;
864 default:
865 break;
866 }
867 }
868 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800869
870 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
871
872 @Override
873 public void event(MapEvent<String, CordVtnNode> event) {
874 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
875 if (!Objects.equals(localNodeId, leaderNodeId)) {
876 // do not allow to proceed without leadership
877 return;
878 }
879
880 CordVtnNode oldNode;
881 CordVtnNode newNode;
882
883 switch (event.type()) {
884 case UPDATE:
885 oldNode = event.oldValue().value();
886 newNode = event.newValue().value();
887
Hyunsun Moon479b7752016-05-06 20:13:28 -0700888 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800889 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800890 log.debug("New node: {}", newNode);
891 }
Hyunsun Moon479b7752016-05-06 20:13:28 -0700892 // performs init procedure even if the node is not changed
893 // for robustness since it's no harm to run init procedure
894 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -0800895 eventExecutor.execute(() -> initNode(newNode));
896 break;
897 case INSERT:
898 newNode = event.newValue().value();
899 log.info("Added {}", newNode.hostname());
900 eventExecutor.execute(() -> initNode(newNode));
901 break;
902 case REMOVE:
903 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700904 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800905 break;
906 default:
907 break;
908 }
909 }
910 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800911}