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