blob: 0406dea9d923522b32cb0ca90e0162d74312ec88 [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 Liebde74d2018-11-14 00:18:57 +0900119import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalIpFromSubnet;
120import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Jian Li5a26ab32019-03-21 15:20:01 +0900121import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getExternalIp;
Jian Liec857292019-04-03 18:18:52 +0900122import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
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 Liebde74d2018-11-14 00:18:57 +0900301 IpAddress externalGatewayIp =
302 externalIpFromSubnet(srcSubnet, osRouterService, osNetworkService);
daniel parkb5817102018-02-15 00:18:51 +0900303
Hyunsun Moon44aac662017-02-18 02:07:01 +0900304 if (externalGatewayIp == null) {
305 return;
306 }
307
Jian Li5a26ab32019-03-21 15:20:01 +0900308 ExternalPeerRouter externalPeerRouter = externalPeerRouterFromSubnet(
309 srcSubnet, osRouterService, osNetworkService);
daniel park576969a2018-03-09 07:07:41 +0900310 if (externalPeerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900311 return;
312 }
313
Hyunsun Moon44aac662017-02-18 02:07:01 +0900314 populateSnatFlowRules(context.inPacket(),
315 srcInstPort,
316 TpPort.tpPort(patPort),
daniel park576969a2018-03-09 07:07:41 +0900317 externalGatewayIp, externalPeerRouter);
318
Hyunsun Moon44aac662017-02-18 02:07:01 +0900319
Ray Milkeyf0c47612017-09-28 11:29:38 -0700320 packetOut(eth.duplicate(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900321 packetIn.receivedFrom().deviceId(),
322 patPort,
daniel park576969a2018-03-09 07:07:41 +0900323 externalGatewayIp, externalPeerRouter);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900324 }
325
326 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
327 Port osPort = osNetworkService.port(instance.portId());
328 IP fixedIp = osPort.getFixedIps().stream()
329 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
330 .findAny().orElse(null);
331 if (fixedIp == null) {
332 return null;
333 }
334 return osNetworkService.subnet(fixedIp.getSubnetId());
335 }
336
Jian Li5ecfd1a2018-12-10 11:41:03 +0900337 private void populateSnatFlowRules(InboundPacket packetIn,
338 InstancePort srcInstPort,
339 TpPort patPort, IpAddress externalIp,
340 ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 Network osNet = osNetworkService.network(srcInstPort.networkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900342 Type netType = osNetworkService.networkType(srcInstPort.networkId());
343
Hyunsun Moon44aac662017-02-18 02:07:01 +0900344 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900345 final String error = String.format("%s network %s not found",
Jian Li5a26ab32019-03-21 15:20:01 +0900346 ERR_PACKET_IN, srcInstPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900347 throw new IllegalStateException(error);
348 }
349
Jian Li5a26ab32019-03-21 15:20:01 +0900350 setStatelessSnatDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900351 osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900352 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900353 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900354 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900355 patPort,
356 packetIn);
357
Jian Li5a26ab32019-03-21 15:20:01 +0900358 setStatelessSnatUpstreamRules(osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900359 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900360 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900361 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900362 patPort,
363 packetIn);
364 }
365
Jian Li5a26ab32019-03-21 15:20:01 +0900366 private void setStatelessSnatDownstreamRules(InstancePort srcInstPort,
367 String segmentId,
368 Type networkType,
369 IpAddress externalIp,
370 ExternalPeerRouter externalPeerRouter,
371 TpPort patPort,
372 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900373 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
374 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
375
376 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
377 .matchEthType(Ethernet.TYPE_IPV4)
378 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900379 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), VM_PREFIX))
380 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900381
382 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900383 .setEthDst(packetIn.parsed().getSourceMAC())
384 .setIpDst(internalIp);
385
Jian Li5e2ad4a2018-07-16 13:40:53 +0900386 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
387 sBuilder.matchVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900388 tBuilder.popVlan();
389 }
390
daniel parkee8700b2017-05-11 15:50:03 +0900391 switch (networkType) {
392 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900393 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900394 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900395 tBuilder.setTunnelId(Long.parseLong(segmentId));
396 break;
397 case VLAN:
398 tBuilder.pushVlan()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900399 .setVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900400 break;
401 default:
Jian Li71670d12018-03-02 21:31:07 +0900402 final String error = String.format("%s %s",
403 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900404 throw new IllegalStateException(error);
405 }
406
407
Hyunsun Moon44aac662017-02-18 02:07:01 +0900408 switch (iPacket.getProtocol()) {
409 case IPv4.PROTOCOL_TCP:
410 TCP tcpPacket = (TCP) iPacket.getPayload();
411 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
412 .matchTcpDst(patPort);
413 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
414 break;
415 case IPv4.PROTOCOL_UDP:
416 UDP udpPacket = (UDP) iPacket.getPayload();
417 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
418 .matchUdpDst(patPort);
419 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
420 break;
421 default:
422 break;
423 }
424
Hyunsun Moon0d457362017-06-27 17:19:41 +0900425 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
426 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Jian Li6a47fd02018-11-27 21:51:03 +0900427 TrafficTreatment treatment =
Jian Li5a26ab32019-03-21 15:20:01 +0900428 getDownstreamTreatment(networkType, tBuilder, gNode, srcNode);
sanghodc375372017-06-08 10:41:30 +0900429 osFlowRuleService.setRule(
430 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900431 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900432 sBuilder.build(),
Jian Li6a47fd02018-11-27 21:51:03 +0900433 treatment,
sanghodc375372017-06-08 10:41:30 +0900434 PRIORITY_SNAT_RULE,
435 GW_COMMON_TABLE,
436 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900437 });
438 }
439
Jian Li5a26ab32019-03-21 15:20:01 +0900440 private TrafficTreatment getDownstreamTreatment(Type networkType,
Jian Li6a47fd02018-11-27 21:51:03 +0900441 TrafficTreatment.Builder tBuilder,
442 OpenstackNode gNode,
443 OpenstackNode srcNode) {
444 TrafficTreatment.Builder tmpBuilder =
445 DefaultTrafficTreatment.builder(tBuilder.build());
446 switch (networkType) {
447 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900448 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900449 case GENEVE:
SONA Project6bc5c4a2018-12-14 23:49:52 +0900450 PortNumber portNum = tunnelPortNumByNetType(networkType, gNode);
Jian Li6a47fd02018-11-27 21:51:03 +0900451 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
452 deviceService,
453 gNode.intgBridge(),
454 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900455 .setOutput(portNum);
Jian Li6a47fd02018-11-27 21:51:03 +0900456 break;
457 case VLAN:
458 tmpBuilder.setOutput(gNode.vlanPortNum());
459 break;
460 default:
461 final String error = String.format("%s %s",
462 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
463 throw new IllegalStateException(error);
464 }
465
466 return tmpBuilder.build();
467 }
468
Jian Li5a26ab32019-03-21 15:20:01 +0900469 private void setStatelessSnatUpstreamRules(String segmentId,
470 Type networkType,
471 IpAddress externalIp,
472 ExternalPeerRouter externalPeerRouter,
473 TpPort patPort,
474 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900475 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900476
477 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900478 .matchEthType(Ethernet.TYPE_IPV4)
479 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900480 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), VM_PREFIX))
481 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900482
483 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900484
485 switch (networkType) {
486 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900487 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900488 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900489 sBuilder.matchTunnelId(Long.parseLong(segmentId));
490 break;
491 case VLAN:
492 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
493 tBuilder.popVlan();
494 break;
495 default:
Jian Li71670d12018-03-02 21:31:07 +0900496 final String error = String.format("%s %s",
497 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900498 throw new IllegalStateException(error);
499 }
500
Hyunsun Moon44aac662017-02-18 02:07:01 +0900501 switch (iPacket.getProtocol()) {
502 case IPv4.PROTOCOL_TCP:
503 TCP tcpPacket = (TCP) iPacket.getPayload();
504 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
505 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900506 tBuilder.setTcpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900507 break;
508 case IPv4.PROTOCOL_UDP:
509 UDP udpPacket = (UDP) iPacket.getPayload();
510 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
511 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900512 tBuilder.setUdpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900513 break;
514 default:
515 log.debug("Unsupported IPv4 protocol {}");
516 break;
517 }
518
Jian Li5e2ad4a2018-07-16 13:40:53 +0900519 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
520 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900521 }
522
Hyunsun Moon44aac662017-02-18 02:07:01 +0900523 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900524 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900525 TrafficTreatment.Builder tmpBuilder =
526 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900527 tmpBuilder.setOutput(gNode.uplinkPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900528
sanghodc375372017-06-08 10:41:30 +0900529 osFlowRuleService.setRule(
530 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900531 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900532 sBuilder.build(),
533 tmpBuilder.build(),
534 PRIORITY_SNAT_RULE,
535 GW_COMMON_TABLE,
536 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900537 });
538 }
539
540 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
daniel park576969a2018-03-09 07:07:41 +0900541 IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900542 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900543 switch (iPacket.getProtocol()) {
544 case IPv4.PROTOCOL_TCP:
Jian Li6a47fd02018-11-27 21:51:03 +0900545 iPacket.setPayload(buildPacketOutTcp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900546 break;
547 case IPv4.PROTOCOL_UDP:
Jian Li6a47fd02018-11-27 21:51:03 +0900548 iPacket.setPayload(buildPacketOutUdp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900549 break;
550 default:
551 log.trace("Temporally, this method can process UDP and TCP protocol.");
552 return;
553 }
554
555 iPacket.setSourceAddress(externalIp.toString());
556 iPacket.resetChecksum();
557 iPacket.setParent(ethPacketIn);
daniel park576969a2018-03-09 07:07:41 +0900558 ethPacketIn.setSourceMACAddress(DEFAULT_GATEWAY_MAC);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900559 ethPacketIn.setDestinationMACAddress(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900560 ethPacketIn.setPayload(iPacket);
daniel park576969a2018-03-09 07:07:41 +0900561
Jian Li5e2ad4a2018-07-16 13:40:53 +0900562 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
563 ethPacketIn.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900564 }
565
daniel parkee8700b2017-05-11 15:50:03 +0900566 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900567
Hyunsun Moon0d457362017-06-27 17:19:41 +0900568 OpenstackNode srcNode = osNodeService.node(srcDevice);
569 if (srcNode == null) {
570 final String error = String.format("Cannot find openstack node for %s",
571 srcDevice);
572 throw new IllegalStateException(error);
573 }
daniel parkee8700b2017-05-11 15:50:03 +0900574
daniel park576969a2018-03-09 07:07:41 +0900575 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
576
Hyunsun Moon44aac662017-02-18 02:07:01 +0900577 packetService.emit(new DefaultOutboundPacket(
578 srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900579 tBuilder.setOutput(srcNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900580 ByteBuffer.wrap(ethPacketIn.serialize())));
581 }
582
Jian Li6a47fd02018-11-27 21:51:03 +0900583 private TCP buildPacketOutTcp(IPv4 iPacket, int patPort) {
584 TCP tcpPacket = (TCP) iPacket.getPayload();
585 tcpPacket.setSourcePort(patPort);
586 tcpPacket.resetChecksum();
587 tcpPacket.setParent(iPacket);
588
589 return tcpPacket;
590 }
591
592 private UDP buildPacketOutUdp(IPv4 iPacket, int patPort) {
593 UDP udpPacket = (UDP) iPacket.getPayload();
594 udpPacket.setSourcePort(patPort);
595 udpPacket.resetChecksum();
596 udpPacket.setParent(iPacket);
597
598 return udpPacket;
599 }
600
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900601 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900602 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900603 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900604 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900605 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900606 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900607 unUsedPortNumSet.remove(portNum);
608 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900609 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900610 return portNum;
611 }
612
613 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900614 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900615 }
616
617 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900618 allocatedPortNumMap.entrySet().forEach(e -> {
Jian Li5a26ab32019-03-21 15:20:01 +0900619 if (System.currentTimeMillis() -
620 e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900621 allocatedPortNumMap.remove(e.getKey());
622 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900623 }
624 });
625 }
626
Jian Li33b4db52019-03-20 18:22:38 +0900627 private void initializeUnusedPortNumSet() {
628 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
629 if (!allocatedPortNumMap.containsKey(i)) {
630 unUsedPortNumSet.add(i);
631 }
632 }
633
634 clearPortNumMap();
635 }
636
637 private void resetSnatRules() {
Jian Liec857292019-04-03 18:18:52 +0900638 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900639 osRouterService.routerInterfaces().forEach(
640 routerIface -> {
641 setReactiveSnatRules(routerIface, false);
642 setStatefulSnatRules(routerIface, true);
643 }
644 );
645 } else {
646 osRouterService.routerInterfaces().forEach(
647 routerIface -> {
648 setStatefulSnatRules(routerIface, false);
649 setReactiveSnatRules(routerIface, true);
650 }
651 );
652 }
653 }
654
655 private void setRulesToGateway(OpenstackNode osNode,
656 String segmentId,
657 IpPrefix srcSubnet,
658 Type networkType,
659 boolean install) {
Jian Li5a26ab32019-03-21 15:20:01 +0900660 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY)
661 .stream().findFirst().orElse(null);
Jian Li33b4db52019-03-20 18:22:38 +0900662
663 if (sourceNatGateway == null) {
664 return;
665 }
666
667 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
668 .matchEthType(Ethernet.TYPE_IPV4)
669 .matchIPSrc(srcSubnet.getIp4Prefix())
670 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
671
672 switch (networkType) {
673 case VXLAN:
674 case GRE:
675 case GENEVE:
676 sBuilder.matchTunnelId(Long.parseLong(segmentId));
677 break;
678 case VLAN:
679 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
680 break;
681 default:
682 final String error = String.format("%s %s",
683 ERR_UNSUPPORTED_NET_TYPE,
684 networkType.toString());
685 throw new IllegalStateException(error);
686 }
687
688 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
689
690 switch (networkType) {
691 case VXLAN:
692 case GRE:
693 case GENEVE:
694 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
695 tBuilder.extension(buildExtension(
696 deviceService,
697 osNode.intgBridge(),
698 sourceNatGateway.dataIp().getIp4Address()),
699 osNode.intgBridge())
700 .setOutput(portNum);
701 break;
702
703 case VLAN:
704 tBuilder.setOutput(osNode.vlanPortNum());
705 break;
706
707 default:
708 break;
709 }
710
711 osFlowRuleService.setRule(
712 appId,
713 osNode.intgBridge(),
714 sBuilder.build(),
715 tBuilder.build(),
716 PRIORITY_EXTERNAL_ROUTING_RULE,
717 ROUTING_TABLE,
718 install);
719 }
720
721
722 private void routerUpdated(Router osRouter) {
723 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
724
725 ExternalPeerRouter externalPeerRouter =
726 osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5a26ab32019-03-21 15:20:01 +0900727 VlanId vlanId = externalPeerRouter == null ?
728 VlanId.NONE : externalPeerRouter.vlanId();
Jian Li33b4db52019-03-20 18:22:38 +0900729
730 if (exGateway == null) {
731 deleteUnassociatedExternalPeerRouter();
732 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
733 setSourceNat(iface, false));
734 } else {
735 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
736 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
737 setSourceNat(iface, exGateway.isEnableSnat()));
738 }
739 }
740
741 private void deleteUnassociatedExternalPeerRouter() {
742 log.trace("Deleting unassociated external peer router");
743
744 try {
745 Set<String> routerIps = Sets.newConcurrentHashSet();
746
747 osRouterService.routers().stream()
748 .filter(router -> getGatewayIpAddress(router) != null)
749 .map(router -> getGatewayIpAddress(router).toString())
750 .forEach(routerIps::add);
751
752 osNetworkAdminService.externalPeerRouters().stream()
753 .filter(externalPeerRouter ->
754 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
755 .forEach(externalPeerRouter -> {
756 osNetworkAdminService
757 .deleteExternalPeerRouter(
758 externalPeerRouter.ipAddress().toString());
759 log.trace("Deleted unassociated external peer router {}",
760 externalPeerRouter.ipAddress().toString());
761 });
762 } catch (Exception e) {
763 log.error("Exception occurred because of {}", e.toString());
764 }
765 }
766
767 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
768 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
769 if (exGateway != null && exGateway.isEnableSnat()) {
770 setSourceNat(osRouterIface, true);
771 }
772 }
773
774 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
775 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
776 if (exGateway != null && exGateway.isEnableSnat()) {
777 setSourceNat(osRouterIface, false);
778 }
779 }
780
781 private void setSourceNat(RouterInterface routerIface, boolean install) {
782 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
783 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
784 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
785
786 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
787 setRulesToGateway(cNode, osNet.getProviderSegID(),
788 IpPrefix.valueOf(osSubnet.getCidr()), netType, install);
789 });
790
Jian Liec857292019-04-03 18:18:52 +0900791 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900792 setStatefulSnatRules(routerIface, install);
793 } else {
794 setReactiveSnatRules(routerIface, install);
795 }
796
797 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
798 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
799 }
800
801 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
802 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
803 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
804 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
805
806 if (netType == FLAT) {
807 return;
808 }
809
810 Optional<Router> osRouter = osRouterService.routers().stream()
811 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
812 .findAny();
813
814 if (!osRouter.isPresent()) {
815 log.error("Cannot find a router for router interface {} ", routerIface);
816 return;
817 }
Jian Li5a26ab32019-03-21 15:20:01 +0900818
819 IpAddress natAddress = getExternalIp(osRouter.get(), osNetworkService);
Jian Li33b4db52019-03-20 18:22:38 +0900820 if (natAddress == null) {
821 return;
822 }
Jian Li5a26ab32019-03-21 15:20:01 +0900823
824 IpAddress extRouterAddress = getGatewayIpAddress(osRouter.get());
825 if (extRouterAddress == null) {
826 return;
827 }
828
829 ExternalPeerRouter externalPeerRouter =
830 osNetworkService.externalPeerRouter(extRouterAddress);
831 if (externalPeerRouter == null) {
832 return;
833 }
834
Jian Lifdb8d872019-04-08 10:38:58 +0900835 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
836
Jian Li5a26ab32019-03-21 15:20:01 +0900837 Map<OpenstackNode, PortRange> gwPortRangeMap = getAssignedPortsForGateway(
Jian Li25257212019-03-26 13:31:14 +0900838 ImmutableList.copyOf(osNodeService.nodes(GATEWAY)));
Jian Li5a26ab32019-03-21 15:20:01 +0900839
Jian Lidc5d5012019-04-04 13:54:41 +0900840 osNodeService.completeNodes(GATEWAY).forEach(gwNode -> {
841 if (install) {
842 PortRange gwPortRange = gwPortRangeMap.get(gwNode);
Jian Li33b4db52019-03-20 18:22:38 +0900843
Jian Lidc5d5012019-04-04 13:54:41 +0900844 Map<String, PortRange> netPortRangeMap =
845 getAssignedPortsForNet(getNetIdByRouterId(routerIface.getId()),
846 gwPortRange.min(), gwPortRange.max());
Jian Li5a26ab32019-03-21 15:20:01 +0900847
Jian Lidc5d5012019-04-04 13:54:41 +0900848 PortRange netPortRange = netPortRangeMap.get(osNet.getId());
Jian Li5a26ab32019-03-21 15:20:01 +0900849
Jian Lidc5d5012019-04-04 13:54:41 +0900850 setStatefulSnatUpstreamRule(gwNode, natAddress,
851 Long.parseLong(osNet.getProviderSegID()),
852 externalPeerRouter, netPortRange.min(),
853 netPortRange.max(), install);
854 } else {
855 setStatefulSnatUpstreamRule(gwNode, natAddress,
856 Long.parseLong(osNet.getProviderSegID()),
857 externalPeerRouter, 0, 0, install);
858 }
859 });
Jian Li33b4db52019-03-20 18:22:38 +0900860 }
861
Jian Li4f3f75a2019-04-03 12:41:30 +0900862 private void setStatefulDownstreamRules(Router osRouter, boolean install) {
863
Jian Li820ec7b2019-04-03 22:01:33 +0900864 if (!getStatefulSnatFlag()) {
865 return;
866 }
867
Jian Li4f3f75a2019-04-03 12:41:30 +0900868 IpAddress natAddress = getExternalIp(osRouter, osNetworkAdminService);
869 if (natAddress == null) {
870 return;
871 }
872
Jian Lidc5d5012019-04-04 13:54:41 +0900873 setStatefulDownstreamRules(natAddress, install);
874 }
875
876 private void setStatefulDownstreamRules(IpAddress natAddress, boolean install) {
Jian Li4f3f75a2019-04-03 12:41:30 +0900877 osNodeService.completeNodes(GATEWAY)
878 .forEach(gwNode -> {
879 setStatefulSnatDownstreamRule(gwNode.intgBridge(),
880 IpPrefix.valueOf(natAddress, VM_PREFIX), install);
Jian Lidc5d5012019-04-04 13:54:41 +0900881 });
Jian Li4f3f75a2019-04-03 12:41:30 +0900882 }
883
Jian Li5a26ab32019-03-21 15:20:01 +0900884 private List<String> getNetIdByRouterId(String routerId) {
885 return osRouterService.routerInterfaces(routerId)
886 .stream()
887 .filter(ri -> osRouterService.router(ri.getId())
888 .getExternalGatewayInfo().isEnableSnat())
889 .map(RouterInterface::getSubnetId)
890 .map(si -> osNetworkAdminService.subnet(si))
891 .map(Subnet::getNetworkId)
892 .collect(Collectors.toList());
893 }
894
895 private Map<OpenstackNode, PortRange>
896 getAssignedPortsForGateway(List<OpenstackNode> gateways) {
897
898 Map<OpenstackNode, PortRange> gwPortRangeMap = Maps.newConcurrentMap();
899
900 int portRangeNumPerGwNode =
901 (TP_PORT_MAXIMUM_NUM - TP_PORT_MINIMUM_NUM + 1) / gateways.size();
902
903 for (int i = 0; i < gateways.size(); i++) {
904 int gwPortRangeMin = TP_PORT_MINIMUM_NUM + i * portRangeNumPerGwNode;
905 int gwPortRangeMax = TP_PORT_MINIMUM_NUM + (i + 1) * portRangeNumPerGwNode - 1;
906
907 gwPortRangeMap.put(gateways.get(i),
908 new PortRange(gwPortRangeMin, gwPortRangeMax));
909 }
910
911 return gwPortRangeMap;
912 }
913
914 private Map<String, PortRange> getAssignedPortsForNet(List<String> netIds,
915 int min, int max) {
916
917 Map<String, PortRange> netPortRangeMap = Maps.newConcurrentMap();
918
919 int portRangeNumPerNet = (max - min + 1) / netIds.size();
920
921 for (int i = 0; i < netIds.size(); i++) {
922 int netPortRangeMin = min + i * portRangeNumPerNet;
923 int netPortRangeMax = min + (i + 1) * portRangeNumPerNet - 1;
924
925 netPortRangeMap.put(netIds.get(i),
926 new PortRange(netPortRangeMin, netPortRangeMax));
927 }
928
929 return netPortRangeMap;
930 }
931
Jian Li33b4db52019-03-20 18:22:38 +0900932 private IpAddress getGatewayIpAddress(Router osRouter) {
933
934 if (osRouter.getExternalGatewayInfo() == null) {
935 return null;
936 }
937 String extNetId = osNetworkAdminService.network(
938 osRouter.getExternalGatewayInfo().getNetworkId()).getId();
939 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
940 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
941 .findAny();
942
943 if (!extSubnet.isPresent()) {
Jian Li5a26ab32019-03-21 15:20:01 +0900944 log.error("Cannot find external subnet for the router");
Jian Li33b4db52019-03-20 18:22:38 +0900945 return null;
946 }
947
948 return IpAddress.valueOf(extSubnet.get().getGateway());
949 }
950
951 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
952 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
953 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
954 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
955
956 osNodeService.completeNodes(GATEWAY)
957 .forEach(gwNode -> setRulesToController(
958 gwNode.intgBridge(),
959 osNet.getProviderSegID(),
960 IpPrefix.valueOf(osSubnet.getCidr()),
961 netType,
962 install));
963 }
964
Jian Li5a26ab32019-03-21 15:20:01 +0900965 private void setGatewayToInstanceDownstreamRule(OpenstackNode gwNode,
966 InstancePort instPort,
967 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +0900968
969 TrafficSelector selector = DefaultTrafficSelector.builder()
970 .matchEthType(Ethernet.TYPE_IPV4)
Jian Li5a26ab32019-03-21 15:20:01 +0900971 .matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX))
972 .build();
973
974 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
975 .setEthDst(instPort.macAddress());
976
977 Type netType = osNetworkAdminService.networkType(instPort.networkId());
978 String segId = osNetworkAdminService.segmentId(instPort.networkId());
979
980 switch (netType) {
981 case VXLAN:
982 case GRE:
983 case GENEVE:
984 tBuilder.setTunnelId(Long.valueOf(segId));
985 break;
986 case VLAN:
987 default:
988 final String error = String.format("%s %s",
989 ERR_UNSUPPORTED_NET_TYPE, netType.name());
990 throw new IllegalStateException(error);
991 }
992
993 OpenstackNode srcNode = osNodeService.node(instPort.deviceId());
994 TrafficTreatment treatment =
995 getDownstreamTreatment(netType, tBuilder, gwNode, srcNode);
996
997 osFlowRuleService.setRule(
998 appId,
999 gwNode.intgBridge(),
1000 selector,
1001 treatment,
1002 PRIORITY_STATEFUL_SNAT_RULE,
1003 GW_COMMON_TABLE,
1004 install);
1005 }
1006
1007 private void setStatefulSnatDownstreamRule(DeviceId deviceId,
1008 IpPrefix gatewayIp,
1009 boolean install) {
1010
Jian Lifdb8d872019-04-08 10:38:58 +09001011 Set<TrafficSelector> selectors = Sets.newConcurrentHashSet();
1012
1013 ImmutableSet<Byte> ipv4Proto = ImmutableSet.of(IPv4.PROTOCOL_TCP, IPv4.PROTOCOL_UDP);
1014
1015 ipv4Proto.forEach(proto -> {
1016 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1017 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
1018 .matchIPDst(gatewayIp)
1019 .matchIPProtocol(proto);
1020 selectors.add(sBuilder.build());
1021 });
1022
Jian Li33b4db52019-03-20 18:22:38 +09001023
1024 ExtensionTreatment natTreatment = RulePopulatorUtil
1025 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
1026 .commit(false)
1027 .natAction(true)
1028 .table((short) 0)
1029 .build();
1030
1031 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li33b4db52019-03-20 18:22:38 +09001032 .extension(natTreatment, deviceId)
1033 .build();
1034
Jian Lifdb8d872019-04-08 10:38:58 +09001035 selectors.forEach(s -> {
1036 osFlowRuleService.setRule(
1037 appId,
1038 deviceId,
1039 s,
1040 treatment,
1041 PRIORITY_STATEFUL_SNAT_RULE,
1042 GW_COMMON_TABLE,
1043 install);
1044 });
Jian Li33b4db52019-03-20 18:22:38 +09001045 }
1046
Jian Li5a26ab32019-03-21 15:20:01 +09001047 private void setStatefulSnatUpstreamRule(OpenstackNode gwNode,
1048 IpAddress gatewayIp,
1049 long vni,
1050 ExternalPeerRouter extPeerRouter,
1051 int minPortNum,
1052 int maxPortNum,
1053 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +09001054
1055 TrafficSelector selector = DefaultTrafficSelector.builder()
1056 .matchEthType(Ethernet.TYPE_IPV4)
1057 .matchEthDst(DEFAULT_GATEWAY_MAC)
1058 .matchTunnelId(vni)
1059 .build();
1060
Jian Lia2995192019-04-02 14:13:04 +09001061 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li33b4db52019-03-20 18:22:38 +09001062
Jian Lia2995192019-04-02 14:13:04 +09001063 // we do not consider to much like port range on removing the rules...
1064 if (install) {
1065 ExtensionTreatment natTreatment = RulePopulatorUtil
1066 .niciraConnTrackTreatmentBuilder(driverService, gwNode.intgBridge())
1067 .commit(true)
1068 .natFlag(CT_NAT_SRC_FLAG)
1069 .natAction(true)
1070 .natIp(gatewayIp)
1071 .natPortMin(TpPort.tpPort(minPortNum))
1072 .natPortMax(TpPort.tpPort(maxPortNum))
1073 .build();
1074
1075 tBuilder.extension(natTreatment, gwNode.intgBridge())
1076 .setEthDst(extPeerRouter.macAddress())
1077 .setEthSrc(DEFAULT_GATEWAY_MAC)
1078 .setOutput(gwNode.uplinkPortNum());
1079 }
Jian Li33b4db52019-03-20 18:22:38 +09001080
1081 osFlowRuleService.setRule(
1082 appId,
Jian Li5a26ab32019-03-21 15:20:01 +09001083 gwNode.intgBridge(),
Jian Li33b4db52019-03-20 18:22:38 +09001084 selector,
Jian Lia2995192019-04-02 14:13:04 +09001085 tBuilder.build(),
Jian Li33b4db52019-03-20 18:22:38 +09001086 PRIORITY_STATEFUL_SNAT_RULE,
1087 GW_COMMON_TABLE,
1088 install);
1089 }
1090
Jian Li33b4db52019-03-20 18:22:38 +09001091 private void setRulesToController(DeviceId deviceId,
1092 String segmentId,
1093 IpPrefix srcSubnet,
1094 Type networkType,
1095 boolean install) {
1096 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
1097 .matchEthType(Ethernet.TYPE_IPV4)
1098 .matchIPSrc(srcSubnet)
1099 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
1100
1101 switch (networkType) {
1102 case VXLAN:
1103 case GRE:
1104 case GENEVE:
1105 sBuilder.matchTunnelId(Long.parseLong(segmentId));
1106 break;
1107 case VLAN:
1108 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
1109 break;
1110 default:
1111 final String error = String.format("%s %s",
1112 ERR_UNSUPPORTED_NET_TYPE,
1113 networkType.toString());
1114 throw new IllegalStateException(error);
1115 }
1116
1117 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1118
1119 if (networkType == VLAN) {
1120 tBuilder.popVlan();
1121 }
1122
1123 tBuilder.punt();
1124
1125 osFlowRuleService.setRule(
1126 appId,
1127 deviceId,
1128 sBuilder.build(),
1129 tBuilder.build(),
1130 PRIORITY_EXTERNAL_ROUTING_RULE,
1131 GW_COMMON_TABLE,
1132 install);
1133 }
1134
Jian Liec857292019-04-03 18:18:52 +09001135 private boolean getStatefulSnatFlag() {
1136 Set<ConfigProperty> properties =
1137 configService.getProperties(getClass().getName());
1138 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
1139 }
1140
Jian Li33b4db52019-03-20 18:22:38 +09001141 private class InternalInstancePortListener implements InstancePortListener {
1142
1143 private boolean isRelevantHelper(InstancePortEvent event) {
1144 return mastershipService.isLocalMaster(event.subject().deviceId());
1145 }
1146
1147 @Override
1148 public void event(InstancePortEvent event) {
1149 InstancePort instPort = event.subject();
1150 switch (event.type()) {
1151 case OPENSTACK_INSTANCE_PORT_DETECTED:
1152 case OPENSTACK_INSTANCE_PORT_UPDATED:
1153 eventExecutor.execute(() ->
1154 processInstancePortDetection(event, instPort));
1155 break;
1156 case OPENSTACK_INSTANCE_PORT_VANISHED:
1157 eventExecutor.execute(() ->
1158 processInstancePortRemoval(event, instPort));
1159 break;
1160 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1161 eventExecutor.execute(() ->
1162 processInstanceMigrationStart(event, instPort));
1163 break;
1164 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1165 eventExecutor.execute(() ->
1166 processInstanceMigrationEnd(event, instPort));
1167 break;
1168 default:
1169 break;
1170 }
1171 }
1172
1173 private void processInstancePortDetection(InstancePortEvent event,
1174 InstancePort instPort) {
1175 if (!isRelevantHelper(event)) {
1176 return;
1177 }
1178
1179 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1180 instPort.macAddress(),
1181 instPort.ipAddress());
1182
1183 instPortDetected(event.subject());
1184 }
1185
1186 private void processInstancePortRemoval(InstancePortEvent event,
1187 InstancePort instPort) {
1188 if (!isRelevantHelper(event)) {
1189 return;
1190 }
1191
1192 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1193 instPort.macAddress(),
1194 instPort.ipAddress());
1195
1196 instPortRemoved(event.subject());
1197 }
1198
1199 private void processInstanceMigrationStart(InstancePortEvent event,
1200 InstancePort instPort) {
1201 if (!isRelevantHelper(event)) {
1202 return;
1203 }
1204
1205 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1206 instPort.macAddress(),
1207 instPort.ipAddress());
1208
1209 instPortDetected(instPort);
1210 }
1211
1212 private void processInstanceMigrationEnd(InstancePortEvent event,
1213 InstancePort instPort) {
1214 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1215 instPort.macAddress(),
1216 instPort.ipAddress());
1217 // TODO: need to reconfigure rules to point to update VM
1218 }
1219
1220 private void instPortDetected(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001221 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1222
1223 if (netType == FLAT) {
1224 return;
1225 }
1226
Jian Liec857292019-04-03 18:18:52 +09001227 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001228 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1229 setGatewayToInstanceDownstreamRule(gwNode, instPort, true));
Jian Li33b4db52019-03-20 18:22:38 +09001230 }
1231 }
1232
1233 private void instPortRemoved(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001234 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1235
1236 if (netType == FLAT) {
1237 return;
1238 }
1239
Jian Liec857292019-04-03 18:18:52 +09001240 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001241 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1242 setGatewayToInstanceDownstreamRule(gwNode, instPort, false));
Jian Li33b4db52019-03-20 18:22:38 +09001243 }
1244 }
1245 }
1246
Jian Lidc5d5012019-04-04 13:54:41 +09001247 private class InternalNetworkEventListener implements OpenstackNetworkListener {
1248
1249 @Override
1250 public boolean isRelevant(OpenstackNetworkEvent event) {
1251 Port osPort = event.port();
1252 if (osPort == null || osPort.getFixedIps() == null) {
1253 return false;
1254 }
1255
1256 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
1257 getStatefulSnatFlag();
1258 }
1259
1260 private boolean isRelevantHelper() {
1261 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1262 }
1263
1264 @Override
1265 public void event(OpenstackNetworkEvent event) {
1266 IpAddress ipAddress = externalIp(event.port());
1267 switch (event.type()) {
1268 case OPENSTACK_PORT_CREATED:
1269 case OPENSTACK_PORT_UPDATED:
1270 eventExecutor.execute(() -> processPortCreation(ipAddress));
1271 break;
1272 case OPENSTACK_PORT_REMOVED:
1273 eventExecutor.execute(() -> processPortRemoval(ipAddress));
1274 break;
1275 default:
1276 // do nothing
1277 break;
1278 }
1279 }
1280
1281 private void processPortCreation(IpAddress ipAddress) {
1282 if (!isRelevantHelper() || ipAddress == null) {
1283 return;
1284 }
1285
1286 setStatefulDownstreamRules(ipAddress, true);
1287 }
1288
1289 private void processPortRemoval(IpAddress ipAddress) {
1290 if (!isRelevantHelper() || ipAddress == null) {
1291 return;
1292 }
1293
1294 setStatefulDownstreamRules(ipAddress, false);
1295 }
1296
1297 private IpAddress externalIp(Port port) {
1298 IP ip = port.getFixedIps().stream().findAny().orElse(null);
1299
1300 if (ip != null && ip.getIpAddress() != null) {
1301 return IpAddress.valueOf(ip.getIpAddress());
1302 }
1303
1304 return null;
1305 }
1306 }
1307
Jian Li33b4db52019-03-20 18:22:38 +09001308 private class InternalRouterEventListener implements OpenstackRouterListener {
1309
1310 private boolean isRelevantHelper() {
1311 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1312 }
1313
1314 @Override
1315 public void event(OpenstackRouterEvent event) {
1316 switch (event.type()) {
1317 case OPENSTACK_ROUTER_CREATED:
1318 eventExecutor.execute(() -> processRouterCreation(event));
1319 break;
1320 case OPENSTACK_ROUTER_UPDATED:
1321 eventExecutor.execute(() -> processRouterUpdate(event));
1322 break;
1323 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1324 eventExecutor.execute(() -> processRouterIntfCreation(event));
1325 break;
1326 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1327 eventExecutor.execute(() -> processRouterIntfRemoval(event));
1328 break;
Jian Li33b4db52019-03-20 18:22:38 +09001329 default:
1330 break;
1331 }
1332 }
1333
1334 private void processRouterCreation(OpenstackRouterEvent event) {
1335 if (!isRelevantHelper()) {
1336 return;
1337 }
1338
1339 log.debug("Router(name:{}, ID:{}) is created",
1340 event.subject().getName(),
1341 event.subject().getId());
1342
1343 routerUpdated(event.subject());
1344 }
1345
1346 private void processRouterUpdate(OpenstackRouterEvent event) {
1347 if (!isRelevantHelper()) {
1348 return;
1349 }
1350
1351 log.debug("Router(name:{}, ID:{}) is updated",
1352 event.subject().getName(),
1353 event.subject().getId());
1354
1355 routerUpdated(event.subject());
1356 }
1357
1358 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1359 if (!isRelevantHelper()) {
1360 return;
1361 }
1362
1363 log.debug("Router interface {} added to router {}",
1364 event.routerIface().getPortId(),
1365 event.routerIface().getId());
1366
1367 routerIfaceAdded(event.subject(), event.routerIface());
1368 }
1369
1370 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1371 if (!isRelevantHelper()) {
1372 return;
1373 }
1374
1375 log.debug("Router interface {} removed from router {}",
1376 event.routerIface().getPortId(),
1377 event.routerIface().getId());
1378
1379 routerIfaceRemoved(event.subject(), event.routerIface());
1380 }
1381 }
1382
Hyunsun Moon44aac662017-02-18 02:07:01 +09001383 private class InternalPacketProcessor implements PacketProcessor {
1384
1385 @Override
1386 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +09001387
Hyunsun Moon44aac662017-02-18 02:07:01 +09001388 if (context.isHandled()) {
1389 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001390 }
1391
1392 InboundPacket pkt = context.inPacket();
1393 Ethernet eth = pkt.parsed();
1394 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
1395 return;
1396 }
1397
1398 IPv4 iPacket = (IPv4) eth.getPayload();
1399 switch (iPacket.getProtocol()) {
1400 case IPv4.PROTOCOL_ICMP:
1401 break;
1402 case IPv4.PROTOCOL_UDP:
1403 UDP udpPacket = (UDP) iPacket.getPayload();
1404 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
1405 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
Jian Li6a47fd02018-11-27 21:51:03 +09001406 break; // don't process DHCP
Hyunsun Moon44aac662017-02-18 02:07:01 +09001407 }
1408 default:
Jian Li34220ea2018-11-14 01:30:24 +09001409 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001410 if (!isRelevantHelper(context)) {
1411 return;
1412 }
Jian Li34220ea2018-11-14 01:30:24 +09001413 processSnatPacket(context, eth);
1414 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001415 break;
1416 }
1417 }
Jian Li34220ea2018-11-14 01:30:24 +09001418
1419 private boolean isRelevantHelper(PacketContext context) {
1420 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
1421 .stream().map(OpenstackNode::intgBridge)
1422 .collect(Collectors.toSet());
1423
1424 return gateways.contains(context.inPacket().receivedFrom().deviceId());
1425 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001426 }
Jian Li33b4db52019-03-20 18:22:38 +09001427
1428 private class InternalNodeEventListener implements OpenstackNodeListener {
1429
1430 private boolean isRelevantHelper() {
1431 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1432 }
1433
1434 @Override
1435 public void event(OpenstackNodeEvent event) {
1436 OpenstackNode osNode = event.subject();
1437 switch (event.type()) {
1438 case OPENSTACK_NODE_COMPLETE:
Jian Li5a26ab32019-03-21 15:20:01 +09001439 eventExecutor.execute(() -> processGatewayCompletion(osNode));
1440 eventExecutor.execute(() -> reconfigureRouters(osNode));
1441 break;
1442 case OPENSTACK_NODE_REMOVED:
1443 eventExecutor.execute(() -> processGatewayRemoval(osNode));
Jian Li5d795f22019-04-01 23:07:40 +09001444 eventExecutor.execute(() -> reconfigureRouters(osNode));
1445 break;
Jian Li33b4db52019-03-20 18:22:38 +09001446 case OPENSTACK_NODE_UPDATED:
Jian Li5a26ab32019-03-21 15:20:01 +09001447 eventExecutor.execute(() -> reconfigureRouters(osNode));
Jian Li33b4db52019-03-20 18:22:38 +09001448 break;
Jian Li238552d2019-09-24 22:32:02 +09001449 case OPENSTACK_NODE_INCOMPLETE:
Jian Li33b4db52019-03-20 18:22:38 +09001450 case OPENSTACK_NODE_CREATED:
1451 default:
1452 break;
1453 }
1454 }
1455
Jian Li5a26ab32019-03-21 15:20:01 +09001456 private void processGatewayCompletion(OpenstackNode osNode) {
1457 if (!isRelevantHelper()) {
1458 return;
1459 }
1460
Jian Liec857292019-04-03 18:18:52 +09001461 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Lid8f56a02019-09-17 03:30:34 +09001462 instancePortService.instancePorts().forEach(instPort -> {
1463 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1464
1465 if (netType == FLAT) {
1466 return;
1467 }
1468 setGatewayToInstanceDownstreamRule(osNode, instPort, true);
1469 });
Jian Li5a26ab32019-03-21 15:20:01 +09001470 }
1471 }
1472
1473 private void processGatewayRemoval(OpenstackNode osNode) {
1474 if (!isRelevantHelper()) {
1475 return;
1476 }
1477
Jian Liec857292019-04-03 18:18:52 +09001478 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Lid8f56a02019-09-17 03:30:34 +09001479 instancePortService.instancePorts().forEach(instPort -> {
1480 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1481
1482 if (netType == FLAT) {
1483 return;
1484 }
1485
1486 setGatewayToInstanceDownstreamRule(osNode, instPort, false);
1487 });
Jian Li5a26ab32019-03-21 15:20:01 +09001488 }
1489 }
1490
Jian Li33b4db52019-03-20 18:22:38 +09001491 private void reconfigureRouters(OpenstackNode osNode) {
Jian Li5a26ab32019-03-21 15:20:01 +09001492 if (!isRelevantHelper()) {
1493 return;
1494 }
1495
Jian Li33b4db52019-03-20 18:22:38 +09001496 osRouterService.routers().forEach(osRouter -> {
1497 routerUpdated(osRouter);
1498 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1499 routerIfaceAdded(osRouter, iface);
1500 });
Jian Lidc5d5012019-04-04 13:54:41 +09001501
1502 setStatefulDownstreamRules(osRouter, true);
Jian Li33b4db52019-03-20 18:22:38 +09001503 });
1504 log.info("Reconfigure routers for {}", osNode.hostname());
1505 }
1506 }
Jian Li5a26ab32019-03-21 15:20:01 +09001507
1508 private class PortRange {
1509 private int min;
1510 private int max;
1511
1512 /**
1513 * A default constructor.
1514 *
1515 * @param min min port num
1516 * @param max max port num
1517 */
1518 public PortRange(int min, int max) {
1519 this.min = min;
1520 this.max = max;
1521 }
1522
1523 /**
1524 * Obtains min port num.
1525 *
1526 * @return min port num
1527 */
1528 int min() {
1529 return min;
1530 }
1531
1532 /**
1533 * Obtains max port num.
1534 *
1535 * @return max port num
1536 */
1537 int max() {
1538 return max;
1539 }
1540
1541 @Override
1542 public String toString() {
1543 return MoreObjects.toStringHelper(this)
1544 .add("min", min)
1545 .add("max", max)
1546 .toString();
1547 }
1548
1549 @Override
1550 public boolean equals(Object o) {
1551 if (this == o) {
1552 return true;
1553 }
1554 if (o == null || getClass() != o.getClass()) {
1555 return false;
1556 }
1557 PortRange portRange = (PortRange) o;
1558 return min == portRange.min &&
1559 max == portRange.max;
1560 }
1561
1562 @Override
1563 public int hashCode() {
1564 return Objects.hash(min, max);
1565 }
1566 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001567}