blob: 5b94518762672cca7f82a06ce9b74674102b4939 [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;
22import org.onlab.packet.IpPrefix;
23import org.onlab.packet.MacAddress;
24import org.onosproject.net.ConnectPoint;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.Host;
27import org.onosproject.net.Port;
28import org.onosproject.net.PortNumber;
29import org.onosproject.net.flow.DefaultTrafficTreatment;
30import org.onosproject.net.flow.TrafficTreatment;
31import org.onosproject.net.packet.DefaultOutboundPacket;
32import org.onosproject.net.packet.InboundPacket;
33import org.onosproject.net.HostId;
34import org.onosproject.net.packet.OutboundPacket;
35import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
38import java.nio.ByteBuffer;
39
40import 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;
47 private NetworkConfigHandler config;
48
49 /**
50 * Creates an ArpHandler object.
51 *
52 * @param srManager SegmentRoutingManager object
53 */
54 public ArpHandler(SegmentRoutingManager srManager) {
55 this.srManager = srManager;
56 this.config = checkNotNull(srManager.networkConfigHandler);
57 }
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) {
92
93 ARP arpRequest = (ARP) payload.getPayload();
94 HostId targetHostId = HostId.hostId(MacAddress.valueOf(
95 arpRequest.getTargetHardwareAddress()));
96
97 // ARP request for router
98 if (isArpReqForRouter(deviceId, arpRequest)) {
99 Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
100 sendArpResponse(arpRequest, config.getRouterMac(targetAddress));
101
102 // ARP request for known hosts
103 } else if (srManager.hostService.getHost(targetHostId) != null) {
104 MacAddress targetMac = srManager.hostService.getHost(targetHostId).mac();
105 sendArpResponse(arpRequest, targetMac);
106
107 // ARP request for unknown host in the subnet
108 } else if (isArpReqForSubnet(deviceId, arpRequest)) {
109 flood(payload, inPort);
110 }
111 }
112
113
114 private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
115 Ip4Address gatewayIpAddress = config.getGatewayIpAddress(deviceId);
116 if (gatewayIpAddress != null) {
117 Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
118 .getTargetProtocolAddress());
119 if (gatewayIpAddress.equals(targetProtocolAddress)) {
120 return true;
121 }
122 }
123 return false;
124 }
125
126 private boolean isArpReqForSubnet(DeviceId deviceId, ARP arpRequest) {
127 String subnetInfo = config.getSubnetInfo(deviceId);
128 if (subnetInfo != null) {
129 IpPrefix prefix = IpPrefix.valueOf(subnetInfo);
130 if (prefix.contains(Ip4Address.valueOf(arpRequest.getTargetProtocolAddress()))) {
131 return true;
132 }
133 }
134
135 return false;
136 }
137
138 /**
139 * Sends an APR request for the target IP address to all ports except in-port.
140 *
141 * @param deviceId Switch device ID
142 * @param targetAddress target IP address for ARP
143 * @param inPort in-port
144 */
145 public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
146
147 byte[] senderMacAddress = config.getRouterMacAddress(deviceId).toBytes();
148 byte[] senderIpAddress = config.getRouterIpAddress(deviceId)
149 .getIp4Prefix().address().toOctets();
150
151 ARP arpRequest = new ARP();
152 arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
153 .setProtocolType(ARP.PROTO_TYPE_IP)
154 .setHardwareAddressLength(
155 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
156 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
157 .setOpCode(ARP.OP_REQUEST)
158 .setSenderHardwareAddress(senderMacAddress)
159 .setTargetHardwareAddress(MacAddress.ZERO.toBytes())
160 .setSenderProtocolAddress(senderIpAddress)
161 .setTargetProtocolAddress(targetAddress.toOctets());
162
163 Ethernet eth = new Ethernet();
164 eth.setDestinationMACAddress(MacAddress.BROADCAST.toBytes())
165 .setSourceMACAddress(senderMacAddress)
166 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
167
168 flood(eth, inPort);
169 }
170
171 private void sendArpResponse(ARP arpRequest, MacAddress targetMac) {
172
173 ARP arpReply = new ARP();
174 arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
175 .setProtocolType(ARP.PROTO_TYPE_IP)
176 .setHardwareAddressLength(
177 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
178 .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
179 .setOpCode(ARP.OP_REPLY)
180 .setSenderHardwareAddress(targetMac.toBytes())
181 .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
182 .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
183 .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
184
185 Ethernet eth = new Ethernet();
186 eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
187 .setSourceMACAddress(targetMac.toBytes())
188 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
189
190
191 HostId dstId = HostId.hostId(MacAddress.valueOf(
192 arpReply.getTargetHardwareAddress()));
193 Host dst = srManager.hostService.getHost(dstId);
194 if (dst == null) {
195 log.warn("Cannot send ARP response to unknown device");
196 return;
197 }
198
199 TrafficTreatment treatment = DefaultTrafficTreatment.builder().
200 setOutput(dst.location().port()).build();
201 OutboundPacket packet = new DefaultOutboundPacket(dst.location().deviceId(),
202 treatment, ByteBuffer.wrap(eth.serialize()));
203
204 srManager.packetService.emit(packet);
205 }
206
207 private void flood(Ethernet request, ConnectPoint inPort) {
208 TrafficTreatment.Builder builder;
209 ByteBuffer buf = ByteBuffer.wrap(request.serialize());
210
211 for (Port port: srManager.deviceService.getPorts(inPort.deviceId())) {
212 if (!port.number().equals(inPort.port()) &&
213 port.number().toLong() > 0) {
214 builder = DefaultTrafficTreatment.builder();
215 builder.setOutput(port.number());
216 srManager.packetService.emit(new DefaultOutboundPacket(inPort.deviceId(),
217 builder.build(), buf));
218 }
219 }
220 }
221
222}