blob: 3bbe98b12269c0cc96ef86f49a8ba8b5bcc0dbcf [file] [log] [blame]
sanghoshin94872a12015-10-16 18:04:34 +09001/*
2* Copyright 2015 Open Networking Laboratory
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*/
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;
sanghoshin94872a12015-10-16 18:04:34 +090031import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
danielbb83ebc2015-10-29 15:13:06 +090033import java.nio.ByteBuffer;
sanghoshinf25d2e02015-11-11 23:07:17 +090034
35import static com.google.common.base.Preconditions.checkNotNull;
sanghoshin94872a12015-10-16 18:04:34 +090036
37/**
sanghoshin46297d22015-11-03 17:51:24 +090038 * Handles ARP packet from VMs.
sanghoshin94872a12015-10-16 18:04:34 +090039 */
40public class OpenstackArpHandler {
41
42 private static Logger log = LoggerFactory
43 .getLogger(OpenstackArpHandler.class);
danielbb83ebc2015-10-29 15:13:06 +090044 private PacketService packetService;
sanghoshinf25d2e02015-11-11 23:07:17 +090045 private OpenstackRestHandler restHandler;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080046 private HostService hostService;
sanghoshin94872a12015-10-16 18:04:34 +090047
48 /**
danielbb83ebc2015-10-29 15:13:06 +090049 * Returns OpenstackArpHandler reference.
sanghoshin94872a12015-10-16 18:04:34 +090050 *
sanghoshinf25d2e02015-11-11 23:07:17 +090051 * @param restHandler rest API handler reference
52 * @param packetService PacketService reference
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080053 * @param hostService host service
sanghoshin94872a12015-10-16 18:04:34 +090054 */
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080055 public OpenstackArpHandler(OpenstackRestHandler restHandler, PacketService packetService,
56 HostService hostService) {
sanghoshinf25d2e02015-11-11 23:07:17 +090057 this.restHandler = checkNotNull(restHandler);
danielbb83ebc2015-10-29 15:13:06 +090058 this.packetService = packetService;
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080059 this.hostService = hostService;
sanghoshin94872a12015-10-16 18:04:34 +090060 }
61
62 /**
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080063 * Processes ARP request packets.
64 * It checks if the target IP is owned by a known host first and then ask to
65 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
sanghoshin94872a12015-10-16 18:04:34 +090066 *
67 * @param pkt ARP request packet
68 */
69 public void processPacketIn(InboundPacket pkt) {
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080070 Ethernet ethRequest = pkt.parsed();
71 ARP arp = (ARP) ethRequest.getPayload();
danielbb83ebc2015-10-29 15:13:06 +090072
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080073 if (arp.getOpCode() != ARP.OP_REQUEST) {
74 return;
75 }
danielbb83ebc2015-10-29 15:13:06 +090076
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080077 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
78 MacAddress dstMac = getMacFromHostService(targetIp);
79 if (dstMac == null) {
80 dstMac = getMacFromOpenstack(targetIp);
81 }
danielbb83ebc2015-10-29 15:13:06 +090082
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080083 if (dstMac == null) {
84 log.debug("Failed to find MAC address for {}", targetIp.toString());
85 return;
86 }
danielbb83ebc2015-10-29 15:13:06 +090087
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080088 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
89 dstMac,
90 ethRequest);
danielbb83ebc2015-10-29 15:13:06 +090091
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080092 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
93 .setOutput(pkt.receivedFrom().port())
94 .build();
danielbb83ebc2015-10-29 15:13:06 +090095
Hyunsun Moonc98e7c52016-01-11 02:54:27 -080096 packetService.emit(new DefaultOutboundPacket(
97 pkt.receivedFrom().deviceId(),
98 treatment,
99 ByteBuffer.wrap(ethReply.serialize())));
100 }
danielbb83ebc2015-10-29 15:13:06 +0900101
Hyunsun Moonc98e7c52016-01-11 02:54:27 -0800102 /**
103 * Returns MAC address of a host with a given target IP address by asking to
104 * OpenStack. It does not support overlapping IP.
105 *
106 * @param targetIp target ip address
107 * @return mac address, or null if it fails to fetch the mac
108 */
109 private MacAddress getMacFromOpenstack(IpAddress targetIp) {
110 checkNotNull(targetIp);
111
112 OpenstackPort openstackPort = restHandler.getPorts()
113 .stream()
114 .filter(port -> port.fixedIps().containsValue(targetIp))
115 .findFirst()
116 .orElse(null);
117
118 if (openstackPort != null) {
119 log.debug("Found MAC from OpenStack for {}", targetIp.toString());
120 return openstackPort.macAddress();
121 } else {
122 return null;
123 }
124 }
125
126 /**
127 * Returns MAC address of a host with a given target IP address by asking to
128 * host service. It does not support overlapping IP.
129 *
130 * @param targetIp target ip
131 * @return mac address, or null if it fails to find the mac
132 */
133 private MacAddress getMacFromHostService(IpAddress targetIp) {
134 checkNotNull(targetIp);
135
136 Host host = hostService.getHostsByIp(targetIp)
137 .stream()
138 .findFirst()
139 .orElse(null);
140
141 if (host != null) {
142 log.debug("Found MAC from host service for {}", targetIp.toString());
143 return host.mac();
144 } else {
145 return null;
danielbb83ebc2015-10-29 15:13:06 +0900146 }
sanghoshin94872a12015-10-16 18:04:34 +0900147 }
148}