blob: 97f5f774bc2d77faca05e170d2b93d8689bb2957 [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 Moon3fc0cbc2016-11-22 18:29:12 -080019import com.google.common.collect.Lists;
Hyunsun Moon126171d2016-02-09 01:55:48 -080020import com.jcraft.jsch.Session;
Hyunsun Mooncb799442016-01-15 20:03:18 -080021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Hyunsun Moon126171d2016-02-09 01:55:48 -080027import org.onlab.packet.IpAddress;
Hyunsun Mooncb799442016-01-15 20:03:18 -080028import 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;
Hyunsun Mooncb799442016-01-15 20:03:18 -080032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080034import org.onosproject.net.ConnectPoint;
Hyunsun Mooncb799442016-01-15 20:03:18 -080035import org.onosproject.net.Device;
36import org.onosproject.net.DeviceId;
Hyunsun Mooncb799442016-01-15 20:03:18 -080037import org.onosproject.net.Port;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070038import org.onosproject.net.PortNumber;
Hyunsun Mooncb799442016-01-15 20:03:18 -080039import org.onosproject.net.behaviour.BridgeConfig;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080040import org.onosproject.net.behaviour.BridgeDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080041import org.onosproject.net.behaviour.BridgeName;
42import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080043import org.onosproject.net.behaviour.DefaultBridgeDescription;
Hyunsun Mooncb799442016-01-15 20:03:18 -080044import org.onosproject.net.behaviour.DefaultTunnelDescription;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080045import org.onosproject.net.behaviour.InterfaceConfig;
Hyunsun Mooncb799442016-01-15 20:03:18 -080046import org.onosproject.net.behaviour.TunnelDescription;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080047import org.onosproject.net.behaviour.TunnelEndPoints;
48import org.onosproject.net.behaviour.TunnelKeys;
Hyunsun Mooncb799442016-01-15 20:03:18 -080049import org.onosproject.net.config.NetworkConfigEvent;
50import org.onosproject.net.config.NetworkConfigListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080051import org.onosproject.net.config.NetworkConfigService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080052import org.onosproject.net.device.DeviceAdminService;
53import org.onosproject.net.device.DeviceEvent;
54import org.onosproject.net.device.DeviceListener;
55import org.onosproject.net.device.DeviceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -080056import org.onosproject.net.host.HostService;
57import org.onosproject.ovsdb.controller.OvsdbClientService;
58import org.onosproject.ovsdb.controller.OvsdbController;
59import org.onosproject.ovsdb.controller.OvsdbNodeId;
60import org.onosproject.store.serializers.KryoNamespaces;
61import org.onosproject.store.service.ConsistentMap;
Hyunsun Moonff55e812016-03-10 12:40:16 -080062import org.onosproject.store.service.MapEvent;
63import org.onosproject.store.service.MapEventListener;
Hyunsun Mooncb799442016-01-15 20:03:18 -080064import org.onosproject.store.service.Serializer;
65import org.onosproject.store.service.StorageService;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080066import org.onosproject.store.service.Versioned;
Hyunsun Moon187bf532017-01-19 10:57:40 +090067import org.opencord.cordvtn.api.CordVtnConfig;
68import org.opencord.cordvtn.api.core.InstanceService;
69import org.opencord.cordvtn.api.net.CidrAddr;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080070import org.opencord.cordvtn.api.node.ConnectionHandler;
71import org.opencord.cordvtn.api.node.CordVtnNode;
72import org.opencord.cordvtn.api.node.CordVtnNodeState;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080073import org.opencord.cordvtn.api.node.SshAccessInfo;
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 Moonc031d9b2016-08-04 13:57:22 -070078import java.util.Optional;
Hyunsun Moon126171d2016-02-09 01:55:48 -080079import java.util.Set;
Hyunsun Mooncb799442016-01-15 20:03:18 -080080import java.util.concurrent.ExecutorService;
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -080081import java.util.stream.Collectors;
Hyunsun Mooncb799442016-01-15 20:03:18 -080082
83import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon537018f2016-07-27 18:51:00 -070084import static java.util.concurrent.Executors.newSingleThreadExecutor;
Hyunsun Mooncb799442016-01-15 20:03:18 -080085import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon81a13562016-08-04 13:48:08 -070086import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Mooncb799442016-01-15 20:03:18 -080087import static org.onosproject.net.Device.Type.SWITCH;
88import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070089import static org.opencord.cordvtn.api.Constants.*;
alshabibb4d31712016-06-01 18:51:03 -070090import static org.opencord.cordvtn.impl.RemoteIpCommandUtil.*;
Hyunsun Mooncb799442016-01-15 20:03:18 -080091import static org.slf4j.LoggerFactory.getLogger;
92
93/**
94 * Reads node information from the network config file and handles the config
95 * update events.
96 * Only a leader controller performs the node addition or deletion.
97 */
98@Component(immediate = true)
99@Service(value = CordVtnNodeManager.class)
100public class CordVtnNodeManager {
101
102 protected final Logger log = getLogger(getClass());
103
104 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
105 .register(KryoNamespaces.API)
106 .register(CordVtnNode.class)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800107 .register(NodeState.class)
108 .register(SshAccessInfo.class)
Hyunsun Moon187bf532017-01-19 10:57:40 +0900109 .register(CidrAddr.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800110
Hyunsun Mooncb799442016-01-15 20:03:18 -0800111 private static final int DPID_BEGIN = 3;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected CoreService coreService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800117 protected NetworkConfigService configService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected StorageService storageService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected DeviceAdminService adminService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700126 protected OvsdbController ovsdbController;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected ClusterService clusterService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800132 protected DeviceService deviceService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected HostService hostService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800138 protected LeadershipService leadershipService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700141 protected InstanceService instanceService;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700144 protected CordVtnPipeline pipeline;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800145
Hyunsun Mooncb799442016-01-15 20:03:18 -0800146 private final ExecutorService eventExecutor =
Hyunsun Moon537018f2016-07-27 18:51:00 -0700147 newSingleThreadExecutor(groupedThreads("onos/cordvtn-node", "event-handler", log));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800148
149 private final NetworkConfigListener configListener = new InternalConfigListener();
150 private final DeviceListener deviceListener = new InternalDeviceListener();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800151 private final MapEventListener<String, CordVtnNode> nodeStoreListener = new InternalMapListener();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800152
153 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
154 private final BridgeHandler bridgeHandler = new BridgeHandler();
155
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800156 private ConsistentMap<String, CordVtnNode> nodeStore;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800157 private List<ControllerInfo> controllers = Lists.newArrayList();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800158 private ApplicationId appId;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800159 private NodeId localNodeId;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800160
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800161 private enum NodeState implements CordVtnNodeState {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800162
163 INIT {
164 @Override
165 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700166 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800167 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800168 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700169 return;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800170 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700171 nodeManager.createIntegrationBridge(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800172 }
173 },
174 BRIDGE_CREATED {
175 @Override
176 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700177 // make sure there is OVSDB connection
Hyunsun Moon126171d2016-02-09 01:55:48 -0800178 if (!nodeManager.isOvsdbConnected(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800179 nodeManager.connectOvsdb(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700180 return;
181 }
182
183 nodeManager.createTunnelInterface(node);
184 nodeManager.addSystemInterface(node, node.dataIface());
185 if (node.hostMgmtIface().isPresent()) {
186 nodeManager.addSystemInterface(node, node.hostMgmtIface().get());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800187 }
188 }
189 },
Hyunsun Moon126171d2016-02-09 01:55:48 -0800190 PORTS_ADDED {
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800191 @Override
192 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800193 nodeManager.setIpAddress(node);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800194 }
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800195 },
Hyunsun Mooncb799442016-01-15 20:03:18 -0800196 COMPLETE {
197 @Override
198 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
199 nodeManager.postInit(node);
200 }
201 },
202 INCOMPLETE {
203 @Override
204 public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
205 }
206 };
207
Hyunsun Mooncb799442016-01-15 20:03:18 -0800208 public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
209 }
210
211 @Activate
Hyunsun Moon479b7752016-05-06 20:13:28 -0700212 protected void activate() {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700213 appId = coreService.registerApplication(CORDVTN_APP_ID);
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800214 leadershipService.runForLeadership(appId.name());
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800215 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800216
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800217 nodeStore = storageService.<String, CordVtnNode>consistentMapBuilder()
Hyunsun Mooncb799442016-01-15 20:03:18 -0800218 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
219 .withName("cordvtn-nodestore")
220 .withApplicationId(appId)
221 .build();
222
Jonathan Hartaf6f60a2017-03-06 13:45:17 -0800223 nodeStore.addListener(nodeStoreListener, eventExecutor);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800224 deviceService.addListener(deviceListener);
225 configService.addListener(configListener);
Hyunsun Moon479b7752016-05-06 20:13:28 -0700226
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800227 readControllers();
Hyunsun Moon96207312017-03-20 16:17:07 +0900228 readNodes();
Hyunsun Moon479b7752016-05-06 20:13:28 -0700229 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 Moon6066bd32016-10-24 15:35:34 -0700276 return isNodeStateComplete(node);
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) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800316 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700317 return null;
318 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700319
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700320 Optional<PortNumber> port = getPortNumber(deviceId, node.dataIface());
321 return port.isPresent() ? port.get() : null;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700322 }
323
324 /**
325 * Returns physical data plane IP address of a given device.
326 *
327 * @param deviceId integration bridge device id
328 * @return ip address; null otherwise
329 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700330 public IpAddress dataIp(DeviceId deviceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700331 CordVtnNode node = nodeByBridgeId(deviceId);
332 if (node == null) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800333 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700334 return null;
335 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700336 return node.dataIp().ip();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700337 }
338
339 /**
340 * Returns tunnel port number of a given device.
341 *
342 * @param deviceId integration bridge device id
343 * @return port number
344 */
345 public PortNumber tunnelPort(DeviceId deviceId) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700346 Optional<PortNumber> port = getPortNumber(deviceId, DEFAULT_TUNNEL);
347 return port.isPresent() ? port.get() : null;
348 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700349
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700350 /**
351 * Returns host management interface port number if exists.
352 *
353 * @param deviceId integration bridge device id
354 * @return port number; null if it does not exist
355 */
356 public PortNumber hostManagementPort(DeviceId deviceId) {
357 CordVtnNode node = nodeByBridgeId(deviceId);
358 if (node == null) {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800359 log.debug("Failed to get node for {}", deviceId);
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700360 return null;
361 }
362
363 if (node.hostMgmtIface().isPresent()) {
364 Optional<PortNumber> port = getPortNumber(deviceId, node.hostMgmtIface().get());
365 return port.isPresent() ? port.get() : null;
366 } else {
367 return null;
368 }
369 }
370
371 private Optional<PortNumber> getPortNumber(DeviceId deviceId, String portName) {
372 PortNumber port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900373 .filter(p -> p.annotations().value(PORT_NAME).equals(portName) &&
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700374 p.isEnabled())
375 .map(Port::number)
376 .findAny()
377 .orElse(null);
378 return Optional.ofNullable(port);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700379 }
380
381 /**
382 * Returns if current node state saved in nodeStore is COMPLETE or not.
383 *
384 * @param node cordvtn node
385 * @return true if it's complete state, otherwise false
386 */
387 private boolean isNodeStateComplete(CordVtnNode node) {
388 checkNotNull(node);
389
390 // the state saved in nodeStore can be wrong if IP address settings are changed
391 // after the node init has been completed since there's no way to detect it
392 // getNodeState and checkNodeInitState always return correct answer but can be slow
393 Versioned<CordVtnNode> versionedNode = nodeStore.get(node.hostname());
394 CordVtnNodeState state = versionedNode.value().state();
395 return state != null && state.equals(NodeState.COMPLETE);
396 }
397
398 /**
399 * Initiates node to serve virtual tenant network.
400 *
401 * @param node cordvtn node
402 */
403 private void initNode(CordVtnNode node) {
404 checkNotNull(node);
405
406 NodeState state = (NodeState) node.state();
407 log.debug("Processing node: {} state: {}", node.hostname(), state);
408
409 state.process(this, node);
410 }
411
412 /**
413 * Performs tasks after node initialization.
414 * It disconnects unnecessary OVSDB connection and installs initial flow
415 * rules on the device.
416 *
417 * @param node cordvtn node
418 */
419 private void postInit(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700420 checkNotNull(node);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700421
Hyunsun Moon81a13562016-08-04 13:48:08 -0700422 // disconnect OVSDB session once the node bootstrap is done
423 OvsdbClientService ovsdbClient = getOvsdbClient(node);
424 if (ovsdbClient != null && ovsdbClient.isConnected()) {
425 ovsdbClient.disconnect();
426 }
427
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700428 pipeline.initPipeline(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700429
430 // adds existing instances to the host list
431 deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700432 .filter(port -> !node.systemIfaces().contains(portName(port)) &&
433 !port.number().equals(PortNumber.LOCAL) &&
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700434 port.isEnabled())
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700435 .forEach(port -> instanceService.addInstance(connectPoint(port)));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700436
Hyunsun Moon81a13562016-08-04 13:48:08 -0700437 // removes stale instances from the host list
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700438 hostService.getHosts().forEach(host -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700439 if (deviceService.getPort(
440 host.location().deviceId(),
441 host.location().port()) == null) {
442 instanceService.removeInstance(host.location());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700443 }
444 });
445
446 log.info("Finished init {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800447 }
448
449 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800450 * Sets a new state for a given cordvtn node.
451 *
452 * @param node cordvtn node
453 * @param newState new node state
454 */
455 private void setNodeState(CordVtnNode node, NodeState newState) {
456 checkNotNull(node);
Hyunsun Moonff55e812016-03-10 12:40:16 -0800457 log.debug("Changed {} state: {}", node.hostname(), newState);
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800458 nodeStore.put(node.hostname(), CordVtnNode.getUpdatedNode(node, newState));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800459 }
460
461 /**
462 * Checks current state of a given cordvtn node and returns it.
463 *
464 * @param node cordvtn node
465 * @return node state
466 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800467 private NodeState getNodeState(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800468 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700469 if (!isIntegrationBridgeCreated(node)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800470 return NodeState.INIT;
471 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700472 for (String iface : node.systemIfaces()) {
473 if (!isIfaceCreated(node, iface)) {
474 return NodeState.BRIDGE_CREATED;
475 }
476 }
477 if (!isIpAddressSet(node)) {
478 return NodeState.PORTS_ADDED;
479 }
480 return NodeState.COMPLETE;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800481 }
482
483 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800484 * Returns connection state of OVSDB server for a given node.
485 *
486 * @param node cordvtn node
487 * @return true if it is connected, false otherwise
488 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800489 private boolean isOvsdbConnected(CordVtnNode node) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800490 checkNotNull(node);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800491 OvsdbClientService ovsdbClient = getOvsdbClient(node);
492 return deviceService.isAvailable(node.ovsdbId()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700493 ovsdbClient != null &&
494 ovsdbClient.isConnected();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800495 }
496
497 /**
498 * Connects to OVSDB server for a given node.
499 *
500 * @param node cordvtn node
501 */
502 private void connectOvsdb(CordVtnNode node) {
503 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700504 ovsdbController.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800505 }
506
507 /**
508 * Returns OVSDB client for a given node.
509 *
510 * @param node cordvtn node
Hyunsun Moon81a13562016-08-04 13:48:08 -0700511 * @return ovsdb client, or null if there's no ovsdb connection
Hyunsun Mooncb799442016-01-15 20:03:18 -0800512 */
513 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
514 checkNotNull(node);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700515 OvsdbNodeId ovsdb = new OvsdbNodeId(
516 node.hostMgmtIp().ip(), node.ovsdbPort().toInt());
517 return ovsdbController.getOvsdbClient(ovsdb);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800518 }
519
Hyunsun Mooncb799442016-01-15 20:03:18 -0800520 private void createIntegrationBridge(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700521 Device device = deviceService.getDevice(node.ovsdbId());
522 if (device == null || !device.is(BridgeConfig.class)) {
523 log.error("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800524 return;
525 }
526
Hyunsun Moon81a13562016-08-04 13:48:08 -0700527 String dpid = node.integrationBridgeId().toString().substring(DPID_BEGIN);
528 BridgeDescription bridgeDesc = DefaultBridgeDescription.builder()
529 .name(INTEGRATION_BRIDGE)
530 .failMode(BridgeDescription.FailMode.SECURE)
531 .datapathId(dpid)
532 .disableInBand()
533 .controllers(controllers)
534 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800535
Hyunsun Moon81a13562016-08-04 13:48:08 -0700536 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
537 bridgeConfig.addBridge(bridgeDesc);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800538 }
539
Hyunsun Mooncb799442016-01-15 20:03:18 -0800540 private void createTunnelInterface(CordVtnNode node) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700541 Device device = deviceService.getDevice(node.ovsdbId());
542 if (device == null || !device.is(InterfaceConfig.class)) {
543 log.error("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800544 return;
545 }
546
Hyunsun Moon81a13562016-08-04 13:48:08 -0700547 TunnelDescription tunnelDesc = DefaultTunnelDescription.builder()
548 .deviceId(INTEGRATION_BRIDGE)
549 .ifaceName(DEFAULT_TUNNEL)
550 .type(VXLAN)
551 .remote(TunnelEndPoints.flowTunnelEndpoint())
552 .key(TunnelKeys.flowTunnelKey())
553 .build();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800554
Hyunsun Moon81a13562016-08-04 13:48:08 -0700555 InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
556 ifaceConfig.addTunnelMode(DEFAULT_TUNNEL, tunnelDesc);
Hyunsun Moonbd572c12016-01-21 00:54:52 -0800557 }
558
Hyunsun Moon81a13562016-08-04 13:48:08 -0700559 private void addSystemInterface(CordVtnNode node, String ifaceName) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700560 Session session = connect(node.sshInfo());
Hyunsun Moon81a13562016-08-04 13:48:08 -0700561 if (session == null || !isInterfaceUp(session, ifaceName)) {
562 log.warn("Interface {} is not available on {}", ifaceName, node.hostname());
563 disconnect(session);
564 return;
565 } else {
566 disconnect(session);
567 }
568
569 Device device = deviceService.getDevice(node.ovsdbId());
570 if (!device.is(BridgeConfig.class)) {
571 log.error("BridgeConfig is not supported for {}", node.ovsdbId());
Hyunsun Moon479b7752016-05-06 20:13:28 -0700572 return;
573 }
574
Hyunsun Moon81a13562016-08-04 13:48:08 -0700575 BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
576 bridgeConfig.addPort(BridgeName.bridgeName(INTEGRATION_BRIDGE), ifaceName);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800577 }
578
579 /**
580 * Flushes IP address from data plane interface and adds data plane IP address
581 * to integration bridge.
582 *
583 * @param node cordvtn node
584 */
585 private void setIpAddress(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700586 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800587 if (session == null) {
588 log.debug("Failed to SSH to {}", node.hostname());
589 return;
590 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700591 getCurrentIps(session, INTEGRATION_BRIDGE).stream()
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700592 .filter(ip -> !ip.equals(node.localMgmtIp().ip()))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700593 .filter(ip -> !ip.equals(node.dataIp().ip()))
594 .forEach(ip -> deleteIp(session, ip, INTEGRATION_BRIDGE));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700595
Hyunsun Moon81a13562016-08-04 13:48:08 -0700596 boolean result = flushIp(session, node.dataIface()) &&
597 setInterfaceUp(session, node.dataIface()) &&
598 addIp(session, node.dataIp(), INTEGRATION_BRIDGE) &&
599 addIp(session, node.localMgmtIp(), INTEGRATION_BRIDGE) &&
600 setInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800601
Hyunsun Moon479b7752016-05-06 20:13:28 -0700602 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800603 if (result) {
604 setNodeState(node, NodeState.COMPLETE);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800605 }
606 }
607
Hyunsun Moon81a13562016-08-04 13:48:08 -0700608 private boolean isIntegrationBridgeCreated(CordVtnNode node) {
609 return deviceService.getDevice(node.integrationBridgeId()) != null &&
610 deviceService.isAvailable(node.integrationBridgeId());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800611 }
612
Hyunsun Moon81a13562016-08-04 13:48:08 -0700613 private boolean isIfaceCreated(CordVtnNode node, String ifaceName) {
614 if (Strings.isNullOrEmpty(ifaceName)) {
615 return false;
616 }
617 return deviceService.getPorts(node.integrationBridgeId()).stream()
Hyunsun Moon851e57f2017-02-23 19:38:40 +0900618 .anyMatch(p -> portName(p).contains(ifaceName) && p.isEnabled());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800619 }
620
621 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800622 * Checks if the IP addresses are correctly set.
623 *
624 * @param node cordvtn node
625 * @return true if the IP is set, false otherwise
626 */
627 private boolean isIpAddressSet(CordVtnNode node) {
Hyunsun Moon479b7752016-05-06 20:13:28 -0700628 Session session = connect(node.sshInfo());
Hyunsun Moon126171d2016-02-09 01:55:48 -0800629 if (session == null) {
630 log.debug("Failed to SSH to {}", node.hostname());
631 return false;
632 }
633
Hyunsun Moon81a13562016-08-04 13:48:08 -0700634 Set<IpAddress> intBrIps = getCurrentIps(session, INTEGRATION_BRIDGE);
635 boolean result = getCurrentIps(session, node.dataIface()).isEmpty() &&
636 isInterfaceUp(session, node.dataIface()) &&
637 intBrIps.contains(node.dataIp().ip()) &&
Hyunsun Moon126171d2016-02-09 01:55:48 -0800638 intBrIps.contains(node.localMgmtIp().ip()) &&
Hyunsun Moon81a13562016-08-04 13:48:08 -0700639 isInterfaceUp(session, INTEGRATION_BRIDGE);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800640
Hyunsun Moon479b7752016-05-06 20:13:28 -0700641 disconnect(session);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800642 return result;
643 }
644
645 /**
Hyunsun Mooncb799442016-01-15 20:03:18 -0800646 * Returns connect point of a given port.
647 *
648 * @param port port
649 * @return connect point
650 */
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700651 private ConnectPoint connectPoint(Port port) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800652 return new ConnectPoint(port.element().id(), port.number());
653 }
654
655 /**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700656 * Returns cordvtn node associated with a given OVSDB device.
657 *
658 * @param ovsdbId OVSDB device id
659 * @return cordvtn node, null if it fails to find the node
660 */
661 private CordVtnNode nodeByOvsdbId(DeviceId ovsdbId) {
662 return getNodes().stream()
663 .filter(node -> node.ovsdbId().equals(ovsdbId))
664 .findFirst().orElse(null);
665 }
666
667 /**
668 * Returns cordvtn node associated with a given integration bridge.
669 *
670 * @param bridgeId device id of integration bridge
671 * @return cordvtn node, null if it fails to find the node
672 */
673 private CordVtnNode nodeByBridgeId(DeviceId bridgeId) {
674 return getNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700675 .filter(node -> node.integrationBridgeId().equals(bridgeId))
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700676 .findFirst().orElse(null);
677 }
678
679 /**
680 * Returns port name.
681 *
682 * @param port port
683 * @return port name
684 */
685 private String portName(Port port) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700686 return port.annotations().value(PORT_NAME);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700687 }
688
Hyunsun Mooncb799442016-01-15 20:03:18 -0800689 private class OvsdbHandler implements ConnectionHandler<Device> {
690
691 @Override
692 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700693 CordVtnNode node = nodeByOvsdbId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800694 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800695 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800696 } else {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900697 log.info("{} is detected on unregistered node, ignore it.", device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800698 }
699 }
700
701 @Override
702 public void disconnected(Device device) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700703 log.debug("Device {} is disconnected", device.id());
704 adminService.removeDevice(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800705 }
706 }
707
708 private class BridgeHandler implements ConnectionHandler<Device> {
709
710 @Override
711 public void connected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700712 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800713 if (node != null) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800714 setNodeState(node, getNodeState(node));
Hyunsun Mooncb799442016-01-15 20:03:18 -0800715 } else {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900716 log.info("{} is detected on unregistered node, ignore it.", device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800717 }
718 }
719
720 @Override
721 public void disconnected(Device device) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700722 CordVtnNode node = nodeByBridgeId(device.id());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800723 if (node != null) {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700724 log.warn("Integration Bridge is disconnected from {}", node.hostname());
Hyunsun Mooncb799442016-01-15 20:03:18 -0800725 setNodeState(node, NodeState.INCOMPLETE);
726 }
727 }
728
729 /**
730 * Handles port added situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800731 * If the added port is tunnel or data plane interface, proceed to the remaining
732 * node initialization. Otherwise, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800733 *
734 * @param port port
735 */
736 public void portAdded(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700737 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
738 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800739 if (node == null) {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900740 log.info("{} is added to unregistered node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800741 return;
742 }
743
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700744 if (node.systemIfaces().contains(portName)) {
Hyunsun Moon126171d2016-02-09 01:55:48 -0800745 setNodeState(node, getNodeState(node));
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700746 } else if (isNodeStateComplete(node)) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900747 // TODO move this logic to InstanceManager
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700748 instanceService.addInstance(connectPoint(port));
749 } else {
750 log.warn("Instance is detected on incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800751 }
752 }
753
754 /**
755 * Handles port removed situation.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800756 * If the removed port is tunnel or data plane interface, proceed to the remaining
757 * node initialization.Others, do nothing.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800758 *
759 * @param port port
760 */
761 public void portRemoved(Port port) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700762 CordVtnNode node = nodeByBridgeId((DeviceId) port.element().id());
763 String portName = portName(port);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800764 if (node == null) {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900765 log.info("{} is removed from unregistered node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800766 return;
767 }
768
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700769 if (node.systemIfaces().contains(portName)) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800770 setNodeState(node, NodeState.INCOMPLETE);
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700771 } else if (isNodeStateComplete(node)) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900772 // TODO move this logic to InstanceManager
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700773 instanceService.removeInstance(connectPoint(port));
774 } else {
775 log.warn("VM is vanished from incomplete node, ignore it.", portName);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800776 }
777 }
778 }
779
780 private class InternalDeviceListener implements DeviceListener {
781
782 @Override
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900783 public boolean isRelevant(DeviceEvent event) {
784 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
785 return Objects.equals(localNodeId, leaderNodeId);
786 }
787
788 @Override
Hyunsun Mooncb799442016-01-15 20:03:18 -0800789 public void event(DeviceEvent event) {
790
791 Device device = event.subject();
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900792 ConnectionHandler<Device> handler = device.type().equals(SWITCH) ?
793 bridgeHandler : ovsdbHandler;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800794
795 switch (event.type()) {
796 case PORT_ADDED:
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900797 eventExecutor.execute(() -> {
798 log.info("Port {} is added to {}",
799 event.port().annotations().value(PORT_NAME),
800 event.subject().id());
801 bridgeHandler.portAdded(event.port());
802 });
Hyunsun Mooncb799442016-01-15 20:03:18 -0800803 break;
804 case PORT_UPDATED:
Hyunsun Moon33a59372017-02-21 17:27:43 +0900805 if (event.port().isEnabled()) {
806 eventExecutor.execute(() -> {
807 log.info("Port {} is added to {}",
808 event.port().annotations().value(PORT_NAME),
809 event.subject().id());
810 bridgeHandler.portAdded(event.port());
811 });
812 } else {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900813 eventExecutor.execute(() -> {
814 log.info("Port {} is removed from {}",
Hyunsun Moon33a59372017-02-21 17:27:43 +0900815 event.port().annotations().value(PORT_NAME),
816 event.subject().id());
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900817 bridgeHandler.portRemoved(event.port());
818 });
Hyunsun Mooncb799442016-01-15 20:03:18 -0800819 }
820 break;
Hyunsun Moon9c2a0982017-03-16 15:07:06 +0900821 case PORT_REMOVED:
822 eventExecutor.execute(() -> {
823 log.info("Port {} is removed from {}",
824 event.port().annotations().value(PORT_NAME),
825 event.subject().id());
826 bridgeHandler.portRemoved(event.port());
827 });
828 break;
Hyunsun Mooncb799442016-01-15 20:03:18 -0800829 case DEVICE_ADDED:
830 case DEVICE_AVAILABILITY_CHANGED:
831 if (deviceService.isAvailable(device.id())) {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900832 eventExecutor.execute(() -> {
833 log.info("Device {} is connected",
834 event.subject().id());
835 handler.connected(device);
836 });
Hyunsun Mooncb799442016-01-15 20:03:18 -0800837 } else {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900838 eventExecutor.execute(() -> {
839 log.info("Device {} is disconnected",
840 event.subject().id());
841 handler.disconnected(device);
842 });
Hyunsun Mooncb799442016-01-15 20:03:18 -0800843 }
844 break;
845 default:
846 break;
847 }
848 }
849 }
850
851 /**
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800852 * Reads cordvtn nodes from config file.
Hyunsun Mooncb799442016-01-15 20:03:18 -0800853 */
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800854 private void readNodes() {
855 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
856 if (!Objects.equals(localNodeId, leaderNodeId)) {
857 // do not allow to proceed without leadership
858 return;
859 }
860
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800861 CordVtnConfig config = configService.getConfig(appId, CordVtnConfig.class);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800862 if (config == null) {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800863 log.debug("No configuration found");
Hyunsun Mooncb799442016-01-15 20:03:18 -0800864 return;
865 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800866 config.cordVtnNodes().forEach(this::addOrUpdateNode);
Hyunsun Mooncb799442016-01-15 20:03:18 -0800867 }
868
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800869 private void readControllers() {
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800870 CordVtnConfig config = configService.getConfig(appId, CordVtnConfig.class);
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800871 if (config == null) {
872 log.debug("No configuration found");
873 return;
874 }
875 controllers = config.controllers();
Hyunsun Moon851e57f2017-02-23 19:38:40 +0900876 controllers.forEach(ctrl -> {
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800877 log.debug("Added controller {}:{}", ctrl.ip(), ctrl.port());
878 });
879 }
880
Hyunsun Mooncb799442016-01-15 20:03:18 -0800881 private class InternalConfigListener implements NetworkConfigListener {
882
883 @Override
884 public void event(NetworkConfigEvent event) {
885 if (!event.configClass().equals(CordVtnConfig.class)) {
886 return;
887 }
888
889 switch (event.type()) {
890 case CONFIG_ADDED:
Hyunsun Mooncb799442016-01-15 20:03:18 -0800891 case CONFIG_UPDATED:
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800892 eventExecutor.execute(() -> {
893 readControllers();
894 readNodes();
895 });
Hyunsun Mooncb799442016-01-15 20:03:18 -0800896 break;
897 default:
898 break;
899 }
900 }
901 }
Hyunsun Moonff55e812016-03-10 12:40:16 -0800902
903 private class InternalMapListener implements MapEventListener<String, CordVtnNode> {
904
905 @Override
906 public void event(MapEvent<String, CordVtnNode> event) {
907 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
908 if (!Objects.equals(localNodeId, leaderNodeId)) {
909 // do not allow to proceed without leadership
910 return;
911 }
912
913 CordVtnNode oldNode;
914 CordVtnNode newNode;
915
916 switch (event.type()) {
Jonathan Hartaf6f60a2017-03-06 13:45:17 -0800917 case UPDATE:
918 oldNode = event.oldValue().value();
919 newNode = event.newValue().value();
Hyunsun Moonff55e812016-03-10 12:40:16 -0800920
Jonathan Hartaf6f60a2017-03-06 13:45:17 -0800921 log.info("Reloaded {}", newNode.hostname());
922 if (!newNode.equals(oldNode)) {
923 log.debug("New node: {}", newNode);
924 }
925 // performs init procedure even if the node is not changed
926 // for robustness since it's no harm to run init procedure
927 // multiple times
928 initNode(newNode);
929 break;
930 case INSERT:
931 newNode = event.newValue().value();
932 log.info("Added {}", newNode.hostname());
933 initNode(newNode);
934 break;
935 case REMOVE:
936 oldNode = event.oldValue().value();
937 log.info("Removed {}", oldNode.hostname());
938 break;
939 default:
940 break;
Hyunsun Moonff55e812016-03-10 12:40:16 -0800941 }
942 }
943 }
Hyunsun Mooncb799442016-01-15 20:03:18 -0800944}