blob: 6e9d71b5b3edc45d100fef1e2c7641d5533124ff [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;
Jian Li4d1b1f32020-05-11 23:02:38 +090021import org.onlab.packet.ARP;
22import org.onlab.packet.EthType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090023import org.onlab.packet.Ethernet;
Jian Li4d1b1f32020-05-11 23:02:38 +090024import org.onlab.packet.Ip4Address;
Hyunsun Moon44aac662017-02-18 02:07:01 +090025import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090027import org.onlab.packet.VlanId;
Jian Li4d1b1f32020-05-11 23:02:38 +090028import org.onosproject.cfg.ComponentConfigService;
29import org.onosproject.cfg.ConfigProperty;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onosproject.cluster.ClusterService;
31import org.onosproject.cluster.LeadershipService;
32import org.onosproject.cluster.NodeId;
33import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
Jian Li4d1b1f32020-05-11 23:02:38 +090035import org.onosproject.net.Device;
Jian Li24ec59f2018-05-23 19:01:25 +090036import org.onosproject.net.DeviceId;
Jian Li2d68c192018-12-13 15:52:59 +090037import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.net.device.DeviceService;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090043import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090045import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090046import org.onosproject.openstacknetworking.api.InstancePort;
Jian Liec5c32b2018-07-13 14:28:58 +090047import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090048import org.onosproject.openstacknetworking.api.InstancePortEvent;
49import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090050import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090051import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Lie1a39032018-06-19 21:49:36 +090052import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
53import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
sanghodc375372017-06-08 10:41:30 +090054import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lif3a28b02018-06-11 21:29:13 +090055import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
57import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li8f64feb2018-07-24 13:20:16 +090058import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090059import org.onosproject.openstacknode.api.OpenstackNode;
60import org.onosproject.openstacknode.api.OpenstackNodeEvent;
61import org.onosproject.openstacknode.api.OpenstackNodeListener;
62import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063import org.openstack4j.model.network.NetFloatingIP;
64import org.openstack4j.model.network.Network;
65import org.openstack4j.model.network.Port;
Jian Lif3a28b02018-06-11 21:29:13 +090066import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
Jian Li34220ea2018-11-14 01:30:24 +090067import org.osgi.service.component.annotations.Activate;
68import org.osgi.service.component.annotations.Component;
69import org.osgi.service.component.annotations.Deactivate;
70import org.osgi.service.component.annotations.Reference;
71import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072import org.slf4j.Logger;
73import org.slf4j.LoggerFactory;
74
75import java.util.Objects;
Jian Li99892e92018-04-13 14:59:39 +090076import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090077import java.util.concurrent.ExecutorService;
78
79import static java.util.concurrent.Executors.newSingleThreadExecutor;
80import static org.onlab.util.Tools.groupedThreads;
Jian Li4d1b1f32020-05-11 23:02:38 +090081import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
sanghodc375372017-06-08 10:41:30 +090082import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
83import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li4d1b1f32020-05-11 23:02:38 +090084import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
daniel parkeeb8e042018-02-21 14:06:58 +090085import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090086import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090087import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8a5fb642018-09-14 15:50:04 +090088import static org.onosproject.openstacknetworking.api.InstancePort.State.REMOVE_PENDING;
Jian Lie1a39032018-06-19 21:49:36 +090089import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_ENDED;
90import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
Jian Lie6e609f2019-05-14 17:45:54 +090091import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090092import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
93import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
94import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Jian Li8f64feb2018-07-24 13:20:16 +090095import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li4d1b1f32020-05-11 23:02:38 +090096import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
Jian Li24ec59f2018-05-23 19:01:25 +090097import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090098import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
Jian Li1064e4f2018-05-29 16:16:53 +090099import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li4d1b1f32020-05-11 23:02:38 +0900101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li24ec59f2018-05-23 19:01:25 +0900102import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Li32b03622018-11-06 17:54:24 +0900103import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +0900104import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +0900105import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Li26949762018-03-30 15:46:37 +0900106import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Jian Li4d1b1f32020-05-11 23:02:38 +0900107import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
108import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
109import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900110import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111
112/**
113 * Handles OpenStack floating IP events.
114 */
115@Component(immediate = true)
116public class OpenstackRoutingFloatingIpHandler {
117
118 private final Logger log = LoggerFactory.getLogger(getClass());
119
120 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800121 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122
Jian Li4d138702018-11-27 17:25:28 +0900123 private static final String NO_EXT_PEER_ROUTER_MSG = "no external peer router found";
124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126 protected CoreService coreService;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129 protected DeviceService deviceService;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 protected LeadershipService leadershipService;
133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135 protected ClusterService clusterService;
136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138 protected OpenstackNodeService osNodeService;
139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liec5c32b2018-07-13 14:28:58 +0900141 protected InstancePortAdminService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900144 protected OpenstackRouterAdminService osRouterAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147 protected OpenstackNetworkService osNetworkService;
148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900150 protected OpenstackFlowRuleService osFlowRuleService;
151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li8f64feb2018-07-24 13:20:16 +0900153 protected PreCommitPortService preCommitPortService;
154
Ray Milkeyd5425682018-10-23 10:21:33 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900156 protected PacketService packetService;
157
Jian Li4d1b1f32020-05-11 23:02:38 +0900158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
159 protected ComponentConfigService configService;
160
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161 private final ExecutorService eventExecutor = newSingleThreadExecutor(
162 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900163 private final OpenstackRouterListener
164 floatingIpListener = new InternalFloatingIpListener();
165 private final InstancePortListener
166 instancePortListener = new InternalInstancePortListener();
167 private final OpenstackNodeListener
168 osNodeListener = new InternalNodeListener();
169 private final OpenstackNetworkListener
170 osNetworkListener = new InternalOpenstackNetworkListener();
171 private final InstancePortListener
172 instPortListener = new InternalInstancePortListener();
Jian Lie1a39032018-06-19 21:49:36 +0900173
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174 private ApplicationId appId;
175 private NodeId localNodeId;
176
177 @Activate
178 protected void activate() {
179 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
180 localNodeId = clusterService.getLocalNode().id();
181 leadershipService.runForLeadership(appId.name());
Jian Li24ec59f2018-05-23 19:01:25 +0900182 osRouterAdminService.addListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900183 osNodeService.addListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900184 instancePortService.addListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900185 osNodeService.addListener(osNodeListener);
186 osNetworkService.addListener(osNetworkListener);
187 instancePortService.addListener(instPortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188
189 log.info("Started");
190 }
191
192 @Deactivate
193 protected void deactivate() {
Jian Li24ec59f2018-05-23 19:01:25 +0900194 instancePortService.removeListener(instancePortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900195 instancePortService.removeListener(instPortListener);
196 osNetworkService.removeListener(osNetworkListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900197 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900198 osRouterAdminService.removeListener(floatingIpListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900199 leadershipService.withdraw(appId.name());
200 eventExecutor.shutdown();
201
202 log.info("Stopped");
203 }
204
Jian Li4d1b1f32020-05-11 23:02:38 +0900205 private String getArpMode() {
206 Set<ConfigProperty> properties =
207 configService.getProperties(OpenstackRoutingArpHandler.class.getName());
208 return getPropertyValue(properties, ARP_MODE);
209 }
210
Jian Lie6e609f2019-05-14 17:45:54 +0900211 private void setFloatingIpRules(NetFloatingIP floatingIp,
212 InstancePort instPort,
213 OpenstackNode gateway,
214 ExternalPeerRouter peerRouter,
215 boolean install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900216
217 if (instPort == null) {
218 log.debug("No instance port found");
219 return;
220 }
221
222 Network osNet = osNetworkService.network(instPort.networkId());
Jian Li8f64feb2018-07-24 13:20:16 +0900223
Jian Lie6e609f2019-05-14 17:45:54 +0900224 ExternalPeerRouter externalPeerRouter = peerRouter != null ? peerRouter :
225 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
226
daniel park32b42202018-03-14 16:53:44 +0900227 if (externalPeerRouter == null) {
Jian Lie6e609f2019-05-14 17:45:54 +0900228 log.warn("External peer router is not ready for now, " +
229 "floating IP rules will be installed/uninstalled " +
230 "when external peer router is available...");
231 return;
daniel park32b42202018-03-14 16:53:44 +0900232 }
233
Jian Li8f64feb2018-07-24 13:20:16 +0900234 if (install) {
Jian Li628a7cb2018-08-11 23:04:24 +0900235 preCommitPortService.subscribePreCommit(instPort.portId(),
Jian Li8f64feb2018-07-24 13:20:16 +0900236 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li628a7cb2018-08-11 23:04:24 +0900237 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900238 } else {
Jian Li628a7cb2018-08-11 23:04:24 +0900239 preCommitPortService.unsubscribePreCommit(instPort.portId(),
240 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
241 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
Jian Li8f64feb2018-07-24 13:20:16 +0900242 }
243
Jian Lide679782018-06-05 01:41:29 +0900244 updateComputeNodeRules(instPort, osNet, gateway, install);
245 updateGatewayNodeRules(floatingIp, instPort, osNet, externalPeerRouter, gateway, install);
246
Jian Lide679782018-06-05 01:41:29 +0900247 // TODO: need to refactor setUpstreamRules if possible
daniel park32b42202018-03-14 16:53:44 +0900248 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
Jian Li8f64feb2018-07-24 13:20:16 +0900249
daniel parkc2a2ed62018-04-10 15:17:42 +0900250 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
251 floatingIp.getFloatingIpAddress(),
252 floatingIp.getFixedIpAddress(),
253 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900254 }
255
Jian Lide679782018-06-05 01:41:29 +0900256 private synchronized void updateGatewayNodeRules(NetFloatingIP fip,
257 InstancePort instPort,
258 Network osNet,
259 ExternalPeerRouter router,
260 OpenstackNode gateway,
261 boolean install) {
262
263 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
264 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
265 finalGws.addAll(ImmutableSet.copyOf(completedGws));
266
Jian Lia171a432018-06-11 11:52:11 +0900267
268 if (gateway == null) {
269 // these are floating IP related cases...
270 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
271 ImmutableSet.copyOf(finalGws), install);
272
Jian Lide679782018-06-05 01:41:29 +0900273 } else {
Jian Lia171a432018-06-11 11:52:11 +0900274 // these are openstack node related cases...
275 if (install) {
276 if (completedGws.contains(gateway)) {
277 if (completedGws.size() > 1) {
278 finalGws.remove(gateway);
279 if (fip.getPortId() != null) {
280 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
281 ImmutableSet.copyOf(finalGws), false);
282 finalGws.add(gateway);
283 }
284 }
Jian Lide679782018-06-05 01:41:29 +0900285 if (fip.getPortId() != null) {
286 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
287 ImmutableSet.copyOf(finalGws), true);
288 }
Jian Lia171a432018-06-11 11:52:11 +0900289 } else {
290 log.warn("Detected node should be included in completed gateway set");
Jian Lide679782018-06-05 01:41:29 +0900291 }
292 } else {
Jian Lia171a432018-06-11 11:52:11 +0900293 if (!completedGws.contains(gateway)) {
Jian Li4d138702018-11-27 17:25:28 +0900294 if (!completedGws.isEmpty() && fip.getPortId() != null) {
295 setDownstreamExternalRulesHelper(fip, osNet, instPort, router,
Jian Lia171a432018-06-11 11:52:11 +0900296 ImmutableSet.copyOf(finalGws), true);
Jian Lia171a432018-06-11 11:52:11 +0900297 }
298 } else {
299 log.warn("Detected node should NOT be included in completed gateway set");
300 }
Jian Lide679782018-06-05 01:41:29 +0900301 }
302 }
303 }
304
305 private synchronized void updateComputeNodeRules(InstancePort instPort,
306 Network osNet,
307 OpenstackNode gateway,
308 boolean install) {
Jian Li1064e4f2018-05-29 16:16:53 +0900309
310 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
311 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
312 finalGws.addAll(ImmutableSet.copyOf(completedGws));
313
314 if (gateway == null) {
315 // these are floating IP related cases...
316 setComputeNodeToGatewayHelper(instPort, osNet,
317 ImmutableSet.copyOf(finalGws), install);
Jian Lide679782018-06-05 01:41:29 +0900318
Jian Li1064e4f2018-05-29 16:16:53 +0900319 } else {
320 // these are openstack node related cases...
321 if (install) {
322 if (completedGws.contains(gateway)) {
323 if (completedGws.size() > 1) {
324 finalGws.remove(gateway);
325 setComputeNodeToGatewayHelper(instPort, osNet,
326 ImmutableSet.copyOf(finalGws), false);
327 finalGws.add(gateway);
328 }
329
330 setComputeNodeToGatewayHelper(instPort, osNet,
331 ImmutableSet.copyOf(finalGws), true);
332 } else {
333 log.warn("Detected node should be included in completed gateway set");
334 }
335 } else {
336 if (!completedGws.contains(gateway)) {
337 finalGws.add(gateway);
338 setComputeNodeToGatewayHelper(instPort, osNet,
339 ImmutableSet.copyOf(finalGws), false);
340 finalGws.remove(gateway);
Jian Li4d138702018-11-27 17:25:28 +0900341 if (!completedGws.isEmpty()) {
Jian Li1064e4f2018-05-29 16:16:53 +0900342 setComputeNodeToGatewayHelper(instPort, osNet,
343 ImmutableSet.copyOf(finalGws), true);
344 }
345 } else {
346 log.warn("Detected node should NOT be included in completed gateway set");
347 }
348 }
349 }
350 }
351
352 // a helper method
353 private void setComputeNodeToGatewayHelper(InstancePort instPort,
354 Network osNet,
355 Set<OpenstackNode> gateways,
356 boolean install) {
daniel parkeeb8e042018-02-21 14:06:58 +0900357
358 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
359 .matchEthType(Ethernet.TYPE_IPV4)
360 .matchIPSrc(instPort.ipAddress().toIpPrefix())
361 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
362
Daniel Park3f26e792018-11-26 18:34:53 +0900363 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkeeb8e042018-02-21 14:06:58 +0900364
Jian Li5ecfd1a2018-12-10 11:41:03 +0900365 OpenstackNode selectedGatewayNode =
366 getGwByComputeDevId(gateways, instPort.deviceId());
Jian Li1064e4f2018-05-29 16:16:53 +0900367
daniel parkeeb8e042018-02-21 14:06:58 +0900368 if (selectedGatewayNode == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900369 log.warn(ERR_FLOW + "no gateway node selected");
Jian Lifb64d882018-11-27 10:57:40 +0900370 return;
daniel parkeeb8e042018-02-21 14:06:58 +0900371 }
Daniel Park3f26e792018-11-26 18:34:53 +0900372
Jian Li621f73c2018-12-15 01:49:22 +0900373 Type netType = osNetworkService.networkType(osNet.getId());
374
375 switch (netType) {
Daniel Park3f26e792018-11-26 18:34:53 +0900376 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900377 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900378 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900379 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
380 osNetworkService, osNodeService.node(instPort.deviceId()));
381
382 if (portNum == null) {
Daniel Park3f26e792018-11-26 18:34:53 +0900383 log.warn(ERR_FLOW + "no tunnel port");
384 return;
385 }
Jian Li2d68c192018-12-13 15:52:59 +0900386
Daniel Park3f26e792018-11-26 18:34:53 +0900387 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
Jian Li2d68c192018-12-13 15:52:59 +0900388
Daniel Park3f26e792018-11-26 18:34:53 +0900389 tBuilder.extension(buildExtension(
daniel parkeeb8e042018-02-21 14:06:58 +0900390 deviceService,
391 instPort.deviceId(),
392 selectedGatewayNode.dataIp().getIp4Address()),
393 instPort.deviceId())
Jian Li2d68c192018-12-13 15:52:59 +0900394 .setOutput(portNum);
Daniel Park3f26e792018-11-26 18:34:53 +0900395 break;
396 case VLAN:
397 if (osNodeService.node(instPort.deviceId()).vlanPortNum() == null) {
398 log.warn(ERR_FLOW + "no vlan port");
399 return;
400 }
401 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
402 tBuilder.setOutput(osNodeService.node(instPort.deviceId()).vlanPortNum());
403 break;
404 default:
405 log.warn(ERR_FLOW + "no supported network type");
406 }
daniel parkeeb8e042018-02-21 14:06:58 +0900407
408 osFlowRuleService.setRule(
409 appId,
410 instPort.deviceId(),
411 sBuilder.build(),
Daniel Park3f26e792018-11-26 18:34:53 +0900412 tBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900413 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
414 ROUTING_TABLE,
415 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900416 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900417 }
418
Jian Lide679782018-06-05 01:41:29 +0900419 private void setDownstreamExternalRulesHelper(NetFloatingIP floatingIp,
420 Network osNet,
421 InstancePort instPort,
422 ExternalPeerRouter externalPeerRouter,
423 Set<OpenstackNode> gateways, boolean install) {
424 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900425 Type netType = osNetworkService.networkType(osNet.getId());
Jian Lide679782018-06-05 01:41:29 +0900426 if (cNode == null) {
427 final String error = String.format("Cannot find openstack node for device %s",
428 instPort.deviceId());
429 throw new IllegalStateException(error);
430 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900431 if (netType == VXLAN && cNode.dataIp() == null) {
Jian Lide679782018-06-05 01:41:29 +0900432 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
433 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
434 throw new IllegalStateException(error);
435 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900436 if (netType == GRE && cNode.dataIp() == null) {
Jian Li2d68c192018-12-13 15:52:59 +0900437 final String errorFormat = ERR_FLOW + "GRE mode is not ready for %s";
438 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
439 throw new IllegalStateException(error);
440 }
Jian Li621f73c2018-12-15 01:49:22 +0900441 if (netType == GENEVE && cNode.dataIp() == null) {
442 final String errorFormat = ERR_FLOW + "GENEVE mode is not ready for %s";
443 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
444 throw new IllegalStateException(error);
445 }
SONA Project6bc5c4a2018-12-14 23:49:52 +0900446 if (netType == VLAN && cNode.vlanIntf() == null) {
Jian Lide679782018-06-05 01:41:29 +0900447 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
448 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
449 throw new IllegalStateException(error);
450 }
451
452 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
453
454 OpenstackNode selectedGatewayNode = getGwByComputeDevId(gateways, instPort.deviceId());
455
456 if (selectedGatewayNode == null) {
457 final String errorFormat = ERR_FLOW + "no gateway node selected";
458 throw new IllegalStateException(errorFormat);
459 }
460
461 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
462 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Park319b9ab2018-09-14 11:27:04 +0900463 .matchInPort(selectedGatewayNode.uplinkPortNum())
Jian Lide679782018-06-05 01:41:29 +0900464 .matchIPDst(floating.toIpPrefix());
465
466 TrafficTreatment.Builder externalTreatmentBuilder = DefaultTrafficTreatment.builder()
467 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
468 .setEthDst(instPort.macAddress())
469 .setIpDst(instPort.ipAddress().getIp4Address());
470
Jian Li5e2ad4a2018-07-16 13:40:53 +0900471 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
472 externalSelectorBuilder.matchVlanId(externalPeerRouter.vlanId()).build();
Jian Lide679782018-06-05 01:41:29 +0900473 externalTreatmentBuilder.popVlan();
474 }
475
Jian Li621f73c2018-12-15 01:49:22 +0900476 switch (netType) {
Jian Lide679782018-06-05 01:41:29 +0900477 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900478 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900479 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900480 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
481 osNetworkService, selectedGatewayNode);
Jian Lide679782018-06-05 01:41:29 +0900482 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
483 .extension(buildExtension(
484 deviceService,
485 selectedGatewayNode.intgBridge(),
486 cNode.dataIp().getIp4Address()),
487 selectedGatewayNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900488 .setOutput(portNum);
Jian Lide679782018-06-05 01:41:29 +0900489 break;
490 case VLAN:
491 externalTreatmentBuilder.pushVlan()
492 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
493 .setOutput(selectedGatewayNode.vlanPortNum());
494 break;
495 default:
496 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
497 osNet.getNetworkType());
498 throw new IllegalStateException(error);
499 }
500
501 osFlowRuleService.setRule(
502 appId,
503 selectedGatewayNode.intgBridge(),
504 externalSelectorBuilder.build(),
505 externalTreatmentBuilder.build(),
506 PRIORITY_FLOATING_EXTERNAL,
507 GW_COMMON_TABLE,
508 install);
Jian Li4d1b1f32020-05-11 23:02:38 +0900509
Jian Li0bc40a32020-12-21 20:16:18 +0900510 setArpRule(floatingIp, instPort.macAddress(), selectedGatewayNode, install);
Jian Li4d1b1f32020-05-11 23:02:38 +0900511 }
512
513 private void setArpRule(NetFloatingIP floatingIp, MacAddress targetMac,
514 OpenstackNode gateway, boolean install) {
Jian Li0bc40a32020-12-21 20:16:18 +0900515 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li4d1b1f32020-05-11 23:02:38 +0900516 TrafficSelector selector = DefaultTrafficSelector.builder()
517 .matchInPort(gateway.uplinkPortNum())
518 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
519 .matchArpOp(ARP.OP_REQUEST)
520 .matchArpTpa(Ip4Address.valueOf(floatingIp.getFloatingIpAddress()))
521 .build();
522
523 Device device = deviceService.getDevice(gateway.intgBridge());
524
525 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
526 .extension(buildMoveEthSrcToDstExtension(device), device.id())
527 .extension(buildMoveArpShaToThaExtension(device), device.id())
528 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
529 .setArpOp(ARP.OP_REPLY)
530 .setEthSrc(targetMac)
531 .setArpSha(targetMac)
532 .setArpSpa(Ip4Address.valueOf(floatingIp.getFloatingIpAddress()))
533 .setOutput(PortNumber.IN_PORT)
534 .build();
535
536 osFlowRuleService.setRule(
537 appId,
538 gateway.intgBridge(),
539 selector,
540 treatment,
541 PRIORITY_ARP_GATEWAY_RULE,
542 GW_COMMON_TABLE,
543 install
544 );
545
546 if (install) {
547 log.info("Install ARP Rule for Floating IP {}",
548 floatingIp.getFloatingIpAddress());
549 } else {
550 log.info("Uninstall ARP Rule for Floating IP {}",
551 floatingIp.getFloatingIpAddress());
552 }
553 }
Jian Lide679782018-06-05 01:41:29 +0900554 }
555
Hyunsun Moon44aac662017-02-18 02:07:01 +0900556 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
Jian Li32b03622018-11-06 17:54:24 +0900557 InstancePort instPort,
558 ExternalPeerRouter externalPeerRouter,
daniel park32b42202018-03-14 16:53:44 +0900559 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900560 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900561 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900562 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900563 .matchIPSrc(instPort.ipAddress().toIpPrefix());
564
Jian Li621f73c2018-12-15 01:49:22 +0900565 Type netType = osNetworkService.networkType(osNet.getId());
566
567 switch (netType) {
daniel parkee8700b2017-05-11 15:50:03 +0900568 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900569 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900570 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900571 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
572 break;
573 case VLAN:
574 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
575 break;
576 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800577 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900578 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900579 throw new IllegalStateException(error);
580 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900581
Daniel Park75e3d7f2018-05-29 14:43:53 +0900582 TrafficSelector selector = sBuilder.build();
daniel parkeeb8e042018-02-21 14:06:58 +0900583
Hyunsun Moon0d457362017-06-27 17:19:41 +0900584 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900585 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
586 .setIpSrc(floating.getIp4Address())
587 .setEthSrc(instPort.macAddress())
Jian Li5e2ad4a2018-07-16 13:40:53 +0900588 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900589
SONA Project6bc5c4a2018-12-14 23:49:52 +0900590 if (netType == VLAN) {
Daniel Park75e3d7f2018-05-29 14:43:53 +0900591 tBuilder.popVlan();
592 }
593
Jian Li5e2ad4a2018-07-16 13:40:53 +0900594 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
595 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
Daniel Park75e3d7f2018-05-29 14:43:53 +0900596 }
sanghodc375372017-06-08 10:41:30 +0900597 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900598 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900599 gNode.intgBridge(),
Daniel Park75e3d7f2018-05-29 14:43:53 +0900600 selector,
daniel parkeeb8e042018-02-21 14:06:58 +0900601 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900602 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900603 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900604 install);
Daniel Park75e3d7f2018-05-29 14:43:53 +0900605 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900606 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900607 }
608
Jian Li99892e92018-04-13 14:59:39 +0900609 private void associateFloatingIp(NetFloatingIP osFip) {
Jian Li628a7cb2018-08-11 23:04:24 +0900610 InstancePort instPort = instancePortService.instancePort(osFip.getPortId());
611
612 if (instPort == null) {
613 log.warn("Failed to insert floating IP rule for {} due to missing of port info.",
614 osFip.getFloatingIpAddress());
615 return;
Jian Li99892e92018-04-13 14:59:39 +0900616 }
Jian Li628a7cb2018-08-11 23:04:24 +0900617
Jian Li99892e92018-04-13 14:59:39 +0900618 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900619 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
Jian Lie6e609f2019-05-14 17:45:54 +0900620 setFloatingIpRules(osFip, instPort, null, null, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900621 processGratuitousArpPacket(osFip, instPort);
622
Jian Li99892e92018-04-13 14:59:39 +0900623 }
624 }
625
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900626 private void processGratuitousArpPacket(NetFloatingIP floatingIP,
627 InstancePort instancePort) {
628 Set<OpenstackNode> gws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
629
630 Network osNet = osNetworkService.network(instancePort.networkId());
631
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900632 OpenstackNode selectedGw = getGwByInstancePort(gws, instancePort);
633 ExternalPeerRouter externalPeerRouter =
634 externalPeerRouterForNetwork(osNet, osNetworkService, osRouterAdminService);
635 if (externalPeerRouter == null) {
Jian Lie6e609f2019-05-14 17:45:54 +0900636 log.error("Failed to process GARP packet for floating ip {}, because ",
Jian Li4d138702018-11-27 17:25:28 +0900637 NO_EXT_PEER_ROUTER_MSG);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900638 return;
639 }
640
Jian Li32b03622018-11-06 17:54:24 +0900641 processGarpPacketForFloatingIp(floatingIP, instancePort,
642 externalPeerRouter.vlanId(), selectedGw, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900643
644 }
645
Jian Li99892e92018-04-13 14:59:39 +0900646 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
Jian Li628a7cb2018-08-11 23:04:24 +0900647 InstancePort instPort = instancePortService.instancePort(portId);
Jian Lie1a39032018-06-19 21:49:36 +0900648
Jian Li628a7cb2018-08-11 23:04:24 +0900649 if (instPort == null) {
650 log.warn("Failed to remove floating IP rule for {} due to missing of port info.",
651 osFip.getFloatingIpAddress());
652 return;
Jian Lie1a39032018-06-19 21:49:36 +0900653 }
654
Jian Li99892e92018-04-13 14:59:39 +0900655 // set floating IP rules only if the port is associated to a VM
Jian Li628a7cb2018-08-11 23:04:24 +0900656 if (!Strings.isNullOrEmpty(instPort.deviceId().toString())) {
Jian Lie6e609f2019-05-14 17:45:54 +0900657 setFloatingIpRules(osFip, instPort, null, null, false);
Jian Li99892e92018-04-13 14:59:39 +0900658 }
659 }
660
Hyunsun Moon0d457362017-06-27 17:19:41 +0900661 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900662
663 @Override
664 public boolean isRelevant(OpenstackRouterEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900665 return event.floatingIp() != null;
666 }
667
Jian Li34220ea2018-11-14 01:30:24 +0900668 private boolean isRelevantHelper() {
669 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
670 }
671
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672 @Override
673 public void event(OpenstackRouterEvent event) {
674 switch (event.type()) {
675 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900676 eventExecutor.execute(() -> processFloatingIpAssociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900677 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900678 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900679 eventExecutor.execute(() -> processFloatingIpDisassociation(event));
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900680 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900681 case OPENSTACK_FLOATING_IP_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900682 eventExecutor.execute(() -> processFloatingIpCreation(event));
Hyunsun Moonb720e632017-05-16 15:41:36 +0900683 break;
Jian Lia171a432018-06-11 11:52:11 +0900684 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900685 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Lia171a432018-06-11 11:52:11 +0900686 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900687 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900688 default:
689 // do nothing for the other events
690 break;
691 }
692 }
Jian Li4d138702018-11-27 17:25:28 +0900693
694 private void processFloatingIpAssociation(OpenstackRouterEvent event) {
695 if (!isRelevantHelper()) {
696 return;
697 }
698
699 NetFloatingIP osFip = event.floatingIp();
700 if (instancePortService.instancePort(osFip.getPortId()) != null) {
701 associateFloatingIp(osFip);
702 log.info("Associated floating IP {}:{}",
703 osFip.getFloatingIpAddress(),
704 osFip.getFixedIpAddress());
705 }
706 }
707
708 private void processFloatingIpDisassociation(OpenstackRouterEvent event) {
709 if (!isRelevantHelper()) {
710 return;
711 }
712
713 NetFloatingIP osFip = event.floatingIp();
714 if (instancePortService.instancePort(event.portId()) != null) {
715 disassociateFloatingIp(osFip, event.portId());
716 log.info("Disassociated floating IP {}:{}",
717 osFip.getFloatingIpAddress(),
718 osFip.getFixedIpAddress());
719 }
720 }
721
722 private void processFloatingIpCreation(OpenstackRouterEvent event) {
723 if (!isRelevantHelper()) {
724 return;
725 }
726
727 NetFloatingIP osFip = event.floatingIp();
728 String portId = osFip.getPortId();
729 if (!Strings.isNullOrEmpty(portId) &&
730 instancePortService.instancePort(portId) != null) {
731 associateFloatingIp(event.floatingIp());
732 }
733 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
734 }
735
736 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
737 if (!isRelevantHelper()) {
738 return;
739 }
740
741 NetFloatingIP osFip = event.floatingIp();
742 String portId = osFip.getPortId();
743 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
744 // in case the floating IP is not associated with any port due to
745 // port removal, we simply do not execute floating IP disassociation
746 if (osNetworkService.port(portId) != null &&
747 instancePortService.instancePort(portId) != null) {
748 disassociateFloatingIp(osFip, portId);
749 }
750
751 // since we skip floating IP disassociation, we need to
752 // manually unsubscribe the port pre-remove event
753 preCommitPortService.unsubscribePreCommit(osFip.getPortId(),
754 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
755 this.getClass().getName());
756 log.info("Unsubscribed the port {} on listening pre-remove event",
757 osFip.getPortId());
758 }
759 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
760 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900761 }
762
763 private class InternalNodeListener implements OpenstackNodeListener {
764
765 @Override
766 public boolean isRelevant(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900767 return event.subject().type() == GATEWAY;
768 }
769
Jian Li34220ea2018-11-14 01:30:24 +0900770 private boolean isRelevantHelper() {
771 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
772 }
773
Hyunsun Moon44aac662017-02-18 02:07:01 +0900774 @Override
775 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900776
777 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900778 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900779 eventExecutor.execute(() -> processNodeCompletion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900780 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900781 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900782 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900783 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900784 break;
785 }
786 }
Jian Li4d138702018-11-27 17:25:28 +0900787
788 private void processNodeCompletion(OpenstackNodeEvent event) {
789 if (!isRelevantHelper()) {
790 return;
791 }
792
793 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
794
795 if (Strings.isNullOrEmpty(fip.getPortId())) {
796 continue;
797 }
798
799 Port osPort = osNetworkService.port(fip.getPortId());
800 InstancePort instPort = instancePortService.instancePort(fip.getPortId());
801
802 // we check both Openstack Port and Instance Port
803 if (osPort == null || instPort == null) {
804 continue;
805 }
806
Jian Lie6e609f2019-05-14 17:45:54 +0900807 setFloatingIpRules(fip, instPort, event.subject(), null, true);
Jian Li4d138702018-11-27 17:25:28 +0900808 }
809 }
810
811 private void processNodeIncompletion(OpenstackNodeEvent event) {
812 if (!isRelevantHelper()) {
813 return;
814 }
815
816 for (NetFloatingIP fip : osRouterAdminService.floatingIps()) {
817 if (Strings.isNullOrEmpty(fip.getPortId())) {
818 continue;
819 }
820 Port osPort = osNetworkService.port(fip.getPortId());
821 if (osPort == null) {
822 log.warn("Failed to set floating IP {}", fip.getId());
823 continue;
824 }
825 Network osNet = osNetworkService.network(osPort.getNetworkId());
826 if (osNet == null) {
827 final String errorFormat = ERR_FLOW + "no network(%s) exists";
828 final String error = String.format(errorFormat,
829 fip.getFloatingIpAddress(),
830 osPort.getNetworkId());
831 throw new IllegalStateException(error);
832 }
833 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
834 log.trace("Mac address of openstack port: {}", srcMac);
835 InstancePort instPort = instancePortService.instancePort(srcMac);
836
837 if (instPort == null) {
838 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
839 final String error = String.format(errorFormat,
840 fip.getFloatingIpAddress(), srcMac);
841 throw new IllegalStateException(error);
842 }
843
844 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
845 osNetworkService, osRouterAdminService);
846 if (externalPeerRouter == null) {
847 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
848 throw new IllegalStateException(errorFormat);
849 }
850
851 updateComputeNodeRules(instPort, osNet, event.subject(), false);
852 updateGatewayNodeRules(fip, instPort, osNet,
853 externalPeerRouter, event.subject(), false);
854 }
855 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900856 }
Jian Li99892e92018-04-13 14:59:39 +0900857
Jian Li24ec59f2018-05-23 19:01:25 +0900858 private class InternalInstancePortListener implements InstancePortListener {
859
Jian Li34220ea2018-11-14 01:30:24 +0900860 private boolean isRelevantHelper(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900861
Jian Lie1a39032018-06-19 21:49:36 +0900862 if (event.type() == OPENSTACK_INSTANCE_MIGRATION_ENDED ||
863 event.type() == OPENSTACK_INSTANCE_MIGRATION_STARTED) {
864 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
865 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
866
867 // we check the possible NPE to avoid duplicated null check
868 // for OPENSTACK_INSTANCE_MIGRATION_ENDED and
869 // OPENSTACK_INSTANCE_MIGRATION_STARTED cases
870 if (fip == null || !isAssociatedWithVM(osNetworkService, fip)) {
871 return false;
872 }
873 }
874
Jian Li34220ea2018-11-14 01:30:24 +0900875 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li24ec59f2018-05-23 19:01:25 +0900876 }
877
878 @Override
879 public void event(InstancePortEvent event) {
Jian Li24ec59f2018-05-23 19:01:25 +0900880 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900881 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900882 eventExecutor.execute(() -> processInstancePortDetection(event));
Jian Lie1a39032018-06-19 21:49:36 +0900883 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900884 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900885 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900886 break;
887 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900888 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900889 break;
890 default:
891 break;
892 }
893 }
Jian Li4d138702018-11-27 17:25:28 +0900894
895 private void processInstancePortDetection(InstancePortEvent event) {
896 if (!isRelevantHelper(event)) {
897 return;
898 }
899
900 InstancePort instPort = event.subject();
901
902 if (instPort != null && instPort.portId() != null) {
903 osRouterAdminService.floatingIps().stream()
904 .filter(f -> f.getPortId() != null)
905 .filter(f -> f.getPortId().equals(instPort.portId()))
906 .forEach(f -> setFloatingIpRules(f,
Jian Lie6e609f2019-05-14 17:45:54 +0900907 instPort, null, null, true));
Jian Li4d138702018-11-27 17:25:28 +0900908 }
909 }
910
911 private void processInstanceMigrationStart(InstancePortEvent event) {
912 if (!isRelevantHelper(event)) {
913 return;
914 }
915
916 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
917 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
918 NetFloatingIP fip = associatedFloatingIp(event.subject(), ips);
919
920 if (fip == null) {
921 return;
922 }
923
924 Port osPort = osNetworkService.port(fip.getPortId());
925 Network osNet = osNetworkService.network(osPort.getNetworkId());
926 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
927 osNetworkService, osRouterAdminService);
928
929 if (externalPeerRouter == null) {
930 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
931 throw new IllegalStateException(errorFormat);
932 }
933
934 // since DownstreamExternal rules should only be placed in
935 // corresponding gateway node, we need to install new rule to
936 // the corresponding gateway node
937 setDownstreamExternalRulesHelper(fip, osNet,
938 event.subject(), externalPeerRouter, gateways, true);
939
940 // since ComputeNodeToGateway rules should only be placed in
941 // corresponding compute node, we need to install new rule to
942 // the target compute node, and remove rules from original node
943 setComputeNodeToGatewayHelper(event.subject(), osNet, gateways, true);
944 }
945
946 private void processInstanceMigrationEnd(InstancePortEvent event) {
947 if (!isRelevantHelper(event)) {
948 return;
949 }
950
951 InstancePort oldInstPort = swapStaleLocation(event.subject());
952
953 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
954 NetFloatingIP fip = associatedFloatingIp(oldInstPort, ips);
955
956 if (fip == null) {
957 return;
958 }
959
960 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
961 Port osPort = osNetworkService.port(fip.getPortId());
962 Network osNet = osNetworkService.network(osPort.getNetworkId());
963 ExternalPeerRouter externalPeerRouter = externalPeerRouterForNetwork(osNet,
964 osNetworkService, osRouterAdminService);
965
966 if (externalPeerRouter == null) {
967 final String errorFormat = ERR_FLOW + NO_EXT_PEER_ROUTER_MSG;
968 throw new IllegalStateException(errorFormat);
969 }
970
971 // We need to remove the old ComputeNodeToGateway rules from
972 // original compute node
973 setComputeNodeToGatewayHelper(oldInstPort, osNet, gateways, false);
974
975 // If we only have one gateway, we simply do not remove any
976 // flow rules from either gateway or compute node
977 if (gateways.size() == 1) {
978 return;
979 }
980
981 // Checks whether the destination compute node's device id
982 // has identical gateway hash or not
983 // if it is true, we simply do not remove the rules, as
984 // it has been overwritten at port detention event
985 // if it is false, we will remove the rules
986 DeviceId newDeviceId = event.subject().deviceId();
987 DeviceId oldDeviceId = oldInstPort.deviceId();
988
989 OpenstackNode oldGateway = getGwByComputeDevId(gateways, oldDeviceId);
990 OpenstackNode newGateway = getGwByComputeDevId(gateways, newDeviceId);
991
992 if (oldGateway != null && oldGateway.equals(newGateway)) {
993 return;
994 }
995
996 // Since DownstreamExternal rules should only be placed in
997 // corresponding gateway node, we need to remove old rule from
998 // the corresponding gateway node
999 setDownstreamExternalRulesHelper(fip, osNet, oldInstPort,
1000 externalPeerRouter, gateways, false);
1001 }
Jian Li24ec59f2018-05-23 19:01:25 +09001002 }
Jian Lie1a39032018-06-19 21:49:36 +09001003
1004 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
1005
Jian Li34220ea2018-11-14 01:30:24 +09001006 private boolean isRelevantHelper() {
1007 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lie1a39032018-06-19 21:49:36 +09001008 }
1009
1010 @Override
1011 public void event(OpenstackNetworkEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +09001012
Jian Lie6e609f2019-05-14 17:45:54 +09001013 switch (event.type()) {
1014 case OPENSTACK_PORT_PRE_REMOVE:
1015 eventExecutor.execute(() -> processPortPreRemoval(event));
1016 break;
1017 case EXTERNAL_PEER_ROUTER_MAC_UPDATED:
1018 eventExecutor.execute(() -> processExternalPeerRouterMacUpdate(event));
1019 break;
1020 default:
1021 break;
Jian Lie1a39032018-06-19 21:49:36 +09001022 }
1023 }
1024
Jian Lie6e609f2019-05-14 17:45:54 +09001025 private void processExternalPeerRouterMacUpdate(OpenstackNetworkEvent event) {
1026 if (!isRelevantHelper()) {
1027 return;
1028 }
1029
1030 instancePortService.instancePorts().forEach(instPort ->
1031 osRouterAdminService.floatingIps().stream()
1032 .filter(f -> f.getPortId() != null)
1033 .filter(f -> f.getPortId().equals(instPort.portId()))
1034 .forEach(f -> setFloatingIpRules(f,
1035 instPort, null, event.peerRouter(), true)));
1036 }
1037
Jian Li4d138702018-11-27 17:25:28 +09001038 private void processPortPreRemoval(OpenstackNetworkEvent event) {
Jian Lie6e609f2019-05-14 17:45:54 +09001039 if (!isRelevantHelper()) {
1040 return;
1041 }
1042
Jian Li32b03622018-11-06 17:54:24 +09001043 InstancePort instPort = instancePortService.instancePort(
1044 event.port().getId());
1045 if (instPort == null) {
1046 return;
1047 }
1048 NetFloatingIP fip = associatedFloatingIp(instPort,
1049 osRouterAdminService.floatingIps());
1050
1051 if (fip != null) {
1052 instancePortService.updateInstancePort(
1053 instPort.updateState(REMOVE_PENDING));
1054 updateFipStore(event.port().getId());
1055 } else {
1056 instancePortService.removeInstancePort(instPort.portId());
1057 }
1058 }
1059
Jian Li2360acb2018-10-17 00:46:31 +09001060 private void updateFipStore(String portId) {
Jian Lie1a39032018-06-19 21:49:36 +09001061
Jian Li2360acb2018-10-17 00:46:31 +09001062 if (portId == null) {
Jian Lie1a39032018-06-19 21:49:36 +09001063 return;
1064 }
1065
1066 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
1067 for (NetFloatingIP fip : ips) {
1068 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
1069 continue;
1070 }
1071 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
1072 continue;
1073 }
Jian Li2360acb2018-10-17 00:46:31 +09001074 if (fip.getPortId().equals(portId)) {
Jian Lie1a39032018-06-19 21:49:36 +09001075 NeutronFloatingIP neutronFip = (NeutronFloatingIP) fip;
1076 // invalidate bound fixed IP and port
1077 neutronFip.setFixedIpAddress(null);
1078 neutronFip.setPortId(null);
Jian Lie1a39032018-06-19 21:49:36 +09001079
1080 // Following update will in turn trigger
1081 // OPENSTACK_FLOATING_IP_DISASSOCIATED event
1082 osRouterAdminService.updateFloatingIp(neutronFip);
1083 log.info("Updated floating IP {}, due to host removal",
1084 neutronFip.getFloatingIpAddress());
1085 }
1086 }
1087 }
1088 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001089}