blob: 4ca4a6a792cdc087012bc51d0f5f835b56096a3e [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;
Jian Li99892e92018-04-13 14:59:39 +090037import org.onosproject.net.Host;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.net.PortNumber;
39import org.onosproject.net.device.DeviceService;
40import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
Jian Li99892e92018-04-13 14:59:39 +090044import org.onosproject.net.host.HostEvent;
45import org.onosproject.net.host.HostListener;
46import org.onosproject.net.host.HostService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090048import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090050import org.onosproject.openstacknetworking.api.InstancePortEvent;
51import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090053import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
54import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090055import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
57import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090058import org.onosproject.openstacknode.api.OpenstackNode;
59import org.onosproject.openstacknode.api.OpenstackNodeEvent;
60import org.onosproject.openstacknode.api.OpenstackNodeListener;
61import org.onosproject.openstacknode.api.OpenstackNodeService;
daniel parkeeb8e042018-02-21 14:06:58 +090062import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063import org.openstack4j.model.network.NetFloatingIP;
64import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090065import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090066import org.openstack4j.model.network.Port;
daniel parkeeb8e042018-02-21 14:06:58 +090067import org.openstack4j.model.network.Router;
68import org.openstack4j.model.network.RouterInterface;
69import org.openstack4j.model.network.Subnet;
Jian Lif3a28b02018-06-11 21:29:13 +090070import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090071import org.slf4j.Logger;
72import org.slf4j.LoggerFactory;
73
Jian Li99892e92018-04-13 14:59:39 +090074import java.util.Map;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090076import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090077import java.util.concurrent.ExecutorService;
78
79import static java.util.concurrent.Executors.newSingleThreadExecutor;
80import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090081import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
82import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090083import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090084import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
85import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090086import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li99892e92018-04-13 14:59:39 +090087import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_NETWORK_ID;
88import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_PORT_ID;
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 Li26949762018-03-30 15:46:37 +090092import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090093import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090094
95/**
96 * Handles OpenStack floating IP events.
97 */
98@Component(immediate = true)
99public class OpenstackRoutingFloatingIpHandler {
100
101 private final Logger log = LoggerFactory.getLogger(getClass());
102
103 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800104 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected CoreService coreService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected DeviceService deviceService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113 protected LeadershipService leadershipService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected ClusterService clusterService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li99892e92018-04-13 14:59:39 +0900119 protected HostService hostService;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122 protected OpenstackNodeService osNodeService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected InstancePortService instancePortService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900128 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected OpenstackNetworkService osNetworkService;
132
sanghodc375372017-06-08 10:41:30 +0900133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
134 protected OpenstackFlowRuleService osFlowRuleService;
135
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136 private final ExecutorService eventExecutor = newSingleThreadExecutor(
137 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li24ec59f2018-05-23 19:01:25 +0900138 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
139 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Li99892e92018-04-13 14:59:39 +0900141 private final HostListener hostListener = new InternalHostListener();
142 private Map<MacAddress, InstancePort> removedPorts = Maps.newConcurrentMap();
Jian Li24ec59f2018-05-23 19:01:25 +0900143 private Map<String, DeviceId> migrationPool = Maps.newConcurrentMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144
145 private ApplicationId appId;
146 private NodeId localNodeId;
147
148 @Activate
149 protected void activate() {
150 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
151 localNodeId = clusterService.getLocalNode().id();
152 leadershipService.runForLeadership(appId.name());
Jian Li99892e92018-04-13 14:59:39 +0900153 hostService.addListener(hostListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900154 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900155 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900156 instancePortService.addListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157
158 log.info("Started");
159 }
160
161 @Deactivate
162 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900163 instancePortService.removeListener(instancePortListener);
Jian Li99892e92018-04-13 14:59:39 +0900164 hostService.removeListener(hostListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900166 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167 leadershipService.withdraw(appId.name());
168 eventExecutor.shutdown();
169
170 log.info("Stopped");
171 }
172
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173 private void setFloatingIpRules(NetFloatingIP floatingIp, Port osPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900174 OpenstackNode gateway, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 Network osNet = osNetworkService.network(osPort.getNetworkId());
176 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900177 final String errorFormat = ERR_FLOW + "no network(%s) exists";
178 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900179 floatingIp.getFloatingIpAddress(),
180 osPort.getNetworkId());
181 throw new IllegalStateException(error);
182 }
183
184 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
daniel parkc2a2ed62018-04-10 15:17:42 +0900185 log.trace("Mac address of openstack port: {}", srcMac);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 InstancePort instPort = instancePortService.instancePort(srcMac);
Jian Li99892e92018-04-13 14:59:39 +0900187
188 // sweep through removed port map
189 if (instPort == null) {
190 instPort = removedPorts.get(srcMac);
191 removedPorts.remove(srcMac);
192 }
193
Hyunsun Moon44aac662017-02-18 02:07:01 +0900194 if (instPort == null) {
Jian Li71670d12018-03-02 21:31:07 +0900195 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
196 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900197 floatingIp.getFloatingIpAddress(), srcMac);
198 throw new IllegalStateException(error);
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 Li1064e4f2018-05-29 16:16:53 +0900606 setFloatingIpRules(osFip, osPort, null, true);
Jian Li99892e92018-04-13 14:59:39 +0900607 }
608 }
609
610 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
611 Port osPort = osNetworkService.port(portId);
612 if (osPort == null) {
613 // FIXME when a port with floating IP removed without
614 // disassociation step, it can reach here
615 return;
616 }
617 // set floating IP rules only if the port is associated to a VM
618 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900619 setFloatingIpRules(osFip, osPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900620 }
621 }
622
Hyunsun Moon0d457362017-06-27 17:19:41 +0900623 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900624
625 @Override
626 public boolean isRelevant(OpenstackRouterEvent event) {
627 // do not allow to proceed without leadership
628 NodeId leader = leadershipService.getLeader(appId.name());
629 if (!Objects.equals(localNodeId, leader)) {
630 return false;
631 }
632 return event.floatingIp() != null;
633 }
634
635 @Override
636 public void event(OpenstackRouterEvent event) {
637 switch (event.type()) {
638 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900639 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900640 NetFloatingIP osFip = event.floatingIp();
641 associateFloatingIp(osFip);
642 log.info("Associated floating IP {}:{}",
643 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900644 });
645 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900646 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
647 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900648 NetFloatingIP osFip = event.floatingIp();
649 disassociateFloatingIp(osFip, event.portId());
650 log.info("Disassociated floating IP {}:{}",
651 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900652 });
653 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900654 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900655 eventExecutor.execute(() -> {
656 NetFloatingIP osFip = event.floatingIp();
657 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
658 associateFloatingIp(event.floatingIp());
659 }
660 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
661 });
662 break;
Jian Lia171a432018-06-11 11:52:11 +0900663 case OPENSTACK_FLOATING_IP_REMOVED:
664 eventExecutor.execute(() -> {
665 NetFloatingIP osFip = event.floatingIp();
666 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
667 disassociateFloatingIp(osFip, osFip.getPortId());
668 }
669 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
670 });
671 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900673 case OPENSTACK_ROUTER_CREATED:
674 case OPENSTACK_ROUTER_UPDATED:
675 case OPENSTACK_ROUTER_REMOVED:
676 case OPENSTACK_ROUTER_INTERFACE_ADDED:
677 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
678 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
679 default:
680 // do nothing for the other events
681 break;
682 }
683 }
684 }
685
686 private class InternalNodeListener implements OpenstackNodeListener {
687
688 @Override
689 public boolean isRelevant(OpenstackNodeEvent event) {
690 // do not allow to proceed without leadership
691 NodeId leader = leadershipService.getLeader(appId.name());
692 if (!Objects.equals(localNodeId, leader)) {
693 return false;
694 }
695 return event.subject().type() == GATEWAY;
696 }
697
698 @Override
699 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900700
701 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900702 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900703 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900704 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900705 if (Strings.isNullOrEmpty(fip.getPortId())) {
706 continue;
707 }
708 Port osPort = osNetworkService.port(fip.getPortId());
709 if (osPort == null) {
710 log.warn("Failed to set floating IP {}", fip.getId());
711 continue;
712 }
Jian Li1064e4f2018-05-29 16:16:53 +0900713 setFloatingIpRules(fip, osPort, event.subject(), true);
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900714 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900715 });
716 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900717 case OPENSTACK_NODE_INCOMPLETE:
Jian Li1064e4f2018-05-29 16:16:53 +0900718 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900719 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900720 if (Strings.isNullOrEmpty(fip.getPortId())) {
721 continue;
722 }
723 Port osPort = osNetworkService.port(fip.getPortId());
724 if (osPort == null) {
725 log.warn("Failed to set floating IP {}", fip.getId());
726 continue;
727 }
728 Network osNet = osNetworkService.network(osPort.getNetworkId());
729 if (osNet == null) {
730 final String errorFormat = ERR_FLOW + "no network(%s) exists";
731 final String error = String.format(errorFormat,
732 fip.getFloatingIpAddress(),
733 osPort.getNetworkId());
734 throw new IllegalStateException(error);
735 }
736 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
737 log.trace("Mac address of openstack port: {}", srcMac);
738 InstancePort instPort = instancePortService.instancePort(srcMac);
739
740 if (instPort == null) {
741 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
742 final String error = String.format(errorFormat,
743 fip.getFloatingIpAddress(), srcMac);
744 throw new IllegalStateException(error);
745 }
746
Jian Lide679782018-06-05 01:41:29 +0900747 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
748 if (externalPeerRouter == null) {
749 final String errorFormat = ERR_FLOW + "no external peer router found";
750 throw new IllegalStateException(errorFormat);
751 }
752
753 updateComputeNodeRules(instPort, osNet, event.subject(), false);
754 updateGatewayNodeRules(fip, instPort, osNet,
755 externalPeerRouter, event.subject(), false);
Jian Li1064e4f2018-05-29 16:16:53 +0900756 }
757 });
758 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900759 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900760 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900761 break;
762 }
763 }
764 }
Jian Li99892e92018-04-13 14:59:39 +0900765
766 private class InternalHostListener implements HostListener {
767
768 @Override
769 public boolean isRelevant(HostEvent event) {
770 Host host = event.subject();
771 if (!isValidHost(host)) {
772 log.debug("Invalid host detected, ignore it {}", host);
773 return false;
774 }
775 return true;
776 }
777
778 @Override
779 public void event(HostEvent event) {
780 InstancePort instPort = HostBasedInstancePort.of(event.subject());
781 switch (event.type()) {
782 case HOST_REMOVED:
783 storeTempInstPort(instPort);
784 break;
785 case HOST_UPDATED:
786 case HOST_ADDED:
787 default:
788 break;
789 }
790 }
791
792 private void storeTempInstPort(InstancePort port) {
Jian Lif3a28b02018-06-11 21:29:13 +0900793 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
Jian Li99892e92018-04-13 14:59:39 +0900794 for (NetFloatingIP fip : ips) {
795 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
796 continue;
797 }
798 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
799 continue;
800 }
801 if (fip.getFixedIpAddress().equals(port.ipAddress().toString())) {
802 removedPorts.put(port.macAddress(), port);
Jian Lif3a28b02018-06-11 21:29:13 +0900803 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
804 // invalidate bound fixed IP and port
805 neutronFip.setFixedIpAddress(null);
806 neutronFip.setPortId(null);
807 osRouterAdminService.updateFloatingIp(neutronFip);
808 log.info("Updated floating IP {}, due to host removal",
809 neutronFip.getFloatingIpAddress());
Jian Li99892e92018-04-13 14:59:39 +0900810 }
811 }
812 }
813
814 private boolean isValidHost(Host host) {
815 return !host.ipAddresses().isEmpty() &&
816 host.annotations().value(ANNOTATION_NETWORK_ID) != null &&
817 host.annotations().value(ANNOTATION_PORT_ID) != null;
818 }
819 }
Jian Li24ec59f2018-05-23 19:01:25 +0900820
821 private class InternalInstancePortListener implements InstancePortListener {
822
823 @Override
824 public boolean isRelevant(InstancePortEvent event) {
825 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
826 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
827
828 return fip != null && isAssociatedWithVM(osNetworkService, fip);
829 }
830
831 @Override
832 public void event(InstancePortEvent event) {
833
834 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
835 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
836 Port osPort = osNetworkService.port(fip.getPortId());
837 Network osNet = osNetworkService.network(osPort.getNetworkId());
838 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
839
840 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
841 if (externalPeerRouter == null) {
842 final String errorFormat = ERR_FLOW + "no external peer router found";
843 throw new IllegalStateException(errorFormat);
844 }
845
846 switch (event.type()) {
847 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
848 eventExecutor.execute(() -> {
849
850 // since downstream internal rules are located in all gateway
851 // nodes, therefore, we simply update the rules with new compute node info
852 setDownstreamInternalRules(fip, osNet, event.subject(), true);
853
854 // since DownstreamExternal rules should only be placed in
855 // corresponding gateway node, we need to install new rule to
856 // the corresponding gateway node
857 setDownstreamExternalRulesHelper(fip, osNet,
858 event.subject(), externalPeerRouter, gateways, true);
859
860 // since ComputeNodeToGateway rules should only be placed in
861 // corresponding compute node, we need to install new rule to
862 // the target compute node, and remove rules from original node
863 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
864
865 migrationPool.put(fip.getFloatingIpAddress(), event.subject().deviceId());
866
867 });
868 break;
869 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
870
871 // if we only have one gateway, we simply do not remove any
872 // flow rules from either gateway or compute node
873 if (gateways.size() == 1) {
874 return;
875 }
876
877 // checks whether the destination compute node's device id
878 // has identical gateway hash or not
879 // if it is true, we simply do not remove the rules, as
880 // it has been overwritten at port detention event
881 // if it is false, we will remove the rules
882 DeviceId newDeviceId = migrationPool.get(fip.getFloatingIpAddress());
883 DeviceId oldDeviceId = event.subject().deviceId();
884 migrationPool.remove(fip.getFloatingIpAddress());
885
886 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
887 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
888
889 if (oldGateway != null && oldGateway.equals(newGateway)) {
890 return;
891 }
892
893 eventExecutor.execute(() -> {
894
895 // we need to remove the old ComputeNodeToGateway rules from
896 // original compute node
897 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, false);
898
899 // since DownstreamExternal rules should only be placed in
900 // corresponding gateway node, we need to remove old rule from
901 // the corresponding gateway node
902 setDownstreamExternalRulesHelper(fip, osNet,
903 event.subject(), externalPeerRouter, gateways, false);
904 });
905 break;
906 default:
907 break;
908 }
909 }
910 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900911}