blob: 96c85ba89c575a5469b7362c3871ca147a9fb43a [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -07001/*
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 */
16package org.onosproject.segmentrouting;
17
18import org.onlab.packet.ARP;
19import org.onlab.packet.Ethernet;
20import org.onlab.packet.Ip4Address;
21import org.onlab.packet.IpAddress;
sanghob35a6192015-04-01 13:05:26 -070022import org.onlab.packet.MacAddress;
23import org.onosproject.net.ConnectPoint;
24import org.onosproject.net.DeviceId;
25import org.onosproject.net.Host;
26import org.onosproject.net.Port;
27import org.onosproject.net.PortNumber;
28import org.onosproject.net.flow.DefaultTrafficTreatment;
29import org.onosproject.net.flow.TrafficTreatment;
30import org.onosproject.net.packet.DefaultOutboundPacket;
31import org.onosproject.net.packet.InboundPacket;
32import org.onosproject.net.HostId;
33import org.onosproject.net.packet.OutboundPacket;
Charles Chan0b4e6182015-11-03 10:42:14 -080034import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
35import org.onosproject.segmentrouting.config.DeviceConfiguration;
sanghob35a6192015-04-01 13:05:26 -070036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39import java.nio.ByteBuffer;
Saurav Das837e0bb2015-10-30 17:45:38 -070040import java.util.Set;
41
sanghob35a6192015-04-01 13:05:26 -070042import static com.google.common.base.Preconditions.checkNotNull;
43
44public class ArpHandler {
45
46 private static Logger log = LoggerFactory.getLogger(ArpHandler.class);
47
48 private SegmentRoutingManager srManager;
sangho666cd6d2015-04-14 16:27:13 -070049 private DeviceConfiguration config;
sanghob35a6192015-04-01 13:05:26 -070050
51 /**
52 * Creates an ArpHandler object.
53 *
54 * @param srManager SegmentRoutingManager object
55 */
56 public ArpHandler(SegmentRoutingManager srManager) {
57 this.srManager = srManager;
sangho666cd6d2015-04-14 16:27:13 -070058 this.config = checkNotNull(srManager.deviceConfiguration);
sanghob35a6192015-04-01 13:05:26 -070059 }
60
61 /**
62 * Processes incoming ARP packets.
63 * If it is an ARP request to router itself or known hosts,
64 * then it sends ARP response.
65 * If it is an ARP request to unknown hosts in its own subnet,
66 * then it flood the ARP request to the ports.
67 * If it is an ARP response, then set a flow rule for the host
68 * and forward any IP packets to the host in the packet buffer to the host.
69 *
70 * @param pkt incoming packet
71 */
72 public void processPacketIn(InboundPacket pkt) {
73
74 Ethernet ethernet = pkt.parsed();
75 ARP arp = (ARP) ethernet.getPayload();
76
77 ConnectPoint connectPoint = pkt.receivedFrom();
78 PortNumber inPort = connectPoint.port();
79 DeviceId deviceId = connectPoint.deviceId();
80 byte[] senderMacAddressByte = arp.getSenderHardwareAddress();
81 Ip4Address hostIpAddress = Ip4Address.valueOf(arp.getSenderProtocolAddress());
82
83 srManager.routingRulePopulator.populateIpRuleForHost(deviceId, hostIpAddress, MacAddress.
84 valueOf(senderMacAddressByte), inPort);
85
86 if (arp.getOpCode() == ARP.OP_REQUEST) {
87 handleArpRequest(deviceId, connectPoint, ethernet);
88 } else {
89 srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
90 }
91 }
92
93 private void handleArpRequest(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
sanghob35a6192015-04-01 13:05:26 -070094 ARP arpRequest = (ARP) payload.getPayload();
95 HostId targetHostId = HostId.hostId(MacAddress.valueOf(
96 arpRequest.getTargetHardwareAddress()));
97
98 // ARP request for router
99 if (isArpReqForRouter(deviceId, arpRequest)) {
100 Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
sanghob35a6192015-04-01 13:05:26 -0700101
sangho666cd6d2015-04-14 16:27:13 -0700102 sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress));
Charles Chaneb088e62015-10-15 10:48:13 -0700103 } else {
104 Host targetHost = srManager.hostService.getHost(targetHostId);
105 // ARP request for known hosts
106 if (targetHost != null) {
107 sendArpResponse(arpRequest, targetHost.mac());
sanghob35a6192015-04-01 13:05:26 -0700108
Charles Chaneb088e62015-10-15 10:48:13 -0700109 // ARP request for unknown host in the subnet
110 } else if (isArpReqForSubnet(deviceId, arpRequest)) {
111 flood(payload, inPort);
112 }
sanghob35a6192015-04-01 13:05:26 -0700113 }
114 }
115
116
117 private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700118 Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700119 if (gatewayIpAddresses != null) {
sanghob35a6192015-04-01 13:05:26 -0700120 Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
121 .getTargetProtocolAddress());
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700122 if (gatewayIpAddresses.contains(targetProtocolAddress)) {
sanghob35a6192015-04-01 13:05:26 -0700123 return true;
124 }
125 }
126 return false;
127 }
128
129 private boolean isArpReqForSubnet(DeviceId deviceId, ARP arpRequest) {
sangho666cd6d2015-04-14 16:27:13 -0700130 return config.getSubnets(deviceId).stream()
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700131 .anyMatch((prefix)->
132 prefix.contains(Ip4Address.
133 valueOf(arpRequest.
134 getTargetProtocolAddress())));
sanghob35a6192015-04-01 13:05:26 -0700135 }
136
137 /**
138 * Sends an APR request for the target IP address to all ports except in-port.
139 *
140 * @param deviceId Switch device ID
141 * @param targetAddress target IP address for ARP
142 * @param inPort in-port
143 */
144 public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
Charles Chan0b4e6182015-11-03 10:42:14 -0800145 byte[] senderMacAddress;
146 byte[] senderIpAddress;
sanghob35a6192015-04-01 13:05:26 -0700147
Charles Chan0b4e6182015-11-03 10:42:14 -0800148 try {
149 senderMacAddress = config.getDeviceMac(deviceId).toBytes();
150 senderIpAddress = config.getRouterIp(deviceId).toOctets();
151 } catch (DeviceConfigNotFoundException e) {
152 log.warn(e.getMessage() + " Aborting sendArpRequest.");
153 return;
154 }
sanghob35a6192015-04-01 13:05:26 -0700155
156 ARP arpRequest = new ARP();
157 arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
158 .setProtocolType(ARP.PROTO_TYPE_IP)
159 .setHardwareAddressLength(
160 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
161 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
162 .setOpCode(ARP.OP_REQUEST)
163 .setSenderHardwareAddress(senderMacAddress)
164 .setTargetHardwareAddress(MacAddress.ZERO.toBytes())
165 .setSenderProtocolAddress(senderIpAddress)
166 .setTargetProtocolAddress(targetAddress.toOctets());
167
168 Ethernet eth = new Ethernet();
169 eth.setDestinationMACAddress(MacAddress.BROADCAST.toBytes())
170 .setSourceMACAddress(senderMacAddress)
171 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
172
173 flood(eth, inPort);
174 }
175
176 private void sendArpResponse(ARP arpRequest, MacAddress targetMac) {
177
178 ARP arpReply = new ARP();
179 arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
180 .setProtocolType(ARP.PROTO_TYPE_IP)
181 .setHardwareAddressLength(
182 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
183 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
184 .setOpCode(ARP.OP_REPLY)
185 .setSenderHardwareAddress(targetMac.toBytes())
186 .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
187 .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
188 .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
189
190 Ethernet eth = new Ethernet();
191 eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
192 .setSourceMACAddress(targetMac.toBytes())
193 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
194
195
196 HostId dstId = HostId.hostId(MacAddress.valueOf(
197 arpReply.getTargetHardwareAddress()));
198 Host dst = srManager.hostService.getHost(dstId);
199 if (dst == null) {
200 log.warn("Cannot send ARP response to unknown device");
201 return;
202 }
203
204 TrafficTreatment treatment = DefaultTrafficTreatment.builder().
205 setOutput(dst.location().port()).build();
206 OutboundPacket packet = new DefaultOutboundPacket(dst.location().deviceId(),
207 treatment, ByteBuffer.wrap(eth.serialize()));
208
209 srManager.packetService.emit(packet);
210 }
211
212 private void flood(Ethernet request, ConnectPoint inPort) {
213 TrafficTreatment.Builder builder;
214 ByteBuffer buf = ByteBuffer.wrap(request.serialize());
215
216 for (Port port: srManager.deviceService.getPorts(inPort.deviceId())) {
217 if (!port.number().equals(inPort.port()) &&
218 port.number().toLong() > 0) {
219 builder = DefaultTrafficTreatment.builder();
220 builder.setOutput(port.number());
221 srManager.packetService.emit(new DefaultOutboundPacket(inPort.deviceId(),
222 builder.build(), buf));
223 }
224 }
225 }
226
227}