blob: 107f3e7f6ae823867272a0d1b7a22d26c57b0bad [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 Moonb219fc42016-01-14 03:42:47 -0800108
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800109 private static final String DEFAULT_BRIDGE = "br-int";
110 private static final String VPORT_PREFIX = "tap";
Hyunsun Moon523d9762015-10-19 12:38:21 -0700111 private static final String DEFAULT_TUNNEL = "vxlan";
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800112 private static final String OK = "OK";
113 private static final String NO = "NO";
114
Hyunsun Moon523d9762015-10-19 12:38:21 -0700115 private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700116 {
117 put("key", "flow");
Hyunsun Moon1f145552015-10-08 22:25:30 -0700118 put("remote_ip", "flow");
119 }
120 };
121 private static final int DPID_BEGIN = 3;
122 private static final int OFPORT = 6653;
Hyunsun Moon2b530322015-09-23 13:24:35 -0700123
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected CoreService coreService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected StorageService storageService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700131 protected DeviceService deviceService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
134 protected HostService hostService;
135
Hyunsun Moon1f145552015-10-08 22:25:30 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond772f342015-10-28 20:28:16 -0700137 protected DriverService driverService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon8539b042015-11-07 22:08:43 -0800140 protected DeviceAdminService adminService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800143 protected FlowRuleService flowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800146 protected PacketService packetService;
147
148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon1f145552015-10-08 22:25:30 -0700149 protected OvsdbController controller;
150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 protected ClusterService clusterService;
153
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800155 protected MastershipService mastershipService;
156
157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
158 protected GroupService groupService;
159
160 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800161 protected OpenstackSwitchingService openstackService;
162
Hyunsun Moon2b530322015-09-23 13:24:35 -0700163 private final ExecutorService eventExecutor = Executors
164 .newFixedThreadPool(NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700165
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700166 private final DeviceListener deviceListener = new InternalDeviceListener();
167 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800168 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700169
170 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700171 private final BridgeHandler bridgeHandler = new BridgeHandler();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700172 private final VmHandler vmHandler = new VmHandler();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700173
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800174 private ApplicationId appId;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800175 private ConsistentMap<CordVtnNode, NodeState> nodeStore;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800176 private Map<HostId, OpenstackNetwork> hostNetMap = Maps.newHashMap();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800177 private CordVtnRuleInstaller ruleInstaller;
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800178 private CordVtnArpProxy arpProxy;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800179
180 private enum NodeState {
181
182 INIT {
183 @Override
184 public void process(CordVtn cordVtn, CordVtnNode node) {
185 cordVtn.connect(node);
186 }
187 },
188 OVSDB_CONNECTED {
189 @Override
190 public void process(CordVtn cordVtn, CordVtnNode node) {
191 if (!cordVtn.getOvsdbConnectionState(node)) {
192 cordVtn.connect(node);
193 } else {
194 cordVtn.createIntegrationBridge(node);
195 }
196 }
197 },
198 BRIDGE_CREATED {
199 @Override
200 public void process(CordVtn cordVtn, CordVtnNode node) {
201 if (!cordVtn.getOvsdbConnectionState(node)) {
202 cordVtn.connect(node);
203 } else {
204 cordVtn.createTunnelInterface(node);
205 }
206 }
207 },
208 COMPLETE {
209 @Override
210 public void process(CordVtn cordVtn, CordVtnNode node) {
211 cordVtn.postInit(node);
212 }
213 },
214 INCOMPLETE {
215 @Override
216 public void process(CordVtn cordVtn, CordVtnNode node) {
217 }
218 };
219
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800220 // TODO Add physical port add state
221
Hyunsun Moon8539b042015-11-07 22:08:43 -0800222 public abstract void process(CordVtn cordVtn, CordVtnNode node);
223 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700224
225 @Activate
226 protected void activate() {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800227 appId = coreService.registerApplication("org.onosproject.cordvtn");
Hyunsun Moon8539b042015-11-07 22:08:43 -0800228 nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder()
Hyunsun Moon1f145552015-10-08 22:25:30 -0700229 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700230 .withName("cordvtn-nodestore")
Hyunsun Moon1f145552015-10-08 22:25:30 -0700231 .withApplicationId(appId)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700232 .build();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700233
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800234 ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
235 deviceService,
236 driverService,
237 groupService,
238 mastershipService,
239 DEFAULT_TUNNEL);
240
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800241 arpProxy = new CordVtnArpProxy(appId, packetService);
242 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
243 arpProxy.requestPacket();
244
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700245 deviceService.addListener(deviceListener);
246 hostService.addListener(hostListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700247
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700248 log.info("Started");
249 }
250
251 @Deactivate
252 protected void deactivate() {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700253 deviceService.removeListener(deviceListener);
254 hostService.removeListener(hostListener);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -0800255 packetService.removeProcessor(packetProcessor);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700256
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700257 eventExecutor.shutdown();
Hyunsun Moon1f145552015-10-08 22:25:30 -0700258 nodeStore.clear();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700259
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700260 log.info("Stopped");
261 }
262
263 @Override
Hyunsun Moon8539b042015-11-07 22:08:43 -0800264 public void addNode(CordVtnNode node) {
265 checkNotNull(node);
Hyunsun Moon523d9762015-10-19 12:38:21 -0700266
Hyunsun Moon8539b042015-11-07 22:08:43 -0800267 nodeStore.putIfAbsent(node, checkNodeState(node));
268 initNode(node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700269 }
270
271 @Override
Hyunsun Moon8539b042015-11-07 22:08:43 -0800272 public void deleteNode(CordVtnNode node) {
273 checkNotNull(node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700274
Hyunsun Moon8539b042015-11-07 22:08:43 -0800275 if (getOvsdbConnectionState(node)) {
276 disconnect(node);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700277 }
Hyunsun Moon523d9762015-10-19 12:38:21 -0700278
Hyunsun Moon8539b042015-11-07 22:08:43 -0800279 nodeStore.remove(node);
Hyunsun Moon523d9762015-10-19 12:38:21 -0700280 }
281
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700282 @Override
283 public int getNodeCount() {
284 return nodeStore.size();
285 }
286
287 @Override
Hyunsun Moon8539b042015-11-07 22:08:43 -0800288 public List<CordVtnNode> getNodes() {
289 List<CordVtnNode> nodes = new ArrayList<>();
290 nodes.addAll(nodeStore.keySet());
291 return nodes;
292 }
293
294 @Override
295 public void initNode(CordVtnNode node) {
296 checkNotNull(node);
297
298 if (!nodeStore.containsKey(node)) {
299 log.warn("Node {} does not exist, add node first", node.hostname());
300 return;
301 }
302
Hyunsun Moonbaf70542015-12-16 14:29:36 -0800303 NodeState state = checkNodeState(node);
Hyunsun Moon8539b042015-11-07 22:08:43 -0800304 state.process(this, node);
305 }
306
307 @Override
308 public boolean getNodeInitState(CordVtnNode node) {
309 checkNotNull(node);
310
311 NodeState state = getNodeState(node);
312 return state != null && state.equals(NodeState.COMPLETE);
313 }
314
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800315 @Override
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800316 public String checkNodeInitState(CordVtnNode node) {
317 checkNotNull(node);
318
319 NodeState state = getNodeState(node);
320 if (state == null) {
321 log.warn("Failed to get init state of {}", node.hostname());
322 return null;
323 }
324
325 String result = String.format(
326 "Integration bridge created/connected : %s (%s)%n" +
327 "VXLAN interface created : %s%n" +
328 "Physical interface added : %s (%s)",
329 checkIntegrationBridge(node) ? OK : NO, DEFAULT_BRIDGE,
330 checkTunnelInterface(node) ? OK : NO,
331 checkPhyInterface(node) ? OK : NO, node.phyPortName());
332
333 return result;
334 }
335
336 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800337 public void createServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
338 CordService tService = getCordService(tServiceId);
339 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800340
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800341 if (tService == null || pService == null) {
342 log.error("Failed to create CordService for {}", tServiceId.id());
343 return;
344 }
345
346 ruleInstaller.populateServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800347 }
348
349 @Override
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800350 public void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId) {
351 CordService tService = getCordService(tServiceId);
352 CordService pService = getCordService(pServiceId);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800353
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800354 if (tService == null || pService == null) {
355 log.error("Failed to create CordService for {}", tServiceId.id());
356 return;
357 }
358
359 ruleInstaller.removeServiceDependencyRules(tService, pService);
Hyunsun Moon699f46b2015-12-04 11:35:25 -0800360 }
361
Hyunsun Moon8539b042015-11-07 22:08:43 -0800362 /**
363 * Returns state of a given cordvtn node.
364 *
365 * @param node cordvtn node
366 * @return node state, or null if no such node exists
367 */
368 private NodeState getNodeState(CordVtnNode node) {
369 checkNotNull(node);
370
371 try {
372 return nodeStore.get(node).value();
373 } catch (NullPointerException e) {
374 log.error("Failed to get state of {}", node.hostname());
Hyunsun Moon1f145552015-10-08 22:25:30 -0700375 return null;
376 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700377 }
378
Hyunsun Moon8539b042015-11-07 22:08:43 -0800379 /**
380 * Sets a new state for a given cordvtn node.
381 *
382 * @param node cordvtn node
383 * @param newState new node state
384 */
385 private void setNodeState(CordVtnNode node, NodeState newState) {
386 checkNotNull(node);
387
388 log.info("Changed {} state: {}", node.hostname(), newState.toString());
389
390 nodeStore.put(node, newState);
391 newState.process(this, node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700392 }
393
Hyunsun Moon8539b042015-11-07 22:08:43 -0800394 /**
395 * Checks current state of a given cordvtn node and returns it.
396 *
397 * @param node cordvtn node
398 * @return node state
399 */
400 private NodeState checkNodeState(CordVtnNode node) {
401 checkNotNull(node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700402
Hyunsun Moon8539b042015-11-07 22:08:43 -0800403 if (checkIntegrationBridge(node) && checkTunnelInterface(node)) {
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800404 // TODO add physical port add state
405 if (checkPhyInterface(node)) {
406 return NodeState.COMPLETE;
407 } else {
408 return NodeState.INCOMPLETE;
409 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800410 } else if (checkIntegrationBridge(node)) {
411 return NodeState.BRIDGE_CREATED;
412 } else if (getOvsdbConnectionState(node)) {
413 return NodeState.OVSDB_CONNECTED;
Hyunsun Moon1f145552015-10-08 22:25:30 -0700414 } else {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800415 return NodeState.INIT;
Hyunsun Moon1f145552015-10-08 22:25:30 -0700416 }
417 }
418
Hyunsun Moon8539b042015-11-07 22:08:43 -0800419 /**
420 * Performs tasks after node initialization.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800421 * First disconnect unnecessary OVSDB connection and then installs flow rules
422 * for existing VMs if there are any.
Hyunsun Moon8539b042015-11-07 22:08:43 -0800423 *
424 * @param node cordvtn node
425 */
426 private void postInit(CordVtnNode node) {
427 disconnect(node);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800428
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800429 ruleInstaller.init(node.intBrId(), getTunnelPort(node.intBrId()));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800430 hostService.getConnectedHosts(node.intBrId())
431 .stream()
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800432 .forEach(vmHandler::connected);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800433
434 log.info("Finished initializing {}", node.hostname());
Hyunsun Moon8539b042015-11-07 22:08:43 -0800435 }
436
437 /**
438 * Returns connection state of OVSDB server for a given node.
439 *
440 * @param node cordvtn node
441 * @return true if it is connected, false otherwise
442 */
443 private boolean getOvsdbConnectionState(CordVtnNode node) {
444 checkNotNull(node);
445
446 OvsdbClientService ovsdbClient = getOvsdbClient(node);
447 return deviceService.isAvailable(node.ovsdbId()) &&
448 ovsdbClient != null && ovsdbClient.isConnected();
449 }
450
451 /**
452 * Connects to OVSDB server for a given node.
453 *
454 * @param node cordvtn node
455 */
456 private void connect(CordVtnNode node) {
457 checkNotNull(node);
458
459 if (!nodeStore.containsKey(node)) {
460 log.warn("Node {} does not exist", node.hostname());
461 return;
462 }
463
464 if (!getOvsdbConnectionState(node)) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800465 controller.connect(node.ovsdbIp(), node.ovsdbPort());
466 }
467 }
468
469 /**
470 * Disconnects OVSDB server for a given node.
471 *
472 * @param node cordvtn node
473 */
474 private void disconnect(CordVtnNode node) {
475 checkNotNull(node);
476
477 if (!nodeStore.containsKey(node)) {
478 log.warn("Node {} does not exist", node.hostname());
479 return;
480 }
481
482 if (getOvsdbConnectionState(node)) {
483 OvsdbClientService ovsdbClient = getOvsdbClient(node);
484 ovsdbClient.disconnect();
485 }
Hyunsun Moon8539b042015-11-07 22:08:43 -0800486 }
487
488 /**
489 * Returns cordvtn node associated with a given OVSDB device.
490 *
491 * @param ovsdbId OVSDB device id
492 * @return cordvtn node, null if it fails to find the node
493 */
494 private CordVtnNode getNodeByOvsdbId(DeviceId ovsdbId) {
495 try {
496 return getNodes().stream()
497 .filter(node -> node.ovsdbId().equals(ovsdbId))
498 .findFirst().get();
499 } catch (NoSuchElementException e) {
500 log.debug("Couldn't find node information for {}", ovsdbId);
501 return null;
502 }
503 }
504
505 /**
506 * Returns cordvtn node associated with a given integration bridge.
507 *
508 * @param bridgeId device id of integration bridge
509 * @return cordvtn node, null if it fails to find the node
510 */
511 private CordVtnNode getNodeByBridgeId(DeviceId bridgeId) {
512 try {
513 return getNodes().stream()
514 .filter(node -> node.intBrId().equals(bridgeId))
515 .findFirst().get();
516 } catch (NoSuchElementException e) {
517 log.debug("Couldn't find node information for {}", bridgeId);
518 return null;
519 }
520 }
521
522 /**
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800523 * Returns port name.
524 *
525 * @param port port
526 * @return port name
527 */
528 private String getPortName(Port port) {
529 return port.annotations().value("portName");
530 }
531
532 /**
Hyunsun Moon8539b042015-11-07 22:08:43 -0800533 * Returns OVSDB client for a given node.
534 *
535 * @param node cordvtn node
536 * @return OVSDB client, or null if it fails to get OVSDB client
537 */
538 private OvsdbClientService getOvsdbClient(CordVtnNode node) {
539 checkNotNull(node);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700540
541 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
Hyunsun Moon8539b042015-11-07 22:08:43 -0800542 new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt()));
Hyunsun Moon1f145552015-10-08 22:25:30 -0700543 if (ovsdbClient == null) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800544 log.debug("Couldn't find OVSDB client for {}", node.hostname());
Hyunsun Moon1f145552015-10-08 22:25:30 -0700545 }
546 return ovsdbClient;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700547 }
548
Hyunsun Moon8539b042015-11-07 22:08:43 -0800549 /**
550 * Creates an integration bridge for a given node.
551 *
552 * @param node cordvtn node
553 */
554 private void createIntegrationBridge(CordVtnNode node) {
555 if (checkIntegrationBridge(node)) {
556 return;
557 }
558
Hyunsun Moon523d9762015-10-19 12:38:21 -0700559 List<ControllerInfo> controllers = new ArrayList<>();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800560 Sets.newHashSet(clusterService.getNodes()).stream()
Hyunsun Moon523d9762015-10-19 12:38:21 -0700561 .forEach(controller -> {
562 ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
563 controllers.add(ctrlInfo);
564 });
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800565
Hyunsun Moon8539b042015-11-07 22:08:43 -0800566 String dpid = node.intBrId().toString().substring(DPID_BEGIN);
Hyunsun Moon523d9762015-10-19 12:38:21 -0700567
Hyunsun Moon523d9762015-10-19 12:38:21 -0700568 try {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800569 DriverHandler handler = driverService.createHandler(node.ovsdbId());
Hyunsun Moond772f342015-10-28 20:28:16 -0700570 BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800571 bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE), dpid, controllers);
Hyunsun Moond772f342015-10-28 20:28:16 -0700572 } catch (ItemNotFoundException e) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800573 log.warn("Failed to create integration bridge on {}", node.ovsdbId());
Hyunsun Moond772f342015-10-28 20:28:16 -0700574 }
575 }
576
Hyunsun Moon8539b042015-11-07 22:08:43 -0800577 /**
578 * Creates tunnel interface to the integration bridge for a given node.
579 *
580 * @param node cordvtn node
581 */
582 private void createTunnelInterface(CordVtnNode node) {
583 if (checkTunnelInterface(node)) {
584 return;
585 }
586
Hyunsun Moond772f342015-10-28 20:28:16 -0700587 DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder();
588 for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
589 optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
590 }
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800591
592 TunnelDescription description = new DefaultTunnelDescription(
593 null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL),
594 optionBuilder.build());
595
Hyunsun Moond772f342015-10-28 20:28:16 -0700596 try {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800597 DriverHandler handler = driverService.createHandler(node.ovsdbId());
Hyunsun Moond772f342015-10-28 20:28:16 -0700598 TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800599 tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE), description);
Hyunsun Moond772f342015-10-28 20:28:16 -0700600 } catch (ItemNotFoundException e) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800601 log.warn("Failed to create tunnel interface on {}", node.ovsdbId());
Hyunsun Moond772f342015-10-28 20:28:16 -0700602 }
603 }
604
Hyunsun Moon8539b042015-11-07 22:08:43 -0800605 /**
606 * Checks if integration bridge exists and available.
607 *
608 * @param node cordvtn node
609 * @return true if the bridge is available, false otherwise
610 */
611 private boolean checkIntegrationBridge(CordVtnNode node) {
612 return (deviceService.getDevice(node.intBrId()) != null
613 && deviceService.isAvailable(node.intBrId()));
614 }
615
616 /**
617 * Checks if tunnel interface exists.
618 *
619 * @param node cordvtn node
620 * @return true if the interface exists, false otherwise
621 */
622 private boolean checkTunnelInterface(CordVtnNode node) {
Hyunsun Moond772f342015-10-28 20:28:16 -0700623 try {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800624 deviceService.getPorts(node.intBrId())
625 .stream()
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800626 .filter(p -> getPortName(p).contains(DEFAULT_TUNNEL)
627 && p.isEnabled())
628 .findAny().get();
629 return true;
630 } catch (NoSuchElementException e) {
631 return false;
632 }
633 }
634
635 /**
636 * Checks if physical interface exists.
637 *
638 * @param node cordvtn node
639 * @return true if the interface exists, false otherwise
640 */
641 private boolean checkPhyInterface(CordVtnNode node) {
642 try {
643 deviceService.getPorts(node.intBrId())
644 .stream()
645 .filter(p -> getPortName(p).contains(node.phyPortName())
Hyunsun Moon8539b042015-11-07 22:08:43 -0800646 && p.isEnabled())
Hyunsun Moond772f342015-10-28 20:28:16 -0700647 .findAny().get();
Hyunsun Moon8539b042015-11-07 22:08:43 -0800648 return true;
649 } catch (NoSuchElementException e) {
Hyunsun Moon523d9762015-10-19 12:38:21 -0700650 return false;
651 }
Hyunsun Moon523d9762015-10-19 12:38:21 -0700652 }
653
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800654 /**
655 * Returns tunnel port of the device.
656 *
657 * @param bridgeId device id
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800658 * @return port number, null if no tunnel port exists on a given device
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800659 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800660 private PortNumber getTunnelPort(DeviceId bridgeId) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800661 try {
662 return deviceService.getPorts(bridgeId).stream()
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800663 .filter(p -> getPortName(p).contains(DEFAULT_TUNNEL)
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800664 && p.isEnabled())
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800665 .findFirst().get().number();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800666 } catch (NoSuchElementException e) {
667 return null;
668 }
669 }
670
671 /**
672 * Returns remote ip address for tunneling.
673 *
674 * @param bridgeId device id
675 * @return ip address, null if no such device exists
676 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800677 private Ip4Address getRemoteIp(DeviceId bridgeId) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800678 CordVtnNode node = getNodeByBridgeId(bridgeId);
679 if (node != null) {
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800680 return node.localIp().getIp4Address();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800681 } else {
682 return null;
683 }
684 }
685
686 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800687 * Returns OpenStack port associated with a given host.
688 *
689 * @param host host
690 * @return OpenStack port, or null if no port has been found
691 */
692 private OpenstackPort getOpenstackPortByHost(Host host) {
693 Port port = deviceService.getPort(host.location().deviceId(),
694 host.location().port());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800695 if (port == null) {
696 log.debug("Failed to get port for {}", host.id());
697 return null;
698 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800699 return openstackService.port(port);
700 }
701
702 /**
703 * Returns OpenStack network associated with a given host.
704 *
705 * @param host host
706 * @return OpenStack network, or null if no network has been found
707 */
708 private OpenstackNetwork getOpenstackNetworkByHost(Host host) {
709 OpenstackPort vPort = getOpenstackPortByHost(host);
710 if (vPort != null) {
711 return openstackService.network(vPort.networkId());
712 } else {
713 return null;
714 }
715 }
716
717 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800718 * Returns hosts associated with a given OpenStack network.
719 *
720 * @param vNet openstack network
721 * @return set of hosts
722 */
723 private Set<Host> getHostsWithOpenstackNetwork(OpenstackNetwork vNet) {
724 checkNotNull(vNet);
725
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800726 Set<Host> hosts = openstackService.ports(vNet.id()).stream()
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800727 .filter(port -> port.deviceOwner().contains("compute"))
728 .map(port -> hostService.getHostsByMac(port.macAddress())
729 .stream()
730 .findFirst()
731 .orElse(null))
732 .collect(Collectors.toSet());
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800733
734 hosts.remove(null);
735 return hosts;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800736 }
737
738 /**
739 * Returns host IP assigned by OpenStack.
740 *
741 * @param host host
742 * @return IPv4 prefix, or null if it fails to get IP from OpenStack
743 */
744 private IpAddress getHostIpFromOpenstack(Host host) {
745 OpenstackPort vPort = getOpenstackPortByHost(host);
746
747 if (vPort == null || vPort.fixedIps().isEmpty()) {
748 log.error("Failed to get VM IP for {}", host.id());
749 return null;
750 }
751 // Assumes there's only one fixed IP is assigned to a port
752 return (Ip4Address) vPort.fixedIps().values()
753 .stream()
754 .findFirst()
755 .orElse(null);
756 }
757
758 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800759 * Returns port name with OpenStack port information.
760 *
761 * @param vPort OpenStack port
762 * @return port name
763 */
764 private String getPortName(OpenstackPort vPort) {
765 checkNotNull(vPort);
766 return VPORT_PREFIX + vPort.id().substring(0, 10);
767 }
768
769 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800770 * Returns if the host is VM or not.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800771 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800772 * @param host host
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800773 * @return true if the host is a VM.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800774 */
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800775 private boolean isVm(Host host) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800776 Port port = deviceService.getPort(host.location().deviceId(),
777 host.location().port());
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800778 return getPortName(port).contains(VPORT_PREFIX);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800779 }
780
781 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800782 * Returns CordService by service ID.
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800783 *
784 * @param serviceId service id
785 * @return cord service, or null if it fails to get network from OpenStack
786 */
787 private CordService getCordService(CordServiceId serviceId) {
788 OpenstackNetwork vNet = openstackService.network(serviceId.id());
789 if (vNet == null) {
790 log.warn("Couldn't find OpenStack network for service {}", serviceId.id());
791 return null;
792 }
793
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800794 OpenstackSubnet subnet = vNet.subnets().stream()
795 .findFirst()
796 .orElse(null);
797 if (subnet == null) {
798 log.warn("Couldn't find OpenStack subnet for service {}", serviceId.id());
799 return null;
800 }
801
802 Set<CordServiceId> tServices = Sets.newHashSet();
803 // TODO get tenant services from XOS
804
805 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
806 .stream()
807 .collect(Collectors.toMap(host -> host,
808 host -> getRemoteIp(host.location().deviceId())));
809
810 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moonbfc47d12015-12-07 14:06:28 -0800811 }
812
813 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800814 * Returns CordService by OpenStack network.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800815 *
816 * @param vNet OpenStack network
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800817 * @return cord service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800818 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800819 private CordService getCordService(OpenstackNetwork vNet) {
820 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800821
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800822 CordServiceId serviceId = CordServiceId.of(vNet.id());
823 OpenstackSubnet subnet = vNet.subnets().stream()
824 .findFirst()
825 .orElse(null);
826 if (subnet == null) {
827 log.warn("Couldn't find OpenStack subnet for service {}", serviceId);
828 return null;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800829 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800830
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800831 Set<CordServiceId> tServices = Sets.newHashSet();
832 // TODO get tenant services from XOS
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800833
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800834 Map<Host, IpAddress> hosts = getHostsWithOpenstackNetwork(vNet)
835 .stream()
836 .collect(Collectors.toMap(host -> host,
837 host -> getRemoteIp(host.location().deviceId())));
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800838
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800839 return new CordService(vNet, subnet, hosts, tServices);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800840 }
841
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700842 private class InternalDeviceListener implements DeviceListener {
843
844 @Override
845 public void event(DeviceEvent event) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800846
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700847 Device device = event.subject();
Hyunsun Moon8539b042015-11-07 22:08:43 -0800848 ConnectionHandler<Device> handler =
849 (device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700850
851 switch (event.type()) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800852 case PORT_ADDED:
853 eventExecutor.submit(() -> bridgeHandler.portAdded(event.port()));
Hyunsun Moon2b530322015-09-23 13:24:35 -0700854 break;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800855 case PORT_UPDATED:
856 if (!event.port().isEnabled()) {
857 eventExecutor.submit(() -> bridgeHandler.portRemoved(event.port()));
858 }
859 break;
860 case DEVICE_ADDED:
Hyunsun Moon2b530322015-09-23 13:24:35 -0700861 case DEVICE_AVAILABILITY_CHANGED:
Hyunsun Moon523d9762015-10-19 12:38:21 -0700862 if (deviceService.isAvailable(device.id())) {
863 eventExecutor.submit(() -> handler.connected(device));
864 } else {
865 eventExecutor.submit(() -> handler.disconnected(device));
866 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700867 break;
868 default:
869 break;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700870 }
871 }
872 }
873
874 private class InternalHostListener implements HostListener {
875
876 @Override
877 public void event(HostEvent event) {
878 Host vm = event.subject();
879
880 switch (event.type()) {
881 case HOST_ADDED:
882 eventExecutor.submit(() -> vmHandler.connected(vm));
883 break;
884 case HOST_REMOVED:
885 eventExecutor.submit(() -> vmHandler.disconnected(vm));
886 break;
887 default:
888 break;
889 }
890 }
891 }
892
Hyunsun Moon2b530322015-09-23 13:24:35 -0700893 private class OvsdbHandler implements ConnectionHandler<Device> {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700894
895 @Override
896 public void connected(Device device) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800897 CordVtnNode node = getNodeByOvsdbId(device.id());
898 if (node != null) {
899 setNodeState(node, checkNodeState(node));
Hyunsun Moon523d9762015-10-19 12:38:21 -0700900 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700901 }
902
903 @Override
904 public void disconnected(Device device) {
Hyunsun Moonba225722015-12-10 13:14:05 -0800905 if (!deviceService.isAvailable(device.id())) {
906 adminService.removeDevice(device.id());
907 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700908 }
909 }
910
911 private class BridgeHandler implements ConnectionHandler<Device> {
912
913 @Override
914 public void connected(Device device) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800915 CordVtnNode node = getNodeByBridgeId(device.id());
916 if (node != null) {
917 setNodeState(node, checkNodeState(node));
Hyunsun Moon1f145552015-10-08 22:25:30 -0700918 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700919 }
920
921 @Override
922 public void disconnected(Device device) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800923 CordVtnNode node = getNodeByBridgeId(device.id());
924 if (node != null) {
925 log.info("Integration Bridge is disconnected from {}", node.hostname());
926 setNodeState(node, NodeState.INCOMPLETE);
927 }
928 }
929
930 /**
931 * Handles port added situation.
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800932 * If the added port is tunnel or physical port, proceed remaining node
933 * initialization. Otherwise, do nothing.
Hyunsun Moon8539b042015-11-07 22:08:43 -0800934 *
935 * @param port port
936 */
937 public void portAdded(Port port) {
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800938 CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
939 if (node == null) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800940 return;
941 }
942
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800943 // TODO add host by updating network config
944 String portName = getPortName(port);
945 if (!portName.contains(DEFAULT_TUNNEL) && !portName.equals(node.phyPortName())) {
946 return;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800947 }
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800948
949 log.info("Port {} is added to {}", portName, node.hostname());
950 setNodeState(node, checkNodeState(node));
Hyunsun Moon8539b042015-11-07 22:08:43 -0800951 }
952
953 /**
954 * Handles port removed situation.
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800955 * If the removed port is tunnel or physical port, proceed remaining node
956 * initialization.Others, do nothing.
Hyunsun Moon8539b042015-11-07 22:08:43 -0800957 *
958 * @param port port
959 */
960 public void portRemoved(Port port) {
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800961 CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
962 if (node == null) {
Hyunsun Moon8539b042015-11-07 22:08:43 -0800963 return;
964 }
965
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800966 // TODO remove host by updating network config
967 String portName = getPortName(port);
968 if (!portName.contains(DEFAULT_TUNNEL) && !portName.equals(node.phyPortName())) {
969 return;
Hyunsun Moon8539b042015-11-07 22:08:43 -0800970 }
Hyunsun Moonb219fc42016-01-14 03:42:47 -0800971
972 log.info("Port {} is removed from {}", portName, node.hostname());
973 setNodeState(node, NodeState.INCOMPLETE);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700974 }
975 }
976
Hyunsun Moon2b530322015-09-23 13:24:35 -0700977 private class VmHandler implements ConnectionHandler<Host> {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700978
979 @Override
980 public void connected(Host host) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800981 // TODO remove check VM here after applying network config host provider
982 if (!isVm(host)) {
Hyunsun Moonbe8edcb2016-01-12 10:13:00 -0800983 log.debug("Host {} is not a VM, ignore it.", host.id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800984 return;
985 }
986
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800987 CordVtnNode node = getNodeByBridgeId(host.location().deviceId());
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800988 if (node == null || !Objects.equals(getNodeState(node), NodeState.COMPLETE)) {
Hyunsun Moonbe8edcb2016-01-12 10:13:00 -0800989 log.debug("VM {} is detected unknown or incomplete device, ignore it.", host.id());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800990 return;
991 }
992
993 OpenstackNetwork vNet = getOpenstackNetworkByHost(host);
994 if (vNet == null) {
Hyunsun Moonbe8edcb2016-01-12 10:13:00 -0800995 log.debug("Failed to get OpenStack network for VM {}, ignore it.", host.id());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800996 return;
997 }
998
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800999 // TODO host ip should be set in host information after applying network config host provider
1000 IpAddress hostIp = getHostIpFromOpenstack(host);
1001 if (hostIp == null) {
Hyunsun Moonbe8edcb2016-01-12 10:13:00 -08001002 log.debug("Failed to get host IP of {}, ignore it.", host.id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001003 return;
1004 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001005
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001006 log.info("VM {} is detected", host.id());
1007 hostNetMap.put(host.id(), vNet);
1008
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -08001009 CordService service = getCordService(vNet);
1010 if (service != null) {
1011 // TODO check if the service needs an update on its group buckets after done CORD-433
1012 ruleInstaller.updateServiceGroup(service);
1013 arpProxy.addServiceIp(service.serviceIp());
1014 }
1015
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001016 ruleInstaller.populateBasicConnectionRules(
1017 host,
1018 hostIp,
1019 checkNotNull(getRemoteIp(host.location().deviceId())).getIp4Address(),
1020 vNet);
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001021 }
1022
1023 @Override
1024 public void disconnected(Host host) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001025 CordVtnNode node = getNodeByBridgeId(host.location().deviceId());
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001026 if (node == null || !Objects.equals(getNodeState(node), NodeState.COMPLETE)) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001027 // do nothing for the host on unregistered or unprepared device
1028 return;
1029 }
1030
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001031 OpenstackNetwork vNet = hostNetMap.get(host.id());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001032 if (vNet == null) {
1033 return;
1034 }
1035
Hyunsun Moon1f145552015-10-08 22:25:30 -07001036 log.info("VM {} is vanished", host.id());
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001037 ruleInstaller.removeBasicConnectionRules(host);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001038
Hyunsun Moon4161e6f2016-01-07 01:32:31 -08001039 CordService service = getCordService(vNet);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -08001040 if (service != null) {
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -08001041 // TODO check if the service needs an update on its group buckets after done CORD-433
Hyunsun Moon4161e6f2016-01-07 01:32:31 -08001042 ruleInstaller.updateServiceGroup(service);
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -08001043
1044 if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
1045 arpProxy.removeServiceIp(service.serviceIp());
1046 }
Hyunsun Moon4161e6f2016-01-07 01:32:31 -08001047 }
1048
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001049 hostNetMap.remove(host.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001050 }
1051 }
Hyunsun Moon42c7b4e2016-01-11 15:30:42 -08001052
1053 private class InternalPacketProcessor implements PacketProcessor {
1054
1055 @Override
1056 public void process(PacketContext context) {
1057 if (context.isHandled()) {
1058 return;
1059 }
1060
1061 Ethernet ethPacket = context.inPacket().parsed();
1062 if (ethPacket == null) {
1063 return;
1064 }
1065
1066 if (ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
1067 return;
1068 }
1069
1070 arpProxy.processArpPacket(context, ethPacket);
1071 }
1072 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001073}