blob: 3e4b5abcf78711bc0b46dffbea0cefa81c8d3ab9 [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.ExternalGateway;
Hyunsun Moon44aac662017-02-18 02:07:01 +090059import org.openstack4j.model.network.Port;
60import org.openstack4j.model.network.Router;
61import org.openstack4j.model.network.RouterInterface;
62import org.openstack4j.model.network.Subnet;
sangho36721992017-08-03 11:13:17 +090063import org.openstack4j.openstack.networking.domain.NeutronIP;
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;
sangho36721992017-08-03 11:13:17 +090073import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074import java.util.Set;
75import java.util.concurrent.ExecutorService;
76import java.util.stream.Collectors;
77
sangho247232c2017-08-24 17:22:08 +090078import static com.google.common.base.Preconditions.checkArgument;
Daniel Park4d486842018-07-24 17:06:43 +090079import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import static java.util.concurrent.Executors.newSingleThreadExecutor;
Daniel Park4d486842018-07-24 17:06:43 +090081import static org.onlab.packet.ICMP.TYPE_ECHO_REPLY;
82import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
Hyunsun Moon44aac662017-02-18 02:07:01 +090083import static org.onlab.util.Tools.groupedThreads;
sangho36721992017-08-03 11:13:17 +090084import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
Daniel Park6a2d95e2018-11-05 18:50:16 +090085import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
sangho36721992017-08-03 11:13:17 +090086import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Daniel Park6a2d95e2018-11-05 18:50:16 +090087import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
Hyunsun Moon0d457362017-06-27 17:19:41 +090088import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090089import static org.slf4j.LoggerFactory.getLogger;
90
Hyunsun Moon44aac662017-02-18 02:07:01 +090091/**
92 * Handles ICMP packet received from a gateway node.
93 * For a request for virtual network subnet gateway, it generates fake ICMP reply.
94 * For a request for the external network, it does source NAT with the public IP and
95 * forward the request to the external only if the requested virtual subnet has
96 * external connectivity.
97 */
98@Component(immediate = true)
99public class OpenstackRoutingIcmpHandler {
100
101 protected final Logger log = getLogger(getClass());
102
103 private static final String ERR_REQ = "Failed to handle ICMP request: ";
sangho247232c2017-08-24 17:22:08 +0900104 private static final String ERR_DUPLICATE = " already exists";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105
Jian Li28ec77f2018-10-31 07:07:25 +0900106 private static final String VXLAN = "VXLAN";
107 private static final String VLAN = "VLAN";
108
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)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125 protected OpenstackNetworkService osNetworkService;
126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128 protected OpenstackRouterService osRouterService;
129
Ray Milkey5739b2c2018-11-06 14:04:51 -0800130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900131 protected LeadershipService leadershipService;
132
Ray Milkey5739b2c2018-11-06 14:04:51 -0800133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900134 protected OpenstackFlowRuleService osFlowRuleService;
135
Ray Milkey5739b2c2018-11-06 14:04:51 -0800136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park6a2d95e2018-11-05 18:50:16 +0900137 protected ClusterService clusterService;
138
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 private final ExecutorService eventExecutor = newSingleThreadExecutor(
140 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
sangho072c4dd2017-05-17 10:45:21 +0900141 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
sangho247232c2017-08-24 17:22:08 +0900142 private ConsistentMap<String, InstancePort> icmpInfoMap;
Daniel Park6a2d95e2018-11-05 18:50:16 +0900143 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
sangho247232c2017-08-24 17:22:08 +0900144
145 private static final KryoNamespace SERIALIZER_ICMP_MAP = KryoNamespace.newBuilder()
146 .register(KryoNamespaces.API)
147 .register(InstancePort.class)
Jian Liec5c32b2018-07-13 14:28:58 +0900148 .register(DefaultInstancePort.class)
149 .register(InstancePort.State.class)
sangho247232c2017-08-24 17:22:08 +0900150 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151
152 private ApplicationId appId;
Daniel Park6a2d95e2018-11-05 18:50:16 +0900153 private NodeId localNodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900154
155 @Activate
156 protected void activate() {
157 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
158 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
Daniel Park6a2d95e2018-11-05 18:50:16 +0900159 localNodeId = clusterService.getLocalNode().id();
160 leadershipService.runForLeadership(appId.name());
161 osNodeService.addListener(osNodeListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162
sangho247232c2017-08-24 17:22:08 +0900163 icmpInfoMap = storageService.<String, InstancePort>consistentMapBuilder()
164 .withSerializer(Serializer.using(SERIALIZER_ICMP_MAP))
165 .withName("openstack-icmpmap")
166 .withApplicationId(appId)
167 .build();
168
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 log.info("Started");
170 }
171
172 @Deactivate
173 protected void deactivate() {
174 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 eventExecutor.shutdown();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900176 leadershipService.withdraw(appId.name());
177 osNodeService.removeListener(osNodeListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900178
179 log.info("Stopped");
180 }
181
Daniel Park6a2d95e2018-11-05 18:50:16 +0900182 private class InternalNodeEventListener implements OpenstackNodeListener {
183 @Override
184 public boolean isRelevant(OpenstackNodeEvent event) {
185 // do not allow to proceed without leadership
186 NodeId leader = leadershipService.getLeader(appId.name());
187 return Objects.equals(localNodeId, leader) && event.subject().type() == GATEWAY;
188 }
189
190 @Override
191 public void event(OpenstackNodeEvent event) {
192 OpenstackNode osNode = event.subject();
193 switch (event.type()) {
194 case OPENSTACK_NODE_COMPLETE:
195 eventExecutor.execute(() -> setIcmpReplyRules(osNode.intgBridge(), true));
196 break;
197 case OPENSTACK_NODE_INCOMPLETE:
198 eventExecutor.execute(() -> setIcmpReplyRules(osNode.intgBridge(), false));
199 break;
200 default:
201 break;
202 }
203 }
204
205 private void setIcmpReplyRules(DeviceId deviceId, boolean install) {
206 // Sends ICMP response to controller for SNATing ingress traffic
207 TrafficSelector selector = DefaultTrafficSelector.builder()
208 .matchEthType(Ethernet.TYPE_IPV4)
209 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
210 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
211 .build();
212
213 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
214 .punt()
215 .build();
216
217 osFlowRuleService.setRule(
218 appId,
219 deviceId,
220 selector,
221 treatment,
222 PRIORITY_INTERNAL_ROUTING_RULE,
223 GW_COMMON_TABLE,
224 install);
225 }
226 }
Jian Li28680442018-11-11 00:35:37 +0900227
228 private class InternalPacketProcessor implements PacketProcessor {
229
230 @Override
231 public void process(PacketContext context) {
232 if (context.isHandled()) {
233 return;
234 }
235
236 eventExecutor.execute(() -> {
237 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
238 .stream().map(OpenstackNode::intgBridge)
239 .collect(Collectors.toSet());
240
241 if (!gateways.isEmpty() &&
242 !gateways.contains(context.inPacket().receivedFrom().deviceId())) {
243 return;
244 }
245
246 InboundPacket pkt = context.inPacket();
247 Ethernet ethernet = pkt.parsed();
248 if (ethernet == null || ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
249 return;
250 }
251
252 IPv4 iPacket = (IPv4) ethernet.getPayload();
253
254 if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
255 processIcmpPacket(context, ethernet);
256 }
257 });
258 }
259
260 private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
261 IPv4 ipPacket = (IPv4) ethernet.getPayload();
262 ICMP icmp = (ICMP) ipPacket.getPayload();
263 log.trace("Processing ICMP packet source MAC:{}, source IP:{}," +
264 "dest MAC:{}, dest IP:{}",
265 ethernet.getSourceMAC(),
266 IpAddress.valueOf(ipPacket.getSourceAddress()),
267 ethernet.getDestinationMAC(),
268 IpAddress.valueOf(ipPacket.getDestinationAddress()));
269
270 switch (icmp.getIcmpType()) {
271 case TYPE_ECHO_REQUEST:
272 if (handleEchoRequest(context.inPacket().receivedFrom().deviceId(),
273 ethernet.getSourceMAC(),
274 ipPacket,
275 icmp)) {
276 context.block();
277 }
278 break;
279 case TYPE_ECHO_REPLY:
280 if (handleEchoReply(ipPacket, icmp)) {
281 context.block();
282 }
283 break;
284 default:
285 break;
286 }
287 }
288
289 private boolean handleEchoRequest(DeviceId srcDevice, MacAddress srcMac, IPv4 ipPacket,
290 ICMP icmp) {
291 //We only handles a request from an instance port
292 //In case of ehco request to SNAT ip address from an external router, we intentionally ignore it
293 InstancePort instPort = instancePortService.instancePort(srcMac);
294 if (instPort == null) {
295 log.warn(ERR_REQ + "unknown source host(MAC:{})", srcMac);
296 return false;
297 }
298
299 IpAddress srcIp = IpAddress.valueOf(ipPacket.getSourceAddress());
300 IpAddress dstIp = IpAddress.valueOf(ipPacket.getDestinationAddress());
301
302 Subnet srcSubnet = getSourceSubnet(instPort);
303 if (srcSubnet == null) {
304 log.warn(ERR_REQ + "unknown source subnet(IP:{})", srcIp);
305 return false;
306 }
307
308 if (Strings.isNullOrEmpty(srcSubnet.getGateway())) {
309 log.warn(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no gateway",
310 srcSubnet.getId(), srcSubnet.getCidr());
311 return false;
312 }
313
314 if (isForSubnetGateway(IpAddress.valueOf(ipPacket.getDestinationAddress()),
315 srcSubnet)) {
316 // this is a request to a subnet gateway
317 log.trace("Icmp request to gateway {} from {}", dstIp, srcIp);
318 processRequestForGateway(ipPacket, instPort);
319 } else {
320 // this is a request to an external network
321 log.trace("Icmp request to external {} from {}", dstIp, srcIp);
322
323 RouterInterface routerInterface = routerInterface(srcSubnet);
324 if (routerInterface == null) {
325 log.warn(ERR_REQ + "failed to get router interface");
326 return false;
327 }
328
329 ExternalGateway externalGateway = externalGateway(routerInterface);
330 if (externalGateway == null) {
331 log.warn(ERR_REQ + "failed to get external gateway");
332 return false;
333 }
334
335 ExternalPeerRouter externalPeerRouter = osNetworkService.externalPeerRouter(externalGateway);
336 if (externalPeerRouter == null) {
337 log.warn(ERR_REQ + "failed to get external peer router");
338 return false;
339 }
340
341 IpAddress externalIp = getExternalIp(externalGateway, routerInterface);
342 if (externalIp == null) {
343 log.warn(ERR_REQ + "failed to get external ip");
344 return false;
345 }
346
347 String icmpInfoKey = icmpInfoKey(icmp,
348 externalIp.toString(),
349 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()));
350 log.trace("Created icmpInfo key is {}", icmpInfoKey);
351
352 sendRequestForExternal(ipPacket, srcDevice, externalIp, externalPeerRouter);
353
354 try {
355 icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
356 checkArgument(existing == null, ERR_DUPLICATE);
357 return instPort;
358 });
359 } catch (IllegalArgumentException e) {
360 log.warn("IllegalArgumentException occurred because of {}", e.toString());
361 return false;
362 }
363 }
364 return true;
365 }
366
367 private String icmpInfoKey(ICMP icmp, String srcIp, String dstIp) {
368 return String.valueOf(getIcmpId(icmp))
369 .concat(srcIp)
370 .concat(dstIp);
371 }
372 private RouterInterface routerInterface(Subnet subnet) {
373 checkNotNull(subnet);
374 return osRouterService.routerInterfaces().stream()
375 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
376 .findAny().orElse(null);
377 }
378
379 private ExternalGateway externalGateway(RouterInterface osRouterIface) {
380 checkNotNull(osRouterIface);
381 Router osRouter = osRouterService.router(osRouterIface.getId());
382 if (osRouter == null) {
383 return null;
384 }
385 if (osRouter.getExternalGatewayInfo() == null) {
386 return null;
387 }
388 return osRouter.getExternalGatewayInfo();
389 }
390
391 private boolean handleEchoReply(IPv4 ipPacket, ICMP icmp) {
392 String icmpInfoKey = icmpInfoKey(icmp,
393 IPv4.fromIPv4Address(ipPacket.getDestinationAddress()),
394 IPv4.fromIPv4Address(ipPacket.getSourceAddress()));
395 log.trace("Retrieved icmpInfo key is {}", icmpInfoKey);
396
397 if (icmpInfoMap.get(icmpInfoKey) != null) {
398 processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey).value());
399 icmpInfoMap.remove(icmpInfoKey);
400 return true;
401 } else {
402 log.debug("No ICMP Info for ICMP packet");
403 return false;
404 }
405 }
406
407 private Subnet getSourceSubnet(InstancePort instance) {
408 checkNotNull(instance);
409
410 Port osPort = osNetworkService.port(instance.portId());
411 return osNetworkService.subnets(osPort.getNetworkId())
412 .stream().findAny().orElse(null);
413 }
414
415 private boolean isForSubnetGateway(IpAddress dstIp, Subnet srcSubnet) {
416 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
417 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
418 .findAny().orElse(null);
419 if (osRouterIface == null) {
420 log.trace(ERR_REQ + "source subnet(ID:{}, CIDR:{}) has no router",
421 srcSubnet.getId(), srcSubnet.getCidr());
422 return false;
423 }
424
425 Router osRouter = osRouterService.router(osRouterIface.getId());
426 Set<IpAddress> routableGateways = osRouterService.routerInterfaces(osRouter.getId())
427 .stream()
428 .map(iface -> osNetworkService.subnet(iface.getSubnetId()).getGateway())
429 .map(IpAddress::valueOf)
430 .collect(Collectors.toSet());
431
432 return routableGateways.contains(dstIp);
433 }
434
435 private IpAddress getExternalIp(ExternalGateway externalGateway, RouterInterface osRouterIface) {
436 checkNotNull(externalGateway);
437 checkNotNull(osRouterIface);
438
439 Router osRouter = osRouterService.router(osRouterIface.getId());
440 if (osRouter == null) {
441 return null;
442 }
443
444 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
445 .stream()
446 .filter(port -> Objects.equals(port.getDeviceId(), osRouter.getId()))
447 .findAny().orElse(null);
448 if (exGatewayPort == null) {
449 final String error = String.format(ERR_REQ +
450 "no external gateway port for router (ID:%s, name:%s)",
451 osRouter.getId(), osRouter.getName());
452 throw new IllegalStateException(error);
453 }
454 Optional<NeutronIP> externalIpAddress =
455 (Optional<NeutronIP>) exGatewayPort.getFixedIps().stream().findFirst();
456 if (!externalIpAddress.isPresent() || externalIpAddress.get().getIpAddress() == null) {
457 final String error = String.format(ERR_REQ +
458 "no external gateway IP address for router (ID:%s, name:%s)",
459 osRouter.getId(), osRouter.getName());
460 log.warn(error);
461 return null;
462 }
463
464 return IpAddress.valueOf(externalIpAddress.get().getIpAddress());
465 }
466
467 private void processRequestForGateway(IPv4 ipPacket, InstancePort instPort) {
468 ICMP icmpReq = (ICMP) ipPacket.getPayload();
469 icmpReq.setChecksum((short) 0);
470 icmpReq.setIcmpType(TYPE_ECHO_REPLY);
471
472 int destinationAddress = ipPacket.getSourceAddress();
473
474 ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
475 .setDestinationAddress(destinationAddress)
476 .resetChecksum();
477
478 ipPacket.setPayload(icmpReq);
479 Ethernet icmpReply = new Ethernet();
480 icmpReply.setEtherType(Ethernet.TYPE_IPV4)
481 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
482 .setDestinationMACAddress(instPort.macAddress())
483 .setPayload(ipPacket);
484
485 sendReply(icmpReply, instPort);
486 }
487
488 private void sendRequestForExternal(IPv4 ipPacket, DeviceId srcDevice,
489 IpAddress srcNatIp, ExternalPeerRouter externalPeerRouter) {
490 ICMP icmpReq = (ICMP) ipPacket.getPayload();
491 icmpReq.resetChecksum();
492 ipPacket.setSourceAddress(srcNatIp.getIp4Address().toInt()).resetChecksum();
493 ipPacket.setPayload(icmpReq);
494
495 Ethernet icmpRequestEth = new Ethernet();
496 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
497 .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
498 .setDestinationMACAddress(externalPeerRouter.macAddress());
499
500 if (!externalPeerRouter.vlanId().equals(VlanId.NONE)) {
501 icmpRequestEth.setVlanID(externalPeerRouter.vlanId().toShort());
502 }
503
504 icmpRequestEth.setPayload(ipPacket);
505
506 OpenstackNode osNode = osNodeService.node(srcDevice);
507 if (osNode == null) {
508 final String error = String.format("Cannot find openstack node for %s",
509 srcDevice);
510 throw new IllegalStateException(error);
511 }
512 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
513 .setOutput(osNode.uplinkPortNum())
514 .build();
515
516 OutboundPacket packet = new DefaultOutboundPacket(
517 srcDevice,
518 treatment,
519 ByteBuffer.wrap(icmpRequestEth.serialize()));
520
521 packetService.emit(packet);
522 }
523
524 private void processReplyFromExternal(IPv4 ipPacket, InstancePort instPort) {
525
526 if (instPort.networkId() == null) {
527 return;
528 }
529
530 ICMP icmpReply = (ICMP) ipPacket.getPayload();
531
532 icmpReply.resetChecksum();
533
534 ipPacket.setDestinationAddress(instPort.ipAddress().getIp4Address().toInt())
535 .resetChecksum();
536 ipPacket.setPayload(icmpReply);
537
538 Ethernet icmpResponseEth = new Ethernet();
539 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
540 .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
541 .setDestinationMACAddress(instPort.macAddress())
542 .setPayload(ipPacket);
543
544 sendReply(icmpResponseEth, instPort);
545 }
546
547 private void sendReply(Ethernet icmpReply, InstancePort instPort) {
548 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
549 .setOutput(instPort.portNumber());
550
551 String netId = instPort.networkId();
552 String segId = osNetworkService.segmentId(netId);
553
554 switch (osNetworkService.networkType(netId)) {
555 case VXLAN:
556 tBuilder.setTunnelId(Long.valueOf(segId));
557 break;
558 case VLAN:
559 tBuilder.setVlanId(VlanId.vlanId(segId));
560 break;
561 default:
562 break;
563 }
564
565 OutboundPacket packet = new DefaultOutboundPacket(
566 instPort.deviceId(),
567 tBuilder.build(),
568 ByteBuffer.wrap(icmpReply.serialize()));
569
570 packetService.emit(packet);
571 }
572
573 private short getIcmpId(ICMP icmp) {
574 return ((ICMPEcho) icmp.getPayload()).getIdentifier();
575 }
576 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900577}