blob: 67cedccc76fd234a56a41a0d0a609502ed1e52ba [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;
26import org.onlab.packet.IPv4;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.MacAddress;
daniel park576969a2018-03-09 07:07:41 +090029import org.onlab.packet.VlanId;
sangho247232c2017-08-24 17:22:08 +090030import org.onlab.util.KryoNamespace;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090033import org.onosproject.net.DeviceId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090034import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090035import org.onosproject.net.flow.TrafficTreatment;
36import org.onosproject.net.packet.DefaultOutboundPacket;
37import org.onosproject.net.packet.InboundPacket;
38import org.onosproject.net.packet.OutboundPacket;
39import org.onosproject.net.packet.PacketContext;
Hyunsun Moon44aac662017-02-18 02:07:01 +090040import org.onosproject.net.packet.PacketProcessor;
41import org.onosproject.net.packet.PacketService;
42import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090043import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.InstancePort;
45import org.onosproject.openstacknetworking.api.InstancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090046import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sangho36721992017-08-03 11:13:17 +090047import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090048import org.onosproject.openstacknode.api.OpenstackNode;
Hyunsun Moon0d457362017-06-27 17:19:41 +090049import org.onosproject.openstacknode.api.OpenstackNodeService;
sangho247232c2017-08-24 17:22:08 +090050import org.onosproject.store.serializers.KryoNamespaces;
51import org.onosproject.store.service.ConsistentMap;
52import org.onosproject.store.service.Serializer;
53import org.onosproject.store.service.StorageService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090054import org.openstack4j.model.network.ExternalGateway;
55import org.openstack4j.model.network.IP;
56import 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
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected CoreService coreService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected PacketService packetService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho247232c2017-08-24 17:22:08 +0900103 protected StorageService storageService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106 protected OpenstackNodeService osNodeService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected InstancePortService instancePortService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected OpenstackNetworkService osNetworkService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected OpenstackRouterService osRouterService;
116
117 private final ExecutorService eventExecutor = newSingleThreadExecutor(
118 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
sangho072c4dd2017-05-17 10:45:21 +0900119 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
sangho247232c2017-08-24 17:22:08 +0900120 private ConsistentMap<String, InstancePort> icmpInfoMap;
121
122 private static final KryoNamespace SERIALIZER_ICMP_MAP = KryoNamespace.newBuilder()
123 .register(KryoNamespaces.API)
124 .register(InstancePort.class)
Jian Liec5c32b2018-07-13 14:28:58 +0900125 .register(DefaultInstancePort.class)
126 .register(InstancePort.State.class)
sangho247232c2017-08-24 17:22:08 +0900127 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
129 private ApplicationId appId;
130
131 @Activate
132 protected void activate() {
133 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
134 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135
sangho247232c2017-08-24 17:22:08 +0900136 icmpInfoMap = storageService.<String, InstancePort>consistentMapBuilder()
137 .withSerializer(Serializer.using(SERIALIZER_ICMP_MAP))
138 .withName("openstack-icmpmap")
139 .withApplicationId(appId)
140 .build();
141
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 log.info("Started");
143 }
144
145 @Deactivate
146 protected void deactivate() {
147 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 eventExecutor.shutdown();
149
150 log.info("Stopped");
151 }
152
Hyunsun Moon44aac662017-02-18 02:07:01 +0900153 private void handleEchoRequest(DeviceId srcDevice, MacAddress srcMac, IPv4 ipPacket,
154 ICMP icmp) {
155 InstancePort instPort = instancePortService.instancePort(srcMac);
156 if (instPort == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900157 log.warn(ERR_REQ + "unknown source host(MAC:{})", srcMac);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158 return;
159 }
160
161 IpAddress srcIp = IpAddress.valueOf(ipPacket.getSourceAddress());
Daniel Park4d486842018-07-24 17:06:43 +0900162 IpAddress dstIp = IpAddress.valueOf(ipPacket.getDestinationAddress());
163
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164 Subnet srcSubnet = getSourceSubnet(instPort, srcIp);
165 if (srcSubnet == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900166 log.warn(ERR_REQ + "unknown source subnet(IP:{})", srcIp);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167 return;
168 }
Daniel Park4d486842018-07-24 17:06:43 +0900169
Hyunsun Moon44aac662017-02-18 02:07:01 +0900170 if (Strings.isNullOrEmpty(srcSubnet.getGateway())) {
Daniel Park4d486842018-07-24 17:06:43 +0900171 log.warn(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no gateway",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172 srcSubnet.getId(), srcSubnet.getCidr());
173 return;
174 }
175
176 if (isForSubnetGateway(IpAddress.valueOf(ipPacket.getDestinationAddress()),
177 srcSubnet)) {
178 // this is a request for the subnet gateway
Daniel Park4d486842018-07-24 17:06:43 +0900179 log.trace("Icmp request to gateway {} from {}", dstIp, srcIp);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900180 processRequestForGateway(ipPacket, instPort);
181 } else {
Daniel Park4d486842018-07-24 17:06:43 +0900182 // this is a request for the external network
183 log.trace("Icmp request to external {} from {}", dstIp, srcIp);
184
185 RouterInterface routerInterface = routerInterface(srcSubnet);
186 if (routerInterface == null) {
187 log.warn(ERR_REQ + "failed to get router interface");
daniel park859db252018-04-18 16:00:51 +0900188 return;
189 }
Daniel Park4d486842018-07-24 17:06:43 +0900190
191 ExternalGateway externalGateway = externalGateway(routerInterface);
192 if (externalGateway == null) {
193 log.warn(ERR_REQ + "failed to get external gateway");
194 return;
195 }
196
197 ExternalPeerRouter externalPeerRouter = osNetworkService.externalPeerRouter(externalGateway);
198 if (externalPeerRouter == null) {
199 log.warn(ERR_REQ + "failed to get external peer router");
200 return;
201 }
202
203 IpAddress externalIp = getExternalIp(externalGateway, routerInterface);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900204 if (externalIp == null) {
Daniel Park4d486842018-07-24 17:06:43 +0900205 log.warn(ERR_REQ + "failed to get external ip");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900206 return;
207 }
daniel parkeeb8e042018-02-21 14:06:58 +0900208
daniel park576969a2018-03-09 07:07:41 +0900209 sendRequestForExternal(ipPacket, srcDevice, externalIp, externalPeerRouter);
Daniel Park4d486842018-07-24 17:06:43 +0900210
211 String icmpInfoKey = icmpInfoKey(icmp,
212 externalIp.toString(),
213 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()));
214 log.trace("Created icmpInfo key is {}", icmpInfoKey);
215
daniel parkeeb8e042018-02-21 14:06:58 +0900216 try {
217 icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
218 checkArgument(existing == null, ERR_DUPLICATE);
219 return instPort;
220 });
221 } catch (IllegalArgumentException e) {
Daniel Park4d486842018-07-24 17:06:43 +0900222 log.warn("IllegalArgumentException occurred because of {}", e.toString());
223 return;
daniel parkeeb8e042018-02-21 14:06:58 +0900224 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900225 }
226 }
227
Daniel Park4d486842018-07-24 17:06:43 +0900228 private String icmpInfoKey(ICMP icmp, String srcIp, String dstIp) {
229 return String.valueOf(getIcmpId(icmp))
230 .concat(srcIp)
231 .concat(dstIp);
232 }
233 private RouterInterface routerInterface(Subnet subnet) {
234 checkNotNull(subnet);
235 return osRouterService.routerInterfaces().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900236 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
237 .findAny().orElse(null);
Daniel Park4d486842018-07-24 17:06:43 +0900238 }
daniel parkeeb8e042018-02-21 14:06:58 +0900239
Daniel Park4d486842018-07-24 17:06:43 +0900240 private ExternalGateway externalGateway(RouterInterface osRouterIface) {
241 checkNotNull(osRouterIface);
daniel parkeeb8e042018-02-21 14:06:58 +0900242 Router osRouter = osRouterService.router(osRouterIface.getId());
243 if (osRouter == null) {
244 return null;
245 }
246 if (osRouter.getExternalGatewayInfo() == null) {
247 return null;
248 }
Daniel Park4d486842018-07-24 17:06:43 +0900249 return osRouter.getExternalGatewayInfo();
daniel parkeeb8e042018-02-21 14:06:58 +0900250 }
251
Hyunsun Moon44aac662017-02-18 02:07:01 +0900252 private void handleEchoReply(IPv4 ipPacket, ICMP icmp) {
Daniel Park4d486842018-07-24 17:06:43 +0900253 String icmpInfoKey = icmpInfoKey(icmp,
254 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()),
255 IPv4.fromIPv4Address(ipPacket.getSourceAddress()));
256 log.trace("Retrieved icmpInfo key is {}", icmpInfoKey);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900257
sangho247232c2017-08-24 17:22:08 +0900258 if (icmpInfoMap.get(icmpInfoKey) != null) {
259 processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey).value());
260 icmpInfoMap.remove(icmpInfoKey);
261 } else {
262 log.warn("No ICMP Info for ICMP packet");
263 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900264 }
265
266 private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
Daniel Park4d486842018-07-24 17:06:43 +0900267 checkNotNull(instance);
268 checkNotNull(srcIp);
269
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 Port osPort = osNetworkService.port(instance.portId());
271 IP fixedIp = osPort.getFixedIps().stream()
272 .filter(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(srcIp))
273 .findAny().orElse(null);
Daniel Park4d486842018-07-24 17:06:43 +0900274 checkNotNull(fixedIp);
275
Hyunsun Moon44aac662017-02-18 02:07:01 +0900276 return osNetworkService.subnet(fixedIp.getSubnetId());
277 }
278
279 private boolean isForSubnetGateway(IpAddress dstIp, Subnet srcSubnet) {
280 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
281 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
282 .findAny().orElse(null);
283 if (osRouterIface == null) {
284 log.trace(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no router",
285 srcSubnet.getId(), srcSubnet.getCidr());
286 return false;
287 }
288
289 Router osRouter = osRouterService.router(osRouterIface.getId());
290 Set<IpAddress> routableGateways = osRouterService.routerInterfaces(osRouter.getId())
291 .stream()
292 .map(iface -> osNetworkService.subnet(iface.getSubnetId()).getGateway())
293 .map(IpAddress::valueOf)
294 .collect(Collectors.toSet());
295
296 return routableGateways.contains(dstIp);
297 }
298
Daniel Park4d486842018-07-24 17:06:43 +0900299 private IpAddress getExternalIp(ExternalGateway externalGateway, RouterInterface osRouterIface) {
300 checkNotNull(externalGateway);
301 checkNotNull(osRouterIface);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900302
303 Router osRouter = osRouterService.router(osRouterIface.getId());
Daniel Park4d486842018-07-24 17:06:43 +0900304 if (osRouter == null) {
305 return null;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900306 }
307
Daniel Park4d486842018-07-24 17:06:43 +0900308 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309 .stream()
310 .filter(port -> Objects.equals(port.getDeviceId(), osRouter.getId()))
311 .findAny().orElse(null);
312 if (exGatewayPort == null) {
313 final String error = String.format(ERR_REQ +
Daniel Park4d486842018-07-24 17:06:43 +0900314 "no external gateway port for router (ID:%s, name:%s)",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900315 osRouter.getId(), osRouter.getName());
316 throw new IllegalStateException(error);
317 }
sangho36721992017-08-03 11:13:17 +0900318 Optional<NeutronIP> externalIpAddress = (Optional<NeutronIP>) exGatewayPort.getFixedIps().stream().findFirst();
319 if (!externalIpAddress.isPresent() || externalIpAddress.get().getIpAddress() == null) {
320 final String error = String.format(ERR_REQ +
321 "no external gateway IP address for router (ID:%s, name:%s)",
322 osRouter.getId(), osRouter.getName());
Daniel Park4d486842018-07-24 17:06:43 +0900323 log.warn(error);
324 return null;
sangho36721992017-08-03 11:13:17 +0900325 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900326
sangho36721992017-08-03 11:13:17 +0900327 return IpAddress.valueOf(externalIpAddress.get().getIpAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900328 }
329
330 private void processRequestForGateway(IPv4 ipPacket, InstancePort instPort) {
331 ICMP icmpReq = (ICMP) ipPacket.getPayload();
332 icmpReq.setChecksum((short) 0);
Daniel Park4d486842018-07-24 17:06:43 +0900333 icmpReq.setIcmpType(TYPE_ECHO_REPLY);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900334
335 int destinationAddress = ipPacket.getSourceAddress();
336
337 ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
338 .setDestinationAddress(destinationAddress)
339 .resetChecksum();
340
341 ipPacket.setPayload(icmpReq);
342 Ethernet icmpReply = new Ethernet();
343 icmpReply.setEtherType(Ethernet.TYPE_IPV4)
344 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
345 .setDestinationMACAddress(instPort.macAddress())
346 .setPayload(ipPacket);
347
348 sendReply(icmpReply, instPort);
349 }
350
daniel parkeeb8e042018-02-21 14:06:58 +0900351 private void sendRequestForExternal(IPv4 ipPacket, DeviceId srcDevice,
daniel park576969a2018-03-09 07:07:41 +0900352 IpAddress srcNatIp, ExternalPeerRouter externalPeerRouter) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900353 ICMP icmpReq = (ICMP) ipPacket.getPayload();
354 icmpReq.resetChecksum();
355 ipPacket.setSourceAddress(srcNatIp.getIp4Address().toInt()).resetChecksum();
356 ipPacket.setPayload(icmpReq);
357
358 Ethernet icmpRequestEth = new Ethernet();
359 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
360 .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
Jian Li5e2ad4a2018-07-16 13:40:53 +0900361 .setDestinationMACAddress(externalPeerRouter.macAddress());
daniel park576969a2018-03-09 07:07:41 +0900362
Jian Li5e2ad4a2018-07-16 13:40:53 +0900363 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
364 icmpRequestEth.setVlanID(externalPeerRouter.vlanId().toShort());
daniel park576969a2018-03-09 07:07:41 +0900365 }
366
367 icmpRequestEth.setPayload(ipPacket);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900368
Hyunsun Moon0d457362017-06-27 17:19:41 +0900369 OpenstackNode osNode = osNodeService.node(srcDevice);
370 if (osNode == null) {
371 final String error = String.format("Cannot find openstack node for %s",
372 srcDevice);
373 throw new IllegalStateException(error);
374 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900375 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel parkeeb8e042018-02-21 14:06:58 +0900376 .setOutput(osNode.uplinkPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900377 .build();
378
379 OutboundPacket packet = new DefaultOutboundPacket(
380 srcDevice,
381 treatment,
382 ByteBuffer.wrap(icmpRequestEth.serialize()));
383
384 packetService.emit(packet);
385 }
386
387 private void processReplyFromExternal(IPv4 ipPacket, InstancePort instPort) {
daniel park576969a2018-03-09 07:07:41 +0900388
389 if (instPort.networkId() == null) {
390 return;
391 }
392
Hyunsun Moon44aac662017-02-18 02:07:01 +0900393 ICMP icmpReply = (ICMP) ipPacket.getPayload();
daniel park576969a2018-03-09 07:07:41 +0900394
Hyunsun Moon44aac662017-02-18 02:07:01 +0900395 icmpReply.resetChecksum();
396
397 ipPacket.setDestinationAddress(instPort.ipAddress().getIp4Address().toInt())
398 .resetChecksum();
399 ipPacket.setPayload(icmpReply);
400
401 Ethernet icmpResponseEth = new Ethernet();
402 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
403 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
404 .setDestinationMACAddress(instPort.macAddress())
405 .setPayload(ipPacket);
406
407 sendReply(icmpResponseEth, instPort);
408 }
409
410 private void sendReply(Ethernet icmpReply, InstancePort instPort) {
411 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
412 .setOutput(instPort.portNumber())
413 .build();
414
415 OutboundPacket packet = new DefaultOutboundPacket(
416 instPort.deviceId(),
417 treatment,
418 ByteBuffer.wrap(icmpReply.serialize()));
419
420 packetService.emit(packet);
421 }
422
423 private short getIcmpId(ICMP icmp) {
424 return ByteBuffer.wrap(icmp.serialize(), 4, 2).getShort();
425 }
426
427 private class InternalPacketProcessor implements PacketProcessor {
428
429 @Override
430 public void process(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900431 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
432 .stream().map(OpenstackNode::intgBridge)
433 .collect(Collectors.toSet());
434
Hyunsun Moon44aac662017-02-18 02:07:01 +0900435 if (context.isHandled()) {
436 return;
Daniel Park4d486842018-07-24 17:06:43 +0900437 }
438
439 if (!gateways.isEmpty() && !gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900440 return;
441 }
442
443 InboundPacket pkt = context.inPacket();
444 Ethernet ethernet = pkt.parsed();
445 if (ethernet == null || ethernet.getEtherType() == Ethernet.TYPE_ARP) {
446 return;
447 }
448
449 IPv4 iPacket = (IPv4) ethernet.getPayload();
450 if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
451 eventExecutor.execute(() -> processIcmpPacket(context, ethernet));
452 }
453 }
Daniel Park4d486842018-07-24 17:06:43 +0900454
455 private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
456 IPv4 ipPacket = (IPv4) ethernet.getPayload();
457 ICMP icmp = (ICMP) ipPacket.getPayload();
458 log.trace("Processing ICMP packet source MAC:{}, source IP:{}," +
459 "dest MAC:{}, dest IP:{}",
460 ethernet.getSourceMAC(),
461 IpAddress.valueOf(ipPacket.getSourceAddress()),
462 ethernet.getDestinationMAC(),
463 IpAddress.valueOf(ipPacket.getDestinationAddress()));
464
465 switch (icmp.getIcmpType()) {
466 case TYPE_ECHO_REQUEST:
467 handleEchoRequest(context.inPacket().receivedFrom().deviceId(),
468 ethernet.getSourceMAC(),
469 ipPacket,
470 icmp);
471 context.block();
472 break;
473 case TYPE_ECHO_REPLY:
474 handleEchoReply(ipPacket, icmp);
475 context.block();
476 break;
477 default:
478 break;
479 }
480 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900481 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900482}