X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Farphandler%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Farphandler%2Finternal%2FArpHandler.java;h=fe456f3f8ebe6f6237352cb09f5b6a7dc8056398;hp=8ae038c30f38bb38410b1c093c7a7a6b791ca507;hb=6f9fda057ddadd8d4eef643bca398cea65dd2007;hpb=91d7c1ee52322acad08e9f81228ac36b3aa684f5 diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java index 8ae038c30f..fe456f3f8e 100644 --- a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java +++ b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java @@ -49,12 +49,12 @@ import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.packet.ARP; import org.opendaylight.controller.sal.packet.Ethernet; import org.opendaylight.controller.sal.packet.IDataPacketService; +import org.opendaylight.controller.sal.packet.IEEE8021Q; import org.opendaylight.controller.sal.packet.IListenDataPacket; import org.opendaylight.controller.sal.packet.IPv4; import org.opendaylight.controller.sal.packet.Packet; import org.opendaylight.controller.sal.packet.PacketResult; import org.opendaylight.controller.sal.packet.RawPacket; -import org.opendaylight.controller.sal.routing.IRouting; import org.opendaylight.controller.sal.utils.EtherTypes; import org.opendaylight.controller.sal.utils.HexEncode; import org.opendaylight.controller.sal.utils.NetUtils; @@ -64,6 +64,31 @@ import org.opendaylight.controller.topologymanager.ITopologyManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * The ArpHandler offers services to react on ARP requests and replies + * sent by network hosts. Moreover it allows for creating ARP messages + * by the controller itself. + * + * The ARP Handler on ODL doesn't use the requester MAC address in + * order to avoid to have to build a spanning tree where to forward + * ARP Requests. The ARP requests are broadcast packets so in order to + * reach everywhere need to be flooded, when you flood in a network + * that is not a tree (all the networks has some level of redundancy) + * that would create forwarding loops without a spanning tree. Given + * the need is only to send out the ARP requests toward all the hosts + * we actually don't need to implement a flooding mechanism in software + * (which would be expensive) we just send out the ARP request toward + * all the ports that are suspected to be host ports on all the + * switches (from the controller). Now the condition for which a port + * is marked as host port could potentially be incorrect so when the + * controller sends out the ARP Request that could come back to the + * controller and could cause another request not needed. So changing + * the source MAC address of the request to be the one of the controller, + * controller can protect itself from honoring twice the same request. + * This enables an ARP handler resolution, without the need of spanning + * tree and limiting software flooding to the minimum required. + */ + public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateAware { private static final Logger log = LoggerFactory.getLogger(ArpHandler.class); static final String ARP_EVENT_CACHE_NAME = "arphandler.arpRequestReplyEvent"; @@ -71,7 +96,6 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA private ISwitchManager switchManager; private ITopologyManager topologyManager; private IDataPacketService dataPacketService; - private IRouting routing; private IClusterContainerServices clusterContainerService; private IConnectionManager connectionManager; private Set hostListeners = new CopyOnWriteArraySet(); @@ -113,16 +137,6 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } } - void setRouting(IRouting r) { - this.routing = r; - } - - void unsetRouting(IRouting r) { - if (this.routing == r) { - this.routing = null; - } - } - void setHostListener(IfHostListener s) { if (this.hostListeners != null) { this.hostListeners.add(s); @@ -167,12 +181,18 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } } - protected void sendARPReply(NodeConnector p, byte[] sMAC, InetAddress sIP, byte[] tMAC, InetAddress tIP) { + protected void sendARPReply(NodeConnector p, byte[] sMAC, InetAddress sIP, byte[] tMAC, InetAddress tIP, short vlan) { byte[] senderIP = sIP.getAddress(); byte[] targetIP = tIP.getAddress(); ARP arp = createARP(ARP.REPLY, sMAC, senderIP, tMAC, targetIP); - Ethernet ethernet = createEthernet(sMAC, tMAC, arp); + if(log.isTraceEnabled()) { + log.trace("Sending Arp Reply with srcMac {} - srcIp {} - dstMac {} - dstIp {} - outport {}", + HexEncode.bytesToHexString(sMAC), + sIP, HexEncode.bytesToHexString(tMAC), tIP, p); + } + + Ethernet ethernet = createEthernet(sMAC, tMAC, arp, vlan); RawPacket destPkt = this.dataPacketService.encodeDataPacket(ethernet); destPkt.setOutgoingNodeConnector(p); @@ -180,7 +200,25 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA this.dataPacketService.transmitDataPacket(destPkt); } - protected void handleARPPacket(Ethernet eHeader, ARP pkt, NodeConnector p) { + private void logArpPacket(ARP pkt, NodeConnector p, short vlan) { + try { + log.trace("Received Arp {} with srcMac {} - srcIp {} - dstMac {} - dstIp {} - inport {} {}", + ((pkt.getOpCode() == ARP.REQUEST) ? "Request" : "Reply"), + HexEncode.bytesToHexString(pkt.getSenderHardwareAddress()), + InetAddress.getByAddress(pkt.getSenderProtocolAddress()), + HexEncode.bytesToHexString(pkt.getTargetHardwareAddress()), + InetAddress.getByAddress(pkt.getTargetProtocolAddress()), p, (vlan != 0 ? "on vlan " + vlan : "")); + + } catch (UnknownHostException e) { + log.warn("Illegal Ip Address in the ARP packet", e); + } + } + + protected void handleARPPacket(Ethernet eHeader, ARP pkt, NodeConnector p, short vlan) { + + if(log.isTraceEnabled()) { + logArpPacket(pkt, p, vlan); + } byte[] sourceMAC = eHeader.getSourceMACAddress(); byte[] targetMAC = eHeader.getDestinationMACAddress(); @@ -223,7 +261,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA HostNodeConnector requestor = null; if (NetUtils.isUnicastMACAddr(sourceMAC) && p.getNode() != null) { try { - requestor = new HostNodeConnector(sourceMAC, sourceIP, p, subnet.getVlan()); + requestor = new HostNodeConnector(sourceMAC, sourceIP, p, vlan); } catch (ConstructionException e) { log.debug("Received ARP packet with invalid MAC: {}", HexEncode.bytesToHexString(sourceMAC)); return; @@ -253,7 +291,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA // the true value indicates we should generate replies to requestors // across the cluster log.trace("Received ARP reply packet from {}, reply to all requestors.", sourceIP); - arpRequestReplyEvent.put(new ARPReply(sourceIP, sourceMAC), true); + arpRequestReplyEvent.put(new ARPReply(sourceIP, sourceMAC, vlan), true); return; } @@ -274,11 +312,11 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA log.trace("Received local ARP req. for default gateway. Replying with controller MAC: {}", HexEncode.bytesToHexString(getControllerMAC())); } - sendARPReply(p, getControllerMAC(), targetIP, pkt.getSenderHardwareAddress(), sourceIP); + sendARPReply(p, getControllerMAC(), targetIP, pkt.getSenderHardwareAddress(), sourceIP, vlan); } else { log.trace("Received non-local ARP req. for default gateway. Raising reply event"); arpRequestReplyEvent.put( - new ARPReply(p, targetIP, getControllerMAC(), sourceIP, pkt.getSenderHardwareAddress()), false); + new ARPReply(p, targetIP, getControllerMAC(), sourceIP, pkt.getSenderHardwareAddress(), vlan), false); } return; } @@ -312,10 +350,10 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA log.trace("Received ARP req. for known host {}, sending reply...", targetIP); if (connectionManager.getLocalityStatus(p.getNode()) == ConnectionLocality.LOCAL) { sendARPReply(p, host.getDataLayerAddressBytes(), host.getNetworkAddress(), - pkt.getSenderHardwareAddress(), sourceIP); + pkt.getSenderHardwareAddress(), sourceIP, vlan); } else { arpRequestReplyEvent.put(new ARPReply(p, host.getNetworkAddress(), host.getDataLayerAddressBytes(), - sourceIP, pkt.getSenderHardwareAddress()), false); + sourceIP, pkt.getSenderHardwareAddress(), vlan), false); } } else { /* @@ -357,8 +395,13 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA byte[] targetIPByte = targetIP.getAddress(); ARP arp = createARP(ARP.REQUEST, getControllerMAC(), senderIP, targetHardwareAddress, targetIPByte); + if(log.isTraceEnabled()) { + log.trace("Sending Broadcast Arp Request with srcMac {} - srcIp {} - dstMac {} - dstIp {} - outport {}", HexEncode.bytesToHexString(getControllerMAC()), + subnet.getNetworkAddress(), HexEncode.bytesToHexString(targetHardwareAddress), targetIP, p); + } + byte[] destMACAddress = NetUtils.getBroadcastMACAddr(); - Ethernet ethernet = createEthernet(getControllerMAC(), destMACAddress, arp); + Ethernet ethernet = createEthernet(getControllerMAC(), destMACAddress, arp, (short)0); // TODO For now send port-by-port, see how to optimize to // send to multiple ports at once @@ -370,9 +413,9 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } /** - * Send a unicast ARP Request to the known host on a specific switch/port as - * defined in the host. The sender IP is the networkAddress of the subnet - * The sender MAC is the controller's MAC + * Send a unicast ARP Request to the known host on specific (switch/port, + * vlan) as defined in the host. The sender IP is the networkAddress of the + * subnet The sender MAC is the controller's MAC */ protected void sendUcastARPRequest(HostNodeConnector host, Subnet subnet) { log.trace("sendUcastARPRequest host:{} subnet:{}", host, subnet); @@ -387,7 +430,14 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA byte[] targetMAC = host.getDataLayerAddressBytes(); ARP arp = createARP(ARP.REQUEST, getControllerMAC(), senderIP, targetMAC, targetIP); - Ethernet ethernet = createEthernet(getControllerMAC(), targetMAC, arp); + if(log.isTraceEnabled()) { + log.trace("Sending Unicast Arp Request with srcMac {} - srcIp {} - dstMac {} - dstIp {} - outport {}", + HexEncode.bytesToHexString(getControllerMAC()), + subnet.getNetworkAddress(), HexEncode.bytesToHexString(targetMAC), host.getNetworkAddress(), + outPort); + } + + Ethernet ethernet = createEthernet(getControllerMAC(), targetMAC, arp, host.getVlan()); RawPacket destPkt = this.dataPacketService.encodeDataPacket(ethernet); destPkt.setOutgoingNodeConnector(outPort); @@ -445,7 +495,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA * @param pkt * @param p */ - protected void handlePuntedIPPacket(IPv4 pkt, NodeConnector p) { + protected void handlePuntedIPPacket(IPv4 pkt, NodeConnector p, short vlan) { InetAddress dIP = NetUtils.getInetAddress(pkt.getDestinationAddress()); if (dIP == null) { @@ -469,41 +519,18 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA // see if we know about the host // Hosttracker hosts db key implementation - IHostId id = HostIdFactory.create(dIP, null); - HostNodeConnector host = hostTracker.hostFind(id); + HostNodeConnector host = hostTracker.hostFind(dIP); if (host == null) { - // if we don't, know about the host, try to find it + // if we don't know about the host, try to find it log.trace("Punted IP pkt to {}, sending bcast ARP event...", dIP); /* * unknown destination host, initiate bcast ARP request */ arpRequestReplyEvent.put(new ARPRequest(dIP, subnet), false); - } else if (routing == null || routing.getRoute(p.getNode(), host.getnodeconnectorNode()) != null) { - /* - * if IRouting is available, make sure that this packet can get it's - * destination normally before teleporting it there. If it's not - * available, then assume it's reachable. - * - * TODO: come up with a way to do this in the absence of IRouting - */ - - log.trace("forwarding punted IP pkt to {} received at {}", dIP, p); - - /* - * if we know where the host is and there's a path from where this - * packet was punted to where the host is, then deliver it to the - * host for now - */ - NodeConnector nc = host.getnodeConnector(); - - // re-encode the Ethernet packet (the parent of the IPv4 packet) - RawPacket rp = this.dataPacketService.encodeDataPacket(pkt.getParent()); - rp.setOutgoingNodeConnector(nc); - this.dataPacketService.transmitDataPacket(rp); } else { - log.trace("ignoring punted IP pkt to {} because there is no route from {}", dIP, p); + log.trace("Ignoring punted IP pkt to known host: {} (received on: {})", dIP, p); } } @@ -623,13 +650,19 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA log.trace("Received a frame of size: {}", inPkt.getPacketData().length); Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt); if (formattedPak instanceof Ethernet) { - Object nextPak = formattedPak.getPayload(); + Packet nextPak = formattedPak.getPayload(); + short vlan = 0; + if (nextPak instanceof IEEE8021Q) { + vlan = ((IEEE8021Q) nextPak).getVid(); + log.trace("Moved after the dot1Q header"); + nextPak = ((IEEE8021Q) nextPak).getPayload(); + } if (nextPak instanceof IPv4) { log.trace("Handle IP packet: {}", formattedPak); - handlePuntedIPPacket((IPv4) nextPak, inPkt.getIncomingNodeConnector()); + handlePuntedIPPacket((IPv4) nextPak, inPkt.getIncomingNodeConnector(), vlan); } else if (nextPak instanceof ARP) { log.trace("Handle ARP packet: {}", formattedPak); - handleARPPacket((Ethernet) formattedPak, (ARP) nextPak, inPkt.getIncomingNodeConnector()); + handleARPPacket((Ethernet) formattedPak, (ARP) nextPak, inPkt.getIncomingNodeConnector(), vlan); } } return PacketResult.IGNORED; @@ -650,12 +683,21 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA return arp; } - private Ethernet createEthernet(byte[] sourceMAC, byte[] targetMAC, ARP arp) { + private Ethernet createEthernet(byte[] sourceMAC, byte[] targetMAC, ARP arp, short vlan) { Ethernet ethernet = new Ethernet(); ethernet.setSourceMACAddress(sourceMAC); ethernet.setDestinationMACAddress(targetMAC); - ethernet.setEtherType(EtherTypes.ARP.shortValue()); - ethernet.setPayload(arp); + if (vlan == 0) { + ethernet.setEtherType(EtherTypes.ARP.shortValue()); + ethernet.setPayload(arp); + } else { + IEEE8021Q dot1q = new IEEE8021Q(); + dot1q.setVid(vlan); + dot1q.setEtherType(EtherTypes.ARP.shortValue()); + dot1q.setPayload(arp); + ethernet.setEtherType(EtherTypes.VLANTAGGED.shortValue()); + ethernet.setPayload(dot1q); + } return ethernet; } @@ -701,7 +743,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA } } - private void generateAndSendReply(InetAddress sourceIP, byte[] sourceMAC) { + private void generateAndSendReply(InetAddress sourceIP, byte[] sourceMAC, short vlan) { if (log.isTraceEnabled()) { log.trace("generateAndSendReply called with params sourceIP:{} sourceMAC:{}", sourceIP, HexEncode.bytesToHexString(sourceMAC)); @@ -715,13 +757,14 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA for (HostNodeConnector host : hosts) { if (log.isTraceEnabled()) { log.trace( - "Sending ARP Reply with src {}/{}, target {}/{}", + "Sending ARP Reply with src {}/{}, target {}/{} {}", new Object[] { HexEncode.bytesToHexString(sourceMAC), sourceIP, - HexEncode.bytesToHexString(host.getDataLayerAddressBytes()), host.getNetworkAddress() }); + HexEncode.bytesToHexString(host.getDataLayerAddressBytes()), host.getNetworkAddress(), + (vlan != 0 ? "on vlan " + vlan : "") }); } if (connectionManager.getLocalityStatus(host.getnodeconnectorNode()) == ConnectionLocality.LOCAL) { sendARPReply(host.getnodeConnector(), sourceMAC, sourceIP, host.getDataLayerAddressBytes(), - host.getNetworkAddress()); + host.getNetworkAddress(), vlan); } else { /* * In the remote event a requestor moved to another controller @@ -730,7 +773,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA */ arpRequestReplyEvent.put( new ARPReply(host.getnodeConnector(), sourceIP, sourceMAC, host.getNetworkAddress(), host - .getDataLayerAddressBytes()), false); + .getDataLayerAddressBytes(), vlan), false); } } } @@ -792,12 +835,12 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA // requestors across the cluster if (ev.isNewReply()) { log.trace("Trigger a generateAndSendReply in response to {}", rep); - generateAndSendReply(rep.getTargetIP(), rep.getTargetMac()); + generateAndSendReply(rep.getTargetIP(), rep.getTargetMac(), rep.getVlan()); // Otherwise, a specific reply. If local, send out. } else if (connectionManager.getLocalityStatus(rep.getPort().getNode()) == ConnectionLocality.LOCAL) { log.trace("ARPCacheEventHandler - sendUcatARPReply locally in response to {}", rep); sendARPReply(rep.getPort(), rep.getSourceMac(), rep.getSourceIP(), rep.getTargetMac(), - rep.getTargetIP()); + rep.getTargetIP(), rep.getVlan()); } } } catch (InterruptedException e) {