blob: 48398fd8d3db509cd7190b4ec91fcbfde12c482b [file] [log] [blame]
sanghoshin94872a12015-10-16 18:04:34 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002* Copyright 2016-present 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*/
sangho0c2a3da2016-02-16 13:39:07 +090016package org.onosproject.openstacknetworking.switching;
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;
sangho93447f12016-02-24 00:33:22 +090030import org.onosproject.openstackinterface.OpenstackInterfaceService;
31import org.onosproject.openstackinterface.OpenstackPort;
sangho0c2a3da2016-02-16 13:39:07 +090032import org.onosproject.openstacknetworking.OpenstackPortInfo;
sanghoshin94872a12015-10-16 18:04:34 +090033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
danielbb83ebc2015-10-29 15:13:06 +090035import java.nio.ByteBuffer;
Daniel Park3a06c522016-01-28 20:51:12 +090036import java.util.Collection;
sanghoshinf25d2e02015-11-11 23:07:17 +090037
38import static com.google.common.base.Preconditions.checkNotNull;
sanghoshin94872a12015-10-16 18:04:34 +090039
40/**
sanghoshin46297d22015-11-03 17:51:24 +090041 * Handles ARP packet from VMs.
sanghoshin94872a12015-10-16 18:04:34 +090042 */
43public class OpenstackArpHandler {
44
45 private static Logger log = LoggerFactory
46 .getLogger(OpenstackArpHandler.class);
Daniel Park3a06c522016-01-28 20:51:12 +090047 private static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
danielbb83ebc2015-10-29 15:13:06 +090048 private PacketService packetService;
sangho93447f12016-02-24 00:33:22 +090049 private OpenstackInterfaceService openstackService;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080050 private HostService hostService;
sanghoshin94872a12015-10-16 18:04:34 +090051
52 /**
danielbb83ebc2015-10-29 15:13:06 +090053 * Returns OpenstackArpHandler reference.
sanghoshin94872a12015-10-16 18:04:34 +090054 *
sangho0c2a3da2016-02-16 13:39:07 +090055 * @param openstackService OpenstackNetworkingService reference
sanghoshinf25d2e02015-11-11 23:07:17 +090056 * @param packetService PacketService reference
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080057 * @param hostService host service
sanghoshin94872a12015-10-16 18:04:34 +090058 */
sangho93447f12016-02-24 00:33:22 +090059 public OpenstackArpHandler(OpenstackInterfaceService openstackService, PacketService packetService,
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080060 HostService hostService) {
sangho0c2a3da2016-02-16 13:39:07 +090061 this.openstackService = openstackService;
danielbb83ebc2015-10-29 15:13:06 +090062 this.packetService = packetService;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080063 this.hostService = hostService;
sanghoshin94872a12015-10-16 18:04:34 +090064 }
65
66 /**
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080067 * 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.
sanghoshin94872a12015-10-16 18:04:34 +090070 *
71 * @param pkt ARP request packet
Hyunsun Moon0dba61f2016-03-03 14:05:21 -080072 * @param openstackPortInfoCollection collection of port information
sanghoshin94872a12015-10-16 18:04:34 +090073 */
Daniel Park3a06c522016-01-28 20:51:12 +090074 public void processPacketIn(InboundPacket pkt, Collection<OpenstackPortInfo> openstackPortInfoCollection) {
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080075 Ethernet ethRequest = pkt.parsed();
76 ARP arp = (ARP) ethRequest.getPayload();
danielbb83ebc2015-10-29 15:13:06 +090077
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080078 if (arp.getOpCode() != ARP.OP_REQUEST) {
79 return;
80 }
danielbb83ebc2015-10-29 15:13:06 +090081
Daniel Park3a06c522016-01-28 20:51:12 +090082 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 Moonc98e7c52016-01-11 02:54:27 -080086 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
Daniel Park3a06c522016-01-28 20:51:12 +090087
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 Moonc98e7c52016-01-11 02:54:27 -080097 }
danielbb83ebc2015-10-29 15:13:06 +090098
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080099 if (dstMac == null) {
100 log.debug("Failed to find MAC address for {}", targetIp.toString());
101 return;
102 }
danielbb83ebc2015-10-29 15:13:06 +0900103
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800104 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
105 dstMac,
106 ethRequest);
danielbb83ebc2015-10-29 15:13:06 +0900107
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800108 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
109 .setOutput(pkt.receivedFrom().port())
110 .build();
danielbb83ebc2015-10-29 15:13:06 +0900111
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800112 packetService.emit(new DefaultOutboundPacket(
113 pkt.receivedFrom().deviceId(),
114 treatment,
115 ByteBuffer.wrap(ethReply.serialize())));
116 }
danielbb83ebc2015-10-29 15:13:06 +0900117
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800118 /**
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
sangho0c2a3da2016-02-16 13:39:07 +0900128 OpenstackPort openstackPort = openstackService.ports()
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800129 .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;
danielbb83ebc2015-10-29 15:13:06 +0900162 }
sanghoshin94872a12015-10-16 18:04:34 +0900163 }
164}