blob: c7c0ef3d84c93821269c668daac985aaac626042 [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;
Jian Liec857292019-04-03 18:18:52 +090033import org.onosproject.cfg.ConfigProperty;
Jian Li33b4db52019-03-20 18:22:38 +090034import org.onosproject.cluster.ClusterService;
35import org.onosproject.cluster.LeadershipService;
36import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.core.ApplicationId;
38import org.onosproject.core.CoreService;
Jian Li33b4db52019-03-20 18:22:38 +090039import org.onosproject.mastership.MastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090040import org.onosproject.net.DeviceId;
Jian Li2d68c192018-12-13 15:52:59 +090041import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.net.device.DeviceService;
Jian Li33b4db52019-03-20 18:22:38 +090043import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.net.flow.DefaultTrafficSelector;
45import org.onosproject.net.flow.DefaultTrafficTreatment;
46import org.onosproject.net.flow.TrafficSelector;
47import org.onosproject.net.flow.TrafficTreatment;
Jian Li33b4db52019-03-20 18:22:38 +090048import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.onosproject.net.packet.DefaultOutboundPacket;
50import org.onosproject.net.packet.InboundPacket;
51import org.onosproject.net.packet.PacketContext;
52import org.onosproject.net.packet.PacketProcessor;
53import org.onosproject.net.packet.PacketService;
Jian Li33b4db52019-03-20 18:22:38 +090054import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090055import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li33b4db52019-03-20 18:22:38 +090057import org.onosproject.openstacknetworking.api.InstancePortEvent;
58import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090059import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090060import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090061import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Li33b4db52019-03-20 18:22:38 +090062import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090063import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Li33b4db52019-03-20 18:22:38 +090064import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
65import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
sanghodc375372017-06-08 10:41:30 +090066import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Li26949762018-03-30 15:46:37 +090067import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090068import org.onosproject.openstacknode.api.OpenstackNode;
Jian Li33b4db52019-03-20 18:22:38 +090069import org.onosproject.openstacknode.api.OpenstackNodeEvent;
70import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090071import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072import org.onosproject.store.serializers.KryoNamespaces;
73import org.onosproject.store.service.ConsistentMap;
daniel park0bc7fdb2017-03-13 14:20:08 +090074import org.onosproject.store.service.DistributedSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075import org.onosproject.store.service.Serializer;
76import org.onosproject.store.service.StorageService;
Jian Li33b4db52019-03-20 18:22:38 +090077import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090078import org.openstack4j.model.network.IP;
79import org.openstack4j.model.network.Network;
80import org.openstack4j.model.network.Port;
Jian Li33b4db52019-03-20 18:22:38 +090081import org.openstack4j.model.network.Router;
82import org.openstack4j.model.network.RouterInterface;
Hyunsun Moon44aac662017-02-18 02:07:01 +090083import org.openstack4j.model.network.Subnet;
Jian Li33b4db52019-03-20 18:22:38 +090084import org.osgi.service.component.ComponentContext;
Jian Liebde74d2018-11-14 00:18:57 +090085import org.osgi.service.component.annotations.Activate;
86import org.osgi.service.component.annotations.Component;
87import org.osgi.service.component.annotations.Deactivate;
Jian Li33b4db52019-03-20 18:22:38 +090088import org.osgi.service.component.annotations.Modified;
Jian Liebde74d2018-11-14 00:18:57 +090089import org.osgi.service.component.annotations.Reference;
90import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090091import org.slf4j.Logger;
92
93import java.nio.ByteBuffer;
Jian Li33b4db52019-03-20 18:22:38 +090094import java.util.Dictionary;
Jian Li5a26ab32019-03-21 15:20:01 +090095import java.util.List;
96import java.util.Map;
Jian Li33b4db52019-03-20 18:22:38 +090097import java.util.Objects;
98import java.util.Optional;
Hyunsun Moon0d457362017-06-27 17:19:41 +090099import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900100import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900101import java.util.stream.Collectors;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102
103import static java.util.concurrent.Executors.newSingleThreadExecutor;
104import static org.onlab.util.Tools.groupedThreads;
daniel parkeeb8e042018-02-21 14:06:58 +0900105import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
106import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
107import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li33b4db52019-03-20 18:22:38 +0900108import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
daniel parkeeb8e042018-02-21 14:06:58 +0900109import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SNAT_RULE;
Jian Li33b4db52019-03-20 18:22:38 +0900110import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
111import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
112import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
113import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
114import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
115import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT;
116import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT_DEFAULT;
Jian Liebde74d2018-11-14 00:18:57 +0900117import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalIpFromSubnet;
118import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Jian Li5a26ab32019-03-21 15:20:01 +0900119import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getExternalIp;
Jian Liec857292019-04-03 18:18:52 +0900120import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Li2d68c192018-12-13 15:52:59 +0900121import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
Jian Li5a26ab32019-03-21 15:20:01 +0900122import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.CT_NAT_SRC_FLAG;
Jian Li33b4db52019-03-20 18:22:38 +0900123import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
124import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900125import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126import static org.slf4j.LoggerFactory.getLogger;
127
128/**
129 * Handle packets needs SNAT.
130 */
Jian Li33b4db52019-03-20 18:22:38 +0900131@Component(
132 immediate = true,
133 property = {
134 USE_STATEFUL_SNAT + ":Boolean=" + USE_STATEFUL_SNAT_DEFAULT
135 }
136)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137public class OpenstackRoutingSnatHandler {
138
139 private final Logger log = getLogger(getClass());
140
Jian Li33b4db52019-03-20 18:22:38 +0900141 private static final String ERR_PACKET_IN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +0900142 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Ray Milkey3717e602018-02-01 13:49:47 -0800143 private static final long TIME_OUT_SNAT_PORT_MS = 120L * 1000L;
Jian Li5a26ab32019-03-21 15:20:01 +0900144 private static final int TP_PORT_MINIMUM_NUM = 1025;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145 private static final int TP_PORT_MAXIMUM_NUM = 65535;
Jian Li6a47fd02018-11-27 21:51:03 +0900146 private static final int VM_PREFIX = 32;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147
Jian Li33b4db52019-03-20 18:22:38 +0900148 private static final String MSG_ENABLED = "Enabled ";
149 private static final String MSG_DISABLED = "Disabled ";
150
151 /** Use Stateful SNAT for source NATing. */
152 private boolean useStatefulSnat = USE_STATEFUL_SNAT_DEFAULT;
153
154 private static final KryoNamespace.Builder NUMBER_SERIALIZER =
155 KryoNamespace.newBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900156 .register(KryoNamespaces.API);
157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159 protected CoreService coreService;
160
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 protected PacketService packetService;
163
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165 protected StorageService storageService;
166
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168 protected DeviceService deviceService;
169
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171 protected InstancePortService instancePortService;
172
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700173 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900174 protected ComponentConfigService configService;
175
176 @Reference(cardinality = ReferenceCardinality.MANDATORY)
177 protected DriverService driverService;
178
179 @Reference(cardinality = ReferenceCardinality.MANDATORY)
180 protected LeadershipService leadershipService;
181
182 @Reference(cardinality = ReferenceCardinality.MANDATORY)
183 protected MastershipService mastershipService;
184
185 @Reference(cardinality = ReferenceCardinality.MANDATORY)
186 protected ClusterService clusterService;
187
188 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900189 protected OpenstackNodeService osNodeService;
190
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700191 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900192 protected OpenstackNetworkAdminService osNetworkAdminService;
193
194 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900195 protected OpenstackNetworkService osNetworkService;
196
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700197 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900198 protected OpenstackRouterService osRouterService;
199
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700200 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900201 protected OpenstackFlowRuleService osFlowRuleService;
202
Hyunsun Moon44aac662017-02-18 02:07:01 +0900203 private final ExecutorService eventExecutor = newSingleThreadExecutor(
204 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900205 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Jian Li33b4db52019-03-20 18:22:38 +0900206 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
207 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
208 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900209
daniel park0bc7fdb2017-03-13 14:20:08 +0900210 private ConsistentMap<Integer, Long> allocatedPortNumMap;
211 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900212 private ApplicationId appId;
Jian Li33b4db52019-03-20 18:22:38 +0900213 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214
215 @Activate
216 protected void activate() {
217 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900218
219 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900220 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
Jian Li5a26ab32019-03-21 15:20:01 +0900221 .withName("openstackrouting-allocated-portnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900222 .withApplicationId(appId)
223 .build();
224
daniel park0bc7fdb2017-03-13 14:20:08 +0900225 unUsedPortNumSet = storageService.<Integer>setBuilder()
Jian Li5a26ab32019-03-21 15:20:01 +0900226 .withName("openstackrouting-unused-portnumset")
daniel park0bc7fdb2017-03-13 14:20:08 +0900227 .withSerializer(Serializer.using(KryoNamespaces.API))
228 .build()
229 .asDistributedSet();
230
Jian Li33b4db52019-03-20 18:22:38 +0900231 localNodeId = clusterService.getLocalNode().id();
232 leadershipService.runForLeadership(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Jian Li33b4db52019-03-20 18:22:38 +0900234
235 configService.registerProperties(getClass());
236 instancePortService.addListener(instancePortListener);
237 osRouterService.addListener(osRouterListener);
238 osNodeService.addListener(osNodeListener);
239
Jian Li5a26ab32019-03-21 15:20:01 +0900240 eventExecutor.execute(this::initializeUnusedPortNumSet);
241
Hyunsun Moon44aac662017-02-18 02:07:01 +0900242 log.info("Started");
243 }
244
245 @Deactivate
246 protected void deactivate() {
Jian Li33b4db52019-03-20 18:22:38 +0900247 osRouterService.removeListener(osRouterListener);
248 osNodeService.removeListener(osNodeListener);
249 instancePortService.removeListener(instancePortListener);
250 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900251 packetService.removeProcessor(packetProcessor);
Jian Li33b4db52019-03-20 18:22:38 +0900252 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900253 eventExecutor.shutdown();
254 log.info("Stopped");
255 }
256
Jian Li33b4db52019-03-20 18:22:38 +0900257 @Modified
258 protected void modified(ComponentContext context) {
259 Dictionary<?, ?> properties = context.getProperties();
260 Boolean flag;
261
262 flag = Tools.isPropertyEnabled(properties, USE_STATEFUL_SNAT);
263 if (flag == null) {
264 log.info("useStatefulSnat is not configured, " +
265 "using current value of {}", useStatefulSnat);
266 } else {
267 useStatefulSnat = flag;
268 log.info("Configured. useStatefulSnat is {}",
269 useStatefulSnat ? "enabled" : "disabled");
270 }
271
272 resetSnatRules();
273 }
274
Hyunsun Moon44aac662017-02-18 02:07:01 +0900275 private void processSnatPacket(PacketContext context, Ethernet eth) {
Jian Li25257212019-03-26 13:31:14 +0900276
Jian Liec857292019-04-03 18:18:52 +0900277 if (getStatefulSnatFlag()) {
Jian Li25257212019-03-26 13:31:14 +0900278 return;
279 }
280
Hyunsun Moon44aac662017-02-18 02:07:01 +0900281 IPv4 iPacket = (IPv4) eth.getPayload();
282 InboundPacket packetIn = context.inPacket();
283
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900284 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285
286 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
287 if (srcInstPort == null) {
Jian Li33b4db52019-03-20 18:22:38 +0900288 log.error(ERR_PACKET_IN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900289 eth.getSourceMAC());
290 return;
291 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900292
Hyunsun Moon44aac662017-02-18 02:07:01 +0900293 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
294 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
Jian Liebde74d2018-11-14 00:18:57 +0900295 IpAddress externalGatewayIp =
296 externalIpFromSubnet(srcSubnet, osRouterService, osNetworkService);
daniel parkb5817102018-02-15 00:18:51 +0900297
Hyunsun Moon44aac662017-02-18 02:07:01 +0900298 if (externalGatewayIp == null) {
299 return;
300 }
301
Jian Li5a26ab32019-03-21 15:20:01 +0900302 ExternalPeerRouter externalPeerRouter = externalPeerRouterFromSubnet(
303 srcSubnet, osRouterService, osNetworkService);
daniel park576969a2018-03-09 07:07:41 +0900304 if (externalPeerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900305 return;
306 }
307
Hyunsun Moon44aac662017-02-18 02:07:01 +0900308 populateSnatFlowRules(context.inPacket(),
309 srcInstPort,
310 TpPort.tpPort(patPort),
daniel park576969a2018-03-09 07:07:41 +0900311 externalGatewayIp, externalPeerRouter);
312
Hyunsun Moon44aac662017-02-18 02:07:01 +0900313
Ray Milkeyf0c47612017-09-28 11:29:38 -0700314 packetOut(eth.duplicate(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900315 packetIn.receivedFrom().deviceId(),
316 patPort,
daniel park576969a2018-03-09 07:07:41 +0900317 externalGatewayIp, externalPeerRouter);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900318 }
319
320 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
321 Port osPort = osNetworkService.port(instance.portId());
322 IP fixedIp = osPort.getFixedIps().stream()
323 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
324 .findAny().orElse(null);
325 if (fixedIp == null) {
326 return null;
327 }
328 return osNetworkService.subnet(fixedIp.getSubnetId());
329 }
330
Jian Li5ecfd1a2018-12-10 11:41:03 +0900331 private void populateSnatFlowRules(InboundPacket packetIn,
332 InstancePort srcInstPort,
333 TpPort patPort, IpAddress externalIp,
334 ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900335 Network osNet = osNetworkService.network(srcInstPort.networkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900336 Type netType = osNetworkService.networkType(srcInstPort.networkId());
337
Hyunsun Moon44aac662017-02-18 02:07:01 +0900338 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900339 final String error = String.format("%s network %s not found",
Jian Li5a26ab32019-03-21 15:20:01 +0900340 ERR_PACKET_IN, srcInstPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 throw new IllegalStateException(error);
342 }
343
Jian Li5a26ab32019-03-21 15:20:01 +0900344 setStatelessSnatDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900345 osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900346 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900347 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900348 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900349 patPort,
350 packetIn);
351
Jian Li5a26ab32019-03-21 15:20:01 +0900352 setStatelessSnatUpstreamRules(osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900353 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900355 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900356 patPort,
357 packetIn);
358 }
359
Jian Li5a26ab32019-03-21 15:20:01 +0900360 private void setStatelessSnatDownstreamRules(InstancePort srcInstPort,
361 String segmentId,
362 Type networkType,
363 IpAddress externalIp,
364 ExternalPeerRouter externalPeerRouter,
365 TpPort patPort,
366 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900367 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
368 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
369
370 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
371 .matchEthType(Ethernet.TYPE_IPV4)
372 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900373 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), VM_PREFIX))
374 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900375
376 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900377 .setEthDst(packetIn.parsed().getSourceMAC())
378 .setIpDst(internalIp);
379
Jian Li5e2ad4a2018-07-16 13:40:53 +0900380 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
381 sBuilder.matchVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900382 tBuilder.popVlan();
383 }
384
daniel parkee8700b2017-05-11 15:50:03 +0900385 switch (networkType) {
386 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900387 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900388 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900389 tBuilder.setTunnelId(Long.parseLong(segmentId));
390 break;
391 case VLAN:
392 tBuilder.pushVlan()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900393 .setVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900394 break;
395 default:
Jian Li71670d12018-03-02 21:31:07 +0900396 final String error = String.format("%s %s",
397 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900398 throw new IllegalStateException(error);
399 }
400
401
Hyunsun Moon44aac662017-02-18 02:07:01 +0900402 switch (iPacket.getProtocol()) {
403 case IPv4.PROTOCOL_TCP:
404 TCP tcpPacket = (TCP) iPacket.getPayload();
405 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
406 .matchTcpDst(patPort);
407 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
408 break;
409 case IPv4.PROTOCOL_UDP:
410 UDP udpPacket = (UDP) iPacket.getPayload();
411 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
412 .matchUdpDst(patPort);
413 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
414 break;
415 default:
416 break;
417 }
418
Hyunsun Moon0d457362017-06-27 17:19:41 +0900419 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
420 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Jian Li6a47fd02018-11-27 21:51:03 +0900421 TrafficTreatment treatment =
Jian Li5a26ab32019-03-21 15:20:01 +0900422 getDownstreamTreatment(networkType, tBuilder, gNode, srcNode);
sanghodc375372017-06-08 10:41:30 +0900423 osFlowRuleService.setRule(
424 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900425 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900426 sBuilder.build(),
Jian Li6a47fd02018-11-27 21:51:03 +0900427 treatment,
sanghodc375372017-06-08 10:41:30 +0900428 PRIORITY_SNAT_RULE,
429 GW_COMMON_TABLE,
430 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900431 });
432 }
433
Jian Li5a26ab32019-03-21 15:20:01 +0900434 private TrafficTreatment getDownstreamTreatment(Type networkType,
Jian Li6a47fd02018-11-27 21:51:03 +0900435 TrafficTreatment.Builder tBuilder,
436 OpenstackNode gNode,
437 OpenstackNode srcNode) {
438 TrafficTreatment.Builder tmpBuilder =
439 DefaultTrafficTreatment.builder(tBuilder.build());
440 switch (networkType) {
441 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900442 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900443 case GENEVE:
SONA Project6bc5c4a2018-12-14 23:49:52 +0900444 PortNumber portNum = tunnelPortNumByNetType(networkType, gNode);
Jian Li6a47fd02018-11-27 21:51:03 +0900445 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
446 deviceService,
447 gNode.intgBridge(),
448 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900449 .setOutput(portNum);
Jian Li6a47fd02018-11-27 21:51:03 +0900450 break;
451 case VLAN:
452 tmpBuilder.setOutput(gNode.vlanPortNum());
453 break;
454 default:
455 final String error = String.format("%s %s",
456 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
457 throw new IllegalStateException(error);
458 }
459
460 return tmpBuilder.build();
461 }
462
Jian Li5a26ab32019-03-21 15:20:01 +0900463 private void setStatelessSnatUpstreamRules(String segmentId,
464 Type networkType,
465 IpAddress externalIp,
466 ExternalPeerRouter externalPeerRouter,
467 TpPort patPort,
468 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900469 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900470
471 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900472 .matchEthType(Ethernet.TYPE_IPV4)
473 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900474 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), VM_PREFIX))
475 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900476
477 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900478
479 switch (networkType) {
480 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900481 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900482 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900483 sBuilder.matchTunnelId(Long.parseLong(segmentId));
484 break;
485 case VLAN:
486 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
487 tBuilder.popVlan();
488 break;
489 default:
Jian Li71670d12018-03-02 21:31:07 +0900490 final String error = String.format("%s %s",
491 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900492 throw new IllegalStateException(error);
493 }
494
Hyunsun Moon44aac662017-02-18 02:07:01 +0900495 switch (iPacket.getProtocol()) {
496 case IPv4.PROTOCOL_TCP:
497 TCP tcpPacket = (TCP) iPacket.getPayload();
498 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
499 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900500 tBuilder.setTcpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900501 break;
502 case IPv4.PROTOCOL_UDP:
503 UDP udpPacket = (UDP) iPacket.getPayload();
504 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
505 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900506 tBuilder.setUdpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900507 break;
508 default:
509 log.debug("Unsupported IPv4 protocol {}");
510 break;
511 }
512
Jian Li5e2ad4a2018-07-16 13:40:53 +0900513 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
514 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900515 }
516
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900518 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900519 TrafficTreatment.Builder tmpBuilder =
520 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900521 tmpBuilder.setOutput(gNode.uplinkPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900522
sanghodc375372017-06-08 10:41:30 +0900523 osFlowRuleService.setRule(
524 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900525 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900526 sBuilder.build(),
527 tmpBuilder.build(),
528 PRIORITY_SNAT_RULE,
529 GW_COMMON_TABLE,
530 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900531 });
532 }
533
534 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
daniel park576969a2018-03-09 07:07:41 +0900535 IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900536 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900537 switch (iPacket.getProtocol()) {
538 case IPv4.PROTOCOL_TCP:
Jian Li6a47fd02018-11-27 21:51:03 +0900539 iPacket.setPayload(buildPacketOutTcp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900540 break;
541 case IPv4.PROTOCOL_UDP:
Jian Li6a47fd02018-11-27 21:51:03 +0900542 iPacket.setPayload(buildPacketOutUdp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900543 break;
544 default:
545 log.trace("Temporally, this method can process UDP and TCP protocol.");
546 return;
547 }
548
549 iPacket.setSourceAddress(externalIp.toString());
550 iPacket.resetChecksum();
551 iPacket.setParent(ethPacketIn);
daniel park576969a2018-03-09 07:07:41 +0900552 ethPacketIn.setSourceMACAddress(DEFAULT_GATEWAY_MAC);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900553 ethPacketIn.setDestinationMACAddress(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900554 ethPacketIn.setPayload(iPacket);
daniel park576969a2018-03-09 07:07:41 +0900555
Jian Li5e2ad4a2018-07-16 13:40:53 +0900556 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
557 ethPacketIn.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900558 }
559
daniel parkee8700b2017-05-11 15:50:03 +0900560 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900561
Hyunsun Moon0d457362017-06-27 17:19:41 +0900562 OpenstackNode srcNode = osNodeService.node(srcDevice);
563 if (srcNode == null) {
564 final String error = String.format("Cannot find openstack node for %s",
565 srcDevice);
566 throw new IllegalStateException(error);
567 }
daniel parkee8700b2017-05-11 15:50:03 +0900568
daniel park576969a2018-03-09 07:07:41 +0900569 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
570
Hyunsun Moon44aac662017-02-18 02:07:01 +0900571 packetService.emit(new DefaultOutboundPacket(
572 srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900573 tBuilder.setOutput(srcNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900574 ByteBuffer.wrap(ethPacketIn.serialize())));
575 }
576
Jian Li6a47fd02018-11-27 21:51:03 +0900577 private TCP buildPacketOutTcp(IPv4 iPacket, int patPort) {
578 TCP tcpPacket = (TCP) iPacket.getPayload();
579 tcpPacket.setSourcePort(patPort);
580 tcpPacket.resetChecksum();
581 tcpPacket.setParent(iPacket);
582
583 return tcpPacket;
584 }
585
586 private UDP buildPacketOutUdp(IPv4 iPacket, int patPort) {
587 UDP udpPacket = (UDP) iPacket.getPayload();
588 udpPacket.setSourcePort(patPort);
589 udpPacket.resetChecksum();
590 udpPacket.setParent(iPacket);
591
592 return udpPacket;
593 }
594
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900595 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900596 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900597 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900598 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900599 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900600 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900601 unUsedPortNumSet.remove(portNum);
602 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900603 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900604 return portNum;
605 }
606
607 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900608 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900609 }
610
611 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900612 allocatedPortNumMap.entrySet().forEach(e -> {
Jian Li5a26ab32019-03-21 15:20:01 +0900613 if (System.currentTimeMillis() -
614 e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900615 allocatedPortNumMap.remove(e.getKey());
616 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900617 }
618 });
619 }
620
Jian Li33b4db52019-03-20 18:22:38 +0900621 private void initializeUnusedPortNumSet() {
622 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
623 if (!allocatedPortNumMap.containsKey(i)) {
624 unUsedPortNumSet.add(i);
625 }
626 }
627
628 clearPortNumMap();
629 }
630
631 private void resetSnatRules() {
Jian Liec857292019-04-03 18:18:52 +0900632 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900633 osRouterService.routerInterfaces().forEach(
634 routerIface -> {
635 setReactiveSnatRules(routerIface, false);
636 setStatefulSnatRules(routerIface, true);
637 }
638 );
639 } else {
640 osRouterService.routerInterfaces().forEach(
641 routerIface -> {
642 setStatefulSnatRules(routerIface, false);
643 setReactiveSnatRules(routerIface, true);
644 }
645 );
646 }
647 }
648
649 private void setRulesToGateway(OpenstackNode osNode,
650 String segmentId,
651 IpPrefix srcSubnet,
652 Type networkType,
653 boolean install) {
Jian Li5a26ab32019-03-21 15:20:01 +0900654 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY)
655 .stream().findFirst().orElse(null);
Jian Li33b4db52019-03-20 18:22:38 +0900656
657 if (sourceNatGateway == null) {
658 return;
659 }
660
661 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
662 .matchEthType(Ethernet.TYPE_IPV4)
663 .matchIPSrc(srcSubnet.getIp4Prefix())
664 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
665
666 switch (networkType) {
667 case VXLAN:
668 case GRE:
669 case GENEVE:
670 sBuilder.matchTunnelId(Long.parseLong(segmentId));
671 break;
672 case VLAN:
673 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
674 break;
675 default:
676 final String error = String.format("%s %s",
677 ERR_UNSUPPORTED_NET_TYPE,
678 networkType.toString());
679 throw new IllegalStateException(error);
680 }
681
682 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
683
684 switch (networkType) {
685 case VXLAN:
686 case GRE:
687 case GENEVE:
688 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
689 tBuilder.extension(buildExtension(
690 deviceService,
691 osNode.intgBridge(),
692 sourceNatGateway.dataIp().getIp4Address()),
693 osNode.intgBridge())
694 .setOutput(portNum);
695 break;
696
697 case VLAN:
698 tBuilder.setOutput(osNode.vlanPortNum());
699 break;
700
701 default:
702 break;
703 }
704
705 osFlowRuleService.setRule(
706 appId,
707 osNode.intgBridge(),
708 sBuilder.build(),
709 tBuilder.build(),
710 PRIORITY_EXTERNAL_ROUTING_RULE,
711 ROUTING_TABLE,
712 install);
713 }
714
715
716 private void routerUpdated(Router osRouter) {
717 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
718
719 ExternalPeerRouter externalPeerRouter =
720 osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5a26ab32019-03-21 15:20:01 +0900721 VlanId vlanId = externalPeerRouter == null ?
722 VlanId.NONE : externalPeerRouter.vlanId();
Jian Li33b4db52019-03-20 18:22:38 +0900723
724 if (exGateway == null) {
725 deleteUnassociatedExternalPeerRouter();
726 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
727 setSourceNat(iface, false));
728 } else {
729 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
730 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
731 setSourceNat(iface, exGateway.isEnableSnat()));
Jian Li4f3f75a2019-04-03 12:41:30 +0900732
733 setStatefulDownstreamRules(osRouter, exGateway.isEnableSnat());
Jian Li33b4db52019-03-20 18:22:38 +0900734 }
735 }
736
737 private void deleteUnassociatedExternalPeerRouter() {
738 log.trace("Deleting unassociated external peer router");
739
740 try {
741 Set<String> routerIps = Sets.newConcurrentHashSet();
742
743 osRouterService.routers().stream()
744 .filter(router -> getGatewayIpAddress(router) != null)
745 .map(router -> getGatewayIpAddress(router).toString())
746 .forEach(routerIps::add);
747
748 osNetworkAdminService.externalPeerRouters().stream()
749 .filter(externalPeerRouter ->
750 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
751 .forEach(externalPeerRouter -> {
752 osNetworkAdminService
753 .deleteExternalPeerRouter(
754 externalPeerRouter.ipAddress().toString());
755 log.trace("Deleted unassociated external peer router {}",
756 externalPeerRouter.ipAddress().toString());
757 });
758 } catch (Exception e) {
759 log.error("Exception occurred because of {}", e.toString());
760 }
761 }
762
763 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
764 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
765 if (exGateway != null && exGateway.isEnableSnat()) {
766 setSourceNat(osRouterIface, true);
767 }
768 }
769
770 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
771 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
772 if (exGateway != null && exGateway.isEnableSnat()) {
773 setSourceNat(osRouterIface, false);
774 }
775 }
776
777 private void setSourceNat(RouterInterface routerIface, boolean install) {
778 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
779 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
780 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
781
782 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
783 setRulesToGateway(cNode, osNet.getProviderSegID(),
784 IpPrefix.valueOf(osSubnet.getCidr()), netType, install);
785 });
786
Jian Liec857292019-04-03 18:18:52 +0900787 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900788 setStatefulSnatRules(routerIface, install);
789 } else {
790 setReactiveSnatRules(routerIface, install);
791 }
792
793 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
794 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
795 }
796
797 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
798 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
799 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
800 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
801
802 if (netType == FLAT) {
803 return;
804 }
805
806 Optional<Router> osRouter = osRouterService.routers().stream()
807 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
808 .findAny();
809
810 if (!osRouter.isPresent()) {
811 log.error("Cannot find a router for router interface {} ", routerIface);
812 return;
813 }
Jian Li5a26ab32019-03-21 15:20:01 +0900814
815 IpAddress natAddress = getExternalIp(osRouter.get(), osNetworkService);
Jian Li33b4db52019-03-20 18:22:38 +0900816 if (natAddress == null) {
817 return;
818 }
Jian Li5a26ab32019-03-21 15:20:01 +0900819
820 IpAddress extRouterAddress = getGatewayIpAddress(osRouter.get());
821 if (extRouterAddress == null) {
822 return;
823 }
824
825 ExternalPeerRouter externalPeerRouter =
826 osNetworkService.externalPeerRouter(extRouterAddress);
827 if (externalPeerRouter == null) {
828 return;
829 }
830
Jian Li33b4db52019-03-20 18:22:38 +0900831 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
832
Jian Li5a26ab32019-03-21 15:20:01 +0900833 Map<OpenstackNode, PortRange> gwPortRangeMap = getAssignedPortsForGateway(
Jian Li25257212019-03-26 13:31:14 +0900834 ImmutableList.copyOf(osNodeService.nodes(GATEWAY)));
Jian Li5a26ab32019-03-21 15:20:01 +0900835
Jian Li33b4db52019-03-20 18:22:38 +0900836 osNodeService.completeNodes(GATEWAY)
837 .forEach(gwNode -> {
838 instancePortService.instancePorts(netId)
839 .stream()
840 .filter(port -> port.state() == ACTIVE)
Jian Li5a26ab32019-03-21 15:20:01 +0900841 .forEach(port -> setGatewayToInstanceDownstreamRule(
842 gwNode, port, install));
Jian Li33b4db52019-03-20 18:22:38 +0900843
Jian Lia2995192019-04-02 14:13:04 +0900844 if (install) {
845 PortRange gwPortRange = gwPortRangeMap.get(gwNode);
Jian Li5a26ab32019-03-21 15:20:01 +0900846
Jian Lia2995192019-04-02 14:13:04 +0900847 Map<String, PortRange> netPortRangeMap =
848 getAssignedPortsForNet(getNetIdByRouterId(routerIface.getId()),
849 gwPortRange.min(), gwPortRange.max());
Jian Li5a26ab32019-03-21 15:20:01 +0900850
Jian Lia2995192019-04-02 14:13:04 +0900851 PortRange netPortRange = netPortRangeMap.get(osNet.getId());
Jian Li5a26ab32019-03-21 15:20:01 +0900852
Jian Lia2995192019-04-02 14:13:04 +0900853 setStatefulSnatUpstreamRule(gwNode, natAddress,
854 Long.parseLong(osNet.getProviderSegID()),
855 externalPeerRouter, netPortRange.min(),
856 netPortRange.max(), install);
857 } else {
858 setStatefulSnatUpstreamRule(gwNode, natAddress,
859 Long.parseLong(osNet.getProviderSegID()),
860 externalPeerRouter, 0, 0, install);
861 }
862
Jian Li33b4db52019-03-20 18:22:38 +0900863 });
864 }
865
Jian Li4f3f75a2019-04-03 12:41:30 +0900866 private void setStatefulDownstreamRules(Router osRouter, boolean install) {
867
Jian Li820ec7b2019-04-03 22:01:33 +0900868 if (!getStatefulSnatFlag()) {
869 return;
870 }
871
Jian Li4f3f75a2019-04-03 12:41:30 +0900872 IpAddress natAddress = getExternalIp(osRouter, osNetworkAdminService);
873 if (natAddress == null) {
874 return;
875 }
876
877 osNodeService.completeNodes(GATEWAY)
878 .forEach(gwNode -> {
879 setStatefulSnatDownstreamRule(gwNode.intgBridge(),
880 IpPrefix.valueOf(natAddress, VM_PREFIX), install);
881 });
882 }
883
Jian Li5a26ab32019-03-21 15:20:01 +0900884 private List<String> getNetIdByRouterId(String routerId) {
885 return osRouterService.routerInterfaces(routerId)
886 .stream()
887 .filter(ri -> osRouterService.router(ri.getId())
888 .getExternalGatewayInfo().isEnableSnat())
889 .map(RouterInterface::getSubnetId)
890 .map(si -> osNetworkAdminService.subnet(si))
891 .map(Subnet::getNetworkId)
892 .collect(Collectors.toList());
893 }
894
895 private Map<OpenstackNode, PortRange>
896 getAssignedPortsForGateway(List<OpenstackNode> gateways) {
897
898 Map<OpenstackNode, PortRange> gwPortRangeMap = Maps.newConcurrentMap();
899
900 int portRangeNumPerGwNode =
901 (TP_PORT_MAXIMUM_NUM - TP_PORT_MINIMUM_NUM + 1) / gateways.size();
902
903 for (int i = 0; i < gateways.size(); i++) {
904 int gwPortRangeMin = TP_PORT_MINIMUM_NUM + i * portRangeNumPerGwNode;
905 int gwPortRangeMax = TP_PORT_MINIMUM_NUM + (i + 1) * portRangeNumPerGwNode - 1;
906
907 gwPortRangeMap.put(gateways.get(i),
908 new PortRange(gwPortRangeMin, gwPortRangeMax));
909 }
910
911 return gwPortRangeMap;
912 }
913
914 private Map<String, PortRange> getAssignedPortsForNet(List<String> netIds,
915 int min, int max) {
916
917 Map<String, PortRange> netPortRangeMap = Maps.newConcurrentMap();
918
919 int portRangeNumPerNet = (max - min + 1) / netIds.size();
920
921 for (int i = 0; i < netIds.size(); i++) {
922 int netPortRangeMin = min + i * portRangeNumPerNet;
923 int netPortRangeMax = min + (i + 1) * portRangeNumPerNet - 1;
924
925 netPortRangeMap.put(netIds.get(i),
926 new PortRange(netPortRangeMin, netPortRangeMax));
927 }
928
929 return netPortRangeMap;
930 }
931
Jian Li33b4db52019-03-20 18:22:38 +0900932 private IpAddress getGatewayIpAddress(Router osRouter) {
933
934 if (osRouter.getExternalGatewayInfo() == null) {
935 return null;
936 }
937 String extNetId = osNetworkAdminService.network(
938 osRouter.getExternalGatewayInfo().getNetworkId()).getId();
939 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
940 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
941 .findAny();
942
943 if (!extSubnet.isPresent()) {
Jian Li5a26ab32019-03-21 15:20:01 +0900944 log.error("Cannot find external subnet for the router");
Jian Li33b4db52019-03-20 18:22:38 +0900945 return null;
946 }
947
948 return IpAddress.valueOf(extSubnet.get().getGateway());
949 }
950
951 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
952 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
953 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
954 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
955
956 osNodeService.completeNodes(GATEWAY)
957 .forEach(gwNode -> setRulesToController(
958 gwNode.intgBridge(),
959 osNet.getProviderSegID(),
960 IpPrefix.valueOf(osSubnet.getCidr()),
961 netType,
962 install));
963 }
964
Jian Li5a26ab32019-03-21 15:20:01 +0900965 private void setGatewayToInstanceDownstreamRule(OpenstackNode gwNode,
966 InstancePort instPort,
967 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +0900968
969 TrafficSelector selector = DefaultTrafficSelector.builder()
970 .matchEthType(Ethernet.TYPE_IPV4)
Jian Li5a26ab32019-03-21 15:20:01 +0900971 .matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX))
972 .build();
973
974 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
975 .setEthDst(instPort.macAddress());
976
977 Type netType = osNetworkAdminService.networkType(instPort.networkId());
978 String segId = osNetworkAdminService.segmentId(instPort.networkId());
979
980 switch (netType) {
981 case VXLAN:
982 case GRE:
983 case GENEVE:
984 tBuilder.setTunnelId(Long.valueOf(segId));
985 break;
986 case VLAN:
987 default:
988 final String error = String.format("%s %s",
989 ERR_UNSUPPORTED_NET_TYPE, netType.name());
990 throw new IllegalStateException(error);
991 }
992
993 OpenstackNode srcNode = osNodeService.node(instPort.deviceId());
994 TrafficTreatment treatment =
995 getDownstreamTreatment(netType, tBuilder, gwNode, srcNode);
996
997 osFlowRuleService.setRule(
998 appId,
999 gwNode.intgBridge(),
1000 selector,
1001 treatment,
1002 PRIORITY_STATEFUL_SNAT_RULE,
1003 GW_COMMON_TABLE,
1004 install);
1005 }
1006
1007 private void setStatefulSnatDownstreamRule(DeviceId deviceId,
1008 IpPrefix gatewayIp,
1009 boolean install) {
1010
1011 TrafficSelector selector = DefaultTrafficSelector.builder()
1012 .matchEthType(Ethernet.TYPE_IPV4)
1013 .matchIPDst(gatewayIp)
Jian Li33b4db52019-03-20 18:22:38 +09001014 .build();
1015
1016 ExtensionTreatment natTreatment = RulePopulatorUtil
1017 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
1018 .commit(false)
1019 .natAction(true)
1020 .table((short) 0)
1021 .build();
1022
1023 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li33b4db52019-03-20 18:22:38 +09001024 .extension(natTreatment, deviceId)
1025 .build();
1026
1027 osFlowRuleService.setRule(
1028 appId,
1029 deviceId,
1030 selector,
1031 treatment,
1032 PRIORITY_STATEFUL_SNAT_RULE,
1033 GW_COMMON_TABLE,
1034 install);
1035 }
1036
Jian Li5a26ab32019-03-21 15:20:01 +09001037 private void setStatefulSnatUpstreamRule(OpenstackNode gwNode,
1038 IpAddress gatewayIp,
1039 long vni,
1040 ExternalPeerRouter extPeerRouter,
1041 int minPortNum,
1042 int maxPortNum,
1043 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +09001044
1045 TrafficSelector selector = DefaultTrafficSelector.builder()
1046 .matchEthType(Ethernet.TYPE_IPV4)
1047 .matchEthDst(DEFAULT_GATEWAY_MAC)
1048 .matchTunnelId(vni)
1049 .build();
1050
Jian Lia2995192019-04-02 14:13:04 +09001051 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li33b4db52019-03-20 18:22:38 +09001052
Jian Lia2995192019-04-02 14:13:04 +09001053 // we do not consider to much like port range on removing the rules...
1054 if (install) {
1055 ExtensionTreatment natTreatment = RulePopulatorUtil
1056 .niciraConnTrackTreatmentBuilder(driverService, gwNode.intgBridge())
1057 .commit(true)
1058 .natFlag(CT_NAT_SRC_FLAG)
1059 .natAction(true)
1060 .natIp(gatewayIp)
1061 .natPortMin(TpPort.tpPort(minPortNum))
1062 .natPortMax(TpPort.tpPort(maxPortNum))
1063 .build();
1064
1065 tBuilder.extension(natTreatment, gwNode.intgBridge())
1066 .setEthDst(extPeerRouter.macAddress())
1067 .setEthSrc(DEFAULT_GATEWAY_MAC)
1068 .setOutput(gwNode.uplinkPortNum());
1069 }
Jian Li33b4db52019-03-20 18:22:38 +09001070
1071 osFlowRuleService.setRule(
1072 appId,
Jian Li5a26ab32019-03-21 15:20:01 +09001073 gwNode.intgBridge(),
Jian Li33b4db52019-03-20 18:22:38 +09001074 selector,
Jian Lia2995192019-04-02 14:13:04 +09001075 tBuilder.build(),
Jian Li33b4db52019-03-20 18:22:38 +09001076 PRIORITY_STATEFUL_SNAT_RULE,
1077 GW_COMMON_TABLE,
1078 install);
1079 }
1080
Jian Li33b4db52019-03-20 18:22:38 +09001081 private void setRulesToController(DeviceId deviceId,
1082 String segmentId,
1083 IpPrefix srcSubnet,
1084 Type networkType,
1085 boolean install) {
1086 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
1087 .matchEthType(Ethernet.TYPE_IPV4)
1088 .matchIPSrc(srcSubnet)
1089 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
1090
1091 switch (networkType) {
1092 case VXLAN:
1093 case GRE:
1094 case GENEVE:
1095 sBuilder.matchTunnelId(Long.parseLong(segmentId));
1096 break;
1097 case VLAN:
1098 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
1099 break;
1100 default:
1101 final String error = String.format("%s %s",
1102 ERR_UNSUPPORTED_NET_TYPE,
1103 networkType.toString());
1104 throw new IllegalStateException(error);
1105 }
1106
1107 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1108
1109 if (networkType == VLAN) {
1110 tBuilder.popVlan();
1111 }
1112
1113 tBuilder.punt();
1114
1115 osFlowRuleService.setRule(
1116 appId,
1117 deviceId,
1118 sBuilder.build(),
1119 tBuilder.build(),
1120 PRIORITY_EXTERNAL_ROUTING_RULE,
1121 GW_COMMON_TABLE,
1122 install);
1123 }
1124
Jian Liec857292019-04-03 18:18:52 +09001125 private boolean getStatefulSnatFlag() {
1126 Set<ConfigProperty> properties =
1127 configService.getProperties(getClass().getName());
1128 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
1129 }
1130
Jian Li33b4db52019-03-20 18:22:38 +09001131 private class InternalInstancePortListener implements InstancePortListener {
1132
1133 private boolean isRelevantHelper(InstancePortEvent event) {
1134 return mastershipService.isLocalMaster(event.subject().deviceId());
1135 }
1136
1137 @Override
1138 public void event(InstancePortEvent event) {
1139 InstancePort instPort = event.subject();
1140 switch (event.type()) {
1141 case OPENSTACK_INSTANCE_PORT_DETECTED:
1142 case OPENSTACK_INSTANCE_PORT_UPDATED:
1143 eventExecutor.execute(() ->
1144 processInstancePortDetection(event, instPort));
1145 break;
1146 case OPENSTACK_INSTANCE_PORT_VANISHED:
1147 eventExecutor.execute(() ->
1148 processInstancePortRemoval(event, instPort));
1149 break;
1150 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1151 eventExecutor.execute(() ->
1152 processInstanceMigrationStart(event, instPort));
1153 break;
1154 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1155 eventExecutor.execute(() ->
1156 processInstanceMigrationEnd(event, instPort));
1157 break;
1158 default:
1159 break;
1160 }
1161 }
1162
1163 private void processInstancePortDetection(InstancePortEvent event,
1164 InstancePort instPort) {
1165 if (!isRelevantHelper(event)) {
1166 return;
1167 }
1168
1169 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1170 instPort.macAddress(),
1171 instPort.ipAddress());
1172
1173 instPortDetected(event.subject());
1174 }
1175
1176 private void processInstancePortRemoval(InstancePortEvent event,
1177 InstancePort instPort) {
1178 if (!isRelevantHelper(event)) {
1179 return;
1180 }
1181
1182 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1183 instPort.macAddress(),
1184 instPort.ipAddress());
1185
1186 instPortRemoved(event.subject());
1187 }
1188
1189 private void processInstanceMigrationStart(InstancePortEvent event,
1190 InstancePort instPort) {
1191 if (!isRelevantHelper(event)) {
1192 return;
1193 }
1194
1195 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1196 instPort.macAddress(),
1197 instPort.ipAddress());
1198
1199 instPortDetected(instPort);
1200 }
1201
1202 private void processInstanceMigrationEnd(InstancePortEvent event,
1203 InstancePort instPort) {
1204 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1205 instPort.macAddress(),
1206 instPort.ipAddress());
1207 // TODO: need to reconfigure rules to point to update VM
1208 }
1209
1210 private void instPortDetected(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001211 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1212
1213 if (netType == FLAT) {
1214 return;
1215 }
1216
Jian Liec857292019-04-03 18:18:52 +09001217 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001218 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1219 setGatewayToInstanceDownstreamRule(gwNode, instPort, true));
Jian Li33b4db52019-03-20 18:22:38 +09001220 }
1221 }
1222
1223 private void instPortRemoved(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001224 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1225
1226 if (netType == FLAT) {
1227 return;
1228 }
1229
Jian Liec857292019-04-03 18:18:52 +09001230 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001231 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1232 setGatewayToInstanceDownstreamRule(gwNode, instPort, false));
Jian Li33b4db52019-03-20 18:22:38 +09001233 }
1234 }
1235 }
1236
1237 private class InternalRouterEventListener implements OpenstackRouterListener {
1238
1239 private boolean isRelevantHelper() {
1240 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1241 }
1242
1243 @Override
1244 public void event(OpenstackRouterEvent event) {
1245 switch (event.type()) {
1246 case OPENSTACK_ROUTER_CREATED:
1247 eventExecutor.execute(() -> processRouterCreation(event));
1248 break;
1249 case OPENSTACK_ROUTER_UPDATED:
1250 eventExecutor.execute(() -> processRouterUpdate(event));
1251 break;
1252 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1253 eventExecutor.execute(() -> processRouterIntfCreation(event));
1254 break;
1255 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1256 eventExecutor.execute(() -> processRouterIntfRemoval(event));
1257 break;
1258 case OPENSTACK_ROUTER_GATEWAY_ADDED:
Jian Li4f3f75a2019-04-03 12:41:30 +09001259 eventExecutor.execute(() -> processRouterGatewayAddition(event));
Jian Li33b4db52019-03-20 18:22:38 +09001260 break;
1261 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Li4f3f75a2019-04-03 12:41:30 +09001262 eventExecutor.execute(() -> processRouterGatewayRemoval(event));
Jian Li33b4db52019-03-20 18:22:38 +09001263 break;
1264 default:
1265 break;
1266 }
1267 }
1268
1269 private void processRouterCreation(OpenstackRouterEvent event) {
1270 if (!isRelevantHelper()) {
1271 return;
1272 }
1273
1274 log.debug("Router(name:{}, ID:{}) is created",
1275 event.subject().getName(),
1276 event.subject().getId());
1277
1278 routerUpdated(event.subject());
1279 }
1280
1281 private void processRouterUpdate(OpenstackRouterEvent event) {
1282 if (!isRelevantHelper()) {
1283 return;
1284 }
1285
1286 log.debug("Router(name:{}, ID:{}) is updated",
1287 event.subject().getName(),
1288 event.subject().getId());
1289
1290 routerUpdated(event.subject());
1291 }
1292
1293 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1294 if (!isRelevantHelper()) {
1295 return;
1296 }
1297
1298 log.debug("Router interface {} added to router {}",
1299 event.routerIface().getPortId(),
1300 event.routerIface().getId());
1301
1302 routerIfaceAdded(event.subject(), event.routerIface());
1303 }
1304
1305 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1306 if (!isRelevantHelper()) {
1307 return;
1308 }
1309
1310 log.debug("Router interface {} removed from router {}",
1311 event.routerIface().getPortId(),
1312 event.routerIface().getId());
1313
1314 routerIfaceRemoved(event.subject(), event.routerIface());
1315 }
Jian Li4f3f75a2019-04-03 12:41:30 +09001316
1317 private void processRouterGatewayAddition(OpenstackRouterEvent event) {
1318 if (!isRelevantHelper()) {
1319 return;
1320 }
1321
1322 log.debug("Router external gateway {} added",
1323 event.externalGateway().getNetworkId());
1324
1325 setStatefulDownstreamRules(event.subject(), true);
1326 }
1327
1328 private void processRouterGatewayRemoval(OpenstackRouterEvent event) {
1329 if (!isRelevantHelper()) {
1330 return;
1331 }
1332
1333 log.debug("Router external gateway {} removed",
1334 event.externalGateway().getNetworkId());
1335
1336 setStatefulDownstreamRules(event.subject(), false);
1337 }
Jian Li33b4db52019-03-20 18:22:38 +09001338 }
1339
Hyunsun Moon44aac662017-02-18 02:07:01 +09001340 private class InternalPacketProcessor implements PacketProcessor {
1341
1342 @Override
1343 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +09001344
Hyunsun Moon44aac662017-02-18 02:07:01 +09001345 if (context.isHandled()) {
1346 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001347 }
1348
1349 InboundPacket pkt = context.inPacket();
1350 Ethernet eth = pkt.parsed();
1351 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
1352 return;
1353 }
1354
1355 IPv4 iPacket = (IPv4) eth.getPayload();
1356 switch (iPacket.getProtocol()) {
1357 case IPv4.PROTOCOL_ICMP:
1358 break;
1359 case IPv4.PROTOCOL_UDP:
1360 UDP udpPacket = (UDP) iPacket.getPayload();
1361 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
1362 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
Jian Li6a47fd02018-11-27 21:51:03 +09001363 break; // don't process DHCP
Hyunsun Moon44aac662017-02-18 02:07:01 +09001364 }
1365 default:
Jian Li34220ea2018-11-14 01:30:24 +09001366 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001367 if (!isRelevantHelper(context)) {
1368 return;
1369 }
Jian Li34220ea2018-11-14 01:30:24 +09001370 processSnatPacket(context, eth);
1371 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001372 break;
1373 }
1374 }
Jian Li34220ea2018-11-14 01:30:24 +09001375
1376 private boolean isRelevantHelper(PacketContext context) {
1377 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
1378 .stream().map(OpenstackNode::intgBridge)
1379 .collect(Collectors.toSet());
1380
1381 return gateways.contains(context.inPacket().receivedFrom().deviceId());
1382 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001383 }
Jian Li33b4db52019-03-20 18:22:38 +09001384
1385 private class InternalNodeEventListener implements OpenstackNodeListener {
1386
1387 private boolean isRelevantHelper() {
1388 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1389 }
1390
1391 @Override
1392 public void event(OpenstackNodeEvent event) {
1393 OpenstackNode osNode = event.subject();
1394 switch (event.type()) {
1395 case OPENSTACK_NODE_COMPLETE:
Jian Li5a26ab32019-03-21 15:20:01 +09001396 eventExecutor.execute(() -> processGatewayCompletion(osNode));
1397 eventExecutor.execute(() -> reconfigureRouters(osNode));
1398 break;
1399 case OPENSTACK_NODE_REMOVED:
1400 eventExecutor.execute(() -> processGatewayRemoval(osNode));
Jian Li5d795f22019-04-01 23:07:40 +09001401 eventExecutor.execute(() -> reconfigureRouters(osNode));
1402 break;
Jian Li33b4db52019-03-20 18:22:38 +09001403 case OPENSTACK_NODE_INCOMPLETE:
1404 case OPENSTACK_NODE_UPDATED:
Jian Li5a26ab32019-03-21 15:20:01 +09001405 eventExecutor.execute(() -> reconfigureRouters(osNode));
Jian Li33b4db52019-03-20 18:22:38 +09001406 break;
1407 case OPENSTACK_NODE_CREATED:
1408 default:
1409 break;
1410 }
1411 }
1412
Jian Li5a26ab32019-03-21 15:20:01 +09001413 private void processGatewayCompletion(OpenstackNode osNode) {
1414 if (!isRelevantHelper()) {
1415 return;
1416 }
1417
Jian Liec857292019-04-03 18:18:52 +09001418 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Li5a26ab32019-03-21 15:20:01 +09001419 instancePortService.instancePorts().forEach(instPort ->
1420 setGatewayToInstanceDownstreamRule(osNode, instPort, true));
1421 }
1422 }
1423
1424 private void processGatewayRemoval(OpenstackNode osNode) {
1425 if (!isRelevantHelper()) {
1426 return;
1427 }
1428
Jian Liec857292019-04-03 18:18:52 +09001429 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Li5a26ab32019-03-21 15:20:01 +09001430 instancePortService.instancePorts().forEach(instPort ->
1431 setGatewayToInstanceDownstreamRule(osNode, instPort, false));
1432 }
1433 }
1434
Jian Li33b4db52019-03-20 18:22:38 +09001435 private void reconfigureRouters(OpenstackNode osNode) {
Jian Li5a26ab32019-03-21 15:20:01 +09001436 if (!isRelevantHelper()) {
1437 return;
1438 }
1439
Jian Li33b4db52019-03-20 18:22:38 +09001440 osRouterService.routers().forEach(osRouter -> {
1441 routerUpdated(osRouter);
1442 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1443 routerIfaceAdded(osRouter, iface);
1444 });
1445 });
1446 log.info("Reconfigure routers for {}", osNode.hostname());
1447 }
1448 }
Jian Li5a26ab32019-03-21 15:20:01 +09001449
1450 private class PortRange {
1451 private int min;
1452 private int max;
1453
1454 /**
1455 * A default constructor.
1456 *
1457 * @param min min port num
1458 * @param max max port num
1459 */
1460 public PortRange(int min, int max) {
1461 this.min = min;
1462 this.max = max;
1463 }
1464
1465 /**
1466 * Obtains min port num.
1467 *
1468 * @return min port num
1469 */
1470 int min() {
1471 return min;
1472 }
1473
1474 /**
1475 * Obtains max port num.
1476 *
1477 * @return max port num
1478 */
1479 int max() {
1480 return max;
1481 }
1482
1483 @Override
1484 public String toString() {
1485 return MoreObjects.toStringHelper(this)
1486 .add("min", min)
1487 .add("max", max)
1488 .toString();
1489 }
1490
1491 @Override
1492 public boolean equals(Object o) {
1493 if (this == o) {
1494 return true;
1495 }
1496 if (o == null || getClass() != o.getClass()) {
1497 return false;
1498 }
1499 PortRange portRange = (PortRange) o;
1500 return min == portRange.min &&
1501 max == portRange.max;
1502 }
1503
1504 @Override
1505 public int hashCode() {
1506 return Objects.hash(min, max);
1507 }
1508 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001509}