3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
13 package org.opendaylight.controller.arphandler.internal;
15 import java.net.InetAddress;
16 import java.net.UnknownHostException;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.EnumSet;
20 import java.util.HashSet;
22 import java.util.Timer;
23 import java.util.TimerTask;
24 import java.util.concurrent.BlockingQueue;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.CopyOnWriteArraySet;
28 import java.util.concurrent.LinkedBlockingQueue;
30 import org.opendaylight.controller.arphandler.ARPCacheEvent;
31 import org.opendaylight.controller.arphandler.ARPEvent;
32 import org.opendaylight.controller.arphandler.ARPReply;
33 import org.opendaylight.controller.arphandler.ARPRequest;
34 import org.opendaylight.controller.clustering.services.CacheConfigException;
35 import org.opendaylight.controller.clustering.services.CacheExistException;
36 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
37 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
38 import org.opendaylight.controller.clustering.services.IClusterServices;
39 import org.opendaylight.controller.connectionmanager.IConnectionManager;
40 import org.opendaylight.controller.hosttracker.IfHostListener;
41 import org.opendaylight.controller.hosttracker.IfIptoHost;
42 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
43 import org.opendaylight.controller.hosttracker.hostAware.IHostFinder;
44 import org.opendaylight.controller.sal.core.ConstructionException;
45 import org.opendaylight.controller.sal.core.Node;
46 import org.opendaylight.controller.sal.core.NodeConnector;
47 import org.opendaylight.controller.sal.packet.ARP;
48 import org.opendaylight.controller.sal.packet.Ethernet;
49 import org.opendaylight.controller.sal.packet.IDataPacketService;
50 import org.opendaylight.controller.sal.packet.IListenDataPacket;
51 import org.opendaylight.controller.sal.packet.IPv4;
52 import org.opendaylight.controller.sal.packet.Packet;
53 import org.opendaylight.controller.sal.packet.PacketResult;
54 import org.opendaylight.controller.sal.packet.RawPacket;
55 import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
56 import org.opendaylight.controller.sal.utils.EtherTypes;
57 import org.opendaylight.controller.sal.utils.HexEncode;
58 import org.opendaylight.controller.sal.utils.NetUtils;
59 import org.opendaylight.controller.switchmanager.ISwitchManager;
60 import org.opendaylight.controller.switchmanager.Subnet;
61 import org.opendaylight.controller.topologymanager.ITopologyManager;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
65 public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateAware<ARPEvent, Boolean> {
66 private static final Logger log = LoggerFactory.getLogger(ArpHandler.class);
67 static final String ARP_EVENT_CACHE_NAME = "arphandler.arpRequestReplyEvent";
68 private IfIptoHost hostTracker;
69 private ISwitchManager switchManager;
70 private ITopologyManager topologyManager;
71 private IDataPacketService dataPacketService;
72 private IClusterContainerServices clusterContainerService;
73 private IConnectionManager connectionManager;
74 private Set<IfHostListener> hostListeners = new CopyOnWriteArraySet<IfHostListener>();
75 private ConcurrentMap<InetAddress, Set<HostNodeConnector>> arpRequestors;
76 private ConcurrentMap<InetAddress, Short> countDownTimers;
77 private Timer periodicTimer;
78 private BlockingQueue<ARPCacheEvent> ARPCacheEvents = new LinkedBlockingQueue<ARPCacheEvent>();
79 private Thread cacheEventHandler;
80 private boolean stopping = false;
82 * A cluster allocated cache. Used for synchronizing ARP request/reply
83 * events across all cluster controllers. To raise an event, we put() a specific
84 * event object (as key) and all nodes handle it in the entryUpdated callback.
86 * In case of ARPReply, we put true value to send replies to any requestors
87 * by calling generateAndSendReply
89 private ConcurrentMap<ARPEvent, Boolean> arpRequestReplyEvent;
91 void setConnectionManager(IConnectionManager cm){
92 this.connectionManager = cm;
95 void unsetConnectionManager(IConnectionManager cm){
96 if (this.connectionManager == cm){
97 connectionManager = null;
101 void setClusterContainerService(IClusterContainerServices s){
102 this.clusterContainerService = s;
105 void unsetClusterContainerService(IClusterContainerServices s) {
106 if (this.clusterContainerService == s) {
107 this.clusterContainerService = null;
111 void setHostListener(IfHostListener s) {
112 if (this.hostListeners != null) {
113 this.hostListeners.add(s);
117 void unsetHostListener(IfHostListener s) {
118 if (this.hostListeners != null) {
119 this.hostListeners.remove(s);
123 void setDataPacketService(IDataPacketService s) {
124 this.dataPacketService = s;
127 void unsetDataPacketService(IDataPacketService s) {
128 if (this.dataPacketService == s) {
129 this.dataPacketService = null;
133 public void setHostTracker(IfIptoHost hostTracker) {
134 log.debug("Setting HostTracker");
135 this.hostTracker = hostTracker;
138 public void unsetHostTracker(IfIptoHost s) {
139 log.debug("UNSetting HostTracker");
140 if (this.hostTracker == s) {
141 this.hostTracker = null;
145 public void setTopologyManager(ITopologyManager tm) {
146 this.topologyManager = tm;
149 public void unsetTopologyManager(ITopologyManager tm) {
150 if (this.topologyManager == tm) {
151 this.topologyManager = null;
155 protected void sendARPReply(NodeConnector p, byte[] sMAC, InetAddress sIP,
156 byte[] tMAC, InetAddress tIP) {
157 byte[] senderIP = sIP.getAddress();
158 byte[] targetIP = tIP.getAddress();
160 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
161 .setProtocolType(EtherTypes.IPv4.shortValue())
162 .setHardwareAddressLength((byte) 6)
163 .setProtocolAddressLength((byte) 4)
164 .setOpCode(ARP.REPLY)
165 .setSenderHardwareAddress(sMAC)
166 .setSenderProtocolAddress(senderIP)
167 .setTargetHardwareAddress(tMAC)
168 .setTargetProtocolAddress(targetIP);
170 Ethernet ethernet = new Ethernet();
171 ethernet.setSourceMACAddress(sMAC)
172 .setDestinationMACAddress(tMAC)
173 .setEtherType(EtherTypes.ARP.shortValue())
176 RawPacket destPkt = this.dataPacketService.encodeDataPacket(ethernet);
177 destPkt.setOutgoingNodeConnector(p);
179 this.dataPacketService.transmitDataPacket(destPkt);
182 protected void handleARPPacket(Ethernet eHeader, ARP pkt, NodeConnector p) {
184 byte[] sourceMAC = eHeader.getSourceMACAddress();
185 byte[] targetMAC = eHeader.getDestinationMACAddress();
187 * Sanity Check; drop ARP packets originated by the controller itself.
188 * This is to avoid continuous flooding
190 if (Arrays.equals(sourceMAC, getControllerMAC())) {
191 if (log.isDebugEnabled()) {
192 log.debug("Receive a self originated ARP pkt (srcMAC {}) --> DROP",
193 HexEncode.bytesToHexString(sourceMAC));
198 InetAddress targetIP, sourceIP;
200 targetIP = InetAddress.getByAddress(pkt.getTargetProtocolAddress());
201 sourceIP = InetAddress.getByAddress(pkt.getSenderProtocolAddress());
202 } catch (UnknownHostException e1) {
203 log.debug("Invalid host in ARP packet: {}", e1.getMessage());
207 Subnet subnet = null;
208 if (switchManager != null) {
209 subnet = switchManager.getSubnetByNetworkAddress(sourceIP);
211 if (subnet == null) {
212 log.debug("ARPHandler: can't find subnet matching {}, drop packet", sourceIP);
216 // Make sure that the host is a legitimate member of this subnet
217 if (!subnet.hasNodeConnector(p)) {
218 log.debug("{} showing up on {} does not belong to {}",
219 new Object[] { sourceIP, p, subnet });
223 HostNodeConnector requestor = null;
224 if (NetUtils.isUnicastMACAddr(sourceMAC) && p.getNode() != null) {
226 requestor = new HostNodeConnector(sourceMAC, sourceIP, p, subnet.getVlan());
227 } catch (ConstructionException e) {
228 log.debug("Received ARP packet with invalid MAC: {}", HexEncode.bytesToHexString(sourceMAC));
232 * Learn host from the received ARP REQ/REPLY, inform Host Tracker
234 log.trace("Inform Host tracker of new host {}", requestor.getNetworkAddress());
235 for (IfHostListener listener : this.hostListeners) {
236 listener.hostListener(requestor);
241 * OpCode != request -> ARP Reply. If there are hosts (in
242 * arpRequestors) waiting for the ARP reply for this sourceIP, it's
243 * time to generate the reply and send it to these hosts.
245 * If sourceIP==targetIP, it is a Gratuitous ARP. If there are hosts (in
246 * arpRequestors) waiting for the ARP reply for this sourceIP, it's time
247 * to generate the reply and send it to these hosts
250 if (pkt.getOpCode() != ARP.REQUEST || sourceIP.equals(targetIP)) {
251 // Raise a reply event so that any waiting requestors will be sent a reply
252 // the true value indicates we should generate replies to requestors across the cluster
253 log.trace("Received ARP reply packet from {}, reply to all requestors.", sourceIP);
254 arpRequestReplyEvent.put(new ARPReply(sourceIP, sourceMAC), true);
259 * ARP Request Handling:
260 * If targetIP is the IP of the subnet, reply with ARP REPLY
261 * If targetIP is a known host, PROXY ARP (by sending ARP REPLY) on behalf of known target hosts.
262 * For unknown target hosts, generate and send an ARP request to ALL switches/ports using
263 * the IP address defined in the subnet as source address
266 * If target IP is gateway IP, Send ARP reply
268 if ((targetIP.equals(subnet.getNetworkAddress()))
269 && (NetUtils.isBroadcastMACAddr(targetMAC) || Arrays.equals(targetMAC, getControllerMAC()))) {
270 if (connectionManager.isLocal(p.getNode())){
271 if (log.isTraceEnabled()){
272 log.trace("Received local ARP req. for default gateway. Replying with controller MAC: {}",
273 HexEncode.bytesToHexString(getControllerMAC()));
275 sendARPReply(p, getControllerMAC(), targetIP, pkt.getSenderHardwareAddress(), sourceIP);
277 log.trace("Received non-local ARP req. for default gateway. Raising reply event");
278 arpRequestReplyEvent.put(
279 new ARPReply(p, targetIP, getControllerMAC(), sourceIP, pkt.getSenderHardwareAddress()), false);
285 HostNodeConnector host = hostTracker.hostQuery(targetIP);
286 // unknown host, initiate ARP request
288 // add the requestor to the list so that we can replay the reply
289 // when the host responds
290 if (requestor != null) {
291 Set<HostNodeConnector> requestorSet = arpRequestors.get(targetIP);
292 if (requestorSet == null) {
293 requestorSet = Collections.newSetFromMap(new ConcurrentHashMap<HostNodeConnector, Boolean>());
294 arpRequestors.put(targetIP, requestorSet);
296 requestorSet.add(requestor);
297 countDownTimers.put(targetIP, (short) 2); // reset timeout to 2sec
299 //Raise a bcast request event, all controllers need to send one
300 log.trace("Sending a bcast ARP request for {}", targetIP);
301 arpRequestReplyEvent.put(new ARPRequest(targetIP, subnet), false);
304 * Target host known (across the cluster), send ARP REPLY make sure that targetMAC
305 * matches the host's MAC if it is not broadcastMAC
307 if (NetUtils.isBroadcastMACAddr(targetMAC) || Arrays.equals(host.getDataLayerAddressBytes(), targetMAC)) {
308 log.trace("Received ARP req. for known host {}, sending reply...", targetIP);
309 if (connectionManager.isLocal(p.getNode())) {
311 host.getDataLayerAddressBytes(),
312 host.getNetworkAddress(),
313 pkt.getSenderHardwareAddress(),
316 arpRequestReplyEvent.put(new ARPReply(
318 host.getNetworkAddress(),
319 host.getDataLayerAddressBytes(),
321 pkt.getSenderHardwareAddress()), false);
325 * Target MAC has been changed. For now, discard it.
326 * TODO: We may need to send unicast ARP REQUEST on behalf of
327 * the target back to the sender to trigger the sender to update
335 * Send a broadcast ARP Request to the switch/ ports using
336 * the networkAddress of the subnet as sender IP
337 * the controller's MAC as sender MAC
338 * the targetIP as the target Network Address
340 protected void sendBcastARPRequest(InetAddress targetIP, Subnet subnet) {
341 log.trace("sendBcatARPRequest targetIP:{} subnet:{}", targetIP, subnet);
342 Set<NodeConnector> nodeConnectors;
343 if (subnet.isFlatLayer2()) {
344 nodeConnectors = new HashSet<NodeConnector>();
345 for (Node n : this.switchManager.getNodes()) {
346 nodeConnectors.addAll(this.switchManager.getUpNodeConnectors(n));
349 nodeConnectors = subnet.getNodeConnectors();
352 for (NodeConnector p : nodeConnectors) {
353 //fiter out any non-local or internal ports
354 if (! connectionManager.isLocal(p.getNode()) || topologyManager.isInternal(p)) {
357 log.trace("Sending toward nodeConnector:{}", p);
359 byte[] senderIP = subnet.getNetworkAddress().getAddress();
360 byte[] targetIPByte = targetIP.getAddress();
361 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
362 .setProtocolType(EtherTypes.IPv4.shortValue())
363 .setHardwareAddressLength((byte) 6)
364 .setProtocolAddressLength((byte) 4)
365 .setOpCode(ARP.REQUEST)
366 .setSenderHardwareAddress(getControllerMAC())
367 .setSenderProtocolAddress(senderIP)
368 .setTargetHardwareAddress(
369 new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 })
370 .setTargetProtocolAddress(targetIPByte);
372 Ethernet ethernet = new Ethernet();
373 ethernet.setSourceMACAddress(getControllerMAC())
374 .setDestinationMACAddress(new byte[] {(byte) -1,
380 .setEtherType(EtherTypes.ARP.shortValue()).setPayload(arp);
382 // TODO For now send port-by-port, see how to optimize to
383 // send to multiple ports at once
384 RawPacket destPkt = this.dataPacketService.encodeDataPacket(ethernet);
385 destPkt.setOutgoingNodeConnector(p);
387 this.dataPacketService.transmitDataPacket(destPkt);
392 * Send a unicast ARP Request to the known host on a specific switch/port as
393 * defined in the host.
394 * The sender IP is the networkAddress of the subnet
395 * The sender MAC is the controller's MAC
397 protected void sendUcastARPRequest(HostNodeConnector host, Subnet subnet) {
398 log.trace("sendUcastARPRequest host:{} subnet:{}", host, subnet);
399 NodeConnector outPort = host.getnodeConnector();
400 if (outPort == null) {
401 log.error("Failed sending UcastARP because cannot extract output port from Host: {}", host);
405 byte[] senderIP = subnet.getNetworkAddress().getAddress();
406 byte[] targetIP = host.getNetworkAddress().getAddress();
407 byte[] targetMAC = host.getDataLayerAddressBytes();
409 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
410 .setProtocolType(EtherTypes.IPv4.shortValue())
411 .setHardwareAddressLength((byte) 6)
412 .setProtocolAddressLength((byte) 4)
413 .setOpCode(ARP.REQUEST)
414 .setSenderHardwareAddress(getControllerMAC())
415 .setSenderProtocolAddress(senderIP)
416 .setTargetHardwareAddress(targetMAC)
417 .setTargetProtocolAddress(targetIP);
419 Ethernet ethernet = new Ethernet();
420 ethernet.setSourceMACAddress(getControllerMAC())
421 .setDestinationMACAddress(targetMAC)
422 .setEtherType(EtherTypes.ARP.shortValue())
425 RawPacket destPkt = this.dataPacketService.encodeDataPacket(ethernet);
426 destPkt.setOutgoingNodeConnector(outPort);
428 this.dataPacketService.transmitDataPacket(destPkt);
432 public void find(InetAddress networkAddress) {
433 log.trace("Received find IP {}", networkAddress);
435 Subnet subnet = null;
436 if (switchManager != null) {
437 subnet = switchManager.getSubnetByNetworkAddress(networkAddress);
439 if (subnet == null) {
440 log.debug("Can't find subnet matching IP {}", networkAddress);
444 // send a broadcast ARP Request to this IP
445 arpRequestReplyEvent.put(new ARPRequest(networkAddress, subnet), false);
449 * Probe the host by sending a unicast ARP Request to the host
452 public void probe(HostNodeConnector host) {
453 log.trace("Received probe host {}", host);
455 Subnet subnet = null;
456 if (switchManager != null) {
457 subnet = switchManager.getSubnetByNetworkAddress(host
458 .getNetworkAddress());
460 if (subnet == null) {
461 log.debug("can't find subnet matching {}", host.getNetworkAddress());
465 if (connectionManager.isLocal(host.getnodeconnectorNode())){
466 log.trace("Send a ucast ARP req. to: {}", host);
467 sendUcastARPRequest(host, subnet);
469 log.trace("Raise a ucast ARP req. event to: {}", host);
470 arpRequestReplyEvent.put(new ARPRequest(host, subnet), false);
475 * An IP packet is punted to the controller, this means that the
476 * destination host is not known to the controller.
477 * Need to discover it by sending a Broadcast ARP Request
479 protected void handlePuntedIPPacket(IPv4 pkt, NodeConnector p) {
481 InetAddress dIP = NetUtils.getInetAddress(pkt.getDestinationAddress());
486 Subnet subnet = null;
487 if (switchManager != null) {
488 subnet = switchManager.getSubnetByNetworkAddress(dIP);
490 if (subnet == null) {
491 log.debug("Can't find subnet matching {}, drop packet", dIP);
494 log.trace("Punted IP pkt from {}, sending bcast ARP event...", dIP);
496 * unknown destination host, initiate bcast ARP request
498 arpRequestReplyEvent.put(new ARPRequest(dIP, subnet), false);
502 public byte[] getControllerMAC() {
503 if (switchManager == null) {
506 return switchManager.getControllerMAC();
510 * Function called by the dependency manager when all the required
511 * dependencies are satisfied
515 arpRequestors = new ConcurrentHashMap<InetAddress, Set<HostNodeConnector>>();
516 countDownTimers = new ConcurrentHashMap<InetAddress, Short>();
517 cacheEventHandler = new Thread(new ARPCacheEventHandler(), "ARPCacheEventHandler Thread");
523 @SuppressWarnings({ "unchecked", "deprecation" })
524 private void retrieveCaches() {
525 ConcurrentMap<?,?> map;
527 if (this.clusterContainerService == null){
528 log.error("Cluster service unavailable, can't retieve ARPHandler caches!");
532 map = clusterContainerService.getCache(ARP_EVENT_CACHE_NAME);
534 this.arpRequestReplyEvent = (ConcurrentMap<ARPEvent, Boolean>) map;
536 log.error("Cache allocation failed for {}", ARP_EVENT_CACHE_NAME);
540 @SuppressWarnings("deprecation")
541 private void allocateCaches() {
542 if (clusterContainerService == null){
543 nonClusterObjectCreate();
544 log.error("Clustering service unavailable. Allocated non-cluster caches for ARPHandler.");
549 clusterContainerService.createCache(ARP_EVENT_CACHE_NAME,
550 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
551 } catch (CacheConfigException e){
552 log.error("ARPHandler cache configuration invalid!");
553 } catch (CacheExistException e){
554 log.debug("ARPHandler cache exists, skipped allocation.");
559 private void nonClusterObjectCreate(){
560 arpRequestReplyEvent = new ConcurrentHashMap<ARPEvent, Boolean>();
563 * Function called by the dependency manager when at least one
564 * dependency become unsatisfied or when the component is shutting
565 * down because for example bundle is being stopped.
569 cacheEventHandler.interrupt();
573 * Function called by dependency manager after "init ()" is called
574 * and after the services provided by the class are registered in
575 * the service registry
580 startPeriodicTimer();
581 cacheEventHandler.start();
585 * Function called by the dependency manager before the services
586 * exported by the component are unregistered, this will be
587 * followed by a "destroy ()" calls
595 cancelPeriodicTimer();
598 void setSwitchManager(ISwitchManager s) {
599 log.debug("SwitchManager service set.");
600 this.switchManager = s;
603 void unsetSwitchManager(ISwitchManager s) {
604 if (this.switchManager == s) {
605 log.debug("SwitchManager service UNset.");
606 this.switchManager = null;
611 public PacketResult receiveDataPacket(RawPacket inPkt) {
613 return PacketResult.IGNORED;
615 log.trace("Received a frame of size: {}", inPkt.getPacketData().length);
616 Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
617 if (formattedPak instanceof Ethernet) {
618 Object nextPak = formattedPak.getPayload();
619 if (nextPak instanceof IPv4) {
620 log.trace("Handle IP packet: {}", formattedPak);
621 handlePuntedIPPacket((IPv4) nextPak, inPkt.getIncomingNodeConnector());
622 } else if (nextPak instanceof ARP) {
623 log.trace("Handle ARP packet: {}", formattedPak);
624 handleARPPacket((Ethernet) formattedPak, (ARP) nextPak, inPkt
625 .getIncomingNodeConnector());
628 return PacketResult.IGNORED;
631 private void startPeriodicTimer() {
632 this.periodicTimer = new Timer("ArpHandler Periodic Timer");
633 this.periodicTimer.scheduleAtFixedRate(new TimerTask() {
634 @SuppressWarnings("deprecation")
637 Set<InetAddress> targetIPs = countDownTimers.keySet();
638 Set<InetAddress> expiredTargets = new HashSet<InetAddress>();
639 for (InetAddress t : targetIPs) {
640 short tick = countDownTimers.get(t);
643 expiredTargets.add(t);
645 countDownTimers.replace(t, tick);
648 for (InetAddress tIP : expiredTargets) {
649 countDownTimers.remove(tIP);
650 // Remove the requestor(s) who have been waiting for the ARP
651 // reply from this target for more than 1sec
652 arpRequestors.remove(tIP);
653 log.debug("ARP reply was not received from {}", tIP);
656 // Clean up ARP event cache
658 if (clusterContainerService.amICoordinator() && ! arpRequestReplyEvent.isEmpty()){
659 arpRequestReplyEvent.clear();
661 } catch (Exception e){
662 log.warn("ARPHandler: A cluster member failed to clear event cache.");
668 private void cancelPeriodicTimer() {
669 if (this.periodicTimer != null) {
670 this.periodicTimer.cancel();
674 private void generateAndSendReply(InetAddress sourceIP, byte[] sourceMAC) {
675 if (log.isTraceEnabled()) {
676 log.trace("generateAndSendReply called with params sourceIP:{} sourceMAC:{}", sourceIP,
677 HexEncode.bytesToHexString(sourceMAC));
679 Set<HostNodeConnector> hosts = arpRequestors.remove(sourceIP);
680 if ((hosts == null) || hosts.isEmpty()) {
681 log.trace("Bailing out no requestors Hosts");
684 countDownTimers.remove(sourceIP);
685 for (HostNodeConnector host : hosts) {
686 if (log.isTraceEnabled()) {
687 log.trace("Sending ARP Reply with src {}/{}, target {}/{}",
689 HexEncode.bytesToHexString(sourceMAC),
691 HexEncode.bytesToHexString(host.getDataLayerAddressBytes()),
692 host.getNetworkAddress() });
694 if (connectionManager.isLocal(host.getnodeconnectorNode())){
695 sendARPReply(host.getnodeConnector(),
698 host.getDataLayerAddressBytes(),
699 host.getNetworkAddress());
702 * In the remote event a requestor moved to another
703 * controller it may turn out it now we need to send
704 * the ARP reply from a different controller, this
707 arpRequestReplyEvent.put(
709 host.getnodeConnector(),
712 host.getNetworkAddress(),
713 host.getDataLayerAddressBytes()), false);
720 public void entryUpdated(ARPEvent key, Boolean new_value, String cacheName, boolean originLocal) {
721 log.trace("Got and entryUpdated for cacheName {} key {} isNew {}", cacheName, key, new_value);
722 enqueueARPCacheEvent(key, new_value);
726 public void entryCreated(ARPEvent key, String cacheName, boolean originLocal) {
730 public void entryDeleted(ARPEvent key, String cacheName, boolean originLocal) {
734 private void enqueueARPCacheEvent (ARPEvent event, boolean new_value) {
736 ARPCacheEvent cacheEvent = new ARPCacheEvent(event, new_value);
737 if (!ARPCacheEvents.contains(cacheEvent)) {
738 this.ARPCacheEvents.add(cacheEvent);
739 log.trace("Enqueued {}", event);
741 } catch (Exception e) {
742 log.debug("enqueueARPCacheEvent caught Interrupt Exception for event {}", event);
747 * this thread monitors the connectionEvent queue for new incoming events from
749 private class ARPCacheEventHandler implements Runnable {
754 ARPCacheEvent ev = ARPCacheEvents.take();
755 ARPEvent event = ev.getEvent();
756 if (event instanceof ARPRequest) {
757 ARPRequest req = (ARPRequest) event;
758 // If broadcast request
759 if (req.getHost() == null) {
760 log.trace("Trigger and ARP Broadcast Request upon receipt of {}", req);
761 sendBcastARPRequest(req.getTargetIP(), req.getSubnet());
763 //If unicast and local, send reply
764 } else if (connectionManager.isLocal(req.getHost().getnodeconnectorNode())) {
765 log.trace("ARPCacheEventHandler - sendUcatARPRequest upon receipt of {}", req);
766 sendUcastARPRequest(req.getHost(), req.getSubnet());
768 } else if (event instanceof ARPReply) {
769 ARPReply rep = (ARPReply) event;
770 // New reply received by controller, notify all awaiting requestors across the cluster
771 if (ev.isNewReply()) {
772 log.trace("Trigger a generateAndSendReply in response to {}", rep);
773 generateAndSendReply(rep.getTargetIP(), rep.getTargetMac());
774 // Otherwise, a specific reply. If local, send out.
775 } else if (connectionManager.isLocal(rep.getPort().getNode())) {
776 log.trace("ARPCacheEventHandler - sendUcatARPReply locally in response to {}", rep);
777 sendARPReply(rep.getPort(),
784 } catch (InterruptedException e) {
785 ARPCacheEvents.clear();