blob: 62037403e2889b2b1fb7372af7360b4b6a8e2b8f [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
Hyunsun Moon44aac662017-02-18 02:07:01 +090018import org.onlab.packet.Ethernet;
19import org.onlab.packet.IPv4;
20import org.onlab.packet.IpAddress;
21import org.onlab.packet.IpPrefix;
Hyunsun Moon44aac662017-02-18 02:07:01 +090022import org.onlab.packet.TCP;
23import org.onlab.packet.TpPort;
24import org.onlab.packet.UDP;
daniel parkee8700b2017-05-11 15:50:03 +090025import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090026import org.onlab.util.KryoNamespace;
27import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.net.DeviceId;
30import org.onosproject.net.device.DeviceService;
31import org.onosproject.net.flow.DefaultTrafficSelector;
32import org.onosproject.net.flow.DefaultTrafficTreatment;
33import org.onosproject.net.flow.TrafficSelector;
34import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090035import org.onosproject.net.packet.DefaultOutboundPacket;
36import org.onosproject.net.packet.InboundPacket;
37import org.onosproject.net.packet.PacketContext;
38import org.onosproject.net.packet.PacketProcessor;
39import org.onosproject.net.packet.PacketService;
daniel park576969a2018-03-09 07:07:41 +090040import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.openstacknetworking.api.InstancePort;
42import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090043import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sanghodc375372017-06-08 10:41:30 +090045import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Li26949762018-03-30 15:46:37 +090046import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090047import org.onosproject.openstacknode.api.OpenstackNode;
48import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.onosproject.store.serializers.KryoNamespaces;
50import org.onosproject.store.service.ConsistentMap;
daniel park0bc7fdb2017-03-13 14:20:08 +090051import org.onosproject.store.service.DistributedSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.onosproject.store.service.Serializer;
53import org.onosproject.store.service.StorageService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090054import org.openstack4j.model.network.IP;
55import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090056import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090057import org.openstack4j.model.network.Port;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.openstack4j.model.network.Subnet;
Jian Liebde74d2018-11-14 00:18:57 +090059import org.osgi.service.component.annotations.Activate;
60import org.osgi.service.component.annotations.Component;
61import org.osgi.service.component.annotations.Deactivate;
62import org.osgi.service.component.annotations.Reference;
63import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import org.slf4j.Logger;
65
66import java.nio.ByteBuffer;
Hyunsun Moon0d457362017-06-27 17:19:41 +090067import java.util.Set;
Hyunsun Moon44aac662017-02-18 02:07:01 +090068import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090069import java.util.stream.Collectors;
Hyunsun Moon44aac662017-02-18 02:07:01 +090070
71import static java.util.concurrent.Executors.newSingleThreadExecutor;
72import static org.onlab.util.Tools.groupedThreads;
daniel parkeeb8e042018-02-21 14:06:58 +090073import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
74import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
75import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
76import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SNAT_RULE;
Jian Liebde74d2018-11-14 00:18:57 +090077import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalIpFromSubnet;
78import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Hyunsun Moon0d457362017-06-27 17:19:41 +090079import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import static org.slf4j.LoggerFactory.getLogger;
81
82/**
83 * Handle packets needs SNAT.
84 */
85@Component(immediate = true)
86public class OpenstackRoutingSnatHandler {
87
88 private final Logger log = getLogger(getClass());
89
90 private static final String ERR_PACKETIN = "Failed to handle packet in: ";
daniel parkee8700b2017-05-11 15:50:03 +090091 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Ray Milkey3717e602018-02-01 13:49:47 -080092 private static final long TIME_OUT_SNAT_PORT_MS = 120L * 1000L;
sangho79d6a832017-05-02 14:53:46 +090093 private static final int TP_PORT_MINIMUM_NUM = 65000;
Hyunsun Moon44aac662017-02-18 02:07:01 +090094 private static final int TP_PORT_MAXIMUM_NUM = 65535;
95
96 private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
97 .register(KryoNamespaces.API);
98
Ray Milkeyd84f89b2018-08-17 14:54:17 -070099 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900100 protected CoreService coreService;
101
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103 protected PacketService packetService;
104
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106 protected StorageService storageService;
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109 protected DeviceService deviceService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 protected InstancePortService instancePortService;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115 protected OpenstackNodeService osNodeService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118 protected OpenstackNetworkService osNetworkService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121 protected OpenstackRouterService osRouterService;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900124 protected OpenstackFlowRuleService osFlowRuleService;
125
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126 private final ExecutorService eventExecutor = newSingleThreadExecutor(
127 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900128 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129
daniel park0bc7fdb2017-03-13 14:20:08 +0900130 private ConsistentMap<Integer, Long> allocatedPortNumMap;
131 private DistributedSet<Integer> unUsedPortNumSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 private ApplicationId appId;
133
134 @Activate
135 protected void activate() {
136 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
daniel park0bc7fdb2017-03-13 14:20:08 +0900137
138 allocatedPortNumMap = storageService.<Integer, Long>consistentMapBuilder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
daniel park0bc7fdb2017-03-13 14:20:08 +0900140 .withName("openstackrouting-allocatedportnummap")
Hyunsun Moon44aac662017-02-18 02:07:01 +0900141 .withApplicationId(appId)
142 .build();
143
daniel park0bc7fdb2017-03-13 14:20:08 +0900144 unUsedPortNumSet = storageService.<Integer>setBuilder()
145 .withName("openstackrouting-unusedportnumset")
146 .withSerializer(Serializer.using(KryoNamespaces.API))
147 .build()
148 .asDistributedSet();
149
150 initializeUnusedPortNumSet();
151
Hyunsun Moon44aac662017-02-18 02:07:01 +0900152 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
153 log.info("Started");
154 }
155
daniel park0bc7fdb2017-03-13 14:20:08 +0900156 private void initializeUnusedPortNumSet() {
157 for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900158 if (!allocatedPortNumMap.containsKey(i)) {
159 unUsedPortNumSet.add(i);
daniel park0bc7fdb2017-03-13 14:20:08 +0900160 }
161 }
162
163 clearPortNumMap();
164 }
165
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 @Deactivate
167 protected void deactivate() {
168 packetService.removeProcessor(packetProcessor);
169 eventExecutor.shutdown();
170 log.info("Stopped");
171 }
172
173 private void processSnatPacket(PacketContext context, Ethernet eth) {
174 IPv4 iPacket = (IPv4) eth.getPayload();
175 InboundPacket packetIn = context.inPacket();
176
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900177 int patPort = getPortNum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900178
179 InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
180 if (srcInstPort == null) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900181 log.error(ERR_PACKETIN + "source host(MAC:{}) does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 eth.getSourceMAC());
183 return;
184 }
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900185
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 IpAddress srcIp = IpAddress.valueOf(iPacket.getSourceAddress());
187 Subnet srcSubnet = getSourceSubnet(srcInstPort, srcIp);
Jian Liebde74d2018-11-14 00:18:57 +0900188 IpAddress externalGatewayIp =
189 externalIpFromSubnet(srcSubnet, osRouterService, osNetworkService);
daniel parkb5817102018-02-15 00:18:51 +0900190
Hyunsun Moon44aac662017-02-18 02:07:01 +0900191 if (externalGatewayIp == null) {
192 return;
193 }
194
Jian Liebde74d2018-11-14 00:18:57 +0900195 ExternalPeerRouter externalPeerRouter =
196 externalPeerRouterFromSubnet(srcSubnet, osRouterService, osNetworkService);
daniel park576969a2018-03-09 07:07:41 +0900197 if (externalPeerRouter == null) {
daniel parkb5817102018-02-15 00:18:51 +0900198 return;
199 }
200
Hyunsun Moon44aac662017-02-18 02:07:01 +0900201 populateSnatFlowRules(context.inPacket(),
202 srcInstPort,
203 TpPort.tpPort(patPort),
daniel park576969a2018-03-09 07:07:41 +0900204 externalGatewayIp, externalPeerRouter);
205
Hyunsun Moon44aac662017-02-18 02:07:01 +0900206
Ray Milkeyf0c47612017-09-28 11:29:38 -0700207 packetOut(eth.duplicate(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900208 packetIn.receivedFrom().deviceId(),
209 patPort,
daniel park576969a2018-03-09 07:07:41 +0900210 externalGatewayIp, externalPeerRouter);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900211 }
212
213 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
214 Port osPort = osNetworkService.port(instance.portId());
215 IP fixedIp = osPort.getFixedIps().stream()
216 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
217 .findAny().orElse(null);
218 if (fixedIp == null) {
219 return null;
220 }
221 return osNetworkService.subnet(fixedIp.getSubnetId());
222 }
223
Hyunsun Moon44aac662017-02-18 02:07:01 +0900224 private void populateSnatFlowRules(InboundPacket packetIn, InstancePort srcInstPort,
daniel park576969a2018-03-09 07:07:41 +0900225 TpPort patPort, IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 Network osNet = osNetworkService.network(srcInstPort.networkId());
227 if (osNet == null) {
Jian Li71670d12018-03-02 21:31:07 +0900228 final String error = String.format("%s network %s not found",
229 ERR_PACKETIN, srcInstPort.networkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900230 throw new IllegalStateException(error);
231 }
232
233 setDownstreamRules(srcInstPort,
daniel parkee8700b2017-05-11 15:50:03 +0900234 osNet.getProviderSegID(),
235 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900236 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900237 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900238 patPort,
239 packetIn);
240
daniel parkee8700b2017-05-11 15:50:03 +0900241 setUpstreamRules(osNet.getProviderSegID(),
242 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900243 externalIp,
daniel park576969a2018-03-09 07:07:41 +0900244 externalPeerRouter,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900245 patPort,
246 packetIn);
247 }
248
Hyunsun Moon0d457362017-06-27 17:19:41 +0900249 private void setDownstreamRules(InstancePort srcInstPort, String segmentId,
250 NetworkType networkType,
daniel parkb5817102018-02-15 00:18:51 +0900251 IpAddress externalIp,
daniel park576969a2018-03-09 07:07:41 +0900252 ExternalPeerRouter externalPeerRouter,
daniel parkb5817102018-02-15 00:18:51 +0900253 TpPort patPort,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900254 InboundPacket packetIn) {
255 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
256 IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
257
258 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
259 .matchEthType(Ethernet.TYPE_IPV4)
260 .matchIPProtocol(iPacket.getProtocol())
Hyunsun Moon0d457362017-06-27 17:19:41 +0900261 .matchIPDst(IpPrefix.valueOf(externalIp.getIp4Address(), 32))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900262 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
263
264 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900265 .setEthDst(packetIn.parsed().getSourceMAC())
266 .setIpDst(internalIp);
267
Jian Li5e2ad4a2018-07-16 13:40:53 +0900268 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
269 sBuilder.matchVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900270 tBuilder.popVlan();
271 }
272
daniel parkee8700b2017-05-11 15:50:03 +0900273 switch (networkType) {
274 case VXLAN:
275 tBuilder.setTunnelId(Long.parseLong(segmentId));
276 break;
277 case VLAN:
278 tBuilder.pushVlan()
Daniel Parkc64b4c62018-05-09 18:13:39 +0900279 .setVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900280 break;
281 default:
Jian Li71670d12018-03-02 21:31:07 +0900282 final String error = String.format("%s %s",
283 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900284 throw new IllegalStateException(error);
285 }
286
287
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 switch (iPacket.getProtocol()) {
289 case IPv4.PROTOCOL_TCP:
290 TCP tcpPacket = (TCP) iPacket.getPayload();
291 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
292 .matchTcpDst(patPort);
293 tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
294 break;
295 case IPv4.PROTOCOL_UDP:
296 UDP udpPacket = (UDP) iPacket.getPayload();
297 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
298 .matchUdpDst(patPort);
299 tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
300 break;
301 default:
302 break;
303 }
304
Hyunsun Moon0d457362017-06-27 17:19:41 +0900305 OpenstackNode srcNode = osNodeService.node(srcInstPort.deviceId());
306 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900307 TrafficTreatment.Builder tmpBuilder =
308 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkee8700b2017-05-11 15:50:03 +0900309 switch (networkType) {
310 case VXLAN:
311 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
312 deviceService,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900313 gNode.intgBridge(),
314 srcNode.dataIp().getIp4Address()), gNode.intgBridge())
315 .setOutput(gNode.tunnelPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900316 break;
317 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900318 tmpBuilder.setOutput(gNode.vlanPortNum());
daniel parkee8700b2017-05-11 15:50:03 +0900319 break;
320 default:
Jian Li71670d12018-03-02 21:31:07 +0900321 final String error = String.format("%s %s",
322 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900323 throw new IllegalStateException(error);
324 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900325
sanghodc375372017-06-08 10:41:30 +0900326 osFlowRuleService.setRule(
327 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900328 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900329 sBuilder.build(),
330 tmpBuilder.build(),
331 PRIORITY_SNAT_RULE,
332 GW_COMMON_TABLE,
333 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900334 });
335 }
336
Hyunsun Moon0d457362017-06-27 17:19:41 +0900337 private void setUpstreamRules(String segmentId, NetworkType networkType,
daniel park576969a2018-03-09 07:07:41 +0900338 IpAddress externalIp, ExternalPeerRouter externalPeerRouter,
daniel parkb5817102018-02-15 00:18:51 +0900339 TpPort patPort,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900340 InboundPacket packetIn) {
341 IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
daniel parkee8700b2017-05-11 15:50:03 +0900342
343 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900344 .matchEthType(Ethernet.TYPE_IPV4)
345 .matchIPProtocol(iPacket.getProtocol())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
347 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
348
349 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
daniel parkee8700b2017-05-11 15:50:03 +0900350
351 switch (networkType) {
352 case VXLAN:
353 sBuilder.matchTunnelId(Long.parseLong(segmentId));
354 break;
355 case VLAN:
356 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
357 tBuilder.popVlan();
358 break;
359 default:
Jian Li71670d12018-03-02 21:31:07 +0900360 final String error = String.format("%s %s",
361 ERR_UNSUPPORTED_NET_TYPE, networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900362 throw new IllegalStateException(error);
363 }
364
Hyunsun Moon44aac662017-02-18 02:07:01 +0900365 switch (iPacket.getProtocol()) {
366 case IPv4.PROTOCOL_TCP:
367 TCP tcpPacket = (TCP) iPacket.getPayload();
368 sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
369 .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
370 tBuilder.setTcpSrc(patPort)
Jian Li5e2ad4a2018-07-16 13:40:53 +0900371 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900372 break;
373 case IPv4.PROTOCOL_UDP:
374 UDP udpPacket = (UDP) iPacket.getPayload();
375 sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
376 .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
377 tBuilder.setUdpSrc(patPort)
Jian Li5e2ad4a2018-07-16 13:40:53 +0900378 .setEthDst(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900379 break;
380 default:
381 log.debug("Unsupported IPv4 protocol {}");
382 break;
383 }
384
Jian Li5e2ad4a2018-07-16 13:40:53 +0900385 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
386 tBuilder.pushVlan().setVlanId(externalPeerRouter.vlanId());
daniel park576969a2018-03-09 07:07:41 +0900387 }
388
Hyunsun Moon44aac662017-02-18 02:07:01 +0900389 tBuilder.setIpSrc(externalIp);
Hyunsun Moon0d457362017-06-27 17:19:41 +0900390 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900391 TrafficTreatment.Builder tmpBuilder =
392 DefaultTrafficTreatment.builder(tBuilder.build());
daniel parkb5817102018-02-15 00:18:51 +0900393 tmpBuilder.setOutput(gNode.uplinkPortNum());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900394
sanghodc375372017-06-08 10:41:30 +0900395 osFlowRuleService.setRule(
396 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900397 gNode.intgBridge(),
sanghodc375372017-06-08 10:41:30 +0900398 sBuilder.build(),
399 tmpBuilder.build(),
400 PRIORITY_SNAT_RULE,
401 GW_COMMON_TABLE,
402 true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900403 });
404 }
405
406 private void packetOut(Ethernet ethPacketIn, DeviceId srcDevice, int patPort,
daniel park576969a2018-03-09 07:07:41 +0900407 IpAddress externalIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900408 IPv4 iPacket = (IPv4) ethPacketIn.getPayload();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900409 switch (iPacket.getProtocol()) {
410 case IPv4.PROTOCOL_TCP:
411 TCP tcpPacket = (TCP) iPacket.getPayload();
412 tcpPacket.setSourcePort(patPort);
413 tcpPacket.resetChecksum();
414 tcpPacket.setParent(iPacket);
415 iPacket.setPayload(tcpPacket);
416 break;
417 case IPv4.PROTOCOL_UDP:
418 UDP udpPacket = (UDP) iPacket.getPayload();
419 udpPacket.setSourcePort(patPort);
420 udpPacket.resetChecksum();
421 udpPacket.setParent(iPacket);
422 iPacket.setPayload(udpPacket);
423 break;
424 default:
425 log.trace("Temporally, this method can process UDP and TCP protocol.");
426 return;
427 }
428
429 iPacket.setSourceAddress(externalIp.toString());
430 iPacket.resetChecksum();
431 iPacket.setParent(ethPacketIn);
daniel park576969a2018-03-09 07:07:41 +0900432 ethPacketIn.setSourceMACAddress(DEFAULT_GATEWAY_MAC);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900433 ethPacketIn.setDestinationMACAddress(externalPeerRouter.macAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900434 ethPacketIn.setPayload(iPacket);
daniel park576969a2018-03-09 07:07:41 +0900435
Jian Li5e2ad4a2018-07-16 13:40:53 +0900436 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
437 ethPacketIn.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900438 }
439
daniel parkee8700b2017-05-11 15:50:03 +0900440 ethPacketIn.resetChecksum();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900441
Hyunsun Moon0d457362017-06-27 17:19:41 +0900442 OpenstackNode srcNode = osNodeService.node(srcDevice);
443 if (srcNode == null) {
444 final String error = String.format("Cannot find openstack node for %s",
445 srcDevice);
446 throw new IllegalStateException(error);
447 }
daniel parkee8700b2017-05-11 15:50:03 +0900448
daniel park576969a2018-03-09 07:07:41 +0900449 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
450
Hyunsun Moon44aac662017-02-18 02:07:01 +0900451 packetService.emit(new DefaultOutboundPacket(
452 srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900453 tBuilder.setOutput(srcNode.uplinkPortNum()).build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900454 ByteBuffer.wrap(ethPacketIn.serialize())));
455 }
456
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900457 private int getPortNum() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900458 if (unUsedPortNumSet.isEmpty()) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900459 clearPortNumMap();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900460 }
daniel park0bc7fdb2017-03-13 14:20:08 +0900461 int portNum = findUnusedPortNum();
daniel park0bc7fdb2017-03-13 14:20:08 +0900462 if (portNum != 0) {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900463 unUsedPortNumSet.remove(portNum);
464 allocatedPortNumMap.put(portNum, System.currentTimeMillis());
daniel park0bc7fdb2017-03-13 14:20:08 +0900465 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900466 return portNum;
467 }
468
469 private int findUnusedPortNum() {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900470 return unUsedPortNumSet.stream().findAny().orElse(0);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900471 }
472
473 private void clearPortNumMap() {
daniel park0bc7fdb2017-03-13 14:20:08 +0900474 allocatedPortNumMap.entrySet().forEach(e -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900475 if (System.currentTimeMillis() - e.getValue().value() > TIME_OUT_SNAT_PORT_MS) {
daniel park0bc7fdb2017-03-13 14:20:08 +0900476 allocatedPortNumMap.remove(e.getKey());
477 unUsedPortNumSet.add(e.getKey());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900478 }
479 });
480 }
481
482 private class InternalPacketProcessor implements PacketProcessor {
483
484 @Override
485 public void process(PacketContext context) {
Jian Li34220ea2018-11-14 01:30:24 +0900486
Hyunsun Moon44aac662017-02-18 02:07:01 +0900487 if (context.isHandled()) {
488 return;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900489 }
490
491 InboundPacket pkt = context.inPacket();
492 Ethernet eth = pkt.parsed();
493 if (eth == null || eth.getEtherType() == Ethernet.TYPE_ARP) {
494 return;
495 }
496
497 IPv4 iPacket = (IPv4) eth.getPayload();
498 switch (iPacket.getProtocol()) {
499 case IPv4.PROTOCOL_ICMP:
500 break;
501 case IPv4.PROTOCOL_UDP:
502 UDP udpPacket = (UDP) iPacket.getPayload();
503 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
504 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
505 // don't process DHCP
506 break;
507 }
508 default:
Jian Li34220ea2018-11-14 01:30:24 +0900509 eventExecutor.execute(() -> {
510
511 if (!isRelevantHelper(context)) {
512 return;
513 }
514
515 processSnatPacket(context, eth);
516 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517 break;
518 }
519 }
Jian Li34220ea2018-11-14 01:30:24 +0900520
521 private boolean isRelevantHelper(PacketContext context) {
522 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
523 .stream().map(OpenstackNode::intgBridge)
524 .collect(Collectors.toSet());
525
526 return gateways.contains(context.inPacket().receivedFrom().deviceId());
527 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900528 }
529}