blob: c037c05df985e619ebb36a05ee2320b06f58685f [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
18import com.google.common.collect.Sets;
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.ItemNotFoundException;
28import org.onlab.util.KryoNamespace;
29import org.onosproject.cluster.ClusterService;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080030import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
alshabibb4d31712016-06-01 18:51:03 -070032import org.opencord.cordvtn.api.ConnectionHandler;
33import org.opencord.cordvtn.api.CordVtnConfig;
34import org.opencord.cordvtn.api.CordVtnNode;
35import org.opencord.cordvtn.api.CordVtnNodeState;
36import org.opencord.cordvtn.api.CordVtnService;
37import org.opencord.cordvtn.api.NetworkAddress;
38import org.opencord.cordvtn.api.SshAccessInfo;
Hyunsun Mooncb799442016-01-15 20:03:18 -080039import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080041import org.onosproject.net.ConnectPoint;
42import org.onosproject.net.DefaultAnnotations;
43import org.onosproject.net.Device;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.Host;
46import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070047import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080048import org.onosproject.net.behaviour.BridgeConfig;
49import org.onosproject.net.behaviour.BridgeName;
50import org.onosproject.net.behaviour.ControllerInfo;
51import org.onosproject.net.behaviour.DefaultTunnelDescription;
52import org.onosproject.net.behaviour.TunnelConfig;
53import org.onosproject.net.behaviour.TunnelDescription;
54import org.onosproject.net.behaviour.TunnelName;
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
76import java.util.ArrayList;
77import java.util.HashMap;
78import java.util.List;
79import java.util.Map;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -080080import java.util.Objects;
Hyunsun Moon126171d2016-02-09 01:55:48 -080081import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080082import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080083import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080084
85import static com.google.common.base.Preconditions.checkNotNull;
86import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
87import static org.onlab.util.Tools.groupedThreads;
alshabibb4d31712016-06-01 18:51:03 -070088import static org.opencord.cordvtn.impl.CordVtnPipeline.DEFAULT_TUNNEL;
Hyunsun Mooncb799442016-01-15 20:03:18 -080089import static org.onosproject.net.Device.Type.SWITCH;
90import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
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
112 private static final String DEFAULT_BRIDGE = "br-int";
Hyunsun Mooncb799442016-01-15 20:03:18 -0800113 private static final String VPORT_PREFIX = "tap";
114 private static final String OK = "OK";
115 private static final String NO = "NO";
116
117 private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
118 {
119 put("key", "flow");
120 put("remote_ip", "flow");
121 }
122 };
123 private static final int DPID_BEGIN = 3;
124 private static final int OFPORT = 6653;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected CoreService coreService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected NetworkConfigRegistry configRegistry;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected NetworkConfigService configService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected StorageService storageService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected DeviceAdminService adminService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected OvsdbController controller;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected ClusterService clusterService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800148 protected DeviceService deviceService;
149
150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
151 protected HostService hostService;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800154 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700157 protected CordVtnInstanceManager instanceManager;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800158
159 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700160 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800161
Hyunsun Mooncb799442016-01-15 20:03:18 -0800162 private final ExecutorService eventExecutor =
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700163 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn-node", "event-handler"));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800164
165 private final NetworkConfigListener configListener = new InternalConfigListener();
166 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800167 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800168
169 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
170 private final BridgeHandler bridgeHandler = new BridgeHandler();
171
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800172 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800173 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800174 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800175
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800176 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800177
178 INIT {
179 @Override
180 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800181 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800182 nodeManager.connectOvsdb(node);
183 } else {
184 nodeManager.createIntegrationBridge(node);
185 }
186 }
187 },
188 BRIDGE_CREATED {
189 @Override
190 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800191 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800192 nodeManager.connectOvsdb(node);
193 } else {
194 nodeManager.createTunnelInterface(node);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800195 nodeManager.addDataPlaneInterface(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800196 }
197 }
198 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800199 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800200 @Override
201 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800202 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800203 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800204 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800205 COMPLETE {
206 @Override
207 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
208 nodeManager.postInit(node);
209 }
210 },
211 INCOMPLETE {
212 @Override
213 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
214 }
215 };
216
Hyunsun Mooncb799442016-01-15 20:03:18 -0800217 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
218 }
219
220 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700221 protected void activate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800222 appId = coreService.getAppId(CordVtnService.CORDVTN_APP_ID);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700223
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800224 localNodeId = clusterService.getLocalNode().id();
225 leadershipService.runForLeadership(appId.name());
226
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800227 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800228 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
229 .withName("cordvtn-nodestore")
230 .withApplicationId(appId)
231 .build();
232
Hyunsun Moonff55e812016-03-10 12:40:16 -0800233 nodeStore.addListener(nodeStoreListener);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800234 deviceService.addListener(deviceListener);
235 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700236
237 log.info("Started");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800238 }
239
240 @Deactivate
241 protected void deactivate() {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800242 configService.removeListener(configListener);
243 deviceService.removeListener(deviceListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800244 nodeStore.removeListener(nodeStoreListener);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800245
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800246 leadershipService.withdraw(appId.name());
Hyunsun Moonff55e812016-03-10 12:40:16 -0800247 eventExecutor.shutdown();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700248
249 log.info("Stopped");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800250 }
251
252 /**
Hyunsun Moonff55e812016-03-10 12:40:16 -0800253 * Adds or updates a new node to the service.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800254 *
255 * @param node cordvtn node
256 */
Hyunsun Moonff55e812016-03-10 12:40:16 -0800257 public void addOrUpdateNode(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800258 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800259 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, getNodeState(node)));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800260 }
261
262 /**
263 * Deletes a node from the service.
264 *
265 * @param node cordvtn node
266 */
267 public void deleteNode(CordVtnNode node) {
268 checkNotNull(node);
269
Hyunsun Moon126171d2016-02-09 01:55:48 -0800270 if (isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800271 disconnectOvsdb(node);
272 }
273
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800274 nodeStore.remove(node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800275 }
276
277 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800278 * Returns node initialization state.
279 *
280 * @param node cordvtn node
281 * @return true if initial node setup is completed, otherwise false
282 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800283 public boolean isNodeInitComplete(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800284 checkNotNull(node);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800285 return nodeStore.containsKey(node.hostname()) && getNodeState(node).equals(NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800286 }
287
288 /**
289 * Returns detailed node initialization state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800290 *
291 * @param node cordvtn node
292 * @return string including detailed node init state
293 */
294 public String checkNodeInitState(CordVtnNode node) {
295 checkNotNull(node);
296
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800297 if (!nodeStore.containsKey(node.hostname())) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800298 log.warn("Node {} does not exist, add node first", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800299 return null;
300 }
301
Hyunsun Moon479b7752016-05-06 20:13:28 -0700302 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800303 if (session == null) {
304 log.debug("Failed to SSH to {}", node.hostname());
305 return null;
306 }
307
Hyunsun Moon479b7752016-05-06 20:13:28 -0700308 Set<IpAddress> intBrIps = getCurrentIps(session, DEFAULT_BRIDGE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800309 String result = String.format(
Hyunsun Moon479b7752016-05-06 20:13:28 -0700310 "Current state : %s%n" +
311 "br-int created and connected to ONOS : %s (%s)%n" +
312 "VXLAN interface added to br-int : %s%n" +
313 "Data plane interface is added to br-int and enabled : %s (%s)%n" +
314 "IP flushed from data plane interface : %s (%s)%n" +
Hyunsun Moon126171d2016-02-09 01:55:48 -0800315 "Data plane IP added to br-int : %s (%s)%n" +
316 "Local management IP added to br-int : %s (%s)",
Hyunsun Moon479b7752016-05-06 20:13:28 -0700317 node.state(),
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800318 isBrIntCreated(node) ? OK : NO, node.intBrId(),
Hyunsun Moon126171d2016-02-09 01:55:48 -0800319 isTunnelIntfCreated(node) ? OK : NO,
320 isDataPlaneIntfAdded(node) ? OK : NO, node.dpIntf(),
Hyunsun Moon479b7752016-05-06 20:13:28 -0700321 isInterfaceUp(session, node.dpIntf()) &&
322 getCurrentIps(session, node.dpIntf()).isEmpty() ? OK : NO, node.dpIntf(),
Hyunsun Moon126171d2016-02-09 01:55:48 -0800323 intBrIps.contains(node.dpIp().ip()) ? OK : NO, node.dpIp().cidr(),
324 intBrIps.contains(node.localMgmtIp().ip()) ? OK : NO, node.localMgmtIp().cidr());
325
Hyunsun Moon479b7752016-05-06 20:13:28 -0700326 disconnect(session);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800327
328 return result;
329 }
330
331 /**
332 * Returns the number of the nodes known to the service.
333 *
334 * @return number of nodes
335 */
336 public int getNodeCount() {
337 return nodeStore.size();
338 }
339
340 /**
341 * Returns all nodes known to the service.
342 *
343 * @return list of nodes
344 */
345 public List<CordVtnNode> getNodes() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700346 return nodeStore.values().stream().map(Versioned::value).collect(Collectors.toList());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800347 }
348
349 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700350 * Returns all nodes in complete state.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800351 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700352 * @return set of nodes
Hyunsun Mooncb799442016-01-15 20:03:18 -0800353 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700354 public Set<CordVtnNode> completeNodes() {
355 return getNodes().stream().filter(this::isNodeInitComplete).collect(Collectors.toSet());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800356 }
357
358 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700359 * Returns physical data plane port number of a given device.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800360 *
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700361 * @param deviceId integration bridge device id
362 * @return port number; null otherwise
Hyunsun Mooncb799442016-01-15 20:03:18 -0800363 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700364 public PortNumber dpPort(DeviceId deviceId) {
365 CordVtnNode node = nodeByBridgeId(deviceId);
366 if (node == null) {
367 log.warn("Failed to get node for {}", deviceId);
368 return null;
369 }
370 Port port = deviceService.getPorts(deviceId).stream()
371 .filter(p -> portName(p).contains(node.dpIntf()) &&
372 p.isEnabled())
Hyunsun Mooncb799442016-01-15 20:03:18 -0800373 .findFirst().orElse(null);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700374
375 return port == null ? null : port.number();
376 }
377
378 /**
379 * Returns physical data plane IP address of a given device.
380 *
381 * @param deviceId integration bridge device id
382 * @return ip address; null otherwise
383 */
384 public IpAddress dpIp(DeviceId deviceId) {
385 CordVtnNode node = nodeByBridgeId(deviceId);
386 if (node == null) {
387 log.warn("Failed to get node for {}", deviceId);
388 return null;
389 }
390 return node.dpIp().ip();
391 }
392
393 /**
394 * Returns tunnel port number of a given device.
395 *
396 * @param deviceId integration bridge device id
397 * @return port number
398 */
399 public PortNumber tunnelPort(DeviceId deviceId) {
400 Port port = deviceService.getPorts(deviceId).stream()
401 .filter(p -> portName(p).contains(DEFAULT_TUNNEL))
402 .findFirst().orElse(null);
403
404 return port == null ? null : port.number();
405 }
406
407 /**
408 * Returns if current node state saved in nodeStore is COMPLETE or not.
409 *
410 * @param node cordvtn node
411 * @return true if it's complete state, otherwise false
412 */
413 private boolean isNodeStateComplete(CordVtnNode node) {
414 checkNotNull(node);
415
416 // the state saved in nodeStore can be wrong if IP address settings are changed
417 // after the node init has been completed since there's no way to detect it
418 // getNodeState and checkNodeInitState always return correct answer but can be slow
419 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
420 CordVtnNodeState state = versionedNode.value().state();
421 return state != null && state.equals(NodeState.COMPLETE);
422 }
423
424 /**
425 * Initiates node to serve virtual tenant network.
426 *
427 * @param node cordvtn node
428 */
429 private void initNode(CordVtnNode node) {
430 checkNotNull(node);
431
432 NodeState state = (NodeState) node.state();
433 log.debug("Processing node: {} state: {}", node.hostname(), state);
434
435 state.process(this, node);
436 }
437
438 /**
439 * Performs tasks after node initialization.
440 * It disconnects unnecessary OVSDB connection and installs initial flow
441 * rules on the device.
442 *
443 * @param node cordvtn node
444 */
445 private void postInit(CordVtnNode node) {
446 disconnectOvsdb(node);
447 pipeline.initPipeline(node, dpPort(node.intBrId()), tunnelPort(node.intBrId()));
448
449 deviceService.getPorts(node.intBrId()).stream()
450 .filter(port -> portName(port).startsWith(VPORT_PREFIX) &&
451 port.isEnabled())
452 .forEach(port -> instanceManager.addInstance(connectPoint(port)));
453
454 hostService.getHosts().forEach(host -> {
455 if (deviceService.getPort(host.location().deviceId(),
456 host.location().port()) == null) {
457 instanceManager.removeInstance(connectPoint(host));
458 }
459 });
460
461 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800462 }
463
464 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800465 * Sets a new state for a given cordvtn node.
466 *
467 * @param node cordvtn node
468 * @param newState new node state
469 */
470 private void setNodeState(CordVtnNode node, NodeState newState) {
471 checkNotNull(node);
472
Hyunsun Moonff55e812016-03-10 12:40:16 -0800473 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800474 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800475 }
476
477 /**
478 * Checks current state of a given cordvtn node and returns it.
479 *
480 * @param node cordvtn node
481 * @return node state
482 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800483 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800484 checkNotNull(node);
485
Hyunsun Moon126171d2016-02-09 01:55:48 -0800486 if (isBrIntCreated(node) && isTunnelIntfCreated(node) &&
487 isDataPlaneIntfAdded(node) && isIpAddressSet(node)) {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800488 return NodeState.COMPLETE;
Hyunsun Moon126171d2016-02-09 01:55:48 -0800489 } else if (isDataPlaneIntfAdded(node) && isTunnelIntfCreated(node)) {
490 return NodeState.PORTS_ADDED;
491 } else if (isBrIntCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800492 return NodeState.BRIDGE_CREATED;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800493 } else {
494 return NodeState.INIT;
495 }
496 }
497
498 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800499 * Returns connection state of OVSDB server for a given node.
500 *
501 * @param node cordvtn node
502 * @return true if it is connected, false otherwise
503 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800504 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800505 checkNotNull(node);
506
507 OvsdbClientService ovsdbClient = getOvsdbClient(node);
508 return deviceService.isAvailable(node.ovsdbId()) &&
509 ovsdbClient != null && ovsdbClient.isConnected();
510 }
511
512 /**
513 * Connects to OVSDB server for a given node.
514 *
515 * @param node cordvtn node
516 */
517 private void connectOvsdb(CordVtnNode node) {
518 checkNotNull(node);
519
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800520 if (!nodeStore.containsKey(node.hostname())) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800521 log.warn("Node {} does not exist", node.hostname());
522 return;
523 }
524
Hyunsun Moon126171d2016-02-09 01:55:48 -0800525 if (!isOvsdbConnected(node)) {
526 controller.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800527 }
528 }
529
530 /**
531 * Disconnects OVSDB server for a given node.
532 *
533 * @param node cordvtn node
534 */
535 private void disconnectOvsdb(CordVtnNode node) {
536 checkNotNull(node);
537
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800538 if (!nodeStore.containsKey(node.hostname())) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800539 log.warn("Node {} does not exist", node.hostname());
540 return;
541 }
542
Hyunsun Moon126171d2016-02-09 01:55:48 -0800543 if (isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800544 OvsdbClientService ovsdbClient = getOvsdbClient(node);
545 ovsdbClient.disconnect();
546 }
547 }
548
549 /**
550 * Returns OVSDB client for a given node.
551 *
552 * @param node cordvtn node
553 * @return OVSDB client, or null if it fails to get OVSDB client
554 */
555 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
556 checkNotNull(node);
557
558 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
Hyunsun Moon126171d2016-02-09 01:55:48 -0800559 new OvsdbNodeId(node.hostMgmtIp().ip(), node.ovsdbPort().toInt()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800560 if (ovsdbClient == null) {
561 log.trace("Couldn't find OVSDB client for {}", node.hostname());
562 }
563 return ovsdbClient;
564 }
565
566 /**
567 * Creates an integration bridge for a given node.
568 *
569 * @param node cordvtn node
570 */
571 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800572 if (isBrIntCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800573 return;
574 }
575
576 List<ControllerInfo> controllers = new ArrayList<>();
577 Sets.newHashSet(clusterService.getNodes()).stream()
578 .forEach(controller -> {
579 ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
580 controllers.add(ctrlInfo);
581 });
582
583 String dpid = node.intBrId().toString().substring(DPID_BEGIN);
584
585 try {
Jian Lie676a9a2016-04-15 13:22:05 -0700586 Device device = deviceService.getDevice(node.ovsdbId());
587 if (device.is(BridgeConfig.class)) {
588 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
589 bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE), dpid, controllers);
590 } else {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700591 log.warn("The bridging behaviour is not supported in device {}", device.id());
Jian Lie676a9a2016-04-15 13:22:05 -0700592 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800593 } catch (ItemNotFoundException e) {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800594 log.warn("Failed to create integration bridge on {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800595 }
596 }
597
598 /**
599 * Creates tunnel interface to the integration bridge for a given node.
600 *
601 * @param node cordvtn node
602 */
603 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800604 if (isTunnelIntfCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800605 return;
606 }
607
608 DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder();
609 for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
610 optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
611 }
612
613 TunnelDescription description = new DefaultTunnelDescription(
614 null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL),
615 optionBuilder.build());
616
617 try {
Jian Lie676a9a2016-04-15 13:22:05 -0700618 Device device = deviceService.getDevice(node.ovsdbId());
619 if (device.is(TunnelConfig.class)) {
620 TunnelConfig tunnelConfig = device.as(TunnelConfig.class);
621 tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE), description);
622 } else {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700623 log.warn("The tunneling behaviour is not supported in device {}", device.id());
Jian Lie676a9a2016-04-15 13:22:05 -0700624 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800625 } catch (ItemNotFoundException e) {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800626 log.warn("Failed to create tunnel interface on {}", node.hostname());
627 }
628 }
629
630 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800631 * Adds data plane interface to a given node.
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800632 *
633 * @param node cordvtn node
634 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800635 private void addDataPlaneInterface(CordVtnNode node) {
636 if (isDataPlaneIntfAdded(node)) {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800637 return;
638 }
639
Hyunsun Moon479b7752016-05-06 20:13:28 -0700640 Session session = connect(node.sshInfo());
641 if (session == null) {
642 log.debug("Failed to SSH to {}", node.hostname());
643 return;
644 }
645
646 if (!isInterfaceUp(session, node.dpIntf())) {
647 log.warn("Interface {} is not available", node.dpIntf());
648 return;
649 }
650 disconnect(session);
651
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800652 try {
Jian Lie676a9a2016-04-15 13:22:05 -0700653 Device device = deviceService.getDevice(node.ovsdbId());
654 if (device.is(BridgeConfig.class)) {
655 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
656 bridgeConfig.addPort(BridgeName.bridgeName(DEFAULT_BRIDGE), node.dpIntf());
657 } else {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700658 log.warn("The bridging behaviour is not supported in device {}", device.id());
Jian Lie676a9a2016-04-15 13:22:05 -0700659 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800660 } catch (ItemNotFoundException e) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800661 log.warn("Failed to add {} on {}", node.dpIntf(), node.hostname());
662 }
663 }
664
665 /**
666 * Flushes IP address from data plane interface and adds data plane IP address
667 * to integration bridge.
668 *
669 * @param node cordvtn node
670 */
671 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700672 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800673 if (session == null) {
674 log.debug("Failed to SSH to {}", node.hostname());
675 return;
676 }
677
Hyunsun Moon479b7752016-05-06 20:13:28 -0700678 getCurrentIps(session, DEFAULT_BRIDGE).stream()
Hyunsun Moonf2760522016-03-04 19:24:08 -0800679 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
680 .filter(ip -> !ip.equals(node.dpIp().ip()))
Hyunsun Moon479b7752016-05-06 20:13:28 -0700681 .forEach(ip -> deleteIp(session, ip, DEFAULT_BRIDGE));
Hyunsun Moonf2760522016-03-04 19:24:08 -0800682
Hyunsun Moon479b7752016-05-06 20:13:28 -0700683 boolean result = flushIp(session, node.dpIntf()) &&
684 setInterfaceUp(session, node.dpIntf()) &&
685 addIp(session, node.dpIp(), DEFAULT_BRIDGE) &&
686 addIp(session, node.localMgmtIp(), DEFAULT_BRIDGE) &&
687 setInterfaceUp(session, DEFAULT_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800688
Hyunsun Moon479b7752016-05-06 20:13:28 -0700689 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800690
691 if (result) {
692 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800693 }
694 }
695
696 /**
697 * Checks if integration bridge exists and available.
698 *
699 * @param node cordvtn node
700 * @return true if the bridge is available, false otherwise
701 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800702 private boolean isBrIntCreated(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800703 return (deviceService.getDevice(node.intBrId()) != null
704 && deviceService.isAvailable(node.intBrId()));
705 }
706
707 /**
708 * Checks if tunnel interface exists.
709 *
710 * @param node cordvtn node
711 * @return true if the interface exists, false otherwise
712 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800713 private boolean isTunnelIntfCreated(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800714 return deviceService.getPorts(node.intBrId())
715 .stream()
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700716 .filter(p -> portName(p).contains(DEFAULT_TUNNEL) &&
Hyunsun Mooncb799442016-01-15 20:03:18 -0800717 p.isEnabled())
718 .findAny().isPresent();
719 }
720
721 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800722 * Checks if data plane interface exists.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800723 *
724 * @param node cordvtn node
725 * @return true if the interface exists, false otherwise
726 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800727 private boolean isDataPlaneIntfAdded(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800728 return deviceService.getPorts(node.intBrId())
729 .stream()
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700730 .filter(p -> portName(p).contains(node.dpIntf()) &&
Hyunsun Mooncb799442016-01-15 20:03:18 -0800731 p.isEnabled())
732 .findAny().isPresent();
733 }
734
735 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800736 * Checks if the IP addresses are correctly set.
737 *
738 * @param node cordvtn node
739 * @return true if the IP is set, false otherwise
740 */
741 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700742 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800743 if (session == null) {
744 log.debug("Failed to SSH to {}", node.hostname());
745 return false;
746 }
747
Hyunsun Moon479b7752016-05-06 20:13:28 -0700748 Set<IpAddress> intBrIps = getCurrentIps(session, DEFAULT_BRIDGE);
749 boolean result = getCurrentIps(session, node.dpIntf()).isEmpty() &&
750 isInterfaceUp(session, node.dpIntf()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800751 intBrIps.contains(node.dpIp().ip()) &&
752 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon479b7752016-05-06 20:13:28 -0700753 isInterfaceUp(session, DEFAULT_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800754
Hyunsun Moon479b7752016-05-06 20:13:28 -0700755 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800756 return result;
757 }
758
759 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800760 * Returns connect point of a given port.
761 *
762 * @param port port
763 * @return connect point
764 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700765 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800766 return new ConnectPoint(port.element().id(), port.number());
767 }
768
769 /**
770 * Returns connect point of a given host.
771 *
772 * @param host host
773 * @return connect point
774 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700775 private ConnectPoint connectPoint(Host host) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800776 return new ConnectPoint(host.location().deviceId(), host.location().port());
777 }
778
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700779 /**
780 * Returns cordvtn node associated with a given OVSDB device.
781 *
782 * @param ovsdbId OVSDB device id
783 * @return cordvtn node, null if it fails to find the node
784 */
785 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
786 return getNodes().stream()
787 .filter(node -> node.ovsdbId().equals(ovsdbId))
788 .findFirst().orElse(null);
789 }
790
791 /**
792 * Returns cordvtn node associated with a given integration bridge.
793 *
794 * @param bridgeId device id of integration bridge
795 * @return cordvtn node, null if it fails to find the node
796 */
797 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
798 return getNodes().stream()
799 .filter(node -> node.intBrId().equals(bridgeId))
800 .findFirst().orElse(null);
801 }
802
803 /**
804 * Returns port name.
805 *
806 * @param port port
807 * @return port name
808 */
809 private String portName(Port port) {
810 return port.annotations().value("portName");
811 }
812
Hyunsun Mooncb799442016-01-15 20:03:18 -0800813 private class OvsdbHandler implements ConnectionHandler<Device> {
814
815 @Override
816 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700817 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800818 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800819 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800820 } else {
821 log.debug("{} is detected on unregistered node, ignore it.", device.id());
822 }
823 }
824
825 @Override
826 public void disconnected(Device device) {
827 if (!deviceService.isAvailable(device.id())) {
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800828 log.debug("Device {} is disconnected", device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800829 adminService.removeDevice(device.id());
830 }
831 }
832 }
833
834 private class BridgeHandler implements ConnectionHandler<Device> {
835
836 @Override
837 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700838 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800839 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800840 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800841 } else {
842 log.debug("{} is detected on unregistered node, ignore it.", device.id());
843 }
844 }
845
846 @Override
847 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700848 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800849 if (node != null) {
850 log.debug("Integration Bridge is disconnected from {}", node.hostname());
851 setNodeState(node, NodeState.INCOMPLETE);
852 }
853 }
854
855 /**
856 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800857 * If the added port is tunnel or data plane interface, proceed to the remaining
858 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800859 *
860 * @param port port
861 */
862 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700863 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
864 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800865
866 if (node == null) {
867 log.debug("{} is added to unregistered node, ignore it.", portName);
868 return;
869 }
870
Hyunsun Moonff55e812016-03-10 12:40:16 -0800871 log.info("Port {} is added to {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800872
873 if (portName.startsWith(VPORT_PREFIX)) {
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800874 if (isNodeStateComplete(node)) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700875 instanceManager.addInstance(connectPoint(port));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800876 } else {
877 log.debug("VM is detected on incomplete node, ignore it.", portName);
878 }
Hyunsun Moon126171d2016-02-09 01:55:48 -0800879 } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.dpIntf())) {
880 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800881 }
882 }
883
884 /**
885 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800886 * If the removed port is tunnel or data plane interface, proceed to the remaining
887 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800888 *
889 * @param port port
890 */
891 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700892 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
893 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800894
895 if (node == null) {
896 return;
897 }
898
Hyunsun Moonff55e812016-03-10 12:40:16 -0800899 log.info("Port {} is removed from {}", portName, node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800900
901 if (portName.startsWith(VPORT_PREFIX)) {
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800902 if (isNodeStateComplete(node)) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700903 instanceManager.removeInstance(connectPoint(port));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800904 } else {
905 log.debug("VM is vanished from incomplete node, ignore it.", portName);
906 }
Hyunsun Moon126171d2016-02-09 01:55:48 -0800907 } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.dpIntf())) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800908 setNodeState(node, NodeState.INCOMPLETE);
909 }
910 }
911 }
912
913 private class InternalDeviceListener implements DeviceListener {
914
915 @Override
916 public void event(DeviceEvent event) {
917
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800918 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
919 if (!Objects.equals(localNodeId, leaderNodeId)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800920 // do not allow to proceed without leadership
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800921 return;
922 }
923
Hyunsun Mooncb799442016-01-15 20:03:18 -0800924 Device device = event.subject();
925 ConnectionHandler<Device> handler =
926 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
927
928 switch (event.type()) {
929 case PORT_ADDED:
Hyunsun Moonff55e812016-03-10 12:40:16 -0800930 eventExecutor.execute(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800931 break;
932 case PORT_UPDATED:
933 if (!event.port().isEnabled()) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800934 eventExecutor.execute(() -> bridgeHandler.portRemoved(event.port()));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800935 }
936 break;
937 case DEVICE_ADDED:
938 case DEVICE_AVAILABILITY_CHANGED:
939 if (deviceService.isAvailable(device.id())) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800940 eventExecutor.execute(() -> handler.connected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800941 } else {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800942 eventExecutor.execute(() -> handler.disconnected(device));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800943 }
944 break;
945 default:
946 break;
947 }
948 }
949 }
950
951 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800952 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800953 */
954 private void readConfiguration() {
955 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800956 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800957 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800958 return;
959 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800960 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800961 }
962
963 private class InternalConfigListener implements NetworkConfigListener {
964
965 @Override
966 public void event(NetworkConfigEvent event) {
Hyunsun Moonff55e812016-03-10 12:40:16 -0800967 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
968 if (!Objects.equals(localNodeId, leaderNodeId)) {
969 // do not allow to proceed without leadership
970 return;
971 }
972
Hyunsun Mooncb799442016-01-15 20:03:18 -0800973 if (!event.configClass().equals(CordVtnConfig.class)) {
974 return;
975 }
976
977 switch (event.type()) {
978 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800979 case CONFIG_UPDATED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800980 eventExecutor.execute(CordVtnNodeManager.this::readConfiguration);
981 break;
982 default:
983 break;
984 }
985 }
986 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800987
988 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
989
990 @Override
991 public void event(MapEvent<String, CordVtnNode> event) {
992 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
993 if (!Objects.equals(localNodeId, leaderNodeId)) {
994 // do not allow to proceed without leadership
995 return;
996 }
997
998 CordVtnNode oldNode;
999 CordVtnNode newNode;
1000
1001 switch (event.type()) {
1002 case UPDATE:
1003 oldNode = event.oldValue().value();
1004 newNode = event.newValue().value();
1005
Hyunsun Moon479b7752016-05-06 20:13:28 -07001006 log.info("Reloaded {}", newNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -08001007 if (!newNode.equals(oldNode)) {
Hyunsun Moonff55e812016-03-10 12:40:16 -08001008 log.debug("New node: {}", newNode);
1009 }
Hyunsun Moon479b7752016-05-06 20:13:28 -07001010 // performs init procedure even if the node is not changed
1011 // for robustness since it's no harm to run init procedure
1012 // multiple times
Hyunsun Moonff55e812016-03-10 12:40:16 -08001013 eventExecutor.execute(() -> initNode(newNode));
1014 break;
1015 case INSERT:
1016 newNode = event.newValue().value();
1017 log.info("Added {}", newNode.hostname());
1018 eventExecutor.execute(() -> initNode(newNode));
1019 break;
1020 case REMOVE:
1021 oldNode = event.oldValue().value();
Hyunsun Moon479b7752016-05-06 20:13:28 -07001022 log.info("Removed {}", oldNode.hostname());
Hyunsun Moonff55e812016-03-10 12:40:16 -08001023 break;
1024 default:
1025 break;
1026 }
1027 }
1028 }
Hyunsun Mooncb799442016-01-15 20:03:18 -08001029}