blob: 95cdd93d207ce834701f451bcafa849c25c45354 [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 Li1064e4f2018-05-29 16:16:53 +090020import com.google.common.collect.Sets;
Hyunsun Moon44aac662017-02-18 02:07:01 +090021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.onlab.packet.Ethernet;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090029import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onosproject.cluster.ClusterService;
31import org.onosproject.cluster.LeadershipService;
32import org.onosproject.cluster.NodeId;
33import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
Jian Li24ec59f2018-05-23 19:01:25 +090035import org.onosproject.net.DeviceId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.PortNumber;
37import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090043import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.InstancePort;
Jian Liec5c32b2018-07-13 14:28:58 +090045import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090046import org.onosproject.openstacknetworking.api.InstancePortEvent;
47import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090048import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Lie1a39032018-06-19 21:49:36 +090049import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
50import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090051import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090052import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
54import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li8f64feb2018-07-24 13:20:16 +090055import org.onosproject.openstacknetworking.api.PreCommitPortService;
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
72import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090073import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074import java.util.concurrent.ExecutorService;
75
76import static java.util.concurrent.Executors.newSingleThreadExecutor;
77import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090078import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
79import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090080import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090081import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
82import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090083import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Lie1a39032018-06-19 21:49:36 +090084import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
85import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Li8f64feb2018-07-24 13:20:16 +090086import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Jian Li1064e4f2018-05-29 16:16:53 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Li24ec59f2018-05-23 19:01:25 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Liec5c32b2018-07-13 14:28:58 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li26949762018-03-30 15:46:37 +090091import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090092import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090093
94/**
95 * Handles OpenStack floating IP events.
96 */
97@Component(immediate = true)
98public class OpenstackRoutingFloatingIpHandler {
99
100 private final Logger log = LoggerFactory.getLogger(getClass());
101
102 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800103 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected CoreService coreService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected DeviceService deviceService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 protected LeadershipService leadershipService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected ClusterService clusterService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected OpenstackNodeService osNodeService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liec5c32b2018-07-13 14:28:58 +0900121 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900124 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected OpenstackNetworkService osNetworkService;
128
sanghodc375372017-06-08 10:41:30 +0900129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected OpenstackFlowRuleService osFlowRuleService;
131
Jian Li8f64feb2018-07-24 13:20:16 +0900132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected PreCommitPortService preCommitPortService;
134
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135 private final ExecutorService eventExecutor = newSingleThreadExecutor(
136 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li24ec59f2018-05-23 19:01:25 +0900137 private final OpenstackRouterListener floatingIpListener = new InternalFloatingIpListener();
138 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Lie1a39032018-06-19 21:49:36 +0900140 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
141 private final InstancePortListener instPortListener = new InternalInstancePortListener();
142
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 private ApplicationId appId;
144 private NodeId localNodeId;
145
146 @Activate
147 protected void activate() {
148 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
149 localNodeId = clusterService.getLocalNode().id();
150 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900151 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900152 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900153 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900154 osNodeService.addListener(osNodeListener);
155 osNetworkService.addListener(osNetworkListener);
156 instancePortService.addListener(instPortListener);
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 Lie1a39032018-06-19 21:49:36 +0900164 instancePortService.removeListener(instPortListener);
165 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900167 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168 leadershipService.withdraw(appId.name());
169 eventExecutor.shutdown();
170
171 log.info("Stopped");
172 }
173
Jian Li628a7cb2018-08-11 23:04:24 +0900174 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900175 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900176
177 if (instPort == null) {
178 log.debug("No instance port found");
179 return;
180 }
181
182 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900183
Hyunsun Moon44aac662017-02-18 02:07:01 +0900184 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900185 final String errorFormat = ERR_FLOW + "no network(%s) exists";
186 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900187 floatingIp.getFloatingIpAddress(),
Jian Li628a7cb2018-08-11 23:04:24 +0900188 instPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900189 throw new IllegalStateException(error);
190 }
191
daniel park32b42202018-03-14 16:53:44 +0900192 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
193 if (externalPeerRouter == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900194 final String errorFormat = ERR_FLOW + "no external peer router found";
195 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900196 }
197
Jian Li8f64feb2018-07-24 13:20:16 +0900198 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900199 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900200 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900201 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900202 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900203 preCommitPortService.unsubscribePreCommit(instPort.portId(),
204 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
205 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900206 }
207
Jian Lide679782018-06-05 01:41:29 +0900208 updateComputeNodeRules(instPort, osNet, gateway, install);
209 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
210
211 // FIXME: downstream internal rules are still duplicated in all gateway nodes
212 // need to make the internal rules de-duplicated sooner or later
213 setDownstreamInternalRules(floatingIp, osNet, instPort, install);
214
215 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900216 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900217
daniel parkc2a2ed62018-04-10 15:17:42 +0900218 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
219 floatingIp.getFloatingIpAddress(),
220 floatingIp.getFixedIpAddress(),
221 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900222 }
223
Jian Lide679782018-06-05 01:41:29 +0900224 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
225 InstancePort instPort,
226 Network osNet,
227 ExternalPeerRouter router,
228 OpenstackNode gateway,
229 boolean install) {
230
231 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
232 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
233 finalGws.addAll(ImmutableSet.copyOf(completedGws));
234
Jian Lia171a432018-06-11 11:52:11 +0900235
236 if (gateway == null) {
237 // these are floating IP related cases...
238 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
239 ImmutableSet.copyOf(finalGws), install);
240
Jian Lide679782018-06-05 01:41:29 +0900241 } else {
Jian Lia171a432018-06-11 11:52:11 +0900242 // these are openstack node related cases...
243 if (install) {
244 if (completedGws.contains(gateway)) {
245 if (completedGws.size() > 1) {
246 finalGws.remove(gateway);
247 if (fip.getPortId() != null) {
248 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
249 ImmutableSet.copyOf(finalGws), false);
250 finalGws.add(gateway);
251 }
252 }
Jian Lide679782018-06-05 01:41:29 +0900253 if (fip.getPortId() != null) {
254 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
255 ImmutableSet.copyOf(finalGws), true);
256 }
Jian Lia171a432018-06-11 11:52:11 +0900257 } else {
258 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900259 }
260 } else {
Jian Lia171a432018-06-11 11:52:11 +0900261 if (!completedGws.contains(gateway)) {
262 if (completedGws.size() >= 1) {
263 if (fip.getPortId() != null) {
264 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
265 ImmutableSet.copyOf(finalGws), true);
266 }
267 }
268 } else {
269 log.warn("Detected node should NOT be included in completed gateway set");
270 }
Jian Lide679782018-06-05 01:41:29 +0900271 }
272 }
273 }
274
275 private synchronized void updateComputeNodeRules(InstancePort instPort,
276 Network osNet,
277 OpenstackNode gateway,
278 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900279
280 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
281 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
282 finalGws.addAll(ImmutableSet.copyOf(completedGws));
283
284 if (gateway == null) {
285 // these are floating IP related cases...
286 setComputeNodeToGatewayHelper(instPort, osNet,
287 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900288
Jian Li1064e4f2018-05-29 16:16:53 +0900289 } else {
290 // these are openstack node related cases...
291 if (install) {
292 if (completedGws.contains(gateway)) {
293 if (completedGws.size() > 1) {
294 finalGws.remove(gateway);
295 setComputeNodeToGatewayHelper(instPort, osNet,
296 ImmutableSet.copyOf(finalGws), false);
297 finalGws.add(gateway);
298 }
299
300 setComputeNodeToGatewayHelper(instPort, osNet,
301 ImmutableSet.copyOf(finalGws), true);
302 } else {
303 log.warn("Detected node should be included in completed gateway set");
304 }
305 } else {
306 if (!completedGws.contains(gateway)) {
307 finalGws.add(gateway);
308 setComputeNodeToGatewayHelper(instPort, osNet,
309 ImmutableSet.copyOf(finalGws), false);
310 finalGws.remove(gateway);
311 if (completedGws.size() >= 1) {
312 setComputeNodeToGatewayHelper(instPort, osNet,
313 ImmutableSet.copyOf(finalGws), true);
314 }
315 } else {
316 log.warn("Detected node should NOT be included in completed gateway set");
317 }
318 }
319 }
320 }
321
322 // a helper method
323 private void setComputeNodeToGatewayHelper(InstancePort instPort,
324 Network osNet,
325 Set<OpenstackNode> gateways,
326 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900327 TrafficTreatment treatment;
328
329 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
330 .matchEthType(Ethernet.TYPE_IPV4)
331 .matchIPSrc(instPort.ipAddress().toIpPrefix())
332 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
333
334 switch (osNet.getNetworkType()) {
335 case VXLAN:
336 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
337 break;
338 case VLAN:
339 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
340 break;
341 default:
342 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800343 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900344 osNet.getNetworkType().toString());
345 throw new IllegalStateException(error);
346 }
347
Jian Li1064e4f2018-05-29 16:16:53 +0900348 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
349
daniel parkeeb8e042018-02-21 14:06:58 +0900350 if (selectedGatewayNode == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900351 final String errorFormat = ERR_FLOW + "no gateway node selected";
352 throw new IllegalStateException(errorFormat);
daniel parkeeb8e042018-02-21 14:06:58 +0900353 }
354 treatment = DefaultTrafficTreatment.builder()
355 .extension(buildExtension(
356 deviceService,
357 instPort.deviceId(),
358 selectedGatewayNode.dataIp().getIp4Address()),
359 instPort.deviceId())
360 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
361 .build();
362
363 osFlowRuleService.setRule(
364 appId,
365 instPort.deviceId(),
366 sBuilder.build(),
367 treatment,
368 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
369 ROUTING_TABLE,
370 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900371 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900372 }
373
Jian Lide679782018-06-05 01:41:29 +0900374 private void setDownstreamInternalRules(NetFloatingIP floatingIp,
375 Network osNet,
376 InstancePort instPort,
377 boolean install) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900378 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
379 if (cNode == null) {
380 final String error = String.format("Cannot find openstack node for device %s",
381 instPort.deviceId());
382 throw new IllegalStateException(error);
383 }
384 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900385 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
386 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900387 throw new IllegalStateException(error);
388 }
389 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900390 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
391 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900392 throw new IllegalStateException(error);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900393 }
394
395 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900396
Jian Lide679782018-06-05 01:41:29 +0900397 // TODO: following code snippet will be refactored sooner or later
Hyunsun Moon0d457362017-06-27 17:19:41 +0900398 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900399 // access from one VM to the others via floating IP
Hyunsun Moon44aac662017-02-18 02:07:01 +0900400 TrafficSelector internalSelector = DefaultTrafficSelector.builder()
401 .matchEthType(Ethernet.TYPE_IPV4)
402 .matchIPDst(floating.toIpPrefix())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900403 .matchInPort(gNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900404 .build();
405
daniel parkee8700b2017-05-11 15:50:03 +0900406 TrafficTreatment.Builder internalBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900407 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
408 .setEthDst(instPort.macAddress())
daniel parkee8700b2017-05-11 15:50:03 +0900409 .setIpDst(instPort.ipAddress().getIp4Address());
410
411 switch (osNet.getNetworkType()) {
412 case VXLAN:
413 internalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
414 .extension(buildExtension(
415 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900416 gNode.intgBridge(),
417 cNode.dataIp().getIp4Address()),
418 gNode.intgBridge())
daniel parkee8700b2017-05-11 15:50:03 +0900419 .setOutput(PortNumber.IN_PORT);
420 break;
421 case VLAN:
422 internalBuilder.pushVlan()
423 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
424 .setOutput(PortNumber.IN_PORT);
425 break;
426 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800427 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900428 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900429 throw new IllegalStateException(error);
430 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900431
sanghodc375372017-06-08 10:41:30 +0900432 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900433 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900434 gNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900435 internalSelector,
daniel parkee8700b2017-05-11 15:50:03 +0900436 internalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900437 PRIORITY_FLOATING_INTERNAL,
sanghodc375372017-06-08 10:41:30 +0900438 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900439 install);
440 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900441 log.trace("Succeeded to set flow rules for downstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900442 }
443
Jian Lide679782018-06-05 01:41:29 +0900444 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
445 Network osNet,
446 InstancePort instPort,
447 ExternalPeerRouter externalPeerRouter,
448 Set<OpenstackNode> gateways, boolean install) {
449 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
450 if (cNode == null) {
451 final String error = String.format("Cannot find openstack node for device %s",
452 instPort.deviceId());
453 throw new IllegalStateException(error);
454 }
455 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
456 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
457 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
458 throw new IllegalStateException(error);
459 }
460 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
461 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
462 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
463 throw new IllegalStateException(error);
464 }
465
466 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
467
468 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
469
470 if (selectedGatewayNode == null) {
471 final String errorFormat = ERR_FLOW + "no gateway node selected";
472 throw new IllegalStateException(errorFormat);
473 }
474
475 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
476 .matchEthType(Ethernet.TYPE_IPV4)
477 .matchIPDst(floating.toIpPrefix());
478
479 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
480 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
481 .setEthDst(instPort.macAddress())
482 .setIpDst(instPort.ipAddress().getIp4Address());
483
Jian Li5e2ad4a2018-07-16 13:40:53 +0900484 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
485 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900486 externalTreatmentBuilder.popVlan();
487 }
488
489 switch (osNet.getNetworkType()) {
490 case VXLAN:
491 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
492 .extension(buildExtension(
493 deviceService,
494 selectedGatewayNode.intgBridge(),
495 cNode.dataIp().getIp4Address()),
496 selectedGatewayNode.intgBridge())
497 .setOutput(selectedGatewayNode.tunnelPortNum());
498 break;
499 case VLAN:
500 externalTreatmentBuilder.pushVlan()
501 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
502 .setOutput(selectedGatewayNode.vlanPortNum());
503 break;
504 default:
505 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
506 osNet.getNetworkType());
507 throw new IllegalStateException(error);
508 }
509
510 osFlowRuleService.setRule(
511 appId,
512 selectedGatewayNode.intgBridge(),
513 externalSelectorBuilder.build(),
514 externalTreatmentBuilder.build(),
515 PRIORITY_FLOATING_EXTERNAL,
516 GW_COMMON_TABLE,
517 install);
518 }
519
Hyunsun Moon44aac662017-02-18 02:07:01 +0900520 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
daniel park32b42202018-03-14 16:53:44 +0900521 InstancePort instPort, ExternalPeerRouter externalPeerRouter,
522 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900523 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900524 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900525 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900526 .matchIPSrc(instPort.ipAddress().toIpPrefix());
527
528 switch (osNet.getNetworkType()) {
529 case VXLAN:
530 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
531 break;
532 case VLAN:
533 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
534 break;
535 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800536 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900537 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900538 throw new IllegalStateException(error);
539 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900540
Daniel Park75e3d7f2018-05-29 14:43:53 +0900541 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900542
Hyunsun Moon0d457362017-06-27 17:19:41 +0900543 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900544 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
545 .setIpSrc(floating.getIp4Address())
546 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900547 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900548
Daniel Park75e3d7f2018-05-29 14:43:53 +0900549 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
550 tBuilder.popVlan();
551 }
552
Jian Li5e2ad4a2018-07-16 13:40:53 +0900553 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
554 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900555 }
sanghodc375372017-06-08 10:41:30 +0900556 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900557 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900558 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900559 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900560 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900561 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900562 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900563 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900564 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900565 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900566 }
567
daniel park32b42202018-03-14 16:53:44 +0900568 private ExternalPeerRouter externalPeerRouter(Network network) {
daniel parkeeb8e042018-02-21 14:06:58 +0900569 if (network == null) {
570 return null;
571 }
572
573 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
574
575 if (subnet == null) {
576 return null;
577 }
578
Jian Lif3a28b02018-06-11 21:29:13 +0900579 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900580 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
581 .findAny().orElse(null);
582 if (osRouterIface == null) {
583 return null;
584 }
585
Jian Lif3a28b02018-06-11 21:29:13 +0900586 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
daniel parkeeb8e042018-02-21 14:06:58 +0900587 if (osRouter == null) {
588 return null;
589 }
590 if (osRouter.getExternalGatewayInfo() == null) {
591 return null;
592 }
593
594 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
daniel park65e1c202018-04-03 13:15:28 +0900595 return osNetworkService.externalPeerRouter(exGatewayInfo);
daniel parkeeb8e042018-02-21 14:06:58 +0900596 }
daniel park65e1c202018-04-03 13:15:28 +0900597
Jian Li99892e92018-04-13 14:59:39 +0900598 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900599 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
600
601 if (instPort == null) {
602 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
603 osFip.getFloatingIpAddress());
604 return;
Jian Li99892e92018-04-13 14:59:39 +0900605 }
Jian Li628a7cb2018-08-11 23:04:24 +0900606
Jian Li99892e92018-04-13 14:59:39 +0900607 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900608 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
609 setFloatingIpRules(osFip, instPort, null, true);
Jian Li99892e92018-04-13 14:59:39 +0900610 }
611 }
612
613 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900614 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900615
Jian Li628a7cb2018-08-11 23:04:24 +0900616 if (instPort == null) {
617 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
618 osFip.getFloatingIpAddress());
619 return;
Jian Lie1a39032018-06-19 21:49:36 +0900620 }
621
Jian Li99892e92018-04-13 14:59:39 +0900622 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900623 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
624 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900625 }
626 }
627
Hyunsun Moon0d457362017-06-27 17:19:41 +0900628 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900629
630 @Override
631 public boolean isRelevant(OpenstackRouterEvent event) {
632 // do not allow to proceed without leadership
633 NodeId leader = leadershipService.getLeader(appId.name());
634 if (!Objects.equals(localNodeId, leader)) {
635 return false;
636 }
637 return event.floatingIp() != null;
638 }
639
640 @Override
641 public void event(OpenstackRouterEvent event) {
642 switch (event.type()) {
643 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900644 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900645 NetFloatingIP osFip = event.floatingIp();
646 associateFloatingIp(osFip);
647 log.info("Associated floating IP {}:{}",
648 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900649 });
650 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900651 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
652 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900653 NetFloatingIP osFip = event.floatingIp();
654 disassociateFloatingIp(osFip, event.portId());
655 log.info("Disassociated floating IP {}:{}",
656 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900657 });
658 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900659 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900660 eventExecutor.execute(() -> {
661 NetFloatingIP osFip = event.floatingIp();
662 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
663 associateFloatingIp(event.floatingIp());
664 }
665 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
666 });
667 break;
Jian Lia171a432018-06-11 11:52:11 +0900668 case OPENSTACK_FLOATING_IP_REMOVED:
669 eventExecutor.execute(() -> {
670 NetFloatingIP osFip = event.floatingIp();
671 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
Jian Lic2403592018-07-18 12:56:45 +0900672 // in case the floating IP is not associated with any port due to
673 // port removal, we simply do not execute floating IP disassociation
674 if (osNetworkService.port(osFip.getPortId()) != null) {
675 disassociateFloatingIp(osFip, osFip.getPortId());
676 }
Jian Lida03ce92018-07-24 21:41:53 +0900677
678 // since we skip floating IP disassociation, we need to
679 // manually unsubscribe the port pre-remove event
680 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
Jian Li628a7cb2018-08-11 23:04:24 +0900681 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
682 this.getClass().getName());
Jian Lida03ce92018-07-24 21:41:53 +0900683 log.info("Unsubscribed the port {} on listening pre-remove event", osFip.getPortId());
Jian Lia171a432018-06-11 11:52:11 +0900684 }
685 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
686 });
687 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900688 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900689 case OPENSTACK_ROUTER_CREATED:
690 case OPENSTACK_ROUTER_UPDATED:
691 case OPENSTACK_ROUTER_REMOVED:
692 case OPENSTACK_ROUTER_INTERFACE_ADDED:
693 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
694 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
695 default:
696 // do nothing for the other events
697 break;
698 }
699 }
700 }
701
702 private class InternalNodeListener implements OpenstackNodeListener {
703
704 @Override
705 public boolean isRelevant(OpenstackNodeEvent event) {
706 // do not allow to proceed without leadership
707 NodeId leader = leadershipService.getLeader(appId.name());
708 if (!Objects.equals(localNodeId, leader)) {
709 return false;
710 }
711 return event.subject().type() == GATEWAY;
712 }
713
714 @Override
715 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900716
717 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900718 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900719 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900720 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Lie1a39032018-06-19 21:49:36 +0900721
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900722 if (Strings.isNullOrEmpty(fip.getPortId())) {
723 continue;
724 }
Jian Lie1a39032018-06-19 21:49:36 +0900725
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900726 Port osPort = osNetworkService.port(fip.getPortId());
Jian Li628a7cb2018-08-11 23:04:24 +0900727 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
728
729 // we check both Openstack Port and Instance Port
730 if (osPort == null || instPort == null) {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900731 continue;
732 }
Jian Lie1a39032018-06-19 21:49:36 +0900733
Jian Li628a7cb2018-08-11 23:04:24 +0900734 setFloatingIpRules(fip, instPort, event.subject(), true);
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900735 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900736 });
737 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900738 case OPENSTACK_NODE_INCOMPLETE:
Jian Li1064e4f2018-05-29 16:16:53 +0900739 eventExecutor.execute(() -> {
Jian Lif3a28b02018-06-11 21:29:13 +0900740 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900741 if (Strings.isNullOrEmpty(fip.getPortId())) {
742 continue;
743 }
744 Port osPort = osNetworkService.port(fip.getPortId());
745 if (osPort == null) {
746 log.warn("Failed to set floating IP {}", fip.getId());
747 continue;
748 }
749 Network osNet = osNetworkService.network(osPort.getNetworkId());
750 if (osNet == null) {
751 final String errorFormat = ERR_FLOW + "no network(%s) exists";
752 final String error = String.format(errorFormat,
753 fip.getFloatingIpAddress(),
754 osPort.getNetworkId());
755 throw new IllegalStateException(error);
756 }
757 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
758 log.trace("Mac address of openstack port: {}", srcMac);
759 InstancePort instPort = instancePortService.instancePort(srcMac);
760
761 if (instPort == null) {
762 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
763 final String error = String.format(errorFormat,
764 fip.getFloatingIpAddress(), srcMac);
765 throw new IllegalStateException(error);
766 }
767
Jian Lide679782018-06-05 01:41:29 +0900768 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
769 if (externalPeerRouter == null) {
770 final String errorFormat = ERR_FLOW + "no external peer router found";
771 throw new IllegalStateException(errorFormat);
772 }
773
774 updateComputeNodeRules(instPort, osNet, event.subject(), false);
775 updateGatewayNodeRules(fip, instPort, osNet,
776 externalPeerRouter, event.subject(), false);
Jian Li1064e4f2018-05-29 16:16:53 +0900777 }
778 });
779 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900780 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900781 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900782 break;
783 }
784 }
785 }
Jian Li99892e92018-04-13 14:59:39 +0900786
Jian Li24ec59f2018-05-23 19:01:25 +0900787 private class InternalInstancePortListener implements InstancePortListener {
788
789 @Override
790 public boolean isRelevant(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900791
Jian Lie1a39032018-06-19 21:49:36 +0900792 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
793 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
794 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
795 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
796
797 // we check the possible NPE to avoid duplicated null check
798 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
799 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
800 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
801 return false;
802 }
803 }
804
805 // do not allow to proceed without leadership
806 NodeId leader = leadershipService.getLeader(appId.name());
807
808 return Objects.equals(localNodeId, leader);
Jian Li24ec59f2018-05-23 19:01:25 +0900809 }
810
811 @Override
812 public void event(InstancePortEvent event) {
Jian Lie1a39032018-06-19 21:49:36 +0900813 InstancePort instPort = event.subject();
Jian Li24ec59f2018-05-23 19:01:25 +0900814 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
815
Jian Lie1a39032018-06-19 21:49:36 +0900816 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
817 NetFloatingIP fip;
818 Port osPort;
819 Network osNet;
820 ExternalPeerRouter externalPeerRouter;
Jian Li24ec59f2018-05-23 19:01:25 +0900821
822 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900823 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li77323c52018-06-24 01:26:18 +0900824 if (instPort != null && instPort.portId() != null) {
Jian Li46b74002018-07-15 18:39:08 +0900825 osRouterAdminService.floatingIps().stream()
826 .filter(f -> f.getPortId() != null)
827 .filter(f -> f.getPortId().equals(instPort.portId()))
Jian Li628a7cb2018-08-11 23:04:24 +0900828 .forEach(f -> setFloatingIpRules(f, instPort, null, true));
Jian Lie1a39032018-06-19 21:49:36 +0900829 }
830
831 break;
832
Jian Li24ec59f2018-05-23 19:01:25 +0900833 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Lie1a39032018-06-19 21:49:36 +0900834
835 fip = associatedFloatingIp(event.subject(), ips);
836
837 if (fip == null) {
838 return;
839 }
840
841 osPort = osNetworkService.port(fip.getPortId());
842 osNet = osNetworkService.network(osPort.getNetworkId());
843 externalPeerRouter = externalPeerRouter(osNet);
844
845 if (externalPeerRouter == null) {
846 final String errorFormat = ERR_FLOW + "no external peer router found";
847 throw new IllegalStateException(errorFormat);
848 }
849
Jian Li24ec59f2018-05-23 19:01:25 +0900850 eventExecutor.execute(() -> {
851
852 // since downstream internal rules are located in all gateway
853 // nodes, therefore, we simply update the rules with new compute node info
854 setDownstreamInternalRules(fip, osNet, event.subject(), true);
855
856 // since DownstreamExternal rules should only be placed in
857 // corresponding gateway node, we need to install new rule to
858 // the corresponding gateway node
859 setDownstreamExternalRulesHelper(fip, osNet,
860 event.subject(), externalPeerRouter, gateways, true);
861
862 // since ComputeNodeToGateway rules should only be placed in
863 // corresponding compute node, we need to install new rule to
864 // the target compute node, and remove rules from original node
865 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
Jian Li24ec59f2018-05-23 19:01:25 +0900866 });
867 break;
868 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
869
Jian Liec5c32b2018-07-13 14:28:58 +0900870 InstancePort revisedInstPort = swapStaleLocation(event.subject());
871
872 fip = associatedFloatingIp(revisedInstPort, ips);
Jian Lie1a39032018-06-19 21:49:36 +0900873
874 if (fip == null) {
875 return;
876 }
877
878 osPort = osNetworkService.port(fip.getPortId());
879 osNet = osNetworkService.network(osPort.getNetworkId());
880 externalPeerRouter = externalPeerRouter(osNet);
881
882 if (externalPeerRouter == null) {
883 final String errorFormat = ERR_FLOW + "no external peer router found";
884 throw new IllegalStateException(errorFormat);
885 }
886
887 // If we only have one gateway, we simply do not remove any
Jian Li24ec59f2018-05-23 19:01:25 +0900888 // flow rules from either gateway or compute node
889 if (gateways.size() == 1) {
890 return;
891 }
892
Jian Lie1a39032018-06-19 21:49:36 +0900893 // Checks whether the destination compute node's device id
Jian Li24ec59f2018-05-23 19:01:25 +0900894 // has identical gateway hash or not
895 // if it is true, we simply do not remove the rules, as
896 // it has been overwritten at port detention event
897 // if it is false, we will remove the rules
Jian Liec5c32b2018-07-13 14:28:58 +0900898 DeviceId newDeviceId = event.subject().deviceId();
899 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Li24ec59f2018-05-23 19:01:25 +0900900
901 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
902 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
903
904 if (oldGateway != null && oldGateway.equals(newGateway)) {
905 return;
906 }
907
908 eventExecutor.execute(() -> {
909
Jian Lie1a39032018-06-19 21:49:36 +0900910 // We need to remove the old ComputeNodeToGateway rules from
Jian Li24ec59f2018-05-23 19:01:25 +0900911 // original compute node
Jian Liec5c32b2018-07-13 14:28:58 +0900912 setComputeNodeToGatewayHelper(revisedInstPort, osNet, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900913
Jian Lie1a39032018-06-19 21:49:36 +0900914 // Since DownstreamExternal rules should only be placed in
Jian Li24ec59f2018-05-23 19:01:25 +0900915 // corresponding gateway node, we need to remove old rule from
916 // the corresponding gateway node
Jian Liec5c32b2018-07-13 14:28:58 +0900917 setDownstreamExternalRulesHelper(fip, osNet, revisedInstPort,
918 externalPeerRouter, gateways, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900919 });
920 break;
921 default:
922 break;
923 }
924 }
925 }
Jian Lie1a39032018-06-19 21:49:36 +0900926
927 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
928
929 @Override
930 public boolean isRelevant(OpenstackNetworkEvent event) {
931 // do not allow to proceed without leadership
932 NodeId leader = leadershipService.getLeader(appId.name());
Jian Lida03ce92018-07-24 21:41:53 +0900933 return Objects.equals(localNodeId, leader);
Jian Lie1a39032018-06-19 21:49:36 +0900934 }
935
936 @Override
937 public void event(OpenstackNetworkEvent event) {
938 switch (event.type()) {
Jian Li8f64feb2018-07-24 13:20:16 +0900939 case OPENSTACK_PORT_PRE_REMOVE:
Jian Li427811e2018-08-28 17:35:16 +0900940 InstancePort instPort =
941 instancePortService.instancePort(event.port().getId());
942 NetFloatingIP fip =
943 associatedFloatingIp(instPort, osRouterAdminService.floatingIps());
944
945 if (fip != null) {
946 eventExecutor.execute(() ->
947 updateFipStore(instancePortService.instancePort(event.port().getId())));
948 } else {
949 instancePortService.removeInstancePort(instPort.portId());
950 }
Jian Li8f64feb2018-07-24 13:20:16 +0900951 break;
Jian Lie1a39032018-06-19 21:49:36 +0900952 default:
953 break;
954 }
955 }
956
957 private void updateFipStore(InstancePort port) {
958
959 if (port == null) {
960 return;
961 }
962
963 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
964 for (NetFloatingIP fip : ips) {
965 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
966 continue;
967 }
968 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
969 continue;
970 }
971 if (fip.getFixedIpAddress().equals(port.ipAddress().toString())) {
972 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
973 // invalidate bound fixed IP and port
974 neutronFip.setFixedIpAddress(null);
975 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900976
977 // Following update will in turn trigger
978 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
979 osRouterAdminService.updateFloatingIp(neutronFip);
980 log.info("Updated floating IP {}, due to host removal",
981 neutronFip.getFloatingIpAddress());
982 }
983 }
984 }
985 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900986}