blob: d7e94cbaa8b9a9f5346967bcbc3b6e149f53dc7f [file] [log] [blame]
Jonathan Hart0961fe82014-04-03 09:56:25 -07001package net.onrc.onos.apps.proxyarp;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12002
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12003import java.net.InetAddress;
4import java.net.UnknownHostException;
TeruU7feef8a2014-04-03 00:15:49 -07005import java.nio.ByteBuffer;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12006import java.util.ArrayList;
7import java.util.Collection;
Jonathan Harte93aed42013-12-05 18:39:50 -08008import java.util.HashMap;
Jonathan Hart6261dcd2013-07-22 17:58:35 +12009import java.util.Iterator;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120010import java.util.List;
11import java.util.Map;
12import java.util.Set;
Jonathan Hart6261dcd2013-07-22 17:58:35 +120013import java.util.Timer;
14import java.util.TimerTask;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120015
16import net.floodlightcontroller.core.FloodlightContext;
17import net.floodlightcontroller.core.IFloodlightProviderService;
18import net.floodlightcontroller.core.IOFMessageListener;
19import net.floodlightcontroller.core.IOFSwitch;
Jonathan Harte93aed42013-12-05 18:39:50 -080020import net.floodlightcontroller.core.module.FloodlightModuleContext;
21import net.floodlightcontroller.core.module.IFloodlightModule;
22import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart5afde492013-10-01 12:30:53 +130023import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart8ec133c2013-06-26 15:25:18 +120024import net.floodlightcontroller.util.MACAddress;
Jonathan Hart382623d2014-04-03 09:48:11 -070025import net.onrc.onos.apps.bgproute.Interface;
Jonathan Hart6df90172014-04-03 10:13:11 -070026import net.onrc.onos.core.datagrid.IDatagridService;
27import net.onrc.onos.core.datagrid.IEventChannel;
28import net.onrc.onos.core.datagrid.IEventChannelListener;
Jonathan Hart23701d12014-04-03 10:45:48 -070029import net.onrc.onos.core.devicemanager.IOnosDeviceService;
30import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070031import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070032import net.onrc.onos.core.packet.ARP;
33import net.onrc.onos.core.packet.Ethernet;
34import net.onrc.onos.core.packet.IPv4;
Jonathan Hart313fdf02014-04-10 14:09:46 -070035import net.onrc.onos.core.packetservice.BroadcastPacketOutNotification;
36import net.onrc.onos.core.packetservice.SinglePacketOutNotification;
Jonathan Hart472062d2014-04-03 10:56:48 -070037import net.onrc.onos.core.topology.Device;
38import net.onrc.onos.core.topology.INetworkGraphService;
39import net.onrc.onos.core.topology.NetworkGraph;
40import net.onrc.onos.core.topology.Switch;
Jonathan Hart23701d12014-04-03 10:45:48 -070041import net.onrc.onos.core.util.Dpid;
Jonathan Hart23701d12014-04-03 10:45:48 -070042import net.onrc.onos.core.util.SwitchPort;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120043
44import org.openflow.protocol.OFMessage;
45import org.openflow.protocol.OFPacketIn;
46import org.openflow.protocol.OFPacketOut;
47import org.openflow.protocol.OFPort;
48import org.openflow.protocol.OFType;
49import org.openflow.protocol.action.OFAction;
50import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart8ec133c2013-06-26 15:25:18 +120051import org.openflow.util.HexString;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120052import org.slf4j.Logger;
53import org.slf4j.LoggerFactory;
54
Jonathan Hart4dfc3652013-08-02 20:22:36 +120055import com.google.common.collect.HashMultimap;
56import com.google.common.collect.Multimaps;
57import com.google.common.collect.SetMultimap;
58
Jonathan Hart18ad55c2013-11-11 22:49:55 -080059public class ProxyArpManager implements IProxyArpService, IOFMessageListener,
Ray Milkey269ffb92014-04-03 14:43:30 -070060 IFloodlightModule {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070061 private static final Logger log = LoggerFactory
62 .getLogger(ProxyArpManager.class);
pingping-lin017a8922013-12-11 11:15:33 +080063
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070064 private static final long ARP_TIMER_PERIOD = 100; // ms
Jonathan Hartdf6ec332013-08-04 01:37:14 +120065
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070066 private static final int ARP_REQUEST_TIMEOUT = 2000; // ms
Jonathan Hartda4d0e12013-09-30 21:00:20 +130067
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070068 private IFloodlightProviderService floodlightProvider;
69 private IDatagridService datagrid;
TeruU7feef8a2014-04-03 00:15:49 -070070 private IEventChannel<Long, ArpReplyNotification> arpReplyEventChannel;
71 private IEventChannel<Long, BroadcastPacketOutNotification> broadcastPacketOutEventChannel;
72 private IEventChannel<Long, SinglePacketOutNotification> singlePacketOutEventChannel;
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070073 private static final String ARP_REPLY_CHANNEL_NAME = "onos.arp_reply";
TeruU7feef8a2014-04-03 00:15:49 -070074 private static final String BROADCAST_PACKET_OUT_CHANNEL_NAME = "onos.broadcast_packet_out";
75 private static final String SINGLE_PACKET_OUT_CHANNEL_NAME = "onos.single_packet_out";
76 private ArpReplyEventHandler arpReplyEventHandler = new ArpReplyEventHandler();
Ray Milkey269ffb92014-04-03 14:43:30 -070077 private BroadcastPacketOutEventHandler broadcastPacketOutEventHandler = new BroadcastPacketOutEventHandler();
TeruU7feef8a2014-04-03 00:15:49 -070078 private SinglePacketOutEventHandler singlePacketOutEventHandler = new SinglePacketOutEventHandler();
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070079
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070080 private IConfigInfoService configService;
81 private IRestApiService restApi;
82 private IFlowPusherService flowPusher;
Ray Milkey269ffb92014-04-03 14:43:30 -070083
84 private INetworkGraphService networkGraphService;
85 private NetworkGraph networkGraph;
86 private IOnosDeviceService onosDeviceService;
Jonathan Harte93aed42013-12-05 18:39:50 -080087
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070088 private short vlan;
89 private static final short NO_VLAN = 0;
Jonathan Harte93aed42013-12-05 18:39:50 -080090
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070091 private SetMultimap<InetAddress, ArpRequest> arpRequests;
Jonathan Hartdf6ec332013-08-04 01:37:14 +120092
TeruU7feef8a2014-04-03 00:15:49 -070093 private class BroadcastPacketOutEventHandler implements
Ray Milkey269ffb92014-04-03 14:43:30 -070094 IEventChannelListener<Long, BroadcastPacketOutNotification> {
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070095
Ray Milkey269ffb92014-04-03 14:43:30 -070096 @Override
97 public void entryAdded(BroadcastPacketOutNotification value) {
98 if (log.isTraceEnabled()) {
Jonathan Hart313fdf02014-04-10 14:09:46 -070099 log.trace("entryAdded ip{}, sw {}, port {}, packet {}", value.getTargetAddress(), value.getInSwitch(), value.getInPort(), value.getPacketData().length);
Ray Milkey269ffb92014-04-03 14:43:30 -0700100 }
101 BroadcastPacketOutNotification notification = (BroadcastPacketOutNotification) value;
Jonathan Hart313fdf02014-04-10 14:09:46 -0700102 broadcastArpRequestOutMyEdge(notification.getPacketData(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 notification.getInSwitch(),
104 notification.getInPort());
105
106 // set timestamp
107 ByteBuffer buffer = ByteBuffer.allocate(4);
108 buffer.putInt(notification.getTargetAddress());
109 InetAddress addr = null;
110 try {
111 addr = InetAddress.getByAddress(buffer.array());
112 } catch (UnknownHostException e) {
113 log.error("Exception:", e);
114 }
115
116 if (addr != null) {
117 for (ArpRequest request : arpRequests.get(addr)) {
118 request.setRequestTime();
119 }
120 }
121 }
122
123 @Override
124 public void entryUpdated(BroadcastPacketOutNotification value) {
125 log.debug("entryUpdated");
126 // TODO: For now, entryUpdated() is processed as entryAdded()
127 entryAdded(value);
128 }
129
130 @Override
131 public void entryRemoved(BroadcastPacketOutNotification value) {
132 log.debug("entryRemoved");
133 // TODO: Not implemented. Revisit when this module is refactored
134 }
TeruU7feef8a2014-04-03 00:15:49 -0700135 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700136
TeruU7feef8a2014-04-03 00:15:49 -0700137 private class SinglePacketOutEventHandler implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 IEventChannelListener<Long, SinglePacketOutNotification> {
139 @Override
140 public void entryAdded(SinglePacketOutNotification packetOutNotification) {
141 log.debug("entryAdded");
142 SinglePacketOutNotification notification =
143 (SinglePacketOutNotification) packetOutNotification;
Jonathan Hart313fdf02014-04-10 14:09:46 -0700144 sendArpRequestOutPort(notification.getPacketData(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 notification.getOutSwitch(),
146 notification.getOutPort());
147
148 // set timestamp
149 ByteBuffer buffer = ByteBuffer.allocate(4);
150 buffer.putInt(notification.getTargetAddress());
151 InetAddress addr = null;
152 try {
153 addr = InetAddress.getByAddress(buffer.array());
154 } catch (UnknownHostException e) {
155 log.error("Exception:", e);
156 }
157
158 if (addr != null) {
159 for (ArpRequest request : arpRequests.get(addr)) {
160 request.setRequestTime();
161 }
162 }
163 }
164
165 @Override
166 public void entryUpdated(SinglePacketOutNotification packetOutNotification) {
167 log.debug("entryUpdated");
168 // TODO: For now, entryUpdated() is processed as entryAdded()
169 entryAdded(packetOutNotification);
170 }
171
172 @Override
173 public void entryRemoved(SinglePacketOutNotification packetOutNotification) {
174 log.debug("entryRemoved");
175 // TODO: Not implemented. Revisit when this module is refactored
176 }
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700177 }
178
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700179 private class ArpReplyEventHandler implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700180 IEventChannelListener<Long, ArpReplyNotification> {
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700181
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 @Override
183 public void entryAdded(ArpReplyNotification arpReply) {
184 log.debug("Received ARP reply notification for ip {}, mac {}",
185 arpReply.getTargetAddress(), arpReply.getTargetMacAddress());
186 ByteBuffer buffer = ByteBuffer.allocate(4);
187 buffer.putInt(arpReply.getTargetAddress());
188 InetAddress addr = null;
189 try {
190 addr = InetAddress.getByAddress(buffer.array());
191 } catch (UnknownHostException e) {
192 log.error("Exception:", e);
193 }
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700194
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 if (addr != null) {
196 sendArpReplyToWaitingRequesters(addr,
197 arpReply.getTargetMacAddress());
198 }
199 }
200
201 @Override
202 public void entryUpdated(ArpReplyNotification arpReply) {
203 // TODO: For now, entryUpdated() is processed as entryAdded()
204 entryAdded(arpReply);
205 }
206
207 @Override
208 public void entryRemoved(ArpReplyNotification arpReply) {
209 // TODO: Not implemented. Revisit when this module is refactored
210 }
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700211 }
212
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700213 private static class ArpRequest {
214 private final IArpRequester requester;
215 private final boolean retry;
216 private boolean sent = false;
217 private long requestTime;
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200218
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700219 public ArpRequest(IArpRequester requester, boolean retry) {
220 this.requester = requester;
221 this.retry = retry;
222 }
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200223
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700224 public ArpRequest(ArpRequest old) {
225 this.requester = old.requester;
226 this.retry = old.retry;
227 }
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200228
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700229 public boolean isExpired() {
230 return sent
231 && ((System.currentTimeMillis() - requestTime) > ARP_REQUEST_TIMEOUT);
232 }
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200233
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700234 public boolean shouldRetry() {
235 return retry;
236 }
237
238 public void dispatchReply(InetAddress ipAddress,
Ray Milkey269ffb92014-04-03 14:43:30 -0700239 MACAddress replyMacAddress) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700240 requester.arpResponse(ipAddress, replyMacAddress);
241 }
242
243 public void setRequestTime() {
244 this.requestTime = System.currentTimeMillis();
245 this.sent = true;
246 }
247 }
248
249 private class HostArpRequester implements IArpRequester {
250 private final ARP arpRequest;
251 private final long dpid;
252 private final short port;
253
254 public HostArpRequester(ARP arpRequest, long dpid, short port) {
255 this.arpRequest = arpRequest;
256 this.dpid = dpid;
257 this.port = port;
258 }
259
260 @Override
261 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
262 ProxyArpManager.this.sendArpReply(arpRequest, dpid, port,
263 macAddress);
264 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700265
266 public ARP getArpRequest() {
267 return arpRequest;
268 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700269 }
270
271 @Override
272 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
273 Collection<Class<? extends IFloodlightService>> l =
274 new ArrayList<Class<? extends IFloodlightService>>();
275 l.add(IProxyArpService.class);
276 return l;
277 }
278
279 @Override
280 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
281 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
282 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
283 m.put(IProxyArpService.class, this);
284 return m;
285 }
286
287 @Override
288 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
289 Collection<Class<? extends IFloodlightService>> dependencies =
290 new ArrayList<Class<? extends IFloodlightService>>();
291 dependencies.add(IFloodlightProviderService.class);
292 dependencies.add(IRestApiService.class);
293 dependencies.add(IDatagridService.class);
294 dependencies.add(IConfigInfoService.class);
295 dependencies.add(IFlowPusherService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700296 dependencies.add(INetworkGraphService.class);
297 dependencies.add(IOnosDeviceService.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700298 return dependencies;
299 }
300
301 @Override
302 public void init(FloodlightModuleContext context) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700304 this.configService = context.getServiceImpl(IConfigInfoService.class);
305 this.restApi = context.getServiceImpl(IRestApiService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700306 this.datagrid = context.getServiceImpl(IDatagridService.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700307 this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700308 this.networkGraphService = context.getServiceImpl(INetworkGraphService.class);
309 this.onosDeviceService = context.getServiceImpl(IOnosDeviceService.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700310
311 // arpCache = new ArpCache();
312
313 arpRequests = Multimaps.synchronizedSetMultimap(HashMultimap
314 .<InetAddress, ArpRequest>create());
315
316 }
317
318 @Override
319 public void startUp(FloodlightModuleContext context) {
320 this.vlan = configService.getVlan();
321 log.info("vlan set to {}", this.vlan);
322
323 restApi.addRestletRoutable(new ArpWebRoutable());
324 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 networkGraph = networkGraphService.getNetworkGraph();
326
327 //
328 // Event notification setup: channels and event handlers
329 //
330 broadcastPacketOutEventChannel = datagrid.addListener(BROADCAST_PACKET_OUT_CHANNEL_NAME,
331 broadcastPacketOutEventHandler,
332 Long.class,
333 BroadcastPacketOutNotification.class);
334
335 singlePacketOutEventChannel = datagrid.addListener(SINGLE_PACKET_OUT_CHANNEL_NAME,
336 singlePacketOutEventHandler,
337 Long.class,
338 SinglePacketOutNotification.class);
339
340 arpReplyEventChannel = datagrid.addListener(ARP_REPLY_CHANNEL_NAME,
341 arpReplyEventHandler,
342 Long.class,
343 ArpReplyNotification.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700344
345 Timer arpTimer = new Timer("arp-processing");
346 arpTimer.scheduleAtFixedRate(new TimerTask() {
347 @Override
348 public void run() {
349 doPeriodicArpProcessing();
350 }
351 }, 0, ARP_TIMER_PERIOD);
352 }
353
354 /*
355 * Function that runs periodically to manage the asynchronous request mechanism.
356 * It basically cleans up old ARP requests if we don't get a response for them.
357 * The caller can designate that a request should be retried indefinitely, and
358 * this task will handle that as well.
359 */
360 private void doPeriodicArpProcessing() {
361 SetMultimap<InetAddress, ArpRequest> retryList = HashMultimap
362 .<InetAddress, ArpRequest>create();
363
364 // Have to synchronize externally on the Multimap while using an
365 // iterator,
366 // even though it's a synchronizedMultimap
367 synchronized (arpRequests) {
368 Iterator<Map.Entry<InetAddress, ArpRequest>> it = arpRequests
369 .entries().iterator();
370
371 while (it.hasNext()) {
372 Map.Entry<InetAddress, ArpRequest> entry = it.next();
373 ArpRequest request = entry.getValue();
374 if (request.isExpired()) {
375 log.debug("Cleaning expired ARP request for {}", entry
376 .getKey().getHostAddress());
377
Ray Milkey269ffb92014-04-03 14:43:30 -0700378 // If the ARP request is expired and then delete the device
379 // TODO check whether this is OK from this thread
380 HostArpRequester requester = (HostArpRequester) request.requester;
381 ARP req = requester.getArpRequest();
382 Device targetDev = networkGraph.getDeviceByMac(MACAddress.valueOf(req.getTargetHardwareAddress()));
383 if (targetDev != null) {
384 onosDeviceService.deleteOnosDeviceByMac(MACAddress.valueOf(req.getTargetHardwareAddress()));
385 if (log.isDebugEnabled()) {
386 log.debug("RemoveDevice: {} due to no have not recieve the ARP reply", targetDev.getMacAddress());
387 }
388 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700389
390 it.remove();
391
392 if (request.shouldRetry()) {
393 retryList.put(entry.getKey(), request);
394 }
395 }
396 }
397 }
398
399 for (Map.Entry<InetAddress, Collection<ArpRequest>> entry : retryList
400 .asMap().entrySet()) {
401
402 InetAddress address = entry.getKey();
403
404 log.debug("Resending ARP request for {}", address.getHostAddress());
405
406 // Only ARP requests sent by the controller will have the retry flag
407 // set, so for now we can just send a new ARP request for that
408 // address.
409 sendArpRequestForAddress(address);
410
411 for (ArpRequest request : entry.getValue()) {
412 arpRequests.put(address, new ArpRequest(request));
413 }
414 }
415 }
416
417 @Override
418 public String getName() {
419 return "proxyarpmanager";
420 }
421
422 @Override
423 public boolean isCallbackOrderingPrereq(OFType type, String name) {
424 if (type == OFType.PACKET_IN) {
425 return "devicemanager".equals(name)
426 || "onosdevicemanager".equals(name);
427 } else {
428 return false;
429 }
430 }
431
432 @Override
433 public boolean isCallbackOrderingPostreq(OFType type, String name) {
434 return type == OFType.PACKET_IN && "onosforwarding".equals(name);
435 }
436
437 @Override
438 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700439 if (!(msg instanceof OFPacketIn)) {
440 return Command.CONTINUE;
441 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700442
443 OFPacketIn pi = (OFPacketIn) msg;
444
445 Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200446 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Jonathan Hart2f790d22013-08-15 14:01:24 +1200447
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700448 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
449 ARP arp = (ARP) eth.getPayload();
450 if (arp.getOpCode() == ARP.OP_REQUEST) {
451 handleArpRequest(sw, pi, arp, eth);
452 } else if (arp.getOpCode() == ARP.OP_REPLY) {
453 // For replies we simply send a notification via Hazelcast
454 sendArpReplyNotification(eth, pi);
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200455
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700456 // handleArpReply(sw, pi, arp);
457 }
pingping-linb8757bf2013-12-13 01:48:58 +0800458
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700459 // Stop ARP packets here
460 return Command.STOP;
461 }
pingping-linb8757bf2013-12-13 01:48:58 +0800462
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700463 // Propagate everything else
464 return Command.CONTINUE;
465 }
pingping-linb8757bf2013-12-13 01:48:58 +0800466
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700467 private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp,
Ray Milkey269ffb92014-04-03 14:43:30 -0700468 Ethernet eth) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700469 if (log.isTraceEnabled()) {
470 log.trace("ARP request received for {}",
471 inetAddressToString(arp.getTargetProtocolAddress()));
472 }
pingping-linb8757bf2013-12-13 01:48:58 +0800473
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700474 InetAddress target;
475 try {
476 target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
477 } catch (UnknownHostException e) {
478 log.debug("Invalid address in ARP request", e);
479 return;
480 }
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700481
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700482 if (configService.fromExternalNetwork(sw.getId(), pi.getInPort())) {
483 // If the request came from outside our network, we only care if
484 // it was a request for one of our interfaces.
485 if (configService.isInterfaceAddress(target)) {
486 log.trace(
487 "ARP request for our interface. Sending reply {} => {}",
488 target.getHostAddress(),
489 configService.getRouterMacAddress());
pingping-linb8757bf2013-12-13 01:48:58 +0800490
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700491 sendArpReply(arp, sw.getId(), pi.getInPort(),
492 configService.getRouterMacAddress());
493 }
pingping-linb8757bf2013-12-13 01:48:58 +0800494
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700495 return;
496 }
pingping-linb8757bf2013-12-13 01:48:58 +0800497
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700498 // MACAddress macAddress = arpCache.lookup(target);
pingping-linb8757bf2013-12-13 01:48:58 +0800499
Ray Milkey269ffb92014-04-03 14:43:30 -0700500 arpRequests.put(target, new ArpRequest(
501 new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
pingping-linb8757bf2013-12-13 01:48:58 +0800502
Ray Milkey269ffb92014-04-03 14:43:30 -0700503 Device targetDevice = networkGraph.getDeviceByMac(MACAddress.valueOf(arp.getTargetHardwareAddress()));
pingping-linb8757bf2013-12-13 01:48:58 +0800504
Ray Milkey269ffb92014-04-03 14:43:30 -0700505 if (targetDevice == null) {
506 if (log.isTraceEnabled()) {
507 log.trace("No device info found for {} - broadcasting",
508 target.getHostAddress());
509 }
Jonathan Hart18ad9502013-12-15 18:28:00 -0800510
Ray Milkey269ffb92014-04-03 14:43:30 -0700511 // We don't know the device so broadcast the request out
512 BroadcastPacketOutNotification key =
513 new BroadcastPacketOutNotification(eth.serialize(),
514 ByteBuffer.wrap(arp.getTargetProtocolAddress()).getInt(), sw.getId(), pi.getInPort());
515 log.debug("broadcastPacketOutEventChannel mac {}, ip {}, dpid {}, port {}, paket {}", eth.getSourceMAC().toLong(),
516 ByteBuffer.wrap(arp.getTargetProtocolAddress()).getInt(), sw.getId(), pi.getInPort(), eth.serialize().length);
517 broadcastPacketOutEventChannel.addTransientEntry(eth.getDestinationMAC().toLong(), key);
518 } else {
519 // Even if the device exists in our database, we do not reply to
520 // the request directly, but check whether the device is still valid
521 MACAddress macAddress = MACAddress.valueOf(arp.getTargetHardwareAddress());
Jonathan Hart2f790d22013-08-15 14:01:24 +1200522
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 if (log.isTraceEnabled()) {
524 log.trace("The target Device Record in DB is: {} => {} from ARP request host at {}/{}",
525 new Object[]{
526 inetAddressToString(arp.getTargetProtocolAddress()),
527 macAddress,
528 HexString.toHexString(sw.getId()), pi.getInPort()});
529 }
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200530
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 // sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
Jonathan Hart7804bea2014-01-07 10:50:52 -0800532
Ray Milkey269ffb92014-04-03 14:43:30 -0700533 Iterable<net.onrc.onos.core.topology.Port> outPorts = targetDevice.getAttachmentPoints();
534
535 if (!outPorts.iterator().hasNext()) {
536 if (log.isTraceEnabled()) {
537 log.trace("Device {} exists but is not connected to any ports" +
538 " - broadcasting", macAddress);
539 }
540
541// BroadcastPacketOutNotification key =
Ray Milkey5d406012014-04-08 14:44:41 -0700542// new BroadcastPacketOutNotification(eth.serialize(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700543// target, sw.getId(), pi.getInPort());
544// broadcastPacketOutEventChannel.addTransientEntry(eth.getDestinationMAC().toLong(), key);
545 } else {
546 for (net.onrc.onos.core.topology.Port portObject : outPorts) {
547 //long outSwitch = 0;
548 //short outPort = 0;
549
550 if (portObject.getOutgoingLink() != null || portObject.getIncomingLink() != null) {
551 continue;
552 }
553
554 short outPort = portObject.getNumber().shortValue();
555 Switch outSwitchObject = portObject.getSwitch();
556 long outSwitch = outSwitchObject.getDpid();
557
558 if (log.isTraceEnabled()) {
559 log.trace("Probing device {} on port {}/{}",
560 new Object[]{macAddress,
561 HexString.toHexString(outSwitch), outPort});
562 }
563
564 SinglePacketOutNotification key =
565 new SinglePacketOutNotification(eth.serialize(),
566 ByteBuffer.wrap(target.getAddress()).getInt(), outSwitch, outPort);
567 singlePacketOutEventChannel.addTransientEntry(eth.getDestinationMAC().toLong(), key);
568 }
569 }
570 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700571 }
pingping-linb8757bf2013-12-13 01:48:58 +0800572
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700573 // Not used because device manager currently updates the database
574 // for ARP replies. May be useful in the future.
575 private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp) {
576 if (log.isTraceEnabled()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700577 log.trace("ARP reply recieved: {} => {}, on {}/{}", new Object[]{
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700578 inetAddressToString(arp.getSenderProtocolAddress()),
579 HexString.toHexString(arp.getSenderHardwareAddress()),
580 HexString.toHexString(sw.getId()), pi.getInPort()});
581 }
Jonathan Hart7804bea2014-01-07 10:50:52 -0800582
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700583 InetAddress senderIpAddress;
584 try {
585 senderIpAddress = InetAddress.getByAddress(arp
586 .getSenderProtocolAddress());
587 } catch (UnknownHostException e) {
588 log.debug("Invalid address in ARP reply", e);
589 return;
590 }
Jonathan Hart7804bea2014-01-07 10:50:52 -0800591
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700592 MACAddress senderMacAddress = MACAddress.valueOf(arp
593 .getSenderHardwareAddress());
594
595 // See if anyone's waiting for this ARP reply
596 Set<ArpRequest> requests = arpRequests.get(senderIpAddress);
597
598 // Synchronize on the Multimap while using an iterator for one of the
599 // sets
600 List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(
601 requests.size());
602 synchronized (arpRequests) {
603 Iterator<ArpRequest> it = requests.iterator();
604 while (it.hasNext()) {
605 ArpRequest request = it.next();
606 it.remove();
607 requestsToSend.add(request);
608 }
609 }
610
611 // Don't hold an ARP lock while dispatching requests
612 for (ArpRequest request : requestsToSend) {
613 request.dispatchReply(senderIpAddress, senderMacAddress);
614 }
615 }
616
617 private void sendArpRequestForAddress(InetAddress ipAddress) {
618 // TODO what should the sender IP address and MAC address be if no
619 // IP addresses are configured? Will there ever be a need to send
620 // ARP requests from the controller in that case?
621 // All-zero MAC address doesn't seem to work - hosts don't respond to it
622
623 byte[] zeroIpv4 = {0x0, 0x0, 0x0, 0x0};
624 byte[] zeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
625 byte[] genericNonZeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x01};
626 byte[] broadcastMac = {(byte) 0xff, (byte) 0xff, (byte) 0xff,
627 (byte) 0xff, (byte) 0xff, (byte) 0xff};
628
629 ARP arpRequest = new ARP();
630
631 arpRequest
632 .setHardwareType(ARP.HW_TYPE_ETHERNET)
633 .setProtocolType(ARP.PROTO_TYPE_IP)
634 .setHardwareAddressLength(
635 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
636 .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
637 .setOpCode(ARP.OP_REQUEST).setTargetHardwareAddress(zeroMac)
638 .setTargetProtocolAddress(ipAddress.getAddress());
639
640 MACAddress routerMacAddress = configService.getRouterMacAddress();
641 // TODO hack for now as it's unclear what the MAC address should be
642 byte[] senderMacAddress = genericNonZeroMac;
643 if (routerMacAddress != null) {
644 senderMacAddress = routerMacAddress.toBytes();
645 }
646 arpRequest.setSenderHardwareAddress(senderMacAddress);
647
648 byte[] senderIPAddress = zeroIpv4;
649 Interface intf = configService.getOutgoingInterface(ipAddress);
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700650 if (intf == null) {
651 // TODO handle the case where the controller needs to send an ARP
652 // request but there's not IP configuration. In this case the
653 // request should be broadcast out all edge ports in the network.
654 log.warn("Sending ARP requests with default configuration "
655 + "not supported");
656 return;
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700657 }
658
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700659 senderIPAddress = intf.getIpAddress().getAddress();
660
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700661 arpRequest.setSenderProtocolAddress(senderIPAddress);
662
663 Ethernet eth = new Ethernet();
664 eth.setSourceMACAddress(senderMacAddress)
665 .setDestinationMACAddress(broadcastMac)
666 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
667
668 if (vlan != NO_VLAN) {
669 eth.setVlanID(vlan).setPriorityCode((byte) 0);
670 }
671
672 // sendArpRequestToSwitches(ipAddress, eth.serialize());
Ray Milkey269ffb92014-04-03 14:43:30 -0700673 SinglePacketOutNotification key =
674 new SinglePacketOutNotification(eth.serialize(), ByteBuffer.wrap(ipAddress.getAddress()).getInt(),
675 intf.getDpid(), intf.getPort());
676 singlePacketOutEventChannel.addTransientEntry(MACAddress.valueOf(senderMacAddress).toLong(), key);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700677 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700678
TeruU7feef8a2014-04-03 00:15:49 -0700679 private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700680 sendArpRequestToSwitches(dstAddress, arpRequest, 0,
681 OFPort.OFPP_NONE.getValue());
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700682 }
683
684 private void sendArpRequestToSwitches(InetAddress dstAddress,
Ray Milkey269ffb92014-04-03 14:43:30 -0700685 byte[] arpRequest, long inSwitch, short inPort) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700686
687 if (configService.hasLayer3Configuration()) {
688 Interface intf = configService.getOutgoingInterface(dstAddress);
689 if (intf == null) {
690 // TODO here it should be broadcast out all non-interface edge
691 // ports.
692 // I think we can assume that if it's not a request for an
693 // external
694 // network, it's an ARP for a host in our own network. So we
695 // want to
696 // send it out all edge ports that don't have an interface
697 // configured
698 // to ensure it reaches all hosts in our network.
699 log.debug("No interface found to send ARP request for {}",
700 dstAddress.getHostAddress());
701 } else {
702 sendArpRequestOutPort(arpRequest, intf.getDpid(),
703 intf.getPort());
704 }
705 } else {
706 // broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
707 broadcastArpRequestOutMyEdge(arpRequest, inSwitch, inPort);
708 }
709 }
710
711 private void sendArpReplyNotification(Ethernet eth, OFPacketIn pi) {
712 ARP arp = (ARP) eth.getPayload();
713
714 if (log.isTraceEnabled()) {
715 log.trace("Sending ARP reply for {} to other ONOS instances",
716 inetAddressToString(arp.getSenderProtocolAddress()));
717 }
718
719 InetAddress targetAddress;
720
721 try {
722 targetAddress = InetAddress.getByAddress(arp
723 .getSenderProtocolAddress());
724 } catch (UnknownHostException e) {
725 log.error("Unknown host", e);
726 return;
727 }
728
729 MACAddress mac = new MACAddress(arp.getSenderHardwareAddress());
730
Ray Milkey269ffb92014-04-03 14:43:30 -0700731 ArpReplyNotification key =
732 new ArpReplyNotification(ByteBuffer.wrap(targetAddress.getAddress()).getInt(), mac);
733 log.debug("ArpReplyNotification ip {}, mac{}", ByteBuffer.wrap(targetAddress.getAddress()).getInt(), mac);
734 arpReplyEventChannel.addTransientEntry(mac.toLong(), key);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700735 }
736
737 private void broadcastArpRequestOutMyEdge(byte[] arpRequest, long inSwitch,
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 short inPort) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700739 List<SwitchPort> switchPorts = new ArrayList<SwitchPort>();
740
741 for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
742
743 OFPacketOut po = new OFPacketOut();
744 po.setInPort(OFPort.OFPP_NONE).setBufferId(-1)
745 .setPacketData(arpRequest);
746
747 List<OFAction> actions = new ArrayList<OFAction>();
748
Ray Milkey269ffb92014-04-03 14:43:30 -0700749 Switch graphSw = networkGraph.getSwitch(sw.getId());
750 Collection<net.onrc.onos.core.topology.Port> ports = graphSw.getPorts();
751
752 if (ports == null) {
753 continue;
754 }
755
756 for (net.onrc.onos.core.topology.Port portObject : ports) {
757 if (portObject.getOutgoingLink() == null && portObject.getNumber() > 0) {
758 Long portNumber = portObject.getNumber();
759
760 if (sw.getId() == inSwitch && portNumber.shortValue() == inPort) {
761 // This is the port that the ARP message came in,
762 // so don't broadcast out this port
763 continue;
764 }
765 switchPorts.add(new SwitchPort(new Dpid(sw.getId()),
766 new net.onrc.onos.core.util.Port(portNumber.shortValue())));
767 actions.add(new OFActionOutput(portNumber.shortValue()));
768 }
769 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700770
771 po.setActions(actions);
772 short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
773 po.setActionsLength(actionsLength);
774 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
775 + arpRequest.length);
776
777 flowPusher.add(sw, po);
778 }
779
780 if (log.isTraceEnabled()) {
781 log.trace("Broadcast ARP request to: {}", switchPorts);
782 }
783 }
784
785 private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
786 if (log.isTraceEnabled()) {
787 log.trace("Sending ARP request out {}/{}",
788 HexString.toHexString(dpid), port);
789 }
790
791 OFPacketOut po = new OFPacketOut();
792 po.setInPort(OFPort.OFPP_NONE).setBufferId(-1)
793 .setPacketData(arpRequest);
794
795 List<OFAction> actions = new ArrayList<OFAction>();
796 actions.add(new OFActionOutput(port));
797 po.setActions(actions);
798 short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
799 po.setActionsLength(actionsLength);
800 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
801 + arpRequest.length);
802
803 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
804
805 if (sw == null) {
806 log.warn("Switch not found when sending ARP request");
807 return;
808 }
809
810 flowPusher.add(sw, po);
811 }
812
813 private void sendArpReply(ARP arpRequest, long dpid, short port,
Ray Milkey269ffb92014-04-03 14:43:30 -0700814 MACAddress targetMac) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700815 if (log.isTraceEnabled()) {
816 log.trace(
817 "Sending reply {} => {} to {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700818 new Object[]{
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700819 inetAddressToString(arpRequest
820 .getTargetProtocolAddress()),
821 targetMac,
822 inetAddressToString(arpRequest
823 .getSenderProtocolAddress())});
824 }
825
826 ARP arpReply = new ARP();
827 arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
828 .setProtocolType(ARP.PROTO_TYPE_IP)
829 .setHardwareAddressLength(
830 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
831 .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
832 .setOpCode(ARP.OP_REPLY)
833 .setSenderHardwareAddress(targetMac.toBytes())
834 .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
835 .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
836 .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
837
838 Ethernet eth = new Ethernet();
839 eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
840 .setSourceMACAddress(targetMac.toBytes())
841 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
842
843 if (vlan != NO_VLAN) {
844 eth.setVlanID(vlan).setPriorityCode((byte) 0);
845 }
846
847 List<OFAction> actions = new ArrayList<OFAction>();
848 actions.add(new OFActionOutput(port));
849
850 OFPacketOut po = new OFPacketOut();
851 po.setInPort(OFPort.OFPP_NONE)
852 .setBufferId(-1)
853 .setPacketData(eth.serialize())
854 .setActions(actions)
855 .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
856 .setLengthU(
857 OFPacketOut.MINIMUM_LENGTH
858 + OFActionOutput.MINIMUM_LENGTH
859 + po.getPacketData().length);
860
861 List<OFMessage> msgList = new ArrayList<OFMessage>();
862 msgList.add(po);
863
864 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
865
866 if (sw == null) {
867 log.warn("Switch {} not found when sending ARP reply",
868 HexString.toHexString(dpid));
869 return;
870 }
871
872 flowPusher.add(sw, po);
873 }
874
875 private String inetAddressToString(byte[] bytes) {
876 try {
877 return InetAddress.getByAddress(bytes).getHostAddress();
878 } catch (UnknownHostException e) {
879 log.debug("Invalid IP address", e);
880 return "";
881 }
882 }
883
884 /*
885 * IProxyArpService methods
886 */
887
888 @Override
889 public MACAddress getMacAddress(InetAddress ipAddress) {
890 // return arpCache.lookup(ipAddress);
891 return null;
892 }
893
894 @Override
895 public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
Ray Milkey269ffb92014-04-03 14:43:30 -0700896 boolean retry) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700897 arpRequests.put(ipAddress, new ArpRequest(requester, retry));
898
899 // Sanity check to make sure we don't send a request for our own address
900 if (!configService.isInterfaceAddress(ipAddress)) {
901 sendArpRequestForAddress(ipAddress);
902 }
903 }
904
905 @Override
906 public List<String> getMappings() {
907 return new ArrayList<String>();
908 }
909
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700910 private void sendArpReplyToWaitingRequesters(InetAddress address,
Ray Milkey269ffb92014-04-03 14:43:30 -0700911 MACAddress mac) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700912 log.debug("Sending ARP reply for {} to requesters",
913 address.getHostAddress());
914
915 // See if anyone's waiting for this ARP reply
916 Set<ArpRequest> requests = arpRequests.get(address);
917
918 // Synchronize on the Multimap while using an iterator for one of the
919 // sets
920 List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(
921 requests.size());
922 synchronized (arpRequests) {
923 Iterator<ArpRequest> it = requests.iterator();
924 while (it.hasNext()) {
925 ArpRequest request = it.next();
926 it.remove();
927 requestsToSend.add(request);
928 }
929 }
930
TeruU7feef8a2014-04-03 00:15:49 -0700931 //TODO here, comment outed from long time ago. I will check if we need it later.
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700932 /*IDeviceObject deviceObject = deviceStorage.getDeviceByIP(
Ray Milkey269ffb92014-04-03 14:43:30 -0700933 InetAddresses.coerceToInteger(address));
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700934
935 MACAddress mac = MACAddress.valueOf(deviceObject.getMACAddress());
936
937 log.debug("Found {} at {} in network map",
Ray Milkey269ffb92014-04-03 14:43:30 -0700938 address.getHostAddress(), mac);*/
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700939
940 // Don't hold an ARP lock while dispatching requests
941 for (ArpRequest request : requestsToSend) {
942 request.dispatchReply(address, mac);
943 }
944 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700945}