Jonathan Hart

Added restrictions for proxy ARP

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 }
......