blob: 0819e40c6ff6d0549795a3faafdc35552ab770ea [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;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onlab.packet.Ethernet;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090027import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090028import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.device.DeviceService;
35import org.onosproject.net.flow.DefaultTrafficSelector;
36import org.onosproject.net.flow.DefaultTrafficTreatment;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.openstacknetworking.api.Constants;
daniel park32b42202018-03-14 16:53:44 +090040import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.openstacknetworking.api.InstancePort;
42import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090043import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
44import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090045import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
46import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
47import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090048import org.onosproject.openstacknode.api.OpenstackNode;
49import org.onosproject.openstacknode.api.OpenstackNodeEvent;
50import org.onosproject.openstacknode.api.OpenstackNodeListener;
51import org.onosproject.openstacknode.api.OpenstackNodeService;
daniel parkeeb8e042018-02-21 14:06:58 +090052import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import org.openstack4j.model.network.NetFloatingIP;
54import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090055import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.openstack4j.model.network.Port;
daniel parkeeb8e042018-02-21 14:06:58 +090057import org.openstack4j.model.network.Router;
58import org.openstack4j.model.network.RouterInterface;
59import org.openstack4j.model.network.Subnet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090060import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
63import java.util.Objects;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import java.util.concurrent.ExecutorService;
65
66import static java.util.concurrent.Executors.newSingleThreadExecutor;
67import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090068import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
69import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel parkeeb8e042018-02-21 14:06:58 +090070import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
sanghodc375372017-06-08 10:41:30 +090071import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
72import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
daniel parkeeb8e042018-02-21 14:06:58 +090073import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li26949762018-03-30 15:46:37 +090074import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090075import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090076
77/**
78 * Handles OpenStack floating IP events.
79 */
80@Component(immediate = true)
81public class OpenstackRoutingFloatingIpHandler {
82
83 private final Logger log = LoggerFactory.getLogger(getClass());
84
85 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
Ray Milkeyc6c9b172018-02-26 09:36:31 -080086 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type %s";
Hyunsun Moon44aac662017-02-18 02:07:01 +090087
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected CoreService coreService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected DeviceService deviceService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +090095 protected LeadershipService leadershipService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected ClusterService clusterService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected OpenstackNodeService osNodeService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected InstancePortService instancePortService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected OpenstackRouterService osRouterService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected OpenstackNetworkService osNetworkService;
111
sanghodc375372017-06-08 10:41:30 +0900112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected OpenstackFlowRuleService osFlowRuleService;
114
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115 private final ExecutorService eventExecutor = newSingleThreadExecutor(
116 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900117 private final OpenstackRouterListener floatingIpLisener = new InternalFloatingIpListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
119
120 private ApplicationId appId;
121 private NodeId localNodeId;
122
123 @Activate
124 protected void activate() {
125 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
126 localNodeId = clusterService.getLocalNode().id();
127 leadershipService.runForLeadership(appId.name());
128 osRouterService.addListener(floatingIpLisener);
129 osNodeService.addListener(osNodeListener);
130
131 log.info("Started");
132 }
133
134 @Deactivate
135 protected void deactivate() {
136 osNodeService.removeListener(osNodeListener);
137 osRouterService.removeListener(floatingIpLisener);
138 leadershipService.withdraw(appId.name());
139 eventExecutor.shutdown();
140
141 log.info("Stopped");
142 }
143
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144 private void setFloatingIpRules(NetFloatingIP floatingIp, Port osPort,
145 boolean install) {
146 Network osNet = osNetworkService.network(osPort.getNetworkId());
147 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900148 final String errorFormat = ERR_FLOW + "no network(%s) exists";
149 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900150 floatingIp.getFloatingIpAddress(),
151 osPort.getNetworkId());
152 throw new IllegalStateException(error);
153 }
154
155 MacAddress srcMac = MacAddress.valueOf(osPort.getMacAddress());
daniel parkc2a2ed62018-04-10 15:17:42 +0900156 log.trace("Mac address of openstack port: {}", srcMac);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 InstancePort instPort = instancePortService.instancePort(srcMac);
158 if (instPort == null) {
Jian Li71670d12018-03-02 21:31:07 +0900159 final String errorFormat = ERR_FLOW + "no host(MAC:%s) found";
160 final String error = String.format(errorFormat,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161 floatingIp.getFloatingIpAddress(), srcMac);
162 throw new IllegalStateException(error);
163 }
164
daniel park32b42202018-03-14 16:53:44 +0900165
166 ExternalPeerRouter externalPeerRouter = externalPeerRouter(osNet);
167 if (externalPeerRouter == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900168 final String errorFormat = ERR_FLOW + "no external peer router found";
169 throw new IllegalStateException(errorFormat);
daniel park32b42202018-03-14 16:53:44 +0900170 }
171
daniel parkeeb8e042018-02-21 14:06:58 +0900172 setComputeNodeToGateway(instPort, osNet, install);
daniel park32b42202018-03-14 16:53:44 +0900173 setDownstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
174 setUpstreamRules(floatingIp, osNet, instPort, externalPeerRouter, install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900175 log.trace("Succeeded to set flow rules for floating ip {}:{} and install: {}",
176 floatingIp.getFloatingIpAddress(),
177 floatingIp.getFixedIpAddress(),
178 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900179 }
180
daniel parkeeb8e042018-02-21 14:06:58 +0900181 private void setComputeNodeToGateway(InstancePort instPort, Network osNet, boolean install) {
182 TrafficTreatment treatment;
183
184 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
185 .matchEthType(Ethernet.TYPE_IPV4)
186 .matchIPSrc(instPort.ipAddress().toIpPrefix())
187 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
188
189 switch (osNet.getNetworkType()) {
190 case VXLAN:
191 sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
192 break;
193 case VLAN:
194 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
195 break;
196 default:
197 final String error = String.format(
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800198 ERR_UNSUPPORTED_NET_TYPE,
daniel parkeeb8e042018-02-21 14:06:58 +0900199 osNet.getNetworkType().toString());
200 throw new IllegalStateException(error);
201 }
202
203 OpenstackNode selectedGatewayNode = selectGatewayNode();
204 if (selectedGatewayNode == null) {
daniel parkc2a2ed62018-04-10 15:17:42 +0900205 final String errorFormat = ERR_FLOW + "no gateway node selected";
206 throw new IllegalStateException(errorFormat);
daniel parkeeb8e042018-02-21 14:06:58 +0900207 }
208 treatment = DefaultTrafficTreatment.builder()
209 .extension(buildExtension(
210 deviceService,
211 instPort.deviceId(),
212 selectedGatewayNode.dataIp().getIp4Address()),
213 instPort.deviceId())
214 .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
215 .build();
216
217 osFlowRuleService.setRule(
218 appId,
219 instPort.deviceId(),
220 sBuilder.build(),
221 treatment,
222 PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
223 ROUTING_TABLE,
224 install);
daniel parkc2a2ed62018-04-10 15:17:42 +0900225 log.trace("Succeeded to set flow rules from compute node to gateway on compute node");
daniel parkeeb8e042018-02-21 14:06:58 +0900226 }
227
228 private OpenstackNode selectGatewayNode() {
229 //TODO support multiple loadbalancing options.
230 return osNodeService.completeNodes(GATEWAY).stream().findAny().orElse(null);
231 }
232
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233 private void setDownstreamRules(NetFloatingIP floatingIp, Network osNet,
daniel park32b42202018-03-14 16:53:44 +0900234 InstancePort instPort, ExternalPeerRouter externalPeerRouter,
235 boolean install) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900236 OpenstackNode cNode = osNodeService.node(instPort.deviceId());
237 if (cNode == null) {
238 final String error = String.format("Cannot find openstack node for device %s",
239 instPort.deviceId());
240 throw new IllegalStateException(error);
241 }
242 if (osNet.getNetworkType() == NetworkType.VXLAN && cNode.dataIp() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900243 final String errorFormat = ERR_FLOW + "VXLAN mode is not ready for %s";
244 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900245 throw new IllegalStateException(error);
246 }
247 if (osNet.getNetworkType() == NetworkType.VLAN && cNode.vlanIntf() == null) {
Jian Li71670d12018-03-02 21:31:07 +0900248 final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
249 final String error = String.format(errorFormat, floatingIp, cNode.hostname());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900250 throw new IllegalStateException(error);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900251 }
252
253 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel park32b42202018-03-14 16:53:44 +0900254 TrafficSelector.Builder externalSelectorBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900255 .matchEthType(Ethernet.TYPE_IPV4)
daniel park32b42202018-03-14 16:53:44 +0900256 .matchIPDst(floating.toIpPrefix());
257
258 TrafficTreatment.Builder externalBuilder = DefaultTrafficTreatment.builder()
259 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
260 .setEthDst(instPort.macAddress())
261 .setIpDst(instPort.ipAddress().getIp4Address());
262
263 if (!externalPeerRouter.externalPeerRouterVlanId().equals(VlanId.NONE)) {
264 externalSelectorBuilder.matchVlanId(externalPeerRouter.externalPeerRouterVlanId()).build();
265 externalBuilder.popVlan();
266 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900267
Hyunsun Moon0d457362017-06-27 17:19:41 +0900268 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
daniel park32b42202018-03-14 16:53:44 +0900269
daniel parkee8700b2017-05-11 15:50:03 +0900270
271 switch (osNet.getNetworkType()) {
272 case VXLAN:
273 externalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
274 .extension(buildExtension(
275 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900276 gNode.intgBridge(),
277 cNode.dataIp().getIp4Address()),
278 gNode.intgBridge())
279 .setOutput(gNode.tunnelPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900280 break;
281 case VLAN:
282 externalBuilder.pushVlan()
283 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900284 .setOutput(gNode.vlanPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900285 break;
286 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800287 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900288 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900289 throw new IllegalStateException(error);
290 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291
sanghodc375372017-06-08 10:41:30 +0900292 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900293 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900294 gNode.intgBridge(),
daniel park32b42202018-03-14 16:53:44 +0900295 externalSelectorBuilder.build(),
daniel parkee8700b2017-05-11 15:50:03 +0900296 externalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900297 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900298 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900299 install);
300
Hyunsun Moon0d457362017-06-27 17:19:41 +0900301 // access from one VM to the others via floating IP
Hyunsun Moon44aac662017-02-18 02:07:01 +0900302 TrafficSelector internalSelector = DefaultTrafficSelector.builder()
303 .matchEthType(Ethernet.TYPE_IPV4)
304 .matchIPDst(floating.toIpPrefix())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900305 .matchInPort(gNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900306 .build();
307
daniel parkee8700b2017-05-11 15:50:03 +0900308 TrafficTreatment.Builder internalBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309 .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
310 .setEthDst(instPort.macAddress())
daniel parkee8700b2017-05-11 15:50:03 +0900311 .setIpDst(instPort.ipAddress().getIp4Address());
312
313 switch (osNet.getNetworkType()) {
314 case VXLAN:
315 internalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
316 .extension(buildExtension(
317 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900318 gNode.intgBridge(),
319 cNode.dataIp().getIp4Address()),
320 gNode.intgBridge())
daniel parkee8700b2017-05-11 15:50:03 +0900321 .setOutput(PortNumber.IN_PORT);
322 break;
323 case VLAN:
324 internalBuilder.pushVlan()
325 .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
326 .setOutput(PortNumber.IN_PORT);
327 break;
328 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800329 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900330 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900331 throw new IllegalStateException(error);
332 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900333
sanghodc375372017-06-08 10:41:30 +0900334 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900335 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900336 gNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900337 internalSelector,
daniel parkee8700b2017-05-11 15:50:03 +0900338 internalBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900339 PRIORITY_FLOATING_INTERNAL,
sanghodc375372017-06-08 10:41:30 +0900340 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 install);
342 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900343 log.trace("Succeeded to set flow rules for downstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900344 }
345
346 private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
daniel park32b42202018-03-14 16:53:44 +0900347 InstancePort instPort, ExternalPeerRouter externalPeerRouter,
348 boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900349 IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
daniel parkee8700b2017-05-11 15:50:03 +0900350 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900351 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900352 .matchIPSrc(instPort.ipAddress().toIpPrefix());
353
354 switch (osNet.getNetworkType()) {
355 case VXLAN:
356 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
357 break;
358 case VLAN:
359 sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
360 break;
361 default:
Ray Milkeyc6c9b172018-02-26 09:36:31 -0800362 final String error = String.format(ERR_UNSUPPORTED_NET_TYPE,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900363 osNet.getNetworkType());
daniel parkee8700b2017-05-11 15:50:03 +0900364 throw new IllegalStateException(error);
365 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900366
daniel park32b42202018-03-14 16:53:44 +0900367 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
368 .setIpSrc(floating.getIp4Address())
369 .setEthSrc(instPort.macAddress())
370 .setEthDst(externalPeerRouter.externalPeerRouterMac());
371
372 if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
373 tBuilder.popVlan();
daniel parkeeb8e042018-02-21 14:06:58 +0900374 }
375
daniel park32b42202018-03-14 16:53:44 +0900376 if (!externalPeerRouter.externalPeerRouterVlanId().equals(VlanId.NONE)) {
377 tBuilder.pushVlan().setVlanId(externalPeerRouter.externalPeerRouterVlanId());
378 }
daniel parkeeb8e042018-02-21 14:06:58 +0900379
Hyunsun Moon0d457362017-06-27 17:19:41 +0900380 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900381
sanghodc375372017-06-08 10:41:30 +0900382 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900383 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900384 gNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900385 sBuilder.build(),
daniel parkeeb8e042018-02-21 14:06:58 +0900386 tBuilder.setOutput(gNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900387 PRIORITY_FLOATING_EXTERNAL,
sanghodc375372017-06-08 10:41:30 +0900388 GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900389 install);
390 });
daniel parkc2a2ed62018-04-10 15:17:42 +0900391 log.trace("Succeeded to set flow rules for upstream on gateway nodes");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900392 }
393
daniel park32b42202018-03-14 16:53:44 +0900394 private ExternalPeerRouter externalPeerRouter(Network network) {
daniel parkeeb8e042018-02-21 14:06:58 +0900395 if (network == null) {
396 return null;
397 }
398
399 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
400
401 if (subnet == null) {
402 return null;
403 }
404
405 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
406 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
407 .findAny().orElse(null);
408 if (osRouterIface == null) {
409 return null;
410 }
411
412 Router osRouter = osRouterService.router(osRouterIface.getId());
413 if (osRouter == null) {
414 return null;
415 }
416 if (osRouter.getExternalGatewayInfo() == null) {
417 return null;
418 }
419
420 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
daniel park65e1c202018-04-03 13:15:28 +0900421 return osNetworkService.externalPeerRouter(exGatewayInfo);
daniel parkeeb8e042018-02-21 14:06:58 +0900422 }
daniel park65e1c202018-04-03 13:15:28 +0900423
Hyunsun Moon0d457362017-06-27 17:19:41 +0900424 private class InternalFloatingIpListener implements OpenstackRouterListener {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900425
426 @Override
427 public boolean isRelevant(OpenstackRouterEvent event) {
428 // do not allow to proceed without leadership
429 NodeId leader = leadershipService.getLeader(appId.name());
430 if (!Objects.equals(localNodeId, leader)) {
431 return false;
432 }
433 return event.floatingIp() != null;
434 }
435
436 @Override
437 public void event(OpenstackRouterEvent event) {
438 switch (event.type()) {
439 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900440 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900441 NetFloatingIP osFip = event.floatingIp();
442 associateFloatingIp(osFip);
443 log.info("Associated floating IP {}:{}",
444 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900445 });
446 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900447 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
448 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900449 NetFloatingIP osFip = event.floatingIp();
450 disassociateFloatingIp(osFip, event.portId());
451 log.info("Disassociated floating IP {}:{}",
452 osFip.getFloatingIpAddress(), osFip.getFixedIpAddress());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900453 });
454 break;
455 case OPENSTACK_FLOATING_IP_REMOVED:
456 eventExecutor.execute(() -> {
Hyunsun Moonb720e632017-05-16 15:41:36 +0900457 NetFloatingIP osFip = event.floatingIp();
458 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
459 disassociateFloatingIp(osFip, osFip.getPortId());
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900460 }
Hyunsun Moonb720e632017-05-16 15:41:36 +0900461 log.info("Removed floating IP {}", osFip.getFloatingIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900462 });
463 break;
464 case OPENSTACK_FLOATING_IP_CREATED:
Hyunsun Moonb720e632017-05-16 15:41:36 +0900465 eventExecutor.execute(() -> {
466 NetFloatingIP osFip = event.floatingIp();
467 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
468 associateFloatingIp(event.floatingIp());
469 }
470 log.info("Created floating IP {}", osFip.getFloatingIpAddress());
471 });
472 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900473 case OPENSTACK_FLOATING_IP_UPDATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900474 case OPENSTACK_ROUTER_CREATED:
475 case OPENSTACK_ROUTER_UPDATED:
476 case OPENSTACK_ROUTER_REMOVED:
477 case OPENSTACK_ROUTER_INTERFACE_ADDED:
478 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
479 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
480 default:
481 // do nothing for the other events
482 break;
483 }
484 }
Hyunsun Moonb720e632017-05-16 15:41:36 +0900485
486 private void associateFloatingIp(NetFloatingIP osFip) {
487 Port osPort = osNetworkService.port(osFip.getPortId());
488 if (osPort == null) {
Jian Li71670d12018-03-02 21:31:07 +0900489 final String errorFormat = ERR_FLOW + "port(%s) not found";
490 final String error = String.format(errorFormat,
Hyunsun Moonb720e632017-05-16 15:41:36 +0900491 osFip.getFloatingIpAddress(), osFip.getPortId());
492 throw new IllegalStateException(error);
493 }
494 // set floating IP rules only if the port is associated to a VM
495 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
496 setFloatingIpRules(osFip, osPort, true);
497 }
498 }
499
500 private void disassociateFloatingIp(NetFloatingIP osFip, String portId) {
501 Port osPort = osNetworkService.port(portId);
502 if (osPort == null) {
503 // FIXME when a port with floating IP removed without
504 // disassociation step, it can reach here
505 return;
506 }
507 // set floating IP rules only if the port is associated to a VM
508 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
509 setFloatingIpRules(osFip, osPort, false);
510 }
511 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900512 }
513
514 private class InternalNodeListener implements OpenstackNodeListener {
515
516 @Override
517 public boolean isRelevant(OpenstackNodeEvent event) {
518 // do not allow to proceed without leadership
519 NodeId leader = leadershipService.getLeader(appId.name());
520 if (!Objects.equals(localNodeId, leader)) {
521 return false;
522 }
523 return event.subject().type() == GATEWAY;
524 }
525
526 @Override
527 public void event(OpenstackNodeEvent event) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900528
529 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900530 case OPENSTACK_NODE_COMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900531 eventExecutor.execute(() -> {
Hyunsun Moon7a5f9042017-05-11 18:19:01 +0900532 for (NetFloatingIP fip : osRouterService.floatingIps()) {
533 if (Strings.isNullOrEmpty(fip.getPortId())) {
534 continue;
535 }
536 Port osPort = osNetworkService.port(fip.getPortId());
537 if (osPort == null) {
538 log.warn("Failed to set floating IP {}", fip.getId());
539 continue;
540 }
541 setFloatingIpRules(fip, osPort, true);
542 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900543 });
544 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900545 case OPENSTACK_NODE_CREATED:
546 case OPENSTACK_NODE_UPDATED:
547 case OPENSTACK_NODE_REMOVED:
548 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900549 default:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900550 // do nothing
Hyunsun Moon44aac662017-02-18 02:07:01 +0900551 break;
552 }
553 }
554 }
555}