blob: 5befa5bb8fab9ce3797c2ae752fb51f36d33d2dc [file] [log] [blame]
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -07001/*******************************************************************************
2 * Copyright (c) 2014 Open Networking Laboratory.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Apache License v2.0
5 * which accompanies this distribution, and is available at
6 * http://www.apache.org/licenses/LICENSE-2.0
7 ******************************************************************************/
8
9package net.onrc.onos.apps.segmentrouting;
10
11import java.util.ArrayList;
Srikanth Vavilapalli27f2a122014-09-24 15:56:02 -070012import java.util.HashSet;
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070013import java.util.Iterator;
14import java.util.List;
15
16import net.floodlightcontroller.core.IFloodlightProviderService;
17import net.floodlightcontroller.core.IOFSwitch;
18import net.floodlightcontroller.core.module.FloodlightModuleContext;
19import net.floodlightcontroller.util.MACAddress;
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070020import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
21import net.onrc.onos.core.packet.ARP;
22import net.onrc.onos.core.packet.Ethernet;
23import net.onrc.onos.core.packet.IPv4;
Srikanth Vavilapalli27f2a122014-09-24 15:56:02 -070024import net.onrc.onos.core.topology.Host;
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070025import net.onrc.onos.core.topology.ITopologyService;
26import net.onrc.onos.core.topology.MutableTopology;
27import net.onrc.onos.core.topology.Port;
28import net.onrc.onos.core.topology.Switch;
29
30import org.json.JSONArray;
31import org.json.JSONException;
32import org.projectfloodlight.openflow.protocol.OFFactory;
33import org.projectfloodlight.openflow.protocol.OFPacketOut;
34import org.projectfloodlight.openflow.protocol.action.OFAction;
35import org.projectfloodlight.openflow.types.IPv4Address;
36import org.projectfloodlight.openflow.types.MacAddress;
37import org.projectfloodlight.openflow.types.OFPort;
38import org.projectfloodlight.openflow.types.U32;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import com.esotericsoftware.minlog.Log;
43
44/**
45 * Handling ARP requests to switches for Segment Routing.
46 * <p/>
47 * The module is for handling ARP requests to switches. It sends ARP response for any known
48 * hosts to the controllers.
49 * TODO: need to check the network config file for all hosts and packets
50 */
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070051public class ArpHandler {
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070052
53 private static final Logger log = LoggerFactory
54 .getLogger(ArpHandler.class);
55
56 private IFloodlightProviderService floodlightProvider;
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070057 private IFlowPusherService flowPusher;
58 private ITopologyService topologyService;
59 private MutableTopology mutableTopology;
60 //private List<ArpEntry> arpEntries;
61 private SegmentRoutingManager srManager;
62
63 private static final short IDLE_TIMEOUT = 0;
64 private static final short HARD_TIMEOUT = 0;
65
66 private static final int TABLE_VLAN = 0;
67 private static final int TABLE_TMAC = 1;
68 private static final int TABLE_IPv4_UNICAST = 2;
69 private static final int TABLE_MPLS = 3;
70 private static final int TABLE_META = 4;
71 private static final int TABLE_ACL = 5;
72
73 private static final short MAX_PRIORITY = (short) 0xffff;
74 private static final short SLASH_24_PRIORITY = (short) 0xfff0;
75 private static final short SLASH_16_PRIORITY = (short) 0xff00;
76 private static final short SLASH_8_PRIORITY = (short) 0xf000;
77 private static final short MIN_PRIORITY = 0x0;
78
79
80 /*
81 * Default Constructor
82 */
83 public ArpHandler(FloodlightModuleContext context, SegmentRoutingManager segmentRoutingManager) {
84
85 this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070086 this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
87 this.topologyService = context.getServiceImpl(ITopologyService.class);
88 this.srManager = segmentRoutingManager;
89 this.mutableTopology = topologyService.getTopology();
90
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070091 Log.debug("Arp Handler is initialized");
92
93 }
94
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070095 public void processPacketIn(Switch sw, Port inPort, Ethernet payload){
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070096
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070097 log.debug("ArpHandler: Received a ARP packet from sw {} ", sw.getDpid());
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -070098
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -070099 ARP arp = (ARP)payload.getPayload();
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700100
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700101 if (arp.getOpCode() == ARP.OP_REQUEST) {
102 log.debug("ArpHandler: Received a ARP Requestfrom sw {} ", sw.getDpid());
103 handleArpRequest(sw, inPort, payload);
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700104 }
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700105 byte[] senderMacAddressByte = arp.getSenderHardwareAddress();
106 IPv4Address hostIpAddress = IPv4Address.of(arp.getSenderProtocolAddress());
107 log.debug("ArpHandler: Add IP route to Host {} ", hostIpAddress);
108 srManager.addRouteToHost(sw,hostIpAddress.getInt(), senderMacAddressByte);
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700109 }
110
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700111 /**
112 * Send an ARP response for the ARP request to the known switches
113 *
114 * @param sw Switch
115 * @param inPort port to send ARP response to
116 * @param arpRequest ARP request packet to handle
117 */
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700118 private void handleArpRequest(Switch sw, Port inPort, Ethernet payload) {
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700119
Srikanth Vavilapallib1fce732014-09-24 14:09:50 -0700120 ARP arpRequest = (ARP)payload.getPayload();
Srikanth Vavilapalli27f2a122014-09-24 15:56:02 -0700121 MACAddress targetMac = null;
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700122
Srikanth Vavilapalli27f2a122014-09-24 15:56:02 -0700123 if (isArpReqForSwitch(sw, arpRequest)) {
124 String switchMacAddressStr = sw.getStringAttribute("routerMac");
125 targetMac = MACAddress.valueOf(switchMacAddressStr);
126 log.debug("ArpHandler: Received a ARP query for a sw {} ", sw.getDpid());
127 }
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700128
Srikanth Vavilapalli27f2a122014-09-24 15:56:02 -0700129 Host knownHost = isArpReqForKnownHost(sw, arpRequest);
130 if (knownHost != null) {
131 targetMac = knownHost.getMacAddress();
132 log.debug("ArpHandler: Received a ARP query for a known host {} ",
133 IPv4Address.of(knownHost.getIpAddress()));
134 }
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700135
Srikanth Vavilapalli27f2a122014-09-24 15:56:02 -0700136 if (targetMac != null) {
137 /* ARP Destination is known. Packet out ARP Reply */
138 ARP arpReply = new ARP();
139 arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
140 .setProtocolType(ARP.PROTO_TYPE_IP)
141 .setHardwareAddressLength(
142 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
143 .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
144 .setOpCode(ARP.OP_REPLY)
145 .setSenderHardwareAddress(targetMac.toBytes())
146 .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
147 .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
148 .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
149
150 Ethernet eth = new Ethernet();
151 eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
152 .setSourceMACAddress(targetMac.toBytes())
153 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
154
155 sendPacketOut(sw, eth, inPort.getPortNumber().shortValue());
156 }
157 else
158 {
159 /* Broadcast the received ARP request to all switch ports
160 * that subnets are connected to except the port from which
161 * ARP request is received
162 */
163 log.debug("ArpHandler: Received a ARP query for unknown host {} ",
164 IPv4Address.of(arpRequest.getTargetProtocolAddress()));
165 for (Integer portNo : getSwitchSubnetPorts(sw)) {
166 if (portNo.shortValue() == inPort.getPortNumber().shortValue())
167 continue;
168 log.debug("ArpHandler: Sending ARP request on switch {} port {}",
169 sw.getDpid(), portNo.shortValue());
170 sendPacketOut(sw, payload, portNo.shortValue());
171 }
172 }
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700173 }
174
Srikanth Vavilapalli27f2a122014-09-24 15:56:02 -0700175 private Host isArpReqForKnownHost(Switch sw, ARP arpRequest) {
176 Host knownHost = null;
177
178 IPv4Address targetIPAddress = IPv4Address.of(
179 arpRequest.getTargetProtocolAddress());
180
181 for (Host host:sw.getHosts()) {
182 if (host.getIpAddress() == targetIPAddress.getInt()) {
183 knownHost = host;
184 break;
185 }
186 }
187 return knownHost;
188
189 }
190 private boolean isArpReqForSwitch(Switch sw, ARP arpRequest) {
191 List<String> subnetGatewayIPs = getSubnetGatewayIps(sw);
192 boolean isArpForSwitch = false;
193 if (!subnetGatewayIPs.isEmpty()) {
194 IPv4Address targetProtocolAddress = IPv4Address.of(arpRequest.getTargetProtocolAddress());
195 if (subnetGatewayIPs.contains(targetProtocolAddress.toString())) {
196 isArpForSwitch = true;
197 }
198 }
199 return isArpForSwitch;
200 }
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700201 /**
202 * Retrieve Gateway IP address of all subnets defined in net config file
203 *
204 * @param sw Switch to retrieve subnet GW IPs for
205 * @return list of GW IP addresses for all subnets
206 */
207 private List<String> getSubnetGatewayIps(Switch sw) {
208
209 List<String> gatewayIps = new ArrayList<String>();
210
211 String subnets = sw.getStringAttribute("subnets");
212 try {
213 JSONArray arry = new JSONArray(subnets);
214 for (int i = 0; i < arry.length(); i++) {
215 String subnetIpSlash = (String) arry.getJSONObject(i).get("subnetIp");
216 if (subnetIpSlash != null) {
217 String subnetIp = subnetIpSlash.substring(0, subnetIpSlash.indexOf('/'));
218 gatewayIps.add(subnetIp);
219 }
220 }
221 } catch (JSONException e) {
222 // TODO Auto-generated catch block
223 e.printStackTrace();
224 }
225
226 return gatewayIps;
227 }
228
Srikanth Vavilapalli27f2a122014-09-24 15:56:02 -0700229 private HashSet<Integer> getSwitchSubnetPorts(Switch sw) {
230 HashSet<Integer> switchSubnetPorts = new HashSet<Integer>();
231
232 String subnets = sw.getStringAttribute("subnets");
233 try {
234 JSONArray arry = new JSONArray(subnets);
235 for (int i = 0; i < arry.length(); i++) {
236 Integer subnetPort = (Integer)arry.getJSONObject(i).get("portNo");
237 switchSubnetPorts.add(subnetPort);
238 }
239 } catch (JSONException e) {
240 // TODO Auto-generated catch block
241 e.printStackTrace();
242 }
243
244 return switchSubnetPorts;
245 }
246
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700247 /**
248 * Send an ARP request
249 *
250 * @param sw Switch
251 * @param targetAddress Target IP address
252 * @param inPort Port to send the ARP request
253 *
254 */
255 public void sendArpRequest(Switch sw, int targetAddressInt, Port inPort) {
256
257 IPv4Address targetAddress = IPv4Address.of(targetAddressInt);
258 String senderMacAddressStr = sw.getStringAttribute("routerMac");
259 String senderIpAddressSlash = sw.getStringAttribute("routerIp");
260 if (senderMacAddressStr == null || senderIpAddressSlash == null)
261 return;
262 String senderIpAddressStr =
263 senderIpAddressSlash.substring(0, senderIpAddressSlash.indexOf('/'));
264 byte[] senderMacAddress = MacAddress.of(senderMacAddressStr).getBytes();
265 byte[] senderIpAddress = IPv4Address.of(senderIpAddressStr).getBytes();
266
267 ARP arpRequest = new ARP();
268 arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
269 .setProtocolType(ARP.PROTO_TYPE_IP)
270 .setHardwareAddressLength(
271 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
272 .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
273 .setOpCode(ARP.OP_REQUEST)
274 .setSenderHardwareAddress(senderMacAddress)
275 .setTargetHardwareAddress(MacAddress.NONE.getBytes())
276 .setSenderProtocolAddress(senderIpAddress)
277 .setTargetProtocolAddress(targetAddress.getBytes());
278
279 Ethernet eth = new Ethernet();
280 eth.setDestinationMACAddress(MacAddress.BROADCAST.getBytes())
281 .setSourceMACAddress(senderMacAddress)
282 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
283
Srikanth Vavilapallia95d5832014-09-24 16:38:52 -0700284 /* Broadcast the ARP request to all switch ports
285 * that subnets are connected to except the port from which
286 * ARP request is received
287 */
288 for (Integer portNo : getSwitchSubnetPorts(sw)) {
289 if (portNo.shortValue() == inPort.getPortNumber().shortValue())
290 continue;
291 log.debug("ArpHandler: Sending ARP request on switch {} port {}",
292 sw.getDpid(), portNo.shortValue());
293 sendPacketOut(sw, eth, portNo.shortValue());
294 }
Srikanth Vavilapalli7f479d92014-09-24 13:36:46 -0700295 }
296
297 /**
298 * Send PACKET_OUT packet to switch
299 *
300 * @param sw Switch to send the packet to
301 * @param packet Packet to send
302 * @param switchPort port to send (if -1, broadcast)
303 */
304 private void sendPacketOut(Switch sw, Ethernet packet, short port) {
305
306 IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
307 OFFactory factory = ofSwitch.getFactory();
308
309 List<OFAction> actions = new ArrayList<>();
310
311 if (port > 0) {
312 OFAction outport = factory.actions().output(OFPort.of(port), Short.MAX_VALUE);
313 actions.add(outport);
314 }
315 else {
316 Iterator<Port> iter = sw.getPorts().iterator();
317 while (iter.hasNext()) {
318 Port p = iter.next();
319 int pnum = p.getPortNumber().shortValue();
320 if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
321 OFAction outport = factory.actions().output(OFPort.of(p.getNumber().shortValue()),
322 Short.MAX_VALUE);
323 actions.add(outport);
324 }
325 }
326 }
327
328 OFPacketOut po = factory.buildPacketOut()
329 .setData(packet.serialize())
330 .setActions(actions)
331 .build();
332
333 flowPusher.add(sw.getDpid(), po);
334 }
335
336}
337