blob: b563dc763d5778e4b8c3047508841a4ae4748117 [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()));
Jian Li4f3f75a2019-04-03 12:41:30 +0900730
731 setStatefulDownstreamRules(osRouter, exGateway.isEnableSnat());
Jian Li33b4db52019-03-20 18:22:38 +0900732 }
733 }
734
735 private void deleteUnassociatedExternalPeerRouter() {
736 log.trace("Deleting unassociated external peer router");
737
738 try {
739 Set<String> routerIps = Sets.newConcurrentHashSet();
740
741 osRouterService.routers().stream()
742 .filter(router -> getGatewayIpAddress(router) != null)
743 .map(router -> getGatewayIpAddress(router).toString())
744 .forEach(routerIps::add);
745
746 osNetworkAdminService.externalPeerRouters().stream()
747 .filter(externalPeerRouter ->
748 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
749 .forEach(externalPeerRouter -> {
750 osNetworkAdminService
751 .deleteExternalPeerRouter(
752 externalPeerRouter.ipAddress().toString());
753 log.trace("Deleted unassociated external peer router {}",
754 externalPeerRouter.ipAddress().toString());
755 });
756 } catch (Exception e) {
757 log.error("Exception occurred because of {}", e.toString());
758 }
759 }
760
761 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
762 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
763 if (exGateway != null && exGateway.isEnableSnat()) {
764 setSourceNat(osRouterIface, true);
765 }
766 }
767
768 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
769 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
770 if (exGateway != null && exGateway.isEnableSnat()) {
771 setSourceNat(osRouterIface, false);
772 }
773 }
774
775 private void setSourceNat(RouterInterface routerIface, boolean install) {
776 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
777 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
778 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
779
780 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
781 setRulesToGateway(cNode, osNet.getProviderSegID(),
782 IpPrefix.valueOf(osSubnet.getCidr()), netType, install);
783 });
784
785 if (useStatefulSnat) {
786 setStatefulSnatRules(routerIface, install);
787 } else {
788 setReactiveSnatRules(routerIface, install);
789 }
790
791 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
792 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
793 }
794
795 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
796 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
797 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
798 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
799
800 if (netType == FLAT) {
801 return;
802 }
803
804 Optional<Router> osRouter = osRouterService.routers().stream()
805 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
806 .findAny();
807
808 if (!osRouter.isPresent()) {
809 log.error("Cannot find a router for router interface {} ", routerIface);
810 return;
811 }
Jian Li5a26ab32019-03-21 15:20:01 +0900812
813 IpAddress natAddress = getExternalIp(osRouter.get(), osNetworkService);
Jian Li33b4db52019-03-20 18:22:38 +0900814 if (natAddress == null) {
815 return;
816 }
Jian Li5a26ab32019-03-21 15:20:01 +0900817
818 IpAddress extRouterAddress = getGatewayIpAddress(osRouter.get());
819 if (extRouterAddress == null) {
820 return;
821 }
822
823 ExternalPeerRouter externalPeerRouter =
824 osNetworkService.externalPeerRouter(extRouterAddress);
825 if (externalPeerRouter == null) {
826 return;
827 }
828
Jian Li33b4db52019-03-20 18:22:38 +0900829 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
830
Jian Li5a26ab32019-03-21 15:20:01 +0900831 Map<OpenstackNode, PortRange> gwPortRangeMap = getAssignedPortsForGateway(
Jian Li25257212019-03-26 13:31:14 +0900832 ImmutableList.copyOf(osNodeService.nodes(GATEWAY)));
Jian Li5a26ab32019-03-21 15:20:01 +0900833
Jian Li33b4db52019-03-20 18:22:38 +0900834 osNodeService.completeNodes(GATEWAY)
835 .forEach(gwNode -> {
836 instancePortService.instancePorts(netId)
837 .stream()
838 .filter(port -> port.state() == ACTIVE)
Jian Li5a26ab32019-03-21 15:20:01 +0900839 .forEach(port -> setGatewayToInstanceDownstreamRule(
840 gwNode, port, install));
Jian Li33b4db52019-03-20 18:22:38 +0900841
Jian Lia2995192019-04-02 14:13:04 +0900842 if (install) {
843 PortRange gwPortRange = gwPortRangeMap.get(gwNode);
Jian Li5a26ab32019-03-21 15:20:01 +0900844
Jian Lia2995192019-04-02 14:13:04 +0900845 Map<String, PortRange> netPortRangeMap =
846 getAssignedPortsForNet(getNetIdByRouterId(routerIface.getId()),
847 gwPortRange.min(), gwPortRange.max());
Jian Li5a26ab32019-03-21 15:20:01 +0900848
Jian Lia2995192019-04-02 14:13:04 +0900849 PortRange netPortRange = netPortRangeMap.get(osNet.getId());
Jian Li5a26ab32019-03-21 15:20:01 +0900850
Jian Lia2995192019-04-02 14:13:04 +0900851 setStatefulSnatUpstreamRule(gwNode, natAddress,
852 Long.parseLong(osNet.getProviderSegID()),
853 externalPeerRouter, netPortRange.min(),
854 netPortRange.max(), install);
855 } else {
856 setStatefulSnatUpstreamRule(gwNode, natAddress,
857 Long.parseLong(osNet.getProviderSegID()),
858 externalPeerRouter, 0, 0, install);
859 }
860
Jian Li33b4db52019-03-20 18:22:38 +0900861 });
862 }
863
Jian Li4f3f75a2019-04-03 12:41:30 +0900864 private void setStatefulDownstreamRules(Router osRouter, boolean install) {
865
866 IpAddress natAddress = getExternalIp(osRouter, osNetworkAdminService);
867 if (natAddress == null) {
868 return;
869 }
870
871 osNodeService.completeNodes(GATEWAY)
872 .forEach(gwNode -> {
873 setStatefulSnatDownstreamRule(gwNode.intgBridge(),
874 IpPrefix.valueOf(natAddress, VM_PREFIX), install);
875 });
876 }
877
Jian Li5a26ab32019-03-21 15:20:01 +0900878 private List<String> getNetIdByRouterId(String routerId) {
879 return osRouterService.routerInterfaces(routerId)
880 .stream()
881 .filter(ri -> osRouterService.router(ri.getId())
882 .getExternalGatewayInfo().isEnableSnat())
883 .map(RouterInterface::getSubnetId)
884 .map(si -> osNetworkAdminService.subnet(si))
885 .map(Subnet::getNetworkId)
886 .collect(Collectors.toList());
887 }
888
889 private Map<OpenstackNode, PortRange>
890 getAssignedPortsForGateway(List<OpenstackNode> gateways) {
891
892 Map<OpenstackNode, PortRange> gwPortRangeMap = Maps.newConcurrentMap();
893
894 int portRangeNumPerGwNode =
895 (TP_PORT_MAXIMUM_NUM - TP_PORT_MINIMUM_NUM + 1) / gateways.size();
896
897 for (int i = 0; i < gateways.size(); i++) {
898 int gwPortRangeMin = TP_PORT_MINIMUM_NUM + i * portRangeNumPerGwNode;
899 int gwPortRangeMax = TP_PORT_MINIMUM_NUM + (i + 1) * portRangeNumPerGwNode - 1;
900
901 gwPortRangeMap.put(gateways.get(i),
902 new PortRange(gwPortRangeMin, gwPortRangeMax));
903 }
904
905 return gwPortRangeMap;
906 }
907
908 private Map<String, PortRange> getAssignedPortsForNet(List<String> netIds,
909 int min, int max) {
910
911 Map<String, PortRange> netPortRangeMap = Maps.newConcurrentMap();
912
913 int portRangeNumPerNet = (max - min + 1) / netIds.size();
914
915 for (int i = 0; i < netIds.size(); i++) {
916 int netPortRangeMin = min + i * portRangeNumPerNet;
917 int netPortRangeMax = min + (i + 1) * portRangeNumPerNet - 1;
918
919 netPortRangeMap.put(netIds.get(i),
920 new PortRange(netPortRangeMin, netPortRangeMax));
921 }
922
923 return netPortRangeMap;
924 }
925
Jian Li33b4db52019-03-20 18:22:38 +0900926 private IpAddress getGatewayIpAddress(Router osRouter) {
927
928 if (osRouter.getExternalGatewayInfo() == null) {
929 return null;
930 }
931 String extNetId = osNetworkAdminService.network(
932 osRouter.getExternalGatewayInfo().getNetworkId()).getId();
933 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
934 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
935 .findAny();
936
937 if (!extSubnet.isPresent()) {
Jian Li5a26ab32019-03-21 15:20:01 +0900938 log.error("Cannot find external subnet for the router");
Jian Li33b4db52019-03-20 18:22:38 +0900939 return null;
940 }
941
942 return IpAddress.valueOf(extSubnet.get().getGateway());
943 }
944
945 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
946 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
947 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
948 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
949
950 osNodeService.completeNodes(GATEWAY)
951 .forEach(gwNode -> setRulesToController(
952 gwNode.intgBridge(),
953 osNet.getProviderSegID(),
954 IpPrefix.valueOf(osSubnet.getCidr()),
955 netType,
956 install));
957 }
958
Jian Li5a26ab32019-03-21 15:20:01 +0900959 private void setGatewayToInstanceDownstreamRule(OpenstackNode gwNode,
960 InstancePort instPort,
961 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +0900962
963 TrafficSelector selector = DefaultTrafficSelector.builder()
964 .matchEthType(Ethernet.TYPE_IPV4)
Jian Li5a26ab32019-03-21 15:20:01 +0900965 .matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX))
966 .build();
967
968 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
969 .setEthDst(instPort.macAddress());
970
971 Type netType = osNetworkAdminService.networkType(instPort.networkId());
972 String segId = osNetworkAdminService.segmentId(instPort.networkId());
973
974 switch (netType) {
975 case VXLAN:
976 case GRE:
977 case GENEVE:
978 tBuilder.setTunnelId(Long.valueOf(segId));
979 break;
980 case VLAN:
981 default:
982 final String error = String.format("%s %s",
983 ERR_UNSUPPORTED_NET_TYPE, netType.name());
984 throw new IllegalStateException(error);
985 }
986
987 OpenstackNode srcNode = osNodeService.node(instPort.deviceId());
988 TrafficTreatment treatment =
989 getDownstreamTreatment(netType, tBuilder, gwNode, srcNode);
990
991 osFlowRuleService.setRule(
992 appId,
993 gwNode.intgBridge(),
994 selector,
995 treatment,
996 PRIORITY_STATEFUL_SNAT_RULE,
997 GW_COMMON_TABLE,
998 install);
999 }
1000
1001 private void setStatefulSnatDownstreamRule(DeviceId deviceId,
1002 IpPrefix gatewayIp,
1003 boolean install) {
1004
1005 TrafficSelector selector = DefaultTrafficSelector.builder()
1006 .matchEthType(Ethernet.TYPE_IPV4)
1007 .matchIPDst(gatewayIp)
Jian Li33b4db52019-03-20 18:22:38 +09001008 .build();
1009
1010 ExtensionTreatment natTreatment = RulePopulatorUtil
1011 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
1012 .commit(false)
1013 .natAction(true)
1014 .table((short) 0)
1015 .build();
1016
1017 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li33b4db52019-03-20 18:22:38 +09001018 .extension(natTreatment, deviceId)
1019 .build();
1020
1021 osFlowRuleService.setRule(
1022 appId,
1023 deviceId,
1024 selector,
1025 treatment,
1026 PRIORITY_STATEFUL_SNAT_RULE,
1027 GW_COMMON_TABLE,
1028 install);
1029 }
1030
Jian Li5a26ab32019-03-21 15:20:01 +09001031 private void setStatefulSnatUpstreamRule(OpenstackNode gwNode,
1032 IpAddress gatewayIp,
1033 long vni,
1034 ExternalPeerRouter extPeerRouter,
1035 int minPortNum,
1036 int maxPortNum,
1037 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +09001038
1039 TrafficSelector selector = DefaultTrafficSelector.builder()
1040 .matchEthType(Ethernet.TYPE_IPV4)
1041 .matchEthDst(DEFAULT_GATEWAY_MAC)
1042 .matchTunnelId(vni)
1043 .build();
1044
Jian Lia2995192019-04-02 14:13:04 +09001045 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li33b4db52019-03-20 18:22:38 +09001046
Jian Lia2995192019-04-02 14:13:04 +09001047 // we do not consider to much like port range on removing the rules...
1048 if (install) {
1049 ExtensionTreatment natTreatment = RulePopulatorUtil
1050 .niciraConnTrackTreatmentBuilder(driverService, gwNode.intgBridge())
1051 .commit(true)
1052 .natFlag(CT_NAT_SRC_FLAG)
1053 .natAction(true)
1054 .natIp(gatewayIp)
1055 .natPortMin(TpPort.tpPort(minPortNum))
1056 .natPortMax(TpPort.tpPort(maxPortNum))
1057 .build();
1058
1059 tBuilder.extension(natTreatment, gwNode.intgBridge())
1060 .setEthDst(extPeerRouter.macAddress())
1061 .setEthSrc(DEFAULT_GATEWAY_MAC)
1062 .setOutput(gwNode.uplinkPortNum());
1063 }
Jian Li33b4db52019-03-20 18:22:38 +09001064
1065 osFlowRuleService.setRule(
1066 appId,
Jian Li5a26ab32019-03-21 15:20:01 +09001067 gwNode.intgBridge(),
Jian Li33b4db52019-03-20 18:22:38 +09001068 selector,
Jian Lia2995192019-04-02 14:13:04 +09001069 tBuilder.build(),
Jian Li33b4db52019-03-20 18:22:38 +09001070 PRIORITY_STATEFUL_SNAT_RULE,
1071 GW_COMMON_TABLE,
1072 install);
1073 }
1074
Jian Li33b4db52019-03-20 18:22:38 +09001075 private void setRulesToController(DeviceId deviceId,
1076 String segmentId,
1077 IpPrefix srcSubnet,
1078 Type networkType,
1079 boolean install) {
1080 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
1081 .matchEthType(Ethernet.TYPE_IPV4)
1082 .matchIPSrc(srcSubnet)
1083 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
1084
1085 switch (networkType) {
1086 case VXLAN:
1087 case GRE:
1088 case GENEVE:
1089 sBuilder.matchTunnelId(Long.parseLong(segmentId));
1090 break;
1091 case VLAN:
1092 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
1093 break;
1094 default:
1095 final String error = String.format("%s %s",
1096 ERR_UNSUPPORTED_NET_TYPE,
1097 networkType.toString());
1098 throw new IllegalStateException(error);
1099 }
1100
1101 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1102
1103 if (networkType == VLAN) {
1104 tBuilder.popVlan();
1105 }
1106
1107 tBuilder.punt();
1108
1109 osFlowRuleService.setRule(
1110 appId,
1111 deviceId,
1112 sBuilder.build(),
1113 tBuilder.build(),
1114 PRIORITY_EXTERNAL_ROUTING_RULE,
1115 GW_COMMON_TABLE,
1116 install);
1117 }
1118
1119 private class InternalInstancePortListener implements InstancePortListener {
1120
1121 private boolean isRelevantHelper(InstancePortEvent event) {
1122 return mastershipService.isLocalMaster(event.subject().deviceId());
1123 }
1124
1125 @Override
1126 public void event(InstancePortEvent event) {
1127 InstancePort instPort = event.subject();
1128 switch (event.type()) {
1129 case OPENSTACK_INSTANCE_PORT_DETECTED:
1130 case OPENSTACK_INSTANCE_PORT_UPDATED:
1131 eventExecutor.execute(() ->
1132 processInstancePortDetection(event, instPort));
1133 break;
1134 case OPENSTACK_INSTANCE_PORT_VANISHED:
1135 eventExecutor.execute(() ->
1136 processInstancePortRemoval(event, instPort));
1137 break;
1138 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1139 eventExecutor.execute(() ->
1140 processInstanceMigrationStart(event, instPort));
1141 break;
1142 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1143 eventExecutor.execute(() ->
1144 processInstanceMigrationEnd(event, instPort));
1145 break;
1146 default:
1147 break;
1148 }
1149 }
1150
1151 private void processInstancePortDetection(InstancePortEvent event,
1152 InstancePort instPort) {
1153 if (!isRelevantHelper(event)) {
1154 return;
1155 }
1156
1157 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1158 instPort.macAddress(),
1159 instPort.ipAddress());
1160
1161 instPortDetected(event.subject());
1162 }
1163
1164 private void processInstancePortRemoval(InstancePortEvent event,
1165 InstancePort instPort) {
1166 if (!isRelevantHelper(event)) {
1167 return;
1168 }
1169
1170 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1171 instPort.macAddress(),
1172 instPort.ipAddress());
1173
1174 instPortRemoved(event.subject());
1175 }
1176
1177 private void processInstanceMigrationStart(InstancePortEvent event,
1178 InstancePort instPort) {
1179 if (!isRelevantHelper(event)) {
1180 return;
1181 }
1182
1183 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1184 instPort.macAddress(),
1185 instPort.ipAddress());
1186
1187 instPortDetected(instPort);
1188 }
1189
1190 private void processInstanceMigrationEnd(InstancePortEvent event,
1191 InstancePort instPort) {
1192 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1193 instPort.macAddress(),
1194 instPort.ipAddress());
1195 // TODO: need to reconfigure rules to point to update VM
1196 }
1197
1198 private void instPortDetected(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, true));
Jian Li33b4db52019-03-20 18:22:38 +09001208 }
1209 }
1210
1211 private void instPortRemoved(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001212 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1213
1214 if (netType == FLAT) {
1215 return;
1216 }
1217
1218 if (useStatefulSnat) {
Jian Li5a26ab32019-03-21 15:20:01 +09001219 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1220 setGatewayToInstanceDownstreamRule(gwNode, instPort, false));
Jian Li33b4db52019-03-20 18:22:38 +09001221 }
1222 }
1223 }
1224
1225 private class InternalRouterEventListener implements OpenstackRouterListener {
1226
1227 private boolean isRelevantHelper() {
1228 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1229 }
1230
1231 @Override
1232 public void event(OpenstackRouterEvent event) {
1233 switch (event.type()) {
1234 case OPENSTACK_ROUTER_CREATED:
1235 eventExecutor.execute(() -> processRouterCreation(event));
1236 break;
1237 case OPENSTACK_ROUTER_UPDATED:
1238 eventExecutor.execute(() -> processRouterUpdate(event));
1239 break;
1240 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1241 eventExecutor.execute(() -> processRouterIntfCreation(event));
1242 break;
1243 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1244 eventExecutor.execute(() -> processRouterIntfRemoval(event));
1245 break;
1246 case OPENSTACK_ROUTER_GATEWAY_ADDED:
Jian Li4f3f75a2019-04-03 12:41:30 +09001247 eventExecutor.execute(() -> processRouterGatewayAddition(event));
Jian Li33b4db52019-03-20 18:22:38 +09001248 break;
1249 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Li4f3f75a2019-04-03 12:41:30 +09001250 eventExecutor.execute(() -> processRouterGatewayRemoval(event));
Jian Li33b4db52019-03-20 18:22:38 +09001251 break;
1252 default:
1253 break;
1254 }
1255 }
1256
1257 private void processRouterCreation(OpenstackRouterEvent event) {
1258 if (!isRelevantHelper()) {
1259 return;
1260 }
1261
1262 log.debug("Router(name:{}, ID:{}) is created",
1263 event.subject().getName(),
1264 event.subject().getId());
1265
1266 routerUpdated(event.subject());
1267 }
1268
1269 private void processRouterUpdate(OpenstackRouterEvent event) {
1270 if (!isRelevantHelper()) {
1271 return;
1272 }
1273
1274 log.debug("Router(name:{}, ID:{}) is updated",
1275 event.subject().getName(),
1276 event.subject().getId());
1277
1278 routerUpdated(event.subject());
1279 }
1280
1281 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1282 if (!isRelevantHelper()) {
1283 return;
1284 }
1285
1286 log.debug("Router interface {} added to router {}",
1287 event.routerIface().getPortId(),
1288 event.routerIface().getId());
1289
1290 routerIfaceAdded(event.subject(), event.routerIface());
1291 }
1292
1293 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1294 if (!isRelevantHelper()) {
1295 return;
1296 }
1297
1298 log.debug("Router interface {} removed from router {}",
1299 event.routerIface().getPortId(),
1300 event.routerIface().getId());
1301
1302 routerIfaceRemoved(event.subject(), event.routerIface());
1303 }
Jian Li4f3f75a2019-04-03 12:41:30 +09001304
1305 private void processRouterGatewayAddition(OpenstackRouterEvent event) {
1306 if (!isRelevantHelper()) {
1307 return;
1308 }
1309
1310 log.debug("Router external gateway {} added",
1311 event.externalGateway().getNetworkId());
1312
1313 setStatefulDownstreamRules(event.subject(), true);
1314 }
1315
1316 private void processRouterGatewayRemoval(OpenstackRouterEvent event) {
1317 if (!isRelevantHelper()) {
1318 return;
1319 }
1320
1321 log.debug("Router external gateway {} removed",
1322 event.externalGateway().getNetworkId());
1323
1324 setStatefulDownstreamRules(event.subject(), false);
1325 }
Jian Li33b4db52019-03-20 18:22:38 +09001326 }
1327
Hyunsun Moon44aac662017-02-18 02:07:01 +09001328 private class InternalPacketProcessor implements PacketProcessor {
1329
1330 @Override
1331 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +09001332
Hyunsun Moon44aac662017-02-18 02:07:01 +09001333 if (context.isHandled()) {
1334 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001335 }
1336
1337 InboundPacket pkt = context.inPacket();
1338 Ethernet eth = pkt.parsed();
1339 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
1340 return;
1341 }
1342
1343 IPv4 iPacket = (IPv4) eth.getPayload();
1344 switch (iPacket.getProtocol()) {
1345 case IPv4.PROTOCOL_ICMP:
1346 break;
1347 case IPv4.PROTOCOL_UDP:
1348 UDP udpPacket = (UDP) iPacket.getPayload();
1349 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
1350 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
Jian Li6a47fd02018-11-27 21:51:03 +09001351 break; // don't process DHCP
Hyunsun Moon44aac662017-02-18 02:07:01 +09001352 }
1353 default:
Jian Li34220ea2018-11-14 01:30:24 +09001354 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001355 if (!isRelevantHelper(context)) {
1356 return;
1357 }
Jian Li34220ea2018-11-14 01:30:24 +09001358 processSnatPacket(context, eth);
1359 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001360 break;
1361 }
1362 }
Jian Li34220ea2018-11-14 01:30:24 +09001363
1364 private boolean isRelevantHelper(PacketContext context) {
1365 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
1366 .stream().map(OpenstackNode::intgBridge)
1367 .collect(Collectors.toSet());
1368
1369 return gateways.contains(context.inPacket().receivedFrom().deviceId());
1370 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001371 }
Jian Li33b4db52019-03-20 18:22:38 +09001372
1373 private class InternalNodeEventListener implements OpenstackNodeListener {
1374
1375 private boolean isRelevantHelper() {
1376 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1377 }
1378
1379 @Override
1380 public void event(OpenstackNodeEvent event) {
1381 OpenstackNode osNode = event.subject();
1382 switch (event.type()) {
1383 case OPENSTACK_NODE_COMPLETE:
Jian Li5a26ab32019-03-21 15:20:01 +09001384 eventExecutor.execute(() -> processGatewayCompletion(osNode));
1385 eventExecutor.execute(() -> reconfigureRouters(osNode));
1386 break;
1387 case OPENSTACK_NODE_REMOVED:
1388 eventExecutor.execute(() -> processGatewayRemoval(osNode));
Jian Li5d795f22019-04-01 23:07:40 +09001389 eventExecutor.execute(() -> reconfigureRouters(osNode));
1390 break;
Jian Li33b4db52019-03-20 18:22:38 +09001391 case OPENSTACK_NODE_INCOMPLETE:
1392 case OPENSTACK_NODE_UPDATED:
Jian Li5a26ab32019-03-21 15:20:01 +09001393 eventExecutor.execute(() -> reconfigureRouters(osNode));
Jian Li33b4db52019-03-20 18:22:38 +09001394 break;
1395 case OPENSTACK_NODE_CREATED:
1396 default:
1397 break;
1398 }
1399 }
1400
Jian Li5a26ab32019-03-21 15:20:01 +09001401 private void processGatewayCompletion(OpenstackNode osNode) {
1402 if (!isRelevantHelper()) {
1403 return;
1404 }
1405
1406 if (useStatefulSnat && osNode.type() == GATEWAY) {
1407 instancePortService.instancePorts().forEach(instPort ->
1408 setGatewayToInstanceDownstreamRule(osNode, instPort, true));
1409 }
1410 }
1411
1412 private void processGatewayRemoval(OpenstackNode osNode) {
1413 if (!isRelevantHelper()) {
1414 return;
1415 }
1416
1417 if (useStatefulSnat && osNode.type() == GATEWAY) {
1418 instancePortService.instancePorts().forEach(instPort ->
1419 setGatewayToInstanceDownstreamRule(osNode, instPort, false));
1420 }
1421 }
1422
Jian Li33b4db52019-03-20 18:22:38 +09001423 private void reconfigureRouters(OpenstackNode osNode) {
Jian Li5a26ab32019-03-21 15:20:01 +09001424 if (!isRelevantHelper()) {
1425 return;
1426 }
1427
Jian Li33b4db52019-03-20 18:22:38 +09001428 osRouterService.routers().forEach(osRouter -> {
1429 routerUpdated(osRouter);
1430 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1431 routerIfaceAdded(osRouter, iface);
1432 });
1433 });
1434 log.info("Reconfigure routers for {}", osNode.hostname());
1435 }
1436 }
Jian Li5a26ab32019-03-21 15:20:01 +09001437
1438 private class PortRange {
1439 private int min;
1440 private int max;
1441
1442 /**
1443 * A default constructor.
1444 *
1445 * @param min min port num
1446 * @param max max port num
1447 */
1448 public PortRange(int min, int max) {
1449 this.min = min;
1450 this.max = max;
1451 }
1452
1453 /**
1454 * Obtains min port num.
1455 *
1456 * @return min port num
1457 */
1458 int min() {
1459 return min;
1460 }
1461
1462 /**
1463 * Obtains max port num.
1464 *
1465 * @return max port num
1466 */
1467 int max() {
1468 return max;
1469 }
1470
1471 @Override
1472 public String toString() {
1473 return MoreObjects.toStringHelper(this)
1474 .add("min", min)
1475 .add("max", max)
1476 .toString();
1477 }
1478
1479 @Override
1480 public boolean equals(Object o) {
1481 if (this == o) {
1482 return true;
1483 }
1484 if (o == null || getClass() != o.getClass()) {
1485 return false;
1486 }
1487 PortRange portRange = (PortRange) o;
1488 return min == portRange.min &&
1489 max == portRange.max;
1490 }
1491
1492 @Override
1493 public int hashCode() {
1494 return Objects.hash(min, max);
1495 }
1496 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001497}