blob: 17d9922ecd60f0a3c66c3cc90ca7af8910265751 [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;
Hyunsun Moon44aac662017-02-18 02:07:01 +090019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import 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;
56import org.openstack4j.model.network.IP;
57import org.openstack4j.model.network.Port;
58import org.openstack4j.model.network.Router;
59import org.openstack4j.model.network.RouterInterface;
60import org.openstack4j.model.network.Subnet;
sangho36721992017-08-03 11:13:17 +090061import org.openstack4j.openstack.networking.domain.NeutronIP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090062import org.slf4j.Logger;
63
64import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090065import java.util.Objects;
sangho36721992017-08-03 11:13:17 +090066import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090067import java.util.Set;
68import java.util.concurrent.ExecutorService;
69import java.util.stream.Collectors;
70
sangho247232c2017-08-24 17:22:08 +090071import static com.google.common.base.Preconditions.checkArgument;
Daniel Park4d486842018-07-24 17:06:43 +090072import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import static java.util.concurrent.Executors.newSingleThreadExecutor;
Daniel Park4d486842018-07-24 17:06:43 +090074import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
75import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
Hyunsun Moon44aac662017-02-18 02:07:01 +090076import static org.onlab.util.Tools.groupedThreads;
sangho36721992017-08-03 11:13:17 +090077import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
78import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
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
Hyunsun Moon44aac662017-02-18 02:07:01 +090082/**
83 * Handles ICMP packet received from a gateway node.
84 * For a request for virtual network subnet gateway, it generates fake ICMP reply.
85 * For a request for the external network, it does source NAT with the public IP and
86 * forward the request to the external only if the requested virtual subnet has
87 * external connectivity.
88 */
89@Component(immediate = true)
90public class OpenstackRoutingIcmpHandler {
91
92 protected final Logger log = getLogger(getClass());
93
94 private static final String ERR_REQ = "Failed to handle ICMP request: ";
sangho247232c2017-08-24 17:22:08 +090095 private static final String ERR_DUPLICATE = " already exists";
Hyunsun Moon44aac662017-02-18 02:07:01 +090096
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected CoreService coreService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected PacketService packetService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho247232c2017-08-24 17:22:08 +0900104 protected StorageService storageService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900107 protected OpenstackNodeService osNodeService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected InstancePortService instancePortService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected OpenstackNetworkService osNetworkService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected OpenstackRouterService osRouterService;
117
118 private final ExecutorService eventExecutor = newSingleThreadExecutor(
119 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
sangho072c4dd2017-05-17 10:45:21 +0900120 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
sangho247232c2017-08-24 17:22:08 +0900121 private ConsistentMap<String, InstancePort> icmpInfoMap;
122
123 private static final KryoNamespace SERIALIZER_ICMP_MAP = KryoNamespace.newBuilder()
124 .register(KryoNamespaces.API)
125 .register(InstancePort.class)
Jian Liec5c32b2018-07-13 14:28:58 +0900126 .register(DefaultInstancePort.class)
127 .register(InstancePort.State.class)
sangho247232c2017-08-24 17:22:08 +0900128 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129
130 private ApplicationId appId;
131
132 @Activate
133 protected void activate() {
134 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
135 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136
sangho247232c2017-08-24 17:22:08 +0900137 icmpInfoMap = storageService.<String, InstancePort>consistentMapBuilder()
138 .withSerializer(Serializer.using(SERIALIZER_ICMP_MAP))
139 .withName("openstack-icmpmap")
140 .withApplicationId(appId)
141 .build();
142
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 log.info("Started");
144 }
145
146 @Deactivate
147 protected void deactivate() {
148 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149 eventExecutor.shutdown();
150
151 log.info("Stopped");
152 }
153
Jian Lid9a24ed2018-08-29 20:53:25 +0900154 private boolean handleEchoRequest(DeviceId srcDevice, MacAddress srcMac, IPv4 ipPacket,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900155 ICMP icmp) {
156 InstancePort instPort = instancePortService.instancePort(srcMac);
157 if (instPort == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900158 log.warn(ERR_REQ + "unknown source host(MAC:{})", srcMac);
Jian Lid9a24ed2018-08-29 20:53:25 +0900159 return false;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160 }
161
162 IpAddress srcIp = IpAddress.valueOf(ipPacket.getSourceAddress());
Daniel Park4d486842018-07-24 17:06:43 +0900163 IpAddress dstIp = IpAddress.valueOf(ipPacket.getDestinationAddress());
164
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165 Subnet srcSubnet = getSourceSubnet(instPort, srcIp);
166 if (srcSubnet == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900167 log.warn(ERR_REQ + "unknown source subnet(IP:{})", srcIp);
Jian Lid9a24ed2018-08-29 20:53:25 +0900168 return false;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 }
Daniel Park4d486842018-07-24 17:06:43 +0900170
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171 if (Strings.isNullOrEmpty(srcSubnet.getGateway())) {
Daniel Park4d486842018-07-24 17:06:43 +0900172 log.warn(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no gateway",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173 srcSubnet.getId(), srcSubnet.getCidr());
Jian Lid9a24ed2018-08-29 20:53:25 +0900174 return false;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 }
176
177 if (isForSubnetGateway(IpAddress.valueOf(ipPacket.getDestinationAddress()),
178 srcSubnet)) {
179 // this is a request for the subnet gateway
Daniel Park4d486842018-07-24 17:06:43 +0900180 log.trace("Icmp request to gateway {} from {}", dstIp, srcIp);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 processRequestForGateway(ipPacket, instPort);
182 } else {
Daniel Park4d486842018-07-24 17:06:43 +0900183 // this is a request for the external network
184 log.trace("Icmp request to external {} from {}", dstIp, srcIp);
185
186 RouterInterface routerInterface = routerInterface(srcSubnet);
187 if (routerInterface == null) {
188 log.warn(ERR_REQ + "failed to get router interface");
Jian Lid9a24ed2018-08-29 20:53:25 +0900189 return false;
daniel park859db252018-04-18 16:00:51 +0900190 }
Daniel Park4d486842018-07-24 17:06:43 +0900191
192 ExternalGateway externalGateway = externalGateway(routerInterface);
193 if (externalGateway == null) {
194 log.warn(ERR_REQ + "failed to get external gateway");
Jian Lid9a24ed2018-08-29 20:53:25 +0900195 return false;
Daniel Park4d486842018-07-24 17:06:43 +0900196 }
197
198 ExternalPeerRouter externalPeerRouter = osNetworkService.externalPeerRouter(externalGateway);
199 if (externalPeerRouter == null) {
200 log.warn(ERR_REQ + "failed to get external peer router");
Jian Lid9a24ed2018-08-29 20:53:25 +0900201 return false;
Daniel Park4d486842018-07-24 17:06:43 +0900202 }
203
204 IpAddress externalIp = getExternalIp(externalGateway, routerInterface);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900205 if (externalIp == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900206 log.warn(ERR_REQ + "failed to get external ip");
Jian Lid9a24ed2018-08-29 20:53:25 +0900207 return false;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900208 }
daniel parkeeb8e042018-02-21 14:06:58 +0900209
daniel park576969a2018-03-09 07:07:41 +0900210 sendRequestForExternal(ipPacket, srcDevice, externalIp, externalPeerRouter);
Daniel Park4d486842018-07-24 17:06:43 +0900211
212 String icmpInfoKey = icmpInfoKey(icmp,
213 externalIp.toString(),
214 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()));
215 log.trace("Created icmpInfo key is {}", icmpInfoKey);
216
daniel parkeeb8e042018-02-21 14:06:58 +0900217 try {
218 icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
219 checkArgument(existing == null, ERR_DUPLICATE);
220 return instPort;
221 });
222 } catch (IllegalArgumentException e) {
Daniel Park4d486842018-07-24 17:06:43 +0900223 log.warn("IllegalArgumentException occurred because of {}", e.toString());
Jian Lid9a24ed2018-08-29 20:53:25 +0900224 return false;
daniel parkeeb8e042018-02-21 14:06:58 +0900225 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 }
Jian Lid9a24ed2018-08-29 20:53:25 +0900227 return true;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900228 }
229
Daniel Park4d486842018-07-24 17:06:43 +0900230 private String icmpInfoKey(ICMP icmp, String srcIp, String dstIp) {
231 return String.valueOf(getIcmpId(icmp))
232 .concat(srcIp)
233 .concat(dstIp);
234 }
235 private RouterInterface routerInterface(Subnet subnet) {
236 checkNotNull(subnet);
237 return osRouterService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900238 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
239 .findAny().orElse(null);
Daniel Park4d486842018-07-24 17:06:43 +0900240 }
daniel parkeeb8e042018-02-21 14:06:58 +0900241
Daniel Park4d486842018-07-24 17:06:43 +0900242 private ExternalGateway externalGateway(RouterInterface osRouterIface) {
243 checkNotNull(osRouterIface);
daniel parkeeb8e042018-02-21 14:06:58 +0900244 Router osRouter = osRouterService.router(osRouterIface.getId());
245 if (osRouter == null) {
246 return null;
247 }
248 if (osRouter.getExternalGatewayInfo() == null) {
249 return null;
250 }
Daniel Park4d486842018-07-24 17:06:43 +0900251 return osRouter.getExternalGatewayInfo();
daniel parkeeb8e042018-02-21 14:06:58 +0900252 }
253
Jian Lic38e9032018-08-09 17:08:38 +0900254 private boolean handleEchoReply(IPv4 ipPacket, ICMP icmp) {
Daniel Park4d486842018-07-24 17:06:43 +0900255 String icmpInfoKey = icmpInfoKey(icmp,
256 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()),
257 IPv4.fromIPv4Address(ipPacket.getSourceAddress()));
258 log.trace("Retrieved icmpInfo key is {}", icmpInfoKey);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900259
sangho247232c2017-08-24 17:22:08 +0900260 if (icmpInfoMap.get(icmpInfoKey) != null) {
261 processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey).value());
262 icmpInfoMap.remove(icmpInfoKey);
Jian Lic38e9032018-08-09 17:08:38 +0900263 return true;
sangho247232c2017-08-24 17:22:08 +0900264 } else {
Jian Lic38e9032018-08-09 17:08:38 +0900265 log.debug("No ICMP Info for ICMP packet");
266 return false;
sangho247232c2017-08-24 17:22:08 +0900267 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900268 }
269
270 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
Daniel Park4d486842018-07-24 17:06:43 +0900271 checkNotNull(instance);
272 checkNotNull(srcIp);
273
Hyunsun Moon44aac662017-02-18 02:07:01 +0900274 Port osPort = osNetworkService.port(instance.portId());
275 IP fixedIp = osPort.getFixedIps().stream()
276 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
277 .findAny().orElse(null);
Daniel Park4d486842018-07-24 17:06:43 +0900278 checkNotNull(fixedIp);
279
Hyunsun Moon44aac662017-02-18 02:07:01 +0900280 return osNetworkService.subnet(fixedIp.getSubnetId());
281 }
282
283 private boolean isForSubnetGateway(IpAddress dstIp, Subnet srcSubnet) {
284 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
285 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
286 .findAny().orElse(null);
287 if (osRouterIface == null) {
288 log.trace(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no router",
289 srcSubnet.getId(), srcSubnet.getCidr());
290 return false;
291 }
292
293 Router osRouter = osRouterService.router(osRouterIface.getId());
294 Set<IpAddress> routableGateways = osRouterService.routerInterfaces(osRouter.getId())
295 .stream()
296 .map(iface -> osNetworkService.subnet(iface.getSubnetId()).getGateway())
297 .map(IpAddress::valueOf)
298 .collect(Collectors.toSet());
299
300 return routableGateways.contains(dstIp);
301 }
302
Daniel Park4d486842018-07-24 17:06:43 +0900303 private IpAddress getExternalIp(ExternalGateway externalGateway, RouterInterface osRouterIface) {
304 checkNotNull(externalGateway);
305 checkNotNull(osRouterIface);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900306
307 Router osRouter = osRouterService.router(osRouterIface.getId());
Daniel Park4d486842018-07-24 17:06:43 +0900308 if (osRouter == null) {
309 return null;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900310 }
311
Daniel Park4d486842018-07-24 17:06:43 +0900312 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900313 .stream()
314 .filter(port -> Objects.equals(port.getDeviceId(), osRouter.getId()))
315 .findAny().orElse(null);
316 if (exGatewayPort == null) {
317 final String error = String.format(ERR_REQ +
Daniel Park4d486842018-07-24 17:06:43 +0900318 "no external gateway port for router (ID:%s, name:%s)",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900319 osRouter.getId(), osRouter.getName());
320 throw new IllegalStateException(error);
321 }
sangho36721992017-08-03 11:13:17 +0900322 Optional<NeutronIP> externalIpAddress = (Optional<NeutronIP>) exGatewayPort.getFixedIps().stream().findFirst();
323 if (!externalIpAddress.isPresent() || externalIpAddress.get().getIpAddress() == null) {
324 final String error = String.format(ERR_REQ +
325 "no external gateway IP address for router (ID:%s, name:%s)",
326 osRouter.getId(), osRouter.getName());
Daniel Park4d486842018-07-24 17:06:43 +0900327 log.warn(error);
328 return null;
sangho36721992017-08-03 11:13:17 +0900329 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900330
sangho36721992017-08-03 11:13:17 +0900331 return IpAddress.valueOf(externalIpAddress.get().getIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900332 }
333
334 private void processRequestForGateway(IPv4 ipPacket, InstancePort instPort) {
335 ICMP icmpReq = (ICMP) ipPacket.getPayload();
336 icmpReq.setChecksum((short) 0);
Daniel Park4d486842018-07-24 17:06:43 +0900337 icmpReq.setIcmpType(TYPE_ECHO_REPLY);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900338
339 int destinationAddress = ipPacket.getSourceAddress();
340
341 ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
342 .setDestinationAddress(destinationAddress)
343 .resetChecksum();
344
345 ipPacket.setPayload(icmpReq);
346 Ethernet icmpReply = new Ethernet();
347 icmpReply.setEtherType(Ethernet.TYPE_IPV4)
348 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
349 .setDestinationMACAddress(instPort.macAddress())
350 .setPayload(ipPacket);
351
352 sendReply(icmpReply, instPort);
353 }
354
daniel parkeeb8e042018-02-21 14:06:58 +0900355 private void sendRequestForExternal(IPv4 ipPacket, DeviceId srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900356 IpAddress srcNatIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900357 ICMP icmpReq = (ICMP) ipPacket.getPayload();
358 icmpReq.resetChecksum();
359 ipPacket.setSourceAddress(srcNatIp.getIp4Address().toInt()).resetChecksum();
360 ipPacket.setPayload(icmpReq);
361
362 Ethernet icmpRequestEth = new Ethernet();
363 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
364 .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
Jian Li5e2ad4a2018-07-16 13:40:53 +0900365 .setDestinationMACAddress(externalPeerRouter.macAddress());
daniel park576969a2018-03-09 07:07:41 +0900366
Jian Li5e2ad4a2018-07-16 13:40:53 +0900367 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
368 icmpRequestEth.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900369 }
370
371 icmpRequestEth.setPayload(ipPacket);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900372
Hyunsun Moon0d457362017-06-27 17:19:41 +0900373 OpenstackNode osNode = osNodeService.node(srcDevice);
374 if (osNode == null) {
375 final String error = String.format("Cannot find openstack node for %s",
376 srcDevice);
377 throw new IllegalStateException(error);
378 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900379 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel parkeeb8e042018-02-21 14:06:58 +0900380 .setOutput(osNode.uplinkPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900381 .build();
382
383 OutboundPacket packet = new DefaultOutboundPacket(
384 srcDevice,
385 treatment,
386 ByteBuffer.wrap(icmpRequestEth.serialize()));
387
388 packetService.emit(packet);
389 }
390
391 private void processReplyFromExternal(IPv4 ipPacket, InstancePort instPort) {
daniel park576969a2018-03-09 07:07:41 +0900392
393 if (instPort.networkId() == null) {
394 return;
395 }
396
Hyunsun Moon44aac662017-02-18 02:07:01 +0900397 ICMP icmpReply = (ICMP) ipPacket.getPayload();
daniel park576969a2018-03-09 07:07:41 +0900398
Hyunsun Moon44aac662017-02-18 02:07:01 +0900399 icmpReply.resetChecksum();
400
401 ipPacket.setDestinationAddress(instPort.ipAddress().getIp4Address().toInt())
402 .resetChecksum();
403 ipPacket.setPayload(icmpReply);
404
405 Ethernet icmpResponseEth = new Ethernet();
406 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
407 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
408 .setDestinationMACAddress(instPort.macAddress())
409 .setPayload(ipPacket);
410
411 sendReply(icmpResponseEth, instPort);
412 }
413
414 private void sendReply(Ethernet icmpReply, InstancePort instPort) {
415 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
416 .setOutput(instPort.portNumber())
417 .build();
418
419 OutboundPacket packet = new DefaultOutboundPacket(
420 instPort.deviceId(),
421 treatment,
422 ByteBuffer.wrap(icmpReply.serialize()));
423
424 packetService.emit(packet);
425 }
426
427 private short getIcmpId(ICMP icmp) {
Jian Li2fa3ded2018-08-10 02:22:47 +0000428 return ((ICMPEcho) icmp.getPayload()).getIdentifier();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900429 }
430
431 private class InternalPacketProcessor implements PacketProcessor {
432
433 @Override
434 public void process(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900435 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
436 .stream().map(OpenstackNode::intgBridge)
437 .collect(Collectors.toSet());
438
Hyunsun Moon44aac662017-02-18 02:07:01 +0900439 if (context.isHandled()) {
440 return;
Daniel Park4d486842018-07-24 17:06:43 +0900441 }
442
443 if (!gateways.isEmpty() && !gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900444 return;
445 }
446
447 InboundPacket pkt = context.inPacket();
448 Ethernet ethernet = pkt.parsed();
Jian Lid9a24ed2018-08-29 20:53:25 +0900449 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900450 return;
451 }
452
453 IPv4 iPacket = (IPv4) ethernet.getPayload();
454 if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
455 eventExecutor.execute(() -> processIcmpPacket(context, ethernet));
456 }
457 }
Daniel Park4d486842018-07-24 17:06:43 +0900458
459 private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
460 IPv4 ipPacket = (IPv4) ethernet.getPayload();
461 ICMP icmp = (ICMP) ipPacket.getPayload();
462 log.trace("Processing ICMP packet source MAC:{}, source IP:{}," +
463 "dest MAC:{}, dest IP:{}",
464 ethernet.getSourceMAC(),
465 IpAddress.valueOf(ipPacket.getSourceAddress()),
466 ethernet.getDestinationMAC(),
467 IpAddress.valueOf(ipPacket.getDestinationAddress()));
468
469 switch (icmp.getIcmpType()) {
470 case TYPE_ECHO_REQUEST:
Jian Lid9a24ed2018-08-29 20:53:25 +0900471 if (handleEchoRequest(context.inPacket().receivedFrom().deviceId(),
Daniel Park4d486842018-07-24 17:06:43 +0900472 ethernet.getSourceMAC(),
473 ipPacket,
Jian Lid9a24ed2018-08-29 20:53:25 +0900474 icmp)) {
475 context.block();
476 }
Daniel Park4d486842018-07-24 17:06:43 +0900477 break;
478 case TYPE_ECHO_REPLY:
Jian Lic38e9032018-08-09 17:08:38 +0900479 if (handleEchoReply(ipPacket, icmp)) {
480 context.block();
481 }
Daniel Park4d486842018-07-24 17:06:43 +0900482 break;
483 default:
484 break;
485 }
486 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900487 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900488}