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