blob: 6b9adac6046b1a1e2edaac6a05c3132d830e06c7 [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;
Jian Li25257212019-03-26 13:31:14 +090027import org.onosproject.cfg.ComponentConfigService;
28import org.onosproject.cfg.ConfigProperty;
Daniel Park6a2d95e2018-11-05 18:50:16 +090029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
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;
Daniel Park6a2d95e2018-11-05 18:50:16 +090035import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.flow.DefaultTrafficTreatment;
Daniel Park6a2d95e2018-11-05 18:50:16 +090037import org.onosproject.net.flow.TrafficSelector;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.net.flow.TrafficTreatment;
39import org.onosproject.net.packet.DefaultOutboundPacket;
40import org.onosproject.net.packet.InboundPacket;
41import org.onosproject.net.packet.OutboundPacket;
42import org.onosproject.net.packet.PacketContext;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.net.packet.PacketProcessor;
44import org.onosproject.net.packet.PacketService;
45import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090046import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.onosproject.openstacknetworking.api.InstancePort;
48import org.onosproject.openstacknetworking.api.InstancePortService;
Daniel Park6a2d95e2018-11-05 18:50:16 +090049import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
sangho36721992017-08-03 11:13:17 +090051import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090052import org.onosproject.openstacknode.api.OpenstackNode;
Daniel Park6a2d95e2018-11-05 18:50:16 +090053import org.onosproject.openstacknode.api.OpenstackNodeEvent;
54import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090055import org.onosproject.openstacknode.api.OpenstackNodeService;
sangho247232c2017-08-24 17:22:08 +090056import org.onosproject.store.serializers.KryoNamespaces;
57import org.onosproject.store.service.ConsistentMap;
58import org.onosproject.store.service.Serializer;
59import org.onosproject.store.service.StorageService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090060import org.openstack4j.model.network.Port;
61import org.openstack4j.model.network.Router;
62import org.openstack4j.model.network.RouterInterface;
63import org.openstack4j.model.network.Subnet;
Jian Li28680442018-11-11 00:35:37 +090064import org.osgi.service.component.annotations.Activate;
65import org.osgi.service.component.annotations.Component;
66import org.osgi.service.component.annotations.Deactivate;
67import org.osgi.service.component.annotations.Reference;
68import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090069import org.slf4j.Logger;
70
71import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072import java.util.Objects;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import java.util.Set;
74import java.util.concurrent.ExecutorService;
75import java.util.stream.Collectors;
76
sangho247232c2017-08-24 17:22:08 +090077import static com.google.common.base.Preconditions.checkArgument;
Daniel Park4d486842018-07-24 17:06:43 +090078import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon44aac662017-02-18 02:07:01 +090079import static java.util.concurrent.Executors.newSingleThreadExecutor;
Daniel Park4d486842018-07-24 17:06:43 +090080import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
81import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
Hyunsun Moon44aac662017-02-18 02:07:01 +090082import static org.onlab.util.Tools.groupedThreads;
sangho36721992017-08-03 11:13:17 +090083import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
Daniel Park6a2d95e2018-11-05 18:50:16 +090084import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
sangho36721992017-08-03 11:13:17 +090085import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Daniel Park6a2d95e2018-11-05 18:50:16 +090086import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
Jian Li25257212019-03-26 13:31:14 +090087import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT;
Jian Lia5c7edf2020-02-24 16:42:24 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalGatewayIp;
Jian Liebde74d2018-11-14 00:18:57 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Jian Li25257212019-03-26 13:31:14 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Lia5c7edf2020-02-24 16:42:24 +090091import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getRouterFromSubnet;
Hyunsun Moon0d457362017-06-27 17:19:41 +090092import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090093import static org.slf4j.LoggerFactory.getLogger;
94
Hyunsun Moon44aac662017-02-18 02:07:01 +090095/**
96 * Handles ICMP packet received from a gateway node.
97 * For a request for virtual network subnet gateway, it generates fake ICMP reply.
98 * For a request for the external network, it does source NAT with the public IP and
99 * forward the request to the external only if the requested virtual subnet has
100 * external connectivity.
101 */
102@Component(immediate = true)
Jian Li25257212019-03-26 13:31:14 +0900103public class OpenstackRoutingSnatIcmpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
105 protected final Logger log = getLogger(getClass());
106
107 private static final String ERR_REQ = "Failed to handle ICMP request: ";
sangho247232c2017-08-24 17:22:08 +0900108 private static final String ERR_DUPLICATE = " already exists";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111 protected CoreService coreService;
112
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114 protected PacketService packetService;
115
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho247232c2017-08-24 17:22:08 +0900117 protected StorageService storageService;
118
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900120 protected OpenstackNodeService osNodeService;
121
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123 protected InstancePortService instancePortService;
124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li25257212019-03-26 13:31:14 +0900126 protected ComponentConfigService configService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129 protected OpenstackNetworkService osNetworkService;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 protected OpenstackRouterService osRouterService;
133
Ray Milkey5739b2c2018-11-06 14:04:51 -0800134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900135 protected LeadershipService leadershipService;
136
Ray Milkey5739b2c2018-11-06 14:04:51 -0800137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900138 protected OpenstackFlowRuleService osFlowRuleService;
139
Ray Milkey5739b2c2018-11-06 14:04:51 -0800140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900141 protected ClusterService clusterService;
142
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 private final ExecutorService eventExecutor = newSingleThreadExecutor(
144 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
sangho072c4dd2017-05-17 10:45:21 +0900145 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
sangho247232c2017-08-24 17:22:08 +0900146 private ConsistentMap<String, InstancePort> icmpInfoMap;
Daniel Park6a2d95e2018-11-05 18:50:16 +0900147 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
sangho247232c2017-08-24 17:22:08 +0900148
149 private static final KryoNamespace SERIALIZER_ICMP_MAP = KryoNamespace.newBuilder()
150 .register(KryoNamespaces.API)
151 .register(InstancePort.class)
Jian Liec5c32b2018-07-13 14:28:58 +0900152 .register(DefaultInstancePort.class)
153 .register(InstancePort.State.class)
sangho247232c2017-08-24 17:22:08 +0900154 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900155
156 private ApplicationId appId;
Daniel Park6a2d95e2018-11-05 18:50:16 +0900157 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158
159 @Activate
160 protected void activate() {
161 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
162 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900163 localNodeId = clusterService.getLocalNode().id();
164 leadershipService.runForLeadership(appId.name());
165 osNodeService.addListener(osNodeListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166
sangho247232c2017-08-24 17:22:08 +0900167 icmpInfoMap = storageService.<String, InstancePort>consistentMapBuilder()
168 .withSerializer(Serializer.using(SERIALIZER_ICMP_MAP))
169 .withName("openstack-icmpmap")
170 .withApplicationId(appId)
171 .build();
172
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173 log.info("Started");
174 }
175
176 @Deactivate
177 protected void deactivate() {
178 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900179 eventExecutor.shutdown();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900180 leadershipService.withdraw(appId.name());
181 osNodeService.removeListener(osNodeListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182
183 log.info("Stopped");
184 }
185
Jian Li25257212019-03-26 13:31:14 +0900186 private boolean getStatefulSnatFlag() {
187 Set<ConfigProperty> properties = configService.getProperties(OpenstackRoutingSnatHandler.class.getName());
188 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
189 }
190
Daniel Park6a2d95e2018-11-05 18:50:16 +0900191 private class InternalNodeEventListener implements OpenstackNodeListener {
192 @Override
193 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Lifdb8d872019-04-08 10:38:58 +0900194 return event.subject().type() == GATEWAY;
Jian Li34220ea2018-11-14 01:30:24 +0900195 }
196
197 private boolean isRelevantHelper() {
198 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900199 }
200
201 @Override
202 public void event(OpenstackNodeEvent event) {
203 OpenstackNode osNode = event.subject();
204 switch (event.type()) {
205 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900206 eventExecutor.execute(() -> processNodeCompletion(osNode));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900207 break;
208 case OPENSTACK_NODE_INCOMPLETE:
Daniel Park6a2d95e2018-11-05 18:50:16 +0900209 default:
210 break;
211 }
212 }
213
Jian Li6a47fd02018-11-27 21:51:03 +0900214 private void processNodeCompletion(OpenstackNode osNode) {
215 if (!isRelevantHelper()) {
216 return;
217 }
218
219 setIcmpReplyRules(osNode.intgBridge(), true);
220 }
221
222 private void processNodeInCompletion(OpenstackNode osNode) {
223 if (!isRelevantHelper()) {
224 return;
225 }
226
227 setIcmpReplyRules(osNode.intgBridge(), false);
228 }
229
Daniel Park6a2d95e2018-11-05 18:50:16 +0900230 private void setIcmpReplyRules(DeviceId deviceId, boolean install) {
231 // Sends ICMP response to controller for SNATing ingress traffic
232 TrafficSelector selector = DefaultTrafficSelector.builder()
233 .matchEthType(Ethernet.TYPE_IPV4)
234 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
235 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
236 .build();
237
238 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
239 .punt()
240 .build();
241
242 osFlowRuleService.setRule(
243 appId,
244 deviceId,
245 selector,
246 treatment,
247 PRIORITY_INTERNAL_ROUTING_RULE,
248 GW_COMMON_TABLE,
249 install);
250 }
251 }
Jian Li28680442018-11-11 00:35:37 +0900252
253 private class InternalPacketProcessor implements PacketProcessor {
254
255 @Override
256 public void process(PacketContext context) {
257 if (context.isHandled()) {
258 return;
259 }
260
261 eventExecutor.execute(() -> {
Jian Li28680442018-11-11 00:35:37 +0900262
Jian Li34220ea2018-11-14 01:30:24 +0900263 if (!isRelevantHelper(context)) {
Jian Li28680442018-11-11 00:35:37 +0900264 return;
265 }
266
267 InboundPacket pkt = context.inPacket();
268 Ethernet ethernet = pkt.parsed();
269 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
270 return;
271 }
272
273 IPv4 iPacket = (IPv4) ethernet.getPayload();
274
275 if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
276 processIcmpPacket(context, ethernet);
277 }
278 });
279 }
280
Jian Li34220ea2018-11-14 01:30:24 +0900281 private boolean isRelevantHelper(PacketContext context) {
282 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
283 .stream().map(OpenstackNode::intgBridge)
284 .collect(Collectors.toSet());
285
286 return gateways.contains(context.inPacket().receivedFrom().deviceId());
287 }
288
Jian Li28680442018-11-11 00:35:37 +0900289 private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
290 IPv4 ipPacket = (IPv4) ethernet.getPayload();
291 ICMP icmp = (ICMP) ipPacket.getPayload();
292 log.trace("Processing ICMP packet source MAC:{}, source IP:{}," +
293 "dest MAC:{}, dest IP:{}",
294 ethernet.getSourceMAC(),
295 IpAddress.valueOf(ipPacket.getSourceAddress()),
296 ethernet.getDestinationMAC(),
297 IpAddress.valueOf(ipPacket.getDestinationAddress()));
298
299 switch (icmp.getIcmpType()) {
300 case TYPE_ECHO_REQUEST:
301 if (handleEchoRequest(context.inPacket().receivedFrom().deviceId(),
Jian Li6a47fd02018-11-27 21:51:03 +0900302 ethernet.getSourceMAC(), ipPacket, icmp)) {
Jian Li28680442018-11-11 00:35:37 +0900303 context.block();
304 }
305 break;
306 case TYPE_ECHO_REPLY:
307 if (handleEchoReply(ipPacket, icmp)) {
308 context.block();
309 }
310 break;
311 default:
312 break;
313 }
314 }
315
316 private boolean handleEchoRequest(DeviceId srcDevice, MacAddress srcMac, IPv4 ipPacket,
317 ICMP icmp) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900318 // we only handles a request from an instance port
319 // in case of ehco request to SNAT ip address from an external router,
320 // we intentionally ignore it
Jian Li28680442018-11-11 00:35:37 +0900321 InstancePort instPort = instancePortService.instancePort(srcMac);
322 if (instPort == null) {
323 log.warn(ERR_REQ + "unknown source host(MAC:{})", srcMac);
324 return false;
325 }
326
327 IpAddress srcIp = IpAddress.valueOf(ipPacket.getSourceAddress());
328 IpAddress dstIp = IpAddress.valueOf(ipPacket.getDestinationAddress());
329
330 Subnet srcSubnet = getSourceSubnet(instPort);
331 if (srcSubnet == null) {
332 log.warn(ERR_REQ + "unknown source subnet(IP:{})", srcIp);
333 return false;
334 }
335
336 if (Strings.isNullOrEmpty(srcSubnet.getGateway())) {
337 log.warn(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no gateway",
338 srcSubnet.getId(), srcSubnet.getCidr());
339 return false;
340 }
341
342 if (isForSubnetGateway(IpAddress.valueOf(ipPacket.getDestinationAddress()),
343 srcSubnet)) {
344 // this is a request to a subnet gateway
345 log.trace("Icmp request to gateway {} from {}", dstIp, srcIp);
346 processRequestForGateway(ipPacket, instPort);
347 } else {
348 // this is a request to an external network
349 log.trace("Icmp request to external {} from {}", dstIp, srcIp);
350
Jian Lia5c7edf2020-02-24 16:42:24 +0900351 Router osRouter = getRouterFromSubnet(srcSubnet, osRouterService);
352
353 if (osRouter == null || osRouter.getExternalGatewayInfo() == null) {
354 // this router does not have external connectivity
355 log.warn("No router is associated with the given subnet {}", srcSubnet);
356 return false;
357 }
358
359 IpAddress externalGatewayIp = externalGatewayIp(osRouter, osNetworkService);
360
361 if (externalGatewayIp == null) {
Jian Li28680442018-11-11 00:35:37 +0900362 log.warn(ERR_REQ + "failed to get external ip");
363 return false;
364 }
365
Jian Liebde74d2018-11-14 00:18:57 +0900366 ExternalPeerRouter externalPeerRouter =
Jian Li5ecfd1a2018-12-10 11:41:03 +0900367 externalPeerRouterFromSubnet(srcSubnet,
368 osRouterService, osNetworkService);
Jian Liebde74d2018-11-14 00:18:57 +0900369 if (externalPeerRouter == null) {
370 log.warn(ERR_REQ + "failed to get external peer router");
371 return false;
372 }
373
Jian Lia5c7edf2020-02-24 16:42:24 +0900374 String icmpInfoKey = icmpInfoKey(icmp, externalGatewayIp.toString(),
Jian Li28680442018-11-11 00:35:37 +0900375 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()));
376 log.trace("Created icmpInfo key is {}", icmpInfoKey);
377
Jian Lia5c7edf2020-02-24 16:42:24 +0900378 sendRequestForExternal(ipPacket, srcDevice, externalGatewayIp, externalPeerRouter);
Jian Li28680442018-11-11 00:35:37 +0900379
380 try {
381 icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
382 checkArgument(existing == null, ERR_DUPLICATE);
383 return instPort;
384 });
385 } catch (IllegalArgumentException e) {
386 log.warn("IllegalArgumentException occurred because of {}", e.toString());
387 return false;
388 }
389 }
390 return true;
391 }
392
393 private String icmpInfoKey(ICMP icmp, String srcIp, String dstIp) {
394 return String.valueOf(getIcmpId(icmp))
395 .concat(srcIp)
396 .concat(dstIp);
397 }
Jian Li28680442018-11-11 00:35:37 +0900398
399 private boolean handleEchoReply(IPv4 ipPacket, ICMP icmp) {
400 String icmpInfoKey = icmpInfoKey(icmp,
401 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()),
402 IPv4.fromIPv4Address(ipPacket.getSourceAddress()));
403 log.trace("Retrieved icmpInfo key is {}", icmpInfoKey);
404
405 if (icmpInfoMap.get(icmpInfoKey) != null) {
406 processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey).value());
407 icmpInfoMap.remove(icmpInfoKey);
408 return true;
409 } else {
410 log.debug("No ICMP Info for ICMP packet");
411 return false;
412 }
413 }
414
415 private Subnet getSourceSubnet(InstancePort instance) {
416 checkNotNull(instance);
417
418 Port osPort = osNetworkService.port(instance.portId());
419 return osNetworkService.subnets(osPort.getNetworkId())
420 .stream().findAny().orElse(null);
421 }
422
423 private boolean isForSubnetGateway(IpAddress dstIp, Subnet srcSubnet) {
424 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
425 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
426 .findAny().orElse(null);
427 if (osRouterIface == null) {
428 log.trace(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no router",
429 srcSubnet.getId(), srcSubnet.getCidr());
430 return false;
431 }
432
433 Router osRouter = osRouterService.router(osRouterIface.getId());
Jian Li5ecfd1a2018-12-10 11:41:03 +0900434 Set<IpAddress> routableGateways =
435 osRouterService.routerInterfaces(osRouter.getId())
Jian Li28680442018-11-11 00:35:37 +0900436 .stream()
437 .map(iface -> osNetworkService.subnet(iface.getSubnetId()).getGateway())
438 .map(IpAddress::valueOf)
439 .collect(Collectors.toSet());
440
441 return routableGateways.contains(dstIp);
442 }
443
Jian Li28680442018-11-11 00:35:37 +0900444 private void processRequestForGateway(IPv4 ipPacket, InstancePort instPort) {
445 ICMP icmpReq = (ICMP) ipPacket.getPayload();
446 icmpReq.setChecksum((short) 0);
447 icmpReq.setIcmpType(TYPE_ECHO_REPLY);
448
449 int destinationAddress = ipPacket.getSourceAddress();
450
451 ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
452 .setDestinationAddress(destinationAddress)
453 .resetChecksum();
454
455 ipPacket.setPayload(icmpReq);
456 Ethernet icmpReply = new Ethernet();
457 icmpReply.setEtherType(Ethernet.TYPE_IPV4)
458 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
459 .setDestinationMACAddress(instPort.macAddress())
460 .setPayload(ipPacket);
461
462 sendReply(icmpReply, instPort);
463 }
464
Jian Li5ecfd1a2018-12-10 11:41:03 +0900465 private void sendRequestForExternal(IPv4 ipPacket,
466 DeviceId srcDevice,
467 IpAddress srcNatIp,
468 ExternalPeerRouter externalPeerRouter) {
Jian Li28680442018-11-11 00:35:37 +0900469 ICMP icmpReq = (ICMP) ipPacket.getPayload();
470 icmpReq.resetChecksum();
471 ipPacket.setSourceAddress(srcNatIp.getIp4Address().toInt()).resetChecksum();
472 ipPacket.setPayload(icmpReq);
473
474 Ethernet icmpRequestEth = new Ethernet();
475 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
476 .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
477 .setDestinationMACAddress(externalPeerRouter.macAddress());
478
479 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
480 icmpRequestEth.setVlanID(externalPeerRouter.vlanId().toShort());
481 }
482
483 icmpRequestEth.setPayload(ipPacket);
484
485 OpenstackNode osNode = osNodeService.node(srcDevice);
486 if (osNode == null) {
487 final String error = String.format("Cannot find openstack node for %s",
488 srcDevice);
489 throw new IllegalStateException(error);
490 }
491 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
492 .setOutput(osNode.uplinkPortNum())
493 .build();
494
495 OutboundPacket packet = new DefaultOutboundPacket(
496 srcDevice,
497 treatment,
498 ByteBuffer.wrap(icmpRequestEth.serialize()));
499
500 packetService.emit(packet);
501 }
502
503 private void processReplyFromExternal(IPv4 ipPacket, InstancePort instPort) {
504
505 if (instPort.networkId() == null) {
506 return;
507 }
508
509 ICMP icmpReply = (ICMP) ipPacket.getPayload();
510
511 icmpReply.resetChecksum();
512
513 ipPacket.setDestinationAddress(instPort.ipAddress().getIp4Address().toInt())
514 .resetChecksum();
515 ipPacket.setPayload(icmpReply);
516
517 Ethernet icmpResponseEth = new Ethernet();
518 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
519 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
520 .setDestinationMACAddress(instPort.macAddress())
521 .setPayload(ipPacket);
522
523 sendReply(icmpResponseEth, instPort);
524 }
525
526 private void sendReply(Ethernet icmpReply, InstancePort instPort) {
527 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
528 .setOutput(instPort.portNumber());
529
530 String netId = instPort.networkId();
531 String segId = osNetworkService.segmentId(netId);
532
533 switch (osNetworkService.networkType(netId)) {
534 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900535 case GRE:
Jian Li25257212019-03-26 13:31:14 +0900536 case GENEVE:
Jian Li28680442018-11-11 00:35:37 +0900537 tBuilder.setTunnelId(Long.valueOf(segId));
538 break;
539 case VLAN:
540 tBuilder.setVlanId(VlanId.vlanId(segId));
541 break;
542 default:
543 break;
544 }
545
546 OutboundPacket packet = new DefaultOutboundPacket(
547 instPort.deviceId(),
548 tBuilder.build(),
549 ByteBuffer.wrap(icmpReply.serialize()));
550
551 packetService.emit(packet);
552 }
553
554 private short getIcmpId(ICMP icmp) {
555 return ((ICMPEcho) icmp.getPayload()).getIdentifier();
556 }
557 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900558}