blob: 2c20f6a7af0d1abb110e394006f81e90744f81f9 [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;
Jian Li1064e4f2018-05-29 16:16:53 +090019import com.google.common.collect.ImmutableSet;
Jian Li99892e92018-04-13 14:59:39 +090020import com.google.common.collect.Maps;
Jian Li1064e4f2018-05-29 16:16:53 +090021import com.google.common.collect.Sets;
Hyunsun Moon44aac662017-02-18 02:07:01 +090022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.onlab.packet.Ethernet;
28import org.onlab.packet.IpAddress;
29import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090030import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onosproject.cluster.ClusterService;
32import org.onosproject.cluster.LeadershipService;
33import org.onosproject.cluster.NodeId;
34import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
Jian Li24ec59f2018-05-23 19:01:25 +090036import org.onosproject.net.DeviceId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.net.PortNumber;
38import org.onosproject.net.device.DeviceService;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090044import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090045import org.onosproject.openstacknetworking.api.InstancePort;
Jian Liec5c32b2018-07-13 14:28:58 +090046import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090047import org.onosproject.openstacknetworking.api.InstancePortEvent;
48import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090049import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Lie1a39032018-06-19 21:49:36 +090050import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
51import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090052import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090053import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090054import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
55import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090056import org.onosproject.openstacknode.api.OpenstackNode;
57import org.onosproject.openstacknode.api.OpenstackNodeEvent;
58import org.onosproject.openstacknode.api.OpenstackNodeListener;
59import org.onosproject.openstacknode.api.OpenstackNodeService;
daniel parkeeb8e042018-02-21 14:06:58 +090060import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import org.openstack4j.model.network.NetFloatingIP;
62import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090063import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import org.openstack4j.model.network.Port;
daniel parkeeb8e042018-02-21 14:06:58 +090065import org.openstack4j.model.network.Router;
66import org.openstack4j.model.network.RouterInterface;
67import org.openstack4j.model.network.Subnet;
Jian Lif3a28b02018-06-11 21:29:13 +090068import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090069import org.slf4j.Logger;
70import org.slf4j.LoggerFactory;
71
Jian Li99892e92018-04-13 14:59:39 +090072import java.util.Map;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090074import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075import java.util.concurrent.ExecutorService;
76
77import static java.util.concurrent.Executors.newSingleThreadExecutor;
78import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090079import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
80import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090081import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090082import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
83import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090084import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Liec5c32b2018-07-13 14:28:58 +090085import static org.onosproject.openstacknetworking.api.InstancePort.State.PENDING_REMOVAL;
86import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVED;
Jian Lie1a39032018-06-19 21:49:36 +090087import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
88import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Li24ec59f2018-05-23 19:01:25 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Jian Li1064e4f2018-05-29 16:16:53 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Li24ec59f2018-05-23 19:01:25 +090091import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Liec5c32b2018-07-13 14:28:58 +090092import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090093import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090094import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090095
96/**
97 * Handles OpenStack floating IP events.
98 */
99@Component(immediate = true)
100public class OpenstackRoutingFloatingIpHandler {
101
102 private final Logger log = LoggerFactory.getLogger(getClass());
103
104 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800105 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected CoreService coreService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected DeviceService deviceService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114 protected LeadershipService leadershipService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected ClusterService clusterService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected OpenstackNodeService osNodeService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liec5c32b2018-07-13 14:28:58 +0900123 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900126 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected OpenstackNetworkService osNetworkService;
130
sanghodc375372017-06-08 10:41:30 +0900131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected OpenstackFlowRuleService osFlowRuleService;
133
Hyunsun Moon44aac662017-02-18 02:07:01 +0900134 private final ExecutorService eventExecutor = newSingleThreadExecutor(
135 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li24ec59f2018-05-23 19:01:25 +0900136 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
137 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Lie1a39032018-06-19 21:49:36 +0900139 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
140 private final InstancePortListener instPortListener = new InternalInstancePortListener();
141
142 private Map<String, Port> terminatedOsPorts = Maps.newConcurrentMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143
144 private ApplicationId appId;
145 private NodeId localNodeId;
146
147 @Activate
148 protected void activate() {
149 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
150 localNodeId = clusterService.getLocalNode().id();
151 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900152 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900153 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900154 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900155 osNodeService.addListener(osNodeListener);
156 osNetworkService.addListener(osNetworkListener);
157 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158
159 log.info("Started");
160 }
161
162 @Deactivate
163 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900164 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900165 instancePortService.removeListener(instPortListener);
166 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900168 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 leadershipService.withdraw(appId.name());
170 eventExecutor.shutdown();
171
172 log.info("Stopped");
173 }
174
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 private void setFloatingIpRules(NetFloatingIP floatingIp, Port osPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900176 OpenstackNode gateway, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 Network osNet = osNetworkService.network(osPort.getNetworkId());
178 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900179 final String errorFormat = ERR_FLOW + "no network(%s) exists";
180 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 floatingIp.getFloatingIpAddress(),
182 osPort.getNetworkId());
183 throw new IllegalStateException(error);
184 }
185
186 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
daniel parkc2a2ed62018-04-10 15:17:42 +0900187 log.trace("Mac address of openstack port: {}", srcMac);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 InstancePort instPort = instancePortService.instancePort(srcMac);
Jian Li99892e92018-04-13 14:59:39 +0900189
Jian Li99892e92018-04-13 14:59:39 +0900190 if (instPort == null) {
Jian Li71670d12018-03-02 21:31:07 +0900191 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
192 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 floatingIp.getFloatingIpAddress(), srcMac);
194 throw new IllegalStateException(error);
195 }
196
Jian Liec5c32b2018-07-13 14:28:58 +0900197 if (instPort.state() == PENDING_REMOVAL) {
198 instancePortService.updateInstancePort(instPort.updateState(REMOVED));
199 }
200
daniel park32b42202018-03-14 16:53:44 +0900201 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
202 if (externalPeerRouter == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900203 final String errorFormat = ERR_FLOW + "no external peer router found";
204 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900205 }
206
Jian Lide679782018-06-05 01:41:29 +0900207 updateComputeNodeRules(instPort, osNet, gateway, install);
208 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
209
210 // FIXME: downstream internal rules are still duplicated in all gateway nodes
211 // need to make the internal rules de-duplicated sooner or later
212 setDownstreamInternalRules(floatingIp, osNet, instPort, install);
213
214 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900215 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900216 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
217 floatingIp.getFloatingIpAddress(),
218 floatingIp.getFixedIpAddress(),
219 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900220 }
221
Jian Lide679782018-06-05 01:41:29 +0900222 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
223 InstancePort instPort,
224 Network osNet,
225 ExternalPeerRouter router,
226 OpenstackNode gateway,
227 boolean install) {
228
229 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
230 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
231 finalGws.addAll(ImmutableSet.copyOf(completedGws));
232
Jian Lia171a432018-06-11 11:52:11 +0900233
234 if (gateway == null) {
235 // these are floating IP related cases...
236 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
237 ImmutableSet.copyOf(finalGws), install);
238
Jian Lide679782018-06-05 01:41:29 +0900239 } else {
Jian Lia171a432018-06-11 11:52:11 +0900240 // these are openstack node related cases...
241 if (install) {
242 if (completedGws.contains(gateway)) {
243 if (completedGws.size() > 1) {
244 finalGws.remove(gateway);
245 if (fip.getPortId() != null) {
246 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
247 ImmutableSet.copyOf(finalGws), false);
248 finalGws.add(gateway);
249 }
250 }
Jian Lide679782018-06-05 01:41:29 +0900251 if (fip.getPortId() != null) {
252 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
253 ImmutableSet.copyOf(finalGws), true);
254 }
Jian Lia171a432018-06-11 11:52:11 +0900255 } else {
256 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900257 }
258 } else {
Jian Lia171a432018-06-11 11:52:11 +0900259 if (!completedGws.contains(gateway)) {
260 if (completedGws.size() >= 1) {
261 if (fip.getPortId() != null) {
262 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
263 ImmutableSet.copyOf(finalGws), true);
264 }
265 }
266 } else {
267 log.warn("Detected node should NOT be included in completed gateway set");
268 }
Jian Lide679782018-06-05 01:41:29 +0900269 }
270 }
271 }
272
273 private synchronized void updateComputeNodeRules(InstancePort instPort,
274 Network osNet,
275 OpenstackNode gateway,
276 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900277
278 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
279 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
280 finalGws.addAll(ImmutableSet.copyOf(completedGws));
281
282 if (gateway == null) {
283 // these are floating IP related cases...
284 setComputeNodeToGatewayHelper(instPort, osNet,
285 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900286
Jian Li1064e4f2018-05-29 16:16:53 +0900287 } else {
288 // these are openstack node related cases...
289 if (install) {
290 if (completedGws.contains(gateway)) {
291 if (completedGws.size() > 1) {
292 finalGws.remove(gateway);
293 setComputeNodeToGatewayHelper(instPort, osNet,
294 ImmutableSet.copyOf(finalGws), false);
295 finalGws.add(gateway);
296 }
297
298 setComputeNodeToGatewayHelper(instPort, osNet,
299 ImmutableSet.copyOf(finalGws), true);
300 } else {
301 log.warn("Detected node should be included in completed gateway set");
302 }
303 } else {
304 if (!completedGws.contains(gateway)) {
305 finalGws.add(gateway);
306 setComputeNodeToGatewayHelper(instPort, osNet,
307 ImmutableSet.copyOf(finalGws), false);
308 finalGws.remove(gateway);
309 if (completedGws.size() >= 1) {
310 setComputeNodeToGatewayHelper(instPort, osNet,
311 ImmutableSet.copyOf(finalGws), true);
312 }
313 } else {
314 log.warn("Detected node should NOT be included in completed gateway set");
315 }
316 }
317 }
318 }
319
320 // a helper method
321 private void setComputeNodeToGatewayHelper(InstancePort instPort,
322 Network osNet,
323 Set<OpenstackNode> gateways,
324 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900325 TrafficTreatment treatment;
326
327 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
328 .matchEthType(Ethernet.TYPE_IPV4)
329 .matchIPSrc(instPort.ipAddress().toIpPrefix())
330 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
331
332 switch (osNet.getNetworkType()) {
333 case VXLAN:
334 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
335 break;
336 case VLAN:
337 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
338 break;
339 default:
340 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800341 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900342 osNet.getNetworkType().toString());
343 throw new IllegalStateException(error);
344 }
345
Jian Li1064e4f2018-05-29 16:16:53 +0900346 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
347
daniel parkeeb8e042018-02-21 14:06:58 +0900348 if (selectedGatewayNode == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900349 final String errorFormat = ERR_FLOW + "no gateway node selected";
350 throw new IllegalStateException(errorFormat);
daniel parkeeb8e042018-02-21 14:06:58 +0900351 }
352 treatment = DefaultTrafficTreatment.builder()
353 .extension(buildExtension(
354 deviceService,
355 instPort.deviceId(),
356 selectedGatewayNode.dataIp().getIp4Address()),
357 instPort.deviceId())
358 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
359 .build();
360
361 osFlowRuleService.setRule(
362 appId,
363 instPort.deviceId(),
364 sBuilder.build(),
365 treatment,
366 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
367 ROUTING_TABLE,
368 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900369 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900370 }
371
Jian Lide679782018-06-05 01:41:29 +0900372 private void setDownstreamInternalRules(NetFloatingIP floatingIp,
373 Network osNet,
374 InstancePort instPort,
375 boolean install) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900376 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
377 if (cNode == null) {
378 final String error = String.format("Cannot find openstack node for device %s",
379 instPort.deviceId());
380 throw new IllegalStateException(error);
381 }
382 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900383 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
384 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900385 throw new IllegalStateException(error);
386 }
387 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900388 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
389 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900390 throw new IllegalStateException(error);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900391 }
392
393 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900394
Jian Lide679782018-06-05 01:41:29 +0900395 // TODO: following code snippet will be refactored sooner or later
Hyunsun Moon0d457362017-06-27 17:19:41 +0900396 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900397 // access from one VM to the others via floating IP
Hyunsun Moon44aac662017-02-18 02:07:01 +0900398 TrafficSelector internalSelector = DefaultTrafficSelector.builder()
399 .matchEthType(Ethernet.TYPE_IPV4)
400 .matchIPDst(floating.toIpPrefix())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900401 .matchInPort(gNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900402 .build();
403
daniel parkee8700b2017-05-11 15:50:03 +0900404 TrafficTreatment.Builder internalBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900405 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
406 .setEthDst(instPort.macAddress())
daniel parkee8700b2017-05-11 15:50:03 +0900407 .setIpDst(instPort.ipAddress().getIp4Address());
408
409 switch (osNet.getNetworkType()) {
410 case VXLAN:
411 internalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
412 .extension(buildExtension(
413 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900414 gNode.intgBridge(),
415 cNode.dataIp().getIp4Address()),
416 gNode.intgBridge())
daniel parkee8700b2017-05-11 15:50:03 +0900417 .setOutput(PortNumber.IN_PORT);
418 break;
419 case VLAN:
420 internalBuilder.pushVlan()
421 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
422 .setOutput(PortNumber.IN_PORT);
423 break;
424 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800425 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900426 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900427 throw new IllegalStateException(error);
428 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900429
sanghodc375372017-06-08 10:41:30 +0900430 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900431 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900432 gNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900433 internalSelector,
daniel parkee8700b2017-05-11 15:50:03 +0900434 internalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900435 PRIORITY_FLOATING_INTERNAL,
sanghodc375372017-06-08 10:41:30 +0900436 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900437 install);
438 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900439 log.trace("Succeeded to set flow rules for downstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900440 }
441
Jian Lide679782018-06-05 01:41:29 +0900442 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
443 Network osNet,
444 InstancePort instPort,
445 ExternalPeerRouter externalPeerRouter,
446 Set<OpenstackNode> gateways, boolean install) {
447 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
448 if (cNode == null) {
449 final String error = String.format("Cannot find openstack node for device %s",
450 instPort.deviceId());
451 throw new IllegalStateException(error);
452 }
453 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
454 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
455 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
456 throw new IllegalStateException(error);
457 }
458 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
459 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
460 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
461 throw new IllegalStateException(error);
462 }
463
464 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
465
466 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
467
468 if (selectedGatewayNode == null) {
469 final String errorFormat = ERR_FLOW + "no gateway node selected";
470 throw new IllegalStateException(errorFormat);
471 }
472
473 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
474 .matchEthType(Ethernet.TYPE_IPV4)
475 .matchIPDst(floating.toIpPrefix());
476
477 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
478 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
479 .setEthDst(instPort.macAddress())
480 .setIpDst(instPort.ipAddress().getIp4Address());
481
482 if (!externalPeerRouter.externalPeerRouterVlanId().equals(VlanId.NONE)) {
483 externalSelectorBuilder.matchVlanId(externalPeerRouter.externalPeerRouterVlanId()).build();
484 externalTreatmentBuilder.popVlan();
485 }
486
487 switch (osNet.getNetworkType()) {
488 case VXLAN:
489 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
490 .extension(buildExtension(
491 deviceService,
492 selectedGatewayNode.intgBridge(),
493 cNode.dataIp().getIp4Address()),
494 selectedGatewayNode.intgBridge())
495 .setOutput(selectedGatewayNode.tunnelPortNum());
496 break;
497 case VLAN:
498 externalTreatmentBuilder.pushVlan()
499 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
500 .setOutput(selectedGatewayNode.vlanPortNum());
501 break;
502 default:
503 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
504 osNet.getNetworkType());
505 throw new IllegalStateException(error);
506 }
507
508 osFlowRuleService.setRule(
509 appId,
510 selectedGatewayNode.intgBridge(),
511 externalSelectorBuilder.build(),
512 externalTreatmentBuilder.build(),
513 PRIORITY_FLOATING_EXTERNAL,
514 GW_COMMON_TABLE,
515 install);
516 }
517
Hyunsun Moon44aac662017-02-18 02:07:01 +0900518 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
daniel park32b42202018-03-14 16:53:44 +0900519 InstancePort instPort, ExternalPeerRouter externalPeerRouter,
520 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900521 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900522 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900523 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900524 .matchIPSrc(instPort.ipAddress().toIpPrefix());
525
526 switch (osNet.getNetworkType()) {
527 case VXLAN:
528 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
529 break;
530 case VLAN:
531 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
532 break;
533 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800534 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900535 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900536 throw new IllegalStateException(error);
537 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900538
Daniel Park75e3d7f2018-05-29 14:43:53 +0900539 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900540
Hyunsun Moon0d457362017-06-27 17:19:41 +0900541 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900542 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
543 .setIpSrc(floating.getIp4Address())
544 .setEthSrc(instPort.macAddress())
545 .setEthDst(externalPeerRouter.externalPeerRouterMac());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900546
Daniel Park75e3d7f2018-05-29 14:43:53 +0900547 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
548 tBuilder.popVlan();
549 }
550
551 if (!externalPeerRouter.externalPeerRouterVlanId().equals(VlanId.NONE)) {
552 tBuilder.pushVlan().setVlanId(externalPeerRouter.externalPeerRouterVlanId());
553 }
sanghodc375372017-06-08 10:41:30 +0900554 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900555 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900556 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900557 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900558 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900560 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900561 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900562 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900563 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900564 }
565
daniel park32b42202018-03-14 16:53:44 +0900566 private ExternalPeerRouter externalPeerRouter(Network network) {
daniel parkeeb8e042018-02-21 14:06:58 +0900567 if (network == null) {
568 return null;
569 }
570
571 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
572
573 if (subnet == null) {
574 return null;
575 }
576
Jian Lif3a28b02018-06-11 21:29:13 +0900577 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900578 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
579 .findAny().orElse(null);
580 if (osRouterIface == null) {
581 return null;
582 }
583
Jian Lif3a28b02018-06-11 21:29:13 +0900584 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
daniel parkeeb8e042018-02-21 14:06:58 +0900585 if (osRouter == null) {
586 return null;
587 }
588 if (osRouter.getExternalGatewayInfo() == null) {
589 return null;
590 }
591
592 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
daniel park65e1c202018-04-03 13:15:28 +0900593 return osNetworkService.externalPeerRouter(exGatewayInfo);
daniel parkeeb8e042018-02-21 14:06:58 +0900594 }
daniel park65e1c202018-04-03 13:15:28 +0900595
Jian Li99892e92018-04-13 14:59:39 +0900596 private void associateFloatingIp(NetFloatingIP osFip) {
597 Port osPort = osNetworkService.port(osFip.getPortId());
598 if (osPort == null) {
599 final String errorFormat = ERR_FLOW + "port(%s) not found";
600 final String error = String.format(errorFormat,
601 osFip.getFloatingIpAddress(), osFip.getPortId());
602 throw new IllegalStateException(error);
603 }
604 // set floating IP rules only if the port is associated to a VM
605 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
Jian Lie1a39032018-06-19 21:49:36 +0900606
607 if (instancePortService.instancePort(osPort.getId()) == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900608 return;
609 }
610
Jian Li1064e4f2018-05-29 16:16:53 +0900611 setFloatingIpRules(osFip, osPort, null, true);
Jian Li99892e92018-04-13 14:59:39 +0900612 }
613 }
614
615 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
616 Port osPort = osNetworkService.port(portId);
617 if (osPort == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900618 osPort = terminatedOsPorts.get(portId);
619 terminatedOsPorts.remove(portId);
Jian Li99892e92018-04-13 14:59:39 +0900620 }
Jian Lie1a39032018-06-19 21:49:36 +0900621
622 if (osPort == null) {
623 final String errorFormat = ERR_FLOW + "port(%s) not found";
624 final String error = String.format(errorFormat,
625 osFip.getFloatingIpAddress(), osFip.getPortId());
626 throw new IllegalStateException(error);
627 }
628
Jian Li99892e92018-04-13 14:59:39 +0900629 // set floating IP rules only if the port is associated to a VM
630 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
Jian Lie1a39032018-06-19 21:49:36 +0900631
Jian Lie1a39032018-06-19 21:49:36 +0900632 if (instancePortService.instancePort(osPort.getId()) == null) {
Jian Li46b74002018-07-15 18:39:08 +0900633 return;
Jian Lie1a39032018-06-19 21:49:36 +0900634 }
635
Jian Li1064e4f2018-05-29 16:16:53 +0900636 setFloatingIpRules(osFip, osPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900637 }
638 }
639
Hyunsun Moon0d457362017-06-27 17:19:41 +0900640 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900641
642 @Override
643 public boolean isRelevant(OpenstackRouterEvent event) {
644 // do not allow to proceed without leadership
645 NodeId leader = leadershipService.getLeader(appId.name());
646 if (!Objects.equals(localNodeId, leader)) {
647 return false;
648 }
649 return event.floatingIp() != null;
650 }
651
652 @Override
653 public void event(OpenstackRouterEvent event) {
654 switch (event.type()) {
655 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900656 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900657 NetFloatingIP osFip = event.floatingIp();
658 associateFloatingIp(osFip);
659 log.info("Associated floating IP {}:{}",
660 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900661 });
662 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900663 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
664 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900665 NetFloatingIP osFip = event.floatingIp();
666 disassociateFloatingIp(osFip, event.portId());
667 log.info("Disassociated floating IP {}:{}",
668 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900669 });
670 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900671 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900672 eventExecutor.execute(() -> {
673 NetFloatingIP osFip = event.floatingIp();
674 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
675 associateFloatingIp(event.floatingIp());
676 }
677 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
678 });
679 break;
Jian Lia171a432018-06-11 11:52:11 +0900680 case OPENSTACK_FLOATING_IP_REMOVED:
681 eventExecutor.execute(() -> {
682 NetFloatingIP osFip = event.floatingIp();
683 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
684 disassociateFloatingIp(osFip, osFip.getPortId());
685 }
686 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
687 });
688 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900689 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900690 case OPENSTACK_ROUTER_CREATED:
691 case OPENSTACK_ROUTER_UPDATED:
692 case OPENSTACK_ROUTER_REMOVED:
693 case OPENSTACK_ROUTER_INTERFACE_ADDED:
694 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
695 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
696 default:
697 // do nothing for the other events
698 break;
699 }
700 }
701 }
702
703 private class InternalNodeListener implements OpenstackNodeListener {
704
705 @Override
706 public boolean isRelevant(OpenstackNodeEvent event) {
707 // do not allow to proceed without leadership
708 NodeId leader = leadershipService.getLeader(appId.name());
709 if (!Objects.equals(localNodeId, leader)) {
710 return false;
711 }
712 return event.subject().type() == GATEWAY;
713 }
714
715 @Override
716 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900717
718 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900719 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900720 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900721 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Lie1a39032018-06-19 21:49:36 +0900722
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900723 if (Strings.isNullOrEmpty(fip.getPortId())) {
724 continue;
725 }
Jian Lie1a39032018-06-19 21:49:36 +0900726
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900727 Port osPort = osNetworkService.port(fip.getPortId());
728 if (osPort == null) {
729 log.warn("Failed to set floating IP {}", fip.getId());
730 continue;
731 }
Jian Lie1a39032018-06-19 21:49:36 +0900732
Jian Li46b74002018-07-15 18:39:08 +0900733 if (instancePortService.instancePort(fip.getPortId()) == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900734 continue;
735 }
Jian Liec5c32b2018-07-13 14:28:58 +0900736
Jian Li1064e4f2018-05-29 16:16:53 +0900737 setFloatingIpRules(fip, osPort, event.subject(), true);
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900738 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900739 });
740 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900741 case OPENSTACK_NODE_INCOMPLETE:
Jian Li1064e4f2018-05-29 16:16:53 +0900742 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900743 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900744 if (Strings.isNullOrEmpty(fip.getPortId())) {
745 continue;
746 }
747 Port osPort = osNetworkService.port(fip.getPortId());
748 if (osPort == null) {
749 log.warn("Failed to set floating IP {}", fip.getId());
750 continue;
751 }
752 Network osNet = osNetworkService.network(osPort.getNetworkId());
753 if (osNet == null) {
754 final String errorFormat = ERR_FLOW + "no network(%s) exists";
755 final String error = String.format(errorFormat,
756 fip.getFloatingIpAddress(),
757 osPort.getNetworkId());
758 throw new IllegalStateException(error);
759 }
760 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
761 log.trace("Mac address of openstack port: {}", srcMac);
762 InstancePort instPort = instancePortService.instancePort(srcMac);
763
764 if (instPort == null) {
765 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
766 final String error = String.format(errorFormat,
767 fip.getFloatingIpAddress(), srcMac);
768 throw new IllegalStateException(error);
769 }
770
Jian Lide679782018-06-05 01:41:29 +0900771 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
772 if (externalPeerRouter == null) {
773 final String errorFormat = ERR_FLOW + "no external peer router found";
774 throw new IllegalStateException(errorFormat);
775 }
776
777 updateComputeNodeRules(instPort, osNet, event.subject(), false);
778 updateGatewayNodeRules(fip, instPort, osNet,
779 externalPeerRouter, event.subject(), false);
Jian Li1064e4f2018-05-29 16:16:53 +0900780 }
781 });
782 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900783 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900784 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900785 break;
786 }
787 }
788 }
Jian Li99892e92018-04-13 14:59:39 +0900789
Jian Li24ec59f2018-05-23 19:01:25 +0900790 private class InternalInstancePortListener implements InstancePortListener {
791
792 @Override
793 public boolean isRelevant(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900794
Jian Lie1a39032018-06-19 21:49:36 +0900795 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
796 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
797 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
798 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
799
800 // we check the possible NPE to avoid duplicated null check
801 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
802 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
803 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
804 return false;
805 }
806 }
807
808 // do not allow to proceed without leadership
809 NodeId leader = leadershipService.getLeader(appId.name());
810
811 return Objects.equals(localNodeId, leader);
Jian Li24ec59f2018-05-23 19:01:25 +0900812 }
813
814 @Override
815 public void event(InstancePortEvent event) {
Jian Lie1a39032018-06-19 21:49:36 +0900816 InstancePort instPort = event.subject();
Jian Li24ec59f2018-05-23 19:01:25 +0900817 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
818
Jian Lie1a39032018-06-19 21:49:36 +0900819 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
820 NetFloatingIP fip;
821 Port osPort;
822 Network osNet;
823 ExternalPeerRouter externalPeerRouter;
Jian Li24ec59f2018-05-23 19:01:25 +0900824
825 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900826 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li77323c52018-06-24 01:26:18 +0900827 if (instPort != null && instPort.portId() != null) {
828 String portId = instPort.portId();
Jian Lie1a39032018-06-19 21:49:36 +0900829
Jian Li77323c52018-06-24 01:26:18 +0900830 terminatedOsPorts.remove(portId);
831
832 Port port = osNetworkService.port(portId);
833
Jian Li46b74002018-07-15 18:39:08 +0900834 osRouterAdminService.floatingIps().stream()
835 .filter(f -> f.getPortId() != null)
836 .filter(f -> f.getPortId().equals(instPort.portId()))
837 .forEach(f -> setFloatingIpRules(f, port, null, true));
Jian Lie1a39032018-06-19 21:49:36 +0900838 }
839
840 break;
841
Jian Li24ec59f2018-05-23 19:01:25 +0900842 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Lie1a39032018-06-19 21:49:36 +0900843
844 fip = associatedFloatingIp(event.subject(), ips);
845
846 if (fip == null) {
847 return;
848 }
849
850 osPort = osNetworkService.port(fip.getPortId());
851 osNet = osNetworkService.network(osPort.getNetworkId());
852 externalPeerRouter = externalPeerRouter(osNet);
853
854 if (externalPeerRouter == null) {
855 final String errorFormat = ERR_FLOW + "no external peer router found";
856 throw new IllegalStateException(errorFormat);
857 }
858
Jian Li24ec59f2018-05-23 19:01:25 +0900859 eventExecutor.execute(() -> {
860
861 // since downstream internal rules are located in all gateway
862 // nodes, therefore, we simply update the rules with new compute node info
863 setDownstreamInternalRules(fip, osNet, event.subject(), true);
864
865 // since DownstreamExternal rules should only be placed in
866 // corresponding gateway node, we need to install new rule to
867 // the corresponding gateway node
868 setDownstreamExternalRulesHelper(fip, osNet,
869 event.subject(), externalPeerRouter, gateways, true);
870
871 // since ComputeNodeToGateway rules should only be placed in
872 // corresponding compute node, we need to install new rule to
873 // the target compute node, and remove rules from original node
874 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
Jian Li24ec59f2018-05-23 19:01:25 +0900875 });
876 break;
877 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
878
Jian Liec5c32b2018-07-13 14:28:58 +0900879 InstancePort revisedInstPort = swapStaleLocation(event.subject());
880
881 fip = associatedFloatingIp(revisedInstPort, ips);
Jian Lie1a39032018-06-19 21:49:36 +0900882
883 if (fip == null) {
884 return;
885 }
886
887 osPort = osNetworkService.port(fip.getPortId());
888 osNet = osNetworkService.network(osPort.getNetworkId());
889 externalPeerRouter = externalPeerRouter(osNet);
890
891 if (externalPeerRouter == null) {
892 final String errorFormat = ERR_FLOW + "no external peer router found";
893 throw new IllegalStateException(errorFormat);
894 }
895
896 // If we only have one gateway, we simply do not remove any
Jian Li24ec59f2018-05-23 19:01:25 +0900897 // flow rules from either gateway or compute node
898 if (gateways.size() == 1) {
899 return;
900 }
901
Jian Lie1a39032018-06-19 21:49:36 +0900902 // Checks whether the destination compute node's device id
Jian Li24ec59f2018-05-23 19:01:25 +0900903 // has identical gateway hash or not
904 // if it is true, we simply do not remove the rules, as
905 // it has been overwritten at port detention event
906 // if it is false, we will remove the rules
Jian Liec5c32b2018-07-13 14:28:58 +0900907 DeviceId newDeviceId = event.subject().deviceId();
908 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Li24ec59f2018-05-23 19:01:25 +0900909
910 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
911 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
912
913 if (oldGateway != null && oldGateway.equals(newGateway)) {
914 return;
915 }
916
917 eventExecutor.execute(() -> {
918
Jian Lie1a39032018-06-19 21:49:36 +0900919 // We need to remove the old ComputeNodeToGateway rules from
Jian Li24ec59f2018-05-23 19:01:25 +0900920 // original compute node
Jian Liec5c32b2018-07-13 14:28:58 +0900921 setComputeNodeToGatewayHelper(revisedInstPort, osNet, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900922
Jian Lie1a39032018-06-19 21:49:36 +0900923 // Since DownstreamExternal rules should only be placed in
Jian Li24ec59f2018-05-23 19:01:25 +0900924 // corresponding gateway node, we need to remove old rule from
925 // the corresponding gateway node
Jian Liec5c32b2018-07-13 14:28:58 +0900926 setDownstreamExternalRulesHelper(fip, osNet, revisedInstPort,
927 externalPeerRouter, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900928 });
929 break;
930 default:
931 break;
932 }
933 }
934 }
Jian Lie1a39032018-06-19 21:49:36 +0900935
936 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
937
938 @Override
939 public boolean isRelevant(OpenstackNetworkEvent event) {
940 // do not allow to proceed without leadership
941 NodeId leader = leadershipService.getLeader(appId.name());
942 return Objects.equals(localNodeId, leader);
943 }
944
945 @Override
946 public void event(OpenstackNetworkEvent event) {
947 switch (event.type()) {
948 case OPENSTACK_PORT_REMOVED:
Jian Liec5c32b2018-07-13 14:28:58 +0900949 String portId = event.port().getId();
950 terminatedOsPorts.put(portId, event.port());
951
952 InstancePort instPort = instancePortService.instancePort(portId);
953 InstancePort updated = instPort.updateState(PENDING_REMOVAL);
954 instancePortService.updateInstancePort(updated);
955
956 updateFipStore(instPort);
957
958 // we will hold the instance port in its store, until its
959 // state is changed to REMOVED
960 while (true) {
961 if (instancePortService.instancePort(portId).state() ==
962 REMOVED) {
963 instancePortService.removeInstancePort(portId);
964 break;
965 }
Jian Lie1a39032018-06-19 21:49:36 +0900966 }
967 break;
968 default:
969 break;
970 }
971 }
972
973 private void updateFipStore(InstancePort port) {
974
975 if (port == null) {
976 return;
977 }
978
979 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
980 for (NetFloatingIP fip : ips) {
981 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
982 continue;
983 }
984 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
985 continue;
986 }
987 if (fip.getFixedIpAddress().equals(port.ipAddress().toString())) {
988 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
989 // invalidate bound fixed IP and port
990 neutronFip.setFixedIpAddress(null);
991 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900992
993 // Following update will in turn trigger
994 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
995 osRouterAdminService.updateFloatingIp(neutronFip);
996 log.info("Updated floating IP {}, due to host removal",
997 neutronFip.getFloatingIpAddress());
998 }
999 }
1000 }
1001 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001002}