blob: 7fb489a2440b1406659611f51bba43e5785a5b5c [file] [log] [blame]
sanghoshin94872a12015-10-16 18:04:34 +09001/*
Daniel Park3a06c522016-01-28 20:51:12 +09002* Copyright 2015-2016 Open Networking Laboratory
sanghoshin94872a12015-10-16 18:04:34 +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*/
Jian Li7f256f52016-01-24 15:08:05 -080016package org.onosproject.openstackswitching.impl;
sanghoshin94872a12015-10-16 18:04:34 +090017
danielbb83ebc2015-10-29 15:13:06 +090018import org.onlab.packet.ARP;
19import org.onlab.packet.Ethernet;
20import org.onlab.packet.Ip4Address;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080021import org.onlab.packet.IpAddress;
danielbb83ebc2015-10-29 15:13:06 +090022import org.onlab.packet.MacAddress;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080023import org.onosproject.net.Host;
danielbb83ebc2015-10-29 15:13:06 +090024import org.onosproject.net.flow.DefaultTrafficTreatment;
25import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080026import org.onosproject.net.host.HostService;
danielbb83ebc2015-10-29 15:13:06 +090027import org.onosproject.net.packet.DefaultOutboundPacket;
sanghoshin94872a12015-10-16 18:04:34 +090028import org.onosproject.net.packet.InboundPacket;
danielbb83ebc2015-10-29 15:13:06 +090029import org.onosproject.net.packet.PacketService;
Jian Li7f256f52016-01-24 15:08:05 -080030import org.onosproject.openstackswitching.OpenstackPort;
Daniel Park3a06c522016-01-28 20:51:12 +090031import org.onosproject.openstackswitching.OpenstackPortInfo;
sanghoshin94872a12015-10-16 18:04:34 +090032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
danielbb83ebc2015-10-29 15:13:06 +090034import java.nio.ByteBuffer;
Daniel Park3a06c522016-01-28 20:51:12 +090035import java.util.Collection;
sanghoshinf25d2e02015-11-11 23:07:17 +090036
37import static com.google.common.base.Preconditions.checkNotNull;
sanghoshin94872a12015-10-16 18:04:34 +090038
39/**
sanghoshin46297d22015-11-03 17:51:24 +090040 * Handles ARP packet from VMs.
sanghoshin94872a12015-10-16 18:04:34 +090041 */
42public class OpenstackArpHandler {
43
44 private static Logger log = LoggerFactory
45 .getLogger(OpenstackArpHandler.class);
Daniel Park3a06c522016-01-28 20:51:12 +090046 private static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
danielbb83ebc2015-10-29 15:13:06 +090047 private PacketService packetService;
sanghoshinf25d2e02015-11-11 23:07:17 +090048 private OpenstackRestHandler restHandler;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080049 private HostService hostService;
sanghoshin94872a12015-10-16 18:04:34 +090050
51 /**
danielbb83ebc2015-10-29 15:13:06 +090052 * Returns OpenstackArpHandler reference.
sanghoshin94872a12015-10-16 18:04:34 +090053 *
sanghoshinf25d2e02015-11-11 23:07:17 +090054 * @param restHandler rest API handler reference
55 * @param packetService PacketService reference
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080056 * @param hostService host service
sanghoshin94872a12015-10-16 18:04:34 +090057 */
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080058 public OpenstackArpHandler(OpenstackRestHandler restHandler, PacketService packetService,
59 HostService hostService) {
sanghoshinf25d2e02015-11-11 23:07:17 +090060 this.restHandler = checkNotNull(restHandler);
danielbb83ebc2015-10-29 15:13:06 +090061 this.packetService = packetService;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080062 this.hostService = hostService;
sanghoshin94872a12015-10-16 18:04:34 +090063 }
64
65 /**
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080066 * Processes ARP request packets.
67 * It checks if the target IP is owned by a known host first and then ask to
68 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
sanghoshin94872a12015-10-16 18:04:34 +090069 *
70 * @param pkt ARP request packet
71 */
Daniel Park3a06c522016-01-28 20:51:12 +090072 public void processPacketIn(InboundPacket pkt, Collection<OpenstackPortInfo> openstackPortInfoCollection) {
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080073 Ethernet ethRequest = pkt.parsed();
74 ARP arp = (ARP) ethRequest.getPayload();
danielbb83ebc2015-10-29 15:13:06 +090075
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080076 if (arp.getOpCode() != ARP.OP_REQUEST) {
77 return;
78 }
danielbb83ebc2015-10-29 15:13:06 +090079
Daniel Park3a06c522016-01-28 20:51:12 +090080 IpAddress sourceIp = Ip4Address.valueOf(arp.getSenderProtocolAddress());
81 MacAddress srcMac = MacAddress.valueOf(arp.getSenderHardwareAddress());
82 OpenstackPortInfo portInfo = openstackPortInfoCollection.stream()
83 .filter(p -> p.ip().equals(sourceIp) && p.mac().equals(srcMac)).findFirst().orElse(null);
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080084 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
Daniel Park3a06c522016-01-28 20:51:12 +090085
86 MacAddress dstMac;
87
88 if (targetIp.equals(portInfo == null ? null : portInfo.gatewayIP())) {
89 dstMac = GATEWAY_MAC;
90 } else {
91 dstMac = getMacFromHostService(targetIp);
92 if (dstMac == null) {
93 dstMac = getMacFromOpenstack(targetIp);
94 }
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080095 }
danielbb83ebc2015-10-29 15:13:06 +090096
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080097 if (dstMac == null) {
98 log.debug("Failed to find MAC address for {}", targetIp.toString());
99 return;
100 }
danielbb83ebc2015-10-29 15:13:06 +0900101
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800102 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
103 dstMac,
104 ethRequest);
danielbb83ebc2015-10-29 15:13:06 +0900105
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800106 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
107 .setOutput(pkt.receivedFrom().port())
108 .build();
danielbb83ebc2015-10-29 15:13:06 +0900109
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800110 packetService.emit(new DefaultOutboundPacket(
111 pkt.receivedFrom().deviceId(),
112 treatment,
113 ByteBuffer.wrap(ethReply.serialize())));
114 }
danielbb83ebc2015-10-29 15:13:06 +0900115
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800116 /**
117 * Returns MAC address of a host with a given target IP address by asking to
118 * OpenStack. It does not support overlapping IP.
119 *
120 * @param targetIp target ip address
121 * @return mac address, or null if it fails to fetch the mac
122 */
123 private MacAddress getMacFromOpenstack(IpAddress targetIp) {
124 checkNotNull(targetIp);
125
126 OpenstackPort openstackPort = restHandler.getPorts()
127 .stream()
128 .filter(port -> port.fixedIps().containsValue(targetIp))
129 .findFirst()
130 .orElse(null);
131
132 if (openstackPort != null) {
133 log.debug("Found MAC from OpenStack for {}", targetIp.toString());
134 return openstackPort.macAddress();
135 } else {
136 return null;
137 }
138 }
139
140 /**
141 * Returns MAC address of a host with a given target IP address by asking to
142 * host service. It does not support overlapping IP.
143 *
144 * @param targetIp target ip
145 * @return mac address, or null if it fails to find the mac
146 */
147 private MacAddress getMacFromHostService(IpAddress targetIp) {
148 checkNotNull(targetIp);
149
150 Host host = hostService.getHostsByIp(targetIp)
151 .stream()
152 .findFirst()
153 .orElse(null);
154
155 if (host != null) {
156 log.debug("Found MAC from host service for {}", targetIp.toString());
157 return host.mac();
158 } else {
159 return null;
danielbb83ebc2015-10-29 15:13:06 +0900160 }
sanghoshin94872a12015-10-16 18:04:34 +0900161 }
162}