sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 1 | /* |
Brian O'Connor | 5ab426f | 2016-04-09 01:19:45 -0700 | [diff] [blame] | 2 | * Copyright 2016-present Open Networking Laboratory |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +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 | */ |
sangho | 0c2a3da | 2016-02-16 13:39:07 +0900 | [diff] [blame] | 16 | package org.onosproject.openstacknetworking.switching; |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 17 | |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 18 | import org.onlab.packet.ARP; |
| 19 | import org.onlab.packet.Ethernet; |
| 20 | import org.onlab.packet.Ip4Address; |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 21 | import org.onlab.packet.IpAddress; |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 22 | import org.onlab.packet.MacAddress; |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 23 | import org.onosproject.net.Host; |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 24 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
| 25 | import org.onosproject.net.flow.TrafficTreatment; |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 26 | import org.onosproject.net.host.HostService; |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 27 | import org.onosproject.net.packet.DefaultOutboundPacket; |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 28 | import org.onosproject.net.packet.InboundPacket; |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 29 | import org.onosproject.net.packet.PacketService; |
sangho | 93447f1 | 2016-02-24 00:33:22 +0900 | [diff] [blame] | 30 | import org.onosproject.openstackinterface.OpenstackInterfaceService; |
| 31 | import org.onosproject.openstackinterface.OpenstackPort; |
sangho | 0c2a3da | 2016-02-16 13:39:07 +0900 | [diff] [blame] | 32 | import org.onosproject.openstacknetworking.OpenstackPortInfo; |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 33 | import org.slf4j.Logger; |
| 34 | import org.slf4j.LoggerFactory; |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 35 | import java.nio.ByteBuffer; |
Daniel Park | 3a06c52 | 2016-01-28 20:51:12 +0900 | [diff] [blame] | 36 | import java.util.Collection; |
sanghoshin | f25d2e0 | 2015-11-11 23:07:17 +0900 | [diff] [blame] | 37 | |
| 38 | import static com.google.common.base.Preconditions.checkNotNull; |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 39 | |
| 40 | /** |
sanghoshin | 46297d2 | 2015-11-03 17:51:24 +0900 | [diff] [blame] | 41 | * Handles ARP packet from VMs. |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 42 | */ |
| 43 | public class OpenstackArpHandler { |
| 44 | |
| 45 | private static Logger log = LoggerFactory |
| 46 | .getLogger(OpenstackArpHandler.class); |
Daniel Park | 3a06c52 | 2016-01-28 20:51:12 +0900 | [diff] [blame] | 47 | private static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f"); |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 48 | private PacketService packetService; |
sangho | 93447f1 | 2016-02-24 00:33:22 +0900 | [diff] [blame] | 49 | private OpenstackInterfaceService openstackService; |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 50 | private HostService hostService; |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 51 | |
| 52 | /** |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 53 | * Returns OpenstackArpHandler reference. |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 54 | * |
sangho | 0c2a3da | 2016-02-16 13:39:07 +0900 | [diff] [blame] | 55 | * @param openstackService OpenstackNetworkingService reference |
sanghoshin | f25d2e0 | 2015-11-11 23:07:17 +0900 | [diff] [blame] | 56 | * @param packetService PacketService reference |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 57 | * @param hostService host service |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 58 | */ |
sangho | 93447f1 | 2016-02-24 00:33:22 +0900 | [diff] [blame] | 59 | public OpenstackArpHandler(OpenstackInterfaceService openstackService, PacketService packetService, |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 60 | HostService hostService) { |
sangho | 0c2a3da | 2016-02-16 13:39:07 +0900 | [diff] [blame] | 61 | this.openstackService = openstackService; |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 62 | this.packetService = packetService; |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 63 | this.hostService = hostService; |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | /** |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 67 | * Processes ARP request packets. |
| 68 | * It checks if the target IP is owned by a known host first and then ask to |
| 69 | * OpenStack if it's not. This ARP proxy does not support overlapping IP. |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 70 | * |
| 71 | * @param pkt ARP request packet |
Hyunsun Moon | 0dba61f | 2016-03-03 14:05:21 -0800 | [diff] [blame] | 72 | * @param openstackPortInfoCollection collection of port information |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 73 | */ |
Daniel Park | 3a06c52 | 2016-01-28 20:51:12 +0900 | [diff] [blame] | 74 | public void processPacketIn(InboundPacket pkt, Collection<OpenstackPortInfo> openstackPortInfoCollection) { |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 75 | Ethernet ethRequest = pkt.parsed(); |
| 76 | ARP arp = (ARP) ethRequest.getPayload(); |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 77 | |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 78 | if (arp.getOpCode() != ARP.OP_REQUEST) { |
| 79 | return; |
| 80 | } |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 81 | |
Daniel Park | 3a06c52 | 2016-01-28 20:51:12 +0900 | [diff] [blame] | 82 | IpAddress sourceIp = Ip4Address.valueOf(arp.getSenderProtocolAddress()); |
| 83 | MacAddress srcMac = MacAddress.valueOf(arp.getSenderHardwareAddress()); |
| 84 | OpenstackPortInfo portInfo = openstackPortInfoCollection.stream() |
| 85 | .filter(p -> p.ip().equals(sourceIp) && p.mac().equals(srcMac)).findFirst().orElse(null); |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 86 | IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress()); |
Daniel Park | 3a06c52 | 2016-01-28 20:51:12 +0900 | [diff] [blame] | 87 | |
| 88 | MacAddress dstMac; |
| 89 | |
| 90 | if (targetIp.equals(portInfo == null ? null : portInfo.gatewayIP())) { |
| 91 | dstMac = GATEWAY_MAC; |
| 92 | } else { |
| 93 | dstMac = getMacFromHostService(targetIp); |
| 94 | if (dstMac == null) { |
| 95 | dstMac = getMacFromOpenstack(targetIp); |
| 96 | } |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 97 | } |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 98 | |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 99 | if (dstMac == null) { |
| 100 | log.debug("Failed to find MAC address for {}", targetIp.toString()); |
| 101 | return; |
| 102 | } |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 103 | |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 104 | Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(), |
| 105 | dstMac, |
| 106 | ethRequest); |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 107 | |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 108 | TrafficTreatment treatment = DefaultTrafficTreatment.builder() |
| 109 | .setOutput(pkt.receivedFrom().port()) |
| 110 | .build(); |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 111 | |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 112 | packetService.emit(new DefaultOutboundPacket( |
| 113 | pkt.receivedFrom().deviceId(), |
| 114 | treatment, |
| 115 | ByteBuffer.wrap(ethReply.serialize()))); |
| 116 | } |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 117 | |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 118 | /** |
| 119 | * Returns MAC address of a host with a given target IP address by asking to |
| 120 | * OpenStack. It does not support overlapping IP. |
| 121 | * |
| 122 | * @param targetIp target ip address |
| 123 | * @return mac address, or null if it fails to fetch the mac |
| 124 | */ |
| 125 | private MacAddress getMacFromOpenstack(IpAddress targetIp) { |
| 126 | checkNotNull(targetIp); |
| 127 | |
sangho | 0c2a3da | 2016-02-16 13:39:07 +0900 | [diff] [blame] | 128 | OpenstackPort openstackPort = openstackService.ports() |
Hyunsun Moon | c98e7c5 | 2016-01-11 02:54:27 -0800 | [diff] [blame] | 129 | .stream() |
| 130 | .filter(port -> port.fixedIps().containsValue(targetIp)) |
| 131 | .findFirst() |
| 132 | .orElse(null); |
| 133 | |
| 134 | if (openstackPort != null) { |
| 135 | log.debug("Found MAC from OpenStack for {}", targetIp.toString()); |
| 136 | return openstackPort.macAddress(); |
| 137 | } else { |
| 138 | return null; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | /** |
| 143 | * Returns MAC address of a host with a given target IP address by asking to |
| 144 | * host service. It does not support overlapping IP. |
| 145 | * |
| 146 | * @param targetIp target ip |
| 147 | * @return mac address, or null if it fails to find the mac |
| 148 | */ |
| 149 | private MacAddress getMacFromHostService(IpAddress targetIp) { |
| 150 | checkNotNull(targetIp); |
| 151 | |
| 152 | Host host = hostService.getHostsByIp(targetIp) |
| 153 | .stream() |
| 154 | .findFirst() |
| 155 | .orElse(null); |
| 156 | |
| 157 | if (host != null) { |
| 158 | log.debug("Found MAC from host service for {}", targetIp.toString()); |
| 159 | return host.mac(); |
| 160 | } else { |
| 161 | return null; |
daniel | bb83ebc | 2015-10-29 15:13:06 +0900 | [diff] [blame] | 162 | } |
sanghoshin | 94872a1 | 2015-10-16 18:04:34 +0900 | [diff] [blame] | 163 | } |
| 164 | } |