blob: 04ec1e703d29024054a1338343c301e228862d3f [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +09003 *
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.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
Hyunsun Moon44aac662017-02-18 02:07:01 +090019import org.onlab.packet.IpAddress;
20import org.onlab.packet.MacAddress;
21import org.onlab.packet.VlanId;
22import org.onlab.util.Tools;
23import org.onosproject.core.CoreService;
24import org.onosproject.mastership.MastershipService;
25import org.onosproject.net.ConnectPoint;
26import org.onosproject.net.DefaultAnnotations;
27import org.onosproject.net.Device;
28import org.onosproject.net.Host;
29import org.onosproject.net.HostId;
30import org.onosproject.net.HostLocation;
31import org.onosproject.net.Port;
32import org.onosproject.net.device.DeviceEvent;
33import org.onosproject.net.device.DeviceListener;
34import org.onosproject.net.device.DeviceService;
35import org.onosproject.net.host.DefaultHostDescription;
36import org.onosproject.net.host.HostDescription;
37import org.onosproject.net.host.HostProvider;
38import org.onosproject.net.host.HostProviderRegistry;
39import org.onosproject.net.host.HostProviderService;
40import org.onosproject.net.host.HostService;
41import org.onosproject.net.provider.AbstractProvider;
42import org.onosproject.net.provider.ProviderId;
Daniel Park7e8c4d82018-08-13 23:47:49 +090043import org.onosproject.openstacknetworking.api.Constants;
SONA Project6bc5c4a2018-12-14 23:49:52 +090044import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Li46276ef2020-07-13 16:20:28 +090045import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
46import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090048import org.onosproject.openstacknode.api.OpenstackNode;
49import org.onosproject.openstacknode.api.OpenstackNodeEvent;
50import org.onosproject.openstacknode.api.OpenstackNodeListener;
51import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.openstack4j.model.network.Network;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070053import org.osgi.service.component.annotations.Activate;
54import org.osgi.service.component.annotations.Component;
55import org.osgi.service.component.annotations.Deactivate;
56import org.osgi.service.component.annotations.Reference;
57import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
60
Jian Liec5c32b2018-07-13 14:28:58 +090061import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090062import java.util.Set;
63import java.util.concurrent.ExecutorService;
64import java.util.concurrent.Executors;
65import java.util.stream.Collectors;
66
67import static org.onlab.util.Tools.groupedThreads;
68import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Jian Liec5c32b2018-07-13 14:28:58 +090069import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_CREATE_TIME;
70import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_NETWORK_ID;
71import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_PORT_ID;
72import static org.onosproject.openstacknetworking.api.Constants.ANNOTATION_SEGMENT_ID;
daniel park796c2eb2018-03-22 17:01:51 +090073import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Daniel Park7e8c4d82018-08-13 23:47:49 +090074import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
75import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
Jian Li46276ef2020-07-13 16:20:28 +090076import static org.onosproject.openstacknetworking.api.Constants.TUNNEL_TYPE;
Ray Milkey9dc57392018-06-08 08:52:31 -070077import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
SONA Project6bc5c4a2018-12-14 23:49:52 +090078import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
Daniel Park7e8c4d82018-08-13 23:47:49 +090079import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.vnicType;
Jian Li51b844c2018-05-31 10:59:03 +090080import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081
Ray Milkeyd84f89b2018-08-17 14:54:17 -070082@Component(immediate = true, service = HostProvider.class)
Jian Li6a47fd02018-11-27 21:51:03 +090083public class OpenstackSwitchingHostProvider
Jian Li46b74002018-07-15 18:39:08 +090084 extends AbstractProvider implements HostProvider {
Hyunsun Moon44aac662017-02-18 02:07:01 +090085
86 private final Logger log = LoggerFactory.getLogger(getClass());
87
Hyunsun Moon44aac662017-02-18 02:07:01 +090088 private static final String ERR_ADD_HOST = "Failed to add host: ";
Jian Li9d676fb2018-03-02 15:25:36 +090089 private static final String SONA_HOST_SCHEME = "sona";
Hyunsun Moon44aac662017-02-18 02:07:01 +090090
Ray Milkeyd84f89b2018-08-17 14:54:17 -070091 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d676fb2018-03-02 15:25:36 +090092 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090093
Ray Milkeyd84f89b2018-08-17 14:54:17 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d676fb2018-03-02 15:25:36 +090095 protected DeviceService deviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090096
Ray Milkeyd84f89b2018-08-17 14:54:17 -070097 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d676fb2018-03-02 15:25:36 +090098 protected HostProviderRegistry hostProviderRegistry;
Hyunsun Moon44aac662017-02-18 02:07:01 +090099
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d676fb2018-03-02 15:25:36 +0900101 protected HostService hostService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700103 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d676fb2018-03-02 15:25:36 +0900104 protected MastershipService mastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d676fb2018-03-02 15:25:36 +0900107 protected OpenstackNetworkService osNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d676fb2018-03-02 15:25:36 +0900110 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111
Jian Li07598ff2018-07-23 18:34:34 +0900112 private HostProviderService hostProviderService;
Jian Li24ec59f2018-05-23 19:01:25 +0900113
Jian Li5ecfd1a2018-12-10 11:41:03 +0900114 private final ExecutorService executor = Executors.newSingleThreadExecutor(
115 groupedThreads(this.getClass().getSimpleName(), "device-event"));
Jian Li46b74002018-07-15 18:39:08 +0900116 private final InternalDeviceListener internalDeviceListener =
117 new InternalDeviceListener();
Jian Li46276ef2020-07-13 16:20:28 +0900118 private final InternalNetworkListener internalNetworkListener =
119 new InternalNetworkListener();
Jian Li46b74002018-07-15 18:39:08 +0900120 private final InternalOpenstackNodeListener internalNodeListener =
121 new InternalOpenstackNodeListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123 /**
124 * Creates OpenStack switching host provider.
125 */
126 public OpenstackSwitchingHostProvider() {
Jian Li9d676fb2018-03-02 15:25:36 +0900127 super(new ProviderId(SONA_HOST_SCHEME, OPENSTACK_NETWORKING_APP_ID));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128 }
129
130 @Activate
Jian Li6a47fd02018-11-27 21:51:03 +0900131 protected void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
133 deviceService.addListener(internalDeviceListener);
134 osNodeService.addListener(internalNodeListener);
Jian Li46276ef2020-07-13 16:20:28 +0900135 osNetworkService.addListener(internalNetworkListener);
Jian Li07598ff2018-07-23 18:34:34 +0900136 hostProviderService = hostProviderRegistry.register(this);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137
138 log.info("Started");
139 }
140
141 @Deactivate
Jian Li6a47fd02018-11-27 21:51:03 +0900142 protected void deactivate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 hostProviderRegistry.unregister(this);
144 osNodeService.removeListener(internalNodeListener);
Jian Li46276ef2020-07-13 16:20:28 +0900145 osNetworkService.removeListener(internalNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900146 deviceService.removeListener(internalDeviceListener);
147
Jian Li07598ff2018-07-23 18:34:34 +0900148 executor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149
150 log.info("Stopped");
151 }
152
153 @Override
154 public void triggerProbe(Host host) {
155 // no probe is required
156 }
157
Jian Li9d676fb2018-03-02 15:25:36 +0900158 /**
Jian Li07598ff2018-07-23 18:34:34 +0900159 * A helper method which logs the port addition event and performs port
160 * addition action.
161 *
162 * @param event device event
163 */
Jian Li6a47fd02018-11-27 21:51:03 +0900164 void portAddedHelper(DeviceEvent event) {
Jian Li07598ff2018-07-23 18:34:34 +0900165 log.debug("Instance port {} is detected from {}",
166 event.port().annotations().value(PORT_NAME),
167 event.subject().id());
Jian Li46276ef2020-07-13 16:20:28 +0900168 // we check the existence of openstack port, in case VM creation
169 // event comes before port creation
170 if (osNetworkService.port(event.port()) != null) {
171 processPortAdded(event.port());
172 }
Jian Li07598ff2018-07-23 18:34:34 +0900173 }
174
175 /**
176 * A helper method which logs the port removal event and performs port
177 * removal action.
178 *
179 * @param event device event
180 */
Jian Li6a47fd02018-11-27 21:51:03 +0900181 void portRemovedHelper(DeviceEvent event) {
Jian Li07598ff2018-07-23 18:34:34 +0900182 log.debug("Instance port {} is removed from {}",
183 event.port().annotations().value(PORT_NAME),
184 event.subject().id());
Jian Li46276ef2020-07-13 16:20:28 +0900185 // we check the existence of openstack port, will not remove any hosts
186 // or instance ports with non-exist openstack port
187 if (osNetworkService.port(event.port()) != null) {
188 processPortRemoved(event.port());
189 }
Jian Li07598ff2018-07-23 18:34:34 +0900190 }
191
192 /**
Jian Li9d676fb2018-03-02 15:25:36 +0900193 * Processes port addition event.
194 * Once a port addition event is detected, it tries to create a host instance
195 * with openstack augmented host information such as networkId, portId,
196 * createTime, segmentId and notifies to host provider.
197 *
198 * @param port port object used in ONOS
199 */
Jian Li6a47fd02018-11-27 21:51:03 +0900200 void processPortAdded(Port port) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900201 // TODO check the node state is COMPLETE
202 org.openstack4j.model.network.Port osPort = osNetworkService.port(port);
203 if (osPort == null) {
204 log.warn(ERR_ADD_HOST + "OpenStack port for {} not found", port);
205 return;
206 }
207
208 Network osNet = osNetworkService.network(osPort.getNetworkId());
209 if (osNet == null) {
210 log.warn(ERR_ADD_HOST + "OpenStack network {} not found",
211 osPort.getNetworkId());
212 return;
213 }
214
215 if (osPort.getFixedIps().isEmpty()) {
216 log.warn(ERR_ADD_HOST + "no fixed IP for port {}", osPort.getId());
217 return;
218 }
219
Jian Liec5c32b2018-07-13 14:28:58 +0900220 MacAddress mac = MacAddress.valueOf(osPort.getMacAddress());
221 HostId hostId = HostId.hostId(mac);
222
Jian Li6a47fd02018-11-27 21:51:03 +0900223 /* typically one openstack port should only be bound to one fix IP address;
224 however, openstack4j binds multiple fixed IPs to one port, this might
225 be a defect of openstack4j implementation */
Jian Liec5c32b2018-07-13 14:28:58 +0900226
227 // TODO: we need to find a way to bind multiple ports from multiple
228 // openstack networks into one host sooner or later
Hyunsun Moon44aac662017-02-18 02:07:01 +0900229 Set<IpAddress> fixedIps = osPort.getFixedIps().stream()
Jian Li46b74002018-07-15 18:39:08 +0900230 .map(ip -> IpAddress.valueOf(ip.getIpAddress()))
231 .collect(Collectors.toSet());
Jian Liec5c32b2018-07-13 14:28:58 +0900232
233 // connect point is the combination of switch ID with port number where
234 // the host is attached to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900235 ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
Jian Li24ec59f2018-05-23 19:01:25 +0900236
Jian Liec5c32b2018-07-13 14:28:58 +0900237 long createTime = System.currentTimeMillis();
Jian Li24ec59f2018-05-23 19:01:25 +0900238
Jian Liee8214a2018-07-21 20:07:28 +0900239 // we check whether the host already attached to same locations
Jian Liec5c32b2018-07-13 14:28:58 +0900240 Host host = hostService.getHost(hostId);
Jian Li46b74002018-07-15 18:39:08 +0900241
242 // build host annotations to include a set of meta info from neutron
243 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
244 .set(ANNOTATION_NETWORK_ID, osPort.getNetworkId())
245 .set(ANNOTATION_PORT_ID, osPort.getId())
246 .set(ANNOTATION_CREATE_TIME, String.valueOf(createTime));
247
Jian Liee8214a2018-07-21 20:07:28 +0900248 // FLAT typed network does not require segment ID
SONA Project6bc5c4a2018-12-14 23:49:52 +0900249 Type netType = osNetworkService.networkType(osNet.getId());
250 if (netType != FLAT) {
Jian Li46b74002018-07-15 18:39:08 +0900251 annotations.set(ANNOTATION_SEGMENT_ID, osNet.getProviderSegID());
252 }
253
254 // build host description object
255 HostDescription hostDesc = new DefaultHostDescription(
256 mac,
257 VlanId.NONE,
258 new HostLocation(connectPoint, createTime),
259 fixedIps,
260 annotations.build());
261
Jian Liec5c32b2018-07-13 14:28:58 +0900262 if (host != null) {
263 Set<HostLocation> locations = host.locations().stream()
264 .filter(l -> l.deviceId().equals(connectPoint.deviceId()))
265 .filter(l -> l.port().equals(connectPoint.port()))
266 .collect(Collectors.toSet());
Jian Li46b74002018-07-15 18:39:08 +0900267
268 // newly added location is not in the existing location list,
269 // therefore, we simply add this into the location list
Jian Li6a47fd02018-11-27 21:51:03 +0900270 if (locations.isEmpty()) {
Jian Li07598ff2018-07-23 18:34:34 +0900271 hostProviderService.addLocationToHost(hostId,
Jian Li46b74002018-07-15 18:39:08 +0900272 new HostLocation(connectPoint, createTime));
273 }
274
275 // newly added location is in the existing location list,
276 // the hostDetected method invocation in turn triggers host Update event
277 if (locations.size() == 1) {
Jian Li07598ff2018-07-23 18:34:34 +0900278 hostProviderService.hostDetected(hostId, hostDesc, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900279 }
Jian Liec5c32b2018-07-13 14:28:58 +0900280 } else {
Jian Li07598ff2018-07-23 18:34:34 +0900281 hostProviderService.hostDetected(hostId, hostDesc, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900282 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900283 }
284
Jian Li9d676fb2018-03-02 15:25:36 +0900285 /**
286 * Processes port removal event.
287 * Once a port removal event is detected, it tries to look for a host
288 * instance through host provider by giving connect point information,
289 * and vanishes it.
290 *
Jian Li07598ff2018-07-23 18:34:34 +0900291 * @param port ONOS port
Jian Li9d676fb2018-03-02 15:25:36 +0900292 */
Jian Li6a47fd02018-11-27 21:51:03 +0900293 private void processPortRemoved(Port port) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900294 ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
Jian Li24ec59f2018-05-23 19:01:25 +0900295
Jian Liec5c32b2018-07-13 14:28:58 +0900296 Set<Host> hosts = hostService.getConnectedHosts(connectPoint);
Jian Li24ec59f2018-05-23 19:01:25 +0900297
Jian Liec5c32b2018-07-13 14:28:58 +0900298 hosts.forEach(h -> {
299 Optional<HostLocation> hostLocation = h.locations().stream()
300 .filter(l -> l.deviceId().equals(port.element().id()))
301 .filter(l -> l.port().equals(port.number())).findAny();
Jian Li24ec59f2018-05-23 19:01:25 +0900302
Jian Liec5c32b2018-07-13 14:28:58 +0900303 // if the host contains only one filtered location, we remove the host
304 if (h.locations().size() == 1) {
Jian Li07598ff2018-07-23 18:34:34 +0900305 hostProviderService.hostVanished(h.id());
Jian Li24ec59f2018-05-23 19:01:25 +0900306 }
307
Jian Liec5c32b2018-07-13 14:28:58 +0900308 // if the host contains multiple locations, we simply remove the
309 // host location
310 if (h.locations().size() > 1 && hostLocation.isPresent()) {
Jian Li07598ff2018-07-23 18:34:34 +0900311 hostProviderService.removeLocationFromHost(h.id(), hostLocation.get());
Jian Liec5c32b2018-07-13 14:28:58 +0900312 }
313 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900314 }
315
Jian Li9d676fb2018-03-02 15:25:36 +0900316 /**
317 * An internal device listener which listens the port events generated from
318 * OVS integration bridge.
319 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900320 private class InternalDeviceListener implements DeviceListener {
321
322 @Override
323 public boolean isRelevant(DeviceEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900324 Port port = event.port();
325 if (port == null) {
326 return false;
327 }
Jian Li34220ea2018-11-14 01:30:24 +0900328
Hyunsun Moon44aac662017-02-18 02:07:01 +0900329 String portName = port.annotations().value(PORT_NAME);
Jian Li9d676fb2018-03-02 15:25:36 +0900330
331 return !Strings.isNullOrEmpty(portName) &&
Daniel Park7e8c4d82018-08-13 23:47:49 +0900332 (portName.startsWith(PORT_NAME_PREFIX_VM) ||
333 isDirectPort(portName) ||
334 portName.startsWith(PORT_NAME_VHOST_USER_PREFIX_VM));
Daniel Parkc4d06402018-05-28 15:57:37 +0900335 }
336
Jian Li34220ea2018-11-14 01:30:24 +0900337 private boolean isRelevantHelper(DeviceEvent event) {
338 return mastershipService.isLocalMaster(event.subject().id());
339 }
340
Daniel Parkc4d06402018-05-28 15:57:37 +0900341 private boolean isDirectPort(String portName) {
Jian Li07598ff2018-07-23 18:34:34 +0900342 return portNamePrefixMap().values().stream().anyMatch(portName::startsWith);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900343 }
344
345 @Override
346 public void event(DeviceEvent event) {
Daniel Parkc4d06402018-05-28 15:57:37 +0900347 log.info("Device event occurred with type {}", event.type());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900348 switch (event.type()) {
349 case PORT_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900350 executor.execute(() -> processPortUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900351 break;
352 case PORT_ADDED:
Jian Li6a47fd02018-11-27 21:51:03 +0900353 executor.execute(() -> processPortAddition(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354 break;
Hyunsun Moonb7a9cd22017-02-24 11:12:53 +0900355 case PORT_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900356 executor.execute(() -> processPortRemoval(event));
Ray Milkeyd6a67c32018-02-02 10:30:35 -0800357 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900358 default:
359 break;
360 }
361 }
Jian Li6a47fd02018-11-27 21:51:03 +0900362
363 private void processPortUpdate(DeviceEvent event) {
364 if (!isRelevantHelper(event)) {
365 return;
366 }
367
368 if (!event.port().isEnabled()) {
369 portRemovedHelper(event);
370 } else if (event.port().isEnabled()) {
371 portAddedHelper(event);
372 }
373 }
374
375 private void processPortAddition(DeviceEvent event) {
376 if (!isRelevantHelper(event)) {
377 return;
378 }
379
380 portAddedHelper(event);
381 }
382
383 private void processPortRemoval(DeviceEvent event) {
384 if (!isRelevantHelper(event)) {
385 return;
386 }
387
388 portRemovedHelper(event);
389 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900390 }
391
392 private class InternalOpenstackNodeListener implements OpenstackNodeListener {
393
394 @Override
Jian Li9d676fb2018-03-02 15:25:36 +0900395 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900396 return event.subject().type() != CONTROLLER;
397 }
Jian Li51b844c2018-05-31 10:59:03 +0900398
Jian Li34220ea2018-11-14 01:30:24 +0900399 private boolean isRelevantHelper(OpenstackNodeEvent event) {
Jian Li9d676fb2018-03-02 15:25:36 +0900400 // do not allow to proceed without mastership
401 Device device = deviceService.getDevice(event.subject().intgBridge());
Jian Li7ddea782018-03-30 11:17:42 +0900402 if (device == null) {
403 return false;
404 }
Jian Li9d676fb2018-03-02 15:25:36 +0900405 return mastershipService.isLocalMaster(device.id());
406 }
407
408 @Override
Hyunsun Moon44aac662017-02-18 02:07:01 +0900409 public void event(OpenstackNodeEvent event) {
410 OpenstackNode osNode = event.subject();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900411
412 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900413 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900414 executor.execute(() -> processCompleteNode(event, event.subject()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900415 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900416 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900417 log.warn("{} is changed to INCOMPLETE state", osNode);
418 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900419 case OPENSTACK_NODE_CREATED:
420 case OPENSTACK_NODE_UPDATED:
421 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900422 default:
423 break;
424 }
425 }
426
Jian Li6a47fd02018-11-27 21:51:03 +0900427 private void processCompleteNode(OpenstackNodeEvent event,
428 OpenstackNode osNode) {
429
430 if (!isRelevantHelper(event)) {
431 return;
432 }
433
434 log.info("COMPLETE node {} is detected", osNode.hostname());
435
Hyunsun Moon0d457362017-06-27 17:19:41 +0900436 deviceService.getPorts(osNode.intgBridge()).stream()
Jian Li32b03622018-11-06 17:54:24 +0900437 .filter(port -> vnicType(port.annotations().value(PORT_NAME))
438 .equals(Constants.VnicType.NORMAL) ||
439 vnicType(port.annotations().value(PORT_NAME))
440 .equals(Constants.VnicType.DIRECT))
Daniel Park7e8c4d82018-08-13 23:47:49 +0900441 .filter(Port::isEnabled)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900442 .forEach(port -> {
443 log.debug("Instance port {} is detected from {}",
Jian Li46b74002018-07-15 18:39:08 +0900444 port.annotations().value(PORT_NAME),
445 osNode.hostname());
Jian Li07598ff2018-07-23 18:34:34 +0900446 processPortAdded(port);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900447 });
448
Hyunsun Moon44aac662017-02-18 02:07:01 +0900449 Tools.stream(hostService.getHosts())
450 .filter(host -> deviceService.getPort(
451 host.location().deviceId(),
452 host.location().port()) == null)
453 .forEach(host -> {
454 log.info("Remove stale host {}", host.id());
Jian Li07598ff2018-07-23 18:34:34 +0900455 hostProviderService.hostVanished(host.id());
Jian Li46b74002018-07-15 18:39:08 +0900456 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900457 }
458 }
Jian Li46276ef2020-07-13 16:20:28 +0900459
460 private class InternalNetworkListener implements OpenstackNetworkListener {
461
462 @Override
463 public void event(OpenstackNetworkEvent event) {
464 switch (event.type()) {
465 case OPENSTACK_PORT_CREATED:
466 executor.execute(() -> processOpenstackPortAddition(event));
467 break;
468 default:
469 break;
470 }
471 }
472
473 private void processOpenstackPortAddition(OpenstackNetworkEvent event) {
474 String portId = event.port().getId();
475 deviceService.getDevices().forEach(device -> {
476 deviceService.getPorts(device.id()).stream()
477 .filter(Port::isEnabled)
478 .filter(p -> p.annotations().value(PORT_NAME) != null)
479 .filter(p -> portId.contains(p.annotations().value(PORT_NAME).substring(3)))
480 .filter(p -> !TUNNEL_TYPE.contains(p.annotations().value(PORT_NAME).toUpperCase()))
481 .findAny().ifPresent(OpenstackSwitchingHostProvider.this::processPortAdded);
482 });
483 }
484 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900485}