blob: 463c5d5af8b662bdcd7076849e5ecb99042c39b3 [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 Moon81a13562016-08-04 13:48:08 -070031import org.onosproject.net.behaviour.BridgeDescription;
32import org.onosproject.net.behaviour.DefaultBridgeDescription;
33import org.onosproject.net.behaviour.InterfaceConfig;
34import org.onosproject.net.behaviour.TunnelEndPoints;
35import org.onosproject.net.behaviour.TunnelKeys;
alshabibb4d31712016-06-01 18:51:03 -070036import org.opencord.cordvtn.api.ConnectionHandler;
37import org.opencord.cordvtn.api.CordVtnConfig;
38import org.opencord.cordvtn.api.CordVtnNode;
39import org.opencord.cordvtn.api.CordVtnNodeState;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070040import org.opencord.cordvtn.api.InstanceService;
alshabibb4d31712016-06-01 18:51:03 -070041import org.opencord.cordvtn.api.NetworkAddress;
42import org.opencord.cordvtn.api.SshAccessInfo;
Hyunsun Mooncb799442016-01-15 20:03:18 -080043import org.onosproject.core.ApplicationId;
44import org.onosproject.core.CoreService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080045import org.onosproject.net.ConnectPoint;
Hyunsun Mooncb799442016-01-15 20:03:18 -080046import org.onosproject.net.Device;
47import org.onosproject.net.DeviceId;
Hyunsun Mooncb799442016-01-15 20:03:18 -080048import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070049import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080050import org.onosproject.net.behaviour.BridgeConfig;
51import org.onosproject.net.behaviour.BridgeName;
52import org.onosproject.net.behaviour.ControllerInfo;
53import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080054import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080055import org.onosproject.net.config.NetworkConfigEvent;
56import org.onosproject.net.config.NetworkConfigListener;
57import org.onosproject.net.config.NetworkConfigRegistry;
58import org.onosproject.net.config.NetworkConfigService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080059import org.onosproject.net.device.DeviceAdminService;
60import org.onosproject.net.device.DeviceEvent;
61import org.onosproject.net.device.DeviceListener;
62import org.onosproject.net.device.DeviceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080063import org.onosproject.net.host.HostService;
64import org.onosproject.ovsdb.controller.OvsdbClientService;
65import org.onosproject.ovsdb.controller.OvsdbController;
66import org.onosproject.ovsdb.controller.OvsdbNodeId;
67import org.onosproject.store.serializers.KryoNamespaces;
68import org.onosproject.store.service.ConsistentMap;
Hyunsun Moonff55e812016-03-10 12:40:16 -080069import org.onosproject.store.service.MapEvent;
70import org.onosproject.store.service.MapEventListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080071import org.onosproject.store.service.Serializer;
72import org.onosproject.store.service.StorageService;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080073import org.onosproject.store.service.Versioned;
Hyunsun Mooncb799442016-01-15 20:03:18 -080074import org.slf4j.Logger;
75
Hyunsun Mooncb799442016-01-15 20:03:18 -080076import java.util.List;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080077import java.util.Objects;
Hyunsun Moon126171d2016-02-09 01:55:48 -080078import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080079import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080080import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080081
82import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon537018f2016-07-27 18:51:00 -070083import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Mooncb799442016-01-15 20:03:18 -080084import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon81a13562016-08-04 13:48:08 -070085import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Mooncb799442016-01-15 20:03:18 -080086import static org.onosproject.net.Device.Type.SWITCH;
87import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070088import static org.opencord.cordvtn.api.Constants.*;
alshabibb4d31712016-06-01 18:51:03 -070089import static org.opencord.cordvtn.impl.RemoteIpCommandUtil.*;
Hyunsun Mooncb799442016-01-15 20:03:18 -080090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
93 * Reads node information from the network config file and handles the config
94 * update events.
95 * Only a leader controller performs the node addition or deletion.
96 */
97@Component(immediate = true)
98@Service(value = CordVtnNodeManager.class)
99public class CordVtnNodeManager {
100
101 protected final Logger log = getLogger(getClass());
102
103 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
104 .register(KryoNamespaces.API)
105 .register(CordVtnNode.class)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800106 .register(NodeState.class)
107 .register(SshAccessInfo.class)
108 .register(NetworkAddress.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800109
Hyunsun Mooncb799442016-01-15 20:03:18 -0800110 private static final int DPID_BEGIN = 3;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected CoreService coreService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected NetworkConfigRegistry configRegistry;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected NetworkConfigService configService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected StorageService storageService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected DeviceAdminService adminService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700128 protected OvsdbController ovsdbController;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected ClusterService clusterService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800134 protected DeviceService deviceService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected HostService hostService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800140 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700143 protected InstanceService instanceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700146 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800147
Hyunsun Mooncb799442016-01-15 20:03:18 -0800148 private final ExecutorService eventExecutor =
Hyunsun Moon537018f2016-07-27 18:51:00 -0700149 newSingleThreadExecutor(groupedThreads("onos/cordvtn-node", "event-handler", log));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800150
151 private final NetworkConfigListener configListener = new InternalConfigListener();
152 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800153 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800154
155 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
156 private final BridgeHandler bridgeHandler = new BridgeHandler();
157
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800158 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800159 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800160 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800161
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800162 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800163
164 INIT {
165 @Override
166 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700167 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800168 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800169 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700170 return;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800171 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700172 nodeManager.createIntegrationBridge(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800173 }
174 },
175 BRIDGE_CREATED {
176 @Override
177 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700178 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800179 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800180 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700181 return;
182 }
183
184 nodeManager.createTunnelInterface(node);
185 nodeManager.addSystemInterface(node, node.dataIface());
186 if (node.hostMgmtIface().isPresent()) {
187 nodeManager.addSystemInterface(node, node.hostMgmtIface().get());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800188 }
189 }
190 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800191 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800192 @Override
193 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800194 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800195 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800196 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800197 COMPLETE {
198 @Override
199 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
200 nodeManager.postInit(node);
201 }
202 },
203 INCOMPLETE {
204 @Override
205 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
206 }
207 };
208
Hyunsun Mooncb799442016-01-15 20:03:18 -0800209 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
210 }
211
212 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700213 protected void activate() {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700214 appId = coreService.getAppId(CORDVTN_APP_ID);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700215
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800216 localNodeId = clusterService.getLocalNode().id();
217 leadershipService.runForLeadership(appId.name());
218
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800219 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800220 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
221 .withName("cordvtn-nodestore")
222 .withApplicationId(appId)
223 .build();
224
Hyunsun Moonff55e812016-03-10 12:40:16 -0800225 nodeStore.addListener(nodeStoreListener);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800226 deviceService.addListener(deviceListener);
227 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700228
229 log.info("Started");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800230 }
231
232 @Deactivate
233 protected void deactivate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800234 configService.removeListener(configListener);
235 deviceService.removeListener(deviceListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800236 nodeStore.removeListener(nodeStoreListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800237
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800238 leadershipService.withdraw(appId.name());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800239 eventExecutor.shutdown();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700240
241 log.info("Stopped");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800242 }
243
244 /**
Hyunsun Moonff55e812016-03-10 12:40:16 -0800245 * Adds or updates a new node to the service.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800246 *
247 * @param node cordvtn node
248 */
Hyunsun Moonff55e812016-03-10 12:40:16 -0800249 public void addOrUpdateNode(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800250 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800251 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800252 }
253
254 /**
255 * Deletes a node from the service.
256 *
257 * @param node cordvtn node
258 */
259 public void deleteNode(CordVtnNode node) {
260 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700261 OvsdbClientService ovsdbClient = getOvsdbClient(node);
262 if (ovsdbClient != null && ovsdbClient.isConnected()) {
263 ovsdbClient.disconnect();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800264 }
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800265 nodeStore.remove(node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800266 }
267
268 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800269 * Returns node initialization state.
270 *
271 * @param node cordvtn node
272 * @return true if initial node setup is completed, otherwise false
273 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800274 public boolean isNodeInitComplete(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800275 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700276 return getNodeState(node).equals(NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800277 }
278
279 /**
280 * Returns the number of the nodes known to the service.
281 *
282 * @return number of nodes
283 */
284 public int getNodeCount() {
285 return nodeStore.size();
286 }
287
288 /**
289 * Returns all nodes known to the service.
290 *
291 * @return list of nodes
292 */
293 public List<CordVtnNode> getNodes() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700294 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800295 }
296
297 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700298 * Returns all nodes in complete state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800299 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700300 * @return set of nodes
Hyunsun Mooncb799442016-01-15 20:03:18 -0800301 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700302 public Set<CordVtnNode> completeNodes() {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700303 return getNodes().stream().filter(this::isNodeStateComplete)
304 .collect(Collectors.toSet());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800305 }
306
307 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700308 * Returns physical data plane port number of a given device.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800309 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700310 * @param deviceId integration bridge device id
311 * @return port number; null otherwise
Hyunsun Mooncb799442016-01-15 20:03:18 -0800312 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700313 public PortNumber dataPort(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700314 CordVtnNode node = nodeByBridgeId(deviceId);
315 if (node == null) {
316 log.warn("Failed to get node for {}", deviceId);
317 return null;
318 }
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700319 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700320 .filter(p -> portName(p).contains(node.dataIface()) &&
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700321 p.isEnabled())
322 .findFirst().orElse(null);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700323
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700324 return port == null ? null : port.number();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700325 }
326
327 /**
328 * Returns physical data plane IP address of a given device.
329 *
330 * @param deviceId integration bridge device id
331 * @return ip address; null otherwise
332 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700333 public IpAddress dataIp(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700334 CordVtnNode node = nodeByBridgeId(deviceId);
335 if (node == null) {
336 log.warn("Failed to get node for {}", deviceId);
337 return null;
338 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700339 return node.dataIp().ip();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700340 }
341
342 /**
343 * Returns tunnel port number of a given device.
344 *
345 * @param deviceId integration bridge device id
346 * @return port number
347 */
348 public PortNumber tunnelPort(DeviceId deviceId) {
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700349 Port port = deviceService.getPorts(deviceId).stream()
350 .filter(p -> portName(p).contains(DEFAULT_TUNNEL))
351 .findFirst().orElse(null);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700352
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700353 return port == null ? null : port.number();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700354 }
355
356 /**
357 * Returns if current node state saved in nodeStore is COMPLETE or not.
358 *
359 * @param node cordvtn node
360 * @return true if it's complete state, otherwise false
361 */
362 private boolean isNodeStateComplete(CordVtnNode node) {
363 checkNotNull(node);
364
365 // the state saved in nodeStore can be wrong if IP address settings are changed
366 // after the node init has been completed since there's no way to detect it
367 // getNodeState and checkNodeInitState always return correct answer but can be slow
368 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
369 CordVtnNodeState state = versionedNode.value().state();
370 return state != null && state.equals(NodeState.COMPLETE);
371 }
372
373 /**
374 * Initiates node to serve virtual tenant network.
375 *
376 * @param node cordvtn node
377 */
378 private void initNode(CordVtnNode node) {
379 checkNotNull(node);
380
381 NodeState state = (NodeState) node.state();
382 log.debug("Processing node: {} state: {}", node.hostname(), state);
383
384 state.process(this, node);
385 }
386
387 /**
388 * Performs tasks after node initialization.
389 * It disconnects unnecessary OVSDB connection and installs initial flow
390 * rules on the device.
391 *
392 * @param node cordvtn node
393 */
394 private void postInit(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700395 checkNotNull(node);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700396
Hyunsun Moon81a13562016-08-04 13:48:08 -0700397 // disconnect OVSDB session once the node bootstrap is done
398 OvsdbClientService ovsdbClient = getOvsdbClient(node);
399 if (ovsdbClient != null && ovsdbClient.isConnected()) {
400 ovsdbClient.disconnect();
401 }
402
403 pipeline.initPipeline(node, dataPort(node.integrationBridgeId()),
404 tunnelPort(node.integrationBridgeId()));
405
406 // adds existing instances to the host list
407 deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moonfb417942016-06-23 14:48:20 -0700408 .filter(port -> portName(port).startsWith(VPORT_PREFIX) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700409 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700410 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700411
Hyunsun Moon81a13562016-08-04 13:48:08 -0700412 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700413 hostService.getHosts().forEach(host -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700414 if (deviceService.getPort(
415 host.location().deviceId(),
416 host.location().port()) == null) {
417 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700418 }
419 });
420
421 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800422 }
423
424 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800425 * Sets a new state for a given cordvtn node.
426 *
427 * @param node cordvtn node
428 * @param newState new node state
429 */
430 private void setNodeState(CordVtnNode node, NodeState newState) {
431 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800432 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800433 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800434 }
435
436 /**
437 * Checks current state of a given cordvtn node and returns it.
438 *
439 * @param node cordvtn node
440 * @return node state
441 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800442 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800443 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700444 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800445 return NodeState.INIT;
446 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700447 for (String iface : node.systemIfaces()) {
448 if (!isIfaceCreated(node, iface)) {
449 return NodeState.BRIDGE_CREATED;
450 }
451 }
452 if (!isIpAddressSet(node)) {
453 return NodeState.PORTS_ADDED;
454 }
455 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800456 }
457
458 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800459 * Returns connection state of OVSDB server for a given node.
460 *
461 * @param node cordvtn node
462 * @return true if it is connected, false otherwise
463 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800464 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800465 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800466 OvsdbClientService ovsdbClient = getOvsdbClient(node);
467 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700468 ovsdbClient != null &&
469 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800470 }
471
472 /**
473 * Connects to OVSDB server for a given node.
474 *
475 * @param node cordvtn node
476 */
477 private void connectOvsdb(CordVtnNode node) {
478 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700479 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800480 }
481
482 /**
483 * Returns OVSDB client for a given node.
484 *
485 * @param node cordvtn node
Hyunsun Moon81a13562016-08-04 13:48:08 -0700486 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800487 */
488 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
489 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700490 OvsdbNodeId ovsdb = new OvsdbNodeId(
491 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
492 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800493 }
494
Hyunsun Mooncb799442016-01-15 20:03:18 -0800495 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700496 Device device = deviceService.getDevice(node.ovsdbId());
497 if (device == null || !device.is(BridgeConfig.class)) {
498 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800499 return;
500 }
501
Hyunsun Moon81a13562016-08-04 13:48:08 -0700502 List<ControllerInfo> controllers = clusterService.getNodes().stream()
503 .map(controller -> new ControllerInfo(controller.ip(), OF_PORT, "tcp"))
504 .collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800505
Hyunsun Moon81a13562016-08-04 13:48:08 -0700506 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
507 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
508 .name(INTEGRATION_BRIDGE)
509 .failMode(BridgeDescription.FailMode.SECURE)
510 .datapathId(dpid)
511 .disableInBand()
512 .controllers(controllers)
513 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800514
Hyunsun Moon81a13562016-08-04 13:48:08 -0700515 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
516 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800517 }
518
Hyunsun Mooncb799442016-01-15 20:03:18 -0800519 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700520 Device device = deviceService.getDevice(node.ovsdbId());
521 if (device == null || !device.is(InterfaceConfig.class)) {
522 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800523 return;
524 }
525
Hyunsun Moon81a13562016-08-04 13:48:08 -0700526 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
527 .deviceId(INTEGRATION_BRIDGE)
528 .ifaceName(DEFAULT_TUNNEL)
529 .type(VXLAN)
530 .remote(TunnelEndPoints.flowTunnelEndpoint())
531 .key(TunnelKeys.flowTunnelKey())
532 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800533
Hyunsun Moon81a13562016-08-04 13:48:08 -0700534 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
535 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800536 }
537
Hyunsun Moon81a13562016-08-04 13:48:08 -0700538 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700539 Session session = connect(node.sshInfo());
Hyunsun Moon81a13562016-08-04 13:48:08 -0700540 if (session == null || !isInterfaceUp(session, ifaceName)) {
541 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
542 disconnect(session);
543 return;
544 } else {
545 disconnect(session);
546 }
547
548 Device device = deviceService.getDevice(node.ovsdbId());
549 if (!device.is(BridgeConfig.class)) {
550 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700551 return;
552 }
553
Hyunsun Moon81a13562016-08-04 13:48:08 -0700554 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
555 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800556 }
557
558 /**
559 * Flushes IP address from data plane interface and adds data plane IP address
560 * to integration bridge.
561 *
562 * @param node cordvtn node
563 */
564 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700565 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800566 if (session == null) {
567 log.debug("Failed to SSH to {}", node.hostname());
568 return;
569 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700570 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700571 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700572 .filter(ip -> !ip.equals(node.dataIp().ip()))
573 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700574
Hyunsun Moon81a13562016-08-04 13:48:08 -0700575 boolean result = flushIp(session, node.dataIface()) &&
576 setInterfaceUp(session, node.dataIface()) &&
577 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
578 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
579 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800580
Hyunsun Moon479b7752016-05-06 20:13:28 -0700581 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800582 if (result) {
583 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800584 }
585 }
586
Hyunsun Moon81a13562016-08-04 13:48:08 -0700587 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
588 return deviceService.getDevice(node.integrationBridgeId()) != null &&
589 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800590 }
591
Hyunsun Moon81a13562016-08-04 13:48:08 -0700592 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
593 if (Strings.isNullOrEmpty(ifaceName)) {
594 return false;
595 }
596 return deviceService.getPorts(node.integrationBridgeId()).stream()
597 .filter(p -> portName(p).contains(ifaceName) &&
598 p.isEnabled())
599 .findAny()
600 .isPresent();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800601 }
602
603 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800604 * Checks if the IP addresses are correctly set.
605 *
606 * @param node cordvtn node
607 * @return true if the IP is set, false otherwise
608 */
609 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700610 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800611 if (session == null) {
612 log.debug("Failed to SSH to {}", node.hostname());
613 return false;
614 }
615
Hyunsun Moon81a13562016-08-04 13:48:08 -0700616 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
617 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
618 isInterfaceUp(session, node.dataIface()) &&
619 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800620 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700621 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800622
Hyunsun Moon479b7752016-05-06 20:13:28 -0700623 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800624 return result;
625 }
626
627 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800628 * Returns connect point of a given port.
629 *
630 * @param port port
631 * @return connect point
632 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700633 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800634 return new ConnectPoint(port.element().id(), port.number());
635 }
636
637 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700638 * Returns cordvtn node associated with a given OVSDB device.
639 *
640 * @param ovsdbId OVSDB device id
641 * @return cordvtn node, null if it fails to find the node
642 */
643 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
644 return getNodes().stream()
645 .filter(node -> node.ovsdbId().equals(ovsdbId))
646 .findFirst().orElse(null);
647 }
648
649 /**
650 * Returns cordvtn node associated with a given integration bridge.
651 *
652 * @param bridgeId device id of integration bridge
653 * @return cordvtn node, null if it fails to find the node
654 */
655 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
656 return getNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700657 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700658 .findFirst().orElse(null);
659 }
660
661 /**
662 * Returns port name.
663 *
664 * @param port port
665 * @return port name
666 */
667 private String portName(Port port) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700668 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700669 }
670
Hyunsun Mooncb799442016-01-15 20:03:18 -0800671 private class OvsdbHandler implements ConnectionHandler<Device> {
672
673 @Override
674 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700675 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800676 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800677 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800678 } else {
679 log.debug("{} is detected on unregistered node, ignore it.", device.id());
680 }
681 }
682
683 @Override
684 public void disconnected(Device device) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700685 log.debug("Device {} is disconnected", device.id());
686 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800687 }
688 }
689
690 private class BridgeHandler implements ConnectionHandler<Device> {
691
692 @Override
693 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700694 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800695 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800696 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800697 } else {
698 log.debug("{} is detected on unregistered node, ignore it.", device.id());
699 }
700 }
701
702 @Override
703 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700704 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800705 if (node != null) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700706 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800707 setNodeState(node, NodeState.INCOMPLETE);
708 }
709 }
710
711 /**
712 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800713 * If the added port is tunnel or data plane interface, proceed to the remaining
714 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800715 *
716 * @param port port
717 */
718 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700719 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
720 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800721
722 if (node == null) {
723 log.debug("{} is added to unregistered node, ignore it.", portName);
724 return;
725 }
726
Hyunsun Moonff55e812016-03-10 12:40:16 -0800727 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800728
Hyunsun Moonfb417942016-06-23 14:48:20 -0700729 if (portName.startsWith(VPORT_PREFIX)) {
730 if (isNodeStateComplete(node)) {
731 instanceService.addInstance(connectPoint(port));
732 } else {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700733 log.warn("VM is detected on incomplete node, ignore it.", portName);
Hyunsun Moonfb417942016-06-23 14:48:20 -0700734 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700735 } else if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800736 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800737 }
738 }
739
740 /**
741 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800742 * If the removed port is tunnel or data plane interface, proceed to the remaining
743 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800744 *
745 * @param port port
746 */
747 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700748 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
749 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800750
751 if (node == null) {
752 return;
753 }
754
Hyunsun Moonff55e812016-03-10 12:40:16 -0800755 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800756
Hyunsun Moonfb417942016-06-23 14:48:20 -0700757 if (portName.startsWith(VPORT_PREFIX)) {
758 if (isNodeStateComplete(node)) {
759 instanceService.removeInstance(connectPoint(port));
760 } else {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700761 log.warn("VM is vanished from incomplete node, ignore it.", portName);
Hyunsun Moonfb417942016-06-23 14:48:20 -0700762 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700763 } else if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800764 setNodeState(node, NodeState.INCOMPLETE);
765 }
766 }
767 }
768
769 private class InternalDeviceListener implements DeviceListener {
770
771 @Override
772 public void event(DeviceEvent event) {
773
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800774 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
775 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800776 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800777 return;
778 }
779
Hyunsun Mooncb799442016-01-15 20:03:18 -0800780 Device device = event.subject();
781 ConnectionHandler<Device> handler =
782 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
783
784 switch (event.type()) {
785 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800786 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800787 break;
788 case PORT_UPDATED:
789 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800790 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800791 }
792 break;
793 case DEVICE_ADDED:
794 case DEVICE_AVAILABILITY_CHANGED:
795 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800796 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800797 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800798 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800799 }
800 break;
801 default:
802 break;
803 }
804 }
805 }
806
807 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800808 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800809 */
810 private void readConfiguration() {
811 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800812 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800813 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800814 return;
815 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800816 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800817 }
818
819 private class InternalConfigListener implements NetworkConfigListener {
820
821 @Override
822 public void event(NetworkConfigEvent event) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800823 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
824 if (!Objects.equals(localNodeId, leaderNodeId)) {
825 // do not allow to proceed without leadership
826 return;
827 }
828
Hyunsun Mooncb799442016-01-15 20:03:18 -0800829 if (!event.configClass().equals(CordVtnConfig.class)) {
830 return;
831 }
832
833 switch (event.type()) {
834 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800835 case CONFIG_UPDATED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800836 eventExecutor.execute(CordVtnNodeManager.this::readConfiguration);
837 break;
838 default:
839 break;
840 }
841 }
842 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800843
844 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
845
846 @Override
847 public void event(MapEvent<String, CordVtnNode> event) {
848 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
849 if (!Objects.equals(localNodeId, leaderNodeId)) {
850 // do not allow to proceed without leadership
851 return;
852 }
853
854 CordVtnNode oldNode;
855 CordVtnNode newNode;
856
857 switch (event.type()) {
858 case UPDATE:
859 oldNode = event.oldValue().value();
860 newNode = event.newValue().value();
861
Hyunsun Moon479b7752016-05-06 20:13:28 -0700862 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800863 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800864 log.debug("New node: {}", newNode);
865 }
Hyunsun Moon479b7752016-05-06 20:13:28 -0700866 // performs init procedure even if the node is not changed
867 // for robustness since it's no harm to run init procedure
868 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -0800869 eventExecutor.execute(() -> initNode(newNode));
870 break;
871 case INSERT:
872 newNode = event.newValue().value();
873 log.info("Added {}", newNode.hostname());
874 eventExecutor.execute(() -> initNode(newNode));
875 break;
876 case REMOVE:
877 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700878 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800879 break;
880 default:
881 break;
882 }
883 }
884 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800885}