blob: 1a56b42a1e15f9d4fcadeb31360c03a810366dba [file] [log] [blame]
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001/*
2 * Copyright 2014-2015 Open Networking Laboratory
3 *
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 */
16package org.onosproject.cordvtn;
17
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080018import com.google.common.collect.Maps;
Hyunsun Moon1f145552015-10-08 22:25:30 -070019import com.google.common.collect.Sets;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070020import 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 Moon42c7b4e2016-01-11 15:30:42 -080026import org.onlab.packet.Ethernet;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080027import org.onlab.packet.Ip4Address;
Hyunsun Moond772f342015-10-28 20:28:16 -070028import org.onlab.util.ItemNotFoundException;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080029import org.onlab.packet.IpAddress;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070030import org.onlab.util.KryoNamespace;
Hyunsun Moon1f145552015-10-08 22:25:30 -070031import org.onosproject.cluster.ClusterService;
32import org.onosproject.core.ApplicationId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070033import org.onosproject.core.CoreService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080034import org.onosproject.mastership.MastershipService;
Hyunsun Moond772f342015-10-28 20:28:16 -070035import org.onosproject.net.DefaultAnnotations;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070036import org.onosproject.net.Device;
37import org.onosproject.net.DeviceId;
38import org.onosproject.net.Host;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080039import org.onosproject.net.HostId;
Hyunsun Moon8539b042015-11-07 22:08:43 -080040import org.onosproject.net.Port;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080041import org.onosproject.net.PortNumber;
Hyunsun Moond772f342015-10-28 20:28:16 -070042import org.onosproject.net.behaviour.BridgeConfig;
43import org.onosproject.net.behaviour.BridgeName;
Hyunsun Moon1f145552015-10-08 22:25:30 -070044import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moond772f342015-10-28 20:28:16 -070045import org.onosproject.net.behaviour.DefaultTunnelDescription;
46import org.onosproject.net.behaviour.TunnelConfig;
47import org.onosproject.net.behaviour.TunnelDescription;
48import org.onosproject.net.behaviour.TunnelName;
Hyunsun Moon8539b042015-11-07 22:08:43 -080049import org.onosproject.net.device.DeviceAdminService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070050import org.onosproject.net.device.DeviceEvent;
51import org.onosproject.net.device.DeviceListener;
52import org.onosproject.net.device.DeviceService;
Hyunsun Moond772f342015-10-28 20:28:16 -070053import org.onosproject.net.driver.DriverHandler;
54import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080055import org.onosproject.net.flow.FlowRuleService;
56import org.onosproject.net.group.GroupService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070057import org.onosproject.net.host.HostEvent;
58import org.onosproject.net.host.HostListener;
59import org.onosproject.net.host.HostService;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -080060import org.onosproject.net.packet.PacketContext;
61import org.onosproject.net.packet.PacketProcessor;
62import org.onosproject.net.packet.PacketService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080063import org.onosproject.openstackswitching.OpenstackNetwork;
64import org.onosproject.openstackswitching.OpenstackPort;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080065import org.onosproject.openstackswitching.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080066import org.onosproject.openstackswitching.OpenstackSwitchingService;
Hyunsun Moon1f145552015-10-08 22:25:30 -070067import org.onosproject.ovsdb.controller.OvsdbClientService;
68import org.onosproject.ovsdb.controller.OvsdbController;
69import org.onosproject.ovsdb.controller.OvsdbNodeId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070070import org.onosproject.store.serializers.KryoNamespaces;
Hyunsun Moon1f145552015-10-08 22:25:30 -070071import org.onosproject.store.service.ConsistentMap;
72import org.onosproject.store.service.Serializer;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070073import org.onosproject.store.service.StorageService;
74import org.slf4j.Logger;
75
Hyunsun Moon1f145552015-10-08 22:25:30 -070076import java.util.ArrayList;
77import java.util.HashMap;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070078import java.util.List;
Hyunsun Moon1f145552015-10-08 22:25:30 -070079import java.util.Map;
Hyunsun Moon523d9762015-10-19 12:38:21 -070080import java.util.NoSuchElementException;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080081import java.util.Objects;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080082import java.util.Set;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070083import java.util.concurrent.ExecutorService;
84import java.util.concurrent.Executors;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080085import java.util.stream.Collectors;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070086
Hyunsun Moon1f145552015-10-08 22:25:30 -070087import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070088import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon2b530322015-09-23 13:24:35 -070089import static org.onosproject.net.Device.Type.SWITCH;
Hyunsun Moond772f342015-10-28 20:28:16 -070090import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070091import static org.slf4j.LoggerFactory.getLogger;
92
93/**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080094 * Provisions virtual tenant networks with service chaining capability
95 * in OpenStack environment.
Hyunsun Moond0e932a2015-09-15 22:39:16 -070096 */
97@Component(immediate = true)
98@Service
99public class CordVtn implements CordVtnService {
100
101 protected final Logger log = getLogger(getClass());
102
Hyunsun Moon2b530322015-09-23 13:24:35 -0700103 private static final int NUM_THREADS = 1;
104 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
105 .register(KryoNamespaces.API)
Hyunsun Moon8539b042015-11-07 22:08:43 -0800106 .register(CordVtnNode.class)
107 .register(NodeState.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800108 private static final String DEFAULT_BRIDGE = "br-int";
109 private static final String VPORT_PREFIX = "tap";
Hyunsun Moon523d9762015-10-19 12:38:21 -0700110 private static final String DEFAULT_TUNNEL = "vxlan";
111 private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700112 {
113 put("key", "flow");
Hyunsun Moon1f145552015-10-08 22:25:30 -0700114 put("remote_ip", "flow");
115 }
116 };
117 private static final int DPID_BEGIN = 3;
118 private static final int OFPORT = 6653;
Hyunsun Moon2b530322015-09-23 13:24:35 -0700119
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected CoreService coreService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected StorageService storageService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700127 protected DeviceService deviceService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected HostService hostService;
131
Hyunsun Moon1f145552015-10-08 22:25:30 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond772f342015-10-28 20:28:16 -0700133 protected DriverService driverService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon8539b042015-11-07 22:08:43 -0800136 protected DeviceAdminService adminService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800139 protected FlowRuleService flowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800142 protected PacketService packetService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon1f145552015-10-08 22:25:30 -0700145 protected OvsdbController controller;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected ClusterService clusterService;
149
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800151 protected MastershipService mastershipService;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
154 protected GroupService groupService;
155
156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800157 protected OpenstackSwitchingService openstackService;
158
Hyunsun Moon2b530322015-09-23 13:24:35 -0700159 private final ExecutorService eventExecutor = Executors
160 .newFixedThreadPool(NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700161
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700162 private final DeviceListener deviceListener = new InternalDeviceListener();
163 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800164 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700165
166 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700167 private final BridgeHandler bridgeHandler = new BridgeHandler();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700168 private final VmHandler vmHandler = new VmHandler();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700169
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800170 private ApplicationId appId;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800171 private ConsistentMap<CordVtnNode, NodeState> nodeStore;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800172 private Map<HostId, OpenstackNetwork> hostNetMap = Maps.newHashMap();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800173 private CordVtnRuleInstaller ruleInstaller;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800174 private CordVtnArpProxy arpProxy;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800175
176 private enum NodeState {
177
178 INIT {
179 @Override
180 public void process(CordVtn cordVtn, CordVtnNode node) {
181 cordVtn.connect(node);
182 }
183 },
184 OVSDB_CONNECTED {
185 @Override
186 public void process(CordVtn cordVtn, CordVtnNode node) {
187 if (!cordVtn.getOvsdbConnectionState(node)) {
188 cordVtn.connect(node);
189 } else {
190 cordVtn.createIntegrationBridge(node);
191 }
192 }
193 },
194 BRIDGE_CREATED {
195 @Override
196 public void process(CordVtn cordVtn, CordVtnNode node) {
197 if (!cordVtn.getOvsdbConnectionState(node)) {
198 cordVtn.connect(node);
199 } else {
200 cordVtn.createTunnelInterface(node);
201 }
202 }
203 },
204 COMPLETE {
205 @Override
206 public void process(CordVtn cordVtn, CordVtnNode node) {
207 cordVtn.postInit(node);
208 }
209 },
210 INCOMPLETE {
211 @Override
212 public void process(CordVtn cordVtn, CordVtnNode node) {
213 }
214 };
215
216 public abstract void process(CordVtn cordVtn, CordVtnNode node);
217 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700218
219 @Activate
220 protected void activate() {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800221 appId = coreService.registerApplication("org.onosproject.cordvtn");
Hyunsun Moon8539b042015-11-07 22:08:43 -0800222 nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder()
Hyunsun Moon1f145552015-10-08 22:25:30 -0700223 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700224 .withName("cordvtn-nodestore")
Hyunsun Moon1f145552015-10-08 22:25:30 -0700225 .withApplicationId(appId)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700226 .build();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700227
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800228 ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
229 deviceService,
230 driverService,
231 groupService,
232 mastershipService,
233 DEFAULT_TUNNEL);
234
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800235 arpProxy = new CordVtnArpProxy(appId, packetService);
236 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
237 arpProxy.requestPacket();
238
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700239 deviceService.addListener(deviceListener);
240 hostService.addListener(hostListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700241
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700242 log.info("Started");
243 }
244
245 @Deactivate
246 protected void deactivate() {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700247 deviceService.removeListener(deviceListener);
248 hostService.removeListener(hostListener);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800249 packetService.removeProcessor(packetProcessor);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700250
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700251 eventExecutor.shutdown();
Hyunsun Moon1f145552015-10-08 22:25:30 -0700252 nodeStore.clear();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700253
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700254 log.info("Stopped");
255 }
256
257 @Override
Hyunsun Moon8539b042015-11-07 22:08:43 -0800258 public void addNode(CordVtnNode node) {
259 checkNotNull(node);
Hyunsun Moon523d9762015-10-19 12:38:21 -0700260
Hyunsun Moon8539b042015-11-07 22:08:43 -0800261 nodeStore.putIfAbsent(node, checkNodeState(node));
262 initNode(node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700263 }
264
265 @Override
Hyunsun Moon8539b042015-11-07 22:08:43 -0800266 public void deleteNode(CordVtnNode node) {
267 checkNotNull(node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700268
Hyunsun Moon8539b042015-11-07 22:08:43 -0800269 if (getOvsdbConnectionState(node)) {
270 disconnect(node);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700271 }
Hyunsun Moon523d9762015-10-19 12:38:21 -0700272
Hyunsun Moon8539b042015-11-07 22:08:43 -0800273 nodeStore.remove(node);
Hyunsun Moon523d9762015-10-19 12:38:21 -0700274 }
275
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700276 @Override
277 public int getNodeCount() {
278 return nodeStore.size();
279 }
280
281 @Override
Hyunsun Moon8539b042015-11-07 22:08:43 -0800282 public List<CordVtnNode> getNodes() {
283 List<CordVtnNode> nodes = new ArrayList<>();
284 nodes.addAll(nodeStore.keySet());
285 return nodes;
286 }
287
288 @Override
289 public void initNode(CordVtnNode node) {
290 checkNotNull(node);
291
292 if (!nodeStore.containsKey(node)) {
293 log.warn("Node {} does not exist, add node first", node.hostname());
294 return;
295 }
296
Hyunsun Moonbaf70542015-12-16 14:29:36 -0800297 NodeState state = checkNodeState(node);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800298 state.process(this, node);
299 }
300
301 @Override
302 public boolean getNodeInitState(CordVtnNode node) {
303 checkNotNull(node);
304
305 NodeState state = getNodeState(node);
306 return state != null && state.equals(NodeState.COMPLETE);
307 }
308
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800309 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800310 public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
311 CordService tService = getCordService(tServiceId);
312 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800313
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800314 if (tService == null || pService == null) {
315 log.error("Failed to create CordService for {}", tServiceId.id());
316 return;
317 }
318
319 ruleInstaller.populateServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800320 }
321
322 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800323 public void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
324 CordService tService = getCordService(tServiceId);
325 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800326
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800327 if (tService == null || pService == null) {
328 log.error("Failed to create CordService for {}", tServiceId.id());
329 return;
330 }
331
332 ruleInstaller.removeServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800333 }
334
Hyunsun Moon8539b042015-11-07 22:08:43 -0800335 /**
336 * Returns state of a given cordvtn node.
337 *
338 * @param node cordvtn node
339 * @return node state, or null if no such node exists
340 */
341 private NodeState getNodeState(CordVtnNode node) {
342 checkNotNull(node);
343
344 try {
345 return nodeStore.get(node).value();
346 } catch (NullPointerException e) {
347 log.error("Failed to get state of {}", node.hostname());
Hyunsun Moon1f145552015-10-08 22:25:30 -0700348 return null;
349 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700350 }
351
Hyunsun Moon8539b042015-11-07 22:08:43 -0800352 /**
353 * Sets a new state for a given cordvtn node.
354 *
355 * @param node cordvtn node
356 * @param newState new node state
357 */
358 private void setNodeState(CordVtnNode node, NodeState newState) {
359 checkNotNull(node);
360
361 log.info("Changed {} state: {}", node.hostname(), newState.toString());
362
363 nodeStore.put(node, newState);
364 newState.process(this, node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700365 }
366
Hyunsun Moon8539b042015-11-07 22:08:43 -0800367 /**
368 * Checks current state of a given cordvtn node and returns it.
369 *
370 * @param node cordvtn node
371 * @return node state
372 */
373 private NodeState checkNodeState(CordVtnNode node) {
374 checkNotNull(node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700375
Hyunsun Moon8539b042015-11-07 22:08:43 -0800376 if (checkIntegrationBridge(node) && checkTunnelInterface(node)) {
377 return NodeState.COMPLETE;
378 } else if (checkIntegrationBridge(node)) {
379 return NodeState.BRIDGE_CREATED;
380 } else if (getOvsdbConnectionState(node)) {
381 return NodeState.OVSDB_CONNECTED;
Hyunsun Moon1f145552015-10-08 22:25:30 -0700382 } else {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800383 return NodeState.INIT;
Hyunsun Moon1f145552015-10-08 22:25:30 -0700384 }
385 }
386
Hyunsun Moon8539b042015-11-07 22:08:43 -0800387 /**
388 * Performs tasks after node initialization.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800389 * First disconnect unnecessary OVSDB connection and then installs flow rules
390 * for existing VMs if there are any.
Hyunsun Moon8539b042015-11-07 22:08:43 -0800391 *
392 * @param node cordvtn node
393 */
394 private void postInit(CordVtnNode node) {
395 disconnect(node);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800396
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800397 ruleInstaller.init(node.intBrId(), getTunnelPort(node.intBrId()));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800398 hostService.getConnectedHosts(node.intBrId())
399 .stream()
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800400 .forEach(vmHandler::connected);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800401
402 log.info("Finished initializing {}", node.hostname());
Hyunsun Moon8539b042015-11-07 22:08:43 -0800403 }
404
405 /**
406 * Returns connection state of OVSDB server for a given node.
407 *
408 * @param node cordvtn node
409 * @return true if it is connected, false otherwise
410 */
411 private boolean getOvsdbConnectionState(CordVtnNode node) {
412 checkNotNull(node);
413
414 OvsdbClientService ovsdbClient = getOvsdbClient(node);
415 return deviceService.isAvailable(node.ovsdbId()) &&
416 ovsdbClient != null && ovsdbClient.isConnected();
417 }
418
419 /**
420 * Connects to OVSDB server for a given node.
421 *
422 * @param node cordvtn node
423 */
424 private void connect(CordVtnNode node) {
425 checkNotNull(node);
426
427 if (!nodeStore.containsKey(node)) {
428 log.warn("Node {} does not exist", node.hostname());
429 return;
430 }
431
432 if (!getOvsdbConnectionState(node)) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800433 controller.connect(node.ovsdbIp(), node.ovsdbPort());
434 }
435 }
436
437 /**
438 * Disconnects OVSDB server for a given node.
439 *
440 * @param node cordvtn node
441 */
442 private void disconnect(CordVtnNode node) {
443 checkNotNull(node);
444
445 if (!nodeStore.containsKey(node)) {
446 log.warn("Node {} does not exist", node.hostname());
447 return;
448 }
449
450 if (getOvsdbConnectionState(node)) {
451 OvsdbClientService ovsdbClient = getOvsdbClient(node);
452 ovsdbClient.disconnect();
453 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800454 }
455
456 /**
457 * Returns cordvtn node associated with a given OVSDB device.
458 *
459 * @param ovsdbId OVSDB device id
460 * @return cordvtn node, null if it fails to find the node
461 */
462 private CordVtnNode getNodeByOvsdbId(DeviceId ovsdbId) {
463 try {
464 return getNodes().stream()
465 .filter(node -> node.ovsdbId().equals(ovsdbId))
466 .findFirst().get();
467 } catch (NoSuchElementException e) {
468 log.debug("Couldn't find node information for {}", ovsdbId);
469 return null;
470 }
471 }
472
473 /**
474 * Returns cordvtn node associated with a given integration bridge.
475 *
476 * @param bridgeId device id of integration bridge
477 * @return cordvtn node, null if it fails to find the node
478 */
479 private CordVtnNode getNodeByBridgeId(DeviceId bridgeId) {
480 try {
481 return getNodes().stream()
482 .filter(node -> node.intBrId().equals(bridgeId))
483 .findFirst().get();
484 } catch (NoSuchElementException e) {
485 log.debug("Couldn't find node information for {}", bridgeId);
486 return null;
487 }
488 }
489
490 /**
491 * Returns OVSDB client for a given node.
492 *
493 * @param node cordvtn node
494 * @return OVSDB client, or null if it fails to get OVSDB client
495 */
496 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
497 checkNotNull(node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700498
499 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
Hyunsun Moon8539b042015-11-07 22:08:43 -0800500 new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt()));
Hyunsun Moon1f145552015-10-08 22:25:30 -0700501 if (ovsdbClient == null) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800502 log.debug("Couldn't find OVSDB client for {}", node.hostname());
Hyunsun Moon1f145552015-10-08 22:25:30 -0700503 }
504 return ovsdbClient;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700505 }
506
Hyunsun Moon8539b042015-11-07 22:08:43 -0800507 /**
508 * Creates an integration bridge for a given node.
509 *
510 * @param node cordvtn node
511 */
512 private void createIntegrationBridge(CordVtnNode node) {
513 if (checkIntegrationBridge(node)) {
514 return;
515 }
516
Hyunsun Moon523d9762015-10-19 12:38:21 -0700517 List<ControllerInfo> controllers = new ArrayList<>();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800518 Sets.newHashSet(clusterService.getNodes()).stream()
Hyunsun Moon523d9762015-10-19 12:38:21 -0700519 .forEach(controller -> {
520 ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
521 controllers.add(ctrlInfo);
522 });
Hyunsun Moon8539b042015-11-07 22:08:43 -0800523 String dpid = node.intBrId().toString().substring(DPID_BEGIN);
Hyunsun Moon523d9762015-10-19 12:38:21 -0700524
Hyunsun Moon523d9762015-10-19 12:38:21 -0700525 try {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800526 DriverHandler handler = driverService.createHandler(node.ovsdbId());
Hyunsun Moond772f342015-10-28 20:28:16 -0700527 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800528 bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE), dpid, controllers);
Hyunsun Moond772f342015-10-28 20:28:16 -0700529 } catch (ItemNotFoundException e) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800530 log.warn("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Moond772f342015-10-28 20:28:16 -0700531 }
532 }
533
Hyunsun Moon8539b042015-11-07 22:08:43 -0800534 /**
535 * Creates tunnel interface to the integration bridge for a given node.
536 *
537 * @param node cordvtn node
538 */
539 private void createTunnelInterface(CordVtnNode node) {
540 if (checkTunnelInterface(node)) {
541 return;
542 }
543
Hyunsun Moond772f342015-10-28 20:28:16 -0700544 DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder();
545 for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
546 optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
547 }
548 TunnelDescription description =
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800549 new DefaultTunnelDescription(null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL),
Hyunsun Moond772f342015-10-28 20:28:16 -0700550 optionBuilder.build());
551 try {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800552 DriverHandler handler = driverService.createHandler(node.ovsdbId());
Hyunsun Moond772f342015-10-28 20:28:16 -0700553 TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800554 tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE), description);
Hyunsun Moond772f342015-10-28 20:28:16 -0700555 } catch (ItemNotFoundException e) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800556 log.warn("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Moond772f342015-10-28 20:28:16 -0700557 }
558 }
559
Hyunsun Moon8539b042015-11-07 22:08:43 -0800560 /**
561 * Checks if integration bridge exists and available.
562 *
563 * @param node cordvtn node
564 * @return true if the bridge is available, false otherwise
565 */
566 private boolean checkIntegrationBridge(CordVtnNode node) {
567 return (deviceService.getDevice(node.intBrId()) != null
568 && deviceService.isAvailable(node.intBrId()));
569 }
570
571 /**
572 * Checks if tunnel interface exists.
573 *
574 * @param node cordvtn node
575 * @return true if the interface exists, false otherwise
576 */
577 private boolean checkTunnelInterface(CordVtnNode node) {
Hyunsun Moond772f342015-10-28 20:28:16 -0700578 try {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800579 deviceService.getPorts(node.intBrId())
580 .stream()
581 .filter(p -> p.annotations().value("portName").contains(DEFAULT_TUNNEL)
582 && p.isEnabled())
Hyunsun Moond772f342015-10-28 20:28:16 -0700583 .findAny().get();
Hyunsun Moon8539b042015-11-07 22:08:43 -0800584 return true;
585 } catch (NoSuchElementException e) {
Hyunsun Moon523d9762015-10-19 12:38:21 -0700586 return false;
587 }
Hyunsun Moon523d9762015-10-19 12:38:21 -0700588 }
589
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800590 /**
591 * Returns tunnel port of the device.
592 *
593 * @param bridgeId device id
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800594 * @return port number, null if no tunnel port exists on a given device
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800595 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800596 private PortNumber getTunnelPort(DeviceId bridgeId) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800597 try {
598 return deviceService.getPorts(bridgeId).stream()
599 .filter(p -> p.annotations().value("portName").contains(DEFAULT_TUNNEL)
600 && p.isEnabled())
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800601 .findFirst().get().number();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800602 } catch (NoSuchElementException e) {
603 return null;
604 }
605 }
606
607 /**
608 * Returns remote ip address for tunneling.
609 *
610 * @param bridgeId device id
611 * @return ip address, null if no such device exists
612 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800613 private Ip4Address getRemoteIp(DeviceId bridgeId) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800614 CordVtnNode node = getNodeByBridgeId(bridgeId);
615 if (node != null) {
616 // TODO get data plane IP for tunneling
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800617 return node.ovsdbIp().getIp4Address();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800618 } else {
619 return null;
620 }
621 }
622
623 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800624 * Returns OpenStack port associated with a given host.
625 *
626 * @param host host
627 * @return OpenStack port, or null if no port has been found
628 */
629 private OpenstackPort getOpenstackPortByHost(Host host) {
630 Port port = deviceService.getPort(host.location().deviceId(),
631 host.location().port());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800632 if (port == null) {
633 log.debug("Failed to get port for {}", host.id());
634 return null;
635 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800636 return openstackService.port(port);
637 }
638
639 /**
640 * Returns OpenStack network associated with a given host.
641 *
642 * @param host host
643 * @return OpenStack network, or null if no network has been found
644 */
645 private OpenstackNetwork getOpenstackNetworkByHost(Host host) {
646 OpenstackPort vPort = getOpenstackPortByHost(host);
647 if (vPort != null) {
648 return openstackService.network(vPort.networkId());
649 } else {
650 return null;
651 }
652 }
653
654 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800655 * Returns hosts associated with a given OpenStack network.
656 *
657 * @param vNet openstack network
658 * @return set of hosts
659 */
660 private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
661 checkNotNull(vNet);
662
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800663 Set<Host> hosts = openstackService.ports(vNet.id()).stream()
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800664 .filter(port -> port.deviceOwner().contains("compute"))
665 .map(port -> hostService.getHostsByMac(port.macAddress())
666 .stream()
667 .findFirst()
668 .orElse(null))
669 .collect(Collectors.toSet());
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800670
671 hosts.remove(null);
672 return hosts;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800673 }
674
675 /**
676 * Returns host IP assigned by OpenStack.
677 *
678 * @param host host
679 * @return IPv4 prefix, or null if it fails to get IP from OpenStack
680 */
681 private IpAddress getHostIpFromOpenstack(Host host) {
682 OpenstackPort vPort = getOpenstackPortByHost(host);
683
684 if (vPort == null || vPort.fixedIps().isEmpty()) {
685 log.error("Failed to get VM IP for {}", host.id());
686 return null;
687 }
688 // Assumes there's only one fixed IP is assigned to a port
689 return (Ip4Address) vPort.fixedIps().values()
690 .stream()
691 .findFirst()
692 .orElse(null);
693 }
694
695 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800696 * Returns port name with OpenStack port information.
697 *
698 * @param vPort OpenStack port
699 * @return port name
700 */
701 private String getPortName(OpenstackPort vPort) {
702 checkNotNull(vPort);
703 return VPORT_PREFIX + vPort.id().substring(0, 10);
704 }
705
706 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800707 * Returns if the host is VM or not.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800708 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800709 * @param host host
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800710 * @return true if the host is a VM.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800711 */
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800712 private boolean isVm(Host host) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800713 Port port = deviceService.getPort(host.location().deviceId(),
714 host.location().port());
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800715 return port.annotations().value("portName").contains(VPORT_PREFIX);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800716 }
717
718 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800719 * Returns CordService by service ID.
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800720 *
721 * @param serviceId service id
722 * @return cord service, or null if it fails to get network from OpenStack
723 */
724 private CordService getCordService(CordServiceId serviceId) {
725 OpenstackNetwork vNet = openstackService.network(serviceId.id());
726 if (vNet == null) {
727 log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
728 return null;
729 }
730
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800731 OpenstackSubnet subnet = vNet.subnets().stream()
732 .findFirst()
733 .orElse(null);
734 if (subnet == null) {
735 log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
736 return null;
737 }
738
739 Set<CordServiceId> tServices = Sets.newHashSet();
740 // TODO get tenant services from XOS
741
742 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
743 .stream()
744 .collect(Collectors.toMap(host -> host,
745 host -> getRemoteIp(host.location().deviceId())));
746
747 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800748 }
749
750 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800751 * Returns CordService by OpenStack network.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800752 *
753 * @param vNet OpenStack network
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800754 * @return cord service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800755 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800756 private CordService getCordService(OpenstackNetwork vNet) {
757 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800758
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800759 CordServiceId serviceId = CordServiceId.of(vNet.id());
760 OpenstackSubnet subnet = vNet.subnets().stream()
761 .findFirst()
762 .orElse(null);
763 if (subnet == null) {
764 log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
765 return null;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800766 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800767
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800768 Set<CordServiceId> tServices = Sets.newHashSet();
769 // TODO get tenant services from XOS
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800770
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800771 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
772 .stream()
773 .collect(Collectors.toMap(host -> host,
774 host -> getRemoteIp(host.location().deviceId())));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800775
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800776 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800777 }
778
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700779 private class InternalDeviceListener implements DeviceListener {
780
781 @Override
782 public void event(DeviceEvent event) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800783
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700784 Device device = event.subject();
Hyunsun Moon8539b042015-11-07 22:08:43 -0800785 ConnectionHandler<Device> handler =
786 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700787
788 switch (event.type()) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800789 case PORT_ADDED:
790 eventExecutor.submit(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Moon2b530322015-09-23 13:24:35 -0700791 break;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800792 case PORT_UPDATED:
793 if (!event.port().isEnabled()) {
794 eventExecutor.submit(() -> bridgeHandler.portRemoved(event.port()));
795 }
796 break;
797 case DEVICE_ADDED:
Hyunsun Moon2b530322015-09-23 13:24:35 -0700798 case DEVICE_AVAILABILITY_CHANGED:
Hyunsun Moon523d9762015-10-19 12:38:21 -0700799 if (deviceService.isAvailable(device.id())) {
800 eventExecutor.submit(() -> handler.connected(device));
801 } else {
802 eventExecutor.submit(() -> handler.disconnected(device));
803 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700804 break;
805 default:
806 break;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700807 }
808 }
809 }
810
811 private class InternalHostListener implements HostListener {
812
813 @Override
814 public void event(HostEvent event) {
815 Host vm = event.subject();
816
817 switch (event.type()) {
818 case HOST_ADDED:
819 eventExecutor.submit(() -> vmHandler.connected(vm));
820 break;
821 case HOST_REMOVED:
822 eventExecutor.submit(() -> vmHandler.disconnected(vm));
823 break;
824 default:
825 break;
826 }
827 }
828 }
829
Hyunsun Moon2b530322015-09-23 13:24:35 -0700830 private class OvsdbHandler implements ConnectionHandler<Device> {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700831
832 @Override
833 public void connected(Device device) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800834 CordVtnNode node = getNodeByOvsdbId(device.id());
835 if (node != null) {
836 setNodeState(node, checkNodeState(node));
Hyunsun Moon523d9762015-10-19 12:38:21 -0700837 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700838 }
839
840 @Override
841 public void disconnected(Device device) {
Hyunsun Moonba225722015-12-10 13:14:05 -0800842 if (!deviceService.isAvailable(device.id())) {
843 adminService.removeDevice(device.id());
844 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700845 }
846 }
847
848 private class BridgeHandler implements ConnectionHandler<Device> {
849
850 @Override
851 public void connected(Device device) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800852 CordVtnNode node = getNodeByBridgeId(device.id());
853 if (node != null) {
854 setNodeState(node, checkNodeState(node));
Hyunsun Moon1f145552015-10-08 22:25:30 -0700855 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700856 }
857
858 @Override
859 public void disconnected(Device device) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800860 CordVtnNode node = getNodeByBridgeId(device.id());
861 if (node != null) {
862 log.info("Integration Bridge is disconnected from {}", node.hostname());
863 setNodeState(node, NodeState.INCOMPLETE);
864 }
865 }
866
867 /**
868 * Handles port added situation.
869 * If the added port is tunnel port, proceed remaining node initialization.
870 * Otherwise, do nothing.
871 *
872 * @param port port
873 */
874 public void portAdded(Port port) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800875 // TODO add host by updating network config
Hyunsun Moon8539b042015-11-07 22:08:43 -0800876 if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) {
877 return;
878 }
879
880 CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
881 if (node != null) {
882 setNodeState(node, checkNodeState(node));
883 }
884 }
885
886 /**
887 * Handles port removed situation.
888 * If the removed port is tunnel port, proceed remaining node initialization.
889 * Others, do nothing.
890 *
891 * @param port port
892 */
893 public void portRemoved(Port port) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800894 // TODO remove host by updating network config
Hyunsun Moon8539b042015-11-07 22:08:43 -0800895 if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) {
896 return;
897 }
898
899 CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
900 if (node != null) {
901 log.info("Tunnel interface is removed from {}", node.hostname());
902 setNodeState(node, NodeState.INCOMPLETE);
903 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700904 }
905 }
906
Hyunsun Moon2b530322015-09-23 13:24:35 -0700907 private class VmHandler implements ConnectionHandler<Host> {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700908
909 @Override
910 public void connected(Host host) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800911 // TODO remove check VM here after applying network config host provider
912 if (!isVm(host)) {
Hyunsun Moonbe8edcb2016-01-12 10:13:00 -0800913 log.debug("Host {} is not a VM, ignore it.", host.id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800914 return;
915 }
916
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800917 CordVtnNode node = getNodeByBridgeId(host.location().deviceId());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800918 if (node == null || !Objects.equals(getNodeState(node), NodeState.COMPLETE)) {
Hyunsun Moonbe8edcb2016-01-12 10:13:00 -0800919 log.debug("VM {} is detected unknown or incomplete device, ignore it.", host.id());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800920 return;
921 }
922
923 OpenstackNetwork vNet = getOpenstackNetworkByHost(host);
924 if (vNet == null) {
Hyunsun Moonbe8edcb2016-01-12 10:13:00 -0800925 log.debug("Failed to get OpenStack network for VM {}, ignore it.", host.id());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800926 return;
927 }
928
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800929 // TODO host ip should be set in host information after applying network config host provider
930 IpAddress hostIp = getHostIpFromOpenstack(host);
931 if (hostIp == null) {
Hyunsun Moonbe8edcb2016-01-12 10:13:00 -0800932 log.debug("Failed to get host IP of {}, ignore it.", host.id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800933 return;
934 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800935
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800936 log.info("VM {} is detected", host.id());
937 hostNetMap.put(host.id(), vNet);
938
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800939 CordService service = getCordService(vNet);
940 if (service != null) {
941 // TODO check if the service needs an update on its group buckets after done CORD-433
942 ruleInstaller.updateServiceGroup(service);
943 arpProxy.addServiceIp(service.serviceIp());
944 }
945
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800946 ruleInstaller.populateBasicConnectionRules(
947 host,
948 hostIp,
949 checkNotNull(getRemoteIp(host.location().deviceId())).getIp4Address(),
950 vNet);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700951 }
952
953 @Override
954 public void disconnected(Host host) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800955 CordVtnNode node = getNodeByBridgeId(host.location().deviceId());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800956 if (node == null || !Objects.equals(getNodeState(node), NodeState.COMPLETE)) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800957 // do nothing for the host on unregistered or unprepared device
958 return;
959 }
960
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800961 OpenstackNetwork vNet = hostNetMap.get(host.id());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800962 if (vNet == null) {
963 return;
964 }
965
Hyunsun Moon1f145552015-10-08 22:25:30 -0700966 log.info("VM {} is vanished", host.id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800967 ruleInstaller.removeBasicConnectionRules(host);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800968
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800969 CordService service = getCordService(vNet);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800970 if (service != null) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800971 // TODO check if the service needs an update on its group buckets after done CORD-433
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800972 ruleInstaller.updateServiceGroup(service);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800973
974 if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
975 arpProxy.removeServiceIp(service.serviceIp());
976 }
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800977 }
978
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800979 hostNetMap.remove(host.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700980 }
981 }
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800982
983 private class InternalPacketProcessor implements PacketProcessor {
984
985 @Override
986 public void process(PacketContext context) {
987 if (context.isHandled()) {
988 return;
989 }
990
991 Ethernet ethPacket = context.inPacket().parsed();
992 if (ethPacket == null) {
993 return;
994 }
995
996 if (ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
997 return;
998 }
999
1000 arpProxy.processArpPacket(context, ethPacket);
1001 }
1002 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001003}