blob: 1cc02b75257c3f6c2e28aaee5452a5b62c45e0fc [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
18import com.google.common.base.Strings;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070019import org.osgi.service.component.annotations.Activate;
20import org.osgi.service.component.annotations.Component;
21import org.osgi.service.component.annotations.Deactivate;
22import org.osgi.service.component.annotations.Reference;
23import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090024import org.onlab.packet.Ethernet;
25import org.onlab.packet.ICMP;
Jian Li2fa3ded2018-08-10 02:22:47 +000026import org.onlab.packet.ICMPEcho;
Hyunsun Moon44aac662017-02-18 02:07:01 +090027import org.onlab.packet.IPv4;
28import org.onlab.packet.IpAddress;
29import org.onlab.packet.MacAddress;
daniel park576969a2018-03-09 07:07:41 +090030import org.onlab.packet.VlanId;
sangho247232c2017-08-24 17:22:08 +090031import org.onlab.util.KryoNamespace;
Hyunsun Moon44aac662017-02-18 02:07:01 +090032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090034import org.onosproject.net.DeviceId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090035import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.packet.DefaultOutboundPacket;
38import org.onosproject.net.packet.InboundPacket;
39import org.onosproject.net.packet.OutboundPacket;
40import org.onosproject.net.packet.PacketContext;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.net.packet.PacketProcessor;
42import org.onosproject.net.packet.PacketService;
43import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090044import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090045import org.onosproject.openstacknetworking.api.InstancePort;
46import org.onosproject.openstacknetworking.api.InstancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sangho36721992017-08-03 11:13:17 +090048import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090049import org.onosproject.openstacknode.api.OpenstackNode;
Hyunsun Moon0d457362017-06-27 17:19:41 +090050import org.onosproject.openstacknode.api.OpenstackNodeService;
sangho247232c2017-08-24 17:22:08 +090051import org.onosproject.store.serializers.KryoNamespaces;
52import org.onosproject.store.service.ConsistentMap;
53import org.onosproject.store.service.Serializer;
54import org.onosproject.store.service.StorageService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.openstack4j.model.network.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.openstack4j.model.network.Port;
57import org.openstack4j.model.network.Router;
58import org.openstack4j.model.network.RouterInterface;
59import org.openstack4j.model.network.Subnet;
sangho36721992017-08-03 11:13:17 +090060import org.openstack4j.openstack.networking.domain.NeutronIP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import org.slf4j.Logger;
62
63import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import java.util.Objects;
sangho36721992017-08-03 11:13:17 +090065import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090066import java.util.Set;
67import java.util.concurrent.ExecutorService;
68import java.util.stream.Collectors;
69
sangho247232c2017-08-24 17:22:08 +090070import static com.google.common.base.Preconditions.checkArgument;
Daniel Park4d486842018-07-24 17:06:43 +090071import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072import static java.util.concurrent.Executors.newSingleThreadExecutor;
Daniel Park4d486842018-07-24 17:06:43 +090073import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
74import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075import static org.onlab.util.Tools.groupedThreads;
sangho36721992017-08-03 11:13:17 +090076import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
77import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Hyunsun Moon0d457362017-06-27 17:19:41 +090078import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090079import static org.slf4j.LoggerFactory.getLogger;
80
Hyunsun Moon44aac662017-02-18 02:07:01 +090081/**
82 * Handles ICMP packet received from a gateway node.
83 * For a request for virtual network subnet gateway, it generates fake ICMP reply.
84 * For a request for the external network, it does source NAT with the public IP and
85 * forward the request to the external only if the requested virtual subnet has
86 * external connectivity.
87 */
88@Component(immediate = true)
89public class OpenstackRoutingIcmpHandler {
90
91 protected final Logger log = getLogger(getClass());
92
93 private static final String ERR_REQ = "Failed to handle ICMP request: ";
sangho247232c2017-08-24 17:22:08 +090094 private static final String ERR_DUPLICATE = " already exists";
Hyunsun Moon44aac662017-02-18 02:07:01 +090095
Jian Li28ec77f2018-10-31 07:07:25 +090096 private static final String VXLAN = "VXLAN";
97 private static final String VLAN = "VLAN";
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)
sangho247232c2017-08-24 17:22:08 +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 OpenstackNodeService osNodeService;
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 OpenstackNetworkService osNetworkService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118 protected OpenstackRouterService osRouterService;
119
120 private final ExecutorService eventExecutor = newSingleThreadExecutor(
121 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
sangho072c4dd2017-05-17 10:45:21 +0900122 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
sangho247232c2017-08-24 17:22:08 +0900123 private ConsistentMap<String, InstancePort> icmpInfoMap;
124
125 private static final KryoNamespace SERIALIZER_ICMP_MAP = KryoNamespace.newBuilder()
126 .register(KryoNamespaces.API)
127 .register(InstancePort.class)
Jian Liec5c32b2018-07-13 14:28:58 +0900128 .register(DefaultInstancePort.class)
129 .register(InstancePort.State.class)
sangho247232c2017-08-24 17:22:08 +0900130 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131
132 private ApplicationId appId;
133
134 @Activate
135 protected void activate() {
136 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
137 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138
sangho247232c2017-08-24 17:22:08 +0900139 icmpInfoMap = storageService.<String, InstancePort>consistentMapBuilder()
140 .withSerializer(Serializer.using(SERIALIZER_ICMP_MAP))
141 .withName("openstack-icmpmap")
142 .withApplicationId(appId)
143 .build();
144
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145 log.info("Started");
146 }
147
148 @Deactivate
149 protected void deactivate() {
150 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151 eventExecutor.shutdown();
152
153 log.info("Stopped");
154 }
155
Jian Lid9a24ed2018-08-29 20:53:25 +0900156 private boolean handleEchoRequest(DeviceId srcDevice, MacAddress srcMac, IPv4 ipPacket,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 ICMP icmp) {
158 InstancePort instPort = instancePortService.instancePort(srcMac);
159 if (instPort == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900160 log.warn(ERR_REQ + "unknown source host(MAC:{})", srcMac);
Jian Lid9a24ed2018-08-29 20:53:25 +0900161 return false;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 }
163
164 IpAddress srcIp = IpAddress.valueOf(ipPacket.getSourceAddress());
Daniel Park4d486842018-07-24 17:06:43 +0900165 IpAddress dstIp = IpAddress.valueOf(ipPacket.getDestinationAddress());
166
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167 Subnet srcSubnet = getSourceSubnet(instPort, srcIp);
168 if (srcSubnet == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900169 log.warn(ERR_REQ + "unknown source subnet(IP:{})", srcIp);
Jian Lid9a24ed2018-08-29 20:53:25 +0900170 return false;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171 }
Daniel Park4d486842018-07-24 17:06:43 +0900172
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173 if (Strings.isNullOrEmpty(srcSubnet.getGateway())) {
Daniel Park4d486842018-07-24 17:06:43 +0900174 log.warn(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no gateway",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 srcSubnet.getId(), srcSubnet.getCidr());
Jian Lid9a24ed2018-08-29 20:53:25 +0900176 return false;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 }
178
179 if (isForSubnetGateway(IpAddress.valueOf(ipPacket.getDestinationAddress()),
180 srcSubnet)) {
181 // this is a request for the subnet gateway
Daniel Park4d486842018-07-24 17:06:43 +0900182 log.trace("Icmp request to gateway {} from {}", dstIp, srcIp);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900183 processRequestForGateway(ipPacket, instPort);
184 } else {
Daniel Park4d486842018-07-24 17:06:43 +0900185 // this is a request for the external network
186 log.trace("Icmp request to external {} from {}", dstIp, srcIp);
187
188 RouterInterface routerInterface = routerInterface(srcSubnet);
189 if (routerInterface == null) {
190 log.warn(ERR_REQ + "failed to get router interface");
Jian Lid9a24ed2018-08-29 20:53:25 +0900191 return false;
daniel park859db252018-04-18 16:00:51 +0900192 }
Daniel Park4d486842018-07-24 17:06:43 +0900193
194 ExternalGateway externalGateway = externalGateway(routerInterface);
195 if (externalGateway == null) {
196 log.warn(ERR_REQ + "failed to get external gateway");
Jian Lid9a24ed2018-08-29 20:53:25 +0900197 return false;
Daniel Park4d486842018-07-24 17:06:43 +0900198 }
199
200 ExternalPeerRouter externalPeerRouter = osNetworkService.externalPeerRouter(externalGateway);
201 if (externalPeerRouter == null) {
202 log.warn(ERR_REQ + "failed to get external peer router");
Jian Lid9a24ed2018-08-29 20:53:25 +0900203 return false;
Daniel Park4d486842018-07-24 17:06:43 +0900204 }
205
206 IpAddress externalIp = getExternalIp(externalGateway, routerInterface);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900207 if (externalIp == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900208 log.warn(ERR_REQ + "failed to get external ip");
Jian Lid9a24ed2018-08-29 20:53:25 +0900209 return false;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900210 }
daniel parkeeb8e042018-02-21 14:06:58 +0900211
daniel park576969a2018-03-09 07:07:41 +0900212 sendRequestForExternal(ipPacket, srcDevice, externalIp, externalPeerRouter);
Daniel Park4d486842018-07-24 17:06:43 +0900213
214 String icmpInfoKey = icmpInfoKey(icmp,
215 externalIp.toString(),
216 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()));
217 log.trace("Created icmpInfo key is {}", icmpInfoKey);
218
daniel parkeeb8e042018-02-21 14:06:58 +0900219 try {
220 icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
221 checkArgument(existing == null, ERR_DUPLICATE);
222 return instPort;
223 });
224 } catch (IllegalArgumentException e) {
Daniel Park4d486842018-07-24 17:06:43 +0900225 log.warn("IllegalArgumentException occurred because of {}", e.toString());
Jian Lid9a24ed2018-08-29 20:53:25 +0900226 return false;
daniel parkeeb8e042018-02-21 14:06:58 +0900227 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900228 }
Jian Lid9a24ed2018-08-29 20:53:25 +0900229 return true;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900230 }
231
Daniel Park4d486842018-07-24 17:06:43 +0900232 private String icmpInfoKey(ICMP icmp, String srcIp, String dstIp) {
233 return String.valueOf(getIcmpId(icmp))
234 .concat(srcIp)
235 .concat(dstIp);
236 }
237 private RouterInterface routerInterface(Subnet subnet) {
238 checkNotNull(subnet);
239 return osRouterService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900240 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
241 .findAny().orElse(null);
Daniel Park4d486842018-07-24 17:06:43 +0900242 }
daniel parkeeb8e042018-02-21 14:06:58 +0900243
Daniel Park4d486842018-07-24 17:06:43 +0900244 private ExternalGateway externalGateway(RouterInterface osRouterIface) {
245 checkNotNull(osRouterIface);
daniel parkeeb8e042018-02-21 14:06:58 +0900246 Router osRouter = osRouterService.router(osRouterIface.getId());
247 if (osRouter == null) {
248 return null;
249 }
250 if (osRouter.getExternalGatewayInfo() == null) {
251 return null;
252 }
Daniel Park4d486842018-07-24 17:06:43 +0900253 return osRouter.getExternalGatewayInfo();
daniel parkeeb8e042018-02-21 14:06:58 +0900254 }
255
Jian Lic38e9032018-08-09 17:08:38 +0900256 private boolean handleEchoReply(IPv4 ipPacket, ICMP icmp) {
Daniel Park4d486842018-07-24 17:06:43 +0900257 String icmpInfoKey = icmpInfoKey(icmp,
258 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()),
259 IPv4.fromIPv4Address(ipPacket.getSourceAddress()));
260 log.trace("Retrieved icmpInfo key is {}", icmpInfoKey);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900261
sangho247232c2017-08-24 17:22:08 +0900262 if (icmpInfoMap.get(icmpInfoKey) != null) {
263 processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey).value());
264 icmpInfoMap.remove(icmpInfoKey);
Jian Lic38e9032018-08-09 17:08:38 +0900265 return true;
sangho247232c2017-08-24 17:22:08 +0900266 } else {
Jian Lic38e9032018-08-09 17:08:38 +0900267 log.debug("No ICMP Info for ICMP packet");
268 return false;
sangho247232c2017-08-24 17:22:08 +0900269 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 }
271
272 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
Daniel Park4d486842018-07-24 17:06:43 +0900273 checkNotNull(instance);
274 checkNotNull(srcIp);
275
Hyunsun Moon44aac662017-02-18 02:07:01 +0900276 Port osPort = osNetworkService.port(instance.portId());
Jian Libcc42282018-09-13 20:59:34 +0900277 return osNetworkService.subnets(osPort.getNetworkId())
278 .stream().findAny().orElse(null);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900279 }
280
281 private boolean isForSubnetGateway(IpAddress dstIp, Subnet srcSubnet) {
282 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
283 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
284 .findAny().orElse(null);
285 if (osRouterIface == null) {
286 log.trace(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no router",
287 srcSubnet.getId(), srcSubnet.getCidr());
288 return false;
289 }
290
291 Router osRouter = osRouterService.router(osRouterIface.getId());
292 Set<IpAddress> routableGateways = osRouterService.routerInterfaces(osRouter.getId())
293 .stream()
294 .map(iface -> osNetworkService.subnet(iface.getSubnetId()).getGateway())
295 .map(IpAddress::valueOf)
296 .collect(Collectors.toSet());
297
298 return routableGateways.contains(dstIp);
299 }
300
Daniel Park4d486842018-07-24 17:06:43 +0900301 private IpAddress getExternalIp(ExternalGateway externalGateway, RouterInterface osRouterIface) {
302 checkNotNull(externalGateway);
303 checkNotNull(osRouterIface);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900304
305 Router osRouter = osRouterService.router(osRouterIface.getId());
Daniel Park4d486842018-07-24 17:06:43 +0900306 if (osRouter == null) {
307 return null;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900308 }
309
Daniel Park4d486842018-07-24 17:06:43 +0900310 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311 .stream()
312 .filter(port -> Objects.equals(port.getDeviceId(), osRouter.getId()))
313 .findAny().orElse(null);
314 if (exGatewayPort == null) {
315 final String error = String.format(ERR_REQ +
Daniel Park4d486842018-07-24 17:06:43 +0900316 "no external gateway port for router (ID:%s, name:%s)",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900317 osRouter.getId(), osRouter.getName());
318 throw new IllegalStateException(error);
319 }
sangho36721992017-08-03 11:13:17 +0900320 Optional<NeutronIP> externalIpAddress = (Optional<NeutronIP>) exGatewayPort.getFixedIps().stream().findFirst();
321 if (!externalIpAddress.isPresent() || externalIpAddress.get().getIpAddress() == null) {
322 final String error = String.format(ERR_REQ +
323 "no external gateway IP address for router (ID:%s, name:%s)",
324 osRouter.getId(), osRouter.getName());
Daniel Park4d486842018-07-24 17:06:43 +0900325 log.warn(error);
326 return null;
sangho36721992017-08-03 11:13:17 +0900327 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900328
sangho36721992017-08-03 11:13:17 +0900329 return IpAddress.valueOf(externalIpAddress.get().getIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900330 }
331
332 private void processRequestForGateway(IPv4 ipPacket, InstancePort instPort) {
333 ICMP icmpReq = (ICMP) ipPacket.getPayload();
334 icmpReq.setChecksum((short) 0);
Daniel Park4d486842018-07-24 17:06:43 +0900335 icmpReq.setIcmpType(TYPE_ECHO_REPLY);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900336
337 int destinationAddress = ipPacket.getSourceAddress();
338
339 ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
340 .setDestinationAddress(destinationAddress)
341 .resetChecksum();
342
343 ipPacket.setPayload(icmpReq);
344 Ethernet icmpReply = new Ethernet();
345 icmpReply.setEtherType(Ethernet.TYPE_IPV4)
346 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
347 .setDestinationMACAddress(instPort.macAddress())
348 .setPayload(ipPacket);
349
350 sendReply(icmpReply, instPort);
351 }
352
daniel parkeeb8e042018-02-21 14:06:58 +0900353 private void sendRequestForExternal(IPv4 ipPacket, DeviceId srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900354 IpAddress srcNatIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900355 ICMP icmpReq = (ICMP) ipPacket.getPayload();
356 icmpReq.resetChecksum();
357 ipPacket.setSourceAddress(srcNatIp.getIp4Address().toInt()).resetChecksum();
358 ipPacket.setPayload(icmpReq);
359
360 Ethernet icmpRequestEth = new Ethernet();
361 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
362 .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
Jian Li5e2ad4a2018-07-16 13:40:53 +0900363 .setDestinationMACAddress(externalPeerRouter.macAddress());
daniel park576969a2018-03-09 07:07:41 +0900364
Jian Li5e2ad4a2018-07-16 13:40:53 +0900365 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
366 icmpRequestEth.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900367 }
368
369 icmpRequestEth.setPayload(ipPacket);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900370
Hyunsun Moon0d457362017-06-27 17:19:41 +0900371 OpenstackNode osNode = osNodeService.node(srcDevice);
372 if (osNode == null) {
373 final String error = String.format("Cannot find openstack node for %s",
374 srcDevice);
375 throw new IllegalStateException(error);
376 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900377 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel parkeeb8e042018-02-21 14:06:58 +0900378 .setOutput(osNode.uplinkPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900379 .build();
380
381 OutboundPacket packet = new DefaultOutboundPacket(
382 srcDevice,
383 treatment,
384 ByteBuffer.wrap(icmpRequestEth.serialize()));
385
386 packetService.emit(packet);
387 }
388
389 private void processReplyFromExternal(IPv4 ipPacket, InstancePort instPort) {
daniel park576969a2018-03-09 07:07:41 +0900390
391 if (instPort.networkId() == null) {
392 return;
393 }
394
Hyunsun Moon44aac662017-02-18 02:07:01 +0900395 ICMP icmpReply = (ICMP) ipPacket.getPayload();
daniel park576969a2018-03-09 07:07:41 +0900396
Hyunsun Moon44aac662017-02-18 02:07:01 +0900397 icmpReply.resetChecksum();
398
399 ipPacket.setDestinationAddress(instPort.ipAddress().getIp4Address().toInt())
400 .resetChecksum();
401 ipPacket.setPayload(icmpReply);
402
403 Ethernet icmpResponseEth = new Ethernet();
404 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
405 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
406 .setDestinationMACAddress(instPort.macAddress())
407 .setPayload(ipPacket);
408
409 sendReply(icmpResponseEth, instPort);
410 }
411
412 private void sendReply(Ethernet icmpReply, InstancePort instPort) {
Jian Li28ec77f2018-10-31 07:07:25 +0900413 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
414 .setOutput(instPort.portNumber());
415
416 String netId = instPort.networkId();
417 String segId = osNetworkService.segmentId(netId);
418
419 switch (osNetworkService.networkType(netId)) {
420 case VXLAN:
421 tBuilder.setTunnelId(Long.valueOf(segId));
422 break;
423 case VLAN:
424 tBuilder.setVlanId(VlanId.vlanId(segId));
425 break;
426 default:
427 break;
428 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900429
430 OutboundPacket packet = new DefaultOutboundPacket(
431 instPort.deviceId(),
Jian Li28ec77f2018-10-31 07:07:25 +0900432 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900433 ByteBuffer.wrap(icmpReply.serialize()));
434
435 packetService.emit(packet);
436 }
437
438 private short getIcmpId(ICMP icmp) {
Jian Li2fa3ded2018-08-10 02:22:47 +0000439 return ((ICMPEcho) icmp.getPayload()).getIdentifier();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900440 }
441
442 private class InternalPacketProcessor implements PacketProcessor {
443
444 @Override
445 public void process(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900446 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
447 .stream().map(OpenstackNode::intgBridge)
448 .collect(Collectors.toSet());
449
Hyunsun Moon44aac662017-02-18 02:07:01 +0900450 if (context.isHandled()) {
451 return;
Daniel Park4d486842018-07-24 17:06:43 +0900452 }
453
Jian Li28ec77f2018-10-31 07:07:25 +0900454 if (!gateways.isEmpty() &&
455 !gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900456 return;
457 }
458
459 InboundPacket pkt = context.inPacket();
460 Ethernet ethernet = pkt.parsed();
Jian Lid9a24ed2018-08-29 20:53:25 +0900461 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900462 return;
463 }
464
465 IPv4 iPacket = (IPv4) ethernet.getPayload();
466 if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
467 eventExecutor.execute(() -> processIcmpPacket(context, ethernet));
468 }
469 }
Daniel Park4d486842018-07-24 17:06:43 +0900470
471 private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
472 IPv4 ipPacket = (IPv4) ethernet.getPayload();
473 ICMP icmp = (ICMP) ipPacket.getPayload();
474 log.trace("Processing ICMP packet source MAC:{}, source IP:{}," +
475 "dest MAC:{}, dest IP:{}",
476 ethernet.getSourceMAC(),
477 IpAddress.valueOf(ipPacket.getSourceAddress()),
478 ethernet.getDestinationMAC(),
479 IpAddress.valueOf(ipPacket.getDestinationAddress()));
480
481 switch (icmp.getIcmpType()) {
482 case TYPE_ECHO_REQUEST:
Jian Lid9a24ed2018-08-29 20:53:25 +0900483 if (handleEchoRequest(context.inPacket().receivedFrom().deviceId(),
Daniel Park4d486842018-07-24 17:06:43 +0900484 ethernet.getSourceMAC(),
485 ipPacket,
Jian Lid9a24ed2018-08-29 20:53:25 +0900486 icmp)) {
487 context.block();
488 }
Daniel Park4d486842018-07-24 17:06:43 +0900489 break;
490 case TYPE_ECHO_REPLY:
Jian Lic38e9032018-08-09 17:08:38 +0900491 if (handleEchoReply(ipPacket, icmp)) {
492 context.block();
493 }
Daniel Park4d486842018-07-24 17:06:43 +0900494 break;
495 default:
496 break;
497 }
498 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900500}