blob: 07cad1e2ccc4f2ef55dba45aacaff733ac1d3fb5 [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 Li5a26ab32019-03-21 15:20:01 +0900843 PortRange gwPortRange = gwPortRangeMap.get(gwNode);
844
845 Map<String, PortRange> netPortRangeMap =
846 getAssignedPortsForNet(getNetIdByRouterId(routerIface.getId()),
847 gwPortRange.min(), gwPortRange.max());
848
849 PortRange netPortRange = netPortRangeMap.get(osNet.getId());
850
851 setStatefulSnatUpstreamRule(gwNode, natAddress,
852 Long.parseLong(osNet.getProviderSegID()),
853 externalPeerRouter, netPortRange.min(),
854 netPortRange.max(), install);
Jian Li33b4db52019-03-20 18:22:38 +0900855 });
856 }
857
Jian Li5a26ab32019-03-21 15:20:01 +0900858 private List<String> getNetIdByRouterId(String routerId) {
859 return osRouterService.routerInterfaces(routerId)
860 .stream()
861 .filter(ri -> osRouterService.router(ri.getId())
862 .getExternalGatewayInfo().isEnableSnat())
863 .map(RouterInterface::getSubnetId)
864 .map(si -> osNetworkAdminService.subnet(si))
865 .map(Subnet::getNetworkId)
866 .collect(Collectors.toList());
867 }
868
869 private Map<OpenstackNode, PortRange>
870 getAssignedPortsForGateway(List<OpenstackNode> gateways) {
871
872 Map<OpenstackNode, PortRange> gwPortRangeMap = Maps.newConcurrentMap();
873
874 int portRangeNumPerGwNode =
875 (TP_PORT_MAXIMUM_NUM - TP_PORT_MINIMUM_NUM + 1) / gateways.size();
876
877 for (int i = 0; i < gateways.size(); i++) {
878 int gwPortRangeMin = TP_PORT_MINIMUM_NUM + i * portRangeNumPerGwNode;
879 int gwPortRangeMax = TP_PORT_MINIMUM_NUM + (i + 1) * portRangeNumPerGwNode - 1;
880
881 gwPortRangeMap.put(gateways.get(i),
882 new PortRange(gwPortRangeMin, gwPortRangeMax));
883 }
884
885 return gwPortRangeMap;
886 }
887
888 private Map<String, PortRange> getAssignedPortsForNet(List<String> netIds,
889 int min, int max) {
890
891 Map<String, PortRange> netPortRangeMap = Maps.newConcurrentMap();
892
893 int portRangeNumPerNet = (max - min + 1) / netIds.size();
894
895 for (int i = 0; i < netIds.size(); i++) {
896 int netPortRangeMin = min + i * portRangeNumPerNet;
897 int netPortRangeMax = min + (i + 1) * portRangeNumPerNet - 1;
898
899 netPortRangeMap.put(netIds.get(i),
900 new PortRange(netPortRangeMin, netPortRangeMax));
901 }
902
903 return netPortRangeMap;
904 }
905
Jian Li33b4db52019-03-20 18:22:38 +0900906 private IpAddress getGatewayIpAddress(Router osRouter) {
907
908 if (osRouter.getExternalGatewayInfo() == null) {
909 return null;
910 }
911 String extNetId = osNetworkAdminService.network(
912 osRouter.getExternalGatewayInfo().getNetworkId()).getId();
913 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
914 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
915 .findAny();
916
917 if (!extSubnet.isPresent()) {
Jian Li5a26ab32019-03-21 15:20:01 +0900918 log.error("Cannot find external subnet for the router");
Jian Li33b4db52019-03-20 18:22:38 +0900919 return null;
920 }
921
922 return IpAddress.valueOf(extSubnet.get().getGateway());
923 }
924
925 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
926 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
927 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
928 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
929
930 osNodeService.completeNodes(GATEWAY)
931 .forEach(gwNode -> setRulesToController(
932 gwNode.intgBridge(),
933 osNet.getProviderSegID(),
934 IpPrefix.valueOf(osSubnet.getCidr()),
935 netType,
936 install));
937 }
938
Jian Li5a26ab32019-03-21 15:20:01 +0900939 private void setGatewayToInstanceDownstreamRule(OpenstackNode gwNode,
940 InstancePort instPort,
941 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +0900942
943 TrafficSelector selector = DefaultTrafficSelector.builder()
944 .matchEthType(Ethernet.TYPE_IPV4)
Jian Li5a26ab32019-03-21 15:20:01 +0900945 .matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX))
946 .build();
947
948 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
949 .setEthDst(instPort.macAddress());
950
951 Type netType = osNetworkAdminService.networkType(instPort.networkId());
952 String segId = osNetworkAdminService.segmentId(instPort.networkId());
953
954 switch (netType) {
955 case VXLAN:
956 case GRE:
957 case GENEVE:
958 tBuilder.setTunnelId(Long.valueOf(segId));
959 break;
960 case VLAN:
961 default:
962 final String error = String.format("%s %s",
963 ERR_UNSUPPORTED_NET_TYPE, netType.name());
964 throw new IllegalStateException(error);
965 }
966
967 OpenstackNode srcNode = osNodeService.node(instPort.deviceId());
968 TrafficTreatment treatment =
969 getDownstreamTreatment(netType, tBuilder, gwNode, srcNode);
970
971 osFlowRuleService.setRule(
972 appId,
973 gwNode.intgBridge(),
974 selector,
975 treatment,
976 PRIORITY_STATEFUL_SNAT_RULE,
977 GW_COMMON_TABLE,
978 install);
979 }
980
981 private void setStatefulSnatDownstreamRule(DeviceId deviceId,
982 IpPrefix gatewayIp,
983 boolean install) {
984
985 TrafficSelector selector = DefaultTrafficSelector.builder()
986 .matchEthType(Ethernet.TYPE_IPV4)
987 .matchIPDst(gatewayIp)
Jian Li33b4db52019-03-20 18:22:38 +0900988 .build();
989
990 ExtensionTreatment natTreatment = RulePopulatorUtil
991 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
992 .commit(false)
993 .natAction(true)
994 .table((short) 0)
995 .build();
996
997 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li33b4db52019-03-20 18:22:38 +0900998 .extension(natTreatment, deviceId)
999 .build();
1000
1001 osFlowRuleService.setRule(
1002 appId,
1003 deviceId,
1004 selector,
1005 treatment,
1006 PRIORITY_STATEFUL_SNAT_RULE,
1007 GW_COMMON_TABLE,
1008 install);
1009 }
1010
Jian Li5a26ab32019-03-21 15:20:01 +09001011 private void setStatefulSnatUpstreamRule(OpenstackNode gwNode,
1012 IpAddress gatewayIp,
1013 long vni,
1014 ExternalPeerRouter extPeerRouter,
1015 int minPortNum,
1016 int maxPortNum,
1017 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +09001018
1019 TrafficSelector selector = DefaultTrafficSelector.builder()
1020 .matchEthType(Ethernet.TYPE_IPV4)
1021 .matchEthDst(DEFAULT_GATEWAY_MAC)
1022 .matchTunnelId(vni)
1023 .build();
1024
1025 ExtensionTreatment natTreatment = RulePopulatorUtil
Jian Li5a26ab32019-03-21 15:20:01 +09001026 .niciraConnTrackTreatmentBuilder(driverService, gwNode.intgBridge())
Jian Li33b4db52019-03-20 18:22:38 +09001027 .commit(true)
Jian Li5a26ab32019-03-21 15:20:01 +09001028 .natFlag(CT_NAT_SRC_FLAG)
Jian Li33b4db52019-03-20 18:22:38 +09001029 .natAction(true)
Jian Li5a26ab32019-03-21 15:20:01 +09001030 .natIp(gatewayIp)
1031 .natPortMin(TpPort.tpPort(minPortNum))
1032 .natPortMax(TpPort.tpPort(maxPortNum))
Jian Li33b4db52019-03-20 18:22:38 +09001033 .build();
1034
1035 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5a26ab32019-03-21 15:20:01 +09001036 .extension(natTreatment, gwNode.intgBridge())
1037 .setEthDst(extPeerRouter.macAddress())
Jian Li33b4db52019-03-20 18:22:38 +09001038 .setEthSrc(DEFAULT_GATEWAY_MAC)
Jian Li5a26ab32019-03-21 15:20:01 +09001039 .setOutput(gwNode.uplinkPortNum())
Jian Li33b4db52019-03-20 18:22:38 +09001040 .build();
1041
1042 osFlowRuleService.setRule(
1043 appId,
Jian Li5a26ab32019-03-21 15:20:01 +09001044 gwNode.intgBridge(),
Jian Li33b4db52019-03-20 18:22:38 +09001045 selector,
1046 treatment,
1047 PRIORITY_STATEFUL_SNAT_RULE,
1048 GW_COMMON_TABLE,
1049 install);
1050 }
1051
Jian Li33b4db52019-03-20 18:22:38 +09001052 private void setRulesToController(DeviceId deviceId,
1053 String segmentId,
1054 IpPrefix srcSubnet,
1055 Type networkType,
1056 boolean install) {
1057 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
1058 .matchEthType(Ethernet.TYPE_IPV4)
1059 .matchIPSrc(srcSubnet)
1060 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
1061
1062 switch (networkType) {
1063 case VXLAN:
1064 case GRE:
1065 case GENEVE:
1066 sBuilder.matchTunnelId(Long.parseLong(segmentId));
1067 break;
1068 case VLAN:
1069 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
1070 break;
1071 default:
1072 final String error = String.format("%s %s",
1073 ERR_UNSUPPORTED_NET_TYPE,
1074 networkType.toString());
1075 throw new IllegalStateException(error);
1076 }
1077
1078 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1079
1080 if (networkType == VLAN) {
1081 tBuilder.popVlan();
1082 }
1083
1084 tBuilder.punt();
1085
1086 osFlowRuleService.setRule(
1087 appId,
1088 deviceId,
1089 sBuilder.build(),
1090 tBuilder.build(),
1091 PRIORITY_EXTERNAL_ROUTING_RULE,
1092 GW_COMMON_TABLE,
1093 install);
1094 }
1095
1096 private class InternalInstancePortListener implements InstancePortListener {
1097
1098 private boolean isRelevantHelper(InstancePortEvent event) {
1099 return mastershipService.isLocalMaster(event.subject().deviceId());
1100 }
1101
1102 @Override
1103 public void event(InstancePortEvent event) {
1104 InstancePort instPort = event.subject();
1105 switch (event.type()) {
1106 case OPENSTACK_INSTANCE_PORT_DETECTED:
1107 case OPENSTACK_INSTANCE_PORT_UPDATED:
1108 eventExecutor.execute(() ->
1109 processInstancePortDetection(event, instPort));
1110 break;
1111 case OPENSTACK_INSTANCE_PORT_VANISHED:
1112 eventExecutor.execute(() ->
1113 processInstancePortRemoval(event, instPort));
1114 break;
1115 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1116 eventExecutor.execute(() ->
1117 processInstanceMigrationStart(event, instPort));
1118 break;
1119 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1120 eventExecutor.execute(() ->
1121 processInstanceMigrationEnd(event, instPort));
1122 break;
1123 default:
1124 break;
1125 }
1126 }
1127
1128 private void processInstancePortDetection(InstancePortEvent event,
1129 InstancePort instPort) {
1130 if (!isRelevantHelper(event)) {
1131 return;
1132 }
1133
1134 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1135 instPort.macAddress(),
1136 instPort.ipAddress());
1137
1138 instPortDetected(event.subject());
1139 }
1140
1141 private void processInstancePortRemoval(InstancePortEvent event,
1142 InstancePort instPort) {
1143 if (!isRelevantHelper(event)) {
1144 return;
1145 }
1146
1147 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1148 instPort.macAddress(),
1149 instPort.ipAddress());
1150
1151 instPortRemoved(event.subject());
1152 }
1153
1154 private void processInstanceMigrationStart(InstancePortEvent event,
1155 InstancePort instPort) {
1156 if (!isRelevantHelper(event)) {
1157 return;
1158 }
1159
1160 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1161 instPort.macAddress(),
1162 instPort.ipAddress());
1163
1164 instPortDetected(instPort);
1165 }
1166
1167 private void processInstanceMigrationEnd(InstancePortEvent event,
1168 InstancePort instPort) {
1169 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1170 instPort.macAddress(),
1171 instPort.ipAddress());
1172 // TODO: need to reconfigure rules to point to update VM
1173 }
1174
1175 private void instPortDetected(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001176 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1177
1178 if (netType == FLAT) {
1179 return;
1180 }
1181
1182 if (useStatefulSnat) {
Jian Li5a26ab32019-03-21 15:20:01 +09001183 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1184 setGatewayToInstanceDownstreamRule(gwNode, instPort, true));
Jian Li33b4db52019-03-20 18:22:38 +09001185 }
1186 }
1187
1188 private void instPortRemoved(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001189 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1190
1191 if (netType == FLAT) {
1192 return;
1193 }
1194
1195 if (useStatefulSnat) {
Jian Li5a26ab32019-03-21 15:20:01 +09001196 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1197 setGatewayToInstanceDownstreamRule(gwNode, instPort, false));
Jian Li33b4db52019-03-20 18:22:38 +09001198 }
1199 }
1200 }
1201
1202 private class InternalRouterEventListener implements OpenstackRouterListener {
1203
1204 private boolean isRelevantHelper() {
1205 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1206 }
1207
1208 @Override
1209 public void event(OpenstackRouterEvent event) {
1210 switch (event.type()) {
1211 case OPENSTACK_ROUTER_CREATED:
1212 eventExecutor.execute(() -> processRouterCreation(event));
1213 break;
1214 case OPENSTACK_ROUTER_UPDATED:
1215 eventExecutor.execute(() -> processRouterUpdate(event));
1216 break;
1217 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1218 eventExecutor.execute(() -> processRouterIntfCreation(event));
1219 break;
1220 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1221 eventExecutor.execute(() -> processRouterIntfRemoval(event));
1222 break;
1223 case OPENSTACK_ROUTER_GATEWAY_ADDED:
1224 log.debug("Router external gateway {} added",
1225 event.externalGateway().getNetworkId());
1226 break;
1227 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
1228 log.debug("Router external gateway {} removed",
1229 event.externalGateway().getNetworkId());
1230 break;
1231 default:
1232 break;
1233 }
1234 }
1235
1236 private void processRouterCreation(OpenstackRouterEvent event) {
1237 if (!isRelevantHelper()) {
1238 return;
1239 }
1240
1241 log.debug("Router(name:{}, ID:{}) is created",
1242 event.subject().getName(),
1243 event.subject().getId());
1244
1245 routerUpdated(event.subject());
1246 }
1247
1248 private void processRouterUpdate(OpenstackRouterEvent event) {
1249 if (!isRelevantHelper()) {
1250 return;
1251 }
1252
1253 log.debug("Router(name:{}, ID:{}) is updated",
1254 event.subject().getName(),
1255 event.subject().getId());
1256
1257 routerUpdated(event.subject());
1258 }
1259
1260 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1261 if (!isRelevantHelper()) {
1262 return;
1263 }
1264
1265 log.debug("Router interface {} added to router {}",
1266 event.routerIface().getPortId(),
1267 event.routerIface().getId());
1268
1269 routerIfaceAdded(event.subject(), event.routerIface());
1270 }
1271
1272 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1273 if (!isRelevantHelper()) {
1274 return;
1275 }
1276
1277 log.debug("Router interface {} removed from router {}",
1278 event.routerIface().getPortId(),
1279 event.routerIface().getId());
1280
1281 routerIfaceRemoved(event.subject(), event.routerIface());
1282 }
1283 }
1284
Hyunsun Moon44aac662017-02-18 02:07:01 +09001285 private class InternalPacketProcessor implements PacketProcessor {
1286
1287 @Override
1288 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +09001289
Hyunsun Moon44aac662017-02-18 02:07:01 +09001290 if (context.isHandled()) {
1291 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001292 }
1293
1294 InboundPacket pkt = context.inPacket();
1295 Ethernet eth = pkt.parsed();
1296 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
1297 return;
1298 }
1299
1300 IPv4 iPacket = (IPv4) eth.getPayload();
1301 switch (iPacket.getProtocol()) {
1302 case IPv4.PROTOCOL_ICMP:
1303 break;
1304 case IPv4.PROTOCOL_UDP:
1305 UDP udpPacket = (UDP) iPacket.getPayload();
1306 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
1307 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
Jian Li6a47fd02018-11-27 21:51:03 +09001308 break; // don't process DHCP
Hyunsun Moon44aac662017-02-18 02:07:01 +09001309 }
1310 default:
Jian Li34220ea2018-11-14 01:30:24 +09001311 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001312 if (!isRelevantHelper(context)) {
1313 return;
1314 }
Jian Li34220ea2018-11-14 01:30:24 +09001315 processSnatPacket(context, eth);
1316 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001317 break;
1318 }
1319 }
Jian Li34220ea2018-11-14 01:30:24 +09001320
1321 private boolean isRelevantHelper(PacketContext context) {
1322 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
1323 .stream().map(OpenstackNode::intgBridge)
1324 .collect(Collectors.toSet());
1325
1326 return gateways.contains(context.inPacket().receivedFrom().deviceId());
1327 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001328 }
Jian Li33b4db52019-03-20 18:22:38 +09001329
1330 private class InternalNodeEventListener implements OpenstackNodeListener {
1331
1332 private boolean isRelevantHelper() {
1333 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1334 }
1335
1336 @Override
1337 public void event(OpenstackNodeEvent event) {
1338 OpenstackNode osNode = event.subject();
1339 switch (event.type()) {
1340 case OPENSTACK_NODE_COMPLETE:
Jian Li5a26ab32019-03-21 15:20:01 +09001341 eventExecutor.execute(() -> processGatewayCompletion(osNode));
1342 eventExecutor.execute(() -> reconfigureRouters(osNode));
1343 break;
1344 case OPENSTACK_NODE_REMOVED:
1345 eventExecutor.execute(() -> processGatewayRemoval(osNode));
Jian Li5d795f22019-04-01 23:07:40 +09001346 eventExecutor.execute(() -> reconfigureRouters(osNode));
1347 break;
Jian Li33b4db52019-03-20 18:22:38 +09001348 case OPENSTACK_NODE_INCOMPLETE:
1349 case OPENSTACK_NODE_UPDATED:
Jian Li5a26ab32019-03-21 15:20:01 +09001350 eventExecutor.execute(() -> reconfigureRouters(osNode));
Jian Li33b4db52019-03-20 18:22:38 +09001351 break;
1352 case OPENSTACK_NODE_CREATED:
1353 default:
1354 break;
1355 }
1356 }
1357
Jian Li5a26ab32019-03-21 15:20:01 +09001358 private void processGatewayCompletion(OpenstackNode osNode) {
1359 if (!isRelevantHelper()) {
1360 return;
1361 }
1362
1363 if (useStatefulSnat && osNode.type() == GATEWAY) {
1364 instancePortService.instancePorts().forEach(instPort ->
1365 setGatewayToInstanceDownstreamRule(osNode, instPort, true));
1366 }
1367 }
1368
1369 private void processGatewayRemoval(OpenstackNode osNode) {
1370 if (!isRelevantHelper()) {
1371 return;
1372 }
1373
1374 if (useStatefulSnat && osNode.type() == GATEWAY) {
1375 instancePortService.instancePorts().forEach(instPort ->
1376 setGatewayToInstanceDownstreamRule(osNode, instPort, false));
1377 }
1378 }
1379
Jian Li33b4db52019-03-20 18:22:38 +09001380 private void reconfigureRouters(OpenstackNode osNode) {
Jian Li5a26ab32019-03-21 15:20:01 +09001381 if (!isRelevantHelper()) {
1382 return;
1383 }
1384
Jian Li33b4db52019-03-20 18:22:38 +09001385 osRouterService.routers().forEach(osRouter -> {
1386 routerUpdated(osRouter);
1387 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1388 routerIfaceAdded(osRouter, iface);
1389 });
1390 });
1391 log.info("Reconfigure routers for {}", osNode.hostname());
1392 }
1393 }
Jian Li5a26ab32019-03-21 15:20:01 +09001394
1395 private class PortRange {
1396 private int min;
1397 private int max;
1398
1399 /**
1400 * A default constructor.
1401 *
1402 * @param min min port num
1403 * @param max max port num
1404 */
1405 public PortRange(int min, int max) {
1406 this.min = min;
1407 this.max = max;
1408 }
1409
1410 /**
1411 * Obtains min port num.
1412 *
1413 * @return min port num
1414 */
1415 int min() {
1416 return min;
1417 }
1418
1419 /**
1420 * Obtains max port num.
1421 *
1422 * @return max port num
1423 */
1424 int max() {
1425 return max;
1426 }
1427
1428 @Override
1429 public String toString() {
1430 return MoreObjects.toStringHelper(this)
1431 .add("min", min)
1432 .add("max", max)
1433 .toString();
1434 }
1435
1436 @Override
1437 public boolean equals(Object o) {
1438 if (this == o) {
1439 return true;
1440 }
1441 if (o == null || getClass() != o.getClass()) {
1442 return false;
1443 }
1444 PortRange portRange = (PortRange) o;
1445 return min == portRange.min &&
1446 max == portRange.max;
1447 }
1448
1449 @Override
1450 public int hashCode() {
1451 return Objects.hash(min, max);
1452 }
1453 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001454}