blob: b3c1a1f2a8585400cc8edbdb95d9b8043e65b323 [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 Lia5c7edf2020-02-24 16:42:24 +0900119import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalGatewayIpSnatEnabled;
Jian Liebde74d2018-11-14 00:18:57 +0900120import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Jian Liec857292019-04-03 18:18:52 +0900121import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Lia5c7edf2020-02-24 16:42:24 +0900122import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getRouterFromSubnet;
Jian Li2d68c192018-12-13 15:52:59 +0900123import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
Jian Li5a26ab32019-03-21 15:20:01 +0900124import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.CT_NAT_SRC_FLAG;
Jian Li33b4db52019-03-20 18:22:38 +0900125import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
126import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900127import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128import static org.slf4j.LoggerFactory.getLogger;
129
130/**
131 * Handle packets needs SNAT.
132 */
Jian Li33b4db52019-03-20 18:22:38 +0900133@Component(
134 immediate = true,
135 property = {
136 USE_STATEFUL_SNAT + ":Boolean=" + USE_STATEFUL_SNAT_DEFAULT
137 }
138)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139public class OpenstackRoutingSnatHandler {
140
141 private final Logger log = getLogger(getClass());
142
Jian Li33b4db52019-03-20 18:22:38 +0900143 private static final String ERR_PACKET_IN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +0900144 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Ray Milkey3717e602018-02-01 13:49:47 -0800145 private static final long TIME_OUT_SNAT_PORT_MS = 120L * 1000L;
Jian Li5a26ab32019-03-21 15:20:01 +0900146 private static final int TP_PORT_MINIMUM_NUM = 1025;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147 private static final int TP_PORT_MAXIMUM_NUM = 65535;
Jian Li6a47fd02018-11-27 21:51:03 +0900148 private static final int VM_PREFIX = 32;
Jian Lidc5d5012019-04-04 13:54:41 +0900149 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900150
Jian Li33b4db52019-03-20 18:22:38 +0900151 private static final String MSG_ENABLED = "Enabled ";
152 private static final String MSG_DISABLED = "Disabled ";
153
154 /** Use Stateful SNAT for source NATing. */
155 private boolean useStatefulSnat = USE_STATEFUL_SNAT_DEFAULT;
156
157 private static final KryoNamespace.Builder NUMBER_SERIALIZER =
158 KryoNamespace.newBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159 .register(KryoNamespaces.API);
160
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 protected CoreService coreService;
163
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165 protected PacketService packetService;
166
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168 protected StorageService storageService;
169
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171 protected DeviceService deviceService;
172
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700173 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174 protected InstancePortService instancePortService;
175
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700176 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900177 protected ComponentConfigService configService;
178
179 @Reference(cardinality = ReferenceCardinality.MANDATORY)
180 protected DriverService driverService;
181
182 @Reference(cardinality = ReferenceCardinality.MANDATORY)
183 protected LeadershipService leadershipService;
184
185 @Reference(cardinality = ReferenceCardinality.MANDATORY)
186 protected MastershipService mastershipService;
187
188 @Reference(cardinality = ReferenceCardinality.MANDATORY)
189 protected ClusterService clusterService;
190
191 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900192 protected OpenstackNodeService osNodeService;
193
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700194 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900195 protected OpenstackNetworkAdminService osNetworkAdminService;
196
197 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900198 protected OpenstackNetworkService osNetworkService;
199
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700200 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900201 protected OpenstackRouterService osRouterService;
202
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700203 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900204 protected OpenstackFlowRuleService osFlowRuleService;
205
Hyunsun Moon44aac662017-02-18 02:07:01 +0900206 private final ExecutorService eventExecutor = newSingleThreadExecutor(
207 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900208 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Jian Li33b4db52019-03-20 18:22:38 +0900209 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
210 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
211 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Lidc5d5012019-04-04 13:54:41 +0900212 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900213
daniel park0bc7fdb2017-03-13 14:20:08 +0900214 private ConsistentMap<Integer, Long> allocatedPortNumMap;
215 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900216 private ApplicationId appId;
Jian Li33b4db52019-03-20 18:22:38 +0900217 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900218
219 @Activate
220 protected void activate() {
221 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900222
223 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900224 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
Jian Li5a26ab32019-03-21 15:20:01 +0900225 .withName("openstackrouting-allocated-portnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 .withApplicationId(appId)
227 .build();
228
daniel park0bc7fdb2017-03-13 14:20:08 +0900229 unUsedPortNumSet = storageService.<Integer>setBuilder()
Jian Li5a26ab32019-03-21 15:20:01 +0900230 .withName("openstackrouting-unused-portnumset")
daniel park0bc7fdb2017-03-13 14:20:08 +0900231 .withSerializer(Serializer.using(KryoNamespaces.API))
232 .build()
233 .asDistributedSet();
234
Jian Li33b4db52019-03-20 18:22:38 +0900235 localNodeId = clusterService.getLocalNode().id();
236 leadershipService.runForLeadership(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900237 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Jian Li33b4db52019-03-20 18:22:38 +0900238
239 configService.registerProperties(getClass());
240 instancePortService.addListener(instancePortListener);
241 osRouterService.addListener(osRouterListener);
242 osNodeService.addListener(osNodeListener);
Jian Lidc5d5012019-04-04 13:54:41 +0900243 osNetworkAdminService.addListener(osNetworkListener);
Jian Li33b4db52019-03-20 18:22:38 +0900244
Jian Li5a26ab32019-03-21 15:20:01 +0900245 eventExecutor.execute(this::initializeUnusedPortNumSet);
246
Hyunsun Moon44aac662017-02-18 02:07:01 +0900247 log.info("Started");
248 }
249
250 @Deactivate
251 protected void deactivate() {
Jian Lidc5d5012019-04-04 13:54:41 +0900252 osNetworkAdminService.removeListener(osNetworkListener);
Jian Li33b4db52019-03-20 18:22:38 +0900253 osRouterService.removeListener(osRouterListener);
254 osNodeService.removeListener(osNodeListener);
255 instancePortService.removeListener(instancePortListener);
256 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900257 packetService.removeProcessor(packetProcessor);
Jian Li33b4db52019-03-20 18:22:38 +0900258 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900259 eventExecutor.shutdown();
260 log.info("Stopped");
261 }
262
Jian Li33b4db52019-03-20 18:22:38 +0900263 @Modified
264 protected void modified(ComponentContext context) {
265 Dictionary<?, ?> properties = context.getProperties();
266 Boolean flag;
267
268 flag = Tools.isPropertyEnabled(properties, USE_STATEFUL_SNAT);
269 if (flag == null) {
270 log.info("useStatefulSnat is not configured, " +
271 "using current value of {}", useStatefulSnat);
272 } else {
273 useStatefulSnat = flag;
274 log.info("Configured. useStatefulSnat is {}",
275 useStatefulSnat ? "enabled" : "disabled");
276 }
277
278 resetSnatRules();
279 }
280
Hyunsun Moon44aac662017-02-18 02:07:01 +0900281 private void processSnatPacket(PacketContext context, Ethernet eth) {
Jian Li25257212019-03-26 13:31:14 +0900282
Jian Liec857292019-04-03 18:18:52 +0900283 if (getStatefulSnatFlag()) {
Jian Li25257212019-03-26 13:31:14 +0900284 return;
285 }
286
Hyunsun Moon44aac662017-02-18 02:07:01 +0900287 IPv4 iPacket = (IPv4) eth.getPayload();
288 InboundPacket packetIn = context.inPacket();
289
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900290 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291
292 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
293 if (srcInstPort == null) {
Jian Li33b4db52019-03-20 18:22:38 +0900294 log.error(ERR_PACKET_IN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900295 eth.getSourceMAC());
296 return;
297 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900298
Hyunsun Moon44aac662017-02-18 02:07:01 +0900299 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
300 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
Jian Lia5c7edf2020-02-24 16:42:24 +0900301
302 Router osRouter = getRouterFromSubnet(srcSubnet, osRouterService);
303
304 if (osRouter == null || osRouter.getExternalGatewayInfo() == null) {
305 // this router does not have external connectivity
306 log.warn("No router is associated with the given subnet {}", srcSubnet);
307 return;
308 }
309
Jian Liebde74d2018-11-14 00:18:57 +0900310 IpAddress externalGatewayIp =
Jian Lia5c7edf2020-02-24 16:42:24 +0900311 externalGatewayIpSnatEnabled(osRouter, osNetworkAdminService);
daniel parkb5817102018-02-15 00:18:51 +0900312
Hyunsun Moon44aac662017-02-18 02:07:01 +0900313 if (externalGatewayIp == null) {
314 return;
315 }
316
Jian Li5a26ab32019-03-21 15:20:01 +0900317 ExternalPeerRouter externalPeerRouter = externalPeerRouterFromSubnet(
318 srcSubnet, osRouterService, osNetworkService);
daniel park576969a2018-03-09 07:07:41 +0900319 if (externalPeerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900320 return;
321 }
322
Hyunsun Moon44aac662017-02-18 02:07:01 +0900323 populateSnatFlowRules(context.inPacket(),
324 srcInstPort,
325 TpPort.tpPort(patPort),
daniel park576969a2018-03-09 07:07:41 +0900326 externalGatewayIp, externalPeerRouter);
327
Hyunsun Moon44aac662017-02-18 02:07:01 +0900328
Ray Milkeyf0c47612017-09-28 11:29:38 -0700329 packetOut(eth.duplicate(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900330 packetIn.receivedFrom().deviceId(),
331 patPort,
daniel park576969a2018-03-09 07:07:41 +0900332 externalGatewayIp, externalPeerRouter);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900333 }
334
335 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
336 Port osPort = osNetworkService.port(instance.portId());
337 IP fixedIp = osPort.getFixedIps().stream()
338 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
339 .findAny().orElse(null);
340 if (fixedIp == null) {
341 return null;
342 }
343 return osNetworkService.subnet(fixedIp.getSubnetId());
344 }
345
Jian Li5ecfd1a2018-12-10 11:41:03 +0900346 private void populateSnatFlowRules(InboundPacket packetIn,
347 InstancePort srcInstPort,
348 TpPort patPort, IpAddress externalIp,
349 ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900350 Network osNet = osNetworkService.network(srcInstPort.networkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900351 Type netType = osNetworkService.networkType(srcInstPort.networkId());
352
Hyunsun Moon44aac662017-02-18 02:07:01 +0900353 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900354 final String error = String.format("%s network %s not found",
Jian Li5a26ab32019-03-21 15:20:01 +0900355 ERR_PACKET_IN, srcInstPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900356 throw new IllegalStateException(error);
357 }
358
Jian Li5a26ab32019-03-21 15:20:01 +0900359 setStatelessSnatDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900360 osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900361 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900362 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900363 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364 patPort,
365 packetIn);
366
Jian Li5a26ab32019-03-21 15:20:01 +0900367 setStatelessSnatUpstreamRules(osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900368 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900369 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900370 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900371 patPort,
372 packetIn);
373 }
374
Jian Li5a26ab32019-03-21 15:20:01 +0900375 private void setStatelessSnatDownstreamRules(InstancePort srcInstPort,
376 String segmentId,
377 Type networkType,
378 IpAddress externalIp,
379 ExternalPeerRouter externalPeerRouter,
380 TpPort patPort,
381 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900382 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
383 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
384
385 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
386 .matchEthType(Ethernet.TYPE_IPV4)
387 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900388 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), VM_PREFIX))
389 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900390
391 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900392 .setEthDst(packetIn.parsed().getSourceMAC())
393 .setIpDst(internalIp);
394
Jian Li5e2ad4a2018-07-16 13:40:53 +0900395 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
396 sBuilder.matchVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900397 tBuilder.popVlan();
398 }
399
daniel parkee8700b2017-05-11 15:50:03 +0900400 switch (networkType) {
401 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900402 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900403 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900404 tBuilder.setTunnelId(Long.parseLong(segmentId));
405 break;
406 case VLAN:
407 tBuilder.pushVlan()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900408 .setVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900409 break;
410 default:
Jian Li71670d12018-03-02 21:31:07 +0900411 final String error = String.format("%s %s",
412 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900413 throw new IllegalStateException(error);
414 }
415
416
Hyunsun Moon44aac662017-02-18 02:07:01 +0900417 switch (iPacket.getProtocol()) {
418 case IPv4.PROTOCOL_TCP:
419 TCP tcpPacket = (TCP) iPacket.getPayload();
420 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
421 .matchTcpDst(patPort);
422 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
423 break;
424 case IPv4.PROTOCOL_UDP:
425 UDP udpPacket = (UDP) iPacket.getPayload();
426 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
427 .matchUdpDst(patPort);
428 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
429 break;
430 default:
431 break;
432 }
433
Hyunsun Moon0d457362017-06-27 17:19:41 +0900434 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
435 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Jian Li6a47fd02018-11-27 21:51:03 +0900436 TrafficTreatment treatment =
Jian Li5a26ab32019-03-21 15:20:01 +0900437 getDownstreamTreatment(networkType, tBuilder, gNode, srcNode);
sanghodc375372017-06-08 10:41:30 +0900438 osFlowRuleService.setRule(
439 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900440 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900441 sBuilder.build(),
Jian Li6a47fd02018-11-27 21:51:03 +0900442 treatment,
sanghodc375372017-06-08 10:41:30 +0900443 PRIORITY_SNAT_RULE,
444 GW_COMMON_TABLE,
445 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900446 });
447 }
448
Jian Li5a26ab32019-03-21 15:20:01 +0900449 private TrafficTreatment getDownstreamTreatment(Type networkType,
Jian Li6a47fd02018-11-27 21:51:03 +0900450 TrafficTreatment.Builder tBuilder,
451 OpenstackNode gNode,
452 OpenstackNode srcNode) {
453 TrafficTreatment.Builder tmpBuilder =
454 DefaultTrafficTreatment.builder(tBuilder.build());
455 switch (networkType) {
456 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900457 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900458 case GENEVE:
SONA Project6bc5c4a2018-12-14 23:49:52 +0900459 PortNumber portNum = tunnelPortNumByNetType(networkType, gNode);
Jian Li6a47fd02018-11-27 21:51:03 +0900460 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
461 deviceService,
462 gNode.intgBridge(),
463 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900464 .setOutput(portNum);
Jian Li6a47fd02018-11-27 21:51:03 +0900465 break;
466 case VLAN:
467 tmpBuilder.setOutput(gNode.vlanPortNum());
468 break;
469 default:
470 final String error = String.format("%s %s",
471 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
472 throw new IllegalStateException(error);
473 }
474
475 return tmpBuilder.build();
476 }
477
Jian Li5a26ab32019-03-21 15:20:01 +0900478 private void setStatelessSnatUpstreamRules(String segmentId,
479 Type networkType,
480 IpAddress externalIp,
481 ExternalPeerRouter externalPeerRouter,
482 TpPort patPort,
483 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900484 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900485
486 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900487 .matchEthType(Ethernet.TYPE_IPV4)
488 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900489 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), VM_PREFIX))
490 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900491
492 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900493
494 switch (networkType) {
495 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900496 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900497 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900498 sBuilder.matchTunnelId(Long.parseLong(segmentId));
499 break;
500 case VLAN:
501 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
502 tBuilder.popVlan();
503 break;
504 default:
Jian Li71670d12018-03-02 21:31:07 +0900505 final String error = String.format("%s %s",
506 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900507 throw new IllegalStateException(error);
508 }
509
Hyunsun Moon44aac662017-02-18 02:07:01 +0900510 switch (iPacket.getProtocol()) {
511 case IPv4.PROTOCOL_TCP:
512 TCP tcpPacket = (TCP) iPacket.getPayload();
513 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
514 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900515 tBuilder.setTcpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900516 break;
517 case IPv4.PROTOCOL_UDP:
518 UDP udpPacket = (UDP) iPacket.getPayload();
519 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
520 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900521 tBuilder.setUdpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900522 break;
523 default:
524 log.debug("Unsupported IPv4 protocol {}");
525 break;
526 }
527
Jian Li5e2ad4a2018-07-16 13:40:53 +0900528 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
529 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900530 }
531
Hyunsun Moon44aac662017-02-18 02:07:01 +0900532 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900533 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900534 TrafficTreatment.Builder tmpBuilder =
535 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900536 tmpBuilder.setOutput(gNode.uplinkPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900537
sanghodc375372017-06-08 10:41:30 +0900538 osFlowRuleService.setRule(
539 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900540 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900541 sBuilder.build(),
542 tmpBuilder.build(),
543 PRIORITY_SNAT_RULE,
544 GW_COMMON_TABLE,
545 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900546 });
547 }
548
549 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
daniel park576969a2018-03-09 07:07:41 +0900550 IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900551 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900552 switch (iPacket.getProtocol()) {
553 case IPv4.PROTOCOL_TCP:
Jian Li6a47fd02018-11-27 21:51:03 +0900554 iPacket.setPayload(buildPacketOutTcp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900555 break;
556 case IPv4.PROTOCOL_UDP:
Jian Li6a47fd02018-11-27 21:51:03 +0900557 iPacket.setPayload(buildPacketOutUdp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900558 break;
559 default:
560 log.trace("Temporally, this method can process UDP and TCP protocol.");
561 return;
562 }
563
564 iPacket.setSourceAddress(externalIp.toString());
565 iPacket.resetChecksum();
566 iPacket.setParent(ethPacketIn);
daniel park576969a2018-03-09 07:07:41 +0900567 ethPacketIn.setSourceMACAddress(DEFAULT_GATEWAY_MAC);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900568 ethPacketIn.setDestinationMACAddress(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900569 ethPacketIn.setPayload(iPacket);
daniel park576969a2018-03-09 07:07:41 +0900570
Jian Li5e2ad4a2018-07-16 13:40:53 +0900571 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
572 ethPacketIn.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900573 }
574
daniel parkee8700b2017-05-11 15:50:03 +0900575 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900576
Hyunsun Moon0d457362017-06-27 17:19:41 +0900577 OpenstackNode srcNode = osNodeService.node(srcDevice);
578 if (srcNode == null) {
579 final String error = String.format("Cannot find openstack node for %s",
580 srcDevice);
581 throw new IllegalStateException(error);
582 }
daniel parkee8700b2017-05-11 15:50:03 +0900583
daniel park576969a2018-03-09 07:07:41 +0900584 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
585
Hyunsun Moon44aac662017-02-18 02:07:01 +0900586 packetService.emit(new DefaultOutboundPacket(
587 srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900588 tBuilder.setOutput(srcNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900589 ByteBuffer.wrap(ethPacketIn.serialize())));
590 }
591
Jian Li6a47fd02018-11-27 21:51:03 +0900592 private TCP buildPacketOutTcp(IPv4 iPacket, int patPort) {
593 TCP tcpPacket = (TCP) iPacket.getPayload();
594 tcpPacket.setSourcePort(patPort);
595 tcpPacket.resetChecksum();
596 tcpPacket.setParent(iPacket);
597
598 return tcpPacket;
599 }
600
601 private UDP buildPacketOutUdp(IPv4 iPacket, int patPort) {
602 UDP udpPacket = (UDP) iPacket.getPayload();
603 udpPacket.setSourcePort(patPort);
604 udpPacket.resetChecksum();
605 udpPacket.setParent(iPacket);
606
607 return udpPacket;
608 }
609
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900610 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900611 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900612 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900613 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900614 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900615 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900616 unUsedPortNumSet.remove(portNum);
617 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900618 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900619 return portNum;
620 }
621
622 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900623 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900624 }
625
626 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900627 allocatedPortNumMap.entrySet().forEach(e -> {
Jian Li5a26ab32019-03-21 15:20:01 +0900628 if (System.currentTimeMillis() -
629 e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900630 allocatedPortNumMap.remove(e.getKey());
631 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900632 }
633 });
634 }
635
Jian Li33b4db52019-03-20 18:22:38 +0900636 private void initializeUnusedPortNumSet() {
637 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
638 if (!allocatedPortNumMap.containsKey(i)) {
639 unUsedPortNumSet.add(i);
640 }
641 }
642
643 clearPortNumMap();
644 }
645
646 private void resetSnatRules() {
Jian Liec857292019-04-03 18:18:52 +0900647 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900648 osRouterService.routerInterfaces().forEach(
649 routerIface -> {
650 setReactiveSnatRules(routerIface, false);
651 setStatefulSnatRules(routerIface, true);
652 }
653 );
654 } else {
655 osRouterService.routerInterfaces().forEach(
656 routerIface -> {
657 setStatefulSnatRules(routerIface, false);
658 setReactiveSnatRules(routerIface, true);
659 }
660 );
661 }
662 }
663
664 private void setRulesToGateway(OpenstackNode osNode,
665 String segmentId,
666 IpPrefix srcSubnet,
667 Type networkType,
668 boolean install) {
Jian Li5a26ab32019-03-21 15:20:01 +0900669 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY)
670 .stream().findFirst().orElse(null);
Jian Li33b4db52019-03-20 18:22:38 +0900671
672 if (sourceNatGateway == null) {
673 return;
674 }
675
676 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
677 .matchEthType(Ethernet.TYPE_IPV4)
678 .matchIPSrc(srcSubnet.getIp4Prefix())
679 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
680
681 switch (networkType) {
682 case VXLAN:
683 case GRE:
684 case GENEVE:
685 sBuilder.matchTunnelId(Long.parseLong(segmentId));
686 break;
687 case VLAN:
688 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
689 break;
690 default:
691 final String error = String.format("%s %s",
692 ERR_UNSUPPORTED_NET_TYPE,
693 networkType.toString());
694 throw new IllegalStateException(error);
695 }
696
697 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
698
699 switch (networkType) {
700 case VXLAN:
701 case GRE:
702 case GENEVE:
703 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
704 tBuilder.extension(buildExtension(
705 deviceService,
706 osNode.intgBridge(),
707 sourceNatGateway.dataIp().getIp4Address()),
708 osNode.intgBridge())
709 .setOutput(portNum);
710 break;
711
712 case VLAN:
713 tBuilder.setOutput(osNode.vlanPortNum());
714 break;
715
716 default:
717 break;
718 }
719
720 osFlowRuleService.setRule(
721 appId,
722 osNode.intgBridge(),
723 sBuilder.build(),
724 tBuilder.build(),
725 PRIORITY_EXTERNAL_ROUTING_RULE,
726 ROUTING_TABLE,
727 install);
728 }
729
730
731 private void routerUpdated(Router osRouter) {
732 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
733
734 ExternalPeerRouter externalPeerRouter =
735 osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5a26ab32019-03-21 15:20:01 +0900736 VlanId vlanId = externalPeerRouter == null ?
737 VlanId.NONE : externalPeerRouter.vlanId();
Jian Li33b4db52019-03-20 18:22:38 +0900738
739 if (exGateway == null) {
740 deleteUnassociatedExternalPeerRouter();
741 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
742 setSourceNat(iface, false));
743 } else {
744 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
745 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
746 setSourceNat(iface, exGateway.isEnableSnat()));
747 }
748 }
749
750 private void deleteUnassociatedExternalPeerRouter() {
751 log.trace("Deleting unassociated external peer router");
752
753 try {
754 Set<String> routerIps = Sets.newConcurrentHashSet();
755
756 osRouterService.routers().stream()
757 .filter(router -> getGatewayIpAddress(router) != null)
758 .map(router -> getGatewayIpAddress(router).toString())
759 .forEach(routerIps::add);
760
761 osNetworkAdminService.externalPeerRouters().stream()
762 .filter(externalPeerRouter ->
763 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
764 .forEach(externalPeerRouter -> {
765 osNetworkAdminService
766 .deleteExternalPeerRouter(
767 externalPeerRouter.ipAddress().toString());
768 log.trace("Deleted unassociated external peer router {}",
769 externalPeerRouter.ipAddress().toString());
770 });
771 } catch (Exception e) {
772 log.error("Exception occurred because of {}", e.toString());
773 }
774 }
775
776 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
777 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
778 if (exGateway != null && exGateway.isEnableSnat()) {
779 setSourceNat(osRouterIface, true);
780 }
781 }
782
783 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
784 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
785 if (exGateway != null && exGateway.isEnableSnat()) {
786 setSourceNat(osRouterIface, false);
787 }
788 }
789
790 private void setSourceNat(RouterInterface routerIface, boolean install) {
791 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
792 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
793 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
794
795 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
796 setRulesToGateway(cNode, osNet.getProviderSegID(),
797 IpPrefix.valueOf(osSubnet.getCidr()), netType, install);
798 });
799
Jian Liec857292019-04-03 18:18:52 +0900800 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900801 setStatefulSnatRules(routerIface, install);
802 } else {
803 setReactiveSnatRules(routerIface, install);
804 }
805
806 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
807 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
808 }
809
810 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
811 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
812 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
813 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
814
815 if (netType == FLAT) {
Jian Lia5c7edf2020-02-24 16:42:24 +0900816 log.warn("FLAT typed network does not need SNAT rules");
Jian Li33b4db52019-03-20 18:22:38 +0900817 return;
818 }
819
820 Optional<Router> osRouter = osRouterService.routers().stream()
Jian Lia5c7edf2020-02-24 16:42:24 +0900821 .filter(router -> routerIface.getId().equals(router.getId()))
Jian Li33b4db52019-03-20 18:22:38 +0900822 .findAny();
823
824 if (!osRouter.isPresent()) {
Jian Lia5c7edf2020-02-24 16:42:24 +0900825 log.warn("Cannot find a router attached with the given router interface {} ", routerIface);
Jian Li33b4db52019-03-20 18:22:38 +0900826 return;
827 }
Jian Li5a26ab32019-03-21 15:20:01 +0900828
Jian Lia5c7edf2020-02-24 16:42:24 +0900829 IpAddress natAddress = externalGatewayIpSnatEnabled(osRouter.get(), osNetworkAdminService);
Jian Li33b4db52019-03-20 18:22:38 +0900830 if (natAddress == null) {
Jian Licf187132020-07-14 00:05:24 +0900831 log.debug("NAT address is not found");
Jian Li33b4db52019-03-20 18:22:38 +0900832 return;
833 }
Jian Li5a26ab32019-03-21 15:20:01 +0900834
835 IpAddress extRouterAddress = getGatewayIpAddress(osRouter.get());
836 if (extRouterAddress == null) {
Jian Lia5c7edf2020-02-24 16:42:24 +0900837 log.warn("External router address is not found");
Jian Li5a26ab32019-03-21 15:20:01 +0900838 return;
839 }
840
841 ExternalPeerRouter externalPeerRouter =
842 osNetworkService.externalPeerRouter(extRouterAddress);
843 if (externalPeerRouter == null) {
Jian Lia5c7edf2020-02-24 16:42:24 +0900844 log.warn("External peer router not found");
Jian Li5a26ab32019-03-21 15:20:01 +0900845 return;
846 }
847
Jian Li5a26ab32019-03-21 15:20:01 +0900848 Map<OpenstackNode, PortRange> gwPortRangeMap = getAssignedPortsForGateway(
Jian Li25257212019-03-26 13:31:14 +0900849 ImmutableList.copyOf(osNodeService.nodes(GATEWAY)));
Jian Li5a26ab32019-03-21 15:20:01 +0900850
Jian Lidc5d5012019-04-04 13:54:41 +0900851 osNodeService.completeNodes(GATEWAY).forEach(gwNode -> {
852 if (install) {
853 PortRange gwPortRange = gwPortRangeMap.get(gwNode);
Jian Li33b4db52019-03-20 18:22:38 +0900854
Jian Lidc5d5012019-04-04 13:54:41 +0900855 Map<String, PortRange> netPortRangeMap =
856 getAssignedPortsForNet(getNetIdByRouterId(routerIface.getId()),
857 gwPortRange.min(), gwPortRange.max());
Jian Li5a26ab32019-03-21 15:20:01 +0900858
Jian Lidc5d5012019-04-04 13:54:41 +0900859 PortRange netPortRange = netPortRangeMap.get(osNet.getId());
Jian Li5a26ab32019-03-21 15:20:01 +0900860
Jian Lidc5d5012019-04-04 13:54:41 +0900861 setStatefulSnatUpstreamRule(gwNode, natAddress,
862 Long.parseLong(osNet.getProviderSegID()),
863 externalPeerRouter, netPortRange.min(),
864 netPortRange.max(), install);
865 } else {
866 setStatefulSnatUpstreamRule(gwNode, natAddress,
867 Long.parseLong(osNet.getProviderSegID()),
868 externalPeerRouter, 0, 0, install);
869 }
870 });
Jian Li33b4db52019-03-20 18:22:38 +0900871 }
872
Jian Li4f3f75a2019-04-03 12:41:30 +0900873 private void setStatefulDownstreamRules(Router osRouter, boolean install) {
874
Jian Li820ec7b2019-04-03 22:01:33 +0900875 if (!getStatefulSnatFlag()) {
876 return;
877 }
878
Jian Lia5c7edf2020-02-24 16:42:24 +0900879 IpAddress natAddress = externalGatewayIpSnatEnabled(osRouter, osNetworkAdminService);
Jian Li4f3f75a2019-04-03 12:41:30 +0900880 if (natAddress == null) {
881 return;
882 }
883
Jian Lidc5d5012019-04-04 13:54:41 +0900884 setStatefulDownstreamRules(natAddress, install);
885 }
886
887 private void setStatefulDownstreamRules(IpAddress natAddress, boolean install) {
Jian Li4f3f75a2019-04-03 12:41:30 +0900888 osNodeService.completeNodes(GATEWAY)
889 .forEach(gwNode -> {
890 setStatefulSnatDownstreamRule(gwNode.intgBridge(),
891 IpPrefix.valueOf(natAddress, VM_PREFIX), install);
Jian Lidc5d5012019-04-04 13:54:41 +0900892 });
Jian Li4f3f75a2019-04-03 12:41:30 +0900893 }
894
Jian Li5a26ab32019-03-21 15:20:01 +0900895 private List<String> getNetIdByRouterId(String routerId) {
896 return osRouterService.routerInterfaces(routerId)
897 .stream()
898 .filter(ri -> osRouterService.router(ri.getId())
899 .getExternalGatewayInfo().isEnableSnat())
900 .map(RouterInterface::getSubnetId)
901 .map(si -> osNetworkAdminService.subnet(si))
902 .map(Subnet::getNetworkId)
903 .collect(Collectors.toList());
904 }
905
906 private Map<OpenstackNode, PortRange>
907 getAssignedPortsForGateway(List<OpenstackNode> gateways) {
908
909 Map<OpenstackNode, PortRange> gwPortRangeMap = Maps.newConcurrentMap();
910
911 int portRangeNumPerGwNode =
912 (TP_PORT_MAXIMUM_NUM - TP_PORT_MINIMUM_NUM + 1) / gateways.size();
913
914 for (int i = 0; i < gateways.size(); i++) {
915 int gwPortRangeMin = TP_PORT_MINIMUM_NUM + i * portRangeNumPerGwNode;
916 int gwPortRangeMax = TP_PORT_MINIMUM_NUM + (i + 1) * portRangeNumPerGwNode - 1;
917
918 gwPortRangeMap.put(gateways.get(i),
919 new PortRange(gwPortRangeMin, gwPortRangeMax));
920 }
921
922 return gwPortRangeMap;
923 }
924
925 private Map<String, PortRange> getAssignedPortsForNet(List<String> netIds,
926 int min, int max) {
927
928 Map<String, PortRange> netPortRangeMap = Maps.newConcurrentMap();
929
930 int portRangeNumPerNet = (max - min + 1) / netIds.size();
931
932 for (int i = 0; i < netIds.size(); i++) {
933 int netPortRangeMin = min + i * portRangeNumPerNet;
934 int netPortRangeMax = min + (i + 1) * portRangeNumPerNet - 1;
935
936 netPortRangeMap.put(netIds.get(i),
937 new PortRange(netPortRangeMin, netPortRangeMax));
938 }
939
940 return netPortRangeMap;
941 }
942
Jian Li33b4db52019-03-20 18:22:38 +0900943 private IpAddress getGatewayIpAddress(Router osRouter) {
944
945 if (osRouter.getExternalGatewayInfo() == null) {
946 return null;
947 }
948 String extNetId = osNetworkAdminService.network(
949 osRouter.getExternalGatewayInfo().getNetworkId()).getId();
950 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
951 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
952 .findAny();
953
954 if (!extSubnet.isPresent()) {
Jian Li5a26ab32019-03-21 15:20:01 +0900955 log.error("Cannot find external subnet for the router");
Jian Li33b4db52019-03-20 18:22:38 +0900956 return null;
957 }
958
959 return IpAddress.valueOf(extSubnet.get().getGateway());
960 }
961
962 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
963 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
964 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
965 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
966
967 osNodeService.completeNodes(GATEWAY)
968 .forEach(gwNode -> setRulesToController(
969 gwNode.intgBridge(),
970 osNet.getProviderSegID(),
971 IpPrefix.valueOf(osSubnet.getCidr()),
972 netType,
973 install));
974 }
975
Jian Li5a26ab32019-03-21 15:20:01 +0900976 private void setGatewayToInstanceDownstreamRule(OpenstackNode gwNode,
977 InstancePort instPort,
978 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +0900979
980 TrafficSelector selector = DefaultTrafficSelector.builder()
981 .matchEthType(Ethernet.TYPE_IPV4)
Jian Li5a26ab32019-03-21 15:20:01 +0900982 .matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX))
983 .build();
984
985 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
986 .setEthDst(instPort.macAddress());
987
988 Type netType = osNetworkAdminService.networkType(instPort.networkId());
989 String segId = osNetworkAdminService.segmentId(instPort.networkId());
990
991 switch (netType) {
992 case VXLAN:
993 case GRE:
994 case GENEVE:
995 tBuilder.setTunnelId(Long.valueOf(segId));
996 break;
997 case VLAN:
998 default:
999 final String error = String.format("%s %s",
1000 ERR_UNSUPPORTED_NET_TYPE, netType.name());
1001 throw new IllegalStateException(error);
1002 }
1003
1004 OpenstackNode srcNode = osNodeService.node(instPort.deviceId());
1005 TrafficTreatment treatment =
1006 getDownstreamTreatment(netType, tBuilder, gwNode, srcNode);
1007
1008 osFlowRuleService.setRule(
1009 appId,
1010 gwNode.intgBridge(),
1011 selector,
1012 treatment,
1013 PRIORITY_STATEFUL_SNAT_RULE,
1014 GW_COMMON_TABLE,
1015 install);
1016 }
1017
1018 private void setStatefulSnatDownstreamRule(DeviceId deviceId,
1019 IpPrefix gatewayIp,
1020 boolean install) {
1021
Jian Lifdb8d872019-04-08 10:38:58 +09001022 Set<TrafficSelector> selectors = Sets.newConcurrentHashSet();
1023
1024 ImmutableSet<Byte> ipv4Proto = ImmutableSet.of(IPv4.PROTOCOL_TCP, IPv4.PROTOCOL_UDP);
1025
1026 ipv4Proto.forEach(proto -> {
1027 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1028 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
1029 .matchIPDst(gatewayIp)
1030 .matchIPProtocol(proto);
1031 selectors.add(sBuilder.build());
1032 });
1033
Jian Li33b4db52019-03-20 18:22:38 +09001034
1035 ExtensionTreatment natTreatment = RulePopulatorUtil
1036 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
1037 .commit(false)
1038 .natAction(true)
1039 .table((short) 0)
1040 .build();
1041
1042 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li33b4db52019-03-20 18:22:38 +09001043 .extension(natTreatment, deviceId)
1044 .build();
1045
Jian Lifdb8d872019-04-08 10:38:58 +09001046 selectors.forEach(s -> {
1047 osFlowRuleService.setRule(
1048 appId,
1049 deviceId,
1050 s,
1051 treatment,
1052 PRIORITY_STATEFUL_SNAT_RULE,
1053 GW_COMMON_TABLE,
1054 install);
1055 });
Jian Li33b4db52019-03-20 18:22:38 +09001056 }
1057
Jian Li5a26ab32019-03-21 15:20:01 +09001058 private void setStatefulSnatUpstreamRule(OpenstackNode gwNode,
1059 IpAddress gatewayIp,
1060 long vni,
1061 ExternalPeerRouter extPeerRouter,
1062 int minPortNum,
1063 int maxPortNum,
1064 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +09001065
1066 TrafficSelector selector = DefaultTrafficSelector.builder()
1067 .matchEthType(Ethernet.TYPE_IPV4)
1068 .matchEthDst(DEFAULT_GATEWAY_MAC)
1069 .matchTunnelId(vni)
1070 .build();
1071
Jian Lia2995192019-04-02 14:13:04 +09001072 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li33b4db52019-03-20 18:22:38 +09001073
Jian Lia2995192019-04-02 14:13:04 +09001074 // we do not consider to much like port range on removing the rules...
1075 if (install) {
1076 ExtensionTreatment natTreatment = RulePopulatorUtil
1077 .niciraConnTrackTreatmentBuilder(driverService, gwNode.intgBridge())
1078 .commit(true)
1079 .natFlag(CT_NAT_SRC_FLAG)
1080 .natAction(true)
1081 .natIp(gatewayIp)
1082 .natPortMin(TpPort.tpPort(minPortNum))
1083 .natPortMax(TpPort.tpPort(maxPortNum))
1084 .build();
1085
1086 tBuilder.extension(natTreatment, gwNode.intgBridge())
1087 .setEthDst(extPeerRouter.macAddress())
1088 .setEthSrc(DEFAULT_GATEWAY_MAC)
1089 .setOutput(gwNode.uplinkPortNum());
1090 }
Jian Li33b4db52019-03-20 18:22:38 +09001091
1092 osFlowRuleService.setRule(
1093 appId,
Jian Li5a26ab32019-03-21 15:20:01 +09001094 gwNode.intgBridge(),
Jian Li33b4db52019-03-20 18:22:38 +09001095 selector,
Jian Lia2995192019-04-02 14:13:04 +09001096 tBuilder.build(),
Jian Li33b4db52019-03-20 18:22:38 +09001097 PRIORITY_STATEFUL_SNAT_RULE,
1098 GW_COMMON_TABLE,
1099 install);
1100 }
1101
Jian Li33b4db52019-03-20 18:22:38 +09001102 private void setRulesToController(DeviceId deviceId,
1103 String segmentId,
1104 IpPrefix srcSubnet,
1105 Type networkType,
1106 boolean install) {
1107 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
1108 .matchEthType(Ethernet.TYPE_IPV4)
1109 .matchIPSrc(srcSubnet)
1110 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
1111
1112 switch (networkType) {
1113 case VXLAN:
1114 case GRE:
1115 case GENEVE:
1116 sBuilder.matchTunnelId(Long.parseLong(segmentId));
1117 break;
1118 case VLAN:
1119 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
1120 break;
1121 default:
1122 final String error = String.format("%s %s",
1123 ERR_UNSUPPORTED_NET_TYPE,
1124 networkType.toString());
1125 throw new IllegalStateException(error);
1126 }
1127
1128 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1129
1130 if (networkType == VLAN) {
1131 tBuilder.popVlan();
1132 }
1133
1134 tBuilder.punt();
1135
1136 osFlowRuleService.setRule(
1137 appId,
1138 deviceId,
1139 sBuilder.build(),
1140 tBuilder.build(),
1141 PRIORITY_EXTERNAL_ROUTING_RULE,
1142 GW_COMMON_TABLE,
1143 install);
1144 }
1145
Jian Liec857292019-04-03 18:18:52 +09001146 private boolean getStatefulSnatFlag() {
1147 Set<ConfigProperty> properties =
1148 configService.getProperties(getClass().getName());
1149 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
1150 }
1151
Jian Li33b4db52019-03-20 18:22:38 +09001152 private class InternalInstancePortListener implements InstancePortListener {
1153
1154 private boolean isRelevantHelper(InstancePortEvent event) {
1155 return mastershipService.isLocalMaster(event.subject().deviceId());
1156 }
1157
1158 @Override
1159 public void event(InstancePortEvent event) {
1160 InstancePort instPort = event.subject();
1161 switch (event.type()) {
1162 case OPENSTACK_INSTANCE_PORT_DETECTED:
1163 case OPENSTACK_INSTANCE_PORT_UPDATED:
1164 eventExecutor.execute(() ->
1165 processInstancePortDetection(event, instPort));
1166 break;
1167 case OPENSTACK_INSTANCE_PORT_VANISHED:
1168 eventExecutor.execute(() ->
1169 processInstancePortRemoval(event, instPort));
1170 break;
1171 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1172 eventExecutor.execute(() ->
1173 processInstanceMigrationStart(event, instPort));
1174 break;
1175 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1176 eventExecutor.execute(() ->
1177 processInstanceMigrationEnd(event, instPort));
1178 break;
1179 default:
1180 break;
1181 }
1182 }
1183
1184 private void processInstancePortDetection(InstancePortEvent event,
1185 InstancePort instPort) {
1186 if (!isRelevantHelper(event)) {
1187 return;
1188 }
1189
1190 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1191 instPort.macAddress(),
1192 instPort.ipAddress());
1193
1194 instPortDetected(event.subject());
1195 }
1196
1197 private void processInstancePortRemoval(InstancePortEvent event,
1198 InstancePort instPort) {
1199 if (!isRelevantHelper(event)) {
1200 return;
1201 }
1202
1203 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1204 instPort.macAddress(),
1205 instPort.ipAddress());
1206
1207 instPortRemoved(event.subject());
1208 }
1209
1210 private void processInstanceMigrationStart(InstancePortEvent event,
1211 InstancePort instPort) {
1212 if (!isRelevantHelper(event)) {
1213 return;
1214 }
1215
1216 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1217 instPort.macAddress(),
1218 instPort.ipAddress());
1219
1220 instPortDetected(instPort);
1221 }
1222
1223 private void processInstanceMigrationEnd(InstancePortEvent event,
1224 InstancePort instPort) {
1225 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1226 instPort.macAddress(),
1227 instPort.ipAddress());
1228 // TODO: need to reconfigure rules to point to update VM
1229 }
1230
1231 private void instPortDetected(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001232 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1233
1234 if (netType == FLAT) {
1235 return;
1236 }
1237
Jian Liec857292019-04-03 18:18:52 +09001238 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001239 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1240 setGatewayToInstanceDownstreamRule(gwNode, instPort, true));
Jian Li33b4db52019-03-20 18:22:38 +09001241 }
1242 }
1243
1244 private void instPortRemoved(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001245 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1246
1247 if (netType == FLAT) {
1248 return;
1249 }
1250
Jian Liec857292019-04-03 18:18:52 +09001251 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001252 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1253 setGatewayToInstanceDownstreamRule(gwNode, instPort, false));
Jian Li33b4db52019-03-20 18:22:38 +09001254 }
1255 }
1256 }
1257
Jian Lidc5d5012019-04-04 13:54:41 +09001258 private class InternalNetworkEventListener implements OpenstackNetworkListener {
1259
1260 @Override
1261 public boolean isRelevant(OpenstackNetworkEvent event) {
1262 Port osPort = event.port();
1263 if (osPort == null || osPort.getFixedIps() == null) {
1264 return false;
1265 }
1266
1267 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
1268 getStatefulSnatFlag();
1269 }
1270
1271 private boolean isRelevantHelper() {
1272 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1273 }
1274
1275 @Override
1276 public void event(OpenstackNetworkEvent event) {
1277 IpAddress ipAddress = externalIp(event.port());
1278 switch (event.type()) {
1279 case OPENSTACK_PORT_CREATED:
1280 case OPENSTACK_PORT_UPDATED:
1281 eventExecutor.execute(() -> processPortCreation(ipAddress));
1282 break;
1283 case OPENSTACK_PORT_REMOVED:
1284 eventExecutor.execute(() -> processPortRemoval(ipAddress));
1285 break;
1286 default:
1287 // do nothing
1288 break;
1289 }
1290 }
1291
1292 private void processPortCreation(IpAddress ipAddress) {
1293 if (!isRelevantHelper() || ipAddress == null) {
1294 return;
1295 }
1296
1297 setStatefulDownstreamRules(ipAddress, true);
1298 }
1299
1300 private void processPortRemoval(IpAddress ipAddress) {
1301 if (!isRelevantHelper() || ipAddress == null) {
1302 return;
1303 }
1304
1305 setStatefulDownstreamRules(ipAddress, false);
1306 }
1307
1308 private IpAddress externalIp(Port port) {
1309 IP ip = port.getFixedIps().stream().findAny().orElse(null);
1310
1311 if (ip != null && ip.getIpAddress() != null) {
1312 return IpAddress.valueOf(ip.getIpAddress());
1313 }
1314
1315 return null;
1316 }
1317 }
1318
Jian Li33b4db52019-03-20 18:22:38 +09001319 private class InternalRouterEventListener implements OpenstackRouterListener {
1320
1321 private boolean isRelevantHelper() {
1322 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1323 }
1324
1325 @Override
1326 public void event(OpenstackRouterEvent event) {
1327 switch (event.type()) {
1328 case OPENSTACK_ROUTER_CREATED:
1329 eventExecutor.execute(() -> processRouterCreation(event));
1330 break;
1331 case OPENSTACK_ROUTER_UPDATED:
1332 eventExecutor.execute(() -> processRouterUpdate(event));
1333 break;
1334 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1335 eventExecutor.execute(() -> processRouterIntfCreation(event));
1336 break;
1337 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1338 eventExecutor.execute(() -> processRouterIntfRemoval(event));
1339 break;
Jian Li33b4db52019-03-20 18:22:38 +09001340 default:
1341 break;
1342 }
1343 }
1344
1345 private void processRouterCreation(OpenstackRouterEvent event) {
1346 if (!isRelevantHelper()) {
1347 return;
1348 }
1349
1350 log.debug("Router(name:{}, ID:{}) is created",
1351 event.subject().getName(),
1352 event.subject().getId());
1353
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",
1363 event.subject().getName(),
1364 event.subject().getId());
1365
1366 routerUpdated(event.subject());
1367 }
1368
1369 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1370 if (!isRelevantHelper()) {
1371 return;
1372 }
1373
1374 log.debug("Router interface {} added to router {}",
1375 event.routerIface().getPortId(),
1376 event.routerIface().getId());
1377
1378 routerIfaceAdded(event.subject(), event.routerIface());
1379 }
1380
1381 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1382 if (!isRelevantHelper()) {
1383 return;
1384 }
1385
1386 log.debug("Router interface {} removed from router {}",
1387 event.routerIface().getPortId(),
1388 event.routerIface().getId());
1389
1390 routerIfaceRemoved(event.subject(), event.routerIface());
1391 }
1392 }
1393
Hyunsun Moon44aac662017-02-18 02:07:01 +09001394 private class InternalPacketProcessor implements PacketProcessor {
1395
1396 @Override
1397 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +09001398
Hyunsun Moon44aac662017-02-18 02:07:01 +09001399 if (context.isHandled()) {
1400 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001401 }
1402
1403 InboundPacket pkt = context.inPacket();
1404 Ethernet eth = pkt.parsed();
1405 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
1406 return;
1407 }
1408
1409 IPv4 iPacket = (IPv4) eth.getPayload();
1410 switch (iPacket.getProtocol()) {
1411 case IPv4.PROTOCOL_ICMP:
1412 break;
1413 case IPv4.PROTOCOL_UDP:
1414 UDP udpPacket = (UDP) iPacket.getPayload();
1415 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
1416 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
Jian Li6a47fd02018-11-27 21:51:03 +09001417 break; // don't process DHCP
Hyunsun Moon44aac662017-02-18 02:07:01 +09001418 }
1419 default:
Jian Li34220ea2018-11-14 01:30:24 +09001420 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001421 if (!isRelevantHelper(context)) {
1422 return;
1423 }
Jian Li34220ea2018-11-14 01:30:24 +09001424 processSnatPacket(context, eth);
1425 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001426 break;
1427 }
1428 }
Jian Li34220ea2018-11-14 01:30:24 +09001429
1430 private boolean isRelevantHelper(PacketContext context) {
1431 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
1432 .stream().map(OpenstackNode::intgBridge)
1433 .collect(Collectors.toSet());
1434
1435 return gateways.contains(context.inPacket().receivedFrom().deviceId());
1436 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001437 }
Jian Li33b4db52019-03-20 18:22:38 +09001438
1439 private class InternalNodeEventListener implements OpenstackNodeListener {
1440
1441 private boolean isRelevantHelper() {
1442 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1443 }
1444
1445 @Override
1446 public void event(OpenstackNodeEvent event) {
1447 OpenstackNode osNode = event.subject();
1448 switch (event.type()) {
1449 case OPENSTACK_NODE_COMPLETE:
Jian Li5a26ab32019-03-21 15:20:01 +09001450 eventExecutor.execute(() -> processGatewayCompletion(osNode));
1451 eventExecutor.execute(() -> reconfigureRouters(osNode));
1452 break;
1453 case OPENSTACK_NODE_REMOVED:
1454 eventExecutor.execute(() -> processGatewayRemoval(osNode));
Jian Li5d795f22019-04-01 23:07:40 +09001455 eventExecutor.execute(() -> reconfigureRouters(osNode));
1456 break;
Jian Li33b4db52019-03-20 18:22:38 +09001457 case OPENSTACK_NODE_UPDATED:
Jian Li5a26ab32019-03-21 15:20:01 +09001458 eventExecutor.execute(() -> reconfigureRouters(osNode));
Jian Li33b4db52019-03-20 18:22:38 +09001459 break;
Jian Li238552d2019-09-24 22:32:02 +09001460 case OPENSTACK_NODE_INCOMPLETE:
Jian Li33b4db52019-03-20 18:22:38 +09001461 case OPENSTACK_NODE_CREATED:
1462 default:
1463 break;
1464 }
1465 }
1466
Jian Li5a26ab32019-03-21 15:20:01 +09001467 private void processGatewayCompletion(OpenstackNode osNode) {
1468 if (!isRelevantHelper()) {
1469 return;
1470 }
1471
Jian Liec857292019-04-03 18:18:52 +09001472 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Lid8f56a02019-09-17 03:30:34 +09001473 instancePortService.instancePorts().forEach(instPort -> {
1474 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1475
1476 if (netType == FLAT) {
1477 return;
1478 }
1479 setGatewayToInstanceDownstreamRule(osNode, instPort, true);
1480 });
Jian Li5a26ab32019-03-21 15:20:01 +09001481 }
1482 }
1483
1484 private void processGatewayRemoval(OpenstackNode osNode) {
1485 if (!isRelevantHelper()) {
1486 return;
1487 }
1488
Jian Liec857292019-04-03 18:18:52 +09001489 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Lid8f56a02019-09-17 03:30:34 +09001490 instancePortService.instancePorts().forEach(instPort -> {
1491 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1492
1493 if (netType == FLAT) {
1494 return;
1495 }
1496
1497 setGatewayToInstanceDownstreamRule(osNode, instPort, false);
1498 });
Jian Li5a26ab32019-03-21 15:20:01 +09001499 }
1500 }
1501
Jian Li33b4db52019-03-20 18:22:38 +09001502 private void reconfigureRouters(OpenstackNode osNode) {
Jian Li5a26ab32019-03-21 15:20:01 +09001503 if (!isRelevantHelper()) {
1504 return;
1505 }
1506
Jian Li33b4db52019-03-20 18:22:38 +09001507 osRouterService.routers().forEach(osRouter -> {
1508 routerUpdated(osRouter);
1509 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1510 routerIfaceAdded(osRouter, iface);
1511 });
Jian Lidc5d5012019-04-04 13:54:41 +09001512
1513 setStatefulDownstreamRules(osRouter, true);
Jian Li33b4db52019-03-20 18:22:38 +09001514 });
Daniel Parkc717c0f2019-09-15 16:38:06 +09001515 log.debug("Reconfigure routers for {}", osNode.hostname());
Jian Li33b4db52019-03-20 18:22:38 +09001516 }
1517 }
Jian Li5a26ab32019-03-21 15:20:01 +09001518
1519 private class PortRange {
1520 private int min;
1521 private int max;
1522
1523 /**
1524 * A default constructor.
1525 *
1526 * @param min min port num
1527 * @param max max port num
1528 */
1529 public PortRange(int min, int max) {
1530 this.min = min;
1531 this.max = max;
1532 }
1533
1534 /**
1535 * Obtains min port num.
1536 *
1537 * @return min port num
1538 */
1539 int min() {
1540 return min;
1541 }
1542
1543 /**
1544 * Obtains max port num.
1545 *
1546 * @return max port num
1547 */
1548 int max() {
1549 return max;
1550 }
1551
1552 @Override
1553 public String toString() {
1554 return MoreObjects.toStringHelper(this)
1555 .add("min", min)
1556 .add("max", max)
1557 .toString();
1558 }
1559
1560 @Override
1561 public boolean equals(Object o) {
1562 if (this == o) {
1563 return true;
1564 }
1565 if (o == null || getClass() != o.getClass()) {
1566 return false;
1567 }
1568 PortRange portRange = (PortRange) o;
1569 return min == portRange.min &&
1570 max == portRange.max;
1571 }
1572
1573 @Override
1574 public int hashCode() {
1575 return Objects.hash(min, max);
1576 }
1577 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001578}