blob: ce04d6947012a429c754df2345001c695d30afb0 [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;
Jian Lie6e609f2019-05-14 17:45:54 +090083import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090084import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
85import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
86import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Jian Li8f64feb2018-07-24 13:20:16 +090087import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
Jian Li1064e4f2018-05-29 16:16:53 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090091import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090092import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Li32b03622018-11-06 17:54:24 +090093import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +090094import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +090095import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Li26949762018-03-30 15:46:37 +090096import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090097import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090098
99/**
100 * Handles OpenStack floating IP events.
101 */
102@Component(immediate = true)
103public class OpenstackRoutingFloatingIpHandler {
104
105 private final Logger log = LoggerFactory.getLogger(getClass());
106
107 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800108 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109
Jian Li4d138702018-11-27 17:25:28 +0900110 private static final String NO_EXT_PEER_ROUTER_MSG = "no external peer router found";
111
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113 protected CoreService coreService;
114
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900116 protected DeviceService deviceService;
117
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119 protected LeadershipService leadershipService;
120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122 protected ClusterService clusterService;
123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125 protected OpenstackNodeService osNodeService;
126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liec5c32b2018-07-13 14:28:58 +0900128 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900131 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900134 protected OpenstackNetworkService osNetworkService;
135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900137 protected OpenstackFlowRuleService osFlowRuleService;
138
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li8f64feb2018-07-24 13:20:16 +0900140 protected PreCommitPortService preCommitPortService;
141
Ray Milkeyd5425682018-10-23 10:21:33 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900143 protected PacketService packetService;
144
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145 private final ExecutorService eventExecutor = newSingleThreadExecutor(
146 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900147 private final OpenstackRouterListener
148 floatingIpListener = new InternalFloatingIpListener();
149 private final InstancePortListener
150 instancePortListener = new InternalInstancePortListener();
151 private final OpenstackNodeListener
152 osNodeListener = new InternalNodeListener();
153 private final OpenstackNetworkListener
154 osNetworkListener = new InternalOpenstackNetworkListener();
155 private final InstancePortListener
156 instPortListener = new InternalInstancePortListener();
Jian Lie1a39032018-06-19 21:49:36 +0900157
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158 private ApplicationId appId;
159 private NodeId localNodeId;
160
161 @Activate
162 protected void activate() {
163 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
164 localNodeId = clusterService.getLocalNode().id();
165 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900166 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900168 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900169 osNodeService.addListener(osNodeListener);
170 osNetworkService.addListener(osNetworkListener);
171 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172
173 log.info("Started");
174 }
175
176 @Deactivate
177 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900178 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900179 instancePortService.removeListener(instPortListener);
180 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900182 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900183 leadershipService.withdraw(appId.name());
184 eventExecutor.shutdown();
185
186 log.info("Stopped");
187 }
188
Jian Lie6e609f2019-05-14 17:45:54 +0900189 private void setFloatingIpRules(NetFloatingIP floatingIp,
190 InstancePort instPort,
191 OpenstackNode gateway,
192 ExternalPeerRouter peerRouter,
193 boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900194
195 if (instPort == null) {
196 log.debug("No instance port found");
197 return;
198 }
199
200 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900201
Jian Lie6e609f2019-05-14 17:45:54 +0900202 ExternalPeerRouter externalPeerRouter = peerRouter != null ? peerRouter :
203 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
204
daniel park32b42202018-03-14 16:53:44 +0900205 if (externalPeerRouter == null) {
Jian Lie6e609f2019-05-14 17:45:54 +0900206 log.warn("External peer router is not ready for now, " +
207 "floating IP rules will be installed/uninstalled " +
208 "when external peer router is available...");
209 return;
daniel park32b42202018-03-14 16:53:44 +0900210 }
211
Jian Li8f64feb2018-07-24 13:20:16 +0900212 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900213 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900214 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900215 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900216 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900217 preCommitPortService.unsubscribePreCommit(instPort.portId(),
218 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
219 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900220 }
221
Jian Lide679782018-06-05 01:41:29 +0900222 updateComputeNodeRules(instPort, osNet, gateway, install);
223 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
224
Jian Lide679782018-06-05 01:41:29 +0900225 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900226 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900227
daniel parkc2a2ed62018-04-10 15:17:42 +0900228 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
229 floatingIp.getFloatingIpAddress(),
230 floatingIp.getFixedIpAddress(),
231 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900232 }
233
Jian Lide679782018-06-05 01:41:29 +0900234 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
235 InstancePort instPort,
236 Network osNet,
237 ExternalPeerRouter router,
238 OpenstackNode gateway,
239 boolean install) {
240
241 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
242 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
243 finalGws.addAll(ImmutableSet.copyOf(completedGws));
244
Jian Lia171a432018-06-11 11:52:11 +0900245
246 if (gateway == null) {
247 // these are floating IP related cases...
248 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
249 ImmutableSet.copyOf(finalGws), install);
250
Jian Lide679782018-06-05 01:41:29 +0900251 } else {
Jian Lia171a432018-06-11 11:52:11 +0900252 // these are openstack node related cases...
253 if (install) {
254 if (completedGws.contains(gateway)) {
255 if (completedGws.size() > 1) {
256 finalGws.remove(gateway);
257 if (fip.getPortId() != null) {
258 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
259 ImmutableSet.copyOf(finalGws), false);
260 finalGws.add(gateway);
261 }
262 }
Jian Lide679782018-06-05 01:41:29 +0900263 if (fip.getPortId() != null) {
264 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
265 ImmutableSet.copyOf(finalGws), true);
266 }
Jian Lia171a432018-06-11 11:52:11 +0900267 } else {
268 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900269 }
270 } else {
Jian Lia171a432018-06-11 11:52:11 +0900271 if (!completedGws.contains(gateway)) {
Jian Li4d138702018-11-27 17:25:28 +0900272 if (!completedGws.isEmpty() && fip.getPortId() != null) {
273 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
Jian Lia171a432018-06-11 11:52:11 +0900274 ImmutableSet.copyOf(finalGws), true);
Jian Lia171a432018-06-11 11:52:11 +0900275 }
276 } else {
277 log.warn("Detected node should NOT be included in completed gateway set");
278 }
Jian Lide679782018-06-05 01:41:29 +0900279 }
280 }
281 }
282
283 private synchronized void updateComputeNodeRules(InstancePort instPort,
284 Network osNet,
285 OpenstackNode gateway,
286 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900287
288 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
289 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
290 finalGws.addAll(ImmutableSet.copyOf(completedGws));
291
292 if (gateway == null) {
293 // these are floating IP related cases...
294 setComputeNodeToGatewayHelper(instPort, osNet,
295 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900296
Jian Li1064e4f2018-05-29 16:16:53 +0900297 } else {
298 // these are openstack node related cases...
299 if (install) {
300 if (completedGws.contains(gateway)) {
301 if (completedGws.size() > 1) {
302 finalGws.remove(gateway);
303 setComputeNodeToGatewayHelper(instPort, osNet,
304 ImmutableSet.copyOf(finalGws), false);
305 finalGws.add(gateway);
306 }
307
308 setComputeNodeToGatewayHelper(instPort, osNet,
309 ImmutableSet.copyOf(finalGws), true);
310 } else {
311 log.warn("Detected node should be included in completed gateway set");
312 }
313 } else {
314 if (!completedGws.contains(gateway)) {
315 finalGws.add(gateway);
316 setComputeNodeToGatewayHelper(instPort, osNet,
317 ImmutableSet.copyOf(finalGws), false);
318 finalGws.remove(gateway);
Jian Li4d138702018-11-27 17:25:28 +0900319 if (!completedGws.isEmpty()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900320 setComputeNodeToGatewayHelper(instPort, osNet,
321 ImmutableSet.copyOf(finalGws), true);
322 }
323 } else {
324 log.warn("Detected node should NOT be included in completed gateway set");
325 }
326 }
327 }
328 }
329
330 // a helper method
331 private void setComputeNodeToGatewayHelper(InstancePort instPort,
332 Network osNet,
333 Set<OpenstackNode> gateways,
334 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900335
336 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
337 .matchEthType(Ethernet.TYPE_IPV4)
338 .matchIPSrc(instPort.ipAddress().toIpPrefix())
339 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
340
Daniel Park3f26e792018-11-26 18:34:53 +0900341 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkeeb8e042018-02-21 14:06:58 +0900342
Jian Li5ecfd1a2018-12-10 11:41:03 +0900343 OpenstackNode selectedGatewayNode =
344 getGwByComputeDevId(gateways, instPort.deviceId());
Jian Li1064e4f2018-05-29 16:16:53 +0900345
daniel parkeeb8e042018-02-21 14:06:58 +0900346 if (selectedGatewayNode == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900347 log.warn(ERR_FLOW + "no gateway node selected");
Jian Lifb64d882018-11-27 10:57:40 +0900348 return;
daniel parkeeb8e042018-02-21 14:06:58 +0900349 }
Daniel Park3f26e792018-11-26 18:34:53 +0900350
Jian Li621f73c2018-12-15 01:49:22 +0900351 Type netType = osNetworkService.networkType(osNet.getId());
352
353 switch (netType) {
Daniel Park3f26e792018-11-26 18:34:53 +0900354 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900355 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900356 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900357 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
358 osNetworkService, osNodeService.node(instPort.deviceId()));
359
360 if (portNum == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900361 log.warn(ERR_FLOW + "no tunnel port");
362 return;
363 }
Jian Li2d68c192018-12-13 15:52:59 +0900364
Daniel Park3f26e792018-11-26 18:34:53 +0900365 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
Jian Li2d68c192018-12-13 15:52:59 +0900366
Daniel Park3f26e792018-11-26 18:34:53 +0900367 tBuilder.extension(buildExtension(
daniel parkeeb8e042018-02-21 14:06:58 +0900368 deviceService,
369 instPort.deviceId(),
370 selectedGatewayNode.dataIp().getIp4Address()),
371 instPort.deviceId())
Jian Li2d68c192018-12-13 15:52:59 +0900372 .setOutput(portNum);
Daniel Park3f26e792018-11-26 18:34:53 +0900373 break;
374 case VLAN:
375 if (osNodeService.node(instPort.deviceId()).vlanPortNum() == null) {
376 log.warn(ERR_FLOW + "no vlan port");
377 return;
378 }
379 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
380 tBuilder.setOutput(osNodeService.node(instPort.deviceId()).vlanPortNum());
381 break;
382 default:
383 log.warn(ERR_FLOW + "no supported network type");
384 }
daniel parkeeb8e042018-02-21 14:06:58 +0900385
386 osFlowRuleService.setRule(
387 appId,
388 instPort.deviceId(),
389 sBuilder.build(),
Daniel Park3f26e792018-11-26 18:34:53 +0900390 tBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900391 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
392 ROUTING_TABLE,
393 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900394 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900395 }
396
Jian Lide679782018-06-05 01:41:29 +0900397 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
398 Network osNet,
399 InstancePort instPort,
400 ExternalPeerRouter externalPeerRouter,
401 Set<OpenstackNode> gateways, boolean install) {
402 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900403 Type netType = osNetworkService.networkType(osNet.getId());
Jian Lide679782018-06-05 01:41:29 +0900404 if (cNode == null) {
405 final String error = String.format("Cannot find openstack node for device %s",
406 instPort.deviceId());
407 throw new IllegalStateException(error);
408 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900409 if (netType == VXLAN && cNode.dataIp() == null) {
Jian Lide679782018-06-05 01:41:29 +0900410 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
411 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
412 throw new IllegalStateException(error);
413 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900414 if (netType == GRE && cNode.dataIp() == null) {
Jian Li2d68c192018-12-13 15:52:59 +0900415 final String errorFormat = ERR_FLOW + "GRE mode is not ready for %s";
416 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
417 throw new IllegalStateException(error);
418 }
Jian Li621f73c2018-12-15 01:49:22 +0900419 if (netType == GENEVE && cNode.dataIp() == null) {
420 final String errorFormat = ERR_FLOW + "GENEVE mode is not ready for %s";
421 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
422 throw new IllegalStateException(error);
423 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900424 if (netType == VLAN && cNode.vlanIntf() == null) {
Jian Lide679782018-06-05 01:41:29 +0900425 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
426 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
427 throw new IllegalStateException(error);
428 }
429
430 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
431
432 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
433
434 if (selectedGatewayNode == null) {
435 final String errorFormat = ERR_FLOW + "no gateway node selected";
436 throw new IllegalStateException(errorFormat);
437 }
438
439 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
440 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900441 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900442 .matchIPDst(floating.toIpPrefix());
443
444 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
445 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
446 .setEthDst(instPort.macAddress())
447 .setIpDst(instPort.ipAddress().getIp4Address());
448
Jian Li5e2ad4a2018-07-16 13:40:53 +0900449 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
450 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900451 externalTreatmentBuilder.popVlan();
452 }
453
Jian Li621f73c2018-12-15 01:49:22 +0900454 switch (netType) {
Jian Lide679782018-06-05 01:41:29 +0900455 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900456 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900457 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900458 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
459 osNetworkService, selectedGatewayNode);
Jian Lide679782018-06-05 01:41:29 +0900460 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
461 .extension(buildExtension(
462 deviceService,
463 selectedGatewayNode.intgBridge(),
464 cNode.dataIp().getIp4Address()),
465 selectedGatewayNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900466 .setOutput(portNum);
Jian Lide679782018-06-05 01:41:29 +0900467 break;
468 case VLAN:
469 externalTreatmentBuilder.pushVlan()
470 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
471 .setOutput(selectedGatewayNode.vlanPortNum());
472 break;
473 default:
474 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
475 osNet.getNetworkType());
476 throw new IllegalStateException(error);
477 }
478
479 osFlowRuleService.setRule(
480 appId,
481 selectedGatewayNode.intgBridge(),
482 externalSelectorBuilder.build(),
483 externalTreatmentBuilder.build(),
484 PRIORITY_FLOATING_EXTERNAL,
485 GW_COMMON_TABLE,
486 install);
487 }
488
Hyunsun Moon44aac662017-02-18 02:07:01 +0900489 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
Jian Li32b03622018-11-06 17:54:24 +0900490 InstancePort instPort,
491 ExternalPeerRouter externalPeerRouter,
daniel park32b42202018-03-14 16:53:44 +0900492 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900493 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900494 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900495 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900496 .matchIPSrc(instPort.ipAddress().toIpPrefix());
497
Jian Li621f73c2018-12-15 01:49:22 +0900498 Type netType = osNetworkService.networkType(osNet.getId());
499
500 switch (netType) {
daniel parkee8700b2017-05-11 15:50:03 +0900501 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900502 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900503 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900504 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
505 break;
506 case VLAN:
507 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
508 break;
509 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800510 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900511 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900512 throw new IllegalStateException(error);
513 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900514
Daniel Park75e3d7f2018-05-29 14:43:53 +0900515 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900516
Hyunsun Moon0d457362017-06-27 17:19:41 +0900517 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900518 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
519 .setIpSrc(floating.getIp4Address())
520 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900521 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900522
SONA Project6bc5c4a2018-12-14 23:49:52 +0900523 if (netType == VLAN) {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900524 tBuilder.popVlan();
525 }
526
Jian Li5e2ad4a2018-07-16 13:40:53 +0900527 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
528 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900529 }
sanghodc375372017-06-08 10:41:30 +0900530 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900531 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900532 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900533 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900534 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900535 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900536 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900537 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900538 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900539 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900540 }
541
Jian Li99892e92018-04-13 14:59:39 +0900542 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900543 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
544
545 if (instPort == null) {
546 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
547 osFip.getFloatingIpAddress());
548 return;
Jian Li99892e92018-04-13 14:59:39 +0900549 }
Jian Li628a7cb2018-08-11 23:04:24 +0900550
Jian Li99892e92018-04-13 14:59:39 +0900551 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900552 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
Jian Lie6e609f2019-05-14 17:45:54 +0900553 setFloatingIpRules(osFip, instPort, null, null, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900554 processGratuitousArpPacket(osFip, instPort);
555
Jian Li99892e92018-04-13 14:59:39 +0900556 }
557 }
558
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900559 private void processGratuitousArpPacket(NetFloatingIP floatingIP,
560 InstancePort instancePort) {
561 Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
562
563 Network osNet = osNetworkService.network(instancePort.networkId());
564
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900565 OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
566 ExternalPeerRouter externalPeerRouter =
567 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
568 if (externalPeerRouter == null) {
Jian Lie6e609f2019-05-14 17:45:54 +0900569 log.error("Failed to process GARP packet for floating ip {}, because ",
Jian Li4d138702018-11-27 17:25:28 +0900570 NO_EXT_PEER_ROUTER_MSG);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900571 return;
572 }
573
Jian Li32b03622018-11-06 17:54:24 +0900574 processGarpPacketForFloatingIp(floatingIP, instancePort,
575 externalPeerRouter.vlanId(), selectedGw, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900576
577 }
578
Jian Li99892e92018-04-13 14:59:39 +0900579 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900580 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900581
Jian Li628a7cb2018-08-11 23:04:24 +0900582 if (instPort == null) {
583 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
584 osFip.getFloatingIpAddress());
585 return;
Jian Lie1a39032018-06-19 21:49:36 +0900586 }
587
Jian Li99892e92018-04-13 14:59:39 +0900588 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900589 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
Jian Lie6e609f2019-05-14 17:45:54 +0900590 setFloatingIpRules(osFip, instPort, null, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900591 }
592 }
593
Hyunsun Moon0d457362017-06-27 17:19:41 +0900594 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900595
596 @Override
597 public boolean isRelevant(OpenstackRouterEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900598 return event.floatingIp() != null;
599 }
600
Jian Li34220ea2018-11-14 01:30:24 +0900601 private boolean isRelevantHelper() {
602 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
603 }
604
Hyunsun Moon44aac662017-02-18 02:07:01 +0900605 @Override
606 public void event(OpenstackRouterEvent event) {
607 switch (event.type()) {
608 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900609 eventExecutor.execute(() -> processFloatingIpAssociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900610 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900611 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900612 eventExecutor.execute(() -> processFloatingIpDisassociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900613 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900614 case OPENSTACK_FLOATING_IP_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900615 eventExecutor.execute(() -> processFloatingIpCreation(event));
Hyunsun Moonb720e632017-05-16 15:41:36 +0900616 break;
Jian Lia171a432018-06-11 11:52:11 +0900617 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900618 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Lia171a432018-06-11 11:52:11 +0900619 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900620 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900621 default:
622 // do nothing for the other events
623 break;
624 }
625 }
Jian Li4d138702018-11-27 17:25:28 +0900626
627 private void processFloatingIpAssociation(OpenstackRouterEvent event) {
628 if (!isRelevantHelper()) {
629 return;
630 }
631
632 NetFloatingIP osFip = event.floatingIp();
633 if (instancePortService.instancePort(osFip.getPortId()) != null) {
634 associateFloatingIp(osFip);
635 log.info("Associated floating IP {}:{}",
636 osFip.getFloatingIpAddress(),
637 osFip.getFixedIpAddress());
638 }
639 }
640
641 private void processFloatingIpDisassociation(OpenstackRouterEvent event) {
642 if (!isRelevantHelper()) {
643 return;
644 }
645
646 NetFloatingIP osFip = event.floatingIp();
647 if (instancePortService.instancePort(event.portId()) != null) {
648 disassociateFloatingIp(osFip, event.portId());
649 log.info("Disassociated floating IP {}:{}",
650 osFip.getFloatingIpAddress(),
651 osFip.getFixedIpAddress());
652 }
653 }
654
655 private void processFloatingIpCreation(OpenstackRouterEvent event) {
656 if (!isRelevantHelper()) {
657 return;
658 }
659
660 NetFloatingIP osFip = event.floatingIp();
661 String portId = osFip.getPortId();
662 if (!Strings.isNullOrEmpty(portId) &&
663 instancePortService.instancePort(portId) != null) {
664 associateFloatingIp(event.floatingIp());
665 }
666 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
667 }
668
669 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
670 if (!isRelevantHelper()) {
671 return;
672 }
673
674 NetFloatingIP osFip = event.floatingIp();
675 String portId = osFip.getPortId();
676 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
677 // in case the floating IP is not associated with any port due to
678 // port removal, we simply do not execute floating IP disassociation
679 if (osNetworkService.port(portId) != null &&
680 instancePortService.instancePort(portId) != null) {
681 disassociateFloatingIp(osFip, portId);
682 }
683
684 // since we skip floating IP disassociation, we need to
685 // manually unsubscribe the port pre-remove event
686 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
687 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
688 this.getClass().getName());
689 log.info("Unsubscribed the port {} on listening pre-remove event",
690 osFip.getPortId());
691 }
692 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
693 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900694 }
695
696 private class InternalNodeListener implements OpenstackNodeListener {
697
698 @Override
699 public boolean isRelevant(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900700 return event.subject().type() == GATEWAY;
701 }
702
Jian Li34220ea2018-11-14 01:30:24 +0900703 private boolean isRelevantHelper() {
704 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
705 }
706
Hyunsun Moon44aac662017-02-18 02:07:01 +0900707 @Override
708 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900709
710 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900711 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900712 eventExecutor.execute(() -> processNodeCompletion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900713 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900714 case OPENSTACK_NODE_INCOMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900715 eventExecutor.execute(() -> processNodeIncompletion(event));
Jian Li1064e4f2018-05-29 16:16:53 +0900716 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900717 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900718 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900719 break;
720 }
721 }
Jian Li4d138702018-11-27 17:25:28 +0900722
723 private void processNodeCompletion(OpenstackNodeEvent event) {
724 if (!isRelevantHelper()) {
725 return;
726 }
727
728 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
729
730 if (Strings.isNullOrEmpty(fip.getPortId())) {
731 continue;
732 }
733
734 Port osPort = osNetworkService.port(fip.getPortId());
735 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
736
737 // we check both Openstack Port and Instance Port
738 if (osPort == null || instPort == null) {
739 continue;
740 }
741
Jian Lie6e609f2019-05-14 17:45:54 +0900742 setFloatingIpRules(fip, instPort, event.subject(), null, true);
Jian Li4d138702018-11-27 17:25:28 +0900743 }
744 }
745
746 private void processNodeIncompletion(OpenstackNodeEvent event) {
747 if (!isRelevantHelper()) {
748 return;
749 }
750
751 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
752 if (Strings.isNullOrEmpty(fip.getPortId())) {
753 continue;
754 }
755 Port osPort = osNetworkService.port(fip.getPortId());
756 if (osPort == null) {
757 log.warn("Failed to set floating IP {}", fip.getId());
758 continue;
759 }
760 Network osNet = osNetworkService.network(osPort.getNetworkId());
761 if (osNet == null) {
762 final String errorFormat = ERR_FLOW + "no network(%s) exists";
763 final String error = String.format(errorFormat,
764 fip.getFloatingIpAddress(),
765 osPort.getNetworkId());
766 throw new IllegalStateException(error);
767 }
768 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
769 log.trace("Mac address of openstack port: {}", srcMac);
770 InstancePort instPort = instancePortService.instancePort(srcMac);
771
772 if (instPort == null) {
773 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
774 final String error = String.format(errorFormat,
775 fip.getFloatingIpAddress(), srcMac);
776 throw new IllegalStateException(error);
777 }
778
779 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
780 osNetworkService, osRouterAdminService);
781 if (externalPeerRouter == null) {
782 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
783 throw new IllegalStateException(errorFormat);
784 }
785
786 updateComputeNodeRules(instPort, osNet, event.subject(), false);
787 updateGatewayNodeRules(fip, instPort, osNet,
788 externalPeerRouter, event.subject(), false);
789 }
790 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900791 }
Jian Li99892e92018-04-13 14:59:39 +0900792
Jian Li24ec59f2018-05-23 19:01:25 +0900793 private class InternalInstancePortListener implements InstancePortListener {
794
Jian Li34220ea2018-11-14 01:30:24 +0900795 private boolean isRelevantHelper(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900796
Jian Lie1a39032018-06-19 21:49:36 +0900797 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
798 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
799 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
800 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
801
802 // we check the possible NPE to avoid duplicated null check
803 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
804 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
805 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
806 return false;
807 }
808 }
809
Jian Li34220ea2018-11-14 01:30:24 +0900810 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li24ec59f2018-05-23 19:01:25 +0900811 }
812
813 @Override
814 public void event(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900815 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900816 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900817 eventExecutor.execute(() -> processInstancePortDetection(event));
Jian Lie1a39032018-06-19 21:49:36 +0900818 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900819 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900820 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900821 break;
822 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900823 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900824 break;
825 default:
826 break;
827 }
828 }
Jian Li4d138702018-11-27 17:25:28 +0900829
830 private void processInstancePortDetection(InstancePortEvent event) {
831 if (!isRelevantHelper(event)) {
832 return;
833 }
834
835 InstancePort instPort = event.subject();
836
837 if (instPort != null && instPort.portId() != null) {
838 osRouterAdminService.floatingIps().stream()
839 .filter(f -> f.getPortId() != null)
840 .filter(f -> f.getPortId().equals(instPort.portId()))
841 .forEach(f -> setFloatingIpRules(f,
Jian Lie6e609f2019-05-14 17:45:54 +0900842 instPort, null, null, true));
Jian Li4d138702018-11-27 17:25:28 +0900843 }
844 }
845
846 private void processInstanceMigrationStart(InstancePortEvent event) {
847 if (!isRelevantHelper(event)) {
848 return;
849 }
850
851 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
852 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
853 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
854
855 if (fip == null) {
856 return;
857 }
858
859 Port osPort = osNetworkService.port(fip.getPortId());
860 Network osNet = osNetworkService.network(osPort.getNetworkId());
861 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
862 osNetworkService, osRouterAdminService);
863
864 if (externalPeerRouter == null) {
865 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
866 throw new IllegalStateException(errorFormat);
867 }
868
869 // since DownstreamExternal rules should only be placed in
870 // corresponding gateway node, we need to install new rule to
871 // the corresponding gateway node
872 setDownstreamExternalRulesHelper(fip, osNet,
873 event.subject(), externalPeerRouter, gateways, true);
874
875 // since ComputeNodeToGateway rules should only be placed in
876 // corresponding compute node, we need to install new rule to
877 // the target compute node, and remove rules from original node
878 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
879 }
880
881 private void processInstanceMigrationEnd(InstancePortEvent event) {
882 if (!isRelevantHelper(event)) {
883 return;
884 }
885
886 InstancePort oldInstPort = swapStaleLocation(event.subject());
887
888 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
889 NetFloatingIP fip = associatedFloatingIp(oldInstPort, ips);
890
891 if (fip == null) {
892 return;
893 }
894
895 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
896 Port osPort = osNetworkService.port(fip.getPortId());
897 Network osNet = osNetworkService.network(osPort.getNetworkId());
898 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
899 osNetworkService, osRouterAdminService);
900
901 if (externalPeerRouter == null) {
902 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
903 throw new IllegalStateException(errorFormat);
904 }
905
906 // We need to remove the old ComputeNodeToGateway rules from
907 // original compute node
908 setComputeNodeToGatewayHelper(oldInstPort, osNet, gateways, false);
909
910 // If we only have one gateway, we simply do not remove any
911 // flow rules from either gateway or compute node
912 if (gateways.size() == 1) {
913 return;
914 }
915
916 // Checks whether the destination compute node's device id
917 // has identical gateway hash or not
918 // if it is true, we simply do not remove the rules, as
919 // it has been overwritten at port detention event
920 // if it is false, we will remove the rules
921 DeviceId newDeviceId = event.subject().deviceId();
922 DeviceId oldDeviceId = oldInstPort.deviceId();
923
924 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
925 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
926
927 if (oldGateway != null && oldGateway.equals(newGateway)) {
928 return;
929 }
930
931 // Since DownstreamExternal rules should only be placed in
932 // corresponding gateway node, we need to remove old rule from
933 // the corresponding gateway node
934 setDownstreamExternalRulesHelper(fip, osNet, oldInstPort,
935 externalPeerRouter, gateways, false);
936 }
Jian Li24ec59f2018-05-23 19:01:25 +0900937 }
Jian Lie1a39032018-06-19 21:49:36 +0900938
939 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
940
Jian Li34220ea2018-11-14 01:30:24 +0900941 private boolean isRelevantHelper() {
942 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lie1a39032018-06-19 21:49:36 +0900943 }
944
945 @Override
946 public void event(OpenstackNetworkEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900947
Jian Lie6e609f2019-05-14 17:45:54 +0900948 switch (event.type()) {
949 case OPENSTACK_PORT_PRE_REMOVE:
950 eventExecutor.execute(() -> processPortPreRemoval(event));
951 break;
952 case EXTERNAL_PEER_ROUTER_MAC_UPDATED:
953 eventExecutor.execute(() -> processExternalPeerRouterMacUpdate(event));
954 break;
955 default:
956 break;
Jian Lie1a39032018-06-19 21:49:36 +0900957 }
958 }
959
Jian Lie6e609f2019-05-14 17:45:54 +0900960 private void processExternalPeerRouterMacUpdate(OpenstackNetworkEvent event) {
961 if (!isRelevantHelper()) {
962 return;
963 }
964
965 instancePortService.instancePorts().forEach(instPort ->
966 osRouterAdminService.floatingIps().stream()
967 .filter(f -> f.getPortId() != null)
968 .filter(f -> f.getPortId().equals(instPort.portId()))
969 .forEach(f -> setFloatingIpRules(f,
970 instPort, null, event.peerRouter(), true)));
971 }
972
Jian Li4d138702018-11-27 17:25:28 +0900973 private void processPortPreRemoval(OpenstackNetworkEvent event) {
Jian Lie6e609f2019-05-14 17:45:54 +0900974 if (!isRelevantHelper()) {
975 return;
976 }
977
Jian Li32b03622018-11-06 17:54:24 +0900978 InstancePort instPort = instancePortService.instancePort(
979 event.port().getId());
980 if (instPort == null) {
981 return;
982 }
983 NetFloatingIP fip = associatedFloatingIp(instPort,
984 osRouterAdminService.floatingIps());
985
986 if (fip != null) {
987 instancePortService.updateInstancePort(
988 instPort.updateState(REMOVE_PENDING));
989 updateFipStore(event.port().getId());
990 } else {
991 instancePortService.removeInstancePort(instPort.portId());
992 }
993 }
994
Jian Li2360acb2018-10-17 00:46:31 +0900995 private void updateFipStore(String portId) {
Jian Lie1a39032018-06-19 21:49:36 +0900996
Jian Li2360acb2018-10-17 00:46:31 +0900997 if (portId == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900998 return;
999 }
1000
1001 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
1002 for (NetFloatingIP fip : ips) {
1003 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
1004 continue;
1005 }
1006 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
1007 continue;
1008 }
Jian Li2360acb2018-10-17 00:46:31 +09001009 if (fip.getPortId().equals(portId)) {
Jian Lie1a39032018-06-19 21:49:36 +09001010 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
1011 // invalidate bound fixed IP and port
1012 neutronFip.setFixedIpAddress(null);
1013 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +09001014
1015 // Following update will in turn trigger
1016 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
1017 osRouterAdminService.updateFloatingIp(neutronFip);
1018 log.info("Updated floating IP {}, due to host removal",
1019 neutronFip.getFloatingIpAddress());
1020 }
1021 }
1022 }
1023 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001024}