blob: 977fe36751228962ac9d9ce15dc45c1529b6219d [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.onlab.packet.Ethernet;
20import org.onlab.packet.ICMP;
Jian Li2fa3ded2018-08-10 02:22:47 +000021import org.onlab.packet.ICMPEcho;
Hyunsun Moon44aac662017-02-18 02:07:01 +090022import org.onlab.packet.IPv4;
23import org.onlab.packet.IpAddress;
24import org.onlab.packet.MacAddress;
daniel park576969a2018-03-09 07:07:41 +090025import org.onlab.packet.VlanId;
sangho247232c2017-08-24 17:22:08 +090026import org.onlab.util.KryoNamespace;
Daniel Park6a2d95e2018-11-05 18:50:16 +090027import org.onosproject.cluster.ClusterService;
28import org.onosproject.cluster.LeadershipService;
29import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090032import org.onosproject.net.DeviceId;
Daniel Park6a2d95e2018-11-05 18:50:16 +090033import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moon44aac662017-02-18 02:07:01 +090034import org.onosproject.net.flow.DefaultTrafficTreatment;
Daniel Park6a2d95e2018-11-05 18:50:16 +090035import org.onosproject.net.flow.TrafficSelector;
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;
Daniel Park6a2d95e2018-11-05 18:50:16 +090047import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090048import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sangho36721992017-08-03 11:13:17 +090049import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090050import org.onosproject.openstacknode.api.OpenstackNode;
Daniel Park6a2d95e2018-11-05 18:50:16 +090051import org.onosproject.openstacknode.api.OpenstackNodeEvent;
52import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090053import org.onosproject.openstacknode.api.OpenstackNodeService;
sangho247232c2017-08-24 17:22:08 +090054import org.onosproject.store.serializers.KryoNamespaces;
55import org.onosproject.store.service.ConsistentMap;
56import org.onosproject.store.service.Serializer;
57import org.onosproject.store.service.StorageService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.openstack4j.model.network.Port;
59import org.openstack4j.model.network.Router;
60import org.openstack4j.model.network.RouterInterface;
61import org.openstack4j.model.network.Subnet;
Jian Li28680442018-11-11 00:35:37 +090062import org.osgi.service.component.annotations.Activate;
63import org.osgi.service.component.annotations.Component;
64import org.osgi.service.component.annotations.Deactivate;
65import org.osgi.service.component.annotations.Reference;
66import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090067import org.slf4j.Logger;
68
69import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090070import java.util.Objects;
Hyunsun Moon44aac662017-02-18 02:07:01 +090071import java.util.Set;
72import java.util.concurrent.ExecutorService;
73import java.util.stream.Collectors;
74
sangho247232c2017-08-24 17:22:08 +090075import static com.google.common.base.Preconditions.checkArgument;
Daniel Park4d486842018-07-24 17:06:43 +090076import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon44aac662017-02-18 02:07:01 +090077import static java.util.concurrent.Executors.newSingleThreadExecutor;
Daniel Park4d486842018-07-24 17:06:43 +090078import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
79import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import static org.onlab.util.Tools.groupedThreads;
sangho36721992017-08-03 11:13:17 +090081import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
Daniel Park6a2d95e2018-11-05 18:50:16 +090082import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
sangho36721992017-08-03 11:13:17 +090083import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Daniel Park6a2d95e2018-11-05 18:50:16 +090084import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
Jian Liebde74d2018-11-14 00:18:57 +090085import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalIpFromSubnet;
86import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Hyunsun Moon0d457362017-06-27 17:19:41 +090087import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090088import static org.slf4j.LoggerFactory.getLogger;
89
Hyunsun Moon44aac662017-02-18 02:07:01 +090090/**
91 * Handles ICMP packet received from a gateway node.
92 * For a request for virtual network subnet gateway, it generates fake ICMP reply.
93 * For a request for the external network, it does source NAT with the public IP and
94 * forward the request to the external only if the requested virtual subnet has
95 * external connectivity.
96 */
97@Component(immediate = true)
98public class OpenstackRoutingIcmpHandler {
99
100 protected final Logger log = getLogger(getClass());
101
102 private static final String ERR_REQ = "Failed to handle ICMP request: ";
sangho247232c2017-08-24 17:22:08 +0900103 private static final String ERR_DUPLICATE = " already exists";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106 protected CoreService coreService;
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109 protected PacketService packetService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho247232c2017-08-24 17:22:08 +0900112 protected StorageService storageService;
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 InstancePortService instancePortService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121 protected OpenstackNetworkService osNetworkService;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124 protected OpenstackRouterService osRouterService;
125
Ray Milkey5739b2c2018-11-06 14:04:51 -0800126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900127 protected LeadershipService leadershipService;
128
Ray Milkey5739b2c2018-11-06 14:04:51 -0800129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900130 protected OpenstackFlowRuleService osFlowRuleService;
131
Ray Milkey5739b2c2018-11-06 14:04:51 -0800132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900133 protected ClusterService clusterService;
134
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135 private final ExecutorService eventExecutor = newSingleThreadExecutor(
136 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
sangho072c4dd2017-05-17 10:45:21 +0900137 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
sangho247232c2017-08-24 17:22:08 +0900138 private ConsistentMap<String, InstancePort> icmpInfoMap;
Daniel Park6a2d95e2018-11-05 18:50:16 +0900139 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
sangho247232c2017-08-24 17:22:08 +0900140
141 private static final KryoNamespace SERIALIZER_ICMP_MAP = KryoNamespace.newBuilder()
142 .register(KryoNamespaces.API)
143 .register(InstancePort.class)
Jian Liec5c32b2018-07-13 14:28:58 +0900144 .register(DefaultInstancePort.class)
145 .register(InstancePort.State.class)
sangho247232c2017-08-24 17:22:08 +0900146 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147
148 private ApplicationId appId;
Daniel Park6a2d95e2018-11-05 18:50:16 +0900149 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900150
151 @Activate
152 protected void activate() {
153 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
154 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900155 localNodeId = clusterService.getLocalNode().id();
156 leadershipService.runForLeadership(appId.name());
157 osNodeService.addListener(osNodeListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158
sangho247232c2017-08-24 17:22:08 +0900159 icmpInfoMap = storageService.<String, InstancePort>consistentMapBuilder()
160 .withSerializer(Serializer.using(SERIALIZER_ICMP_MAP))
161 .withName("openstack-icmpmap")
162 .withApplicationId(appId)
163 .build();
164
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165 log.info("Started");
166 }
167
168 @Deactivate
169 protected void deactivate() {
170 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171 eventExecutor.shutdown();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900172 leadershipService.withdraw(appId.name());
173 osNodeService.removeListener(osNodeListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174
175 log.info("Stopped");
176 }
177
Daniel Park6a2d95e2018-11-05 18:50:16 +0900178 private class InternalNodeEventListener implements OpenstackNodeListener {
179 @Override
180 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900181 return event.subject().type() == GATEWAY;
182 }
183
184 private boolean isRelevantHelper() {
185 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900186 }
187
188 @Override
189 public void event(OpenstackNodeEvent event) {
190 OpenstackNode osNode = event.subject();
191 switch (event.type()) {
192 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900193 eventExecutor.execute(() -> processNodeCompletion(osNode));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900194 break;
195 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900196 eventExecutor.execute(() -> processNodeInCompletion(osNode));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900197 break;
198 default:
199 break;
200 }
201 }
202
Jian Li6a47fd02018-11-27 21:51:03 +0900203 private void processNodeCompletion(OpenstackNode osNode) {
204 if (!isRelevantHelper()) {
205 return;
206 }
207
208 setIcmpReplyRules(osNode.intgBridge(), true);
209 }
210
211 private void processNodeInCompletion(OpenstackNode osNode) {
212 if (!isRelevantHelper()) {
213 return;
214 }
215
216 setIcmpReplyRules(osNode.intgBridge(), false);
217 }
218
Daniel Park6a2d95e2018-11-05 18:50:16 +0900219 private void setIcmpReplyRules(DeviceId deviceId, boolean install) {
220 // Sends ICMP response to controller for SNATing ingress traffic
221 TrafficSelector selector = DefaultTrafficSelector.builder()
222 .matchEthType(Ethernet.TYPE_IPV4)
223 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
224 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
225 .build();
226
227 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
228 .punt()
229 .build();
230
231 osFlowRuleService.setRule(
232 appId,
233 deviceId,
234 selector,
235 treatment,
236 PRIORITY_INTERNAL_ROUTING_RULE,
237 GW_COMMON_TABLE,
238 install);
239 }
240 }
Jian Li28680442018-11-11 00:35:37 +0900241
242 private class InternalPacketProcessor implements PacketProcessor {
243
244 @Override
245 public void process(PacketContext context) {
246 if (context.isHandled()) {
247 return;
248 }
249
250 eventExecutor.execute(() -> {
Jian Li28680442018-11-11 00:35:37 +0900251
Jian Li34220ea2018-11-14 01:30:24 +0900252 if (!isRelevantHelper(context)) {
Jian Li28680442018-11-11 00:35:37 +0900253 return;
254 }
255
256 InboundPacket pkt = context.inPacket();
257 Ethernet ethernet = pkt.parsed();
258 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
259 return;
260 }
261
262 IPv4 iPacket = (IPv4) ethernet.getPayload();
263
264 if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
265 processIcmpPacket(context, ethernet);
266 }
267 });
268 }
269
Jian Li34220ea2018-11-14 01:30:24 +0900270 private boolean isRelevantHelper(PacketContext context) {
271 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
272 .stream().map(OpenstackNode::intgBridge)
273 .collect(Collectors.toSet());
274
275 return gateways.contains(context.inPacket().receivedFrom().deviceId());
276 }
277
Jian Li28680442018-11-11 00:35:37 +0900278 private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
279 IPv4 ipPacket = (IPv4) ethernet.getPayload();
280 ICMP icmp = (ICMP) ipPacket.getPayload();
281 log.trace("Processing ICMP packet source MAC:{}, source IP:{}," +
282 "dest MAC:{}, dest IP:{}",
283 ethernet.getSourceMAC(),
284 IpAddress.valueOf(ipPacket.getSourceAddress()),
285 ethernet.getDestinationMAC(),
286 IpAddress.valueOf(ipPacket.getDestinationAddress()));
287
288 switch (icmp.getIcmpType()) {
289 case TYPE_ECHO_REQUEST:
290 if (handleEchoRequest(context.inPacket().receivedFrom().deviceId(),
Jian Li6a47fd02018-11-27 21:51:03 +0900291 ethernet.getSourceMAC(), ipPacket, icmp)) {
Jian Li28680442018-11-11 00:35:37 +0900292 context.block();
293 }
294 break;
295 case TYPE_ECHO_REPLY:
296 if (handleEchoReply(ipPacket, icmp)) {
297 context.block();
298 }
299 break;
300 default:
301 break;
302 }
303 }
304
305 private boolean handleEchoRequest(DeviceId srcDevice, MacAddress srcMac, IPv4 ipPacket,
306 ICMP icmp) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900307 // we only handles a request from an instance port
308 // in case of ehco request to SNAT ip address from an external router,
309 // we intentionally ignore it
Jian Li28680442018-11-11 00:35:37 +0900310 InstancePort instPort = instancePortService.instancePort(srcMac);
311 if (instPort == null) {
312 log.warn(ERR_REQ + "unknown source host(MAC:{})", srcMac);
313 return false;
314 }
315
316 IpAddress srcIp = IpAddress.valueOf(ipPacket.getSourceAddress());
317 IpAddress dstIp = IpAddress.valueOf(ipPacket.getDestinationAddress());
318
319 Subnet srcSubnet = getSourceSubnet(instPort);
320 if (srcSubnet == null) {
321 log.warn(ERR_REQ + "unknown source subnet(IP:{})", srcIp);
322 return false;
323 }
324
325 if (Strings.isNullOrEmpty(srcSubnet.getGateway())) {
326 log.warn(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no gateway",
327 srcSubnet.getId(), srcSubnet.getCidr());
328 return false;
329 }
330
331 if (isForSubnetGateway(IpAddress.valueOf(ipPacket.getDestinationAddress()),
332 srcSubnet)) {
333 // this is a request to a subnet gateway
334 log.trace("Icmp request to gateway {} from {}", dstIp, srcIp);
335 processRequestForGateway(ipPacket, instPort);
336 } else {
337 // this is a request to an external network
338 log.trace("Icmp request to external {} from {}", dstIp, srcIp);
339
Jian Li5ecfd1a2018-12-10 11:41:03 +0900340 IpAddress externalIp = externalIpFromSubnet(srcSubnet,
341 osRouterService, osNetworkService);
Jian Li28680442018-11-11 00:35:37 +0900342 if (externalIp == null) {
343 log.warn(ERR_REQ + "failed to get external ip");
344 return false;
345 }
346
Jian Liebde74d2018-11-14 00:18:57 +0900347 ExternalPeerRouter externalPeerRouter =
Jian Li5ecfd1a2018-12-10 11:41:03 +0900348 externalPeerRouterFromSubnet(srcSubnet,
349 osRouterService, osNetworkService);
Jian Liebde74d2018-11-14 00:18:57 +0900350 if (externalPeerRouter == null) {
351 log.warn(ERR_REQ + "failed to get external peer router");
352 return false;
353 }
354
Jian Li28680442018-11-11 00:35:37 +0900355 String icmpInfoKey = icmpInfoKey(icmp,
356 externalIp.toString(),
357 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()));
358 log.trace("Created icmpInfo key is {}", icmpInfoKey);
359
360 sendRequestForExternal(ipPacket, srcDevice, externalIp, externalPeerRouter);
361
362 try {
363 icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
364 checkArgument(existing == null, ERR_DUPLICATE);
365 return instPort;
366 });
367 } catch (IllegalArgumentException e) {
368 log.warn("IllegalArgumentException occurred because of {}", e.toString());
369 return false;
370 }
371 }
372 return true;
373 }
374
375 private String icmpInfoKey(ICMP icmp, String srcIp, String dstIp) {
376 return String.valueOf(getIcmpId(icmp))
377 .concat(srcIp)
378 .concat(dstIp);
379 }
Jian Li28680442018-11-11 00:35:37 +0900380
381 private boolean handleEchoReply(IPv4 ipPacket, ICMP icmp) {
382 String icmpInfoKey = icmpInfoKey(icmp,
383 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()),
384 IPv4.fromIPv4Address(ipPacket.getSourceAddress()));
385 log.trace("Retrieved icmpInfo key is {}", icmpInfoKey);
386
387 if (icmpInfoMap.get(icmpInfoKey) != null) {
388 processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey).value());
389 icmpInfoMap.remove(icmpInfoKey);
390 return true;
391 } else {
392 log.debug("No ICMP Info for ICMP packet");
393 return false;
394 }
395 }
396
397 private Subnet getSourceSubnet(InstancePort instance) {
398 checkNotNull(instance);
399
400 Port osPort = osNetworkService.port(instance.portId());
401 return osNetworkService.subnets(osPort.getNetworkId())
402 .stream().findAny().orElse(null);
403 }
404
405 private boolean isForSubnetGateway(IpAddress dstIp, Subnet srcSubnet) {
406 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
407 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
408 .findAny().orElse(null);
409 if (osRouterIface == null) {
410 log.trace(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no router",
411 srcSubnet.getId(), srcSubnet.getCidr());
412 return false;
413 }
414
415 Router osRouter = osRouterService.router(osRouterIface.getId());
Jian Li5ecfd1a2018-12-10 11:41:03 +0900416 Set<IpAddress> routableGateways =
417 osRouterService.routerInterfaces(osRouter.getId())
Jian Li28680442018-11-11 00:35:37 +0900418 .stream()
419 .map(iface -> osNetworkService.subnet(iface.getSubnetId()).getGateway())
420 .map(IpAddress::valueOf)
421 .collect(Collectors.toSet());
422
423 return routableGateways.contains(dstIp);
424 }
425
Jian Li28680442018-11-11 00:35:37 +0900426 private void processRequestForGateway(IPv4 ipPacket, InstancePort instPort) {
427 ICMP icmpReq = (ICMP) ipPacket.getPayload();
428 icmpReq.setChecksum((short) 0);
429 icmpReq.setIcmpType(TYPE_ECHO_REPLY);
430
431 int destinationAddress = ipPacket.getSourceAddress();
432
433 ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
434 .setDestinationAddress(destinationAddress)
435 .resetChecksum();
436
437 ipPacket.setPayload(icmpReq);
438 Ethernet icmpReply = new Ethernet();
439 icmpReply.setEtherType(Ethernet.TYPE_IPV4)
440 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
441 .setDestinationMACAddress(instPort.macAddress())
442 .setPayload(ipPacket);
443
444 sendReply(icmpReply, instPort);
445 }
446
Jian Li5ecfd1a2018-12-10 11:41:03 +0900447 private void sendRequestForExternal(IPv4 ipPacket,
448 DeviceId srcDevice,
449 IpAddress srcNatIp,
450 ExternalPeerRouter externalPeerRouter) {
Jian Li28680442018-11-11 00:35:37 +0900451 ICMP icmpReq = (ICMP) ipPacket.getPayload();
452 icmpReq.resetChecksum();
453 ipPacket.setSourceAddress(srcNatIp.getIp4Address().toInt()).resetChecksum();
454 ipPacket.setPayload(icmpReq);
455
456 Ethernet icmpRequestEth = new Ethernet();
457 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
458 .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
459 .setDestinationMACAddress(externalPeerRouter.macAddress());
460
461 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
462 icmpRequestEth.setVlanID(externalPeerRouter.vlanId().toShort());
463 }
464
465 icmpRequestEth.setPayload(ipPacket);
466
467 OpenstackNode osNode = osNodeService.node(srcDevice);
468 if (osNode == null) {
469 final String error = String.format("Cannot find openstack node for %s",
470 srcDevice);
471 throw new IllegalStateException(error);
472 }
473 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
474 .setOutput(osNode.uplinkPortNum())
475 .build();
476
477 OutboundPacket packet = new DefaultOutboundPacket(
478 srcDevice,
479 treatment,
480 ByteBuffer.wrap(icmpRequestEth.serialize()));
481
482 packetService.emit(packet);
483 }
484
485 private void processReplyFromExternal(IPv4 ipPacket, InstancePort instPort) {
486
487 if (instPort.networkId() == null) {
488 return;
489 }
490
491 ICMP icmpReply = (ICMP) ipPacket.getPayload();
492
493 icmpReply.resetChecksum();
494
495 ipPacket.setDestinationAddress(instPort.ipAddress().getIp4Address().toInt())
496 .resetChecksum();
497 ipPacket.setPayload(icmpReply);
498
499 Ethernet icmpResponseEth = new Ethernet();
500 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
501 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
502 .setDestinationMACAddress(instPort.macAddress())
503 .setPayload(ipPacket);
504
505 sendReply(icmpResponseEth, instPort);
506 }
507
508 private void sendReply(Ethernet icmpReply, InstancePort instPort) {
509 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
510 .setOutput(instPort.portNumber());
511
512 String netId = instPort.networkId();
513 String segId = osNetworkService.segmentId(netId);
514
515 switch (osNetworkService.networkType(netId)) {
516 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900517 case GRE:
Jian Li28680442018-11-11 00:35:37 +0900518 tBuilder.setTunnelId(Long.valueOf(segId));
519 break;
520 case VLAN:
521 tBuilder.setVlanId(VlanId.vlanId(segId));
522 break;
523 default:
524 break;
525 }
526
527 OutboundPacket packet = new DefaultOutboundPacket(
528 instPort.deviceId(),
529 tBuilder.build(),
530 ByteBuffer.wrap(icmpReply.serialize()));
531
532 packetService.emit(packet);
533 }
534
535 private short getIcmpId(ICMP icmp) {
536 return ((ICMPEcho) icmp.getPayload()).getIdentifier();
537 }
538 }
Jian Li2d68c192018-12-13 15:52:59 +0900539
Hyunsun Moon44aac662017-02-18 02:07:01 +0900540}