blob: d74e276c48a49894156c88861df1c49430271b07 [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 Lifdb8d872019-04-08 10:38:58 +0900115import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
Jian Li33b4db52019-03-20 18:22:38 +0900116import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
117import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
118import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT;
119import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT_DEFAULT;
Jian Liebde74d2018-11-14 00:18:57 +0900120import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalIpFromSubnet;
121import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Jian Li5a26ab32019-03-21 15:20:01 +0900122import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getExternalIp;
Jian Liec857292019-04-03 18:18:52 +0900123import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Li2d68c192018-12-13 15:52:59 +0900124import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
Jian Li5a26ab32019-03-21 15:20:01 +0900125import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.CT_NAT_SRC_FLAG;
Jian Li33b4db52019-03-20 18:22:38 +0900126import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
127import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900128import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129import static org.slf4j.LoggerFactory.getLogger;
130
131/**
132 * Handle packets needs SNAT.
133 */
Jian Li33b4db52019-03-20 18:22:38 +0900134@Component(
135 immediate = true,
136 property = {
137 USE_STATEFUL_SNAT + ":Boolean=" + USE_STATEFUL_SNAT_DEFAULT
138 }
139)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140public class OpenstackRoutingSnatHandler {
141
142 private final Logger log = getLogger(getClass());
143
Jian Li33b4db52019-03-20 18:22:38 +0900144 private static final String ERR_PACKET_IN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +0900145 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Ray Milkey3717e602018-02-01 13:49:47 -0800146 private static final long TIME_OUT_SNAT_PORT_MS = 120L * 1000L;
Jian Li5a26ab32019-03-21 15:20:01 +0900147 private static final int TP_PORT_MINIMUM_NUM = 1025;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 private static final int TP_PORT_MAXIMUM_NUM = 65535;
Jian Li6a47fd02018-11-27 21:51:03 +0900149 private static final int VM_PREFIX = 32;
Jian Lidc5d5012019-04-04 13:54:41 +0900150 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151
Jian Li33b4db52019-03-20 18:22:38 +0900152 private static final String MSG_ENABLED = "Enabled ";
153 private static final String MSG_DISABLED = "Disabled ";
154
155 /** Use Stateful SNAT for source NATing. */
156 private boolean useStatefulSnat = USE_STATEFUL_SNAT_DEFAULT;
157
158 private static final KryoNamespace.Builder NUMBER_SERIALIZER =
159 KryoNamespace.newBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160 .register(KryoNamespaces.API);
161
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163 protected CoreService coreService;
164
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700165 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 protected PacketService packetService;
167
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700168 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 protected StorageService storageService;
170
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700171 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172 protected DeviceService deviceService;
173
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700174 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 protected InstancePortService instancePortService;
176
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700177 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900178 protected ComponentConfigService configService;
179
180 @Reference(cardinality = ReferenceCardinality.MANDATORY)
181 protected DriverService driverService;
182
183 @Reference(cardinality = ReferenceCardinality.MANDATORY)
184 protected LeadershipService leadershipService;
185
186 @Reference(cardinality = ReferenceCardinality.MANDATORY)
187 protected MastershipService mastershipService;
188
189 @Reference(cardinality = ReferenceCardinality.MANDATORY)
190 protected ClusterService clusterService;
191
192 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 protected OpenstackNodeService osNodeService;
194
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700195 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li33b4db52019-03-20 18:22:38 +0900196 protected OpenstackNetworkAdminService osNetworkAdminService;
197
198 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900199 protected OpenstackNetworkService osNetworkService;
200
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700201 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900202 protected OpenstackRouterService osRouterService;
203
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700204 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900205 protected OpenstackFlowRuleService osFlowRuleService;
206
Hyunsun Moon44aac662017-02-18 02:07:01 +0900207 private final ExecutorService eventExecutor = newSingleThreadExecutor(
208 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900209 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Jian Li33b4db52019-03-20 18:22:38 +0900210 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
211 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
212 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Lidc5d5012019-04-04 13:54:41 +0900213 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214
daniel park0bc7fdb2017-03-13 14:20:08 +0900215 private ConsistentMap<Integer, Long> allocatedPortNumMap;
216 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900217 private ApplicationId appId;
Jian Li33b4db52019-03-20 18:22:38 +0900218 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900219
220 @Activate
221 protected void activate() {
222 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900223
224 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900225 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
Jian Li5a26ab32019-03-21 15:20:01 +0900226 .withName("openstackrouting-allocated-portnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900227 .withApplicationId(appId)
228 .build();
229
daniel park0bc7fdb2017-03-13 14:20:08 +0900230 unUsedPortNumSet = storageService.<Integer>setBuilder()
Jian Li5a26ab32019-03-21 15:20:01 +0900231 .withName("openstackrouting-unused-portnumset")
daniel park0bc7fdb2017-03-13 14:20:08 +0900232 .withSerializer(Serializer.using(KryoNamespaces.API))
233 .build()
234 .asDistributedSet();
235
Jian Li33b4db52019-03-20 18:22:38 +0900236 localNodeId = clusterService.getLocalNode().id();
237 leadershipService.runForLeadership(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900238 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Jian Li33b4db52019-03-20 18:22:38 +0900239
240 configService.registerProperties(getClass());
241 instancePortService.addListener(instancePortListener);
242 osRouterService.addListener(osRouterListener);
243 osNodeService.addListener(osNodeListener);
Jian Lidc5d5012019-04-04 13:54:41 +0900244 osNetworkAdminService.addListener(osNetworkListener);
Jian Li33b4db52019-03-20 18:22:38 +0900245
Jian Li5a26ab32019-03-21 15:20:01 +0900246 eventExecutor.execute(this::initializeUnusedPortNumSet);
247
Hyunsun Moon44aac662017-02-18 02:07:01 +0900248 log.info("Started");
249 }
250
251 @Deactivate
252 protected void deactivate() {
Jian Lidc5d5012019-04-04 13:54:41 +0900253 osNetworkAdminService.removeListener(osNetworkListener);
Jian Li33b4db52019-03-20 18:22:38 +0900254 osRouterService.removeListener(osRouterListener);
255 osNodeService.removeListener(osNodeListener);
256 instancePortService.removeListener(instancePortListener);
257 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900258 packetService.removeProcessor(packetProcessor);
Jian Li33b4db52019-03-20 18:22:38 +0900259 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900260 eventExecutor.shutdown();
261 log.info("Stopped");
262 }
263
Jian Li33b4db52019-03-20 18:22:38 +0900264 @Modified
265 protected void modified(ComponentContext context) {
266 Dictionary<?, ?> properties = context.getProperties();
267 Boolean flag;
268
269 flag = Tools.isPropertyEnabled(properties, USE_STATEFUL_SNAT);
270 if (flag == null) {
271 log.info("useStatefulSnat is not configured, " +
272 "using current value of {}", useStatefulSnat);
273 } else {
274 useStatefulSnat = flag;
275 log.info("Configured. useStatefulSnat is {}",
276 useStatefulSnat ? "enabled" : "disabled");
277 }
278
279 resetSnatRules();
280 }
281
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 private void processSnatPacket(PacketContext context, Ethernet eth) {
Jian Li25257212019-03-26 13:31:14 +0900283
Jian Liec857292019-04-03 18:18:52 +0900284 if (getStatefulSnatFlag()) {
Jian Li25257212019-03-26 13:31:14 +0900285 return;
286 }
287
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 IPv4 iPacket = (IPv4) eth.getPayload();
289 InboundPacket packetIn = context.inPacket();
290
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900291 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900292
293 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
294 if (srcInstPort == null) {
Jian Li33b4db52019-03-20 18:22:38 +0900295 log.error(ERR_PACKET_IN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900296 eth.getSourceMAC());
297 return;
298 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900299
Hyunsun Moon44aac662017-02-18 02:07:01 +0900300 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
301 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
Jian Liebde74d2018-11-14 00:18:57 +0900302 IpAddress externalGatewayIp =
303 externalIpFromSubnet(srcSubnet, osRouterService, osNetworkService);
daniel parkb5817102018-02-15 00:18:51 +0900304
Hyunsun Moon44aac662017-02-18 02:07:01 +0900305 if (externalGatewayIp == null) {
306 return;
307 }
308
Jian Li5a26ab32019-03-21 15:20:01 +0900309 ExternalPeerRouter externalPeerRouter = externalPeerRouterFromSubnet(
310 srcSubnet, osRouterService, osNetworkService);
daniel park576969a2018-03-09 07:07:41 +0900311 if (externalPeerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900312 return;
313 }
314
Hyunsun Moon44aac662017-02-18 02:07:01 +0900315 populateSnatFlowRules(context.inPacket(),
316 srcInstPort,
317 TpPort.tpPort(patPort),
daniel park576969a2018-03-09 07:07:41 +0900318 externalGatewayIp, externalPeerRouter);
319
Hyunsun Moon44aac662017-02-18 02:07:01 +0900320
Ray Milkeyf0c47612017-09-28 11:29:38 -0700321 packetOut(eth.duplicate(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900322 packetIn.receivedFrom().deviceId(),
323 patPort,
daniel park576969a2018-03-09 07:07:41 +0900324 externalGatewayIp, externalPeerRouter);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900325 }
326
327 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
328 Port osPort = osNetworkService.port(instance.portId());
329 IP fixedIp = osPort.getFixedIps().stream()
330 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
331 .findAny().orElse(null);
332 if (fixedIp == null) {
333 return null;
334 }
335 return osNetworkService.subnet(fixedIp.getSubnetId());
336 }
337
Jian Li5ecfd1a2018-12-10 11:41:03 +0900338 private void populateSnatFlowRules(InboundPacket packetIn,
339 InstancePort srcInstPort,
340 TpPort patPort, IpAddress externalIp,
341 ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900342 Network osNet = osNetworkService.network(srcInstPort.networkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900343 Type netType = osNetworkService.networkType(srcInstPort.networkId());
344
Hyunsun Moon44aac662017-02-18 02:07:01 +0900345 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900346 final String error = String.format("%s network %s not found",
Jian Li5a26ab32019-03-21 15:20:01 +0900347 ERR_PACKET_IN, srcInstPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900348 throw new IllegalStateException(error);
349 }
350
Jian Li5a26ab32019-03-21 15:20:01 +0900351 setStatelessSnatDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900352 osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900353 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900355 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900356 patPort,
357 packetIn);
358
Jian Li5a26ab32019-03-21 15:20:01 +0900359 setStatelessSnatUpstreamRules(osNet.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900360 netType,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900361 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900362 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900363 patPort,
364 packetIn);
365 }
366
Jian Li5a26ab32019-03-21 15:20:01 +0900367 private void setStatelessSnatDownstreamRules(InstancePort srcInstPort,
368 String segmentId,
369 Type networkType,
370 IpAddress externalIp,
371 ExternalPeerRouter externalPeerRouter,
372 TpPort patPort,
373 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900374 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
375 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
376
377 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
378 .matchEthType(Ethernet.TYPE_IPV4)
379 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900380 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), VM_PREFIX))
381 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900382
383 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900384 .setEthDst(packetIn.parsed().getSourceMAC())
385 .setIpDst(internalIp);
386
Jian Li5e2ad4a2018-07-16 13:40:53 +0900387 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
388 sBuilder.matchVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900389 tBuilder.popVlan();
390 }
391
daniel parkee8700b2017-05-11 15:50:03 +0900392 switch (networkType) {
393 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900394 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900395 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900396 tBuilder.setTunnelId(Long.parseLong(segmentId));
397 break;
398 case VLAN:
399 tBuilder.pushVlan()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900400 .setVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900401 break;
402 default:
Jian Li71670d12018-03-02 21:31:07 +0900403 final String error = String.format("%s %s",
404 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900405 throw new IllegalStateException(error);
406 }
407
408
Hyunsun Moon44aac662017-02-18 02:07:01 +0900409 switch (iPacket.getProtocol()) {
410 case IPv4.PROTOCOL_TCP:
411 TCP tcpPacket = (TCP) iPacket.getPayload();
412 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
413 .matchTcpDst(patPort);
414 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
415 break;
416 case IPv4.PROTOCOL_UDP:
417 UDP udpPacket = (UDP) iPacket.getPayload();
418 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
419 .matchUdpDst(patPort);
420 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
421 break;
422 default:
423 break;
424 }
425
Hyunsun Moon0d457362017-06-27 17:19:41 +0900426 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
427 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Jian Li6a47fd02018-11-27 21:51:03 +0900428 TrafficTreatment treatment =
Jian Li5a26ab32019-03-21 15:20:01 +0900429 getDownstreamTreatment(networkType, tBuilder, gNode, srcNode);
sanghodc375372017-06-08 10:41:30 +0900430 osFlowRuleService.setRule(
431 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900432 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900433 sBuilder.build(),
Jian Li6a47fd02018-11-27 21:51:03 +0900434 treatment,
sanghodc375372017-06-08 10:41:30 +0900435 PRIORITY_SNAT_RULE,
436 GW_COMMON_TABLE,
437 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900438 });
439 }
440
Jian Li5a26ab32019-03-21 15:20:01 +0900441 private TrafficTreatment getDownstreamTreatment(Type networkType,
Jian Li6a47fd02018-11-27 21:51:03 +0900442 TrafficTreatment.Builder tBuilder,
443 OpenstackNode gNode,
444 OpenstackNode srcNode) {
445 TrafficTreatment.Builder tmpBuilder =
446 DefaultTrafficTreatment.builder(tBuilder.build());
447 switch (networkType) {
448 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900449 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900450 case GENEVE:
SONA Project6bc5c4a2018-12-14 23:49:52 +0900451 PortNumber portNum = tunnelPortNumByNetType(networkType, gNode);
Jian Li6a47fd02018-11-27 21:51:03 +0900452 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
453 deviceService,
454 gNode.intgBridge(),
455 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900456 .setOutput(portNum);
Jian Li6a47fd02018-11-27 21:51:03 +0900457 break;
458 case VLAN:
459 tmpBuilder.setOutput(gNode.vlanPortNum());
460 break;
461 default:
462 final String error = String.format("%s %s",
463 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
464 throw new IllegalStateException(error);
465 }
466
467 return tmpBuilder.build();
468 }
469
Jian Li5a26ab32019-03-21 15:20:01 +0900470 private void setStatelessSnatUpstreamRules(String segmentId,
471 Type networkType,
472 IpAddress externalIp,
473 ExternalPeerRouter externalPeerRouter,
474 TpPort patPort,
475 InboundPacket packetIn) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900476 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900477
478 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900479 .matchEthType(Ethernet.TYPE_IPV4)
480 .matchIPProtocol(iPacket.getProtocol())
Jian Li6a47fd02018-11-27 21:51:03 +0900481 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), VM_PREFIX))
482 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), VM_PREFIX));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900483
484 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900485
486 switch (networkType) {
487 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900488 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900489 case GENEVE:
daniel parkee8700b2017-05-11 15:50:03 +0900490 sBuilder.matchTunnelId(Long.parseLong(segmentId));
491 break;
492 case VLAN:
493 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
494 tBuilder.popVlan();
495 break;
496 default:
Jian Li71670d12018-03-02 21:31:07 +0900497 final String error = String.format("%s %s",
498 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900499 throw new IllegalStateException(error);
500 }
501
Hyunsun Moon44aac662017-02-18 02:07:01 +0900502 switch (iPacket.getProtocol()) {
503 case IPv4.PROTOCOL_TCP:
504 TCP tcpPacket = (TCP) iPacket.getPayload();
505 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
506 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900507 tBuilder.setTcpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900508 break;
509 case IPv4.PROTOCOL_UDP:
510 UDP udpPacket = (UDP) iPacket.getPayload();
511 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
512 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
Jian Li6a47fd02018-11-27 21:51:03 +0900513 tBuilder.setUdpSrc(patPort).setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900514 break;
515 default:
516 log.debug("Unsupported IPv4 protocol {}");
517 break;
518 }
519
Jian Li5e2ad4a2018-07-16 13:40:53 +0900520 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
521 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900522 }
523
Hyunsun Moon44aac662017-02-18 02:07:01 +0900524 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900525 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900526 TrafficTreatment.Builder tmpBuilder =
527 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900528 tmpBuilder.setOutput(gNode.uplinkPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900529
sanghodc375372017-06-08 10:41:30 +0900530 osFlowRuleService.setRule(
531 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900532 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900533 sBuilder.build(),
534 tmpBuilder.build(),
535 PRIORITY_SNAT_RULE,
536 GW_COMMON_TABLE,
537 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900538 });
539 }
540
541 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
daniel park576969a2018-03-09 07:07:41 +0900542 IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900543 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900544 switch (iPacket.getProtocol()) {
545 case IPv4.PROTOCOL_TCP:
Jian Li6a47fd02018-11-27 21:51:03 +0900546 iPacket.setPayload(buildPacketOutTcp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900547 break;
548 case IPv4.PROTOCOL_UDP:
Jian Li6a47fd02018-11-27 21:51:03 +0900549 iPacket.setPayload(buildPacketOutUdp(iPacket, patPort));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900550 break;
551 default:
552 log.trace("Temporally, this method can process UDP and TCP protocol.");
553 return;
554 }
555
556 iPacket.setSourceAddress(externalIp.toString());
557 iPacket.resetChecksum();
558 iPacket.setParent(ethPacketIn);
daniel park576969a2018-03-09 07:07:41 +0900559 ethPacketIn.setSourceMACAddress(DEFAULT_GATEWAY_MAC);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900560 ethPacketIn.setDestinationMACAddress(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900561 ethPacketIn.setPayload(iPacket);
daniel park576969a2018-03-09 07:07:41 +0900562
Jian Li5e2ad4a2018-07-16 13:40:53 +0900563 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
564 ethPacketIn.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900565 }
566
daniel parkee8700b2017-05-11 15:50:03 +0900567 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900568
Hyunsun Moon0d457362017-06-27 17:19:41 +0900569 OpenstackNode srcNode = osNodeService.node(srcDevice);
570 if (srcNode == null) {
571 final String error = String.format("Cannot find openstack node for %s",
572 srcDevice);
573 throw new IllegalStateException(error);
574 }
daniel parkee8700b2017-05-11 15:50:03 +0900575
daniel park576969a2018-03-09 07:07:41 +0900576 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
577
Hyunsun Moon44aac662017-02-18 02:07:01 +0900578 packetService.emit(new DefaultOutboundPacket(
579 srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900580 tBuilder.setOutput(srcNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900581 ByteBuffer.wrap(ethPacketIn.serialize())));
582 }
583
Jian Li6a47fd02018-11-27 21:51:03 +0900584 private TCP buildPacketOutTcp(IPv4 iPacket, int patPort) {
585 TCP tcpPacket = (TCP) iPacket.getPayload();
586 tcpPacket.setSourcePort(patPort);
587 tcpPacket.resetChecksum();
588 tcpPacket.setParent(iPacket);
589
590 return tcpPacket;
591 }
592
593 private UDP buildPacketOutUdp(IPv4 iPacket, int patPort) {
594 UDP udpPacket = (UDP) iPacket.getPayload();
595 udpPacket.setSourcePort(patPort);
596 udpPacket.resetChecksum();
597 udpPacket.setParent(iPacket);
598
599 return udpPacket;
600 }
601
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900602 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900603 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900604 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900605 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900606 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900607 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900608 unUsedPortNumSet.remove(portNum);
609 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900610 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900611 return portNum;
612 }
613
614 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900615 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900616 }
617
618 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900619 allocatedPortNumMap.entrySet().forEach(e -> {
Jian Li5a26ab32019-03-21 15:20:01 +0900620 if (System.currentTimeMillis() -
621 e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900622 allocatedPortNumMap.remove(e.getKey());
623 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900624 }
625 });
626 }
627
Jian Li33b4db52019-03-20 18:22:38 +0900628 private void initializeUnusedPortNumSet() {
629 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
630 if (!allocatedPortNumMap.containsKey(i)) {
631 unUsedPortNumSet.add(i);
632 }
633 }
634
635 clearPortNumMap();
636 }
637
638 private void resetSnatRules() {
Jian Liec857292019-04-03 18:18:52 +0900639 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900640 osRouterService.routerInterfaces().forEach(
641 routerIface -> {
642 setReactiveSnatRules(routerIface, false);
643 setStatefulSnatRules(routerIface, true);
644 }
645 );
646 } else {
647 osRouterService.routerInterfaces().forEach(
648 routerIface -> {
649 setStatefulSnatRules(routerIface, false);
650 setReactiveSnatRules(routerIface, true);
651 }
652 );
653 }
654 }
655
656 private void setRulesToGateway(OpenstackNode osNode,
657 String segmentId,
658 IpPrefix srcSubnet,
659 Type networkType,
660 boolean install) {
Jian Li5a26ab32019-03-21 15:20:01 +0900661 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY)
662 .stream().findFirst().orElse(null);
Jian Li33b4db52019-03-20 18:22:38 +0900663
664 if (sourceNatGateway == null) {
665 return;
666 }
667
668 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
669 .matchEthType(Ethernet.TYPE_IPV4)
670 .matchIPSrc(srcSubnet.getIp4Prefix())
671 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
672
673 switch (networkType) {
674 case VXLAN:
675 case GRE:
676 case GENEVE:
677 sBuilder.matchTunnelId(Long.parseLong(segmentId));
678 break;
679 case VLAN:
680 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
681 break;
682 default:
683 final String error = String.format("%s %s",
684 ERR_UNSUPPORTED_NET_TYPE,
685 networkType.toString());
686 throw new IllegalStateException(error);
687 }
688
689 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
690
691 switch (networkType) {
692 case VXLAN:
693 case GRE:
694 case GENEVE:
695 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
696 tBuilder.extension(buildExtension(
697 deviceService,
698 osNode.intgBridge(),
699 sourceNatGateway.dataIp().getIp4Address()),
700 osNode.intgBridge())
701 .setOutput(portNum);
702 break;
703
704 case VLAN:
705 tBuilder.setOutput(osNode.vlanPortNum());
706 break;
707
708 default:
709 break;
710 }
711
712 osFlowRuleService.setRule(
713 appId,
714 osNode.intgBridge(),
715 sBuilder.build(),
716 tBuilder.build(),
717 PRIORITY_EXTERNAL_ROUTING_RULE,
718 ROUTING_TABLE,
719 install);
720 }
721
722
723 private void routerUpdated(Router osRouter) {
724 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
725
726 ExternalPeerRouter externalPeerRouter =
727 osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5a26ab32019-03-21 15:20:01 +0900728 VlanId vlanId = externalPeerRouter == null ?
729 VlanId.NONE : externalPeerRouter.vlanId();
Jian Li33b4db52019-03-20 18:22:38 +0900730
731 if (exGateway == null) {
732 deleteUnassociatedExternalPeerRouter();
733 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
734 setSourceNat(iface, false));
735 } else {
736 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
737 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
738 setSourceNat(iface, exGateway.isEnableSnat()));
739 }
740 }
741
742 private void deleteUnassociatedExternalPeerRouter() {
743 log.trace("Deleting unassociated external peer router");
744
745 try {
746 Set<String> routerIps = Sets.newConcurrentHashSet();
747
748 osRouterService.routers().stream()
749 .filter(router -> getGatewayIpAddress(router) != null)
750 .map(router -> getGatewayIpAddress(router).toString())
751 .forEach(routerIps::add);
752
753 osNetworkAdminService.externalPeerRouters().stream()
754 .filter(externalPeerRouter ->
755 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
756 .forEach(externalPeerRouter -> {
757 osNetworkAdminService
758 .deleteExternalPeerRouter(
759 externalPeerRouter.ipAddress().toString());
760 log.trace("Deleted unassociated external peer router {}",
761 externalPeerRouter.ipAddress().toString());
762 });
763 } catch (Exception e) {
764 log.error("Exception occurred because of {}", e.toString());
765 }
766 }
767
768 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
769 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
770 if (exGateway != null && exGateway.isEnableSnat()) {
771 setSourceNat(osRouterIface, true);
772 }
773 }
774
775 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
776 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
777 if (exGateway != null && exGateway.isEnableSnat()) {
778 setSourceNat(osRouterIface, false);
779 }
780 }
781
782 private void setSourceNat(RouterInterface routerIface, boolean install) {
783 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
784 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
785 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
786
787 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
788 setRulesToGateway(cNode, osNet.getProviderSegID(),
789 IpPrefix.valueOf(osSubnet.getCidr()), netType, install);
790 });
791
Jian Liec857292019-04-03 18:18:52 +0900792 if (getStatefulSnatFlag()) {
Jian Li33b4db52019-03-20 18:22:38 +0900793 setStatefulSnatRules(routerIface, install);
794 } else {
795 setReactiveSnatRules(routerIface, install);
796 }
797
798 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
799 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
800 }
801
802 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
803 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
804 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
805 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
806
807 if (netType == FLAT) {
808 return;
809 }
810
811 Optional<Router> osRouter = osRouterService.routers().stream()
812 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
813 .findAny();
814
815 if (!osRouter.isPresent()) {
816 log.error("Cannot find a router for router interface {} ", routerIface);
817 return;
818 }
Jian Li5a26ab32019-03-21 15:20:01 +0900819
820 IpAddress natAddress = getExternalIp(osRouter.get(), osNetworkService);
Jian Li33b4db52019-03-20 18:22:38 +0900821 if (natAddress == null) {
822 return;
823 }
Jian Li5a26ab32019-03-21 15:20:01 +0900824
825 IpAddress extRouterAddress = getGatewayIpAddress(osRouter.get());
826 if (extRouterAddress == null) {
827 return;
828 }
829
830 ExternalPeerRouter externalPeerRouter =
831 osNetworkService.externalPeerRouter(extRouterAddress);
832 if (externalPeerRouter == null) {
833 return;
834 }
835
Jian Lifdb8d872019-04-08 10:38:58 +0900836 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
837
Jian Li5a26ab32019-03-21 15:20:01 +0900838 Map<OpenstackNode, PortRange> gwPortRangeMap = getAssignedPortsForGateway(
Jian Li25257212019-03-26 13:31:14 +0900839 ImmutableList.copyOf(osNodeService.nodes(GATEWAY)));
Jian Li5a26ab32019-03-21 15:20:01 +0900840
Jian Lidc5d5012019-04-04 13:54:41 +0900841 osNodeService.completeNodes(GATEWAY).forEach(gwNode -> {
Jian Lifdb8d872019-04-08 10:38:58 +0900842 instancePortService.instancePorts(netId)
843 .stream()
844 .filter(port -> port.state() == ACTIVE)
845 .forEach(port -> setGatewayToInstanceDownstreamRule(
846 gwNode, port, install));
Jian Lidc5d5012019-04-04 13:54:41 +0900847 if (install) {
848 PortRange gwPortRange = gwPortRangeMap.get(gwNode);
Jian Li33b4db52019-03-20 18:22:38 +0900849
Jian Lidc5d5012019-04-04 13:54:41 +0900850 Map<String, PortRange> netPortRangeMap =
851 getAssignedPortsForNet(getNetIdByRouterId(routerIface.getId()),
852 gwPortRange.min(), gwPortRange.max());
Jian Li5a26ab32019-03-21 15:20:01 +0900853
Jian Lidc5d5012019-04-04 13:54:41 +0900854 PortRange netPortRange = netPortRangeMap.get(osNet.getId());
Jian Li5a26ab32019-03-21 15:20:01 +0900855
Jian Lidc5d5012019-04-04 13:54:41 +0900856 setStatefulSnatUpstreamRule(gwNode, natAddress,
857 Long.parseLong(osNet.getProviderSegID()),
858 externalPeerRouter, netPortRange.min(),
859 netPortRange.max(), install);
860 } else {
861 setStatefulSnatUpstreamRule(gwNode, natAddress,
862 Long.parseLong(osNet.getProviderSegID()),
863 externalPeerRouter, 0, 0, install);
864 }
865 });
Jian Li33b4db52019-03-20 18:22:38 +0900866 }
867
Jian Li4f3f75a2019-04-03 12:41:30 +0900868 private void setStatefulDownstreamRules(Router osRouter, boolean install) {
869
Jian Li820ec7b2019-04-03 22:01:33 +0900870 if (!getStatefulSnatFlag()) {
871 return;
872 }
873
Jian Li4f3f75a2019-04-03 12:41:30 +0900874 IpAddress natAddress = getExternalIp(osRouter, osNetworkAdminService);
875 if (natAddress == null) {
876 return;
877 }
878
Jian Lidc5d5012019-04-04 13:54:41 +0900879 setStatefulDownstreamRules(natAddress, install);
880 }
881
882 private void setStatefulDownstreamRules(IpAddress natAddress, boolean install) {
Jian Li4f3f75a2019-04-03 12:41:30 +0900883 osNodeService.completeNodes(GATEWAY)
884 .forEach(gwNode -> {
885 setStatefulSnatDownstreamRule(gwNode.intgBridge(),
886 IpPrefix.valueOf(natAddress, VM_PREFIX), install);
Jian Lidc5d5012019-04-04 13:54:41 +0900887 });
Jian Li4f3f75a2019-04-03 12:41:30 +0900888 }
889
Jian Li5a26ab32019-03-21 15:20:01 +0900890 private List<String> getNetIdByRouterId(String routerId) {
891 return osRouterService.routerInterfaces(routerId)
892 .stream()
893 .filter(ri -> osRouterService.router(ri.getId())
894 .getExternalGatewayInfo().isEnableSnat())
895 .map(RouterInterface::getSubnetId)
896 .map(si -> osNetworkAdminService.subnet(si))
897 .map(Subnet::getNetworkId)
898 .collect(Collectors.toList());
899 }
900
901 private Map<OpenstackNode, PortRange>
902 getAssignedPortsForGateway(List<OpenstackNode> gateways) {
903
904 Map<OpenstackNode, PortRange> gwPortRangeMap = Maps.newConcurrentMap();
905
906 int portRangeNumPerGwNode =
907 (TP_PORT_MAXIMUM_NUM - TP_PORT_MINIMUM_NUM + 1) / gateways.size();
908
909 for (int i = 0; i < gateways.size(); i++) {
910 int gwPortRangeMin = TP_PORT_MINIMUM_NUM + i * portRangeNumPerGwNode;
911 int gwPortRangeMax = TP_PORT_MINIMUM_NUM + (i + 1) * portRangeNumPerGwNode - 1;
912
913 gwPortRangeMap.put(gateways.get(i),
914 new PortRange(gwPortRangeMin, gwPortRangeMax));
915 }
916
917 return gwPortRangeMap;
918 }
919
920 private Map<String, PortRange> getAssignedPortsForNet(List<String> netIds,
921 int min, int max) {
922
923 Map<String, PortRange> netPortRangeMap = Maps.newConcurrentMap();
924
925 int portRangeNumPerNet = (max - min + 1) / netIds.size();
926
927 for (int i = 0; i < netIds.size(); i++) {
928 int netPortRangeMin = min + i * portRangeNumPerNet;
929 int netPortRangeMax = min + (i + 1) * portRangeNumPerNet - 1;
930
931 netPortRangeMap.put(netIds.get(i),
932 new PortRange(netPortRangeMin, netPortRangeMax));
933 }
934
935 return netPortRangeMap;
936 }
937
Jian Li33b4db52019-03-20 18:22:38 +0900938 private IpAddress getGatewayIpAddress(Router osRouter) {
939
940 if (osRouter.getExternalGatewayInfo() == null) {
941 return null;
942 }
943 String extNetId = osNetworkAdminService.network(
944 osRouter.getExternalGatewayInfo().getNetworkId()).getId();
945 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
946 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
947 .findAny();
948
949 if (!extSubnet.isPresent()) {
Jian Li5a26ab32019-03-21 15:20:01 +0900950 log.error("Cannot find external subnet for the router");
Jian Li33b4db52019-03-20 18:22:38 +0900951 return null;
952 }
953
954 return IpAddress.valueOf(extSubnet.get().getGateway());
955 }
956
957 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
958 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
959 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
960 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
961
962 osNodeService.completeNodes(GATEWAY)
963 .forEach(gwNode -> setRulesToController(
964 gwNode.intgBridge(),
965 osNet.getProviderSegID(),
966 IpPrefix.valueOf(osSubnet.getCidr()),
967 netType,
968 install));
969 }
970
Jian Li5a26ab32019-03-21 15:20:01 +0900971 private void setGatewayToInstanceDownstreamRule(OpenstackNode gwNode,
972 InstancePort instPort,
973 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +0900974
975 TrafficSelector selector = DefaultTrafficSelector.builder()
976 .matchEthType(Ethernet.TYPE_IPV4)
Jian Li5a26ab32019-03-21 15:20:01 +0900977 .matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX))
978 .build();
979
980 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
981 .setEthDst(instPort.macAddress());
982
983 Type netType = osNetworkAdminService.networkType(instPort.networkId());
984 String segId = osNetworkAdminService.segmentId(instPort.networkId());
985
986 switch (netType) {
987 case VXLAN:
988 case GRE:
989 case GENEVE:
990 tBuilder.setTunnelId(Long.valueOf(segId));
991 break;
992 case VLAN:
993 default:
994 final String error = String.format("%s %s",
995 ERR_UNSUPPORTED_NET_TYPE, netType.name());
996 throw new IllegalStateException(error);
997 }
998
999 OpenstackNode srcNode = osNodeService.node(instPort.deviceId());
1000 TrafficTreatment treatment =
1001 getDownstreamTreatment(netType, tBuilder, gwNode, srcNode);
1002
1003 osFlowRuleService.setRule(
1004 appId,
1005 gwNode.intgBridge(),
1006 selector,
1007 treatment,
1008 PRIORITY_STATEFUL_SNAT_RULE,
1009 GW_COMMON_TABLE,
1010 install);
1011 }
1012
1013 private void setStatefulSnatDownstreamRule(DeviceId deviceId,
1014 IpPrefix gatewayIp,
1015 boolean install) {
1016
Jian Lifdb8d872019-04-08 10:38:58 +09001017 Set<TrafficSelector> selectors = Sets.newConcurrentHashSet();
1018
1019 ImmutableSet<Byte> ipv4Proto = ImmutableSet.of(IPv4.PROTOCOL_TCP, IPv4.PROTOCOL_UDP);
1020
1021 ipv4Proto.forEach(proto -> {
1022 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1023 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
1024 .matchIPDst(gatewayIp)
1025 .matchIPProtocol(proto);
1026 selectors.add(sBuilder.build());
1027 });
1028
Jian Li33b4db52019-03-20 18:22:38 +09001029
1030 ExtensionTreatment natTreatment = RulePopulatorUtil
1031 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
1032 .commit(false)
1033 .natAction(true)
1034 .table((short) 0)
1035 .build();
1036
1037 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li33b4db52019-03-20 18:22:38 +09001038 .extension(natTreatment, deviceId)
1039 .build();
1040
Jian Lifdb8d872019-04-08 10:38:58 +09001041 selectors.forEach(s -> {
1042 osFlowRuleService.setRule(
1043 appId,
1044 deviceId,
1045 s,
1046 treatment,
1047 PRIORITY_STATEFUL_SNAT_RULE,
1048 GW_COMMON_TABLE,
1049 install);
1050 });
Jian Li33b4db52019-03-20 18:22:38 +09001051 }
1052
Jian Li5a26ab32019-03-21 15:20:01 +09001053 private void setStatefulSnatUpstreamRule(OpenstackNode gwNode,
1054 IpAddress gatewayIp,
1055 long vni,
1056 ExternalPeerRouter extPeerRouter,
1057 int minPortNum,
1058 int maxPortNum,
1059 boolean install) {
Jian Li33b4db52019-03-20 18:22:38 +09001060
1061 TrafficSelector selector = DefaultTrafficSelector.builder()
1062 .matchEthType(Ethernet.TYPE_IPV4)
1063 .matchEthDst(DEFAULT_GATEWAY_MAC)
1064 .matchTunnelId(vni)
1065 .build();
1066
Jian Lia2995192019-04-02 14:13:04 +09001067 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Jian Li33b4db52019-03-20 18:22:38 +09001068
Jian Lia2995192019-04-02 14:13:04 +09001069 // we do not consider to much like port range on removing the rules...
1070 if (install) {
1071 ExtensionTreatment natTreatment = RulePopulatorUtil
1072 .niciraConnTrackTreatmentBuilder(driverService, gwNode.intgBridge())
1073 .commit(true)
1074 .natFlag(CT_NAT_SRC_FLAG)
1075 .natAction(true)
1076 .natIp(gatewayIp)
1077 .natPortMin(TpPort.tpPort(minPortNum))
1078 .natPortMax(TpPort.tpPort(maxPortNum))
1079 .build();
1080
1081 tBuilder.extension(natTreatment, gwNode.intgBridge())
1082 .setEthDst(extPeerRouter.macAddress())
1083 .setEthSrc(DEFAULT_GATEWAY_MAC)
1084 .setOutput(gwNode.uplinkPortNum());
1085 }
Jian Li33b4db52019-03-20 18:22:38 +09001086
1087 osFlowRuleService.setRule(
1088 appId,
Jian Li5a26ab32019-03-21 15:20:01 +09001089 gwNode.intgBridge(),
Jian Li33b4db52019-03-20 18:22:38 +09001090 selector,
Jian Lia2995192019-04-02 14:13:04 +09001091 tBuilder.build(),
Jian Li33b4db52019-03-20 18:22:38 +09001092 PRIORITY_STATEFUL_SNAT_RULE,
1093 GW_COMMON_TABLE,
1094 install);
1095 }
1096
Jian Li33b4db52019-03-20 18:22:38 +09001097 private void setRulesToController(DeviceId deviceId,
1098 String segmentId,
1099 IpPrefix srcSubnet,
1100 Type networkType,
1101 boolean install) {
1102 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
1103 .matchEthType(Ethernet.TYPE_IPV4)
1104 .matchIPSrc(srcSubnet)
1105 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
1106
1107 switch (networkType) {
1108 case VXLAN:
1109 case GRE:
1110 case GENEVE:
1111 sBuilder.matchTunnelId(Long.parseLong(segmentId));
1112 break;
1113 case VLAN:
1114 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
1115 break;
1116 default:
1117 final String error = String.format("%s %s",
1118 ERR_UNSUPPORTED_NET_TYPE,
1119 networkType.toString());
1120 throw new IllegalStateException(error);
1121 }
1122
1123 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1124
1125 if (networkType == VLAN) {
1126 tBuilder.popVlan();
1127 }
1128
1129 tBuilder.punt();
1130
1131 osFlowRuleService.setRule(
1132 appId,
1133 deviceId,
1134 sBuilder.build(),
1135 tBuilder.build(),
1136 PRIORITY_EXTERNAL_ROUTING_RULE,
1137 GW_COMMON_TABLE,
1138 install);
1139 }
1140
Jian Liec857292019-04-03 18:18:52 +09001141 private boolean getStatefulSnatFlag() {
1142 Set<ConfigProperty> properties =
1143 configService.getProperties(getClass().getName());
1144 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
1145 }
1146
Jian Li33b4db52019-03-20 18:22:38 +09001147 private class InternalInstancePortListener implements InstancePortListener {
1148
1149 private boolean isRelevantHelper(InstancePortEvent event) {
1150 return mastershipService.isLocalMaster(event.subject().deviceId());
1151 }
1152
1153 @Override
1154 public void event(InstancePortEvent event) {
1155 InstancePort instPort = event.subject();
1156 switch (event.type()) {
1157 case OPENSTACK_INSTANCE_PORT_DETECTED:
1158 case OPENSTACK_INSTANCE_PORT_UPDATED:
1159 eventExecutor.execute(() ->
1160 processInstancePortDetection(event, instPort));
1161 break;
1162 case OPENSTACK_INSTANCE_PORT_VANISHED:
1163 eventExecutor.execute(() ->
1164 processInstancePortRemoval(event, instPort));
1165 break;
1166 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1167 eventExecutor.execute(() ->
1168 processInstanceMigrationStart(event, instPort));
1169 break;
1170 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1171 eventExecutor.execute(() ->
1172 processInstanceMigrationEnd(event, instPort));
1173 break;
1174 default:
1175 break;
1176 }
1177 }
1178
1179 private void processInstancePortDetection(InstancePortEvent event,
1180 InstancePort instPort) {
1181 if (!isRelevantHelper(event)) {
1182 return;
1183 }
1184
1185 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1186 instPort.macAddress(),
1187 instPort.ipAddress());
1188
1189 instPortDetected(event.subject());
1190 }
1191
1192 private void processInstancePortRemoval(InstancePortEvent event,
1193 InstancePort instPort) {
1194 if (!isRelevantHelper(event)) {
1195 return;
1196 }
1197
1198 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1199 instPort.macAddress(),
1200 instPort.ipAddress());
1201
1202 instPortRemoved(event.subject());
1203 }
1204
1205 private void processInstanceMigrationStart(InstancePortEvent event,
1206 InstancePort instPort) {
1207 if (!isRelevantHelper(event)) {
1208 return;
1209 }
1210
1211 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1212 instPort.macAddress(),
1213 instPort.ipAddress());
1214
1215 instPortDetected(instPort);
1216 }
1217
1218 private void processInstanceMigrationEnd(InstancePortEvent event,
1219 InstancePort instPort) {
1220 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1221 instPort.macAddress(),
1222 instPort.ipAddress());
1223 // TODO: need to reconfigure rules to point to update VM
1224 }
1225
1226 private void instPortDetected(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001227 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1228
1229 if (netType == FLAT) {
1230 return;
1231 }
1232
Jian Liec857292019-04-03 18:18:52 +09001233 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001234 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1235 setGatewayToInstanceDownstreamRule(gwNode, instPort, true));
Jian Li33b4db52019-03-20 18:22:38 +09001236 }
1237 }
1238
1239 private void instPortRemoved(InstancePort instPort) {
Jian Li33b4db52019-03-20 18:22:38 +09001240 Type netType = osNetworkAdminService.networkType(instPort.networkId());
1241
1242 if (netType == FLAT) {
1243 return;
1244 }
1245
Jian Liec857292019-04-03 18:18:52 +09001246 if (getStatefulSnatFlag()) {
Jian Li5a26ab32019-03-21 15:20:01 +09001247 osNodeService.completeNodes(GATEWAY).forEach(gwNode ->
1248 setGatewayToInstanceDownstreamRule(gwNode, instPort, false));
Jian Li33b4db52019-03-20 18:22:38 +09001249 }
1250 }
1251 }
1252
Jian Lidc5d5012019-04-04 13:54:41 +09001253 private class InternalNetworkEventListener implements OpenstackNetworkListener {
1254
1255 @Override
1256 public boolean isRelevant(OpenstackNetworkEvent event) {
1257 Port osPort = event.port();
1258 if (osPort == null || osPort.getFixedIps() == null) {
1259 return false;
1260 }
1261
1262 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
1263 getStatefulSnatFlag();
1264 }
1265
1266 private boolean isRelevantHelper() {
1267 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1268 }
1269
1270 @Override
1271 public void event(OpenstackNetworkEvent event) {
1272 IpAddress ipAddress = externalIp(event.port());
1273 switch (event.type()) {
1274 case OPENSTACK_PORT_CREATED:
1275 case OPENSTACK_PORT_UPDATED:
1276 eventExecutor.execute(() -> processPortCreation(ipAddress));
1277 break;
1278 case OPENSTACK_PORT_REMOVED:
1279 eventExecutor.execute(() -> processPortRemoval(ipAddress));
1280 break;
1281 default:
1282 // do nothing
1283 break;
1284 }
1285 }
1286
1287 private void processPortCreation(IpAddress ipAddress) {
1288 if (!isRelevantHelper() || ipAddress == null) {
1289 return;
1290 }
1291
1292 setStatefulDownstreamRules(ipAddress, true);
1293 }
1294
1295 private void processPortRemoval(IpAddress ipAddress) {
1296 if (!isRelevantHelper() || ipAddress == null) {
1297 return;
1298 }
1299
1300 setStatefulDownstreamRules(ipAddress, false);
1301 }
1302
1303 private IpAddress externalIp(Port port) {
1304 IP ip = port.getFixedIps().stream().findAny().orElse(null);
1305
1306 if (ip != null && ip.getIpAddress() != null) {
1307 return IpAddress.valueOf(ip.getIpAddress());
1308 }
1309
1310 return null;
1311 }
1312 }
1313
Jian Li33b4db52019-03-20 18:22:38 +09001314 private class InternalRouterEventListener implements OpenstackRouterListener {
1315
1316 private boolean isRelevantHelper() {
1317 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1318 }
1319
1320 @Override
1321 public void event(OpenstackRouterEvent event) {
1322 switch (event.type()) {
1323 case OPENSTACK_ROUTER_CREATED:
1324 eventExecutor.execute(() -> processRouterCreation(event));
1325 break;
1326 case OPENSTACK_ROUTER_UPDATED:
1327 eventExecutor.execute(() -> processRouterUpdate(event));
1328 break;
1329 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1330 eventExecutor.execute(() -> processRouterIntfCreation(event));
1331 break;
1332 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1333 eventExecutor.execute(() -> processRouterIntfRemoval(event));
1334 break;
Jian Li33b4db52019-03-20 18:22:38 +09001335 default:
1336 break;
1337 }
1338 }
1339
1340 private void processRouterCreation(OpenstackRouterEvent event) {
1341 if (!isRelevantHelper()) {
1342 return;
1343 }
1344
1345 log.debug("Router(name:{}, ID:{}) is created",
1346 event.subject().getName(),
1347 event.subject().getId());
1348
1349 routerUpdated(event.subject());
1350 }
1351
1352 private void processRouterUpdate(OpenstackRouterEvent event) {
1353 if (!isRelevantHelper()) {
1354 return;
1355 }
1356
1357 log.debug("Router(name:{}, ID:{}) is updated",
1358 event.subject().getName(),
1359 event.subject().getId());
1360
1361 routerUpdated(event.subject());
1362 }
1363
1364 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1365 if (!isRelevantHelper()) {
1366 return;
1367 }
1368
1369 log.debug("Router interface {} added to router {}",
1370 event.routerIface().getPortId(),
1371 event.routerIface().getId());
1372
1373 routerIfaceAdded(event.subject(), event.routerIface());
1374 }
1375
1376 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1377 if (!isRelevantHelper()) {
1378 return;
1379 }
1380
1381 log.debug("Router interface {} removed from router {}",
1382 event.routerIface().getPortId(),
1383 event.routerIface().getId());
1384
1385 routerIfaceRemoved(event.subject(), event.routerIface());
1386 }
1387 }
1388
Hyunsun Moon44aac662017-02-18 02:07:01 +09001389 private class InternalPacketProcessor implements PacketProcessor {
1390
1391 @Override
1392 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +09001393
Hyunsun Moon44aac662017-02-18 02:07:01 +09001394 if (context.isHandled()) {
1395 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001396 }
1397
1398 InboundPacket pkt = context.inPacket();
1399 Ethernet eth = pkt.parsed();
1400 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
1401 return;
1402 }
1403
1404 IPv4 iPacket = (IPv4) eth.getPayload();
1405 switch (iPacket.getProtocol()) {
1406 case IPv4.PROTOCOL_ICMP:
1407 break;
1408 case IPv4.PROTOCOL_UDP:
1409 UDP udpPacket = (UDP) iPacket.getPayload();
1410 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
1411 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
Jian Li6a47fd02018-11-27 21:51:03 +09001412 break; // don't process DHCP
Hyunsun Moon44aac662017-02-18 02:07:01 +09001413 }
1414 default:
Jian Li34220ea2018-11-14 01:30:24 +09001415 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001416 if (!isRelevantHelper(context)) {
1417 return;
1418 }
Jian Li34220ea2018-11-14 01:30:24 +09001419 processSnatPacket(context, eth);
1420 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001421 break;
1422 }
1423 }
Jian Li34220ea2018-11-14 01:30:24 +09001424
1425 private boolean isRelevantHelper(PacketContext context) {
1426 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
1427 .stream().map(OpenstackNode::intgBridge)
1428 .collect(Collectors.toSet());
1429
1430 return gateways.contains(context.inPacket().receivedFrom().deviceId());
1431 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001432 }
Jian Li33b4db52019-03-20 18:22:38 +09001433
1434 private class InternalNodeEventListener implements OpenstackNodeListener {
1435
1436 private boolean isRelevantHelper() {
1437 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
1438 }
1439
1440 @Override
1441 public void event(OpenstackNodeEvent event) {
1442 OpenstackNode osNode = event.subject();
1443 switch (event.type()) {
1444 case OPENSTACK_NODE_COMPLETE:
Jian Li5a26ab32019-03-21 15:20:01 +09001445 eventExecutor.execute(() -> processGatewayCompletion(osNode));
1446 eventExecutor.execute(() -> reconfigureRouters(osNode));
1447 break;
1448 case OPENSTACK_NODE_REMOVED:
1449 eventExecutor.execute(() -> processGatewayRemoval(osNode));
Jian Li5d795f22019-04-01 23:07:40 +09001450 eventExecutor.execute(() -> reconfigureRouters(osNode));
1451 break;
Jian Li33b4db52019-03-20 18:22:38 +09001452 case OPENSTACK_NODE_INCOMPLETE:
1453 case OPENSTACK_NODE_UPDATED:
Jian Li5a26ab32019-03-21 15:20:01 +09001454 eventExecutor.execute(() -> reconfigureRouters(osNode));
Jian Li33b4db52019-03-20 18:22:38 +09001455 break;
1456 case OPENSTACK_NODE_CREATED:
1457 default:
1458 break;
1459 }
1460 }
1461
Jian Li5a26ab32019-03-21 15:20:01 +09001462 private void processGatewayCompletion(OpenstackNode osNode) {
1463 if (!isRelevantHelper()) {
1464 return;
1465 }
1466
Jian Liec857292019-04-03 18:18:52 +09001467 if (getStatefulSnatFlag() && osNode.type() == GATEWAY) {
Jian Li5a26ab32019-03-21 15:20:01 +09001468 instancePortService.instancePorts().forEach(instPort ->
1469 setGatewayToInstanceDownstreamRule(osNode, instPort, true));
1470 }
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 Li5a26ab32019-03-21 15:20:01 +09001479 instancePortService.instancePorts().forEach(instPort ->
1480 setGatewayToInstanceDownstreamRule(osNode, instPort, false));
1481 }
1482 }
1483
Jian Li33b4db52019-03-20 18:22:38 +09001484 private void reconfigureRouters(OpenstackNode osNode) {
Jian Li5a26ab32019-03-21 15:20:01 +09001485 if (!isRelevantHelper()) {
1486 return;
1487 }
1488
Jian Li33b4db52019-03-20 18:22:38 +09001489 osRouterService.routers().forEach(osRouter -> {
1490 routerUpdated(osRouter);
1491 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1492 routerIfaceAdded(osRouter, iface);
1493 });
Jian Lidc5d5012019-04-04 13:54:41 +09001494
1495 setStatefulDownstreamRules(osRouter, true);
Jian Li33b4db52019-03-20 18:22:38 +09001496 });
1497 log.info("Reconfigure routers for {}", osNode.hostname());
1498 }
1499 }
Jian Li5a26ab32019-03-21 15:20:01 +09001500
1501 private class PortRange {
1502 private int min;
1503 private int max;
1504
1505 /**
1506 * A default constructor.
1507 *
1508 * @param min min port num
1509 * @param max max port num
1510 */
1511 public PortRange(int min, int max) {
1512 this.min = min;
1513 this.max = max;
1514 }
1515
1516 /**
1517 * Obtains min port num.
1518 *
1519 * @return min port num
1520 */
1521 int min() {
1522 return min;
1523 }
1524
1525 /**
1526 * Obtains max port num.
1527 *
1528 * @return max port num
1529 */
1530 int max() {
1531 return max;
1532 }
1533
1534 @Override
1535 public String toString() {
1536 return MoreObjects.toStringHelper(this)
1537 .add("min", min)
1538 .add("max", max)
1539 .toString();
1540 }
1541
1542 @Override
1543 public boolean equals(Object o) {
1544 if (this == o) {
1545 return true;
1546 }
1547 if (o == null || getClass() != o.getClass()) {
1548 return false;
1549 }
1550 PortRange portRange = (PortRange) o;
1551 return min == portRange.min &&
1552 max == portRange.max;
1553 }
1554
1555 @Override
1556 public int hashCode() {
1557 return Objects.hash(min, max);
1558 }
1559 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001560}