blob: 82e419692cbc7a7bdd4275168ee7e6e23a862572 [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;
Jian Lifdb8d872019-04-08 10:38:58 +090020import com.google.common.collect.ImmutableSet;
Jian Li5a26ab32019-03-21 15:20:01 +090021import com.google.common.collect.Maps;
Jian Li33b4db52019-03-20 18:22:38 +090022import com.google.common.collect.Sets;
Hyunsun Moon44aac662017-02-18 02:07:01 +090023import org.onlab.packet.Ethernet;
24import org.onlab.packet.IPv4;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.IpPrefix;
Hyunsun Moon44aac662017-02-18 02:07:01 +090027import org.onlab.packet.TCP;
28import org.onlab.packet.TpPort;
29import org.onlab.packet.UDP;
daniel parkee8700b2017-05-11 15:50:03 +090030import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onlab.util.KryoNamespace;
Jian Li33b4db52019-03-20 18:22:38 +090032import org.onlab.util.Tools;
33import org.onosproject.cfg.ComponentConfigService;
Jian Liec857292019-04-03 18:18:52 +090034import org.onosproject.cfg.ConfigProperty;
Jian Li33b4db52019-03-20 18:22:38 +090035import org.onosproject.cluster.ClusterService;
36import org.onosproject.cluster.LeadershipService;
37import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
Jian Li33b4db52019-03-20 18:22:38 +090040import org.onosproject.mastership.MastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.net.DeviceId;
Jian Li2d68c192018-12-13 15:52:59 +090042import org.onosproject.net.PortNumber;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.net.device.DeviceService;
Jian Li33b4db52019-03-20 18:22:38 +090044import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090045import org.onosproject.net.flow.DefaultTrafficSelector;
46import org.onosproject.net.flow.DefaultTrafficTreatment;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.flow.TrafficTreatment;
Jian Li33b4db52019-03-20 18:22:38 +090049import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.onosproject.net.packet.DefaultOutboundPacket;
51import org.onosproject.net.packet.InboundPacket;
52import org.onosproject.net.packet.PacketContext;
53import org.onosproject.net.packet.PacketProcessor;
54import org.onosproject.net.packet.PacketService;
Jian Li33b4db52019-03-20 18:22:38 +090055import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090056import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090057import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li33b4db52019-03-20 18:22:38 +090058import org.onosproject.openstacknetworking.api.InstancePortEvent;
59import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090060import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090061import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090062import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Li33b4db52019-03-20 18:22:38 +090063import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lidc5d5012019-04-04 13:54:41 +090065import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
66import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Jian Li33b4db52019-03-20 18:22:38 +090067import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
68import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
sanghodc375372017-06-08 10:41:30 +090069import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Li26949762018-03-30 15:46:37 +090070import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090071import org.onosproject.openstacknode.api.OpenstackNode;
Jian Li33b4db52019-03-20 18:22:38 +090072import org.onosproject.openstacknode.api.OpenstackNodeEvent;
73import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090074import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075import org.onosproject.store.serializers.KryoNamespaces;
76import org.onosproject.store.service.ConsistentMap;
daniel park0bc7fdb2017-03-13 14:20:08 +090077import org.onosproject.store.service.DistributedSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090078import org.onosproject.store.service.Serializer;
79import org.onosproject.store.service.StorageService;
Jian Li33b4db52019-03-20 18:22:38 +090080import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081import org.openstack4j.model.network.IP;
82import org.openstack4j.model.network.Network;
83import org.openstack4j.model.network.Port;
Jian Li33b4db52019-03-20 18:22:38 +090084import org.openstack4j.model.network.Router;
85import org.openstack4j.model.network.RouterInterface;
Hyunsun Moon44aac662017-02-18 02:07:01 +090086import org.openstack4j.model.network.Subnet;
Jian Li33b4db52019-03-20 18:22:38 +090087import org.osgi.service.component.ComponentContext;
Jian Liebde74d2018-11-14 00:18:57 +090088import org.osgi.service.component.annotations.Activate;
89import org.osgi.service.component.annotations.Component;
90import org.osgi.service.component.annotations.Deactivate;
Jian Li33b4db52019-03-20 18:22:38 +090091import org.osgi.service.component.annotations.Modified;
Jian Liebde74d2018-11-14 00:18:57 +090092import org.osgi.service.component.annotations.Reference;
93import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090094import org.slf4j.Logger;
95
96import java.nio.ByteBuffer;
Jian Li33b4db52019-03-20 18:22:38 +090097import java.util.Dictionary;
Jian Li5a26ab32019-03-21 15:20:01 +090098import java.util.List;
99import java.util.Map;
Jian Li33b4db52019-03-20 18:22:38 +0900100import java.util.Objects;
101import java.util.Optional;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900102import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900104import java.util.stream.Collectors;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105
106import static java.util.concurrent.Executors.newSingleThreadExecutor;
107import static org.onlab.util.Tools.groupedThreads;
daniel parkeeb8e042018-02-21 14:06:58 +0900108import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
109import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
110import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li33b4db52019-03-20 18:22:38 +0900111import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
daniel parkeeb8e042018-02-21 14:06:58 +0900112import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SNAT_RULE;
Jian Li33b4db52019-03-20 18:22:38 +0900113import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
114import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li33b4db52019-03-20 18:22:38 +0900115import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
116import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
117import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT;
118import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT_DEFAULT;
Jian Li5b22f112020-10-05 22:36:41 +0900119import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.deriveResourceName;
Jian Lifa62b372020-02-24 16:42:24 +0900120import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalGatewayIpSnatEnabled;
Jian Liebde74d2018-11-14 00:18:57 +0900121import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Jian Liec857292019-04-03 18:18:52 +0900122import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Lifa62b372020-02-24 16:42:24 +0900123import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getRouterFromSubnet;
Jian Li2d68c192018-12-13 15:52:59 +0900124import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
Jian Li5a26ab32019-03-21 15:20:01 +0900125import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.CT_NAT_SRC_FLAG;
Jian Li33b4db52019-03-20 18:22:38 +0900126import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
127import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900128import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129import static org.slf4j.LoggerFactory.getLogger;
130
131/**
132 * Handle packets needs SNAT.
133 */
Jian Li33b4db52019-03-20 18:22:38 +0900134@Component(
135 immediate = true,
136 property = {
137 USE_STATEFUL_SNAT + ":Boolean=" + USE_STATEFUL_SNAT_DEFAULT
138 }
139)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140public class OpenstackRoutingSnatHandler {
141
142 private final Logger log = getLogger(getClass());
143
Jian Li33b4db52019-03-20 18:22:38 +0900144 private static final String ERR_PACKET_IN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +0900145 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Ray Milkey3717e602018-02-01 13:49:47 -0800146 private static final long TIME_OUT_SNAT_PORT_MS = 120L * 1000L;
Jian Li5a26ab32019-03-21 15:20:01 +0900147 private static final int TP_PORT_MINIMUM_NUM = 1025;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 private static final int TP_PORT_MAXIMUM_NUM = 65535;
Jian Li6a47fd02018-11-27 21:51:03 +0900149 private static final int VM_PREFIX = 32;
Jian Lidc5d5012019-04-04 13:54:41 +0900150 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151
Jian Li33b4db52019-03-20 18:22:38 +0900152 private static final String MSG_ENABLED = "Enabled ";
153 private static final String MSG_DISABLED = "Disabled ";
154
155 /** Use Stateful SNAT for source NATing. */
156 private boolean useStatefulSnat = USE_STATEFUL_SNAT_DEFAULT;
157
158 private static final KryoNamespace.Builder NUMBER_SERIALIZER =
159 KryoNamespace.newBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160 .register(KryoNamespaces.API);
161
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163 protected CoreService coreService;
164
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700165 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 protected PacketService packetService;
167
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700168 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 protected StorageService storageService;
170
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700171 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172 protected DeviceService deviceService;
173
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700174 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 protected InstancePortService instancePortService;
176
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700177 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900178 protected ComponentConfigService configService;
179
180 @Reference(cardinality = ReferenceCardinality.MANDATORY)
181 protected DriverService driverService;
182
183 @Reference(cardinality = ReferenceCardinality.MANDATORY)
184 protected LeadershipService leadershipService;
185
186 @Reference(cardinality = ReferenceCardinality.MANDATORY)
187 protected MastershipService mastershipService;
188
189 @Reference(cardinality = ReferenceCardinality.MANDATORY)
190 protected ClusterService clusterService;
191
192 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 protected OpenstackNodeService osNodeService;
194
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700195 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900196 protected OpenstackNetworkAdminService osNetworkAdminService;
197
198 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900199 protected OpenstackNetworkService osNetworkService;
200
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700201 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900202 protected OpenstackRouterService osRouterService;
203
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700204 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900205 protected OpenstackFlowRuleService osFlowRuleService;
206
Hyunsun Moon44aac662017-02-18 02:07:01 +0900207 private final ExecutorService eventExecutor = newSingleThreadExecutor(
208 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900209 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Jian Li33b4db52019-03-20 18:22:38 +0900210 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
211 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
212 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Lidc5d5012019-04-04 13:54:41 +0900213 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214
daniel park0bc7fdb2017-03-13 14:20:08 +0900215 private ConsistentMap<Integer, Long> allocatedPortNumMap;
216 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900217 private ApplicationId appId;
Jian Li33b4db52019-03-20 18:22:38 +0900218 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900219
220 @Activate
221 protected void activate() {
222 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900223
224 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900225 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
Jian Li5a26ab32019-03-21 15:20:01 +0900226 .withName("openstackrouting-allocated-portnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900227 .withApplicationId(appId)
228 .build();
229
daniel park0bc7fdb2017-03-13 14:20:08 +0900230 unUsedPortNumSet = storageService.<Integer>setBuilder()
Jian Li5a26ab32019-03-21 15:20:01 +0900231 .withName("openstackrouting-unused-portnumset")
daniel park0bc7fdb2017-03-13 14:20:08 +0900232 .withSerializer(Serializer.using(KryoNamespaces.API))
233 .build()
234 .asDistributedSet();
235
Jian Li33b4db52019-03-20 18:22:38 +0900236 localNodeId = clusterService.getLocalNode().id();
237 leadershipService.runForLeadership(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900238 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Jian Li33b4db52019-03-20 18:22:38 +0900239
240 configService.registerProperties(getClass());
241 instancePortService.addListener(instancePortListener);
242 osRouterService.addListener(osRouterListener);
243 osNodeService.addListener(osNodeListener);
Jian Lidc5d5012019-04-04 13:54:41 +0900244 osNetworkAdminService.addListener(osNetworkListener);
Jian Li33b4db52019-03-20 18:22:38 +0900245
Jian Li5a26ab32019-03-21 15:20:01 +0900246 eventExecutor.execute(this::initializeUnusedPortNumSet);
247
Hyunsun Moon44aac662017-02-18 02:07:01 +0900248 log.info("Started");
249 }
250
251 @Deactivate
252 protected void deactivate() {
Jian Lidc5d5012019-04-04 13:54:41 +0900253 osNetworkAdminService.removeListener(osNetworkListener);
Jian Li33b4db52019-03-20 18:22:38 +0900254 osRouterService.removeListener(osRouterListener);
255 osNodeService.removeListener(osNodeListener);
256 instancePortService.removeListener(instancePortListener);
257 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900258 packetService.removeProcessor(packetProcessor);
Jian Li33b4db52019-03-20 18:22:38 +0900259 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900260 eventExecutor.shutdown();
261 log.info("Stopped");
262 }
263
Jian Li33b4db52019-03-20 18:22:38 +0900264 @Modified
265 protected void modified(ComponentContext context) {
266 Dictionary<?, ?> properties = context.getProperties();
267 Boolean flag;
268
269 flag = Tools.isPropertyEnabled(properties, USE_STATEFUL_SNAT);
270 if (flag == null) {
271 log.info("useStatefulSnat is not configured, " +
272 "using current value of {}", useStatefulSnat);
273 } else {
274 useStatefulSnat = flag;
275 log.info("Configured. useStatefulSnat is {}",
276 useStatefulSnat ? "enabled" : "disabled");
277 }
278
279 resetSnatRules();
280 }
281
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 private void processSnatPacket(PacketContext context, Ethernet eth) {
Jian Li25257212019-03-26 13:31:14 +0900283
Jian Liec857292019-04-03 18:18:52 +0900284 if (getStatefulSnatFlag()) {
Jian Li25257212019-03-26 13:31:14 +0900285 return;
286 }
287
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 IPv4 iPacket = (IPv4) eth.getPayload();
289 InboundPacket packetIn = context.inPacket();
290
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900291 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900292
293 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
294 if (srcInstPort == null) {
Jian Li33b4db52019-03-20 18:22:38 +0900295 log.error(ERR_PACKET_IN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900296 eth.getSourceMAC());
297 return;
298 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900299
Hyunsun Moon44aac662017-02-18 02:07:01 +0900300 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
301 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
Jian Lifa62b372020-02-24 16:42:24 +0900302
303 Router osRouter = getRouterFromSubnet(srcSubnet, osRouterService);
304
305 if (osRouter == null || osRouter.getExternalGatewayInfo() == null) {
306 // this router does not have external connectivity
307 log.warn("No router is associated with the given subnet {}", srcSubnet);
308 return;
309 }
310
Jian Liebde74d2018-11-14 00:18:57 +0900311 IpAddress externalGatewayIp =
Jian Lifa62b372020-02-24 16:42:24 +0900312 externalGatewayIpSnatEnabled(osRouter, osNetworkAdminService);
daniel parkb5817102018-02-15 00:18:51 +0900313
Hyunsun Moon44aac662017-02-18 02:07:01 +0900314 if (externalGatewayIp == null) {
315 return;
316 }
317
Jian Li5a26ab32019-03-21 15:20:01 +0900318 ExternalPeerRouter externalPeerRouter = externalPeerRouterFromSubnet(
319 srcSubnet, osRouterService, osNetworkService);
daniel park576969a2018-03-09 07:07:41 +0900320 if (externalPeerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900321 return;
322 }
323
Hyunsun Moon44aac662017-02-18 02:07:01 +0900324 populateSnatFlowRules(context.inPacket(),
325 srcInstPort,
326 TpPort.tpPort(patPort),
daniel park576969a2018-03-09 07:07:41 +0900327 externalGatewayIp, externalPeerRouter);
328
Hyunsun Moon44aac662017-02-18 02:07:01 +0900329
Ray Milkeyf0c47612017-09-28 11:29:38 -0700330 packetOut(eth.duplicate(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900331 packetIn.receivedFrom().deviceId(),
332 patPort,
daniel park576969a2018-03-09 07:07:41 +0900333 externalGatewayIp, externalPeerRouter);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900334 }
335
336 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
337 Port osPort = osNetworkService.port(instance.portId());
338 IP fixedIp = osPort.getFixedIps().stream()
339 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
340 .findAny().orElse(null);
341 if (fixedIp == null) {
342 return null;
343 }
344 return osNetworkService.subnet(fixedIp.getSubnetId());
345 }
346
Jian Li5ecfd1a2018-12-10 11:41:03 +0900347 private void populateSnatFlowRules(InboundPacket packetIn,
348 InstancePort srcInstPort,
349 TpPort patPort, IpAddress externalIp,
350 ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900351 Network osNet = osNetworkService.network(srcInstPort.networkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900352 Type netType = osNetworkService.networkType(srcInstPort.networkId());
353
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900355 final String error = String.format("%s network %s not found",
Jian Li5a26ab32019-03-21 15:20:01 +0900356 ERR_PACKET_IN, srcInstPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900357 throw new IllegalStateException(error);
358 }
359
Jian Li5a26ab32019-03-21 15:20:01 +0900360 setStatelessSnatDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900361 osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900362 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900363 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900364 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900365 patPort,
366 packetIn);
367
Jian Li5a26ab32019-03-21 15:20:01 +0900368 setStatelessSnatUpstreamRules(osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900369 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900370 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900371 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900372 patPort,
373 packetIn);
374 }
375
Jian Li5a26ab32019-03-21 15:20:01 +0900376 private void setStatelessSnatDownstreamRules(InstancePort srcInstPort,
377 String segmentId,
378 Type networkType,
379 IpAddress externalIp,
380 ExternalPeerRouter externalPeerRouter,
381 TpPort patPort,
382 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900383 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
384 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
385
386 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
387 .matchEthType(Ethernet.TYPE_IPV4)
388 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900389 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), VM_PREFIX))
390 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900391
392 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900393 .setEthDst(packetIn.parsed().getSourceMAC())
394 .setIpDst(internalIp);
395
Jian Li5e2ad4a2018-07-16 13:40:53 +0900396 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
397 sBuilder.matchVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900398 tBuilder.popVlan();
399 }
400
daniel parkee8700b2017-05-11 15:50:03 +0900401 switch (networkType) {
402 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900403 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900404 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900405 tBuilder.setTunnelId(Long.parseLong(segmentId));
406 break;
407 case VLAN:
408 tBuilder.pushVlan()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900409 .setVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900410 break;
411 default:
Jian Li71670d12018-03-02 21:31:07 +0900412 final String error = String.format("%s %s",
413 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900414 throw new IllegalStateException(error);
415 }
416
417
Hyunsun Moon44aac662017-02-18 02:07:01 +0900418 switch (iPacket.getProtocol()) {
419 case IPv4.PROTOCOL_TCP:
420 TCP tcpPacket = (TCP) iPacket.getPayload();
421 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
422 .matchTcpDst(patPort);
423 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
424 break;
425 case IPv4.PROTOCOL_UDP:
426 UDP udpPacket = (UDP) iPacket.getPayload();
427 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
428 .matchUdpDst(patPort);
429 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
430 break;
431 default:
432 break;
433 }
434
Hyunsun Moon0d457362017-06-27 17:19:41 +0900435 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
436 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Jian Li6a47fd02018-11-27 21:51:03 +0900437 TrafficTreatment treatment =
Jian Li5a26ab32019-03-21 15:20:01 +0900438 getDownstreamTreatment(networkType, tBuilder, gNode, srcNode);
sanghodc375372017-06-08 10:41:30 +0900439 osFlowRuleService.setRule(
440 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900441 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900442 sBuilder.build(),
Jian Li6a47fd02018-11-27 21:51:03 +0900443 treatment,
sanghodc375372017-06-08 10:41:30 +0900444 PRIORITY_SNAT_RULE,
445 GW_COMMON_TABLE,
446 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900447 });
448 }
449
Jian Li5a26ab32019-03-21 15:20:01 +0900450 private TrafficTreatment getDownstreamTreatment(Type networkType,
Jian Li6a47fd02018-11-27 21:51:03 +0900451 TrafficTreatment.Builder tBuilder,
452 OpenstackNode gNode,
453 OpenstackNode srcNode) {
454 TrafficTreatment.Builder tmpBuilder =
455 DefaultTrafficTreatment.builder(tBuilder.build());
456 switch (networkType) {
457 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900458 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900459 case GENEVE:
SONA Project6bc5c4a2018-12-14 23:49:52 +0900460 PortNumber portNum = tunnelPortNumByNetType(networkType, gNode);
Jian Li6a47fd02018-11-27 21:51:03 +0900461 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
462 deviceService,
463 gNode.intgBridge(),
464 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900465 .setOutput(portNum);
Jian Li6a47fd02018-11-27 21:51:03 +0900466 break;
467 case VLAN:
468 tmpBuilder.setOutput(gNode.vlanPortNum());
469 break;
470 default:
471 final String error = String.format("%s %s",
472 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
473 throw new IllegalStateException(error);
474 }
475
476 return tmpBuilder.build();
477 }
478
Jian Li5a26ab32019-03-21 15:20:01 +0900479 private void setStatelessSnatUpstreamRules(String segmentId,
480 Type networkType,
481 IpAddress externalIp,
482 ExternalPeerRouter externalPeerRouter,
483 TpPort patPort,
484 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900485 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900486
487 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900488 .matchEthType(Ethernet.TYPE_IPV4)
489 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900490 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), VM_PREFIX))
491 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900492
493 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900494
495 switch (networkType) {
496 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900497 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900498 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900499 sBuilder.matchTunnelId(Long.parseLong(segmentId));
500 break;
501 case VLAN:
502 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
503 tBuilder.popVlan();
504 break;
505 default:
Jian Li71670d12018-03-02 21:31:07 +0900506 final String error = String.format("%s %s",
507 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900508 throw new IllegalStateException(error);
509 }
510
Hyunsun Moon44aac662017-02-18 02:07:01 +0900511 switch (iPacket.getProtocol()) {
512 case IPv4.PROTOCOL_TCP:
513 TCP tcpPacket = (TCP) iPacket.getPayload();
514 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
515 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900516 tBuilder.setTcpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517 break;
518 case IPv4.PROTOCOL_UDP:
519 UDP udpPacket = (UDP) iPacket.getPayload();
520 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
521 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900522 tBuilder.setUdpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900523 break;
524 default:
525 log.debug("Unsupported IPv4 protocol {}");
526 break;
527 }
528
Jian Li5e2ad4a2018-07-16 13:40:53 +0900529 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
530 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900531 }
532
Hyunsun Moon44aac662017-02-18 02:07:01 +0900533 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900534 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900535 TrafficTreatment.Builder tmpBuilder =
536 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900537 tmpBuilder.setOutput(gNode.uplinkPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900538
sanghodc375372017-06-08 10:41:30 +0900539 osFlowRuleService.setRule(
540 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900541 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900542 sBuilder.build(),
543 tmpBuilder.build(),
544 PRIORITY_SNAT_RULE,
545 GW_COMMON_TABLE,
546 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900547 });
548 }
549
550 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
daniel park576969a2018-03-09 07:07:41 +0900551 IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900552 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900553 switch (iPacket.getProtocol()) {
554 case IPv4.PROTOCOL_TCP:
Jian Li6a47fd02018-11-27 21:51:03 +0900555 iPacket.setPayload(buildPacketOutTcp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900556 break;
557 case IPv4.PROTOCOL_UDP:
Jian Li6a47fd02018-11-27 21:51:03 +0900558 iPacket.setPayload(buildPacketOutUdp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559 break;
560 default:
561 log.trace("Temporally, this method can process UDP and TCP protocol.");
562 return;
563 }
564
565 iPacket.setSourceAddress(externalIp.toString());
566 iPacket.resetChecksum();
567 iPacket.setParent(ethPacketIn);
daniel park576969a2018-03-09 07:07:41 +0900568 ethPacketIn.setSourceMACAddress(DEFAULT_GATEWAY_MAC);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900569 ethPacketIn.setDestinationMACAddress(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900570 ethPacketIn.setPayload(iPacket);
daniel park576969a2018-03-09 07:07:41 +0900571
Jian Li5e2ad4a2018-07-16 13:40:53 +0900572 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
573 ethPacketIn.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900574 }
575
daniel parkee8700b2017-05-11 15:50:03 +0900576 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900577
Hyunsun Moon0d457362017-06-27 17:19:41 +0900578 OpenstackNode srcNode = osNodeService.node(srcDevice);
579 if (srcNode == null) {
580 final String error = String.format("Cannot find openstack node for %s",
581 srcDevice);
582 throw new IllegalStateException(error);
583 }
daniel parkee8700b2017-05-11 15:50:03 +0900584
daniel park576969a2018-03-09 07:07:41 +0900585 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
586
Hyunsun Moon44aac662017-02-18 02:07:01 +0900587 packetService.emit(new DefaultOutboundPacket(
588 srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900589 tBuilder.setOutput(srcNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900590 ByteBuffer.wrap(ethPacketIn.serialize())));
591 }
592
Jian Li6a47fd02018-11-27 21:51:03 +0900593 private TCP buildPacketOutTcp(IPv4 iPacket, int patPort) {
594 TCP tcpPacket = (TCP) iPacket.getPayload();
595 tcpPacket.setSourcePort(patPort);
596 tcpPacket.resetChecksum();
597 tcpPacket.setParent(iPacket);
598
599 return tcpPacket;
600 }
601
602 private UDP buildPacketOutUdp(IPv4 iPacket, int patPort) {
603 UDP udpPacket = (UDP) iPacket.getPayload();
604 udpPacket.setSourcePort(patPort);
605 udpPacket.resetChecksum();
606 udpPacket.setParent(iPacket);
607
608 return udpPacket;
609 }
610
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900611 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900612 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900613 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900614 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900615 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900616 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900617 unUsedPortNumSet.remove(portNum);
618 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900619 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900620 return portNum;
621 }
622
623 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900624 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900625 }
626
627 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900628 allocatedPortNumMap.entrySet().forEach(e -> {
Jian Li5a26ab32019-03-21 15:20:01 +0900629 if (System.currentTimeMillis() -
630 e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900631 allocatedPortNumMap.remove(e.getKey());
632 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900633 }
634 });
635 }
636
Jian Li33b4db52019-03-20 18:22:38 +0900637 private void initializeUnusedPortNumSet() {
638 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
639 if (!allocatedPortNumMap.containsKey(i)) {
640 unUsedPortNumSet.add(i);
641 }
642 }
643
644 clearPortNumMap();
645 }
646
647 private void resetSnatRules() {
Jian Liec857292019-04-03 18:18:52 +0900648 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900649 osRouterService.routerInterfaces().forEach(
650 routerIface -> {
651 setReactiveSnatRules(routerIface, false);
652 setStatefulSnatRules(routerIface, true);
653 }
654 );
655 } else {
656 osRouterService.routerInterfaces().forEach(
657 routerIface -> {
658 setStatefulSnatRules(routerIface, false);
659 setReactiveSnatRules(routerIface, true);
660 }
661 );
662 }
663 }
664
665 private void setRulesToGateway(OpenstackNode osNode,
666 String segmentId,
667 IpPrefix srcSubnet,
668 Type networkType,
669 boolean install) {
Jian Li5a26ab32019-03-21 15:20:01 +0900670 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY)
671 .stream().findFirst().orElse(null);
Jian Li33b4db52019-03-20 18:22:38 +0900672
673 if (sourceNatGateway == null) {
674 return;
675 }
676
677 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
678 .matchEthType(Ethernet.TYPE_IPV4)
679 .matchIPSrc(srcSubnet.getIp4Prefix())
680 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
681
682 switch (networkType) {
683 case VXLAN:
684 case GRE:
685 case GENEVE:
686 sBuilder.matchTunnelId(Long.parseLong(segmentId));
687 break;
688 case VLAN:
689 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
690 break;
691 default:
692 final String error = String.format("%s %s",
693 ERR_UNSUPPORTED_NET_TYPE,
694 networkType.toString());
695 throw new IllegalStateException(error);
696 }
697
698 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
699
700 switch (networkType) {
701 case VXLAN:
702 case GRE:
703 case GENEVE:
704 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
705 tBuilder.extension(buildExtension(
706 deviceService,
707 osNode.intgBridge(),
708 sourceNatGateway.dataIp().getIp4Address()),
709 osNode.intgBridge())
710 .setOutput(portNum);
711 break;
712
713 case VLAN:
714 tBuilder.setOutput(osNode.vlanPortNum());
715 break;
716
717 default:
718 break;
719 }
720
721 osFlowRuleService.setRule(
722 appId,
723 osNode.intgBridge(),
724 sBuilder.build(),
725 tBuilder.build(),
726 PRIORITY_EXTERNAL_ROUTING_RULE,
727 ROUTING_TABLE,
728 install);
729 }
730
731
732 private void routerUpdated(Router osRouter) {
733 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
734
735 ExternalPeerRouter externalPeerRouter =
736 osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5a26ab32019-03-21 15:20:01 +0900737 VlanId vlanId = externalPeerRouter == null ?
738 VlanId.NONE : externalPeerRouter.vlanId();
Jian Li33b4db52019-03-20 18:22:38 +0900739
740 if (exGateway == null) {
741 deleteUnassociatedExternalPeerRouter();
742 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
743 setSourceNat(iface, false));
744 } else {
745 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
746 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
747 setSourceNat(iface, exGateway.isEnableSnat()));
748 }
749 }
750
751 private void deleteUnassociatedExternalPeerRouter() {
752 log.trace("Deleting unassociated external peer router");
753
754 try {
755 Set<String> routerIps = Sets.newConcurrentHashSet();
756
757 osRouterService.routers().stream()
758 .filter(router -> getGatewayIpAddress(router) != null)
759 .map(router -> getGatewayIpAddress(router).toString())
760 .forEach(routerIps::add);
761
762 osNetworkAdminService.externalPeerRouters().stream()
763 .filter(externalPeerRouter ->
764 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
765 .forEach(externalPeerRouter -> {
766 osNetworkAdminService
767 .deleteExternalPeerRouter(
768 externalPeerRouter.ipAddress().toString());
769 log.trace("Deleted unassociated external peer router {}",
770 externalPeerRouter.ipAddress().toString());
771 });
772 } catch (Exception e) {
773 log.error("Exception occurred because of {}", e.toString());
774 }
775 }
776
777 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
778 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
779 if (exGateway != null && exGateway.isEnableSnat()) {
780 setSourceNat(osRouterIface, true);
781 }
782 }
783
784 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
785 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
786 if (exGateway != null && exGateway.isEnableSnat()) {
787 setSourceNat(osRouterIface, false);
788 }
789 }
790
791 private void setSourceNat(RouterInterface routerIface, boolean install) {
792 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
793 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
794 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
795
796 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
797 setRulesToGateway(cNode, osNet.getProviderSegID(),
798 IpPrefix.valueOf(osSubnet.getCidr()), netType, install);
799 });
800
Jian Liec857292019-04-03 18:18:52 +0900801 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900802 setStatefulSnatRules(routerIface, install);
803 } else {
804 setReactiveSnatRules(routerIface, install);
805 }
806
807 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
808 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
809 }
810
811 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
812 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
813 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
814 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
815
816 if (netType == FLAT) {
Jian Lifa62b372020-02-24 16:42:24 +0900817 log.warn("FLAT typed network does not need SNAT rules");
Jian Li33b4db52019-03-20 18:22:38 +0900818 return;
819 }
820
821 Optional<Router> osRouter = osRouterService.routers().stream()
Jian Lifa62b372020-02-24 16:42:24 +0900822 .filter(router -> routerIface.getId().equals(router.getId()))
Jian Li33b4db52019-03-20 18:22:38 +0900823 .findAny();
824
825 if (!osRouter.isPresent()) {
Jian Lifa62b372020-02-24 16:42:24 +0900826 log.warn("Cannot find a router attached with the given router interface {} ", routerIface);
Jian Li33b4db52019-03-20 18:22:38 +0900827 return;
828 }
Jian Li5a26ab32019-03-21 15:20:01 +0900829
Jian Lifa62b372020-02-24 16:42:24 +0900830 IpAddress natAddress = externalGatewayIpSnatEnabled(osRouter.get(), osNetworkAdminService);
Jian Li33b4db52019-03-20 18:22:38 +0900831 if (natAddress == null) {
Jian Lid529d422020-07-14 00:05:24 +0900832 log.debug("NAT address is not found");
Jian Li33b4db52019-03-20 18:22:38 +0900833 return;
834 }
Jian Li5a26ab32019-03-21 15:20:01 +0900835
836 IpAddress extRouterAddress = getGatewayIpAddress(osRouter.get());
837 if (extRouterAddress == null) {
Jian Lifa62b372020-02-24 16:42:24 +0900838 log.warn("External router address is not found");
Jian Li5a26ab32019-03-21 15:20:01 +0900839 return;
840 }
841
842 ExternalPeerRouter externalPeerRouter =
843 osNetworkService.externalPeerRouter(extRouterAddress);
844 if (externalPeerRouter == null) {
Jian Lifa62b372020-02-24 16:42:24 +0900845 log.warn("External peer router not found");
Jian Li5a26ab32019-03-21 15:20:01 +0900846 return;
847 }
848
Jian Li5a26ab32019-03-21 15:20:01 +0900849 Map<OpenstackNode, PortRange> gwPortRangeMap = getAssignedPortsForGateway(
Jian Li25257212019-03-26 13:31:14 +0900850 ImmutableList.copyOf(osNodeService.nodes(GATEWAY)));
Jian Li5a26ab32019-03-21 15:20:01 +0900851
Jian Lidc5d5012019-04-04 13:54:41 +0900852 osNodeService.completeNodes(GATEWAY).forEach(gwNode -> {
853 if (install) {
854 PortRange gwPortRange = gwPortRangeMap.get(gwNode);
Jian Li33b4db52019-03-20 18:22:38 +0900855
Jian Lidc5d5012019-04-04 13:54:41 +0900856 Map<String, PortRange> netPortRangeMap =
857 getAssignedPortsForNet(getNetIdByRouterId(routerIface.getId()),
858 gwPortRange.min(), gwPortRange.max());
Jian Li5a26ab32019-03-21 15:20:01 +0900859
Jian Lidc5d5012019-04-04 13:54:41 +0900860 PortRange netPortRange = netPortRangeMap.get(osNet.getId());
Jian Li5a26ab32019-03-21 15:20:01 +0900861
Jian Lidc5d5012019-04-04 13:54:41 +0900862 setStatefulSnatUpstreamRule(gwNode, natAddress,
863 Long.parseLong(osNet.getProviderSegID()),
864 externalPeerRouter, netPortRange.min(),
865 netPortRange.max(), install);
866 } else {
867 setStatefulSnatUpstreamRule(gwNode, natAddress,
868 Long.parseLong(osNet.getProviderSegID()),
869 externalPeerRouter, 0, 0, install);
870 }
871 });
Jian Li33b4db52019-03-20 18:22:38 +0900872 }
873
Jian Li4f3f75a2019-04-03 12:41:30 +0900874 private void setStatefulDownstreamRules(Router osRouter, boolean install) {
875
Jian Li820ec7b2019-04-03 22:01:33 +0900876 if (!getStatefulSnatFlag()) {
877 return;
878 }
879
Jian Lifa62b372020-02-24 16:42:24 +0900880 IpAddress natAddress = externalGatewayIpSnatEnabled(osRouter, osNetworkAdminService);
Jian Li4f3f75a2019-04-03 12:41:30 +0900881 if (natAddress == null) {
882 return;
883 }
884
Jian Lidc5d5012019-04-04 13:54:41 +0900885 setStatefulDownstreamRules(natAddress, install);
886 }
887
888 private void setStatefulDownstreamRules(IpAddress natAddress, boolean install) {
Jian Li4f3f75a2019-04-03 12:41:30 +0900889 osNodeService.completeNodes(GATEWAY)
890 .forEach(gwNode -> {
891 setStatefulSnatDownstreamRule(gwNode.intgBridge(),
892 IpPrefix.valueOf(natAddress, VM_PREFIX), install);
Jian Lidc5d5012019-04-04 13:54:41 +0900893 });
Jian Li4f3f75a2019-04-03 12:41:30 +0900894 }
895
Jian Li5a26ab32019-03-21 15:20:01 +0900896 private List<String> getNetIdByRouterId(String routerId) {
897 return osRouterService.routerInterfaces(routerId)
898 .stream()
899 .filter(ri -> osRouterService.router(ri.getId())
900 .getExternalGatewayInfo().isEnableSnat())
901 .map(RouterInterface::getSubnetId)
902 .map(si -> osNetworkAdminService.subnet(si))
903 .map(Subnet::getNetworkId)
904 .collect(Collectors.toList());
905 }
906
907 private Map<OpenstackNode, PortRange>
908 getAssignedPortsForGateway(List<OpenstackNode> gateways) {
909
910 Map<OpenstackNode, PortRange> gwPortRangeMap = Maps.newConcurrentMap();
911
912 int portRangeNumPerGwNode =
913 (TP_PORT_MAXIMUM_NUM - TP_PORT_MINIMUM_NUM + 1) / gateways.size();
914
915 for (int i = 0; i < gateways.size(); i++) {
916 int gwPortRangeMin = TP_PORT_MINIMUM_NUM + i * portRangeNumPerGwNode;
917 int gwPortRangeMax = TP_PORT_MINIMUM_NUM + (i + 1) * portRangeNumPerGwNode - 1;
918
919 gwPortRangeMap.put(gateways.get(i),
920 new PortRange(gwPortRangeMin, gwPortRangeMax));
921 }
922
923 return gwPortRangeMap;
924 }
925
926 private Map<String, PortRange> getAssignedPortsForNet(List<String> netIds,
927 int min, int max) {
928
929 Map<String, PortRange> netPortRangeMap = Maps.newConcurrentMap();
930
931 int portRangeNumPerNet = (max - min + 1) / netIds.size();
932
933 for (int i = 0; i < netIds.size(); i++) {
934 int netPortRangeMin = min + i * portRangeNumPerNet;
935 int netPortRangeMax = min + (i + 1) * portRangeNumPerNet - 1;
936
937 netPortRangeMap.put(netIds.get(i),
938 new PortRange(netPortRangeMin, netPortRangeMax));
939 }
940
941 return netPortRangeMap;
942 }
943
Jian Li33b4db52019-03-20 18:22:38 +0900944 private IpAddress getGatewayIpAddress(Router osRouter) {
945
946 if (osRouter.getExternalGatewayInfo() == null) {
947 return null;
948 }
949 String extNetId = osNetworkAdminService.network(
950 osRouter.getExternalGatewayInfo().getNetworkId()).getId();
951 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
952 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
953 .findAny();
954
955 if (!extSubnet.isPresent()) {
Jian Li5a26ab32019-03-21 15:20:01 +0900956 log.error("Cannot find external subnet for the router");
Jian Li33b4db52019-03-20 18:22:38 +0900957 return null;
958 }
959
960 return IpAddress.valueOf(extSubnet.get().getGateway());
961 }
962
963 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
964 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
965 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
966 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
967
968 osNodeService.completeNodes(GATEWAY)
969 .forEach(gwNode -> setRulesToController(
970 gwNode.intgBridge(),
971 osNet.getProviderSegID(),
972 IpPrefix.valueOf(osSubnet.getCidr()),
973 netType,
974 install));
975 }
976
Jian Li5a26ab32019-03-21 15:20:01 +0900977 private void setGatewayToInstanceDownstreamRule(OpenstackNode gwNode,
978 InstancePort instPort,
979 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +0900980
981 TrafficSelector selector = DefaultTrafficSelector.builder()
982 .matchEthType(Ethernet.TYPE_IPV4)
Jian Li5a26ab32019-03-21 15:20:01 +0900983 .matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX))
984 .build();
985
986 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
987 .setEthDst(instPort.macAddress());
988
989 Type netType = osNetworkAdminService.networkType(instPort.networkId());
990 String segId = osNetworkAdminService.segmentId(instPort.networkId());
991
992 switch (netType) {
993 case VXLAN:
994 case GRE:
995 case GENEVE:
996 tBuilder.setTunnelId(Long.valueOf(segId));
997 break;
998 case VLAN:
999 default:
1000 final String error = String.format("%s %s",
1001 ERR_UNSUPPORTED_NET_TYPE, netType.name());
1002 throw new IllegalStateException(error);
1003 }
1004
1005 OpenstackNode srcNode = osNodeService.node(instPort.deviceId());
1006 TrafficTreatment treatment =
1007 getDownstreamTreatment(netType, tBuilder, gwNode, srcNode);
1008
1009 osFlowRuleService.setRule(
1010 appId,
1011 gwNode.intgBridge(),
1012 selector,
1013 treatment,
1014 PRIORITY_STATEFUL_SNAT_RULE,
1015 GW_COMMON_TABLE,
1016 install);
1017 }
1018
1019 private void setStatefulSnatDownstreamRule(DeviceId deviceId,
1020 IpPrefix gatewayIp,
1021 boolean install) {
1022
Jian Lifdb8d872019-04-08 10:38:58 +09001023 Set<TrafficSelector> selectors = Sets.newConcurrentHashSet();
1024
1025 ImmutableSet<Byte> ipv4Proto = ImmutableSet.of(IPv4.PROTOCOL_TCP, IPv4.PROTOCOL_UDP);
1026
1027 ipv4Proto.forEach(proto -> {
1028 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1029 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
1030 .matchIPDst(gatewayIp)
1031 .matchIPProtocol(proto);
1032 selectors.add(sBuilder.build());
1033 });
1034
Jian Li33b4db52019-03-20 18:22:38 +09001035
1036 ExtensionTreatment natTreatment = RulePopulatorUtil
1037 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
1038 .commit(false)
1039 .natAction(true)
1040 .table((short) 0)
1041 .build();
1042
1043 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li33b4db52019-03-20 18:22:38 +09001044 .extension(natTreatment, deviceId)
1045 .build();
1046
Jian Lifdb8d872019-04-08 10:38:58 +09001047 selectors.forEach(s -> {
1048 osFlowRuleService.setRule(
1049 appId,
1050 deviceId,
1051 s,
1052 treatment,
1053 PRIORITY_STATEFUL_SNAT_RULE,
1054 GW_COMMON_TABLE,
1055 install);
1056 });
Jian Li33b4db52019-03-20 18:22:38 +09001057 }
1058
Jian Li5a26ab32019-03-21 15:20:01 +09001059 private void setStatefulSnatUpstreamRule(OpenstackNode gwNode,
1060 IpAddress gatewayIp,
1061 long vni,
1062 ExternalPeerRouter extPeerRouter,
1063 int minPortNum,
1064 int maxPortNum,
1065 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +09001066
1067 TrafficSelector selector = DefaultTrafficSelector.builder()
1068 .matchEthType(Ethernet.TYPE_IPV4)
1069 .matchEthDst(DEFAULT_GATEWAY_MAC)
1070 .matchTunnelId(vni)
1071 .build();
1072
Jian Lia2995192019-04-02 14:13:04 +09001073 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li33b4db52019-03-20 18:22:38 +09001074
Jian Lia2995192019-04-02 14:13:04 +09001075 // we do not consider to much like port range on removing the rules...
1076 if (install) {
1077 ExtensionTreatment natTreatment = RulePopulatorUtil
1078 .niciraConnTrackTreatmentBuilder(driverService, gwNode.intgBridge())
1079 .commit(true)
1080 .natFlag(CT_NAT_SRC_FLAG)
1081 .natAction(true)
1082 .natIp(gatewayIp)
1083 .natPortMin(TpPort.tpPort(minPortNum))
1084 .natPortMax(TpPort.tpPort(maxPortNum))
1085 .build();
1086
1087 tBuilder.extension(natTreatment, gwNode.intgBridge())
1088 .setEthDst(extPeerRouter.macAddress())
1089 .setEthSrc(DEFAULT_GATEWAY_MAC)
1090 .setOutput(gwNode.uplinkPortNum());
1091 }
Jian Li33b4db52019-03-20 18:22:38 +09001092
1093 osFlowRuleService.setRule(
1094 appId,
Jian Li5a26ab32019-03-21 15:20:01 +09001095 gwNode.intgBridge(),
Jian Li33b4db52019-03-20 18:22:38 +09001096 selector,
Jian Lia2995192019-04-02 14:13:04 +09001097 tBuilder.build(),
Jian Li33b4db52019-03-20 18:22:38 +09001098 PRIORITY_STATEFUL_SNAT_RULE,
1099 GW_COMMON_TABLE,
1100 install);
1101 }
1102
Jian Li33b4db52019-03-20 18:22:38 +09001103 private void setRulesToController(DeviceId deviceId,
1104 String segmentId,
1105 IpPrefix srcSubnet,
1106 Type networkType,
1107 boolean install) {
1108 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
1109 .matchEthType(Ethernet.TYPE_IPV4)
1110 .matchIPSrc(srcSubnet)
1111 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
1112
1113 switch (networkType) {
1114 case VXLAN:
1115 case GRE:
1116 case GENEVE:
1117 sBuilder.matchTunnelId(Long.parseLong(segmentId));
1118 break;
1119 case VLAN:
1120 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
1121 break;
1122 default:
1123 final String error = String.format("%s %s",
1124 ERR_UNSUPPORTED_NET_TYPE,
1125 networkType.toString());
1126 throw new IllegalStateException(error);
1127 }
1128
1129 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1130
1131 if (networkType == VLAN) {
1132 tBuilder.popVlan();
1133 }
1134
1135 tBuilder.punt();
1136
1137 osFlowRuleService.setRule(
1138 appId,
1139 deviceId,
1140 sBuilder.build(),
1141 tBuilder.build(),
1142 PRIORITY_EXTERNAL_ROUTING_RULE,
1143 GW_COMMON_TABLE,
1144 install);
1145 }
1146
Jian Liec857292019-04-03 18:18:52 +09001147 private boolean getStatefulSnatFlag() {
1148 Set<ConfigProperty> properties =
1149 configService.getProperties(getClass().getName());
1150 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
1151 }
1152
Jian Li33b4db52019-03-20 18:22:38 +09001153 private class InternalInstancePortListener implements InstancePortListener {
1154
1155 private boolean isRelevantHelper(InstancePortEvent event) {
1156 return mastershipService.isLocalMaster(event.subject().deviceId());
1157 }
1158
1159 @Override
1160 public void event(InstancePortEvent event) {
1161 InstancePort instPort = event.subject();
1162 switch (event.type()) {
1163 case OPENSTACK_INSTANCE_PORT_DETECTED:
1164 case OPENSTACK_INSTANCE_PORT_UPDATED:
1165 eventExecutor.execute(() ->
1166 processInstancePortDetection(event, instPort));
1167 break;
1168 case OPENSTACK_INSTANCE_PORT_VANISHED:
1169 eventExecutor.execute(() ->
1170 processInstancePortRemoval(event, instPort));
1171 break;
1172 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1173 eventExecutor.execute(() ->
1174 processInstanceMigrationStart(event, instPort));
1175 break;
1176 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1177 eventExecutor.execute(() ->
1178 processInstanceMigrationEnd(event, instPort));
1179 break;
1180 default:
1181 break;
1182 }
1183 }
1184
1185 private void processInstancePortDetection(InstancePortEvent event,
1186 InstancePort instPort) {
1187 if (!isRelevantHelper(event)) {
1188 return;
1189 }
1190
1191 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1192 instPort.macAddress(),
1193 instPort.ipAddress());
1194
1195 instPortDetected(event.subject());
1196 }
1197
1198 private void processInstancePortRemoval(InstancePortEvent event,
1199 InstancePort instPort) {
1200 if (!isRelevantHelper(event)) {
1201 return;
1202 }
1203
1204 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1205 instPort.macAddress(),
1206 instPort.ipAddress());
1207
1208 instPortRemoved(event.subject());
1209 }
1210
1211 private void processInstanceMigrationStart(InstancePortEvent event,
1212 InstancePort instPort) {
1213 if (!isRelevantHelper(event)) {
1214 return;
1215 }
1216
1217 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1218 instPort.macAddress(),
1219 instPort.ipAddress());
1220
1221 instPortDetected(instPort);
1222 }
1223
1224 private void processInstanceMigrationEnd(InstancePortEvent event,
1225 InstancePort instPort) {
1226 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1227 instPort.macAddress(),
1228 instPort.ipAddress());
1229 // TODO: need to reconfigure rules to point to update VM
1230 }
1231
1232 private void instPortDetected(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001233 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1234
1235 if (netType == FLAT) {
1236 return;
1237 }
1238
Jian Liec857292019-04-03 18:18:52 +09001239 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001240 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1241 setGatewayToInstanceDownstreamRule(gwNode, instPort, true));
Jian Li33b4db52019-03-20 18:22:38 +09001242 }
1243 }
1244
1245 private void instPortRemoved(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001246 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1247
1248 if (netType == FLAT) {
1249 return;
1250 }
1251
Jian Liec857292019-04-03 18:18:52 +09001252 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001253 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1254 setGatewayToInstanceDownstreamRule(gwNode, instPort, false));
Jian Li33b4db52019-03-20 18:22:38 +09001255 }
1256 }
1257 }
1258
Jian Lidc5d5012019-04-04 13:54:41 +09001259 private class InternalNetworkEventListener implements OpenstackNetworkListener {
1260
1261 @Override
1262 public boolean isRelevant(OpenstackNetworkEvent event) {
1263 Port osPort = event.port();
1264 if (osPort == null || osPort.getFixedIps() == null) {
1265 return false;
1266 }
1267
1268 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
1269 getStatefulSnatFlag();
1270 }
1271
1272 private boolean isRelevantHelper() {
1273 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1274 }
1275
1276 @Override
1277 public void event(OpenstackNetworkEvent event) {
1278 IpAddress ipAddress = externalIp(event.port());
1279 switch (event.type()) {
1280 case OPENSTACK_PORT_CREATED:
1281 case OPENSTACK_PORT_UPDATED:
1282 eventExecutor.execute(() -> processPortCreation(ipAddress));
1283 break;
1284 case OPENSTACK_PORT_REMOVED:
1285 eventExecutor.execute(() -> processPortRemoval(ipAddress));
1286 break;
1287 default:
1288 // do nothing
1289 break;
1290 }
1291 }
1292
1293 private void processPortCreation(IpAddress ipAddress) {
1294 if (!isRelevantHelper() || ipAddress == null) {
1295 return;
1296 }
1297
1298 setStatefulDownstreamRules(ipAddress, true);
1299 }
1300
1301 private void processPortRemoval(IpAddress ipAddress) {
1302 if (!isRelevantHelper() || ipAddress == null) {
1303 return;
1304 }
1305
1306 setStatefulDownstreamRules(ipAddress, false);
1307 }
1308
1309 private IpAddress externalIp(Port port) {
1310 IP ip = port.getFixedIps().stream().findAny().orElse(null);
1311
1312 if (ip != null && ip.getIpAddress() != null) {
1313 return IpAddress.valueOf(ip.getIpAddress());
1314 }
1315
1316 return null;
1317 }
1318 }
1319
Jian Li33b4db52019-03-20 18:22:38 +09001320 private class InternalRouterEventListener implements OpenstackRouterListener {
1321
1322 private boolean isRelevantHelper() {
1323 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1324 }
1325
1326 @Override
1327 public void event(OpenstackRouterEvent event) {
1328 switch (event.type()) {
1329 case OPENSTACK_ROUTER_CREATED:
1330 eventExecutor.execute(() -> processRouterCreation(event));
1331 break;
1332 case OPENSTACK_ROUTER_UPDATED:
1333 eventExecutor.execute(() -> processRouterUpdate(event));
1334 break;
1335 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1336 eventExecutor.execute(() -> processRouterIntfCreation(event));
1337 break;
1338 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1339 eventExecutor.execute(() -> processRouterIntfRemoval(event));
1340 break;
Jian Li33b4db52019-03-20 18:22:38 +09001341 default:
1342 break;
1343 }
1344 }
1345
1346 private void processRouterCreation(OpenstackRouterEvent event) {
1347 if (!isRelevantHelper()) {
1348 return;
1349 }
1350
1351 log.debug("Router(name:{}, ID:{}) is created",
Jian Li5b22f112020-10-05 22:36:41 +09001352 deriveResourceName(event.subject()), event.subject().getId());
Jian Li33b4db52019-03-20 18:22:38 +09001353
1354 routerUpdated(event.subject());
1355 }
1356
1357 private void processRouterUpdate(OpenstackRouterEvent event) {
1358 if (!isRelevantHelper()) {
1359 return;
1360 }
1361
1362 log.debug("Router(name:{}, ID:{}) is updated",
Jian Li5b22f112020-10-05 22:36:41 +09001363 deriveResourceName(event.subject()), event.subject().getId());
Jian Li33b4db52019-03-20 18:22:38 +09001364
1365 routerUpdated(event.subject());
1366 }
1367
1368 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1369 if (!isRelevantHelper()) {
1370 return;
1371 }
1372
1373 log.debug("Router interface {} added to router {}",
1374 event.routerIface().getPortId(),
1375 event.routerIface().getId());
1376
1377 routerIfaceAdded(event.subject(), event.routerIface());
1378 }
1379
1380 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1381 if (!isRelevantHelper()) {
1382 return;
1383 }
1384
1385 log.debug("Router interface {} removed from router {}",
1386 event.routerIface().getPortId(),
1387 event.routerIface().getId());
1388
1389 routerIfaceRemoved(event.subject(), event.routerIface());
1390 }
1391 }
1392
Hyunsun Moon44aac662017-02-18 02:07:01 +09001393 private class InternalPacketProcessor implements PacketProcessor {
1394
1395 @Override
1396 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +09001397
Hyunsun Moon44aac662017-02-18 02:07:01 +09001398 if (context.isHandled()) {
1399 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001400 }
1401
1402 InboundPacket pkt = context.inPacket();
1403 Ethernet eth = pkt.parsed();
1404 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
1405 return;
1406 }
1407
1408 IPv4 iPacket = (IPv4) eth.getPayload();
1409 switch (iPacket.getProtocol()) {
1410 case IPv4.PROTOCOL_ICMP:
1411 break;
1412 case IPv4.PROTOCOL_UDP:
1413 UDP udpPacket = (UDP) iPacket.getPayload();
1414 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
1415 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
Jian Li6a47fd02018-11-27 21:51:03 +09001416 break; // don't process DHCP
Hyunsun Moon44aac662017-02-18 02:07:01 +09001417 }
1418 default:
Jian Li34220ea2018-11-14 01:30:24 +09001419 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001420 if (!isRelevantHelper(context)) {
1421 return;
1422 }
Jian Li34220ea2018-11-14 01:30:24 +09001423 processSnatPacket(context, eth);
1424 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001425 break;
1426 }
1427 }
Jian Li34220ea2018-11-14 01:30:24 +09001428
1429 private boolean isRelevantHelper(PacketContext context) {
1430 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
1431 .stream().map(OpenstackNode::intgBridge)
1432 .collect(Collectors.toSet());
1433
1434 return gateways.contains(context.inPacket().receivedFrom().deviceId());
1435 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001436 }
Jian Li33b4db52019-03-20 18:22:38 +09001437
1438 private class InternalNodeEventListener implements OpenstackNodeListener {
1439
1440 private boolean isRelevantHelper() {
1441 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1442 }
1443
1444 @Override
1445 public void event(OpenstackNodeEvent event) {
1446 OpenstackNode osNode = event.subject();
1447 switch (event.type()) {
1448 case OPENSTACK_NODE_COMPLETE:
Jian Li5a26ab32019-03-21 15:20:01 +09001449 eventExecutor.execute(() -> processGatewayCompletion(osNode));
1450 eventExecutor.execute(() -> reconfigureRouters(osNode));
1451 break;
1452 case OPENSTACK_NODE_REMOVED:
1453 eventExecutor.execute(() -> processGatewayRemoval(osNode));
Jian Li5d795f22019-04-01 23:07:40 +09001454 eventExecutor.execute(() -> reconfigureRouters(osNode));
1455 break;
Jian Li33b4db52019-03-20 18:22:38 +09001456 case OPENSTACK_NODE_UPDATED:
Jian Li5a26ab32019-03-21 15:20:01 +09001457 eventExecutor.execute(() -> reconfigureRouters(osNode));
Jian Li33b4db52019-03-20 18:22:38 +09001458 break;
Jian Lif7f01d12019-09-24 22:32:02 +09001459 case OPENSTACK_NODE_INCOMPLETE:
Jian Li33b4db52019-03-20 18:22:38 +09001460 case OPENSTACK_NODE_CREATED:
1461 default:
1462 break;
1463 }
1464 }
1465
Jian Li5a26ab32019-03-21 15:20:01 +09001466 private void processGatewayCompletion(OpenstackNode osNode) {
1467 if (!isRelevantHelper()) {
1468 return;
1469 }
1470
Jian Liec857292019-04-03 18:18:52 +09001471 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Licb0a24e2019-09-17 03:30:34 +09001472 instancePortService.instancePorts().forEach(instPort -> {
1473 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1474
1475 if (netType == FLAT) {
1476 return;
1477 }
1478 setGatewayToInstanceDownstreamRule(osNode, instPort, true);
1479 });
Jian Li5a26ab32019-03-21 15:20:01 +09001480 }
1481 }
1482
1483 private void processGatewayRemoval(OpenstackNode osNode) {
1484 if (!isRelevantHelper()) {
1485 return;
1486 }
1487
Jian Liec857292019-04-03 18:18:52 +09001488 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Licb0a24e2019-09-17 03:30:34 +09001489 instancePortService.instancePorts().forEach(instPort -> {
1490 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1491
1492 if (netType == FLAT) {
1493 return;
1494 }
1495
1496 setGatewayToInstanceDownstreamRule(osNode, instPort, false);
1497 });
Jian Li5a26ab32019-03-21 15:20:01 +09001498 }
1499 }
1500
Jian Li33b4db52019-03-20 18:22:38 +09001501 private void reconfigureRouters(OpenstackNode osNode) {
Jian Li5a26ab32019-03-21 15:20:01 +09001502 if (!isRelevantHelper()) {
1503 return;
1504 }
1505
Jian Li33b4db52019-03-20 18:22:38 +09001506 osRouterService.routers().forEach(osRouter -> {
1507 routerUpdated(osRouter);
1508 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1509 routerIfaceAdded(osRouter, iface);
1510 });
Jian Lidc5d5012019-04-04 13:54:41 +09001511
1512 setStatefulDownstreamRules(osRouter, true);
Jian Li33b4db52019-03-20 18:22:38 +09001513 });
Daniel Parkf8f4f202019-09-15 16:38:06 +09001514 log.debug("Reconfigure routers for {}", osNode.hostname());
Jian Li33b4db52019-03-20 18:22:38 +09001515 }
1516 }
Jian Li5a26ab32019-03-21 15:20:01 +09001517
1518 private class PortRange {
1519 private int min;
1520 private int max;
1521
1522 /**
1523 * A default constructor.
1524 *
1525 * @param min min port num
1526 * @param max max port num
1527 */
1528 public PortRange(int min, int max) {
1529 this.min = min;
1530 this.max = max;
1531 }
1532
1533 /**
1534 * Obtains min port num.
1535 *
1536 * @return min port num
1537 */
1538 int min() {
1539 return min;
1540 }
1541
1542 /**
1543 * Obtains max port num.
1544 *
1545 * @return max port num
1546 */
1547 int max() {
1548 return max;
1549 }
1550
1551 @Override
1552 public String toString() {
1553 return MoreObjects.toStringHelper(this)
1554 .add("min", min)
1555 .add("max", max)
1556 .toString();
1557 }
1558
1559 @Override
1560 public boolean equals(Object o) {
1561 if (this == o) {
1562 return true;
1563 }
1564 if (o == null || getClass() != o.getClass()) {
1565 return false;
1566 }
1567 PortRange portRange = (PortRange) o;
1568 return min == portRange.min &&
1569 max == portRange.max;
1570 }
1571
1572 @Override
1573 public int hashCode() {
1574 return Objects.hash(min, max);
1575 }
1576 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001577}