blob: 10abe3b5be824e0ca9c81dfd2f89a0115c0cc220 [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.onlab.packet.Ethernet;
22import org.onlab.packet.IpAddress;
23import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090024import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090025import org.onosproject.cluster.ClusterService;
26import org.onosproject.cluster.LeadershipService;
27import org.onosproject.cluster.NodeId;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
Jian Li24ec59f2018-05-23 19:01:25 +090030import org.onosproject.net.DeviceId;
Jian Li2d68c192018-12-13 15:52:59 +090031import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090032import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090037import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090039import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090040import org.onosproject.openstacknetworking.api.InstancePort;
Jian Liec5c32b2018-07-13 14:28:58 +090041import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090042import org.onosproject.openstacknetworking.api.InstancePortEvent;
43import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090044import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Lie1a39032018-06-19 21:49:36 +090045import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
46import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090047import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090048import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
50import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li8f64feb2018-07-24 13:20:16 +090051import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090052import org.onosproject.openstacknode.api.OpenstackNode;
53import org.onosproject.openstacknode.api.OpenstackNodeEvent;
54import org.onosproject.openstacknode.api.OpenstackNodeListener;
55import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.openstack4j.model.network.NetFloatingIP;
57import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090058import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090059import org.openstack4j.model.network.Port;
Jian Lif3a28b02018-06-11 21:29:13 +090060import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
Jian Li34220ea2018-11-14 01:30:24 +090061import org.osgi.service.component.annotations.Activate;
62import org.osgi.service.component.annotations.Component;
63import org.osgi.service.component.annotations.Deactivate;
64import org.osgi.service.component.annotations.Reference;
65import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
69import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090070import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090071import java.util.concurrent.ExecutorService;
72
73import static java.util.concurrent.Executors.newSingleThreadExecutor;
74import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090075import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
76import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090077import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090078import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090079import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8a5fb642018-09-14 15:50:04 +090080import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVE_PENDING;
Jian Lie1a39032018-06-19 21:49:36 +090081import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
82import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Li8f64feb2018-07-24 13:20:16 +090083import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090084import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090085import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
Jian Li1064e4f2018-05-29 16:16:53 +090086import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090087import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Li32b03622018-11-06 17:54:24 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +090091import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
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
Jian Li4d138702018-11-27 17:25:28 +0900106 private static final String NO_EXT_PEER_ROUTER_MSG = "no external peer router found";
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109 protected CoreService coreService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 protected DeviceService deviceService;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115 protected LeadershipService leadershipService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118 protected ClusterService clusterService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121 protected OpenstackNodeService osNodeService;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liec5c32b2018-07-13 14:28:58 +0900124 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900127 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130 protected OpenstackNetworkService osNetworkService;
131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900133 protected OpenstackFlowRuleService osFlowRuleService;
134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li8f64feb2018-07-24 13:20:16 +0900136 protected PreCommitPortService preCommitPortService;
137
Ray Milkeyd5425682018-10-23 10:21:33 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900139 protected PacketService packetService;
140
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141 private final ExecutorService eventExecutor = newSingleThreadExecutor(
142 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900143 private final OpenstackRouterListener
144 floatingIpListener = new InternalFloatingIpListener();
145 private final InstancePortListener
146 instancePortListener = new InternalInstancePortListener();
147 private final OpenstackNodeListener
148 osNodeListener = new InternalNodeListener();
149 private final OpenstackNetworkListener
150 osNetworkListener = new InternalOpenstackNetworkListener();
151 private final InstancePortListener
152 instPortListener = new InternalInstancePortListener();
Jian Lie1a39032018-06-19 21:49:36 +0900153
Hyunsun Moon44aac662017-02-18 02:07:01 +0900154 private ApplicationId appId;
155 private NodeId localNodeId;
156
157 @Activate
158 protected void activate() {
159 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
160 localNodeId = clusterService.getLocalNode().id();
161 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900162 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900164 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900165 osNodeService.addListener(osNodeListener);
166 osNetworkService.addListener(osNetworkListener);
167 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168
169 log.info("Started");
170 }
171
172 @Deactivate
173 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900174 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900175 instancePortService.removeListener(instPortListener);
176 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900178 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900179 leadershipService.withdraw(appId.name());
180 eventExecutor.shutdown();
181
182 log.info("Stopped");
183 }
184
Jian Li628a7cb2018-08-11 23:04:24 +0900185 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900186 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900187
188 if (instPort == null) {
189 log.debug("No instance port found");
190 return;
191 }
192
193 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900194
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900195 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
196 osNetworkService, osRouterAdminService);
daniel park32b42202018-03-14 16:53:44 +0900197 if (externalPeerRouter == null) {
Jian Li4d138702018-11-27 17:25:28 +0900198 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
daniel parkc2a2ed62018-04-10 15:17:42 +0900199 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900200 }
201
Jian Li8f64feb2018-07-24 13:20:16 +0900202 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900203 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900204 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900205 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900206 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900207 preCommitPortService.unsubscribePreCommit(instPort.portId(),
208 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
209 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900210 }
211
Jian Lide679782018-06-05 01:41:29 +0900212 updateComputeNodeRules(instPort, osNet, gateway, install);
213 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
214
Jian Lide679782018-06-05 01:41:29 +0900215 // 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)) {
Jian Li4d138702018-11-27 17:25:28 +0900262 if (!completedGws.isEmpty() && fip.getPortId() != null) {
263 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
Jian Lia171a432018-06-11 11:52:11 +0900264 ImmutableSet.copyOf(finalGws), true);
Jian Lia171a432018-06-11 11:52:11 +0900265 }
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);
Jian Li4d138702018-11-27 17:25:28 +0900309 if (!completedGws.isEmpty()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900310 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
326 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
327 .matchEthType(Ethernet.TYPE_IPV4)
328 .matchIPSrc(instPort.ipAddress().toIpPrefix())
329 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
330
Daniel Park3f26e792018-11-26 18:34:53 +0900331 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkeeb8e042018-02-21 14:06:58 +0900332
Jian Li5ecfd1a2018-12-10 11:41:03 +0900333 OpenstackNode selectedGatewayNode =
334 getGwByComputeDevId(gateways, instPort.deviceId());
Jian Li1064e4f2018-05-29 16:16:53 +0900335
daniel parkeeb8e042018-02-21 14:06:58 +0900336 if (selectedGatewayNode == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900337 log.warn(ERR_FLOW + "no gateway node selected");
Jian Lifb64d882018-11-27 10:57:40 +0900338 return;
daniel parkeeb8e042018-02-21 14:06:58 +0900339 }
Daniel Park3f26e792018-11-26 18:34:53 +0900340
341 switch (osNet.getNetworkType()) {
342 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900343 case GRE:
344 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
345 osNetworkService, osNodeService.node(instPort.deviceId()));
346
347 if (portNum == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900348 log.warn(ERR_FLOW + "no tunnel port");
349 return;
350 }
Jian Li2d68c192018-12-13 15:52:59 +0900351
Daniel Park3f26e792018-11-26 18:34:53 +0900352 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
Jian Li2d68c192018-12-13 15:52:59 +0900353
Daniel Park3f26e792018-11-26 18:34:53 +0900354 tBuilder.extension(buildExtension(
daniel parkeeb8e042018-02-21 14:06:58 +0900355 deviceService,
356 instPort.deviceId(),
357 selectedGatewayNode.dataIp().getIp4Address()),
358 instPort.deviceId())
Jian Li2d68c192018-12-13 15:52:59 +0900359 .setOutput(portNum);
Daniel Park3f26e792018-11-26 18:34:53 +0900360 break;
361 case VLAN:
362 if (osNodeService.node(instPort.deviceId()).vlanPortNum() == null) {
363 log.warn(ERR_FLOW + "no vlan port");
364 return;
365 }
366 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
367 tBuilder.setOutput(osNodeService.node(instPort.deviceId()).vlanPortNum());
368 break;
369 default:
370 log.warn(ERR_FLOW + "no supported network type");
371 }
daniel parkeeb8e042018-02-21 14:06:58 +0900372
373 osFlowRuleService.setRule(
374 appId,
375 instPort.deviceId(),
376 sBuilder.build(),
Daniel Park3f26e792018-11-26 18:34:53 +0900377 tBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900378 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
379 ROUTING_TABLE,
380 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900381 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900382 }
383
Jian Lide679782018-06-05 01:41:29 +0900384 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
385 Network osNet,
386 InstancePort instPort,
387 ExternalPeerRouter externalPeerRouter,
388 Set<OpenstackNode> gateways, boolean install) {
389 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
390 if (cNode == null) {
391 final String error = String.format("Cannot find openstack node for device %s",
392 instPort.deviceId());
393 throw new IllegalStateException(error);
394 }
395 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
396 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
397 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
398 throw new IllegalStateException(error);
399 }
Jian Li2d68c192018-12-13 15:52:59 +0900400 if (osNet.getNetworkType() == NetworkType.GRE && cNode.dataIp() == null) {
401 final String errorFormat = ERR_FLOW + "GRE mode is not ready for %s";
402 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
403 throw new IllegalStateException(error);
404 }
Jian Lide679782018-06-05 01:41:29 +0900405 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
406 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
407 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
408 throw new IllegalStateException(error);
409 }
410
411 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
412
413 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
414
415 if (selectedGatewayNode == null) {
416 final String errorFormat = ERR_FLOW + "no gateway node selected";
417 throw new IllegalStateException(errorFormat);
418 }
419
420 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
421 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900422 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900423 .matchIPDst(floating.toIpPrefix());
424
425 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
426 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
427 .setEthDst(instPort.macAddress())
428 .setIpDst(instPort.ipAddress().getIp4Address());
429
Jian Li5e2ad4a2018-07-16 13:40:53 +0900430 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
431 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900432 externalTreatmentBuilder.popVlan();
433 }
434
435 switch (osNet.getNetworkType()) {
436 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900437 case GRE:
438 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
439 osNetworkService, selectedGatewayNode);
Jian Lide679782018-06-05 01:41:29 +0900440 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
441 .extension(buildExtension(
442 deviceService,
443 selectedGatewayNode.intgBridge(),
444 cNode.dataIp().getIp4Address()),
445 selectedGatewayNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900446 .setOutput(portNum);
Jian Lide679782018-06-05 01:41:29 +0900447 break;
448 case VLAN:
449 externalTreatmentBuilder.pushVlan()
450 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
451 .setOutput(selectedGatewayNode.vlanPortNum());
452 break;
453 default:
454 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
455 osNet.getNetworkType());
456 throw new IllegalStateException(error);
457 }
458
459 osFlowRuleService.setRule(
460 appId,
461 selectedGatewayNode.intgBridge(),
462 externalSelectorBuilder.build(),
463 externalTreatmentBuilder.build(),
464 PRIORITY_FLOATING_EXTERNAL,
465 GW_COMMON_TABLE,
466 install);
467 }
468
Hyunsun Moon44aac662017-02-18 02:07:01 +0900469 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
Jian Li32b03622018-11-06 17:54:24 +0900470 InstancePort instPort,
471 ExternalPeerRouter externalPeerRouter,
daniel park32b42202018-03-14 16:53:44 +0900472 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900473 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900474 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900475 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900476 .matchIPSrc(instPort.ipAddress().toIpPrefix());
477
478 switch (osNet.getNetworkType()) {
479 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900480 case GRE:
daniel parkee8700b2017-05-11 15:50:03 +0900481 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
482 break;
483 case VLAN:
484 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
485 break;
486 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800487 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900488 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900489 throw new IllegalStateException(error);
490 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900491
Daniel Park75e3d7f2018-05-29 14:43:53 +0900492 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900493
Hyunsun Moon0d457362017-06-27 17:19:41 +0900494 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900495 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
496 .setIpSrc(floating.getIp4Address())
497 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900498 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499
Daniel Park75e3d7f2018-05-29 14:43:53 +0900500 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
501 tBuilder.popVlan();
502 }
503
Jian Li5e2ad4a2018-07-16 13:40:53 +0900504 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
505 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900506 }
sanghodc375372017-06-08 10:41:30 +0900507 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900508 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900509 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900510 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900511 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900512 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900513 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900514 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900515 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900516 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517 }
518
Jian Li99892e92018-04-13 14:59:39 +0900519 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900520 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
521
522 if (instPort == null) {
523 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
524 osFip.getFloatingIpAddress());
525 return;
Jian Li99892e92018-04-13 14:59:39 +0900526 }
Jian Li628a7cb2018-08-11 23:04:24 +0900527
Jian Li99892e92018-04-13 14:59:39 +0900528 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900529 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
530 setFloatingIpRules(osFip, instPort, null, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900531 processGratuitousArpPacket(osFip, instPort);
532
Jian Li99892e92018-04-13 14:59:39 +0900533 }
534 }
535
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900536 private void processGratuitousArpPacket(NetFloatingIP floatingIP,
537 InstancePort instancePort) {
538 Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
539
540 Network osNet = osNetworkService.network(instancePort.networkId());
541
542
543 OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
544 ExternalPeerRouter externalPeerRouter =
545 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
546 if (externalPeerRouter == null) {
Jian Li4d138702018-11-27 17:25:28 +0900547 log.error("Failed to process GARP packet for floating ip {}, because " +
548 NO_EXT_PEER_ROUTER_MSG);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900549 return;
550 }
551
Jian Li32b03622018-11-06 17:54:24 +0900552 processGarpPacketForFloatingIp(floatingIP, instancePort,
553 externalPeerRouter.vlanId(), selectedGw, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900554
555 }
556
Jian Li99892e92018-04-13 14:59:39 +0900557 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900558 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900559
Jian Li628a7cb2018-08-11 23:04:24 +0900560 if (instPort == null) {
561 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
562 osFip.getFloatingIpAddress());
563 return;
Jian Lie1a39032018-06-19 21:49:36 +0900564 }
565
Jian Li99892e92018-04-13 14:59:39 +0900566 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900567 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
568 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900569 }
570 }
571
Hyunsun Moon0d457362017-06-27 17:19:41 +0900572 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900573
574 @Override
575 public boolean isRelevant(OpenstackRouterEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900576 return event.floatingIp() != null;
577 }
578
Jian Li34220ea2018-11-14 01:30:24 +0900579 private boolean isRelevantHelper() {
580 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
581 }
582
Hyunsun Moon44aac662017-02-18 02:07:01 +0900583 @Override
584 public void event(OpenstackRouterEvent event) {
585 switch (event.type()) {
586 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900587 eventExecutor.execute(() -> processFloatingIpAssociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900588 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900589 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900590 eventExecutor.execute(() -> processFloatingIpDisassociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900591 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900592 case OPENSTACK_FLOATING_IP_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900593 eventExecutor.execute(() -> processFloatingIpCreation(event));
Hyunsun Moonb720e632017-05-16 15:41:36 +0900594 break;
Jian Lia171a432018-06-11 11:52:11 +0900595 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900596 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Lia171a432018-06-11 11:52:11 +0900597 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900598 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900599 default:
600 // do nothing for the other events
601 break;
602 }
603 }
Jian Li4d138702018-11-27 17:25:28 +0900604
605 private void processFloatingIpAssociation(OpenstackRouterEvent event) {
606 if (!isRelevantHelper()) {
607 return;
608 }
609
610 NetFloatingIP osFip = event.floatingIp();
611 if (instancePortService.instancePort(osFip.getPortId()) != null) {
612 associateFloatingIp(osFip);
613 log.info("Associated floating IP {}:{}",
614 osFip.getFloatingIpAddress(),
615 osFip.getFixedIpAddress());
616 }
617 }
618
619 private void processFloatingIpDisassociation(OpenstackRouterEvent event) {
620 if (!isRelevantHelper()) {
621 return;
622 }
623
624 NetFloatingIP osFip = event.floatingIp();
625 if (instancePortService.instancePort(event.portId()) != null) {
626 disassociateFloatingIp(osFip, event.portId());
627 log.info("Disassociated floating IP {}:{}",
628 osFip.getFloatingIpAddress(),
629 osFip.getFixedIpAddress());
630 }
631 }
632
633 private void processFloatingIpCreation(OpenstackRouterEvent event) {
634 if (!isRelevantHelper()) {
635 return;
636 }
637
638 NetFloatingIP osFip = event.floatingIp();
639 String portId = osFip.getPortId();
640 if (!Strings.isNullOrEmpty(portId) &&
641 instancePortService.instancePort(portId) != null) {
642 associateFloatingIp(event.floatingIp());
643 }
644 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
645 }
646
647 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
648 if (!isRelevantHelper()) {
649 return;
650 }
651
652 NetFloatingIP osFip = event.floatingIp();
653 String portId = osFip.getPortId();
654 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
655 // in case the floating IP is not associated with any port due to
656 // port removal, we simply do not execute floating IP disassociation
657 if (osNetworkService.port(portId) != null &&
658 instancePortService.instancePort(portId) != null) {
659 disassociateFloatingIp(osFip, portId);
660 }
661
662 // since we skip floating IP disassociation, we need to
663 // manually unsubscribe the port pre-remove event
664 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
665 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
666 this.getClass().getName());
667 log.info("Unsubscribed the port {} on listening pre-remove event",
668 osFip.getPortId());
669 }
670 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
671 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672 }
673
674 private class InternalNodeListener implements OpenstackNodeListener {
675
676 @Override
677 public boolean isRelevant(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900678 return event.subject().type() == GATEWAY;
679 }
680
Jian Li34220ea2018-11-14 01:30:24 +0900681 private boolean isRelevantHelper() {
682 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
683 }
684
Hyunsun Moon44aac662017-02-18 02:07:01 +0900685 @Override
686 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900687
688 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900689 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900690 eventExecutor.execute(() -> processNodeCompletion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900691 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900692 case OPENSTACK_NODE_INCOMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900693 eventExecutor.execute(() -> processNodeIncompletion(event));
Jian Li1064e4f2018-05-29 16:16:53 +0900694 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900695 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900696 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900697 break;
698 }
699 }
Jian Li4d138702018-11-27 17:25:28 +0900700
701 private void processNodeCompletion(OpenstackNodeEvent event) {
702 if (!isRelevantHelper()) {
703 return;
704 }
705
706 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
707
708 if (Strings.isNullOrEmpty(fip.getPortId())) {
709 continue;
710 }
711
712 Port osPort = osNetworkService.port(fip.getPortId());
713 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
714
715 // we check both Openstack Port and Instance Port
716 if (osPort == null || instPort == null) {
717 continue;
718 }
719
720 setFloatingIpRules(fip, instPort, event.subject(), true);
721 }
722 }
723
724 private void processNodeIncompletion(OpenstackNodeEvent event) {
725 if (!isRelevantHelper()) {
726 return;
727 }
728
729 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
730 if (Strings.isNullOrEmpty(fip.getPortId())) {
731 continue;
732 }
733 Port osPort = osNetworkService.port(fip.getPortId());
734 if (osPort == null) {
735 log.warn("Failed to set floating IP {}", fip.getId());
736 continue;
737 }
738 Network osNet = osNetworkService.network(osPort.getNetworkId());
739 if (osNet == null) {
740 final String errorFormat = ERR_FLOW + "no network(%s) exists";
741 final String error = String.format(errorFormat,
742 fip.getFloatingIpAddress(),
743 osPort.getNetworkId());
744 throw new IllegalStateException(error);
745 }
746 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
747 log.trace("Mac address of openstack port: {}", srcMac);
748 InstancePort instPort = instancePortService.instancePort(srcMac);
749
750 if (instPort == null) {
751 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
752 final String error = String.format(errorFormat,
753 fip.getFloatingIpAddress(), srcMac);
754 throw new IllegalStateException(error);
755 }
756
757 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
758 osNetworkService, osRouterAdminService);
759 if (externalPeerRouter == null) {
760 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
761 throw new IllegalStateException(errorFormat);
762 }
763
764 updateComputeNodeRules(instPort, osNet, event.subject(), false);
765 updateGatewayNodeRules(fip, instPort, osNet,
766 externalPeerRouter, event.subject(), false);
767 }
768 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900769 }
Jian Li99892e92018-04-13 14:59:39 +0900770
Jian Li24ec59f2018-05-23 19:01:25 +0900771 private class InternalInstancePortListener implements InstancePortListener {
772
Jian Li34220ea2018-11-14 01:30:24 +0900773 private boolean isRelevantHelper(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900774
Jian Lie1a39032018-06-19 21:49:36 +0900775 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
776 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
777 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
778 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
779
780 // we check the possible NPE to avoid duplicated null check
781 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
782 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
783 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
784 return false;
785 }
786 }
787
Jian Li34220ea2018-11-14 01:30:24 +0900788 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li24ec59f2018-05-23 19:01:25 +0900789 }
790
791 @Override
792 public void event(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900793 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900794 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900795 eventExecutor.execute(() -> processInstancePortDetection(event));
Jian Lie1a39032018-06-19 21:49:36 +0900796 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900797 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900798 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900799 break;
800 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900801 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900802 break;
803 default:
804 break;
805 }
806 }
Jian Li4d138702018-11-27 17:25:28 +0900807
808 private void processInstancePortDetection(InstancePortEvent event) {
809 if (!isRelevantHelper(event)) {
810 return;
811 }
812
813 InstancePort instPort = event.subject();
814
815 if (instPort != null && instPort.portId() != null) {
816 osRouterAdminService.floatingIps().stream()
817 .filter(f -> f.getPortId() != null)
818 .filter(f -> f.getPortId().equals(instPort.portId()))
819 .forEach(f -> setFloatingIpRules(f,
820 instPort, null, true));
821 }
822 }
823
824 private void processInstanceMigrationStart(InstancePortEvent event) {
825 if (!isRelevantHelper(event)) {
826 return;
827 }
828
829 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
830 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
831 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
832
833 if (fip == null) {
834 return;
835 }
836
837 Port osPort = osNetworkService.port(fip.getPortId());
838 Network osNet = osNetworkService.network(osPort.getNetworkId());
839 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
840 osNetworkService, osRouterAdminService);
841
842 if (externalPeerRouter == null) {
843 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
844 throw new IllegalStateException(errorFormat);
845 }
846
847 // since DownstreamExternal rules should only be placed in
848 // corresponding gateway node, we need to install new rule to
849 // the corresponding gateway node
850 setDownstreamExternalRulesHelper(fip, osNet,
851 event.subject(), externalPeerRouter, gateways, true);
852
853 // since ComputeNodeToGateway rules should only be placed in
854 // corresponding compute node, we need to install new rule to
855 // the target compute node, and remove rules from original node
856 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
857 }
858
859 private void processInstanceMigrationEnd(InstancePortEvent event) {
860 if (!isRelevantHelper(event)) {
861 return;
862 }
863
864 InstancePort oldInstPort = swapStaleLocation(event.subject());
865
866 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
867 NetFloatingIP fip = associatedFloatingIp(oldInstPort, ips);
868
869 if (fip == null) {
870 return;
871 }
872
873 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
874 Port osPort = osNetworkService.port(fip.getPortId());
875 Network osNet = osNetworkService.network(osPort.getNetworkId());
876 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
877 osNetworkService, osRouterAdminService);
878
879 if (externalPeerRouter == null) {
880 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
881 throw new IllegalStateException(errorFormat);
882 }
883
884 // We need to remove the old ComputeNodeToGateway rules from
885 // original compute node
886 setComputeNodeToGatewayHelper(oldInstPort, osNet, gateways, false);
887
888 // If we only have one gateway, we simply do not remove any
889 // flow rules from either gateway or compute node
890 if (gateways.size() == 1) {
891 return;
892 }
893
894 // Checks whether the destination compute node's device id
895 // has identical gateway hash or not
896 // if it is true, we simply do not remove the rules, as
897 // it has been overwritten at port detention event
898 // if it is false, we will remove the rules
899 DeviceId newDeviceId = event.subject().deviceId();
900 DeviceId oldDeviceId = oldInstPort.deviceId();
901
902 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
903 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
904
905 if (oldGateway != null && oldGateway.equals(newGateway)) {
906 return;
907 }
908
909 // Since DownstreamExternal rules should only be placed in
910 // corresponding gateway node, we need to remove old rule from
911 // the corresponding gateway node
912 setDownstreamExternalRulesHelper(fip, osNet, oldInstPort,
913 externalPeerRouter, gateways, false);
914 }
Jian Li24ec59f2018-05-23 19:01:25 +0900915 }
Jian Lie1a39032018-06-19 21:49:36 +0900916
917 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
918
Jian Li34220ea2018-11-14 01:30:24 +0900919 private boolean isRelevantHelper() {
920 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lie1a39032018-06-19 21:49:36 +0900921 }
922
923 @Override
924 public void event(OpenstackNetworkEvent event) {
Jian Li4d138702018-11-27 17:25:28 +0900925 if (event.type() == OPENSTACK_PORT_PRE_REMOVE) {
926 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900927
Jian Li4d138702018-11-27 17:25:28 +0900928 if (!isRelevantHelper()) {
929 return;
930 }
Jian Li34220ea2018-11-14 01:30:24 +0900931
Jian Li4d138702018-11-27 17:25:28 +0900932 processPortPreRemoval(event);
933 });
Jian Lie1a39032018-06-19 21:49:36 +0900934 }
935 }
936
Jian Li4d138702018-11-27 17:25:28 +0900937 private void processPortPreRemoval(OpenstackNetworkEvent event) {
Jian Li32b03622018-11-06 17:54:24 +0900938 InstancePort instPort = instancePortService.instancePort(
939 event.port().getId());
940 if (instPort == null) {
941 return;
942 }
943 NetFloatingIP fip = associatedFloatingIp(instPort,
944 osRouterAdminService.floatingIps());
945
946 if (fip != null) {
947 instancePortService.updateInstancePort(
948 instPort.updateState(REMOVE_PENDING));
949 updateFipStore(event.port().getId());
950 } else {
951 instancePortService.removeInstancePort(instPort.portId());
952 }
953 }
954
Jian Li2360acb2018-10-17 00:46:31 +0900955 private void updateFipStore(String portId) {
Jian Lie1a39032018-06-19 21:49:36 +0900956
Jian Li2360acb2018-10-17 00:46:31 +0900957 if (portId == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900958 return;
959 }
960
961 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
962 for (NetFloatingIP fip : ips) {
963 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
964 continue;
965 }
966 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
967 continue;
968 }
Jian Li2360acb2018-10-17 00:46:31 +0900969 if (fip.getPortId().equals(portId)) {
Jian Lie1a39032018-06-19 21:49:36 +0900970 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
971 // invalidate bound fixed IP and port
972 neutronFip.setFixedIpAddress(null);
973 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900974
975 // Following update will in turn trigger
976 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
977 osRouterAdminService.updateFloatingIp(neutronFip);
978 log.info("Updated floating IP {}, due to host removal",
979 neutronFip.getFloatingIpAddress());
980 }
981 }
982 }
983 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900984}