blob: 9769203255d5f7df9dfa0360084e48198e6889ed [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
Jian Li5a26ab32019-03-21 15:20:01 +090018import com.google.common.base.MoreObjects;
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.Maps;
Jian Li33b4db52019-03-20 18:22:38 +090021import com.google.common.collect.Sets;
Hyunsun Moon44aac662017-02-18 02:07:01 +090022import org.onlab.packet.Ethernet;
23import org.onlab.packet.IPv4;
24import org.onlab.packet.IpAddress;
25import org.onlab.packet.IpPrefix;
Hyunsun Moon44aac662017-02-18 02:07:01 +090026import org.onlab.packet.TCP;
27import org.onlab.packet.TpPort;
28import org.onlab.packet.UDP;
daniel parkee8700b2017-05-11 15:50:03 +090029import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onlab.util.KryoNamespace;
Jian Li33b4db52019-03-20 18:22:38 +090031import org.onlab.util.Tools;
32import org.onosproject.cfg.ComponentConfigService;
33import org.onosproject.cluster.ClusterService;
34import org.onosproject.cluster.LeadershipService;
35import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.core.ApplicationId;
37import org.onosproject.core.CoreService;
Jian Li33b4db52019-03-20 18:22:38 +090038import org.onosproject.mastership.MastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.net.DeviceId;
Jian Li2d68c192018-12-13 15:52:59 +090040import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.net.device.DeviceService;
Jian Li33b4db52019-03-20 18:22:38 +090042import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.TrafficSelector;
46import org.onosproject.net.flow.TrafficTreatment;
Jian Li33b4db52019-03-20 18:22:38 +090047import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090048import org.onosproject.net.packet.DefaultOutboundPacket;
49import org.onosproject.net.packet.InboundPacket;
50import org.onosproject.net.packet.PacketContext;
51import org.onosproject.net.packet.PacketProcessor;
52import org.onosproject.net.packet.PacketService;
Jian Li33b4db52019-03-20 18:22:38 +090053import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090054import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li33b4db52019-03-20 18:22:38 +090056import org.onosproject.openstacknetworking.api.InstancePortEvent;
57import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090059import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090060import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Li33b4db52019-03-20 18:22:38 +090061import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090062import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Li33b4db52019-03-20 18:22:38 +090063import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
64import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
sanghodc375372017-06-08 10:41:30 +090065import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Li26949762018-03-30 15:46:37 +090066import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090067import org.onosproject.openstacknode.api.OpenstackNode;
Jian Li33b4db52019-03-20 18:22:38 +090068import org.onosproject.openstacknode.api.OpenstackNodeEvent;
69import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090070import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090071import org.onosproject.store.serializers.KryoNamespaces;
72import org.onosproject.store.service.ConsistentMap;
daniel park0bc7fdb2017-03-13 14:20:08 +090073import org.onosproject.store.service.DistributedSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074import org.onosproject.store.service.Serializer;
75import org.onosproject.store.service.StorageService;
Jian Li33b4db52019-03-20 18:22:38 +090076import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090077import org.openstack4j.model.network.IP;
78import org.openstack4j.model.network.Network;
79import org.openstack4j.model.network.Port;
Jian Li33b4db52019-03-20 18:22:38 +090080import org.openstack4j.model.network.Router;
81import org.openstack4j.model.network.RouterInterface;
Hyunsun Moon44aac662017-02-18 02:07:01 +090082import org.openstack4j.model.network.Subnet;
Jian Li33b4db52019-03-20 18:22:38 +090083import org.osgi.service.component.ComponentContext;
Jian Liebde74d2018-11-14 00:18:57 +090084import org.osgi.service.component.annotations.Activate;
85import org.osgi.service.component.annotations.Component;
86import org.osgi.service.component.annotations.Deactivate;
Jian Li33b4db52019-03-20 18:22:38 +090087import org.osgi.service.component.annotations.Modified;
Jian Liebde74d2018-11-14 00:18:57 +090088import org.osgi.service.component.annotations.Reference;
89import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090090import org.slf4j.Logger;
91
92import java.nio.ByteBuffer;
Jian Li33b4db52019-03-20 18:22:38 +090093import java.util.Dictionary;
Jian Li5a26ab32019-03-21 15:20:01 +090094import java.util.List;
95import java.util.Map;
Jian Li33b4db52019-03-20 18:22:38 +090096import java.util.Objects;
97import java.util.Optional;
Hyunsun Moon0d457362017-06-27 17:19:41 +090098import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090099import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900100import java.util.stream.Collectors;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101
102import static java.util.concurrent.Executors.newSingleThreadExecutor;
103import static org.onlab.util.Tools.groupedThreads;
daniel parkeeb8e042018-02-21 14:06:58 +0900104import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
105import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
106import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li33b4db52019-03-20 18:22:38 +0900107import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
daniel parkeeb8e042018-02-21 14:06:58 +0900108import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SNAT_RULE;
Jian Li33b4db52019-03-20 18:22:38 +0900109import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
110import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
111import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
112import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
113import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
114import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT;
115import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT_DEFAULT;
Jian Liebde74d2018-11-14 00:18:57 +0900116import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalIpFromSubnet;
117import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Jian Li5a26ab32019-03-21 15:20:01 +0900118import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getExternalIp;
Jian Li2d68c192018-12-13 15:52:59 +0900119import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
Jian Li5a26ab32019-03-21 15:20:01 +0900120import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.CT_NAT_SRC_FLAG;
Jian Li33b4db52019-03-20 18:22:38 +0900121import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
122import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900123import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124import static org.slf4j.LoggerFactory.getLogger;
125
126/**
127 * Handle packets needs SNAT.
128 */
Jian Li33b4db52019-03-20 18:22:38 +0900129@Component(
130 immediate = true,
131 property = {
132 USE_STATEFUL_SNAT + ":Boolean=" + USE_STATEFUL_SNAT_DEFAULT
133 }
134)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135public class OpenstackRoutingSnatHandler {
136
137 private final Logger log = getLogger(getClass());
138
Jian Li33b4db52019-03-20 18:22:38 +0900139 private static final String ERR_PACKET_IN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +0900140 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Ray Milkey3717e602018-02-01 13:49:47 -0800141 private static final long TIME_OUT_SNAT_PORT_MS = 120L * 1000L;
Jian Li5a26ab32019-03-21 15:20:01 +0900142 private static final int TP_PORT_MINIMUM_NUM = 1025;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 private static final int TP_PORT_MAXIMUM_NUM = 65535;
Jian Li6a47fd02018-11-27 21:51:03 +0900144 private static final int VM_PREFIX = 32;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145
Jian Li33b4db52019-03-20 18:22:38 +0900146 private static final String MSG_ENABLED = "Enabled ";
147 private static final String MSG_DISABLED = "Disabled ";
148
149 /** Use Stateful SNAT for source NATing. */
150 private boolean useStatefulSnat = USE_STATEFUL_SNAT_DEFAULT;
151
152 private static final KryoNamespace.Builder NUMBER_SERIALIZER =
153 KryoNamespace.newBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900154 .register(KryoNamespaces.API);
155
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 protected CoreService coreService;
158
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160 protected PacketService packetService;
161
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163 protected StorageService storageService;
164
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700165 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 protected DeviceService deviceService;
167
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700168 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 protected InstancePortService instancePortService;
170
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700171 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900172 protected ComponentConfigService configService;
173
174 @Reference(cardinality = ReferenceCardinality.MANDATORY)
175 protected DriverService driverService;
176
177 @Reference(cardinality = ReferenceCardinality.MANDATORY)
178 protected LeadershipService leadershipService;
179
180 @Reference(cardinality = ReferenceCardinality.MANDATORY)
181 protected MastershipService mastershipService;
182
183 @Reference(cardinality = ReferenceCardinality.MANDATORY)
184 protected ClusterService clusterService;
185
186 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900187 protected OpenstackNodeService osNodeService;
188
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700189 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900190 protected OpenstackNetworkAdminService osNetworkAdminService;
191
192 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 protected OpenstackNetworkService osNetworkService;
194
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700195 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900196 protected OpenstackRouterService osRouterService;
197
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700198 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900199 protected OpenstackFlowRuleService osFlowRuleService;
200
Hyunsun Moon44aac662017-02-18 02:07:01 +0900201 private final ExecutorService eventExecutor = newSingleThreadExecutor(
202 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900203 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Jian Li33b4db52019-03-20 18:22:38 +0900204 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
205 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
206 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900207
daniel park0bc7fdb2017-03-13 14:20:08 +0900208 private ConsistentMap<Integer, Long> allocatedPortNumMap;
209 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900210 private ApplicationId appId;
Jian Li33b4db52019-03-20 18:22:38 +0900211 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900212
213 @Activate
214 protected void activate() {
215 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900216
217 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900218 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
Jian Li5a26ab32019-03-21 15:20:01 +0900219 .withName("openstackrouting-allocated-portnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900220 .withApplicationId(appId)
221 .build();
222
daniel park0bc7fdb2017-03-13 14:20:08 +0900223 unUsedPortNumSet = storageService.<Integer>setBuilder()
Jian Li5a26ab32019-03-21 15:20:01 +0900224 .withName("openstackrouting-unused-portnumset")
daniel park0bc7fdb2017-03-13 14:20:08 +0900225 .withSerializer(Serializer.using(KryoNamespaces.API))
226 .build()
227 .asDistributedSet();
228
Jian Li33b4db52019-03-20 18:22:38 +0900229 localNodeId = clusterService.getLocalNode().id();
230 leadershipService.runForLeadership(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900231 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Jian Li33b4db52019-03-20 18:22:38 +0900232
233 configService.registerProperties(getClass());
234 instancePortService.addListener(instancePortListener);
235 osRouterService.addListener(osRouterListener);
236 osNodeService.addListener(osNodeListener);
237
Jian Li5a26ab32019-03-21 15:20:01 +0900238 eventExecutor.execute(this::initializeUnusedPortNumSet);
239
Hyunsun Moon44aac662017-02-18 02:07:01 +0900240 log.info("Started");
241 }
242
243 @Deactivate
244 protected void deactivate() {
Jian Li33b4db52019-03-20 18:22:38 +0900245 osRouterService.removeListener(osRouterListener);
246 osNodeService.removeListener(osNodeListener);
247 instancePortService.removeListener(instancePortListener);
248 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900249 packetService.removeProcessor(packetProcessor);
Jian Li33b4db52019-03-20 18:22:38 +0900250 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900251 eventExecutor.shutdown();
252 log.info("Stopped");
253 }
254
Jian Li33b4db52019-03-20 18:22:38 +0900255 @Modified
256 protected void modified(ComponentContext context) {
257 Dictionary<?, ?> properties = context.getProperties();
258 Boolean flag;
259
260 flag = Tools.isPropertyEnabled(properties, USE_STATEFUL_SNAT);
261 if (flag == null) {
262 log.info("useStatefulSnat is not configured, " +
263 "using current value of {}", useStatefulSnat);
264 } else {
265 useStatefulSnat = flag;
266 log.info("Configured. useStatefulSnat is {}",
267 useStatefulSnat ? "enabled" : "disabled");
268 }
269
270 resetSnatRules();
271 }
272
Hyunsun Moon44aac662017-02-18 02:07:01 +0900273 private void processSnatPacket(PacketContext context, Ethernet eth) {
Jian Li25257212019-03-26 13:31:14 +0900274
275 if (useStatefulSnat) {
276 return;
277 }
278
Hyunsun Moon44aac662017-02-18 02:07:01 +0900279 IPv4 iPacket = (IPv4) eth.getPayload();
280 InboundPacket packetIn = context.inPacket();
281
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900282 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900283
284 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
285 if (srcInstPort == null) {
Jian Li33b4db52019-03-20 18:22:38 +0900286 log.error(ERR_PACKET_IN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900287 eth.getSourceMAC());
288 return;
289 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900290
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
292 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
Jian Liebde74d2018-11-14 00:18:57 +0900293 IpAddress externalGatewayIp =
294 externalIpFromSubnet(srcSubnet, osRouterService, osNetworkService);
daniel parkb5817102018-02-15 00:18:51 +0900295
Hyunsun Moon44aac662017-02-18 02:07:01 +0900296 if (externalGatewayIp == null) {
297 return;
298 }
299
Jian Li5a26ab32019-03-21 15:20:01 +0900300 ExternalPeerRouter externalPeerRouter = externalPeerRouterFromSubnet(
301 srcSubnet, osRouterService, osNetworkService);
daniel park576969a2018-03-09 07:07:41 +0900302 if (externalPeerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900303 return;
304 }
305
Hyunsun Moon44aac662017-02-18 02:07:01 +0900306 populateSnatFlowRules(context.inPacket(),
307 srcInstPort,
308 TpPort.tpPort(patPort),
daniel park576969a2018-03-09 07:07:41 +0900309 externalGatewayIp, externalPeerRouter);
310
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311
Ray Milkeyf0c47612017-09-28 11:29:38 -0700312 packetOut(eth.duplicate(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900313 packetIn.receivedFrom().deviceId(),
314 patPort,
daniel park576969a2018-03-09 07:07:41 +0900315 externalGatewayIp, externalPeerRouter);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900316 }
317
318 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
319 Port osPort = osNetworkService.port(instance.portId());
320 IP fixedIp = osPort.getFixedIps().stream()
321 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
322 .findAny().orElse(null);
323 if (fixedIp == null) {
324 return null;
325 }
326 return osNetworkService.subnet(fixedIp.getSubnetId());
327 }
328
Jian Li5ecfd1a2018-12-10 11:41:03 +0900329 private void populateSnatFlowRules(InboundPacket packetIn,
330 InstancePort srcInstPort,
331 TpPort patPort, IpAddress externalIp,
332 ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900333 Network osNet = osNetworkService.network(srcInstPort.networkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900334 Type netType = osNetworkService.networkType(srcInstPort.networkId());
335
Hyunsun Moon44aac662017-02-18 02:07:01 +0900336 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900337 final String error = String.format("%s network %s not found",
Jian Li5a26ab32019-03-21 15:20:01 +0900338 ERR_PACKET_IN, srcInstPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900339 throw new IllegalStateException(error);
340 }
341
Jian Li5a26ab32019-03-21 15:20:01 +0900342 setStatelessSnatDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900343 osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900344 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900345 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900346 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900347 patPort,
348 packetIn);
349
Jian Li5a26ab32019-03-21 15:20:01 +0900350 setStatelessSnatUpstreamRules(osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900351 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900352 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900353 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354 patPort,
355 packetIn);
356 }
357
Jian Li5a26ab32019-03-21 15:20:01 +0900358 private void setStatelessSnatDownstreamRules(InstancePort srcInstPort,
359 String segmentId,
360 Type networkType,
361 IpAddress externalIp,
362 ExternalPeerRouter externalPeerRouter,
363 TpPort patPort,
364 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900365 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
366 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
367
368 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
369 .matchEthType(Ethernet.TYPE_IPV4)
370 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900371 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), VM_PREFIX))
372 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900373
374 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900375 .setEthDst(packetIn.parsed().getSourceMAC())
376 .setIpDst(internalIp);
377
Jian Li5e2ad4a2018-07-16 13:40:53 +0900378 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
379 sBuilder.matchVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900380 tBuilder.popVlan();
381 }
382
daniel parkee8700b2017-05-11 15:50:03 +0900383 switch (networkType) {
384 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900385 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900386 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900387 tBuilder.setTunnelId(Long.parseLong(segmentId));
388 break;
389 case VLAN:
390 tBuilder.pushVlan()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900391 .setVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900392 break;
393 default:
Jian Li71670d12018-03-02 21:31:07 +0900394 final String error = String.format("%s %s",
395 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900396 throw new IllegalStateException(error);
397 }
398
399
Hyunsun Moon44aac662017-02-18 02:07:01 +0900400 switch (iPacket.getProtocol()) {
401 case IPv4.PROTOCOL_TCP:
402 TCP tcpPacket = (TCP) iPacket.getPayload();
403 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
404 .matchTcpDst(patPort);
405 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
406 break;
407 case IPv4.PROTOCOL_UDP:
408 UDP udpPacket = (UDP) iPacket.getPayload();
409 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
410 .matchUdpDst(patPort);
411 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
412 break;
413 default:
414 break;
415 }
416
Hyunsun Moon0d457362017-06-27 17:19:41 +0900417 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
418 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Jian Li6a47fd02018-11-27 21:51:03 +0900419 TrafficTreatment treatment =
Jian Li5a26ab32019-03-21 15:20:01 +0900420 getDownstreamTreatment(networkType, tBuilder, gNode, srcNode);
sanghodc375372017-06-08 10:41:30 +0900421 osFlowRuleService.setRule(
422 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900423 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900424 sBuilder.build(),
Jian Li6a47fd02018-11-27 21:51:03 +0900425 treatment,
sanghodc375372017-06-08 10:41:30 +0900426 PRIORITY_SNAT_RULE,
427 GW_COMMON_TABLE,
428 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900429 });
430 }
431
Jian Li5a26ab32019-03-21 15:20:01 +0900432 private TrafficTreatment getDownstreamTreatment(Type networkType,
Jian Li6a47fd02018-11-27 21:51:03 +0900433 TrafficTreatment.Builder tBuilder,
434 OpenstackNode gNode,
435 OpenstackNode srcNode) {
436 TrafficTreatment.Builder tmpBuilder =
437 DefaultTrafficTreatment.builder(tBuilder.build());
438 switch (networkType) {
439 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900440 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900441 case GENEVE:
SONA Project6bc5c4a2018-12-14 23:49:52 +0900442 PortNumber portNum = tunnelPortNumByNetType(networkType, gNode);
Jian Li6a47fd02018-11-27 21:51:03 +0900443 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
444 deviceService,
445 gNode.intgBridge(),
446 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900447 .setOutput(portNum);
Jian Li6a47fd02018-11-27 21:51:03 +0900448 break;
449 case VLAN:
450 tmpBuilder.setOutput(gNode.vlanPortNum());
451 break;
452 default:
453 final String error = String.format("%s %s",
454 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
455 throw new IllegalStateException(error);
456 }
457
458 return tmpBuilder.build();
459 }
460
Jian Li5a26ab32019-03-21 15:20:01 +0900461 private void setStatelessSnatUpstreamRules(String segmentId,
462 Type networkType,
463 IpAddress externalIp,
464 ExternalPeerRouter externalPeerRouter,
465 TpPort patPort,
466 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900467 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900468
469 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900470 .matchEthType(Ethernet.TYPE_IPV4)
471 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900472 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), VM_PREFIX))
473 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900474
475 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900476
477 switch (networkType) {
478 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900479 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900480 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900481 sBuilder.matchTunnelId(Long.parseLong(segmentId));
482 break;
483 case VLAN:
484 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
485 tBuilder.popVlan();
486 break;
487 default:
Jian Li71670d12018-03-02 21:31:07 +0900488 final String error = String.format("%s %s",
489 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900490 throw new IllegalStateException(error);
491 }
492
Hyunsun Moon44aac662017-02-18 02:07:01 +0900493 switch (iPacket.getProtocol()) {
494 case IPv4.PROTOCOL_TCP:
495 TCP tcpPacket = (TCP) iPacket.getPayload();
496 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
497 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900498 tBuilder.setTcpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499 break;
500 case IPv4.PROTOCOL_UDP:
501 UDP udpPacket = (UDP) iPacket.getPayload();
502 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
503 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900504 tBuilder.setUdpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900505 break;
506 default:
507 log.debug("Unsupported IPv4 protocol {}");
508 break;
509 }
510
Jian Li5e2ad4a2018-07-16 13:40:53 +0900511 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
512 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900513 }
514
Hyunsun Moon44aac662017-02-18 02:07:01 +0900515 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900516 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517 TrafficTreatment.Builder tmpBuilder =
518 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900519 tmpBuilder.setOutput(gNode.uplinkPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900520
sanghodc375372017-06-08 10:41:30 +0900521 osFlowRuleService.setRule(
522 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900523 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900524 sBuilder.build(),
525 tmpBuilder.build(),
526 PRIORITY_SNAT_RULE,
527 GW_COMMON_TABLE,
528 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900529 });
530 }
531
532 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
daniel park576969a2018-03-09 07:07:41 +0900533 IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900534 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900535 switch (iPacket.getProtocol()) {
536 case IPv4.PROTOCOL_TCP:
Jian Li6a47fd02018-11-27 21:51:03 +0900537 iPacket.setPayload(buildPacketOutTcp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900538 break;
539 case IPv4.PROTOCOL_UDP:
Jian Li6a47fd02018-11-27 21:51:03 +0900540 iPacket.setPayload(buildPacketOutUdp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900541 break;
542 default:
543 log.trace("Temporally, this method can process UDP and TCP protocol.");
544 return;
545 }
546
547 iPacket.setSourceAddress(externalIp.toString());
548 iPacket.resetChecksum();
549 iPacket.setParent(ethPacketIn);
daniel park576969a2018-03-09 07:07:41 +0900550 ethPacketIn.setSourceMACAddress(DEFAULT_GATEWAY_MAC);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900551 ethPacketIn.setDestinationMACAddress(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900552 ethPacketIn.setPayload(iPacket);
daniel park576969a2018-03-09 07:07:41 +0900553
Jian Li5e2ad4a2018-07-16 13:40:53 +0900554 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
555 ethPacketIn.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900556 }
557
daniel parkee8700b2017-05-11 15:50:03 +0900558 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559
Hyunsun Moon0d457362017-06-27 17:19:41 +0900560 OpenstackNode srcNode = osNodeService.node(srcDevice);
561 if (srcNode == null) {
562 final String error = String.format("Cannot find openstack node for %s",
563 srcDevice);
564 throw new IllegalStateException(error);
565 }
daniel parkee8700b2017-05-11 15:50:03 +0900566
daniel park576969a2018-03-09 07:07:41 +0900567 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
568
Hyunsun Moon44aac662017-02-18 02:07:01 +0900569 packetService.emit(new DefaultOutboundPacket(
570 srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900571 tBuilder.setOutput(srcNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900572 ByteBuffer.wrap(ethPacketIn.serialize())));
573 }
574
Jian Li6a47fd02018-11-27 21:51:03 +0900575 private TCP buildPacketOutTcp(IPv4 iPacket, int patPort) {
576 TCP tcpPacket = (TCP) iPacket.getPayload();
577 tcpPacket.setSourcePort(patPort);
578 tcpPacket.resetChecksum();
579 tcpPacket.setParent(iPacket);
580
581 return tcpPacket;
582 }
583
584 private UDP buildPacketOutUdp(IPv4 iPacket, int patPort) {
585 UDP udpPacket = (UDP) iPacket.getPayload();
586 udpPacket.setSourcePort(patPort);
587 udpPacket.resetChecksum();
588 udpPacket.setParent(iPacket);
589
590 return udpPacket;
591 }
592
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900593 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900594 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900595 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900596 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900597 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900598 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900599 unUsedPortNumSet.remove(portNum);
600 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900601 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900602 return portNum;
603 }
604
605 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900606 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900607 }
608
609 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900610 allocatedPortNumMap.entrySet().forEach(e -> {
Jian Li5a26ab32019-03-21 15:20:01 +0900611 if (System.currentTimeMillis() -
612 e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900613 allocatedPortNumMap.remove(e.getKey());
614 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900615 }
616 });
617 }
618
Jian Li33b4db52019-03-20 18:22:38 +0900619 private void initializeUnusedPortNumSet() {
620 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
621 if (!allocatedPortNumMap.containsKey(i)) {
622 unUsedPortNumSet.add(i);
623 }
624 }
625
626 clearPortNumMap();
627 }
628
629 private void resetSnatRules() {
630 if (useStatefulSnat) {
631 osRouterService.routerInterfaces().forEach(
632 routerIface -> {
633 setReactiveSnatRules(routerIface, false);
634 setStatefulSnatRules(routerIface, true);
635 }
636 );
637 } else {
638 osRouterService.routerInterfaces().forEach(
639 routerIface -> {
640 setStatefulSnatRules(routerIface, false);
641 setReactiveSnatRules(routerIface, true);
642 }
643 );
644 }
645 }
646
647 private void setRulesToGateway(OpenstackNode osNode,
648 String segmentId,
649 IpPrefix srcSubnet,
650 Type networkType,
651 boolean install) {
Jian Li5a26ab32019-03-21 15:20:01 +0900652 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY)
653 .stream().findFirst().orElse(null);
Jian Li33b4db52019-03-20 18:22:38 +0900654
655 if (sourceNatGateway == null) {
656 return;
657 }
658
659 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
660 .matchEthType(Ethernet.TYPE_IPV4)
661 .matchIPSrc(srcSubnet.getIp4Prefix())
662 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
663
664 switch (networkType) {
665 case VXLAN:
666 case GRE:
667 case GENEVE:
668 sBuilder.matchTunnelId(Long.parseLong(segmentId));
669 break;
670 case VLAN:
671 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
672 break;
673 default:
674 final String error = String.format("%s %s",
675 ERR_UNSUPPORTED_NET_TYPE,
676 networkType.toString());
677 throw new IllegalStateException(error);
678 }
679
680 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
681
682 switch (networkType) {
683 case VXLAN:
684 case GRE:
685 case GENEVE:
686 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
687 tBuilder.extension(buildExtension(
688 deviceService,
689 osNode.intgBridge(),
690 sourceNatGateway.dataIp().getIp4Address()),
691 osNode.intgBridge())
692 .setOutput(portNum);
693 break;
694
695 case VLAN:
696 tBuilder.setOutput(osNode.vlanPortNum());
697 break;
698
699 default:
700 break;
701 }
702
703 osFlowRuleService.setRule(
704 appId,
705 osNode.intgBridge(),
706 sBuilder.build(),
707 tBuilder.build(),
708 PRIORITY_EXTERNAL_ROUTING_RULE,
709 ROUTING_TABLE,
710 install);
711 }
712
713
714 private void routerUpdated(Router osRouter) {
715 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
716
717 ExternalPeerRouter externalPeerRouter =
718 osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5a26ab32019-03-21 15:20:01 +0900719 VlanId vlanId = externalPeerRouter == null ?
720 VlanId.NONE : externalPeerRouter.vlanId();
Jian Li33b4db52019-03-20 18:22:38 +0900721
722 if (exGateway == null) {
723 deleteUnassociatedExternalPeerRouter();
724 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
725 setSourceNat(iface, false));
726 } else {
727 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
728 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
729 setSourceNat(iface, exGateway.isEnableSnat()));
730 }
731 }
732
733 private void deleteUnassociatedExternalPeerRouter() {
734 log.trace("Deleting unassociated external peer router");
735
736 try {
737 Set<String> routerIps = Sets.newConcurrentHashSet();
738
739 osRouterService.routers().stream()
740 .filter(router -> getGatewayIpAddress(router) != null)
741 .map(router -> getGatewayIpAddress(router).toString())
742 .forEach(routerIps::add);
743
744 osNetworkAdminService.externalPeerRouters().stream()
745 .filter(externalPeerRouter ->
746 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
747 .forEach(externalPeerRouter -> {
748 osNetworkAdminService
749 .deleteExternalPeerRouter(
750 externalPeerRouter.ipAddress().toString());
751 log.trace("Deleted unassociated external peer router {}",
752 externalPeerRouter.ipAddress().toString());
753 });
754 } catch (Exception e) {
755 log.error("Exception occurred because of {}", e.toString());
756 }
757 }
758
759 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
760 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
761 if (exGateway != null && exGateway.isEnableSnat()) {
762 setSourceNat(osRouterIface, true);
763 }
764 }
765
766 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
767 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
768 if (exGateway != null && exGateway.isEnableSnat()) {
769 setSourceNat(osRouterIface, false);
770 }
771 }
772
773 private void setSourceNat(RouterInterface routerIface, boolean install) {
774 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
775 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
776 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
777
778 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
779 setRulesToGateway(cNode, osNet.getProviderSegID(),
780 IpPrefix.valueOf(osSubnet.getCidr()), netType, install);
781 });
782
783 if (useStatefulSnat) {
784 setStatefulSnatRules(routerIface, install);
785 } else {
786 setReactiveSnatRules(routerIface, install);
787 }
788
789 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
790 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
791 }
792
793 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
794 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
795 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
796 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
797
798 if (netType == FLAT) {
799 return;
800 }
801
802 Optional<Router> osRouter = osRouterService.routers().stream()
803 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
804 .findAny();
805
806 if (!osRouter.isPresent()) {
807 log.error("Cannot find a router for router interface {} ", routerIface);
808 return;
809 }
Jian Li5a26ab32019-03-21 15:20:01 +0900810
811 IpAddress natAddress = getExternalIp(osRouter.get(), osNetworkService);
Jian Li33b4db52019-03-20 18:22:38 +0900812 if (natAddress == null) {
813 return;
814 }
Jian Li5a26ab32019-03-21 15:20:01 +0900815
816 IpAddress extRouterAddress = getGatewayIpAddress(osRouter.get());
817 if (extRouterAddress == null) {
818 return;
819 }
820
821 ExternalPeerRouter externalPeerRouter =
822 osNetworkService.externalPeerRouter(extRouterAddress);
823 if (externalPeerRouter == null) {
824 return;
825 }
826
Jian Li33b4db52019-03-20 18:22:38 +0900827 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
828
Jian Li5a26ab32019-03-21 15:20:01 +0900829 Map<OpenstackNode, PortRange> gwPortRangeMap = getAssignedPortsForGateway(
Jian Li25257212019-03-26 13:31:14 +0900830 ImmutableList.copyOf(osNodeService.nodes(GATEWAY)));
Jian Li5a26ab32019-03-21 15:20:01 +0900831
Jian Li33b4db52019-03-20 18:22:38 +0900832 osNodeService.completeNodes(GATEWAY)
833 .forEach(gwNode -> {
834 instancePortService.instancePorts(netId)
835 .stream()
836 .filter(port -> port.state() == ACTIVE)
Jian Li5a26ab32019-03-21 15:20:01 +0900837 .forEach(port -> setGatewayToInstanceDownstreamRule(
838 gwNode, port, install));
Jian Li33b4db52019-03-20 18:22:38 +0900839
Jian Li5a26ab32019-03-21 15:20:01 +0900840 setStatefulSnatDownstreamRule(gwNode.intgBridge(),
841 IpPrefix.valueOf(natAddress, VM_PREFIX), install);
Jian Li33b4db52019-03-20 18:22:38 +0900842
Jian Lia2995192019-04-02 14:13:04 +0900843 if (install) {
844 PortRange gwPortRange = gwPortRangeMap.get(gwNode);
Jian Li5a26ab32019-03-21 15:20:01 +0900845
Jian Lia2995192019-04-02 14:13:04 +0900846 Map<String, PortRange> netPortRangeMap =
847 getAssignedPortsForNet(getNetIdByRouterId(routerIface.getId()),
848 gwPortRange.min(), gwPortRange.max());
Jian Li5a26ab32019-03-21 15:20:01 +0900849
Jian Lia2995192019-04-02 14:13:04 +0900850 PortRange netPortRange = netPortRangeMap.get(osNet.getId());
Jian Li5a26ab32019-03-21 15:20:01 +0900851
Jian Lia2995192019-04-02 14:13:04 +0900852 setStatefulSnatUpstreamRule(gwNode, natAddress,
853 Long.parseLong(osNet.getProviderSegID()),
854 externalPeerRouter, netPortRange.min(),
855 netPortRange.max(), install);
856 } else {
857 setStatefulSnatUpstreamRule(gwNode, natAddress,
858 Long.parseLong(osNet.getProviderSegID()),
859 externalPeerRouter, 0, 0, install);
860 }
861
Jian Li33b4db52019-03-20 18:22:38 +0900862 });
863 }
864
Jian Li5a26ab32019-03-21 15:20:01 +0900865 private List<String> getNetIdByRouterId(String routerId) {
866 return osRouterService.routerInterfaces(routerId)
867 .stream()
868 .filter(ri -> osRouterService.router(ri.getId())
869 .getExternalGatewayInfo().isEnableSnat())
870 .map(RouterInterface::getSubnetId)
871 .map(si -> osNetworkAdminService.subnet(si))
872 .map(Subnet::getNetworkId)
873 .collect(Collectors.toList());
874 }
875
876 private Map<OpenstackNode, PortRange>
877 getAssignedPortsForGateway(List<OpenstackNode> gateways) {
878
879 Map<OpenstackNode, PortRange> gwPortRangeMap = Maps.newConcurrentMap();
880
881 int portRangeNumPerGwNode =
882 (TP_PORT_MAXIMUM_NUM - TP_PORT_MINIMUM_NUM + 1) / gateways.size();
883
884 for (int i = 0; i < gateways.size(); i++) {
885 int gwPortRangeMin = TP_PORT_MINIMUM_NUM + i * portRangeNumPerGwNode;
886 int gwPortRangeMax = TP_PORT_MINIMUM_NUM + (i + 1) * portRangeNumPerGwNode - 1;
887
888 gwPortRangeMap.put(gateways.get(i),
889 new PortRange(gwPortRangeMin, gwPortRangeMax));
890 }
891
892 return gwPortRangeMap;
893 }
894
895 private Map<String, PortRange> getAssignedPortsForNet(List<String> netIds,
896 int min, int max) {
897
898 Map<String, PortRange> netPortRangeMap = Maps.newConcurrentMap();
899
900 int portRangeNumPerNet = (max - min + 1) / netIds.size();
901
902 for (int i = 0; i < netIds.size(); i++) {
903 int netPortRangeMin = min + i * portRangeNumPerNet;
904 int netPortRangeMax = min + (i + 1) * portRangeNumPerNet - 1;
905
906 netPortRangeMap.put(netIds.get(i),
907 new PortRange(netPortRangeMin, netPortRangeMax));
908 }
909
910 return netPortRangeMap;
911 }
912
Jian Li33b4db52019-03-20 18:22:38 +0900913 private IpAddress getGatewayIpAddress(Router osRouter) {
914
915 if (osRouter.getExternalGatewayInfo() == null) {
916 return null;
917 }
918 String extNetId = osNetworkAdminService.network(
919 osRouter.getExternalGatewayInfo().getNetworkId()).getId();
920 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
921 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
922 .findAny();
923
924 if (!extSubnet.isPresent()) {
Jian Li5a26ab32019-03-21 15:20:01 +0900925 log.error("Cannot find external subnet for the router");
Jian Li33b4db52019-03-20 18:22:38 +0900926 return null;
927 }
928
929 return IpAddress.valueOf(extSubnet.get().getGateway());
930 }
931
932 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
933 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
934 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
935 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
936
937 osNodeService.completeNodes(GATEWAY)
938 .forEach(gwNode -> setRulesToController(
939 gwNode.intgBridge(),
940 osNet.getProviderSegID(),
941 IpPrefix.valueOf(osSubnet.getCidr()),
942 netType,
943 install));
944 }
945
Jian Li5a26ab32019-03-21 15:20:01 +0900946 private void setGatewayToInstanceDownstreamRule(OpenstackNode gwNode,
947 InstancePort instPort,
948 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +0900949
950 TrafficSelector selector = DefaultTrafficSelector.builder()
951 .matchEthType(Ethernet.TYPE_IPV4)
Jian Li5a26ab32019-03-21 15:20:01 +0900952 .matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX))
953 .build();
954
955 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
956 .setEthDst(instPort.macAddress());
957
958 Type netType = osNetworkAdminService.networkType(instPort.networkId());
959 String segId = osNetworkAdminService.segmentId(instPort.networkId());
960
961 switch (netType) {
962 case VXLAN:
963 case GRE:
964 case GENEVE:
965 tBuilder.setTunnelId(Long.valueOf(segId));
966 break;
967 case VLAN:
968 default:
969 final String error = String.format("%s %s",
970 ERR_UNSUPPORTED_NET_TYPE, netType.name());
971 throw new IllegalStateException(error);
972 }
973
974 OpenstackNode srcNode = osNodeService.node(instPort.deviceId());
975 TrafficTreatment treatment =
976 getDownstreamTreatment(netType, tBuilder, gwNode, srcNode);
977
978 osFlowRuleService.setRule(
979 appId,
980 gwNode.intgBridge(),
981 selector,
982 treatment,
983 PRIORITY_STATEFUL_SNAT_RULE,
984 GW_COMMON_TABLE,
985 install);
986 }
987
988 private void setStatefulSnatDownstreamRule(DeviceId deviceId,
989 IpPrefix gatewayIp,
990 boolean install) {
991
992 TrafficSelector selector = DefaultTrafficSelector.builder()
993 .matchEthType(Ethernet.TYPE_IPV4)
994 .matchIPDst(gatewayIp)
Jian Li33b4db52019-03-20 18:22:38 +0900995 .build();
996
997 ExtensionTreatment natTreatment = RulePopulatorUtil
998 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
999 .commit(false)
1000 .natAction(true)
1001 .table((short) 0)
1002 .build();
1003
1004 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li33b4db52019-03-20 18:22:38 +09001005 .extension(natTreatment, deviceId)
1006 .build();
1007
1008 osFlowRuleService.setRule(
1009 appId,
1010 deviceId,
1011 selector,
1012 treatment,
1013 PRIORITY_STATEFUL_SNAT_RULE,
1014 GW_COMMON_TABLE,
1015 install);
1016 }
1017
Jian Li5a26ab32019-03-21 15:20:01 +09001018 private void setStatefulSnatUpstreamRule(OpenstackNode gwNode,
1019 IpAddress gatewayIp,
1020 long vni,
1021 ExternalPeerRouter extPeerRouter,
1022 int minPortNum,
1023 int maxPortNum,
1024 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +09001025
1026 TrafficSelector selector = DefaultTrafficSelector.builder()
1027 .matchEthType(Ethernet.TYPE_IPV4)
1028 .matchEthDst(DEFAULT_GATEWAY_MAC)
1029 .matchTunnelId(vni)
1030 .build();
1031
Jian Lia2995192019-04-02 14:13:04 +09001032 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li33b4db52019-03-20 18:22:38 +09001033
Jian Lia2995192019-04-02 14:13:04 +09001034 // we do not consider to much like port range on removing the rules...
1035 if (install) {
1036 ExtensionTreatment natTreatment = RulePopulatorUtil
1037 .niciraConnTrackTreatmentBuilder(driverService, gwNode.intgBridge())
1038 .commit(true)
1039 .natFlag(CT_NAT_SRC_FLAG)
1040 .natAction(true)
1041 .natIp(gatewayIp)
1042 .natPortMin(TpPort.tpPort(minPortNum))
1043 .natPortMax(TpPort.tpPort(maxPortNum))
1044 .build();
1045
1046 tBuilder.extension(natTreatment, gwNode.intgBridge())
1047 .setEthDst(extPeerRouter.macAddress())
1048 .setEthSrc(DEFAULT_GATEWAY_MAC)
1049 .setOutput(gwNode.uplinkPortNum());
1050 }
Jian Li33b4db52019-03-20 18:22:38 +09001051
1052 osFlowRuleService.setRule(
1053 appId,
Jian Li5a26ab32019-03-21 15:20:01 +09001054 gwNode.intgBridge(),
Jian Li33b4db52019-03-20 18:22:38 +09001055 selector,
Jian Lia2995192019-04-02 14:13:04 +09001056 tBuilder.build(),
Jian Li33b4db52019-03-20 18:22:38 +09001057 PRIORITY_STATEFUL_SNAT_RULE,
1058 GW_COMMON_TABLE,
1059 install);
1060 }
1061
Jian Li33b4db52019-03-20 18:22:38 +09001062 private void setRulesToController(DeviceId deviceId,
1063 String segmentId,
1064 IpPrefix srcSubnet,
1065 Type networkType,
1066 boolean install) {
1067 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
1068 .matchEthType(Ethernet.TYPE_IPV4)
1069 .matchIPSrc(srcSubnet)
1070 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
1071
1072 switch (networkType) {
1073 case VXLAN:
1074 case GRE:
1075 case GENEVE:
1076 sBuilder.matchTunnelId(Long.parseLong(segmentId));
1077 break;
1078 case VLAN:
1079 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
1080 break;
1081 default:
1082 final String error = String.format("%s %s",
1083 ERR_UNSUPPORTED_NET_TYPE,
1084 networkType.toString());
1085 throw new IllegalStateException(error);
1086 }
1087
1088 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1089
1090 if (networkType == VLAN) {
1091 tBuilder.popVlan();
1092 }
1093
1094 tBuilder.punt();
1095
1096 osFlowRuleService.setRule(
1097 appId,
1098 deviceId,
1099 sBuilder.build(),
1100 tBuilder.build(),
1101 PRIORITY_EXTERNAL_ROUTING_RULE,
1102 GW_COMMON_TABLE,
1103 install);
1104 }
1105
1106 private class InternalInstancePortListener implements InstancePortListener {
1107
1108 private boolean isRelevantHelper(InstancePortEvent event) {
1109 return mastershipService.isLocalMaster(event.subject().deviceId());
1110 }
1111
1112 @Override
1113 public void event(InstancePortEvent event) {
1114 InstancePort instPort = event.subject();
1115 switch (event.type()) {
1116 case OPENSTACK_INSTANCE_PORT_DETECTED:
1117 case OPENSTACK_INSTANCE_PORT_UPDATED:
1118 eventExecutor.execute(() ->
1119 processInstancePortDetection(event, instPort));
1120 break;
1121 case OPENSTACK_INSTANCE_PORT_VANISHED:
1122 eventExecutor.execute(() ->
1123 processInstancePortRemoval(event, instPort));
1124 break;
1125 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1126 eventExecutor.execute(() ->
1127 processInstanceMigrationStart(event, instPort));
1128 break;
1129 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1130 eventExecutor.execute(() ->
1131 processInstanceMigrationEnd(event, instPort));
1132 break;
1133 default:
1134 break;
1135 }
1136 }
1137
1138 private void processInstancePortDetection(InstancePortEvent event,
1139 InstancePort instPort) {
1140 if (!isRelevantHelper(event)) {
1141 return;
1142 }
1143
1144 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1145 instPort.macAddress(),
1146 instPort.ipAddress());
1147
1148 instPortDetected(event.subject());
1149 }
1150
1151 private void processInstancePortRemoval(InstancePortEvent event,
1152 InstancePort instPort) {
1153 if (!isRelevantHelper(event)) {
1154 return;
1155 }
1156
1157 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1158 instPort.macAddress(),
1159 instPort.ipAddress());
1160
1161 instPortRemoved(event.subject());
1162 }
1163
1164 private void processInstanceMigrationStart(InstancePortEvent event,
1165 InstancePort instPort) {
1166 if (!isRelevantHelper(event)) {
1167 return;
1168 }
1169
1170 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1171 instPort.macAddress(),
1172 instPort.ipAddress());
1173
1174 instPortDetected(instPort);
1175 }
1176
1177 private void processInstanceMigrationEnd(InstancePortEvent event,
1178 InstancePort instPort) {
1179 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1180 instPort.macAddress(),
1181 instPort.ipAddress());
1182 // TODO: need to reconfigure rules to point to update VM
1183 }
1184
1185 private void instPortDetected(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001186 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1187
1188 if (netType == FLAT) {
1189 return;
1190 }
1191
1192 if (useStatefulSnat) {
Jian Li5a26ab32019-03-21 15:20:01 +09001193 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1194 setGatewayToInstanceDownstreamRule(gwNode, instPort, true));
Jian Li33b4db52019-03-20 18:22:38 +09001195 }
1196 }
1197
1198 private void instPortRemoved(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001199 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1200
1201 if (netType == FLAT) {
1202 return;
1203 }
1204
1205 if (useStatefulSnat) {
Jian Li5a26ab32019-03-21 15:20:01 +09001206 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1207 setGatewayToInstanceDownstreamRule(gwNode, instPort, false));
Jian Li33b4db52019-03-20 18:22:38 +09001208 }
1209 }
1210 }
1211
1212 private class InternalRouterEventListener implements OpenstackRouterListener {
1213
1214 private boolean isRelevantHelper() {
1215 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1216 }
1217
1218 @Override
1219 public void event(OpenstackRouterEvent event) {
1220 switch (event.type()) {
1221 case OPENSTACK_ROUTER_CREATED:
1222 eventExecutor.execute(() -> processRouterCreation(event));
1223 break;
1224 case OPENSTACK_ROUTER_UPDATED:
1225 eventExecutor.execute(() -> processRouterUpdate(event));
1226 break;
1227 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1228 eventExecutor.execute(() -> processRouterIntfCreation(event));
1229 break;
1230 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1231 eventExecutor.execute(() -> processRouterIntfRemoval(event));
1232 break;
1233 case OPENSTACK_ROUTER_GATEWAY_ADDED:
1234 log.debug("Router external gateway {} added",
1235 event.externalGateway().getNetworkId());
1236 break;
1237 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
1238 log.debug("Router external gateway {} removed",
1239 event.externalGateway().getNetworkId());
1240 break;
1241 default:
1242 break;
1243 }
1244 }
1245
1246 private void processRouterCreation(OpenstackRouterEvent event) {
1247 if (!isRelevantHelper()) {
1248 return;
1249 }
1250
1251 log.debug("Router(name:{}, ID:{}) is created",
1252 event.subject().getName(),
1253 event.subject().getId());
1254
1255 routerUpdated(event.subject());
1256 }
1257
1258 private void processRouterUpdate(OpenstackRouterEvent event) {
1259 if (!isRelevantHelper()) {
1260 return;
1261 }
1262
1263 log.debug("Router(name:{}, ID:{}) is updated",
1264 event.subject().getName(),
1265 event.subject().getId());
1266
1267 routerUpdated(event.subject());
1268 }
1269
1270 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1271 if (!isRelevantHelper()) {
1272 return;
1273 }
1274
1275 log.debug("Router interface {} added to router {}",
1276 event.routerIface().getPortId(),
1277 event.routerIface().getId());
1278
1279 routerIfaceAdded(event.subject(), event.routerIface());
1280 }
1281
1282 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1283 if (!isRelevantHelper()) {
1284 return;
1285 }
1286
1287 log.debug("Router interface {} removed from router {}",
1288 event.routerIface().getPortId(),
1289 event.routerIface().getId());
1290
1291 routerIfaceRemoved(event.subject(), event.routerIface());
1292 }
1293 }
1294
Hyunsun Moon44aac662017-02-18 02:07:01 +09001295 private class InternalPacketProcessor implements PacketProcessor {
1296
1297 @Override
1298 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +09001299
Hyunsun Moon44aac662017-02-18 02:07:01 +09001300 if (context.isHandled()) {
1301 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001302 }
1303
1304 InboundPacket pkt = context.inPacket();
1305 Ethernet eth = pkt.parsed();
1306 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
1307 return;
1308 }
1309
1310 IPv4 iPacket = (IPv4) eth.getPayload();
1311 switch (iPacket.getProtocol()) {
1312 case IPv4.PROTOCOL_ICMP:
1313 break;
1314 case IPv4.PROTOCOL_UDP:
1315 UDP udpPacket = (UDP) iPacket.getPayload();
1316 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
1317 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
Jian Li6a47fd02018-11-27 21:51:03 +09001318 break; // don't process DHCP
Hyunsun Moon44aac662017-02-18 02:07:01 +09001319 }
1320 default:
Jian Li34220ea2018-11-14 01:30:24 +09001321 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001322 if (!isRelevantHelper(context)) {
1323 return;
1324 }
Jian Li34220ea2018-11-14 01:30:24 +09001325 processSnatPacket(context, eth);
1326 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001327 break;
1328 }
1329 }
Jian Li34220ea2018-11-14 01:30:24 +09001330
1331 private boolean isRelevantHelper(PacketContext context) {
1332 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
1333 .stream().map(OpenstackNode::intgBridge)
1334 .collect(Collectors.toSet());
1335
1336 return gateways.contains(context.inPacket().receivedFrom().deviceId());
1337 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001338 }
Jian Li33b4db52019-03-20 18:22:38 +09001339
1340 private class InternalNodeEventListener implements OpenstackNodeListener {
1341
1342 private boolean isRelevantHelper() {
1343 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1344 }
1345
1346 @Override
1347 public void event(OpenstackNodeEvent event) {
1348 OpenstackNode osNode = event.subject();
1349 switch (event.type()) {
1350 case OPENSTACK_NODE_COMPLETE:
Jian Li5a26ab32019-03-21 15:20:01 +09001351 eventExecutor.execute(() -> processGatewayCompletion(osNode));
1352 eventExecutor.execute(() -> reconfigureRouters(osNode));
1353 break;
1354 case OPENSTACK_NODE_REMOVED:
1355 eventExecutor.execute(() -> processGatewayRemoval(osNode));
Jian Li5d795f22019-04-01 23:07:40 +09001356 eventExecutor.execute(() -> reconfigureRouters(osNode));
1357 break;
Jian Li33b4db52019-03-20 18:22:38 +09001358 case OPENSTACK_NODE_INCOMPLETE:
1359 case OPENSTACK_NODE_UPDATED:
Jian Li5a26ab32019-03-21 15:20:01 +09001360 eventExecutor.execute(() -> reconfigureRouters(osNode));
Jian Li33b4db52019-03-20 18:22:38 +09001361 break;
1362 case OPENSTACK_NODE_CREATED:
1363 default:
1364 break;
1365 }
1366 }
1367
Jian Li5a26ab32019-03-21 15:20:01 +09001368 private void processGatewayCompletion(OpenstackNode osNode) {
1369 if (!isRelevantHelper()) {
1370 return;
1371 }
1372
1373 if (useStatefulSnat && osNode.type() == GATEWAY) {
1374 instancePortService.instancePorts().forEach(instPort ->
1375 setGatewayToInstanceDownstreamRule(osNode, instPort, true));
1376 }
1377 }
1378
1379 private void processGatewayRemoval(OpenstackNode osNode) {
1380 if (!isRelevantHelper()) {
1381 return;
1382 }
1383
1384 if (useStatefulSnat && osNode.type() == GATEWAY) {
1385 instancePortService.instancePorts().forEach(instPort ->
1386 setGatewayToInstanceDownstreamRule(osNode, instPort, false));
1387 }
1388 }
1389
Jian Li33b4db52019-03-20 18:22:38 +09001390 private void reconfigureRouters(OpenstackNode osNode) {
Jian Li5a26ab32019-03-21 15:20:01 +09001391 if (!isRelevantHelper()) {
1392 return;
1393 }
1394
Jian Li33b4db52019-03-20 18:22:38 +09001395 osRouterService.routers().forEach(osRouter -> {
1396 routerUpdated(osRouter);
1397 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1398 routerIfaceAdded(osRouter, iface);
1399 });
1400 });
1401 log.info("Reconfigure routers for {}", osNode.hostname());
1402 }
1403 }
Jian Li5a26ab32019-03-21 15:20:01 +09001404
1405 private class PortRange {
1406 private int min;
1407 private int max;
1408
1409 /**
1410 * A default constructor.
1411 *
1412 * @param min min port num
1413 * @param max max port num
1414 */
1415 public PortRange(int min, int max) {
1416 this.min = min;
1417 this.max = max;
1418 }
1419
1420 /**
1421 * Obtains min port num.
1422 *
1423 * @return min port num
1424 */
1425 int min() {
1426 return min;
1427 }
1428
1429 /**
1430 * Obtains max port num.
1431 *
1432 * @return max port num
1433 */
1434 int max() {
1435 return max;
1436 }
1437
1438 @Override
1439 public String toString() {
1440 return MoreObjects.toStringHelper(this)
1441 .add("min", min)
1442 .add("max", max)
1443 .toString();
1444 }
1445
1446 @Override
1447 public boolean equals(Object o) {
1448 if (this == o) {
1449 return true;
1450 }
1451 if (o == null || getClass() != o.getClass()) {
1452 return false;
1453 }
1454 PortRange portRange = (PortRange) o;
1455 return min == portRange.min &&
1456 max == portRange.max;
1457 }
1458
1459 @Override
1460 public int hashCode() {
1461 return Objects.hash(min, max);
1462 }
1463 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001464}