blob: 117312ac2fa275c71158c1c583f4748fdec23fc4 [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 Liebde74d2018-11-14 00:18:57 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalIpFromSubnet;
89import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterFromSubnet;
Jian Li25257212019-03-26 13:31:14 +090090import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Hyunsun Moon0d457362017-06-27 17:19:41 +090091import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090092import static org.slf4j.LoggerFactory.getLogger;
93
Hyunsun Moon44aac662017-02-18 02:07:01 +090094/**
95 * Handles ICMP packet received from a gateway node.
96 * For a request for virtual network subnet gateway, it generates fake ICMP reply.
97 * For a request for the external network, it does source NAT with the public IP and
98 * forward the request to the external only if the requested virtual subnet has
99 * external connectivity.
100 */
101@Component(immediate = true)
Jian Li25257212019-03-26 13:31:14 +0900102public class OpenstackRoutingSnatIcmpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103
104 protected final Logger log = getLogger(getClass());
105
106 private static final String ERR_REQ = "Failed to handle ICMP request: ";
sangho247232c2017-08-24 17:22:08 +0900107 private static final String ERR_DUPLICATE = " already exists";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900110 protected CoreService coreService;
111
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113 protected PacketService packetService;
114
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho247232c2017-08-24 17:22:08 +0900116 protected StorageService storageService;
117
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119 protected OpenstackNodeService osNodeService;
120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122 protected InstancePortService instancePortService;
123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li25257212019-03-26 13:31:14 +0900125 protected ComponentConfigService configService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128 protected OpenstackNetworkService osNetworkService;
129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131 protected OpenstackRouterService osRouterService;
132
Ray Milkey5739b2c2018-11-06 14:04:51 -0800133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900134 protected LeadershipService leadershipService;
135
Ray Milkey5739b2c2018-11-06 14:04:51 -0800136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900137 protected OpenstackFlowRuleService osFlowRuleService;
138
Ray Milkey5739b2c2018-11-06 14:04:51 -0800139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900140 protected ClusterService clusterService;
141
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 private final ExecutorService eventExecutor = newSingleThreadExecutor(
143 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
sangho072c4dd2017-05-17 10:45:21 +0900144 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
sangho247232c2017-08-24 17:22:08 +0900145 private ConsistentMap<String, InstancePort> icmpInfoMap;
Daniel Park6a2d95e2018-11-05 18:50:16 +0900146 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
sangho247232c2017-08-24 17:22:08 +0900147
148 private static final KryoNamespace SERIALIZER_ICMP_MAP = KryoNamespace.newBuilder()
149 .register(KryoNamespaces.API)
150 .register(InstancePort.class)
Jian Liec5c32b2018-07-13 14:28:58 +0900151 .register(DefaultInstancePort.class)
152 .register(InstancePort.State.class)
sangho247232c2017-08-24 17:22:08 +0900153 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900154
155 private ApplicationId appId;
Daniel Park6a2d95e2018-11-05 18:50:16 +0900156 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157
158 @Activate
159 protected void activate() {
160 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
161 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900162 localNodeId = clusterService.getLocalNode().id();
163 leadershipService.runForLeadership(appId.name());
164 osNodeService.addListener(osNodeListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165
sangho247232c2017-08-24 17:22:08 +0900166 icmpInfoMap = storageService.<String, InstancePort>consistentMapBuilder()
167 .withSerializer(Serializer.using(SERIALIZER_ICMP_MAP))
168 .withName("openstack-icmpmap")
169 .withApplicationId(appId)
170 .build();
171
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172 log.info("Started");
173 }
174
175 @Deactivate
176 protected void deactivate() {
177 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900178 eventExecutor.shutdown();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900179 leadershipService.withdraw(appId.name());
180 osNodeService.removeListener(osNodeListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181
182 log.info("Stopped");
183 }
184
Jian Li25257212019-03-26 13:31:14 +0900185 private boolean getStatefulSnatFlag() {
186 Set<ConfigProperty> properties = configService.getProperties(OpenstackRoutingSnatHandler.class.getName());
187 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
188 }
189
Daniel Park6a2d95e2018-11-05 18:50:16 +0900190 private class InternalNodeEventListener implements OpenstackNodeListener {
191 @Override
192 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Lifdb8d872019-04-08 10:38:58 +0900193 return event.subject().type() == GATEWAY;
Jian Li34220ea2018-11-14 01:30:24 +0900194 }
195
196 private boolean isRelevantHelper() {
197 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900198 }
199
200 @Override
201 public void event(OpenstackNodeEvent event) {
202 OpenstackNode osNode = event.subject();
203 switch (event.type()) {
204 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900205 eventExecutor.execute(() -> processNodeCompletion(osNode));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900206 break;
207 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900208 eventExecutor.execute(() -> processNodeInCompletion(osNode));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900209 break;
210 default:
211 break;
212 }
213 }
214
Jian Li6a47fd02018-11-27 21:51:03 +0900215 private void processNodeCompletion(OpenstackNode osNode) {
216 if (!isRelevantHelper()) {
217 return;
218 }
219
220 setIcmpReplyRules(osNode.intgBridge(), true);
221 }
222
223 private void processNodeInCompletion(OpenstackNode osNode) {
224 if (!isRelevantHelper()) {
225 return;
226 }
227
228 setIcmpReplyRules(osNode.intgBridge(), false);
229 }
230
Daniel Park6a2d95e2018-11-05 18:50:16 +0900231 private void setIcmpReplyRules(DeviceId deviceId, boolean install) {
232 // Sends ICMP response to controller for SNATing ingress traffic
233 TrafficSelector selector = DefaultTrafficSelector.builder()
234 .matchEthType(Ethernet.TYPE_IPV4)
235 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
236 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
237 .build();
238
239 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
240 .punt()
241 .build();
242
243 osFlowRuleService.setRule(
244 appId,
245 deviceId,
246 selector,
247 treatment,
248 PRIORITY_INTERNAL_ROUTING_RULE,
249 GW_COMMON_TABLE,
250 install);
251 }
252 }
Jian Li28680442018-11-11 00:35:37 +0900253
254 private class InternalPacketProcessor implements PacketProcessor {
255
256 @Override
257 public void process(PacketContext context) {
258 if (context.isHandled()) {
259 return;
260 }
261
262 eventExecutor.execute(() -> {
Jian Li28680442018-11-11 00:35:37 +0900263
Jian Li34220ea2018-11-14 01:30:24 +0900264 if (!isRelevantHelper(context)) {
Jian Li28680442018-11-11 00:35:37 +0900265 return;
266 }
267
268 InboundPacket pkt = context.inPacket();
269 Ethernet ethernet = pkt.parsed();
270 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
271 return;
272 }
273
274 IPv4 iPacket = (IPv4) ethernet.getPayload();
275
276 if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
277 processIcmpPacket(context, ethernet);
278 }
279 });
280 }
281
Jian Li34220ea2018-11-14 01:30:24 +0900282 private boolean isRelevantHelper(PacketContext context) {
283 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
284 .stream().map(OpenstackNode::intgBridge)
285 .collect(Collectors.toSet());
286
287 return gateways.contains(context.inPacket().receivedFrom().deviceId());
288 }
289
Jian Li28680442018-11-11 00:35:37 +0900290 private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
291 IPv4 ipPacket = (IPv4) ethernet.getPayload();
292 ICMP icmp = (ICMP) ipPacket.getPayload();
293 log.trace("Processing ICMP packet source MAC:{}, source IP:{}," +
294 "dest MAC:{}, dest IP:{}",
295 ethernet.getSourceMAC(),
296 IpAddress.valueOf(ipPacket.getSourceAddress()),
297 ethernet.getDestinationMAC(),
298 IpAddress.valueOf(ipPacket.getDestinationAddress()));
299
300 switch (icmp.getIcmpType()) {
301 case TYPE_ECHO_REQUEST:
302 if (handleEchoRequest(context.inPacket().receivedFrom().deviceId(),
Jian Li6a47fd02018-11-27 21:51:03 +0900303 ethernet.getSourceMAC(), ipPacket, icmp)) {
Jian Li28680442018-11-11 00:35:37 +0900304 context.block();
305 }
306 break;
307 case TYPE_ECHO_REPLY:
308 if (handleEchoReply(ipPacket, icmp)) {
309 context.block();
310 }
311 break;
312 default:
313 break;
314 }
315 }
316
317 private boolean handleEchoRequest(DeviceId srcDevice, MacAddress srcMac, IPv4 ipPacket,
318 ICMP icmp) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900319 // we only handles a request from an instance port
320 // in case of ehco request to SNAT ip address from an external router,
321 // we intentionally ignore it
Jian Li28680442018-11-11 00:35:37 +0900322 InstancePort instPort = instancePortService.instancePort(srcMac);
323 if (instPort == null) {
324 log.warn(ERR_REQ + "unknown source host(MAC:{})", srcMac);
325 return false;
326 }
327
328 IpAddress srcIp = IpAddress.valueOf(ipPacket.getSourceAddress());
329 IpAddress dstIp = IpAddress.valueOf(ipPacket.getDestinationAddress());
330
331 Subnet srcSubnet = getSourceSubnet(instPort);
332 if (srcSubnet == null) {
333 log.warn(ERR_REQ + "unknown source subnet(IP:{})", srcIp);
334 return false;
335 }
336
337 if (Strings.isNullOrEmpty(srcSubnet.getGateway())) {
338 log.warn(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no gateway",
339 srcSubnet.getId(), srcSubnet.getCidr());
340 return false;
341 }
342
343 if (isForSubnetGateway(IpAddress.valueOf(ipPacket.getDestinationAddress()),
344 srcSubnet)) {
345 // this is a request to a subnet gateway
346 log.trace("Icmp request to gateway {} from {}", dstIp, srcIp);
347 processRequestForGateway(ipPacket, instPort);
348 } else {
349 // this is a request to an external network
350 log.trace("Icmp request to external {} from {}", dstIp, srcIp);
351
Jian Li5ecfd1a2018-12-10 11:41:03 +0900352 IpAddress externalIp = externalIpFromSubnet(srcSubnet,
353 osRouterService, osNetworkService);
Jian Li28680442018-11-11 00:35:37 +0900354 if (externalIp == null) {
355 log.warn(ERR_REQ + "failed to get external ip");
356 return false;
357 }
358
Jian Liebde74d2018-11-14 00:18:57 +0900359 ExternalPeerRouter externalPeerRouter =
Jian Li5ecfd1a2018-12-10 11:41:03 +0900360 externalPeerRouterFromSubnet(srcSubnet,
361 osRouterService, osNetworkService);
Jian Liebde74d2018-11-14 00:18:57 +0900362 if (externalPeerRouter == null) {
363 log.warn(ERR_REQ + "failed to get external peer router");
364 return false;
365 }
366
Jian Li28680442018-11-11 00:35:37 +0900367 String icmpInfoKey = icmpInfoKey(icmp,
368 externalIp.toString(),
369 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()));
370 log.trace("Created icmpInfo key is {}", icmpInfoKey);
371
372 sendRequestForExternal(ipPacket, srcDevice, externalIp, externalPeerRouter);
373
374 try {
375 icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
376 checkArgument(existing == null, ERR_DUPLICATE);
377 return instPort;
378 });
379 } catch (IllegalArgumentException e) {
380 log.warn("IllegalArgumentException occurred because of {}", e.toString());
381 return false;
382 }
383 }
384 return true;
385 }
386
387 private String icmpInfoKey(ICMP icmp, String srcIp, String dstIp) {
388 return String.valueOf(getIcmpId(icmp))
389 .concat(srcIp)
390 .concat(dstIp);
391 }
Jian Li28680442018-11-11 00:35:37 +0900392
393 private boolean handleEchoReply(IPv4 ipPacket, ICMP icmp) {
394 String icmpInfoKey = icmpInfoKey(icmp,
395 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()),
396 IPv4.fromIPv4Address(ipPacket.getSourceAddress()));
397 log.trace("Retrieved icmpInfo key is {}", icmpInfoKey);
398
399 if (icmpInfoMap.get(icmpInfoKey) != null) {
400 processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey).value());
401 icmpInfoMap.remove(icmpInfoKey);
402 return true;
403 } else {
404 log.debug("No ICMP Info for ICMP packet");
405 return false;
406 }
407 }
408
409 private Subnet getSourceSubnet(InstancePort instance) {
410 checkNotNull(instance);
411
412 Port osPort = osNetworkService.port(instance.portId());
413 return osNetworkService.subnets(osPort.getNetworkId())
414 .stream().findAny().orElse(null);
415 }
416
417 private boolean isForSubnetGateway(IpAddress dstIp, Subnet srcSubnet) {
418 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
419 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
420 .findAny().orElse(null);
421 if (osRouterIface == null) {
422 log.trace(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no router",
423 srcSubnet.getId(), srcSubnet.getCidr());
424 return false;
425 }
426
427 Router osRouter = osRouterService.router(osRouterIface.getId());
Jian Li5ecfd1a2018-12-10 11:41:03 +0900428 Set<IpAddress> routableGateways =
429 osRouterService.routerInterfaces(osRouter.getId())
Jian Li28680442018-11-11 00:35:37 +0900430 .stream()
431 .map(iface -> osNetworkService.subnet(iface.getSubnetId()).getGateway())
432 .map(IpAddress::valueOf)
433 .collect(Collectors.toSet());
434
435 return routableGateways.contains(dstIp);
436 }
437
Jian Li28680442018-11-11 00:35:37 +0900438 private void processRequestForGateway(IPv4 ipPacket, InstancePort instPort) {
439 ICMP icmpReq = (ICMP) ipPacket.getPayload();
440 icmpReq.setChecksum((short) 0);
441 icmpReq.setIcmpType(TYPE_ECHO_REPLY);
442
443 int destinationAddress = ipPacket.getSourceAddress();
444
445 ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
446 .setDestinationAddress(destinationAddress)
447 .resetChecksum();
448
449 ipPacket.setPayload(icmpReq);
450 Ethernet icmpReply = new Ethernet();
451 icmpReply.setEtherType(Ethernet.TYPE_IPV4)
452 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
453 .setDestinationMACAddress(instPort.macAddress())
454 .setPayload(ipPacket);
455
456 sendReply(icmpReply, instPort);
457 }
458
Jian Li5ecfd1a2018-12-10 11:41:03 +0900459 private void sendRequestForExternal(IPv4 ipPacket,
460 DeviceId srcDevice,
461 IpAddress srcNatIp,
462 ExternalPeerRouter externalPeerRouter) {
Jian Li28680442018-11-11 00:35:37 +0900463 ICMP icmpReq = (ICMP) ipPacket.getPayload();
464 icmpReq.resetChecksum();
465 ipPacket.setSourceAddress(srcNatIp.getIp4Address().toInt()).resetChecksum();
466 ipPacket.setPayload(icmpReq);
467
468 Ethernet icmpRequestEth = new Ethernet();
469 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
470 .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
471 .setDestinationMACAddress(externalPeerRouter.macAddress());
472
473 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
474 icmpRequestEth.setVlanID(externalPeerRouter.vlanId().toShort());
475 }
476
477 icmpRequestEth.setPayload(ipPacket);
478
479 OpenstackNode osNode = osNodeService.node(srcDevice);
480 if (osNode == null) {
481 final String error = String.format("Cannot find openstack node for %s",
482 srcDevice);
483 throw new IllegalStateException(error);
484 }
485 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
486 .setOutput(osNode.uplinkPortNum())
487 .build();
488
489 OutboundPacket packet = new DefaultOutboundPacket(
490 srcDevice,
491 treatment,
492 ByteBuffer.wrap(icmpRequestEth.serialize()));
493
494 packetService.emit(packet);
495 }
496
497 private void processReplyFromExternal(IPv4 ipPacket, InstancePort instPort) {
498
499 if (instPort.networkId() == null) {
500 return;
501 }
502
503 ICMP icmpReply = (ICMP) ipPacket.getPayload();
504
505 icmpReply.resetChecksum();
506
507 ipPacket.setDestinationAddress(instPort.ipAddress().getIp4Address().toInt())
508 .resetChecksum();
509 ipPacket.setPayload(icmpReply);
510
511 Ethernet icmpResponseEth = new Ethernet();
512 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
513 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
514 .setDestinationMACAddress(instPort.macAddress())
515 .setPayload(ipPacket);
516
517 sendReply(icmpResponseEth, instPort);
518 }
519
520 private void sendReply(Ethernet icmpReply, InstancePort instPort) {
521 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
522 .setOutput(instPort.portNumber());
523
524 String netId = instPort.networkId();
525 String segId = osNetworkService.segmentId(netId);
526
527 switch (osNetworkService.networkType(netId)) {
528 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900529 case GRE:
Jian Li25257212019-03-26 13:31:14 +0900530 case GENEVE:
Jian Li28680442018-11-11 00:35:37 +0900531 tBuilder.setTunnelId(Long.valueOf(segId));
532 break;
533 case VLAN:
534 tBuilder.setVlanId(VlanId.vlanId(segId));
535 break;
536 default:
537 break;
538 }
539
540 OutboundPacket packet = new DefaultOutboundPacket(
541 instPort.deviceId(),
542 tBuilder.build(),
543 ByteBuffer.wrap(icmpReply.serialize()));
544
545 packetService.emit(packet);
546 }
547
548 private short getIcmpId(ICMP icmp) {
549 return ((ICMPEcho) icmp.getPayload()).getIdentifier();
550 }
551 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900552}