blob: 5a324ee4baf4ec1c6408bda0db4959404e43dff9 [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;
SONA Project6bc5c4a2018-12-14 23:49:52 +090045import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Lie1a39032018-06-19 21:49:36 +090046import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
47import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090048import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090049import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
51import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li8f64feb2018-07-24 13:20:16 +090052import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090053import org.onosproject.openstacknode.api.OpenstackNode;
54import org.onosproject.openstacknode.api.OpenstackNodeEvent;
55import org.onosproject.openstacknode.api.OpenstackNodeListener;
56import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090057import org.openstack4j.model.network.NetFloatingIP;
58import org.openstack4j.model.network.Network;
59import 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;
SONA Project6bc5c4a2018-12-14 23:49:52 +090083import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
84import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
85import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
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;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
Jian Li1064e4f2018-05-29 16:16:53 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090091import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Li32b03622018-11-06 17:54:24 +090092import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +090093import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +090094import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Li26949762018-03-30 15:46:37 +090095import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090096import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090097
98/**
99 * Handles OpenStack floating IP events.
100 */
101@Component(immediate = true)
102public class OpenstackRoutingFloatingIpHandler {
103
104 private final Logger log = LoggerFactory.getLogger(getClass());
105
106 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800107 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108
Jian Li4d138702018-11-27 17:25:28 +0900109 private static final String NO_EXT_PEER_ROUTER_MSG = "no external peer router found";
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 protected CoreService coreService;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115 protected DeviceService deviceService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118 protected LeadershipService leadershipService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121 protected ClusterService clusterService;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124 protected OpenstackNodeService osNodeService;
125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liec5c32b2018-07-13 14:28:58 +0900127 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900130 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900133 protected OpenstackNetworkService osNetworkService;
134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900136 protected OpenstackFlowRuleService osFlowRuleService;
137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li8f64feb2018-07-24 13:20:16 +0900139 protected PreCommitPortService preCommitPortService;
140
Ray Milkeyd5425682018-10-23 10:21:33 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900142 protected PacketService packetService;
143
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144 private final ExecutorService eventExecutor = newSingleThreadExecutor(
145 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900146 private final OpenstackRouterListener
147 floatingIpListener = new InternalFloatingIpListener();
148 private final InstancePortListener
149 instancePortListener = new InternalInstancePortListener();
150 private final OpenstackNodeListener
151 osNodeListener = new InternalNodeListener();
152 private final OpenstackNetworkListener
153 osNetworkListener = new InternalOpenstackNetworkListener();
154 private final InstancePortListener
155 instPortListener = new InternalInstancePortListener();
Jian Lie1a39032018-06-19 21:49:36 +0900156
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 private ApplicationId appId;
158 private NodeId localNodeId;
159
160 @Activate
161 protected void activate() {
162 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
163 localNodeId = clusterService.getLocalNode().id();
164 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900165 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900167 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900168 osNodeService.addListener(osNodeListener);
169 osNetworkService.addListener(osNetworkListener);
170 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171
172 log.info("Started");
173 }
174
175 @Deactivate
176 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900177 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900178 instancePortService.removeListener(instPortListener);
179 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900180 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900181 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 leadershipService.withdraw(appId.name());
183 eventExecutor.shutdown();
184
185 log.info("Stopped");
186 }
187
Jian Li628a7cb2018-08-11 23:04:24 +0900188 private void setFloatingIpRules(NetFloatingIP floatingIp, InstancePort instPort,
Jian Li1064e4f2018-05-29 16:16:53 +0900189 OpenstackNode gateway, boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900190
191 if (instPort == null) {
192 log.debug("No instance port found");
193 return;
194 }
195
196 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900197
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900198 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
199 osNetworkService, osRouterAdminService);
daniel park32b42202018-03-14 16:53:44 +0900200 if (externalPeerRouter == null) {
Jian Li4d138702018-11-27 17:25:28 +0900201 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
daniel parkc2a2ed62018-04-10 15:17:42 +0900202 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900203 }
204
Jian Li8f64feb2018-07-24 13:20:16 +0900205 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900206 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900207 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900208 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900209 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900210 preCommitPortService.unsubscribePreCommit(instPort.portId(),
211 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
212 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900213 }
214
Jian Lide679782018-06-05 01:41:29 +0900215 updateComputeNodeRules(instPort, osNet, gateway, install);
216 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
217
Jian Lide679782018-06-05 01:41:29 +0900218 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900219 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900220
daniel parkc2a2ed62018-04-10 15:17:42 +0900221 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
222 floatingIp.getFloatingIpAddress(),
223 floatingIp.getFixedIpAddress(),
224 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900225 }
226
Jian Lide679782018-06-05 01:41:29 +0900227 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
228 InstancePort instPort,
229 Network osNet,
230 ExternalPeerRouter router,
231 OpenstackNode gateway,
232 boolean install) {
233
234 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
235 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
236 finalGws.addAll(ImmutableSet.copyOf(completedGws));
237
Jian Lia171a432018-06-11 11:52:11 +0900238
239 if (gateway == null) {
240 // these are floating IP related cases...
241 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
242 ImmutableSet.copyOf(finalGws), install);
243
Jian Lide679782018-06-05 01:41:29 +0900244 } else {
Jian Lia171a432018-06-11 11:52:11 +0900245 // these are openstack node related cases...
246 if (install) {
247 if (completedGws.contains(gateway)) {
248 if (completedGws.size() > 1) {
249 finalGws.remove(gateway);
250 if (fip.getPortId() != null) {
251 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
252 ImmutableSet.copyOf(finalGws), false);
253 finalGws.add(gateway);
254 }
255 }
Jian Lide679782018-06-05 01:41:29 +0900256 if (fip.getPortId() != null) {
257 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
258 ImmutableSet.copyOf(finalGws), true);
259 }
Jian Lia171a432018-06-11 11:52:11 +0900260 } else {
261 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900262 }
263 } else {
Jian Lia171a432018-06-11 11:52:11 +0900264 if (!completedGws.contains(gateway)) {
Jian Li4d138702018-11-27 17:25:28 +0900265 if (!completedGws.isEmpty() && fip.getPortId() != null) {
266 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
Jian Lia171a432018-06-11 11:52:11 +0900267 ImmutableSet.copyOf(finalGws), true);
Jian Lia171a432018-06-11 11:52:11 +0900268 }
269 } else {
270 log.warn("Detected node should NOT be included in completed gateway set");
271 }
Jian Lide679782018-06-05 01:41:29 +0900272 }
273 }
274 }
275
276 private synchronized void updateComputeNodeRules(InstancePort instPort,
277 Network osNet,
278 OpenstackNode gateway,
279 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900280
281 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
282 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
283 finalGws.addAll(ImmutableSet.copyOf(completedGws));
284
285 if (gateway == null) {
286 // these are floating IP related cases...
287 setComputeNodeToGatewayHelper(instPort, osNet,
288 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900289
Jian Li1064e4f2018-05-29 16:16:53 +0900290 } else {
291 // these are openstack node related cases...
292 if (install) {
293 if (completedGws.contains(gateway)) {
294 if (completedGws.size() > 1) {
295 finalGws.remove(gateway);
296 setComputeNodeToGatewayHelper(instPort, osNet,
297 ImmutableSet.copyOf(finalGws), false);
298 finalGws.add(gateway);
299 }
300
301 setComputeNodeToGatewayHelper(instPort, osNet,
302 ImmutableSet.copyOf(finalGws), true);
303 } else {
304 log.warn("Detected node should be included in completed gateway set");
305 }
306 } else {
307 if (!completedGws.contains(gateway)) {
308 finalGws.add(gateway);
309 setComputeNodeToGatewayHelper(instPort, osNet,
310 ImmutableSet.copyOf(finalGws), false);
311 finalGws.remove(gateway);
Jian Li4d138702018-11-27 17:25:28 +0900312 if (!completedGws.isEmpty()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900313 setComputeNodeToGatewayHelper(instPort, osNet,
314 ImmutableSet.copyOf(finalGws), true);
315 }
316 } else {
317 log.warn("Detected node should NOT be included in completed gateway set");
318 }
319 }
320 }
321 }
322
323 // a helper method
324 private void setComputeNodeToGatewayHelper(InstancePort instPort,
325 Network osNet,
326 Set<OpenstackNode> gateways,
327 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900328
329 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
330 .matchEthType(Ethernet.TYPE_IPV4)
331 .matchIPSrc(instPort.ipAddress().toIpPrefix())
332 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
333
Daniel Park3f26e792018-11-26 18:34:53 +0900334 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkeeb8e042018-02-21 14:06:58 +0900335
Jian Li5ecfd1a2018-12-10 11:41:03 +0900336 OpenstackNode selectedGatewayNode =
337 getGwByComputeDevId(gateways, instPort.deviceId());
Jian Li1064e4f2018-05-29 16:16:53 +0900338
daniel parkeeb8e042018-02-21 14:06:58 +0900339 if (selectedGatewayNode == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900340 log.warn(ERR_FLOW + "no gateway node selected");
Jian Lifb64d882018-11-27 10:57:40 +0900341 return;
daniel parkeeb8e042018-02-21 14:06:58 +0900342 }
Daniel Park3f26e792018-11-26 18:34:53 +0900343
344 switch (osNet.getNetworkType()) {
345 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900346 case GRE:
347 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
348 osNetworkService, osNodeService.node(instPort.deviceId()));
349
350 if (portNum == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900351 log.warn(ERR_FLOW + "no tunnel port");
352 return;
353 }
Jian Li2d68c192018-12-13 15:52:59 +0900354
Daniel Park3f26e792018-11-26 18:34:53 +0900355 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
Jian Li2d68c192018-12-13 15:52:59 +0900356
Daniel Park3f26e792018-11-26 18:34:53 +0900357 tBuilder.extension(buildExtension(
daniel parkeeb8e042018-02-21 14:06:58 +0900358 deviceService,
359 instPort.deviceId(),
360 selectedGatewayNode.dataIp().getIp4Address()),
361 instPort.deviceId())
Jian Li2d68c192018-12-13 15:52:59 +0900362 .setOutput(portNum);
Daniel Park3f26e792018-11-26 18:34:53 +0900363 break;
364 case VLAN:
365 if (osNodeService.node(instPort.deviceId()).vlanPortNum() == null) {
366 log.warn(ERR_FLOW + "no vlan port");
367 return;
368 }
369 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
370 tBuilder.setOutput(osNodeService.node(instPort.deviceId()).vlanPortNum());
371 break;
372 default:
373 log.warn(ERR_FLOW + "no supported network type");
374 }
daniel parkeeb8e042018-02-21 14:06:58 +0900375
376 osFlowRuleService.setRule(
377 appId,
378 instPort.deviceId(),
379 sBuilder.build(),
Daniel Park3f26e792018-11-26 18:34:53 +0900380 tBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900381 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
382 ROUTING_TABLE,
383 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900384 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900385 }
386
Jian Lide679782018-06-05 01:41:29 +0900387 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
388 Network osNet,
389 InstancePort instPort,
390 ExternalPeerRouter externalPeerRouter,
391 Set<OpenstackNode> gateways, boolean install) {
392 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900393 Type netType = osNetworkService.networkType(osNet.getId());
Jian Lide679782018-06-05 01:41:29 +0900394 if (cNode == null) {
395 final String error = String.format("Cannot find openstack node for device %s",
396 instPort.deviceId());
397 throw new IllegalStateException(error);
398 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900399 if (netType == VXLAN && cNode.dataIp() == null) {
Jian Lide679782018-06-05 01:41:29 +0900400 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
401 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
402 throw new IllegalStateException(error);
403 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900404 if (netType == GRE && cNode.dataIp() == null) {
Jian Li2d68c192018-12-13 15:52:59 +0900405 final String errorFormat = ERR_FLOW + "GRE mode is not ready for %s";
406 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
407 throw new IllegalStateException(error);
408 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900409 if (netType == VLAN && cNode.vlanIntf() == null) {
Jian Lide679782018-06-05 01:41:29 +0900410 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
411 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
412 throw new IllegalStateException(error);
413 }
414
415 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
416
417 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
418
419 if (selectedGatewayNode == null) {
420 final String errorFormat = ERR_FLOW + "no gateway node selected";
421 throw new IllegalStateException(errorFormat);
422 }
423
424 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
425 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900426 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900427 .matchIPDst(floating.toIpPrefix());
428
429 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
430 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
431 .setEthDst(instPort.macAddress())
432 .setIpDst(instPort.ipAddress().getIp4Address());
433
Jian Li5e2ad4a2018-07-16 13:40:53 +0900434 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
435 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900436 externalTreatmentBuilder.popVlan();
437 }
438
439 switch (osNet.getNetworkType()) {
440 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900441 case GRE:
442 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
443 osNetworkService, selectedGatewayNode);
Jian Lide679782018-06-05 01:41:29 +0900444 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
445 .extension(buildExtension(
446 deviceService,
447 selectedGatewayNode.intgBridge(),
448 cNode.dataIp().getIp4Address()),
449 selectedGatewayNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900450 .setOutput(portNum);
Jian Lide679782018-06-05 01:41:29 +0900451 break;
452 case VLAN:
453 externalTreatmentBuilder.pushVlan()
454 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
455 .setOutput(selectedGatewayNode.vlanPortNum());
456 break;
457 default:
458 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
459 osNet.getNetworkType());
460 throw new IllegalStateException(error);
461 }
462
463 osFlowRuleService.setRule(
464 appId,
465 selectedGatewayNode.intgBridge(),
466 externalSelectorBuilder.build(),
467 externalTreatmentBuilder.build(),
468 PRIORITY_FLOATING_EXTERNAL,
469 GW_COMMON_TABLE,
470 install);
471 }
472
Hyunsun Moon44aac662017-02-18 02:07:01 +0900473 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
Jian Li32b03622018-11-06 17:54:24 +0900474 InstancePort instPort,
475 ExternalPeerRouter externalPeerRouter,
daniel park32b42202018-03-14 16:53:44 +0900476 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900477 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900478 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900479 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900480 .matchIPSrc(instPort.ipAddress().toIpPrefix());
481
482 switch (osNet.getNetworkType()) {
483 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900484 case GRE:
daniel parkee8700b2017-05-11 15:50:03 +0900485 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
486 break;
487 case VLAN:
488 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
489 break;
490 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800491 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900492 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900493 throw new IllegalStateException(error);
494 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900495
Daniel Park75e3d7f2018-05-29 14:43:53 +0900496 TrafficSelector selector = sBuilder.build();
SONA Project6bc5c4a2018-12-14 23:49:52 +0900497 Type netType = osNetworkService.networkType(osNet.getId());
daniel parkeeb8e042018-02-21 14:06:58 +0900498
Hyunsun Moon0d457362017-06-27 17:19:41 +0900499 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900500 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
501 .setIpSrc(floating.getIp4Address())
502 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900503 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900504
SONA Project6bc5c4a2018-12-14 23:49:52 +0900505 if (netType == VLAN) {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900506 tBuilder.popVlan();
507 }
508
Jian Li5e2ad4a2018-07-16 13:40:53 +0900509 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
510 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900511 }
sanghodc375372017-06-08 10:41:30 +0900512 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900513 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900514 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900515 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900516 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900518 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900519 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900520 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900521 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900522 }
523
Jian Li99892e92018-04-13 14:59:39 +0900524 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900525 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
526
527 if (instPort == null) {
528 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
529 osFip.getFloatingIpAddress());
530 return;
Jian Li99892e92018-04-13 14:59:39 +0900531 }
Jian Li628a7cb2018-08-11 23:04:24 +0900532
Jian Li99892e92018-04-13 14:59:39 +0900533 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900534 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
535 setFloatingIpRules(osFip, instPort, null, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900536 processGratuitousArpPacket(osFip, instPort);
537
Jian Li99892e92018-04-13 14:59:39 +0900538 }
539 }
540
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900541 private void processGratuitousArpPacket(NetFloatingIP floatingIP,
542 InstancePort instancePort) {
543 Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
544
545 Network osNet = osNetworkService.network(instancePort.networkId());
546
547
548 OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
549 ExternalPeerRouter externalPeerRouter =
550 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
551 if (externalPeerRouter == null) {
Jian Li4d138702018-11-27 17:25:28 +0900552 log.error("Failed to process GARP packet for floating ip {}, because " +
553 NO_EXT_PEER_ROUTER_MSG);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900554 return;
555 }
556
Jian Li32b03622018-11-06 17:54:24 +0900557 processGarpPacketForFloatingIp(floatingIP, instancePort,
558 externalPeerRouter.vlanId(), selectedGw, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900559
560 }
561
Jian Li99892e92018-04-13 14:59:39 +0900562 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900563 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900564
Jian Li628a7cb2018-08-11 23:04:24 +0900565 if (instPort == null) {
566 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
567 osFip.getFloatingIpAddress());
568 return;
Jian Lie1a39032018-06-19 21:49:36 +0900569 }
570
Jian Li99892e92018-04-13 14:59:39 +0900571 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900572 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
573 setFloatingIpRules(osFip, instPort, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900574 }
575 }
576
Hyunsun Moon0d457362017-06-27 17:19:41 +0900577 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900578
579 @Override
580 public boolean isRelevant(OpenstackRouterEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900581 return event.floatingIp() != null;
582 }
583
Jian Li34220ea2018-11-14 01:30:24 +0900584 private boolean isRelevantHelper() {
585 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
586 }
587
Hyunsun Moon44aac662017-02-18 02:07:01 +0900588 @Override
589 public void event(OpenstackRouterEvent event) {
590 switch (event.type()) {
591 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900592 eventExecutor.execute(() -> processFloatingIpAssociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900593 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900594 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900595 eventExecutor.execute(() -> processFloatingIpDisassociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900596 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900597 case OPENSTACK_FLOATING_IP_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900598 eventExecutor.execute(() -> processFloatingIpCreation(event));
Hyunsun Moonb720e632017-05-16 15:41:36 +0900599 break;
Jian Lia171a432018-06-11 11:52:11 +0900600 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900601 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Lia171a432018-06-11 11:52:11 +0900602 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900603 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900604 default:
605 // do nothing for the other events
606 break;
607 }
608 }
Jian Li4d138702018-11-27 17:25:28 +0900609
610 private void processFloatingIpAssociation(OpenstackRouterEvent event) {
611 if (!isRelevantHelper()) {
612 return;
613 }
614
615 NetFloatingIP osFip = event.floatingIp();
616 if (instancePortService.instancePort(osFip.getPortId()) != null) {
617 associateFloatingIp(osFip);
618 log.info("Associated floating IP {}:{}",
619 osFip.getFloatingIpAddress(),
620 osFip.getFixedIpAddress());
621 }
622 }
623
624 private void processFloatingIpDisassociation(OpenstackRouterEvent event) {
625 if (!isRelevantHelper()) {
626 return;
627 }
628
629 NetFloatingIP osFip = event.floatingIp();
630 if (instancePortService.instancePort(event.portId()) != null) {
631 disassociateFloatingIp(osFip, event.portId());
632 log.info("Disassociated floating IP {}:{}",
633 osFip.getFloatingIpAddress(),
634 osFip.getFixedIpAddress());
635 }
636 }
637
638 private void processFloatingIpCreation(OpenstackRouterEvent event) {
639 if (!isRelevantHelper()) {
640 return;
641 }
642
643 NetFloatingIP osFip = event.floatingIp();
644 String portId = osFip.getPortId();
645 if (!Strings.isNullOrEmpty(portId) &&
646 instancePortService.instancePort(portId) != null) {
647 associateFloatingIp(event.floatingIp());
648 }
649 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
650 }
651
652 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
653 if (!isRelevantHelper()) {
654 return;
655 }
656
657 NetFloatingIP osFip = event.floatingIp();
658 String portId = osFip.getPortId();
659 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
660 // in case the floating IP is not associated with any port due to
661 // port removal, we simply do not execute floating IP disassociation
662 if (osNetworkService.port(portId) != null &&
663 instancePortService.instancePort(portId) != null) {
664 disassociateFloatingIp(osFip, portId);
665 }
666
667 // since we skip floating IP disassociation, we need to
668 // manually unsubscribe the port pre-remove event
669 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
670 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
671 this.getClass().getName());
672 log.info("Unsubscribed the port {} on listening pre-remove event",
673 osFip.getPortId());
674 }
675 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
676 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900677 }
678
679 private class InternalNodeListener implements OpenstackNodeListener {
680
681 @Override
682 public boolean isRelevant(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900683 return event.subject().type() == GATEWAY;
684 }
685
Jian Li34220ea2018-11-14 01:30:24 +0900686 private boolean isRelevantHelper() {
687 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
688 }
689
Hyunsun Moon44aac662017-02-18 02:07:01 +0900690 @Override
691 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900692
693 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900694 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900695 eventExecutor.execute(() -> processNodeCompletion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900696 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900697 case OPENSTACK_NODE_INCOMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900698 eventExecutor.execute(() -> processNodeIncompletion(event));
Jian Li1064e4f2018-05-29 16:16:53 +0900699 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900700 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900701 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900702 break;
703 }
704 }
Jian Li4d138702018-11-27 17:25:28 +0900705
706 private void processNodeCompletion(OpenstackNodeEvent event) {
707 if (!isRelevantHelper()) {
708 return;
709 }
710
711 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
712
713 if (Strings.isNullOrEmpty(fip.getPortId())) {
714 continue;
715 }
716
717 Port osPort = osNetworkService.port(fip.getPortId());
718 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
719
720 // we check both Openstack Port and Instance Port
721 if (osPort == null || instPort == null) {
722 continue;
723 }
724
725 setFloatingIpRules(fip, instPort, event.subject(), true);
726 }
727 }
728
729 private void processNodeIncompletion(OpenstackNodeEvent event) {
730 if (!isRelevantHelper()) {
731 return;
732 }
733
734 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
735 if (Strings.isNullOrEmpty(fip.getPortId())) {
736 continue;
737 }
738 Port osPort = osNetworkService.port(fip.getPortId());
739 if (osPort == null) {
740 log.warn("Failed to set floating IP {}", fip.getId());
741 continue;
742 }
743 Network osNet = osNetworkService.network(osPort.getNetworkId());
744 if (osNet == null) {
745 final String errorFormat = ERR_FLOW + "no network(%s) exists";
746 final String error = String.format(errorFormat,
747 fip.getFloatingIpAddress(),
748 osPort.getNetworkId());
749 throw new IllegalStateException(error);
750 }
751 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
752 log.trace("Mac address of openstack port: {}", srcMac);
753 InstancePort instPort = instancePortService.instancePort(srcMac);
754
755 if (instPort == null) {
756 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
757 final String error = String.format(errorFormat,
758 fip.getFloatingIpAddress(), srcMac);
759 throw new IllegalStateException(error);
760 }
761
762 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
763 osNetworkService, osRouterAdminService);
764 if (externalPeerRouter == null) {
765 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
766 throw new IllegalStateException(errorFormat);
767 }
768
769 updateComputeNodeRules(instPort, osNet, event.subject(), false);
770 updateGatewayNodeRules(fip, instPort, osNet,
771 externalPeerRouter, event.subject(), false);
772 }
773 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900774 }
Jian Li99892e92018-04-13 14:59:39 +0900775
Jian Li24ec59f2018-05-23 19:01:25 +0900776 private class InternalInstancePortListener implements InstancePortListener {
777
Jian Li34220ea2018-11-14 01:30:24 +0900778 private boolean isRelevantHelper(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900779
Jian Lie1a39032018-06-19 21:49:36 +0900780 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
781 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
782 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
783 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
784
785 // we check the possible NPE to avoid duplicated null check
786 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
787 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
788 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
789 return false;
790 }
791 }
792
Jian Li34220ea2018-11-14 01:30:24 +0900793 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li24ec59f2018-05-23 19:01:25 +0900794 }
795
796 @Override
797 public void event(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900798 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900799 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900800 eventExecutor.execute(() -> processInstancePortDetection(event));
Jian Lie1a39032018-06-19 21:49:36 +0900801 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900802 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900803 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900804 break;
805 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900806 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900807 break;
808 default:
809 break;
810 }
811 }
Jian Li4d138702018-11-27 17:25:28 +0900812
813 private void processInstancePortDetection(InstancePortEvent event) {
814 if (!isRelevantHelper(event)) {
815 return;
816 }
817
818 InstancePort instPort = event.subject();
819
820 if (instPort != null && instPort.portId() != null) {
821 osRouterAdminService.floatingIps().stream()
822 .filter(f -> f.getPortId() != null)
823 .filter(f -> f.getPortId().equals(instPort.portId()))
824 .forEach(f -> setFloatingIpRules(f,
825 instPort, null, true));
826 }
827 }
828
829 private void processInstanceMigrationStart(InstancePortEvent event) {
830 if (!isRelevantHelper(event)) {
831 return;
832 }
833
834 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
835 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
836 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
837
838 if (fip == null) {
839 return;
840 }
841
842 Port osPort = osNetworkService.port(fip.getPortId());
843 Network osNet = osNetworkService.network(osPort.getNetworkId());
844 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
845 osNetworkService, osRouterAdminService);
846
847 if (externalPeerRouter == null) {
848 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
849 throw new IllegalStateException(errorFormat);
850 }
851
852 // since DownstreamExternal rules should only be placed in
853 // corresponding gateway node, we need to install new rule to
854 // the corresponding gateway node
855 setDownstreamExternalRulesHelper(fip, osNet,
856 event.subject(), externalPeerRouter, gateways, true);
857
858 // since ComputeNodeToGateway rules should only be placed in
859 // corresponding compute node, we need to install new rule to
860 // the target compute node, and remove rules from original node
861 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
862 }
863
864 private void processInstanceMigrationEnd(InstancePortEvent event) {
865 if (!isRelevantHelper(event)) {
866 return;
867 }
868
869 InstancePort oldInstPort = swapStaleLocation(event.subject());
870
871 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
872 NetFloatingIP fip = associatedFloatingIp(oldInstPort, ips);
873
874 if (fip == null) {
875 return;
876 }
877
878 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
879 Port osPort = osNetworkService.port(fip.getPortId());
880 Network osNet = osNetworkService.network(osPort.getNetworkId());
881 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
882 osNetworkService, osRouterAdminService);
883
884 if (externalPeerRouter == null) {
885 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
886 throw new IllegalStateException(errorFormat);
887 }
888
889 // We need to remove the old ComputeNodeToGateway rules from
890 // original compute node
891 setComputeNodeToGatewayHelper(oldInstPort, osNet, gateways, false);
892
893 // If we only have one gateway, we simply do not remove any
894 // flow rules from either gateway or compute node
895 if (gateways.size() == 1) {
896 return;
897 }
898
899 // Checks whether the destination compute node's device id
900 // has identical gateway hash or not
901 // if it is true, we simply do not remove the rules, as
902 // it has been overwritten at port detention event
903 // if it is false, we will remove the rules
904 DeviceId newDeviceId = event.subject().deviceId();
905 DeviceId oldDeviceId = oldInstPort.deviceId();
906
907 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
908 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
909
910 if (oldGateway != null && oldGateway.equals(newGateway)) {
911 return;
912 }
913
914 // Since DownstreamExternal rules should only be placed in
915 // corresponding gateway node, we need to remove old rule from
916 // the corresponding gateway node
917 setDownstreamExternalRulesHelper(fip, osNet, oldInstPort,
918 externalPeerRouter, gateways, false);
919 }
Jian Li24ec59f2018-05-23 19:01:25 +0900920 }
Jian Lie1a39032018-06-19 21:49:36 +0900921
922 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
923
Jian Li34220ea2018-11-14 01:30:24 +0900924 private boolean isRelevantHelper() {
925 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lie1a39032018-06-19 21:49:36 +0900926 }
927
928 @Override
929 public void event(OpenstackNetworkEvent event) {
Jian Li4d138702018-11-27 17:25:28 +0900930 if (event.type() == OPENSTACK_PORT_PRE_REMOVE) {
931 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900932
Jian Li4d138702018-11-27 17:25:28 +0900933 if (!isRelevantHelper()) {
934 return;
935 }
Jian Li34220ea2018-11-14 01:30:24 +0900936
Jian Li4d138702018-11-27 17:25:28 +0900937 processPortPreRemoval(event);
938 });
Jian Lie1a39032018-06-19 21:49:36 +0900939 }
940 }
941
Jian Li4d138702018-11-27 17:25:28 +0900942 private void processPortPreRemoval(OpenstackNetworkEvent event) {
Jian Li32b03622018-11-06 17:54:24 +0900943 InstancePort instPort = instancePortService.instancePort(
944 event.port().getId());
945 if (instPort == null) {
946 return;
947 }
948 NetFloatingIP fip = associatedFloatingIp(instPort,
949 osRouterAdminService.floatingIps());
950
951 if (fip != null) {
952 instancePortService.updateInstancePort(
953 instPort.updateState(REMOVE_PENDING));
954 updateFipStore(event.port().getId());
955 } else {
956 instancePortService.removeInstancePort(instPort.portId());
957 }
958 }
959
Jian Li2360acb2018-10-17 00:46:31 +0900960 private void updateFipStore(String portId) {
Jian Lie1a39032018-06-19 21:49:36 +0900961
Jian Li2360acb2018-10-17 00:46:31 +0900962 if (portId == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900963 return;
964 }
965
966 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
967 for (NetFloatingIP fip : ips) {
968 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
969 continue;
970 }
971 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
972 continue;
973 }
Jian Li2360acb2018-10-17 00:46:31 +0900974 if (fip.getPortId().equals(portId)) {
Jian Lie1a39032018-06-19 21:49:36 +0900975 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
976 // invalidate bound fixed IP and port
977 neutronFip.setFixedIpAddress(null);
978 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +0900979
980 // Following update will in turn trigger
981 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
982 osRouterAdminService.updateFloatingIp(neutronFip);
983 log.info("Updated floating IP {}, due to host removal",
984 neutronFip.getFloatingIpAddress());
985 }
986 }
987 }
988 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900989}