blob: 7ee498ae6d0c81d4266bd11659b430bf4791fe78 [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 Hart8f6dc092014-04-18 15:56:43 -070025import net.onrc.onos.apps.sdnip.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
TeruU3c049c42014-04-15 10:13:25 -070064 private static long arpTimerPeriodConfig = 100; // ms
65 private static int arpRequestTimeoutConfig = 2000; // ms
66 private long arpCleaningTimerPeriodConfig = 60 * 1000; // ms (1 min)
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;
TeruU3c049c42014-04-15 10:13:25 -070073 private IEventChannel<String, ArpCacheNotification> arpCacheEventChannel;
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070074 private static final String ARP_REPLY_CHANNEL_NAME = "onos.arp_reply";
TeruU7feef8a2014-04-03 00:15:49 -070075 private static final String BROADCAST_PACKET_OUT_CHANNEL_NAME = "onos.broadcast_packet_out";
76 private static final String SINGLE_PACKET_OUT_CHANNEL_NAME = "onos.single_packet_out";
TeruU3c049c42014-04-15 10:13:25 -070077 private static final String ARP_CACHE_CHANNEL_NAME = "onos.arp_cache";
78 private final ArpReplyEventHandler arpReplyEventHandler = new ArpReplyEventHandler();
79 private final BroadcastPacketOutEventHandler broadcastPacketOutEventHandler = new BroadcastPacketOutEventHandler();
80 private final SinglePacketOutEventHandler singlePacketOutEventHandler = new SinglePacketOutEventHandler();
81 private final ArpCacheEventHandler arpCacheEventHandler = new ArpCacheEventHandler();
Pavlin Radoslavov902fe522014-03-31 10:11:31 -070082
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070083 private IConfigInfoService configService;
84 private IRestApiService restApi;
85 private IFlowPusherService flowPusher;
Ray Milkey269ffb92014-04-03 14:43:30 -070086
87 private INetworkGraphService networkGraphService;
88 private NetworkGraph networkGraph;
89 private IOnosDeviceService onosDeviceService;
Jonathan Harte93aed42013-12-05 18:39:50 -080090
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070091 private short vlan;
92 private static final short NO_VLAN = 0;
Jonathan Harte93aed42013-12-05 18:39:50 -080093
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -070094 private SetMultimap<InetAddress, ArpRequest> arpRequests;
Jonathan Hartdf6ec332013-08-04 01:37:14 +120095
TeruU3c049c42014-04-15 10:13:25 -070096 private ArpCache arpCache;
97
TeruU7feef8a2014-04-03 00:15:49 -070098 private class BroadcastPacketOutEventHandler implements
Ray Milkey269ffb92014-04-03 14:43:30 -070099 IEventChannelListener<Long, BroadcastPacketOutNotification> {
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700100
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 @Override
102 public void entryAdded(BroadcastPacketOutNotification value) {
103 if (log.isTraceEnabled()) {
TeruU3c049c42014-04-15 10:13:25 -0700104 log.trace("entryAdded for BroadcastPacketOutEventHandler, ip{}, sw {}, port {}",
105 value.getTargetAddress(), value.getInSwitch(), value.getInPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700106 }
TeruU3c049c42014-04-15 10:13:25 -0700107 BroadcastPacketOutNotification notification = value;
Jonathan Hart313fdf02014-04-10 14:09:46 -0700108 broadcastArpRequestOutMyEdge(notification.getPacketData(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700109 notification.getInSwitch(),
110 notification.getInPort());
111
112 // set timestamp
TeruU3c049c42014-04-15 10:13:25 -0700113 //This 4 means ipv4 addr size. Need to change it in the future.
Ray Milkey269ffb92014-04-03 14:43:30 -0700114 ByteBuffer buffer = ByteBuffer.allocate(4);
115 buffer.putInt(notification.getTargetAddress());
116 InetAddress addr = null;
117 try {
118 addr = InetAddress.getByAddress(buffer.array());
119 } catch (UnknownHostException e) {
120 log.error("Exception:", e);
121 }
122
123 if (addr != null) {
124 for (ArpRequest request : arpRequests.get(addr)) {
125 request.setRequestTime();
126 }
127 }
128 }
129
130 @Override
131 public void entryUpdated(BroadcastPacketOutNotification value) {
TeruU3c049c42014-04-15 10:13:25 -0700132 log.debug("entryUpdated for BroadcastPacketOutEventHandler");
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 entryAdded(value);
134 }
135
136 @Override
137 public void entryRemoved(BroadcastPacketOutNotification value) {
TeruU3c049c42014-04-15 10:13:25 -0700138 //Not implemented. BroadcastPacketOutNotification is used only for remote messaging.
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 }
TeruU7feef8a2014-04-03 00:15:49 -0700140 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700141
TeruU7feef8a2014-04-03 00:15:49 -0700142 private class SinglePacketOutEventHandler implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700143 IEventChannelListener<Long, SinglePacketOutNotification> {
144 @Override
145 public void entryAdded(SinglePacketOutNotification packetOutNotification) {
TeruU3c049c42014-04-15 10:13:25 -0700146 log.debug("entryAdded for SinglePacketOutEventHandler");
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 SinglePacketOutNotification notification =
TeruU3c049c42014-04-15 10:13:25 -0700148 packetOutNotification;
Jonathan Hart313fdf02014-04-10 14:09:46 -0700149 sendArpRequestOutPort(notification.getPacketData(),
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 notification.getOutSwitch(),
151 notification.getOutPort());
152
153 // set timestamp
TeruU3c049c42014-04-15 10:13:25 -0700154 //This 4 means ipv4 addr size. Need to change it in the future.
Ray Milkey269ffb92014-04-03 14:43:30 -0700155 ByteBuffer buffer = ByteBuffer.allocate(4);
156 buffer.putInt(notification.getTargetAddress());
157 InetAddress addr = null;
158 try {
159 addr = InetAddress.getByAddress(buffer.array());
160 } catch (UnknownHostException e) {
161 log.error("Exception:", e);
162 }
163
164 if (addr != null) {
165 for (ArpRequest request : arpRequests.get(addr)) {
166 request.setRequestTime();
167 }
168 }
169 }
170
171 @Override
172 public void entryUpdated(SinglePacketOutNotification packetOutNotification) {
TeruU3c049c42014-04-15 10:13:25 -0700173 log.debug("entryUpdated for SinglePacketOutEventHandler");
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 entryAdded(packetOutNotification);
175 }
176
177 @Override
178 public void entryRemoved(SinglePacketOutNotification packetOutNotification) {
TeruU3c049c42014-04-15 10:13:25 -0700179 //Not implemented. SinglePacketOutNotification is used only for remote messaging.
Ray Milkey269ffb92014-04-03 14:43:30 -0700180 }
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700181 }
182
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700183 private class ArpReplyEventHandler implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 IEventChannelListener<Long, ArpReplyNotification> {
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700185
Ray Milkey269ffb92014-04-03 14:43:30 -0700186 @Override
187 public void entryAdded(ArpReplyNotification arpReply) {
188 log.debug("Received ARP reply notification for ip {}, mac {}",
189 arpReply.getTargetAddress(), arpReply.getTargetMacAddress());
TeruU3c049c42014-04-15 10:13:25 -0700190 //This 4 means ipv4 addr size. Need to change it in the future.
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 ByteBuffer buffer = ByteBuffer.allocate(4);
192 buffer.putInt(arpReply.getTargetAddress());
193 InetAddress addr = null;
194 try {
195 addr = InetAddress.getByAddress(buffer.array());
196 } catch (UnknownHostException e) {
197 log.error("Exception:", e);
198 }
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700199
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 if (addr != null) {
201 sendArpReplyToWaitingRequesters(addr,
202 arpReply.getTargetMacAddress());
203 }
204 }
205
206 @Override
207 public void entryUpdated(ArpReplyNotification arpReply) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 entryAdded(arpReply);
209 }
210
211 @Override
212 public void entryRemoved(ArpReplyNotification arpReply) {
TeruU3c049c42014-04-15 10:13:25 -0700213 //Not implemented. ArpReplyEventHandler is used only for remote messaging.
214 }
215 }
216
217 private class ArpCacheEventHandler implements
218 IEventChannelListener<String, ArpCacheNotification> {
219
220 /**
221 * Startup processing.
222 */
223 private void startUp() {
224 //
225 // TODO: Read all state from the database:
226 // For now, as a shortcut we read it from the datagrid
227 //
228 Collection<ArpCacheNotification> arpCacheEvents =
229 arpCacheEventChannel.getAllEntries();
230
231 for (ArpCacheNotification arpCacheEvent : arpCacheEvents) {
232 entryAdded(arpCacheEvent);
233 }
234 }
235
236 @Override
237 public void entryAdded(ArpCacheNotification value) {
238
239 try {
240 log.debug("Received entryAdded for ARP cache notification for ip {}, mac {}",
241 InetAddress.getByAddress(value.getTargetAddress()), value.getTargetMacAddress());
242 arpCache.update(InetAddress.getByAddress(value.getTargetAddress()), MACAddress.valueOf(value.getTargetMacAddress()));
243 } catch (UnknownHostException e) {
244 log.error("Exception : ", e);
245 }
246 }
247
248 @Override
249 public void entryRemoved(ArpCacheNotification value) {
250 log.debug("Received entryRemoved for ARP cache notification for ip {}, mac {}",
251 value.getTargetAddress(), value.getTargetMacAddress());
252 try {
253 arpCache.remove(InetAddress.getByAddress(value.getTargetAddress()));
254 } catch (UnknownHostException e) {
255 log.error("Exception : ", e);
256 }
257 }
258
259 @Override
260 public void entryUpdated(ArpCacheNotification value) {
261 try {
262 log.debug("Received entryUpdated for ARP cache notification for ip {}, mac {}",
263 InetAddress.getByAddress(value.getTargetAddress()), value.getTargetMacAddress());
264 arpCache.update(InetAddress.getByAddress(value.getTargetAddress()), MACAddress.valueOf(value.getTargetMacAddress()));
265 } catch (UnknownHostException e) {
266 log.error("Exception : ", e);
267 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 }
Pavlin Radoslavov902fe522014-03-31 10:11:31 -0700269 }
270
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700271 private static class ArpRequest {
272 private final IArpRequester requester;
273 private final boolean retry;
274 private boolean sent = false;
275 private long requestTime;
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200276
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700277 public ArpRequest(IArpRequester requester, boolean retry) {
278 this.requester = requester;
279 this.retry = retry;
280 }
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200281
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700282 public ArpRequest(ArpRequest old) {
283 this.requester = old.requester;
284 this.retry = old.retry;
285 }
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200286
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700287 public boolean isExpired() {
288 return sent
TeruU3c049c42014-04-15 10:13:25 -0700289 && ((System.currentTimeMillis() - requestTime) > arpRequestTimeoutConfig);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700290 }
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200291
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700292 public boolean shouldRetry() {
293 return retry;
294 }
295
296 public void dispatchReply(InetAddress ipAddress,
Ray Milkey269ffb92014-04-03 14:43:30 -0700297 MACAddress replyMacAddress) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700298 requester.arpResponse(ipAddress, replyMacAddress);
299 }
300
301 public void setRequestTime() {
302 this.requestTime = System.currentTimeMillis();
303 this.sent = true;
304 }
305 }
306
307 private class HostArpRequester implements IArpRequester {
308 private final ARP arpRequest;
309 private final long dpid;
310 private final short port;
311
312 public HostArpRequester(ARP arpRequest, long dpid, short port) {
313 this.arpRequest = arpRequest;
314 this.dpid = dpid;
315 this.port = port;
316 }
317
318 @Override
319 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
320 ProxyArpManager.this.sendArpReply(arpRequest, dpid, port,
321 macAddress);
322 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700323
324 public ARP getArpRequest() {
325 return arpRequest;
326 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700327 }
328
329 @Override
330 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
331 Collection<Class<? extends IFloodlightService>> l =
332 new ArrayList<Class<? extends IFloodlightService>>();
333 l.add(IProxyArpService.class);
334 return l;
335 }
336
337 @Override
338 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
339 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
340 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
341 m.put(IProxyArpService.class, this);
342 return m;
343 }
344
345 @Override
346 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
347 Collection<Class<? extends IFloodlightService>> dependencies =
348 new ArrayList<Class<? extends IFloodlightService>>();
349 dependencies.add(IFloodlightProviderService.class);
350 dependencies.add(IRestApiService.class);
351 dependencies.add(IDatagridService.class);
352 dependencies.add(IConfigInfoService.class);
353 dependencies.add(IFlowPusherService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700354 dependencies.add(INetworkGraphService.class);
355 dependencies.add(IOnosDeviceService.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700356 return dependencies;
357 }
358
359 @Override
360 public void init(FloodlightModuleContext context) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700361 this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700362 this.configService = context.getServiceImpl(IConfigInfoService.class);
363 this.restApi = context.getServiceImpl(IRestApiService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700364 this.datagrid = context.getServiceImpl(IDatagridService.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700365 this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
TeruU7feef8a2014-04-03 00:15:49 -0700366 this.networkGraphService = context.getServiceImpl(INetworkGraphService.class);
367 this.onosDeviceService = context.getServiceImpl(IOnosDeviceService.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700368
TeruU3c049c42014-04-15 10:13:25 -0700369 Map<String, String> configOptions = context.getConfigParams(this);
TeruU3c049c42014-04-15 10:13:25 -0700370
371 try {
372 arpCleaningTimerPeriodConfig = Long.parseLong(configOptions.get("cleanupmsec"));
373 } catch (NumberFormatException e) {
374 log.debug("ArpCleaningTimerPeriod related config options were not set. Use default.");
375 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700376
377 arpRequests = Multimaps.synchronizedSetMultimap(HashMultimap
378 .<InetAddress, ArpRequest>create());
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700379 }
380
381 @Override
382 public void startUp(FloodlightModuleContext context) {
Jonathan Hart4aa47532014-04-23 15:23:41 -0700383 Map<String, String> configOptions = context.getConfigParams(this);
384
385 Long agingmsec = null;
386 try {
387 agingmsec = Long.parseLong(configOptions.get("agingmsec"));
388 } catch (NumberFormatException e) {
389 log.debug("ArpEntryTimeout related config options were not set. Use default.");
390 }
391
392 arpCache = new ArpCache();
393 if (agingmsec != null) {
394 arpCache.setArpEntryTimeoutConfig(agingmsec);
395 }
396
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700397 this.vlan = configService.getVlan();
398 log.info("vlan set to {}", this.vlan);
399
400 restApi.addRestletRoutable(new ArpWebRoutable());
401 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700402 networkGraph = networkGraphService.getNetworkGraph();
403
404 //
405 // Event notification setup: channels and event handlers
406 //
407 broadcastPacketOutEventChannel = datagrid.addListener(BROADCAST_PACKET_OUT_CHANNEL_NAME,
408 broadcastPacketOutEventHandler,
409 Long.class,
410 BroadcastPacketOutNotification.class);
411
412 singlePacketOutEventChannel = datagrid.addListener(SINGLE_PACKET_OUT_CHANNEL_NAME,
413 singlePacketOutEventHandler,
414 Long.class,
415 SinglePacketOutNotification.class);
416
417 arpReplyEventChannel = datagrid.addListener(ARP_REPLY_CHANNEL_NAME,
418 arpReplyEventHandler,
419 Long.class,
420 ArpReplyNotification.class);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700421
TeruU3c049c42014-04-15 10:13:25 -0700422 arpCacheEventChannel = datagrid.addListener(ARP_CACHE_CHANNEL_NAME,
423 arpCacheEventHandler,
424 String.class,
425 ArpCacheNotification.class);
426 arpCacheEventHandler.startUp();
427
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700428 Timer arpTimer = new Timer("arp-processing");
429 arpTimer.scheduleAtFixedRate(new TimerTask() {
430 @Override
431 public void run() {
432 doPeriodicArpProcessing();
433 }
TeruU3c049c42014-04-15 10:13:25 -0700434 }, 0, arpTimerPeriodConfig);
435
436 Timer arpCacheTimer = new Timer("arp-clearning");
437 arpCacheTimer.scheduleAtFixedRate(new TimerTask() {
438 @Override
439 public void run() {
440 doPeriodicArpCleaning();
441 }
442 }, 0, arpCleaningTimerPeriodConfig);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700443 }
444
445 /*
446 * Function that runs periodically to manage the asynchronous request mechanism.
447 * It basically cleans up old ARP requests if we don't get a response for them.
448 * The caller can designate that a request should be retried indefinitely, and
449 * this task will handle that as well.
450 */
451 private void doPeriodicArpProcessing() {
452 SetMultimap<InetAddress, ArpRequest> retryList = HashMultimap
453 .<InetAddress, ArpRequest>create();
454
455 // Have to synchronize externally on the Multimap while using an
456 // iterator,
457 // even though it's a synchronizedMultimap
458 synchronized (arpRequests) {
459 Iterator<Map.Entry<InetAddress, ArpRequest>> it = arpRequests
460 .entries().iterator();
461
462 while (it.hasNext()) {
463 Map.Entry<InetAddress, ArpRequest> entry = it.next();
464 ArpRequest request = entry.getValue();
465 if (request.isExpired()) {
466 log.debug("Cleaning expired ARP request for {}", entry
467 .getKey().getHostAddress());
468
Ray Milkey269ffb92014-04-03 14:43:30 -0700469 // If the ARP request is expired and then delete the device
Ray Milkey269ffb92014-04-03 14:43:30 -0700470 HostArpRequester requester = (HostArpRequester) request.requester;
471 ARP req = requester.getArpRequest();
TeruU3c049c42014-04-15 10:13:25 -0700472 networkGraph.acquireReadLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700473 Device targetDev = networkGraph.getDeviceByMac(MACAddress.valueOf(req.getTargetHardwareAddress()));
TeruU3c049c42014-04-15 10:13:25 -0700474 networkGraph.releaseReadLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700475 if (targetDev != null) {
476 onosDeviceService.deleteOnosDeviceByMac(MACAddress.valueOf(req.getTargetHardwareAddress()));
477 if (log.isDebugEnabled()) {
478 log.debug("RemoveDevice: {} due to no have not recieve the ARP reply", targetDev.getMacAddress());
479 }
480 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700481
482 it.remove();
483
484 if (request.shouldRetry()) {
485 retryList.put(entry.getKey(), request);
486 }
487 }
488 }
489 }
490
491 for (Map.Entry<InetAddress, Collection<ArpRequest>> entry : retryList
492 .asMap().entrySet()) {
493
494 InetAddress address = entry.getKey();
495
496 log.debug("Resending ARP request for {}", address.getHostAddress());
497
498 // Only ARP requests sent by the controller will have the retry flag
499 // set, so for now we can just send a new ARP request for that
500 // address.
501 sendArpRequestForAddress(address);
502
503 for (ArpRequest request : entry.getValue()) {
504 arpRequests.put(address, new ArpRequest(request));
505 }
506 }
507 }
508
509 @Override
510 public String getName() {
511 return "proxyarpmanager";
512 }
513
514 @Override
515 public boolean isCallbackOrderingPrereq(OFType type, String name) {
516 if (type == OFType.PACKET_IN) {
517 return "devicemanager".equals(name)
518 || "onosdevicemanager".equals(name);
519 } else {
520 return false;
521 }
522 }
523
524 @Override
525 public boolean isCallbackOrderingPostreq(OFType type, String name) {
526 return type == OFType.PACKET_IN && "onosforwarding".equals(name);
527 }
528
529 @Override
530 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700531 if (!(msg instanceof OFPacketIn)) {
532 return Command.CONTINUE;
533 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700534
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700535 Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200536 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Jonathan Hart2f790d22013-08-15 14:01:24 +1200537
TeruU3c049c42014-04-15 10:13:25 -0700538 return classifyPacket(sw, msg, eth);
539 }
540
541 protected Command classifyPacket(IOFSwitch sw, OFMessage msg, Ethernet eth) {
542 OFPacketIn pi = (OFPacketIn) msg;
543
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700544 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
545 ARP arp = (ARP) eth.getPayload();
TeruU3c049c42014-04-15 10:13:25 -0700546 learnArp(arp);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700547 if (arp.getOpCode() == ARP.OP_REQUEST) {
548 handleArpRequest(sw, pi, arp, eth);
549 } else if (arp.getOpCode() == ARP.OP_REPLY) {
550 // For replies we simply send a notification via Hazelcast
551 sendArpReplyNotification(eth, pi);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700552 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700553 // Stop ARP packets here
554 return Command.STOP;
555 }
pingping-linb8757bf2013-12-13 01:48:58 +0800556
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700557 // Propagate everything else
558 return Command.CONTINUE;
559 }
pingping-linb8757bf2013-12-13 01:48:58 +0800560
TeruU3c049c42014-04-15 10:13:25 -0700561 private void learnArp(ARP arp) {
562 ArpCacheNotification arpCacheNotification = null;
563
564 arpCacheNotification = new ArpCacheNotification(arp.getSenderProtocolAddress(), arp.getSenderHardwareAddress());
565
566 try {
567 arpCacheEventChannel.addEntry(InetAddress.getByAddress(arp.getSenderProtocolAddress()).toString(), arpCacheNotification);
568 } catch (UnknownHostException e) {
569 log.error("Exception : ", e);
570 }
571 }
572
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700573 private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp,
Ray Milkey269ffb92014-04-03 14:43:30 -0700574 Ethernet eth) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700575 if (log.isTraceEnabled()) {
576 log.trace("ARP request received for {}",
577 inetAddressToString(arp.getTargetProtocolAddress()));
578 }
pingping-linb8757bf2013-12-13 01:48:58 +0800579
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700580 InetAddress target;
581 try {
582 target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
583 } catch (UnknownHostException e) {
584 log.debug("Invalid address in ARP request", e);
585 return;
586 }
Pavlin Radoslavov4cf8ee52014-03-26 18:19:58 -0700587
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700588 if (configService.fromExternalNetwork(sw.getId(), pi.getInPort())) {
589 // If the request came from outside our network, we only care if
590 // it was a request for one of our interfaces.
591 if (configService.isInterfaceAddress(target)) {
592 log.trace(
593 "ARP request for our interface. Sending reply {} => {}",
594 target.getHostAddress(),
595 configService.getRouterMacAddress());
pingping-linb8757bf2013-12-13 01:48:58 +0800596
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700597 sendArpReply(arp, sw.getId(), pi.getInPort(),
598 configService.getRouterMacAddress());
599 }
pingping-linb8757bf2013-12-13 01:48:58 +0800600
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700601 return;
602 }
pingping-linb8757bf2013-12-13 01:48:58 +0800603
TeruU3c049c42014-04-15 10:13:25 -0700604 //MACAddress mac = arpCache.lookup(target);
pingping-linb8757bf2013-12-13 01:48:58 +0800605
TeruU3c049c42014-04-15 10:13:25 -0700606 arpRequests.put(target, new ArpRequest(new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
pingping-linb8757bf2013-12-13 01:48:58 +0800607
TeruU3c049c42014-04-15 10:13:25 -0700608 networkGraph.acquireReadLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 Device targetDevice = networkGraph.getDeviceByMac(MACAddress.valueOf(arp.getTargetHardwareAddress()));
TeruU3c049c42014-04-15 10:13:25 -0700610 networkGraph.releaseReadLock();
pingping-linb8757bf2013-12-13 01:48:58 +0800611
Ray Milkey269ffb92014-04-03 14:43:30 -0700612 if (targetDevice == null) {
613 if (log.isTraceEnabled()) {
614 log.trace("No device info found for {} - broadcasting",
615 target.getHostAddress());
616 }
Jonathan Hart18ad9502013-12-15 18:28:00 -0800617
Ray Milkey269ffb92014-04-03 14:43:30 -0700618 // We don't know the device so broadcast the request out
TeruU3c049c42014-04-15 10:13:25 -0700619 BroadcastPacketOutNotification value =
Ray Milkey269ffb92014-04-03 14:43:30 -0700620 new BroadcastPacketOutNotification(eth.serialize(),
621 ByteBuffer.wrap(arp.getTargetProtocolAddress()).getInt(), sw.getId(), pi.getInPort());
622 log.debug("broadcastPacketOutEventChannel mac {}, ip {}, dpid {}, port {}, paket {}", eth.getSourceMAC().toLong(),
623 ByteBuffer.wrap(arp.getTargetProtocolAddress()).getInt(), sw.getId(), pi.getInPort(), eth.serialize().length);
TeruU3c049c42014-04-15 10:13:25 -0700624 broadcastPacketOutEventChannel.addTransientEntry(eth.getDestinationMAC().toLong(), value);
Ray Milkey269ffb92014-04-03 14:43:30 -0700625 } else {
626 // Even if the device exists in our database, we do not reply to
627 // the request directly, but check whether the device is still valid
628 MACAddress macAddress = MACAddress.valueOf(arp.getTargetHardwareAddress());
Jonathan Hart2f790d22013-08-15 14:01:24 +1200629
Ray Milkey269ffb92014-04-03 14:43:30 -0700630 if (log.isTraceEnabled()) {
631 log.trace("The target Device Record in DB is: {} => {} from ARP request host at {}/{}",
632 new Object[]{
633 inetAddressToString(arp.getTargetProtocolAddress()),
634 macAddress,
635 HexString.toHexString(sw.getId()), pi.getInPort()});
636 }
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200637
Ray Milkey269ffb92014-04-03 14:43:30 -0700638 // sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
Jonathan Hart7804bea2014-01-07 10:50:52 -0800639
Ray Milkey269ffb92014-04-03 14:43:30 -0700640 Iterable<net.onrc.onos.core.topology.Port> outPorts = targetDevice.getAttachmentPoints();
641
642 if (!outPorts.iterator().hasNext()) {
643 if (log.isTraceEnabled()) {
644 log.trace("Device {} exists but is not connected to any ports" +
645 " - broadcasting", macAddress);
646 }
647
TeruU3c049c42014-04-15 10:13:25 -0700648 BroadcastPacketOutNotification value =
649 new BroadcastPacketOutNotification(eth.serialize(),
650 ByteBuffer.wrap(arp.getTargetProtocolAddress()).getInt(), sw.getId(), pi.getInPort());
651 broadcastPacketOutEventChannel.addTransientEntry(eth.getDestinationMAC().toLong(), value);
Ray Milkey269ffb92014-04-03 14:43:30 -0700652 } else {
653 for (net.onrc.onos.core.topology.Port portObject : outPorts) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700654
655 if (portObject.getOutgoingLink() != null || portObject.getIncomingLink() != null) {
656 continue;
657 }
658
659 short outPort = portObject.getNumber().shortValue();
660 Switch outSwitchObject = portObject.getSwitch();
661 long outSwitch = outSwitchObject.getDpid();
662
663 if (log.isTraceEnabled()) {
664 log.trace("Probing device {} on port {}/{}",
665 new Object[]{macAddress,
666 HexString.toHexString(outSwitch), outPort});
667 }
668
TeruU3c049c42014-04-15 10:13:25 -0700669 SinglePacketOutNotification value =
Ray Milkey269ffb92014-04-03 14:43:30 -0700670 new SinglePacketOutNotification(eth.serialize(),
671 ByteBuffer.wrap(target.getAddress()).getInt(), outSwitch, outPort);
TeruU3c049c42014-04-15 10:13:25 -0700672 singlePacketOutEventChannel.addTransientEntry(eth.getDestinationMAC().toLong(), value);
Ray Milkey269ffb92014-04-03 14:43:30 -0700673 }
674 }
675 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700676 }
pingping-linb8757bf2013-12-13 01:48:58 +0800677
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700678 private void sendArpRequestForAddress(InetAddress ipAddress) {
679 // TODO what should the sender IP address and MAC address be if no
680 // IP addresses are configured? Will there ever be a need to send
681 // ARP requests from the controller in that case?
682 // All-zero MAC address doesn't seem to work - hosts don't respond to it
683
684 byte[] zeroIpv4 = {0x0, 0x0, 0x0, 0x0};
685 byte[] zeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
686 byte[] genericNonZeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x01};
687 byte[] broadcastMac = {(byte) 0xff, (byte) 0xff, (byte) 0xff,
688 (byte) 0xff, (byte) 0xff, (byte) 0xff};
689
690 ARP arpRequest = new ARP();
691
692 arpRequest
693 .setHardwareType(ARP.HW_TYPE_ETHERNET)
694 .setProtocolType(ARP.PROTO_TYPE_IP)
695 .setHardwareAddressLength(
696 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
697 .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
698 .setOpCode(ARP.OP_REQUEST).setTargetHardwareAddress(zeroMac)
699 .setTargetProtocolAddress(ipAddress.getAddress());
700
701 MACAddress routerMacAddress = configService.getRouterMacAddress();
TeruU3c049c42014-04-15 10:13:25 -0700702 // As for now, it's unclear what the MAC address should be
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700703 byte[] senderMacAddress = genericNonZeroMac;
704 if (routerMacAddress != null) {
705 senderMacAddress = routerMacAddress.toBytes();
706 }
707 arpRequest.setSenderHardwareAddress(senderMacAddress);
708
709 byte[] senderIPAddress = zeroIpv4;
710 Interface intf = configService.getOutgoingInterface(ipAddress);
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700711 if (intf == null) {
712 // TODO handle the case where the controller needs to send an ARP
713 // request but there's not IP configuration. In this case the
714 // request should be broadcast out all edge ports in the network.
715 log.warn("Sending ARP requests with default configuration "
716 + "not supported");
717 return;
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700718 }
719
Jonathan Hart8ed69c52014-04-09 13:29:16 -0700720 senderIPAddress = intf.getIpAddress().getAddress();
721
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700722 arpRequest.setSenderProtocolAddress(senderIPAddress);
723
724 Ethernet eth = new Ethernet();
725 eth.setSourceMACAddress(senderMacAddress)
726 .setDestinationMACAddress(broadcastMac)
727 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest);
728
729 if (vlan != NO_VLAN) {
730 eth.setVlanID(vlan).setPriorityCode((byte) 0);
731 }
732
733 // sendArpRequestToSwitches(ipAddress, eth.serialize());
TeruU3c049c42014-04-15 10:13:25 -0700734 SinglePacketOutNotification value =
Ray Milkey269ffb92014-04-03 14:43:30 -0700735 new SinglePacketOutNotification(eth.serialize(), ByteBuffer.wrap(ipAddress.getAddress()).getInt(),
736 intf.getDpid(), intf.getPort());
TeruU3c049c42014-04-15 10:13:25 -0700737
738 singlePacketOutEventChannel.addTransientEntry(MACAddress.valueOf(senderMacAddress).toLong(), value);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700739 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700740
TeruU3c049c42014-04-15 10:13:25 -0700741 //Please leave it for now because this code is needed for SDN-IP. It will be removed soon.
Pavlin Radoslavovf1fdc7a2014-04-10 16:05:28 -0700742 /*
TeruU7feef8a2014-04-03 00:15:49 -0700743 private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
TeruU3c049c42014-04-15 10:13:25 -0700744 sendArpRequestToSwitches(dstAddress, arpRequest,
745 0, OFPort.OFPP_NONE.getValue());
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700746 }
747
TeruU3c049c42014-04-15 10:13:25 -0700748 private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest,
749 long inSwitch, short inPort) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700750
751 if (configService.hasLayer3Configuration()) {
752 Interface intf = configService.getOutgoingInterface(dstAddress);
TeruU3c049c42014-04-15 10:13:25 -0700753 if (intf != null) {
754 sendArpRequestOutPort(arpRequest, intf.getDpid(), intf.getPort());
755 }
756 else {
757 //TODO here it should be broadcast out all non-interface edge ports.
758 //I think we can assume that if it's not a request for an external
759 //network, it's an ARP for a host in our own network. So we want to
760 //send it out all edge ports that don't have an interface configured
761 //to ensure it reaches all hosts in our network.
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700762 log.debug("No interface found to send ARP request for {}",
763 dstAddress.getHostAddress());
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700764 }
TeruU3c049c42014-04-15 10:13:25 -0700765 }
766 else {
767 broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700768 }
769 }
Pavlin Radoslavovf1fdc7a2014-04-10 16:05:28 -0700770 */
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700771
772 private void sendArpReplyNotification(Ethernet eth, OFPacketIn pi) {
773 ARP arp = (ARP) eth.getPayload();
774
775 if (log.isTraceEnabled()) {
776 log.trace("Sending ARP reply for {} to other ONOS instances",
777 inetAddressToString(arp.getSenderProtocolAddress()));
778 }
779
780 InetAddress targetAddress;
781
782 try {
783 targetAddress = InetAddress.getByAddress(arp
784 .getSenderProtocolAddress());
785 } catch (UnknownHostException e) {
786 log.error("Unknown host", e);
787 return;
788 }
789
790 MACAddress mac = new MACAddress(arp.getSenderHardwareAddress());
791
TeruU3c049c42014-04-15 10:13:25 -0700792 ArpReplyNotification value =
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 new ArpReplyNotification(ByteBuffer.wrap(targetAddress.getAddress()).getInt(), mac);
794 log.debug("ArpReplyNotification ip {}, mac{}", ByteBuffer.wrap(targetAddress.getAddress()).getInt(), mac);
TeruU3c049c42014-04-15 10:13:25 -0700795 arpReplyEventChannel.addTransientEntry(mac.toLong(), value);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700796 }
797
798 private void broadcastArpRequestOutMyEdge(byte[] arpRequest, long inSwitch,
Ray Milkey269ffb92014-04-03 14:43:30 -0700799 short inPort) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700800 List<SwitchPort> switchPorts = new ArrayList<SwitchPort>();
801
802 for (IOFSwitch sw : floodlightProvider.getSwitches().values()) {
803
804 OFPacketOut po = new OFPacketOut();
805 po.setInPort(OFPort.OFPP_NONE).setBufferId(-1)
806 .setPacketData(arpRequest);
807
808 List<OFAction> actions = new ArrayList<OFAction>();
809
TeruU3c049c42014-04-15 10:13:25 -0700810 networkGraph.acquireReadLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700811 Switch graphSw = networkGraph.getSwitch(sw.getId());
TeruU3c049c42014-04-15 10:13:25 -0700812 networkGraph.releaseReadLock();
813
Ray Milkey269ffb92014-04-03 14:43:30 -0700814 Collection<net.onrc.onos.core.topology.Port> ports = graphSw.getPorts();
815
816 if (ports == null) {
817 continue;
818 }
819
820 for (net.onrc.onos.core.topology.Port portObject : ports) {
821 if (portObject.getOutgoingLink() == null && portObject.getNumber() > 0) {
822 Long portNumber = portObject.getNumber();
823
824 if (sw.getId() == inSwitch && portNumber.shortValue() == inPort) {
825 // This is the port that the ARP message came in,
826 // so don't broadcast out this port
827 continue;
828 }
829 switchPorts.add(new SwitchPort(new Dpid(sw.getId()),
830 new net.onrc.onos.core.util.Port(portNumber.shortValue())));
831 actions.add(new OFActionOutput(portNumber.shortValue()));
832 }
833 }
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700834
835 po.setActions(actions);
836 short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
837 po.setActionsLength(actionsLength);
838 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
839 + arpRequest.length);
840
841 flowPusher.add(sw, po);
842 }
843
844 if (log.isTraceEnabled()) {
845 log.trace("Broadcast ARP request to: {}", switchPorts);
846 }
847 }
848
849 private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
850 if (log.isTraceEnabled()) {
851 log.trace("Sending ARP request out {}/{}",
852 HexString.toHexString(dpid), port);
853 }
854
855 OFPacketOut po = new OFPacketOut();
856 po.setInPort(OFPort.OFPP_NONE).setBufferId(-1)
857 .setPacketData(arpRequest);
858
859 List<OFAction> actions = new ArrayList<OFAction>();
860 actions.add(new OFActionOutput(port));
861 po.setActions(actions);
862 short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
863 po.setActionsLength(actionsLength);
864 po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
865 + arpRequest.length);
866
867 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
868
869 if (sw == null) {
870 log.warn("Switch not found when sending ARP request");
871 return;
872 }
873
874 flowPusher.add(sw, po);
875 }
876
877 private void sendArpReply(ARP arpRequest, long dpid, short port,
Ray Milkey269ffb92014-04-03 14:43:30 -0700878 MACAddress targetMac) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700879 if (log.isTraceEnabled()) {
880 log.trace(
881 "Sending reply {} => {} to {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700882 new Object[]{
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700883 inetAddressToString(arpRequest
884 .getTargetProtocolAddress()),
885 targetMac,
886 inetAddressToString(arpRequest
887 .getSenderProtocolAddress())});
888 }
889
890 ARP arpReply = new ARP();
891 arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
892 .setProtocolType(ARP.PROTO_TYPE_IP)
893 .setHardwareAddressLength(
894 (byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
895 .setProtocolAddressLength((byte) IPv4.ADDRESS_LENGTH)
896 .setOpCode(ARP.OP_REPLY)
897 .setSenderHardwareAddress(targetMac.toBytes())
898 .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
899 .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
900 .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
901
902 Ethernet eth = new Ethernet();
903 eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
904 .setSourceMACAddress(targetMac.toBytes())
905 .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply);
906
907 if (vlan != NO_VLAN) {
908 eth.setVlanID(vlan).setPriorityCode((byte) 0);
909 }
910
911 List<OFAction> actions = new ArrayList<OFAction>();
912 actions.add(new OFActionOutput(port));
913
914 OFPacketOut po = new OFPacketOut();
915 po.setInPort(OFPort.OFPP_NONE)
916 .setBufferId(-1)
917 .setPacketData(eth.serialize())
918 .setActions(actions)
919 .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
920 .setLengthU(
921 OFPacketOut.MINIMUM_LENGTH
922 + OFActionOutput.MINIMUM_LENGTH
923 + po.getPacketData().length);
924
925 List<OFMessage> msgList = new ArrayList<OFMessage>();
926 msgList.add(po);
927
928 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
929
930 if (sw == null) {
931 log.warn("Switch {} not found when sending ARP reply",
932 HexString.toHexString(dpid));
933 return;
934 }
935
936 flowPusher.add(sw, po);
937 }
938
939 private String inetAddressToString(byte[] bytes) {
940 try {
941 return InetAddress.getByAddress(bytes).getHostAddress();
942 } catch (UnknownHostException e) {
943 log.debug("Invalid IP address", e);
944 return "";
945 }
946 }
947
948 /*
949 * IProxyArpService methods
950 */
951
952 @Override
953 public MACAddress getMacAddress(InetAddress ipAddress) {
TeruU3c049c42014-04-15 10:13:25 -0700954 return arpCache.lookup(ipAddress);
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700955 }
956
957 @Override
958 public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
Ray Milkey269ffb92014-04-03 14:43:30 -0700959 boolean retry) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700960 arpRequests.put(ipAddress, new ArpRequest(requester, retry));
961
962 // Sanity check to make sure we don't send a request for our own address
963 if (!configService.isInterfaceAddress(ipAddress)) {
964 sendArpRequestForAddress(ipAddress);
965 }
966 }
967
968 @Override
969 public List<String> getMappings() {
970 return new ArrayList<String>();
971 }
972
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700973 private void sendArpReplyToWaitingRequesters(InetAddress address,
Ray Milkey269ffb92014-04-03 14:43:30 -0700974 MACAddress mac) {
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700975 log.debug("Sending ARP reply for {} to requesters",
976 address.getHostAddress());
977
978 // See if anyone's waiting for this ARP reply
979 Set<ArpRequest> requests = arpRequests.get(address);
980
981 // Synchronize on the Multimap while using an iterator for one of the
982 // sets
983 List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(
984 requests.size());
985 synchronized (arpRequests) {
986 Iterator<ArpRequest> it = requests.iterator();
987 while (it.hasNext()) {
988 ArpRequest request = it.next();
989 it.remove();
990 requestsToSend.add(request);
991 }
992 }
993
Jonathan Hart7c9a2fb2014-03-27 09:51:41 -0700994 // Don't hold an ARP lock while dispatching requests
995 for (ArpRequest request : requestsToSend) {
996 request.dispatchReply(address, mac);
997 }
998 }
TeruU3c049c42014-04-15 10:13:25 -0700999
1000 private void doPeriodicArpCleaning() {
1001 List<InetAddress> expiredipslist = arpCache.getExpiredArpCacheIps();
1002 for (InetAddress expireIp : expiredipslist) {
1003 log.debug("call arpCacheEventChannel.removeEntry, ip {}", expireIp);
1004 arpCacheEventChannel.removeEntry(expireIp.toString());
1005 }
1006 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001007}