Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 1 | /* |
Brian O'Connor | 5ab426f | 2016-04-09 01:19:45 -0700 | [diff] [blame] | 2 | * Copyright 2016-present Open Networking Laboratory |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 3 | * |
| 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 | */ |
| 16 | package org.onosproject.openstacknetworking.routing; |
| 17 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 18 | import org.apache.felix.scr.annotations.Activate; |
| 19 | import org.apache.felix.scr.annotations.Component; |
| 20 | import org.apache.felix.scr.annotations.Deactivate; |
| 21 | import org.apache.felix.scr.annotations.Reference; |
| 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 23 | import org.onlab.packet.ARP; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 24 | import org.onlab.packet.Ethernet; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 25 | import org.onlab.packet.Ip4Address; |
| 26 | import org.onlab.packet.IpAddress; |
| 27 | import org.onlab.packet.MacAddress; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 28 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 29 | import org.onosproject.net.flow.TrafficTreatment; |
| 30 | import org.onosproject.net.packet.DefaultOutboundPacket; |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 31 | import org.onosproject.net.packet.InboundPacket; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 32 | import org.onosproject.net.packet.PacketContext; |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 33 | import org.onosproject.net.packet.PacketProcessor; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 34 | import org.onosproject.net.packet.PacketService; |
| 35 | import org.onosproject.openstackinterface.OpenstackInterfaceService; |
| 36 | import org.onosproject.openstackinterface.OpenstackPort; |
Kyuhwi Choi | 92d9ea4 | 2016-06-13 17:28:00 +0900 | [diff] [blame] | 37 | import org.onosproject.scalablegateway.api.ScalableGatewayService; |
sangho | 6032f34 | 2016-07-07 14:32:03 +0900 | [diff] [blame] | 38 | import org.onosproject.openstacknetworking.Constants; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 39 | import org.slf4j.Logger; |
| 40 | |
| 41 | import java.nio.ByteBuffer; |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 42 | import java.util.concurrent.ExecutorService; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 43 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 44 | import static java.util.concurrent.Executors.newSingleThreadExecutor; |
| 45 | import static org.onlab.util.Tools.groupedThreads; |
| 46 | import static org.onosproject.openstacknetworking.Constants.DEVICE_OWNER_FLOATING_IP; |
| 47 | import static org.onosproject.openstacknetworking.Constants.DEVICE_OWNER_ROUTER_GATEWAY; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 48 | import static org.slf4j.LoggerFactory.getLogger; |
| 49 | |
| 50 | /** |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 51 | * Handle ARP, ICMP and NAT packets from gateway nodes. |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 52 | */ |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 53 | @Component(immediate = true) |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 54 | public class OpenstackRoutingArpHandler { |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 55 | private final Logger log = getLogger(getClass()); |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 56 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 57 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 58 | protected PacketService packetService; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 59 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 60 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 61 | protected OpenstackInterfaceService openstackService; |
| 62 | |
| 63 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 64 | protected ScalableGatewayService gatewayService; |
| 65 | |
| 66 | private final ExecutorService executorService = |
| 67 | newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "packet-event", log)); |
| 68 | |
| 69 | private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor(); |
| 70 | |
| 71 | @Activate |
| 72 | protected void activate() { |
| 73 | packetService.addProcessor(packetProcessor, PacketProcessor.director(1)); |
| 74 | log.info("Started"); |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 75 | } |
| 76 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 77 | @Deactivate |
| 78 | protected void deactivate() { |
| 79 | packetService.removeProcessor(packetProcessor); |
| 80 | log.info("Stopped"); |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 81 | } |
| 82 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 83 | private void processArpPacket(PacketContext context, Ethernet ethernet) { |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 84 | ARP arp = (ARP) ethernet.getPayload(); |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 85 | log.trace("arpEvent called from {} to {}", |
Daniel Park | f78306f | 2016-04-06 17:57:48 +0900 | [diff] [blame] | 86 | Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(), |
| 87 | Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString()); |
| 88 | |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 89 | if (arp.getOpCode() != ARP.OP_REQUEST) { |
| 90 | return; |
| 91 | } |
| 92 | |
| 93 | IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress()); |
hyungseo Ryu | 38b5f18 | 2016-06-14 16:42:27 +0900 | [diff] [blame] | 94 | if (getTargetMacForTargetIp(targetIp.getIp4Address()) == MacAddress.NONE) { |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 95 | return; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 96 | } |
| 97 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 98 | MacAddress targetMac = Constants.DEFAULT_EXTERNAL_ROUTER_MAC; |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 99 | Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(), |
| 100 | targetMac, ethernet); |
| 101 | |
| 102 | TrafficTreatment treatment = DefaultTrafficTreatment.builder() |
| 103 | .setOutput(context.inPacket().receivedFrom().port()) |
| 104 | .build(); |
| 105 | |
| 106 | packetService.emit(new DefaultOutboundPacket( |
| 107 | context.inPacket().receivedFrom().deviceId(), |
| 108 | treatment, |
| 109 | ByteBuffer.wrap(ethReply.serialize()))); |
| 110 | } |
| 111 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 112 | private class InternalPacketProcessor implements PacketProcessor { |
| 113 | |
| 114 | @Override |
| 115 | public void process(PacketContext context) { |
| 116 | if (context.isHandled()) { |
| 117 | return; |
| 118 | } else if (!gatewayService.getGatewayDeviceIds().contains( |
| 119 | context.inPacket().receivedFrom().deviceId())) { |
| 120 | // return if the packet is not from gateway nodes |
| 121 | return; |
| 122 | } |
| 123 | |
| 124 | InboundPacket pkt = context.inPacket(); |
| 125 | Ethernet ethernet = pkt.parsed(); |
| 126 | if (ethernet != null && |
| 127 | ethernet.getEtherType() == Ethernet.TYPE_ARP) { |
| 128 | executorService.execute(() -> processArpPacket(context, ethernet)); |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | // TODO make a cache for the MAC, not a good idea to REST call every time it gets ARP request |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 134 | private MacAddress getTargetMacForTargetIp(Ip4Address targetIp) { |
| 135 | OpenstackPort port = openstackService.ports().stream() |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 136 | .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_GATEWAY) || |
| 137 | p.deviceOwner().equals(DEVICE_OWNER_FLOATING_IP)) |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 138 | .filter(p -> p.fixedIps().containsValue(targetIp.getIp4Address())) |
| 139 | .findAny().orElse(null); |
| 140 | |
Hyunsun Moon | b3eb84d | 2016-07-27 19:10:52 -0700 | [diff] [blame] | 141 | return port == null ? MacAddress.NONE : port.macAddress(); |
Kyuhwi Choi | 92d9ea4 | 2016-06-13 17:28:00 +0900 | [diff] [blame] | 142 | } |
Daniel Park | 81a61a1 | 2016-02-26 08:24:44 +0900 | [diff] [blame] | 143 | } |