blob: b696525c199d945eabe581ebdc2cfebb0357979a [file] [log] [blame]
sangho80f11cb2015-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;
sangho80f11cb2015-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 Vavilapalli37a461b2015-04-07 15:12:32 -070038import java.util.List;
sangho80f11cb2015-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;
46 private NetworkConfigHandler config;
47
48 /**
49 * Creates an ArpHandler object.
50 *
51 * @param srManager SegmentRoutingManager object
52 */
53 public ArpHandler(SegmentRoutingManager srManager) {
54 this.srManager = srManager;
55 this.config = checkNotNull(srManager.networkConfigHandler);
56 }
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) {
91
92 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());
99 sendArpResponse(arpRequest, config.getRouterMac(targetAddress));
100
101 // ARP request for known hosts
102 } else if (srManager.hostService.getHost(targetHostId) != null) {
103 MacAddress targetMac = srManager.hostService.getHost(targetHostId).mac();
104 sendArpResponse(arpRequest, targetMac);
105
106 // ARP request for unknown host in the subnet
107 } else if (isArpReqForSubnet(deviceId, arpRequest)) {
108 flood(payload, inPort);
109 }
110 }
111
112
113 private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700114 List<Ip4Address> gatewayIpAddresses = config.getGatewayIpAddress(deviceId);
115 if (gatewayIpAddresses != null) {
sangho80f11cb2015-04-01 13:05:26 -0700116 Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
117 .getTargetProtocolAddress());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700118 if (gatewayIpAddresses.contains(targetProtocolAddress)) {
sangho80f11cb2015-04-01 13:05:26 -0700119 return true;
120 }
121 }
122 return false;
123 }
124
125 private boolean isArpReqForSubnet(DeviceId deviceId, ARP arpRequest) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700126 return config.getSubnetInfo(deviceId).stream()
127 .anyMatch((prefix)->
128 prefix.contains(Ip4Address.
129 valueOf(arpRequest.
130 getTargetProtocolAddress())));
sangho80f11cb2015-04-01 13:05:26 -0700131 }
132
133 /**
134 * Sends an APR request for the target IP address to all ports except in-port.
135 *
136 * @param deviceId Switch device ID
137 * @param targetAddress target IP address for ARP
138 * @param inPort in-port
139 */
140 public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
141
142 byte[] senderMacAddress = config.getRouterMacAddress(deviceId).toBytes();
143 byte[] senderIpAddress = config.getRouterIpAddress(deviceId)
144 .getIp4Prefix().address().toOctets();
145
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}