blob: 36563f01b44009f15ba4eca0201c20735afc6e5c [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;
34import org.slf4j.Logger;
35import org.slf4j.LoggerFactory;
36
37import java.nio.ByteBuffer;
Saurav Das837e0bb2015-10-30 17:45:38 -070038import java.util.Set;
39
sanghob35a6192015-04-01 13:05:26 -070040import static com.google.common.base.Preconditions.checkNotNull;
41
42public class ArpHandler {
43
44 private static Logger log = LoggerFactory.getLogger(ArpHandler.class);
45
46 private SegmentRoutingManager srManager;
sangho666cd6d2015-04-14 16:27:13 -070047 private DeviceConfiguration config;
sanghob35a6192015-04-01 13:05:26 -070048
49 /**
50 * Creates an ArpHandler object.
51 *
52 * @param srManager SegmentRoutingManager object
53 */
54 public ArpHandler(SegmentRoutingManager srManager) {
55 this.srManager = srManager;
sangho666cd6d2015-04-14 16:27:13 -070056 this.config = checkNotNull(srManager.deviceConfiguration);
sanghob35a6192015-04-01 13:05:26 -070057 }
58
59 /**
60 * Processes incoming ARP packets.
61 * If it is an ARP request to router itself or known hosts,
62 * then it sends ARP response.
63 * If it is an ARP request to unknown hosts in its own subnet,
64 * then it flood the ARP request to the ports.
65 * If it is an ARP response, then set a flow rule for the host
66 * and forward any IP packets to the host in the packet buffer to the host.
67 *
68 * @param pkt incoming packet
69 */
70 public void processPacketIn(InboundPacket pkt) {
71
72 Ethernet ethernet = pkt.parsed();
73 ARP arp = (ARP) ethernet.getPayload();
74
75 ConnectPoint connectPoint = pkt.receivedFrom();
76 PortNumber inPort = connectPoint.port();
77 DeviceId deviceId = connectPoint.deviceId();
78 byte[] senderMacAddressByte = arp.getSenderHardwareAddress();
79 Ip4Address hostIpAddress = Ip4Address.valueOf(arp.getSenderProtocolAddress());
80
81 srManager.routingRulePopulator.populateIpRuleForHost(deviceId, hostIpAddress, MacAddress.
82 valueOf(senderMacAddressByte), inPort);
83
84 if (arp.getOpCode() == ARP.OP_REQUEST) {
85 handleArpRequest(deviceId, connectPoint, ethernet);
86 } else {
87 srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
88 }
89 }
90
91 private void handleArpRequest(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
sanghob35a6192015-04-01 13:05:26 -070092 ARP arpRequest = (ARP) payload.getPayload();
93 HostId targetHostId = HostId.hostId(MacAddress.valueOf(
94 arpRequest.getTargetHardwareAddress()));
95
96 // ARP request for router
97 if (isArpReqForRouter(deviceId, arpRequest)) {
98 Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
sanghob35a6192015-04-01 13:05:26 -070099
sangho666cd6d2015-04-14 16:27:13 -0700100 sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress));
Charles Chaneb088e62015-10-15 10:48:13 -0700101 } else {
102 Host targetHost = srManager.hostService.getHost(targetHostId);
103 // ARP request for known hosts
104 if (targetHost != null) {
105 sendArpResponse(arpRequest, targetHost.mac());
sanghob35a6192015-04-01 13:05:26 -0700106
Charles Chaneb088e62015-10-15 10:48:13 -0700107 // ARP request for unknown host in the subnet
108 } else if (isArpReqForSubnet(deviceId, arpRequest)) {
109 flood(payload, inPort);
110 }
sanghob35a6192015-04-01 13:05:26 -0700111 }
112 }
113
114
115 private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
Saurav Das837e0bb2015-10-30 17:45:38 -0700116 Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700117 if (gatewayIpAddresses != null) {
sanghob35a6192015-04-01 13:05:26 -0700118 Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
119 .getTargetProtocolAddress());
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700120 if (gatewayIpAddresses.contains(targetProtocolAddress)) {
sanghob35a6192015-04-01 13:05:26 -0700121 return true;
122 }
123 }
124 return false;
125 }
126
127 private boolean isArpReqForSubnet(DeviceId deviceId, ARP arpRequest) {
sangho666cd6d2015-04-14 16:27:13 -0700128 return config.getSubnets(deviceId).stream()
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700129 .anyMatch((prefix)->
130 prefix.contains(Ip4Address.
131 valueOf(arpRequest.
132 getTargetProtocolAddress())));
sanghob35a6192015-04-01 13:05:26 -0700133 }
134
135 /**
136 * Sends an APR request for the target IP address to all ports except in-port.
137 *
138 * @param deviceId Switch device ID
139 * @param targetAddress target IP address for ARP
140 * @param inPort in-port
141 */
142 public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
143
sangho666cd6d2015-04-14 16:27:13 -0700144 byte[] senderMacAddress = config.getDeviceMac(deviceId).toBytes();
145 byte[] senderIpAddress = config.getRouterIp(deviceId).toOctets();
sanghob35a6192015-04-01 13:05:26 -0700146
147 ARP arpRequest = new ARP();
148 arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
149 .setProtocolType(ARP.PROTO_TYPE_IP)
150 .setHardwareAddressLength(
151 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
152 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
153 .setOpCode(ARP.OP_REQUEST)
154 .setSenderHardwareAddress(senderMacAddress)
155 .setTargetHardwareAddress(MacAddress.ZERO.toBytes())
156 .setSenderProtocolAddress(senderIpAddress)
157 .setTargetProtocolAddress(targetAddress.toOctets());
158
159 Ethernet eth = new Ethernet();
160 eth.setDestinationMACAddress(MacAddress.BROADCAST.toBytes())
161 .setSourceMACAddress(senderMacAddress)
162 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
163
164 flood(eth, inPort);
165 }
166
167 private void sendArpResponse(ARP arpRequest, MacAddress targetMac) {
168
169 ARP arpReply = new ARP();
170 arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
171 .setProtocolType(ARP.PROTO_TYPE_IP)
172 .setHardwareAddressLength(
173 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
174 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
175 .setOpCode(ARP.OP_REPLY)
176 .setSenderHardwareAddress(targetMac.toBytes())
177 .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
178 .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
179 .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
180
181 Ethernet eth = new Ethernet();
182 eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
183 .setSourceMACAddress(targetMac.toBytes())
184 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
185
186
187 HostId dstId = HostId.hostId(MacAddress.valueOf(
188 arpReply.getTargetHardwareAddress()));
189 Host dst = srManager.hostService.getHost(dstId);
190 if (dst == null) {
191 log.warn("Cannot send ARP response to unknown device");
192 return;
193 }
194
195 TrafficTreatment treatment = DefaultTrafficTreatment.builder().
196 setOutput(dst.location().port()).build();
197 OutboundPacket packet = new DefaultOutboundPacket(dst.location().deviceId(),
198 treatment, ByteBuffer.wrap(eth.serialize()));
199
200 srManager.packetService.emit(packet);
201 }
202
203 private void flood(Ethernet request, ConnectPoint inPort) {
204 TrafficTreatment.Builder builder;
205 ByteBuffer buf = ByteBuffer.wrap(request.serialize());
206
207 for (Port port: srManager.deviceService.getPorts(inPort.deviceId())) {
208 if (!port.number().equals(inPort.port()) &&
209 port.number().toLong() > 0) {
210 builder = DefaultTrafficTreatment.builder();
211 builder.setOutput(port.number());
212 srManager.packetService.emit(new DefaultOutboundPacket(inPort.deviceId(),
213 builder.build(), buf));
214 }
215 }
216 }
217
218}