Showing
7 changed files
with
274 additions
and
50 deletions
| 1 | package org.onlab.onos.net.host; | 1 | package org.onlab.onos.net.host; |
| 2 | 2 | ||
| 3 | -import java.util.Set; | ||
| 4 | - | ||
| 5 | import org.onlab.onos.net.ConnectPoint; | 3 | import org.onlab.onos.net.ConnectPoint; |
| 6 | import org.onlab.onos.net.HostId; | 4 | import org.onlab.onos.net.HostId; |
| 7 | 5 | ||
| ... | @@ -47,20 +45,4 @@ public interface HostAdminService { | ... | @@ -47,20 +45,4 @@ public interface HostAdminService { |
| 47 | */ | 45 | */ |
| 48 | void clearAddresses(ConnectPoint connectPoint); | 46 | void clearAddresses(ConnectPoint connectPoint); |
| 49 | 47 | ||
| 50 | - /** | ||
| 51 | - * Returns the addresses information for all connection points. | ||
| 52 | - * | ||
| 53 | - * @return the set of address bindings for all connection points | ||
| 54 | - */ | ||
| 55 | - Set<PortAddresses> getAddressBindings(); | ||
| 56 | - | ||
| 57 | - /** | ||
| 58 | - * Retrieves the addresses that have been bound to the given connection | ||
| 59 | - * point. | ||
| 60 | - * | ||
| 61 | - * @param connectPoint the connection point to retrieve address bindings | ||
| 62 | - * for | ||
| 63 | - * @return addresses bound to the port | ||
| 64 | - */ | ||
| 65 | - PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint); | ||
| 66 | } | 48 | } | ... | ... |
| ... | @@ -110,6 +110,23 @@ public interface HostService { | ... | @@ -110,6 +110,23 @@ public interface HostService { |
| 110 | void requestMac(IpAddress ip); | 110 | void requestMac(IpAddress ip); |
| 111 | 111 | ||
| 112 | /** | 112 | /** |
| 113 | + * Returns the addresses information for all connection points. | ||
| 114 | + * | ||
| 115 | + * @return the set of address bindings for all connection points | ||
| 116 | + */ | ||
| 117 | + Set<PortAddresses> getAddressBindings(); | ||
| 118 | + | ||
| 119 | + /** | ||
| 120 | + * Retrieves the addresses that have been bound to the given connection | ||
| 121 | + * point. | ||
| 122 | + * | ||
| 123 | + * @param connectPoint the connection point to retrieve address bindings | ||
| 124 | + * for | ||
| 125 | + * @return addresses bound to the port | ||
| 126 | + */ | ||
| 127 | + PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint); | ||
| 128 | + | ||
| 129 | + /** | ||
| 113 | * Adds the specified host listener. | 130 | * Adds the specified host listener. |
| 114 | * | 131 | * |
| 115 | * @param listener host listener | 132 | * @param listener host listener | ... | ... |
| 1 | package org.onlab.onos.net.proxyarp; | 1 | package org.onlab.onos.net.proxyarp; |
| 2 | 2 | ||
| 3 | +import org.onlab.onos.net.ConnectPoint; | ||
| 3 | import org.onlab.onos.net.packet.PacketContext; | 4 | import org.onlab.onos.net.packet.PacketContext; |
| 4 | import org.onlab.packet.Ethernet; | 5 | import org.onlab.packet.Ethernet; |
| 5 | import org.onlab.packet.IpPrefix; | 6 | import org.onlab.packet.IpPrefix; |
| ... | @@ -23,8 +24,9 @@ public interface ProxyArpService { | ... | @@ -23,8 +24,9 @@ public interface ProxyArpService { |
| 23 | * will be flooded at all edge ports. | 24 | * will be flooded at all edge ports. |
| 24 | * | 25 | * |
| 25 | * @param eth an arp request | 26 | * @param eth an arp request |
| 27 | + * @param inPort the port the request was received on | ||
| 26 | */ | 28 | */ |
| 27 | - void reply(Ethernet eth); | 29 | + void reply(Ethernet eth, ConnectPoint inPort); |
| 28 | 30 | ||
| 29 | /** | 31 | /** |
| 30 | * Forwards an ARP request to its destination. Floods at the edge the ARP request if the | 32 | * Forwards an ARP request to its destination. Floods at the edge the ARP request if the | ... | ... |
| ... | @@ -75,4 +75,14 @@ public class HostServiceAdapter implements HostService { | ... | @@ -75,4 +75,14 @@ public class HostServiceAdapter implements HostService { |
| 75 | public void removeListener(HostListener listener) { | 75 | public void removeListener(HostListener listener) { |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | + @Override | ||
| 79 | + public Set<PortAddresses> getAddressBindings() { | ||
| 80 | + return null; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @Override | ||
| 84 | + public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) { | ||
| 85 | + return null; | ||
| 86 | + } | ||
| 87 | + | ||
| 78 | } | 88 | } | ... | ... |
| ... | @@ -5,6 +5,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -5,6 +5,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
| 5 | import static org.slf4j.LoggerFactory.getLogger; | 5 | import static org.slf4j.LoggerFactory.getLogger; |
| 6 | 6 | ||
| 7 | import java.nio.ByteBuffer; | 7 | import java.nio.ByteBuffer; |
| 8 | +import java.util.Collections; | ||
| 8 | import java.util.List; | 9 | import java.util.List; |
| 9 | import java.util.Map.Entry; | 10 | import java.util.Map.Entry; |
| 10 | import java.util.Set; | 11 | import java.util.Set; |
| ... | @@ -15,6 +16,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -15,6 +16,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
| 15 | import org.apache.felix.scr.annotations.Reference; | 16 | import org.apache.felix.scr.annotations.Reference; |
| 16 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 17 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 17 | import org.apache.felix.scr.annotations.Service; | 18 | import org.apache.felix.scr.annotations.Service; |
| 19 | +import org.onlab.onos.net.ConnectPoint; | ||
| 18 | import org.onlab.onos.net.Device; | 20 | import org.onlab.onos.net.Device; |
| 19 | import org.onlab.onos.net.Host; | 21 | import org.onlab.onos.net.Host; |
| 20 | import org.onlab.onos.net.HostId; | 22 | import org.onlab.onos.net.HostId; |
| ... | @@ -27,6 +29,7 @@ import org.onlab.onos.net.device.DeviceService; | ... | @@ -27,6 +29,7 @@ import org.onlab.onos.net.device.DeviceService; |
| 27 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; | 29 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; |
| 28 | import org.onlab.onos.net.flow.TrafficTreatment; | 30 | import org.onlab.onos.net.flow.TrafficTreatment; |
| 29 | import org.onlab.onos.net.host.HostService; | 31 | import org.onlab.onos.net.host.HostService; |
| 32 | +import org.onlab.onos.net.host.PortAddresses; | ||
| 30 | import org.onlab.onos.net.link.LinkEvent; | 33 | import org.onlab.onos.net.link.LinkEvent; |
| 31 | import org.onlab.onos.net.link.LinkListener; | 34 | import org.onlab.onos.net.link.LinkListener; |
| 32 | import org.onlab.onos.net.link.LinkService; | 35 | import org.onlab.onos.net.link.LinkService; |
| ... | @@ -37,7 +40,9 @@ import org.onlab.onos.net.packet.PacketService; | ... | @@ -37,7 +40,9 @@ import org.onlab.onos.net.packet.PacketService; |
| 37 | import org.onlab.onos.net.proxyarp.ProxyArpService; | 40 | import org.onlab.onos.net.proxyarp.ProxyArpService; |
| 38 | import org.onlab.packet.ARP; | 41 | import org.onlab.packet.ARP; |
| 39 | import org.onlab.packet.Ethernet; | 42 | import org.onlab.packet.Ethernet; |
| 43 | +import org.onlab.packet.IpAddress; | ||
| 40 | import org.onlab.packet.IpPrefix; | 44 | import org.onlab.packet.IpPrefix; |
| 45 | +import org.onlab.packet.MacAddress; | ||
| 41 | import org.onlab.packet.VlanId; | 46 | import org.onlab.packet.VlanId; |
| 42 | import org.slf4j.Logger; | 47 | import org.slf4j.Logger; |
| 43 | 48 | ||
| ... | @@ -101,12 +106,46 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -101,12 +106,46 @@ public class ProxyArpManager implements ProxyArpService { |
| 101 | } | 106 | } |
| 102 | 107 | ||
| 103 | @Override | 108 | @Override |
| 104 | - public void reply(Ethernet eth) { | 109 | + public void reply(Ethernet eth, ConnectPoint inPort) { |
| 105 | checkNotNull(eth, REQUEST_NULL); | 110 | checkNotNull(eth, REQUEST_NULL); |
| 106 | checkArgument(eth.getEtherType() == Ethernet.TYPE_ARP, | 111 | checkArgument(eth.getEtherType() == Ethernet.TYPE_ARP, |
| 107 | REQUEST_NOT_ARP); | 112 | REQUEST_NOT_ARP); |
| 108 | ARP arp = (ARP) eth.getPayload(); | 113 | ARP arp = (ARP) eth.getPayload(); |
| 109 | checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST); | 114 | checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST); |
| 115 | + checkNotNull(inPort); | ||
| 116 | + | ||
| 117 | + // If the source address matches one of our external addresses | ||
| 118 | + // it could be a request from an internal host to an external | ||
| 119 | + // address. Forward it over to the correct port. | ||
| 120 | + IpAddress source = IpAddress.valueOf(arp.getSenderProtocolAddress()); | ||
| 121 | + PortAddresses sourceAddresses = findOutsidePortInSubnet(source); | ||
| 122 | + if (sourceAddresses != null && !isOutsidePort(inPort)) { | ||
| 123 | + for (IpPrefix subnet : sourceAddresses.ips()) { | ||
| 124 | + if (subnet.toIpAddress().equals(source)) { | ||
| 125 | + sendTo(eth, sourceAddresses.connectPoint()); | ||
| 126 | + return; | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + // If the request came from outside the network, only reply if it was | ||
| 132 | + // for one of our external addresses. | ||
| 133 | + if (isOutsidePort(inPort)) { | ||
| 134 | + IpAddress target = IpAddress.valueOf(arp.getTargetProtocolAddress()); | ||
| 135 | + PortAddresses addresses = hostService.getAddressBindingsForPort(inPort); | ||
| 136 | + | ||
| 137 | + for (IpPrefix interfaceAddress : addresses.ips()) { | ||
| 138 | + if (interfaceAddress.toIpAddress().equals(target)) { | ||
| 139 | + Ethernet arpReply = buildArpReply(interfaceAddress, | ||
| 140 | + addresses.mac(), eth); | ||
| 141 | + sendTo(arpReply, inPort); | ||
| 142 | + } | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + return; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + // Continue with normal proxy ARP case | ||
| 110 | 149 | ||
| 111 | VlanId vlan = VlanId.vlanId(eth.getVlanID()); | 150 | VlanId vlan = VlanId.vlanId(eth.getVlanID()); |
| 112 | Set<Host> hosts = hostService.getHostsByIp(IpPrefix.valueOf(arp | 151 | Set<Host> hosts = hostService.getHostsByIp(IpPrefix.valueOf(arp |
| ... | @@ -128,12 +167,62 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -128,12 +167,62 @@ public class ProxyArpManager implements ProxyArpService { |
| 128 | return; | 167 | return; |
| 129 | } | 168 | } |
| 130 | 169 | ||
| 131 | - Ethernet arpReply = buildArpReply(dst, eth); | 170 | + Ethernet arpReply = buildArpReply(dst.ipAddresses().iterator().next(), |
| 171 | + dst.mac(), eth); | ||
| 132 | // TODO: check send status with host service. | 172 | // TODO: check send status with host service. |
| 173 | + sendTo(arpReply, src.location()); | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + /** | ||
| 177 | + * Outputs the given packet out the given port. | ||
| 178 | + * | ||
| 179 | + * @param packet the packet to send | ||
| 180 | + * @param outPort the port to send it out | ||
| 181 | + */ | ||
| 182 | + private void sendTo(Ethernet packet, ConnectPoint outPort) { | ||
| 183 | + if (internalPorts.containsEntry( | ||
| 184 | + deviceService.getDevice(outPort.deviceId()), outPort.port())) { | ||
| 185 | + // Sanity check to make sure we don't send the packet out an | ||
| 186 | + // internal port and create a loop (could happen due to | ||
| 187 | + // misconfiguration). | ||
| 188 | + return; | ||
| 189 | + } | ||
| 190 | + | ||
| 133 | TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); | 191 | TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); |
| 134 | - builder.setOutput(src.location().port()); | 192 | + builder.setOutput(outPort.port()); |
| 135 | - packetService.emit(new DefaultOutboundPacket(src.location().deviceId(), | 193 | + packetService.emit(new DefaultOutboundPacket(outPort.deviceId(), |
| 136 | - builder.build(), ByteBuffer.wrap(arpReply.serialize()))); | 194 | + builder.build(), ByteBuffer.wrap(packet.serialize()))); |
| 195 | + } | ||
| 196 | + | ||
| 197 | + /** | ||
| 198 | + * Finds the port with an address in the subnet of the target address, if | ||
| 199 | + * one exists. | ||
| 200 | + * | ||
| 201 | + * @param target the target address to find a matching external port for | ||
| 202 | + * @return a PortAddresses object containing the external addresses if one | ||
| 203 | + * was found, otherwise null. | ||
| 204 | + */ | ||
| 205 | + private PortAddresses findOutsidePortInSubnet(IpAddress target) { | ||
| 206 | + for (PortAddresses addresses : hostService.getAddressBindings()) { | ||
| 207 | + for (IpPrefix prefix : addresses.ips()) { | ||
| 208 | + if (prefix.contains(target)) { | ||
| 209 | + return new PortAddresses(addresses.connectPoint(), | ||
| 210 | + Collections.singleton(prefix), addresses.mac()); | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + } | ||
| 214 | + return null; | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + /** | ||
| 218 | + * Returns whether the given port is an outside-facing port with an IP | ||
| 219 | + * address configured. | ||
| 220 | + * | ||
| 221 | + * @param port the port to check | ||
| 222 | + * @return true if the port is an outside-facing port, otherwise false | ||
| 223 | + */ | ||
| 224 | + private boolean isOutsidePort(ConnectPoint port) { | ||
| 225 | + return !hostService.getAddressBindingsForPort(port).ips().isEmpty(); | ||
| 137 | } | 226 | } |
| 138 | 227 | ||
| 139 | @Override | 228 | @Override |
| ... | @@ -167,7 +256,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -167,7 +256,7 @@ public class ProxyArpManager implements ProxyArpService { |
| 167 | if (arp.getOpCode() == ARP.OP_REPLY) { | 256 | if (arp.getOpCode() == ARP.OP_REPLY) { |
| 168 | forward(ethPkt); | 257 | forward(ethPkt); |
| 169 | } else if (arp.getOpCode() == ARP.OP_REQUEST) { | 258 | } else if (arp.getOpCode() == ARP.OP_REQUEST) { |
| 170 | - reply(ethPkt); | 259 | + reply(ethPkt, context.inPacket().receivedFrom()); |
| 171 | } | 260 | } |
| 172 | context.block(); | 261 | context.block(); |
| 173 | return true; | 262 | return true; |
| ... | @@ -185,12 +274,16 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -185,12 +274,16 @@ public class ProxyArpManager implements ProxyArpService { |
| 185 | 274 | ||
| 186 | synchronized (externalPorts) { | 275 | synchronized (externalPorts) { |
| 187 | for (Entry<Device, PortNumber> entry : externalPorts.entries()) { | 276 | for (Entry<Device, PortNumber> entry : externalPorts.entries()) { |
| 277 | + ConnectPoint cp = new ConnectPoint(entry.getKey().id(), entry.getValue()); | ||
| 278 | + if (isOutsidePort(cp)) { | ||
| 279 | + continue; | ||
| 280 | + } | ||
| 281 | + | ||
| 188 | builder = DefaultTrafficTreatment.builder(); | 282 | builder = DefaultTrafficTreatment.builder(); |
| 189 | builder.setOutput(entry.getValue()); | 283 | builder.setOutput(entry.getValue()); |
| 190 | packetService.emit(new DefaultOutboundPacket(entry.getKey().id(), | 284 | packetService.emit(new DefaultOutboundPacket(entry.getKey().id(), |
| 191 | builder.build(), buf)); | 285 | builder.build(), buf)); |
| 192 | } | 286 | } |
| 193 | - | ||
| 194 | } | 287 | } |
| 195 | } | 288 | } |
| 196 | 289 | ||
| ... | @@ -234,15 +327,19 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -234,15 +327,19 @@ public class ProxyArpManager implements ProxyArpService { |
| 234 | } | 327 | } |
| 235 | 328 | ||
| 236 | /** | 329 | /** |
| 237 | - * Builds an arp reply based on a request. | 330 | + * Builds an ARP reply based on a request. |
| 238 | - * @param h the host we want to send to | 331 | + * |
| 239 | - * @param request the arp request we got | 332 | + * @param srcIp the IP address to use as the reply source |
| 240 | - * @return an ethernet frame containing the arp reply | 333 | + * @param srcMac the MAC address to use as the reply source |
| 334 | + * @param request the ARP request we got | ||
| 335 | + * @return an Ethernet frame containing the ARP reply | ||
| 241 | */ | 336 | */ |
| 242 | - private Ethernet buildArpReply(Host h, Ethernet request) { | 337 | + private Ethernet buildArpReply(IpPrefix srcIp, MacAddress srcMac, |
| 338 | + Ethernet request) { | ||
| 339 | + | ||
| 243 | Ethernet eth = new Ethernet(); | 340 | Ethernet eth = new Ethernet(); |
| 244 | eth.setDestinationMACAddress(request.getSourceMACAddress()); | 341 | eth.setDestinationMACAddress(request.getSourceMACAddress()); |
| 245 | - eth.setSourceMACAddress(h.mac().getAddress()); | 342 | + eth.setSourceMACAddress(srcMac.getAddress()); |
| 246 | eth.setEtherType(Ethernet.TYPE_ARP); | 343 | eth.setEtherType(Ethernet.TYPE_ARP); |
| 247 | eth.setVlanID(request.getVlanID()); | 344 | eth.setVlanID(request.getVlanID()); |
| 248 | 345 | ||
| ... | @@ -253,12 +350,12 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -253,12 +350,12 @@ public class ProxyArpManager implements ProxyArpService { |
| 253 | 350 | ||
| 254 | arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN); | 351 | arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN); |
| 255 | arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH); | 352 | arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH); |
| 256 | - arp.setSenderHardwareAddress(h.mac().getAddress()); | 353 | + arp.setSenderHardwareAddress(srcMac.getAddress()); |
| 257 | arp.setTargetHardwareAddress(request.getSourceMACAddress()); | 354 | arp.setTargetHardwareAddress(request.getSourceMACAddress()); |
| 258 | 355 | ||
| 259 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) | 356 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) |
| 260 | .getSenderProtocolAddress()); | 357 | .getSenderProtocolAddress()); |
| 261 | - arp.setSenderProtocolAddress(h.ipAddresses().iterator().next().toRealInt()); | 358 | + arp.setSenderProtocolAddress(srcIp.toRealInt()); |
| 262 | eth.setPayload(arp); | 359 | eth.setPayload(arp); |
| 263 | return eth; | 360 | return eth; |
| 264 | } | 361 | } | ... | ... |
| ... | @@ -13,6 +13,7 @@ import java.util.Arrays; | ... | @@ -13,6 +13,7 @@ import java.util.Arrays; |
| 13 | import java.util.Collections; | 13 | import java.util.Collections; |
| 14 | import java.util.Comparator; | 14 | import java.util.Comparator; |
| 15 | import java.util.List; | 15 | import java.util.List; |
| 16 | +import java.util.Set; | ||
| 16 | 17 | ||
| 17 | import org.junit.Before; | 18 | import org.junit.Before; |
| 18 | import org.junit.Test; | 19 | import org.junit.Test; |
| ... | @@ -31,6 +32,7 @@ import org.onlab.onos.net.device.DeviceService; | ... | @@ -31,6 +32,7 @@ import org.onlab.onos.net.device.DeviceService; |
| 31 | import org.onlab.onos.net.flow.instructions.Instruction; | 32 | import org.onlab.onos.net.flow.instructions.Instruction; |
| 32 | import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction; | 33 | import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction; |
| 33 | import org.onlab.onos.net.host.HostService; | 34 | import org.onlab.onos.net.host.HostService; |
| 35 | +import org.onlab.onos.net.host.PortAddresses; | ||
| 34 | import org.onlab.onos.net.link.LinkListener; | 36 | import org.onlab.onos.net.link.LinkListener; |
| 35 | import org.onlab.onos.net.link.LinkService; | 37 | import org.onlab.onos.net.link.LinkService; |
| 36 | import org.onlab.onos.net.packet.OutboundPacket; | 38 | import org.onlab.onos.net.packet.OutboundPacket; |
| ... | @@ -50,12 +52,13 @@ import com.google.common.collect.Sets; | ... | @@ -50,12 +52,13 @@ import com.google.common.collect.Sets; |
| 50 | */ | 52 | */ |
| 51 | public class ProxyArpManagerTest { | 53 | public class ProxyArpManagerTest { |
| 52 | 54 | ||
| 53 | - private static final int NUM_DEVICES = 4; | 55 | + private static final int NUM_DEVICES = 6; |
| 54 | private static final int NUM_PORTS_PER_DEVICE = 3; | 56 | private static final int NUM_PORTS_PER_DEVICE = 3; |
| 55 | - private static final int NUM_FLOOD_PORTS = 4; | 57 | + private static final int NUM_ADDRESS_PORTS = NUM_DEVICES / 2; |
| 58 | + private static final int NUM_FLOOD_PORTS = 3; | ||
| 56 | 59 | ||
| 57 | - private static final IpPrefix IP1 = IpPrefix.valueOf("10.0.0.1/24"); | 60 | + private static final IpPrefix IP1 = IpPrefix.valueOf("192.168.1.1/24"); |
| 58 | - private static final IpPrefix IP2 = IpPrefix.valueOf("10.0.0.2/24"); | 61 | + private static final IpPrefix IP2 = IpPrefix.valueOf("192.168.1.2/24"); |
| 59 | 62 | ||
| 60 | private static final ProviderId PID = new ProviderId("of", "foo"); | 63 | private static final ProviderId PID = new ProviderId("of", "foo"); |
| 61 | 64 | ||
| ... | @@ -104,6 +107,9 @@ public class ProxyArpManagerTest { | ... | @@ -104,6 +107,9 @@ public class ProxyArpManagerTest { |
| 104 | * The default topology is a unidirectional ring topology. Each switch has | 107 | * The default topology is a unidirectional ring topology. Each switch has |
| 105 | * 3 ports. Ports 2 and 3 have the links to neighbor switches, and port 1 | 108 | * 3 ports. Ports 2 and 3 have the links to neighbor switches, and port 1 |
| 106 | * is free (edge port). | 109 | * is free (edge port). |
| 110 | + * The first half of the switches have IP addresses configured on their | ||
| 111 | + * free ports (port 1). The second half of the switches have no IP | ||
| 112 | + * addresses configured. | ||
| 107 | */ | 113 | */ |
| 108 | private void createTopology() { | 114 | private void createTopology() { |
| 109 | deviceService = createMock(DeviceService.class); | 115 | deviceService = createMock(DeviceService.class); |
| ... | @@ -114,6 +120,7 @@ public class ProxyArpManagerTest { | ... | @@ -114,6 +120,7 @@ public class ProxyArpManagerTest { |
| 114 | 120 | ||
| 115 | createDevices(NUM_DEVICES, NUM_PORTS_PER_DEVICE); | 121 | createDevices(NUM_DEVICES, NUM_PORTS_PER_DEVICE); |
| 116 | createLinks(NUM_DEVICES); | 122 | createLinks(NUM_DEVICES); |
| 123 | + addAddressBindings(); | ||
| 117 | } | 124 | } |
| 118 | 125 | ||
| 119 | /** | 126 | /** |
| ... | @@ -138,10 +145,11 @@ public class ProxyArpManagerTest { | ... | @@ -138,10 +145,11 @@ public class ProxyArpManagerTest { |
| 138 | ports.add(port); | 145 | ports.add(port); |
| 139 | } | 146 | } |
| 140 | 147 | ||
| 141 | - expect(deviceService.getPorts(devId)).andReturn(ports); | 148 | + expect(deviceService.getPorts(devId)).andReturn(ports).anyTimes(); |
| 149 | + expect(deviceService.getDevice(devId)).andReturn(device).anyTimes(); | ||
| 142 | } | 150 | } |
| 143 | 151 | ||
| 144 | - expect(deviceService.getDevices()).andReturn(devices); | 152 | + expect(deviceService.getDevices()).andReturn(devices).anyTimes(); |
| 145 | replay(deviceService); | 153 | replay(deviceService); |
| 146 | } | 154 | } |
| 147 | 155 | ||
| ... | @@ -173,6 +181,31 @@ public class ProxyArpManagerTest { | ... | @@ -173,6 +181,31 @@ public class ProxyArpManagerTest { |
| 173 | replay(linkService); | 181 | replay(linkService); |
| 174 | } | 182 | } |
| 175 | 183 | ||
| 184 | + private void addAddressBindings() { | ||
| 185 | + Set<PortAddresses> addresses = Sets.newHashSet(); | ||
| 186 | + | ||
| 187 | + for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) { | ||
| 188 | + ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1); | ||
| 189 | + IpPrefix prefix1 = IpPrefix.valueOf("10.0." + (2 * i - 1) + ".1/24"); | ||
| 190 | + IpPrefix prefix2 = IpPrefix.valueOf("10.0." + (2 * i) + ".1/24"); | ||
| 191 | + PortAddresses pa = new PortAddresses(cp, | ||
| 192 | + Sets.newHashSet(prefix1, prefix2), MacAddress.valueOf(i)); | ||
| 193 | + addresses.add(pa); | ||
| 194 | + | ||
| 195 | + expect(hostService.getAddressBindingsForPort(cp)) | ||
| 196 | + .andReturn(pa).anyTimes(); | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + expect(hostService.getAddressBindings()).andReturn(addresses).anyTimes(); | ||
| 200 | + | ||
| 201 | + for (int i = 1; i <= NUM_FLOOD_PORTS; i++) { | ||
| 202 | + ConnectPoint cp = new ConnectPoint(getDeviceId(i + NUM_ADDRESS_PORTS), | ||
| 203 | + P1); | ||
| 204 | + expect(hostService.getAddressBindingsForPort(cp)) | ||
| 205 | + .andReturn(new PortAddresses(cp, null, null)).anyTimes(); | ||
| 206 | + } | ||
| 207 | + } | ||
| 208 | + | ||
| 176 | /** | 209 | /** |
| 177 | * Tests {@link ProxyArpManager#known(IpPrefix)} in the case where the | 210 | * Tests {@link ProxyArpManager#known(IpPrefix)} in the case where the |
| 178 | * IP address is not known. | 211 | * IP address is not known. |
| ... | @@ -210,10 +243,10 @@ public class ProxyArpManagerTest { | ... | @@ -210,10 +243,10 @@ public class ProxyArpManagerTest { |
| 210 | */ | 243 | */ |
| 211 | @Test | 244 | @Test |
| 212 | public void testReplyKnown() { | 245 | public void testReplyKnown() { |
| 213 | - Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC2, | 246 | + Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(4), |
| 214 | Collections.singleton(IP1)); | 247 | Collections.singleton(IP1)); |
| 215 | 248 | ||
| 216 | - Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1, | 249 | + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5), |
| 217 | Collections.singleton(IP2)); | 250 | Collections.singleton(IP2)); |
| 218 | 251 | ||
| 219 | expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets()))) | 252 | expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets()))) |
| ... | @@ -224,11 +257,11 @@ public class ProxyArpManagerTest { | ... | @@ -224,11 +257,11 @@ public class ProxyArpManagerTest { |
| 224 | 257 | ||
| 225 | Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1); | 258 | Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1); |
| 226 | 259 | ||
| 227 | - proxyArp.reply(arpRequest); | 260 | + proxyArp.reply(arpRequest, getLocation(5)); |
| 228 | 261 | ||
| 229 | assertEquals(1, packetService.packets.size()); | 262 | assertEquals(1, packetService.packets.size()); |
| 230 | Ethernet arpReply = buildArp(ARP.OP_REPLY, MAC1, MAC2, IP1, IP2); | 263 | Ethernet arpReply = buildArp(ARP.OP_REPLY, MAC1, MAC2, IP1, IP2); |
| 231 | - verifyPacketOut(arpReply, LOC1, packetService.packets.get(0)); | 264 | + verifyPacketOut(arpReply, getLocation(5), packetService.packets.get(0)); |
| 232 | } | 265 | } |
| 233 | 266 | ||
| 234 | /** | 267 | /** |
| ... | @@ -238,7 +271,7 @@ public class ProxyArpManagerTest { | ... | @@ -238,7 +271,7 @@ public class ProxyArpManagerTest { |
| 238 | */ | 271 | */ |
| 239 | @Test | 272 | @Test |
| 240 | public void testReplyUnknown() { | 273 | public void testReplyUnknown() { |
| 241 | - Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1, | 274 | + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5), |
| 242 | Collections.singleton(IP2)); | 275 | Collections.singleton(IP2)); |
| 243 | 276 | ||
| 244 | expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets()))) | 277 | expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets()))) |
| ... | @@ -249,7 +282,7 @@ public class ProxyArpManagerTest { | ... | @@ -249,7 +282,7 @@ public class ProxyArpManagerTest { |
| 249 | 282 | ||
| 250 | Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1); | 283 | Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1); |
| 251 | 284 | ||
| 252 | - proxyArp.reply(arpRequest); | 285 | + proxyArp.reply(arpRequest, getLocation(5)); |
| 253 | 286 | ||
| 254 | verifyFlood(arpRequest); | 287 | verifyFlood(arpRequest); |
| 255 | } | 288 | } |
| ... | @@ -262,10 +295,10 @@ public class ProxyArpManagerTest { | ... | @@ -262,10 +295,10 @@ public class ProxyArpManagerTest { |
| 262 | */ | 295 | */ |
| 263 | @Test | 296 | @Test |
| 264 | public void testReplyDifferentVlan() { | 297 | public void testReplyDifferentVlan() { |
| 265 | - Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN2, LOC2, | 298 | + Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN2, getLocation(4), |
| 266 | Collections.singleton(IP1)); | 299 | Collections.singleton(IP1)); |
| 267 | 300 | ||
| 268 | - Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1, | 301 | + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5), |
| 269 | Collections.singleton(IP2)); | 302 | Collections.singleton(IP2)); |
| 270 | 303 | ||
| 271 | expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets()))) | 304 | expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets()))) |
| ... | @@ -276,11 +309,84 @@ public class ProxyArpManagerTest { | ... | @@ -276,11 +309,84 @@ public class ProxyArpManagerTest { |
| 276 | 309 | ||
| 277 | Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1); | 310 | Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1); |
| 278 | 311 | ||
| 279 | - proxyArp.reply(arpRequest); | 312 | + proxyArp.reply(arpRequest, getLocation(5)); |
| 280 | 313 | ||
| 281 | verifyFlood(arpRequest); | 314 | verifyFlood(arpRequest); |
| 282 | } | 315 | } |
| 283 | 316 | ||
| 317 | + @Test | ||
| 318 | + public void testReplyToRequestForUs() { | ||
| 319 | + IpPrefix theirIp = IpPrefix.valueOf("10.0.1.254/24"); | ||
| 320 | + IpPrefix ourFirstIp = IpPrefix.valueOf("10.0.1.1/24"); | ||
| 321 | + IpPrefix ourSecondIp = IpPrefix.valueOf("10.0.2.1/24"); | ||
| 322 | + MacAddress ourMac = MacAddress.valueOf(1L); | ||
| 323 | + | ||
| 324 | + Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1, | ||
| 325 | + Collections.singleton(theirIp)); | ||
| 326 | + | ||
| 327 | + expect(hostService.getHost(HID2)).andReturn(requestor); | ||
| 328 | + replay(hostService); | ||
| 329 | + | ||
| 330 | + Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourFirstIp); | ||
| 331 | + | ||
| 332 | + proxyArp.reply(arpRequest, LOC1); | ||
| 333 | + | ||
| 334 | + assertEquals(1, packetService.packets.size()); | ||
| 335 | + Ethernet arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourFirstIp, theirIp); | ||
| 336 | + verifyPacketOut(arpReply, LOC1, packetService.packets.get(0)); | ||
| 337 | + | ||
| 338 | + // Test a request for the second address on that port | ||
| 339 | + packetService.packets.clear(); | ||
| 340 | + arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourSecondIp); | ||
| 341 | + | ||
| 342 | + proxyArp.reply(arpRequest, LOC1); | ||
| 343 | + | ||
| 344 | + assertEquals(1, packetService.packets.size()); | ||
| 345 | + arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourSecondIp, theirIp); | ||
| 346 | + verifyPacketOut(arpReply, LOC1, packetService.packets.get(0)); | ||
| 347 | + } | ||
| 348 | + | ||
| 349 | + @Test | ||
| 350 | + public void testReplyExternalPortBadRequest() { | ||
| 351 | + replay(hostService); // no further host service expectations | ||
| 352 | + | ||
| 353 | + IpPrefix theirIp = IpPrefix.valueOf("10.0.1.254/24"); | ||
| 354 | + | ||
| 355 | + // Request for a valid external IP address but coming in the wrong port | ||
| 356 | + Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp, | ||
| 357 | + IpPrefix.valueOf("10.0.3.1")); | ||
| 358 | + proxyArp.reply(arpRequest, LOC1); | ||
| 359 | + assertEquals(0, packetService.packets.size()); | ||
| 360 | + | ||
| 361 | + // Request for a valid internal IP address but coming in an external port | ||
| 362 | + packetService.packets.clear(); | ||
| 363 | + arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp, IP1); | ||
| 364 | + proxyArp.reply(arpRequest, LOC1); | ||
| 365 | + assertEquals(0, packetService.packets.size()); | ||
| 366 | + } | ||
| 367 | + | ||
| 368 | + @Test | ||
| 369 | + public void testReplyToRequestFromUs() { | ||
| 370 | + replay(hostService); // no further host service expectations | ||
| 371 | + | ||
| 372 | + IpPrefix ourIp = IpPrefix.valueOf("10.0.1.1/24"); | ||
| 373 | + MacAddress ourMac = MacAddress.valueOf(1L); | ||
| 374 | + IpPrefix theirIp = IpPrefix.valueOf("10.0.1.100/24"); | ||
| 375 | + | ||
| 376 | + // This is a request from something inside our network (like a BGP | ||
| 377 | + // daemon) to an external host. | ||
| 378 | + Ethernet arpRequest = buildArp(ARP.OP_REQUEST, ourMac, null, ourIp, theirIp); | ||
| 379 | + proxyArp.reply(arpRequest, getLocation(5)); | ||
| 380 | + | ||
| 381 | + assertEquals(1, packetService.packets.size()); | ||
| 382 | + verifyPacketOut(arpRequest, getLocation(1), packetService.packets.get(0)); | ||
| 383 | + | ||
| 384 | + // The same request from a random external port should fail | ||
| 385 | + packetService.packets.clear(); | ||
| 386 | + proxyArp.reply(arpRequest, getLocation(2)); | ||
| 387 | + assertEquals(0, packetService.packets.size()); | ||
| 388 | + } | ||
| 389 | + | ||
| 284 | /** | 390 | /** |
| 285 | * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the | 391 | * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the |
| 286 | * destination host is known. | 392 | * destination host is known. |
| ... | @@ -338,7 +444,8 @@ public class ProxyArpManagerTest { | ... | @@ -338,7 +444,8 @@ public class ProxyArpManagerTest { |
| 338 | }); | 444 | }); |
| 339 | 445 | ||
| 340 | for (int i = 0; i < NUM_FLOOD_PORTS; i++) { | 446 | for (int i = 0; i < NUM_FLOOD_PORTS; i++) { |
| 341 | - ConnectPoint cp = new ConnectPoint(getDeviceId(i + 1), PortNumber.portNumber(1)); | 447 | + ConnectPoint cp = new ConnectPoint(getDeviceId(NUM_ADDRESS_PORTS + i + 1), |
| 448 | + PortNumber.portNumber(1)); | ||
| 342 | 449 | ||
| 343 | OutboundPacket outboundPacket = packetService.packets.get(i); | 450 | OutboundPacket outboundPacket = packetService.packets.get(i); |
| 344 | verifyPacketOut(packet, cp, outboundPacket); | 451 | verifyPacketOut(packet, cp, outboundPacket); |
| ... | @@ -372,6 +479,10 @@ public class ProxyArpManagerTest { | ... | @@ -372,6 +479,10 @@ public class ProxyArpManagerTest { |
| 372 | return DeviceId.deviceId("" + i); | 479 | return DeviceId.deviceId("" + i); |
| 373 | } | 480 | } |
| 374 | 481 | ||
| 482 | + private static HostLocation getLocation(int i) { | ||
| 483 | + return new HostLocation(new ConnectPoint(getDeviceId(i), P1), 123L); | ||
| 484 | + } | ||
| 485 | + | ||
| 375 | /** | 486 | /** |
| 376 | * Builds an ARP packet with the given parameters. | 487 | * Builds an ARP packet with the given parameters. |
| 377 | * | 488 | * | ... | ... |
| ... | @@ -108,5 +108,10 @@ public class IpPrefixTest { | ... | @@ -108,5 +108,10 @@ public class IpPrefixTest { |
| 108 | IpAddress addr = IpAddress.valueOf("192.168.10.1"); | 108 | IpAddress addr = IpAddress.valueOf("192.168.10.1"); |
| 109 | 109 | ||
| 110 | assertTrue(intf.contains(addr)); | 110 | assertTrue(intf.contains(addr)); |
| 111 | + | ||
| 112 | + IpPrefix intf1 = IpPrefix.valueOf("10.0.0.101/24"); | ||
| 113 | + IpAddress addr1 = IpAddress.valueOf("10.0.0.4"); | ||
| 114 | + | ||
| 115 | + assertTrue(intf1.contains(addr1)); | ||
| 111 | } | 116 | } |
| 112 | } | 117 | } | ... | ... |
-
Please register or login to post a comment