blob: e82151e82eef2760ac7e0508a3ca9a3df2a89cb3 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jonathan Hart704ca142014-10-09 09:34:39 -070016package org.onlab.onos.net.proxyarp.impl;
17
18import static org.easymock.EasyMock.anyObject;
19import static org.easymock.EasyMock.createMock;
20import static org.easymock.EasyMock.expect;
21import static org.easymock.EasyMock.replay;
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -080022import static org.junit.Assert.*;
Jonathan Hart704ca142014-10-09 09:34:39 -070023
24import java.util.ArrayList;
Jonathan Hart704ca142014-10-09 09:34:39 -070025import java.util.Collections;
26import java.util.Comparator;
27import java.util.List;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070028import java.util.Set;
Jonathan Hart704ca142014-10-09 09:34:39 -070029
30import org.junit.Before;
31import org.junit.Test;
32import org.onlab.onos.net.ConnectPoint;
33import org.onlab.onos.net.DefaultHost;
34import org.onlab.onos.net.Device;
35import org.onlab.onos.net.DeviceId;
36import org.onlab.onos.net.Host;
37import org.onlab.onos.net.HostId;
38import org.onlab.onos.net.HostLocation;
39import org.onlab.onos.net.Link;
40import org.onlab.onos.net.Port;
41import org.onlab.onos.net.PortNumber;
42import org.onlab.onos.net.device.DeviceListener;
43import org.onlab.onos.net.device.DeviceService;
44import org.onlab.onos.net.flow.instructions.Instruction;
45import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
46import org.onlab.onos.net.host.HostService;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070047import org.onlab.onos.net.host.InterfaceIpAddress;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070048import org.onlab.onos.net.host.PortAddresses;
Jonathan Hart704ca142014-10-09 09:34:39 -070049import org.onlab.onos.net.link.LinkListener;
50import org.onlab.onos.net.link.LinkService;
51import org.onlab.onos.net.packet.OutboundPacket;
52import org.onlab.onos.net.packet.PacketProcessor;
53import org.onlab.onos.net.packet.PacketService;
54import org.onlab.onos.net.provider.ProviderId;
55import org.onlab.packet.ARP;
56import org.onlab.packet.Ethernet;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070057import org.onlab.packet.IpAddress;
Jonathan Hart704ca142014-10-09 09:34:39 -070058import org.onlab.packet.IpPrefix;
59import org.onlab.packet.MacAddress;
60import org.onlab.packet.VlanId;
61
62import com.google.common.collect.Sets;
63
64/**
65 * Tests for the {@link ProxyArpManager} class.
66 */
67public class ProxyArpManagerTest {
68
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070069 private static final int NUM_DEVICES = 6;
Jonathan Hart704ca142014-10-09 09:34:39 -070070 private static final int NUM_PORTS_PER_DEVICE = 3;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070071 private static final int NUM_ADDRESS_PORTS = NUM_DEVICES / 2;
72 private static final int NUM_FLOOD_PORTS = 3;
Jonathan Hart704ca142014-10-09 09:34:39 -070073
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -070074 private static final IpAddress IP1 = IpAddress.valueOf("192.168.1.1");
75 private static final IpAddress IP2 = IpAddress.valueOf("192.168.1.2");
Jonathan Hart704ca142014-10-09 09:34:39 -070076
77 private static final ProviderId PID = new ProviderId("of", "foo");
78
79 private static final VlanId VLAN1 = VlanId.vlanId((short) 1);
80 private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
81 private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01");
82 private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
83 private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
84 private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
85
86 private static final DeviceId DID1 = getDeviceId(1);
87 private static final DeviceId DID2 = getDeviceId(2);
88 private static final PortNumber P1 = PortNumber.portNumber(1);
89 private static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L);
90 private static final HostLocation LOC2 = new HostLocation(DID2, P1, 123L);
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -080091 private static final byte[] ZERO_MAC_ADDRESS = MacAddress.ZERO.toBytes();
Jonathan Hart704ca142014-10-09 09:34:39 -070092
93 private ProxyArpManager proxyArp;
94
95 private TestPacketService packetService;
96
97 private DeviceService deviceService;
98 private LinkService linkService;
99 private HostService hostService;
100
101 @Before
102 public void setUp() throws Exception {
103 proxyArp = new ProxyArpManager();
104 packetService = new TestPacketService();
105 proxyArp.packetService = packetService;
106
107 // Create a host service mock here. Must be replayed by tests once the
108 // expectations have been set up
109 hostService = createMock(HostService.class);
110 proxyArp.hostService = hostService;
111
112 createTopology();
113 proxyArp.deviceService = deviceService;
114 proxyArp.linkService = linkService;
115
116 proxyArp.activate();
117 }
118
119 /**
120 * Creates a fake topology to feed into the ARP module.
121 * <p/>
122 * The default topology is a unidirectional ring topology. Each switch has
123 * 3 ports. Ports 2 and 3 have the links to neighbor switches, and port 1
124 * is free (edge port).
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700125 * The first half of the switches have IP addresses configured on their
126 * free ports (port 1). The second half of the switches have no IP
127 * addresses configured.
Jonathan Hart704ca142014-10-09 09:34:39 -0700128 */
129 private void createTopology() {
130 deviceService = createMock(DeviceService.class);
131 linkService = createMock(LinkService.class);
132
133 deviceService.addListener(anyObject(DeviceListener.class));
134 linkService.addListener(anyObject(LinkListener.class));
135
136 createDevices(NUM_DEVICES, NUM_PORTS_PER_DEVICE);
137 createLinks(NUM_DEVICES);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700138 addAddressBindings();
Jonathan Hart704ca142014-10-09 09:34:39 -0700139 }
140
141 /**
142 * Creates the devices for the fake topology.
143 */
144 private void createDevices(int numDevices, int numPorts) {
145 List<Device> devices = new ArrayList<>();
146
147 for (int i = 1; i <= numDevices; i++) {
148 DeviceId devId = getDeviceId(i);
149 Device device = createMock(Device.class);
150 expect(device.id()).andReturn(devId).anyTimes();
151 replay(device);
152
153 devices.add(device);
154
155 List<Port> ports = new ArrayList<>();
156 for (int j = 1; j <= numPorts; j++) {
157 Port port = createMock(Port.class);
158 expect(port.number()).andReturn(PortNumber.portNumber(j)).anyTimes();
159 replay(port);
160 ports.add(port);
161 }
162
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700163 expect(deviceService.getPorts(devId)).andReturn(ports).anyTimes();
164 expect(deviceService.getDevice(devId)).andReturn(device).anyTimes();
Jonathan Hart704ca142014-10-09 09:34:39 -0700165 }
166
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700167 expect(deviceService.getDevices()).andReturn(devices).anyTimes();
Jonathan Hart704ca142014-10-09 09:34:39 -0700168 replay(deviceService);
169 }
170
171 /**
172 * Creates the links for the fake topology.
173 * NB: Only unidirectional links are created, as for this purpose all we
174 * need is to occupy the ports with some link.
175 */
176 private void createLinks(int numDevices) {
177 List<Link> links = new ArrayList<Link>();
178
179 for (int i = 1; i <= numDevices; i++) {
180 ConnectPoint src = new ConnectPoint(
181 getDeviceId(i),
182 PortNumber.portNumber(2));
183 ConnectPoint dst = new ConnectPoint(
184 getDeviceId((i + 1 > numDevices) ? 1 : i + 1),
185 PortNumber.portNumber(3));
186
187 Link link = createMock(Link.class);
188 expect(link.src()).andReturn(src).anyTimes();
189 expect(link.dst()).andReturn(dst).anyTimes();
190 replay(link);
191
192 links.add(link);
193 }
194
195 expect(linkService.getLinks()).andReturn(links).anyTimes();
196 replay(linkService);
197 }
198
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700199 private void addAddressBindings() {
200 Set<PortAddresses> addresses = Sets.newHashSet();
201
202 for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) {
203 ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700204 IpPrefix prefix1 = IpPrefix.valueOf("10.0." + (2 * i - 1) + ".0/24");
205 IpAddress addr1 = IpAddress.valueOf("10.0." + (2 * i - 1) + ".1");
206 IpPrefix prefix2 = IpPrefix.valueOf("10.0." + (2 * i) + ".0/24");
207 IpAddress addr2 = IpAddress.valueOf("10.0." + (2 * i) + ".1");
208 InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
209 InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
210 PortAddresses pa =
211 new PortAddresses(cp, Sets.newHashSet(ia1, ia2),
212 MacAddress.valueOf(i));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700213 addresses.add(pa);
214
215 expect(hostService.getAddressBindingsForPort(cp))
216 .andReturn(pa).anyTimes();
217 }
218
219 expect(hostService.getAddressBindings()).andReturn(addresses).anyTimes();
220
221 for (int i = 1; i <= NUM_FLOOD_PORTS; i++) {
222 ConnectPoint cp = new ConnectPoint(getDeviceId(i + NUM_ADDRESS_PORTS),
223 P1);
224 expect(hostService.getAddressBindingsForPort(cp))
225 .andReturn(new PortAddresses(cp, null, null)).anyTimes();
226 }
227 }
228
Jonathan Hart704ca142014-10-09 09:34:39 -0700229 /**
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700230 * Tests {@link ProxyArpManager#known(IpAddress)} in the case where the
Jonathan Hart704ca142014-10-09 09:34:39 -0700231 * IP address is not known.
232 * Verifies the method returns false.
233 */
234 @Test
235 public void testNotKnown() {
236 expect(hostService.getHostsByIp(IP1)).andReturn(Collections.<Host>emptySet());
237 replay(hostService);
238
239 assertFalse(proxyArp.known(IP1));
240 }
241
242 /**
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700243 * Tests {@link ProxyArpManager#known(IpAddress)} in the case where the
Jonathan Hart704ca142014-10-09 09:34:39 -0700244 * IP address is known.
245 * Verifies the method returns true.
246 */
247 @Test
248 public void testKnown() {
249 Host host1 = createMock(Host.class);
250 Host host2 = createMock(Host.class);
251
252 expect(hostService.getHostsByIp(IP1))
253 .andReturn(Sets.newHashSet(host1, host2));
254 replay(hostService);
255
256 assertTrue(proxyArp.known(IP1));
257 }
258
259 /**
260 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
261 * destination host is known.
262 * Verifies the correct ARP reply is sent out the correct port.
263 */
264 @Test
265 public void testReplyKnown() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700266 Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(4),
Jonathan Hart704ca142014-10-09 09:34:39 -0700267 Collections.singleton(IP1));
268
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700269 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700270 Collections.singleton(IP2));
271
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700272 expect(hostService.getHostsByIp(IP1))
273 .andReturn(Collections.singleton(replyer));
Jonathan Hart704ca142014-10-09 09:34:39 -0700274 expect(hostService.getHost(HID2)).andReturn(requestor);
275
276 replay(hostService);
277
278 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
279
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700280 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700281
282 assertEquals(1, packetService.packets.size());
283 Ethernet arpReply = buildArp(ARP.OP_REPLY, MAC1, MAC2, IP1, IP2);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700284 verifyPacketOut(arpReply, getLocation(5), packetService.packets.get(0));
Jonathan Hart704ca142014-10-09 09:34:39 -0700285 }
286
287 /**
288 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
289 * destination host is not known.
290 * Verifies the ARP request is flooded out the correct edge ports.
291 */
292 @Test
293 public void testReplyUnknown() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700294 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700295 Collections.singleton(IP2));
296
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700297 expect(hostService.getHostsByIp(IP1))
Jonathan Hart704ca142014-10-09 09:34:39 -0700298 .andReturn(Collections.<Host>emptySet());
299 expect(hostService.getHost(HID2)).andReturn(requestor);
300
301 replay(hostService);
302
303 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
304
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700305 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700306
307 verifyFlood(arpRequest);
308 }
309
310 /**
311 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
312 * destination host is known for that IP address, but is not on the same
313 * VLAN as the source host.
314 * Verifies the ARP request is flooded out the correct edge ports.
315 */
316 @Test
317 public void testReplyDifferentVlan() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700318 Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN2, getLocation(4),
Jonathan Hart704ca142014-10-09 09:34:39 -0700319 Collections.singleton(IP1));
320
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700321 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700322 Collections.singleton(IP2));
323
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700324 expect(hostService.getHostsByIp(IP1))
Jonathan Hart704ca142014-10-09 09:34:39 -0700325 .andReturn(Collections.singleton(replyer));
326 expect(hostService.getHost(HID2)).andReturn(requestor);
327
328 replay(hostService);
329
330 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
331
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700332 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700333
334 verifyFlood(arpRequest);
335 }
336
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700337 @Test
338 public void testReplyToRequestForUs() {
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700339 IpAddress theirIp = IpAddress.valueOf("10.0.1.254");
340 IpAddress ourFirstIp = IpAddress.valueOf("10.0.1.1");
341 IpAddress ourSecondIp = IpAddress.valueOf("10.0.2.1");
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700342 MacAddress ourMac = MacAddress.valueOf(1L);
343
344 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
345 Collections.singleton(theirIp));
346
347 expect(hostService.getHost(HID2)).andReturn(requestor);
348 replay(hostService);
349
350 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourFirstIp);
351
352 proxyArp.reply(arpRequest, LOC1);
353
354 assertEquals(1, packetService.packets.size());
355 Ethernet arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourFirstIp, theirIp);
356 verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
357
358 // Test a request for the second address on that port
359 packetService.packets.clear();
360 arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourSecondIp);
361
362 proxyArp.reply(arpRequest, LOC1);
363
364 assertEquals(1, packetService.packets.size());
365 arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourSecondIp, theirIp);
366 verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
367 }
368
369 @Test
370 public void testReplyExternalPortBadRequest() {
371 replay(hostService); // no further host service expectations
372
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700373 IpAddress theirIp = IpAddress.valueOf("10.0.1.254");
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700374
375 // Request for a valid external IP address but coming in the wrong port
376 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp,
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700377 IpAddress.valueOf("10.0.3.1"));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700378 proxyArp.reply(arpRequest, LOC1);
379 assertEquals(0, packetService.packets.size());
380
381 // Request for a valid internal IP address but coming in an external port
382 packetService.packets.clear();
383 arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp, IP1);
384 proxyArp.reply(arpRequest, LOC1);
385 assertEquals(0, packetService.packets.size());
386 }
387
388 @Test
389 public void testReplyToRequestFromUs() {
390 replay(hostService); // no further host service expectations
391
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700392 IpAddress ourIp = IpAddress.valueOf("10.0.1.1");
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700393 MacAddress ourMac = MacAddress.valueOf(1L);
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700394 IpAddress theirIp = IpAddress.valueOf("10.0.1.100");
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700395
396 // This is a request from something inside our network (like a BGP
397 // daemon) to an external host.
398 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, ourMac, null, ourIp, theirIp);
399 proxyArp.reply(arpRequest, getLocation(5));
400
401 assertEquals(1, packetService.packets.size());
402 verifyPacketOut(arpRequest, getLocation(1), packetService.packets.get(0));
403
404 // The same request from a random external port should fail
405 packetService.packets.clear();
406 proxyArp.reply(arpRequest, getLocation(2));
407 assertEquals(0, packetService.packets.size());
408 }
409
Jonathan Hart704ca142014-10-09 09:34:39 -0700410 /**
411 * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
412 * destination host is known.
413 * Verifies the correct ARP request is sent out the correct port.
414 */
415 @Test
416 public void testForwardToHost() {
417 Host host1 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1,
418 Collections.singleton(IP1));
419
420 expect(hostService.getHost(HID1)).andReturn(host1);
421 replay(hostService);
422
423 Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
424
425 proxyArp.forward(arpRequest);
426
427 assertEquals(1, packetService.packets.size());
428 OutboundPacket packet = packetService.packets.get(0);
429
430 verifyPacketOut(arpRequest, LOC1, packet);
431 }
432
433 /**
434 * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
435 * destination host is not known.
436 * Verifies the correct ARP request is flooded out the correct edge ports.
437 */
438 @Test
439 public void testForwardFlood() {
440 expect(hostService.getHost(HID1)).andReturn(null);
441 replay(hostService);
442
443 Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
444
445 proxyArp.forward(arpRequest);
446
447 verifyFlood(arpRequest);
448 }
449
450 /**
451 * Verifies that the given packet was flooded out all available edge ports.
452 *
453 * @param packet the packet that was expected to be flooded
454 */
455 private void verifyFlood(Ethernet packet) {
456 assertEquals(NUM_FLOOD_PORTS, packetService.packets.size());
457
458 Collections.sort(packetService.packets,
459 new Comparator<OutboundPacket>() {
460 @Override
461 public int compare(OutboundPacket o1, OutboundPacket o2) {
462 return o1.sendThrough().uri().compareTo(o2.sendThrough().uri());
463 }
464 });
465
466 for (int i = 0; i < NUM_FLOOD_PORTS; i++) {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700467 ConnectPoint cp = new ConnectPoint(getDeviceId(NUM_ADDRESS_PORTS + i + 1),
468 PortNumber.portNumber(1));
Jonathan Hart704ca142014-10-09 09:34:39 -0700469
470 OutboundPacket outboundPacket = packetService.packets.get(i);
471 verifyPacketOut(packet, cp, outboundPacket);
472 }
473 }
474
475 /**
476 * Verifies the given packet was sent out the given port.
477 *
478 * @param expected the packet that was expected to be sent
479 * @param outPort the port the packet was expected to be sent out
480 * @param actual the actual OutboundPacket to verify
481 */
482 private void verifyPacketOut(Ethernet expected, ConnectPoint outPort,
483 OutboundPacket actual) {
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800484 assertArrayEquals(expected.serialize(), actual.data().array());
Jonathan Hart704ca142014-10-09 09:34:39 -0700485 assertEquals(1, actual.treatment().instructions().size());
486 assertEquals(outPort.deviceId(), actual.sendThrough());
487 Instruction instruction = actual.treatment().instructions().get(0);
488 assertTrue(instruction instanceof OutputInstruction);
489 assertEquals(outPort.port(), ((OutputInstruction) instruction).port());
490 }
491
492 /**
493 * Returns the device ID of the ith device.
494 *
495 * @param i device to get the ID of
496 * @return the device ID
497 */
498 private static DeviceId getDeviceId(int i) {
499 return DeviceId.deviceId("" + i);
500 }
501
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700502 private static HostLocation getLocation(int i) {
503 return new HostLocation(new ConnectPoint(getDeviceId(i), P1), 123L);
504 }
505
Jonathan Hart704ca142014-10-09 09:34:39 -0700506 /**
507 * Builds an ARP packet with the given parameters.
508 *
509 * @param opcode opcode of the ARP packet
510 * @param srcMac source MAC address
511 * @param dstMac destination MAC address, or null if this is a request
512 * @param srcIp source IP address
513 * @param dstIp destination IP address
514 * @return the ARP packet
515 */
516 private Ethernet buildArp(short opcode, MacAddress srcMac, MacAddress dstMac,
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700517 IpAddress srcIp, IpAddress dstIp) {
Jonathan Hart704ca142014-10-09 09:34:39 -0700518 Ethernet eth = new Ethernet();
519
520 if (dstMac == null) {
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800521 eth.setDestinationMACAddress(MacAddress.BROADCAST);
Jonathan Hart704ca142014-10-09 09:34:39 -0700522 } else {
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800523 eth.setDestinationMACAddress(dstMac);
Jonathan Hart704ca142014-10-09 09:34:39 -0700524 }
525
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800526 eth.setSourceMACAddress(srcMac);
Jonathan Hart704ca142014-10-09 09:34:39 -0700527 eth.setEtherType(Ethernet.TYPE_ARP);
528 eth.setVlanID(VLAN1.toShort());
529
530 ARP arp = new ARP();
531 arp.setOpCode(opcode);
532 arp.setProtocolType(ARP.PROTO_TYPE_IP);
533 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
534
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700535 arp.setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH);
Jonathan Hart704ca142014-10-09 09:34:39 -0700536 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800537 arp.setSenderHardwareAddress(srcMac.toBytes());
Jonathan Hart704ca142014-10-09 09:34:39 -0700538
539 if (dstMac == null) {
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800540 arp.setTargetHardwareAddress(ZERO_MAC_ADDRESS);
Jonathan Hart704ca142014-10-09 09:34:39 -0700541 } else {
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800542 arp.setTargetHardwareAddress(dstMac.toBytes());
Jonathan Hart704ca142014-10-09 09:34:39 -0700543 }
544
545 arp.setSenderProtocolAddress(srcIp.toOctets());
546 arp.setTargetProtocolAddress(dstIp.toOctets());
547
548 eth.setPayload(arp);
549 return eth;
550 }
551
552 /**
553 * Test PacketService implementation that simply stores OutboundPackets
554 * passed to {@link #emit(OutboundPacket)} for later verification.
555 */
556 class TestPacketService implements PacketService {
557
558 List<OutboundPacket> packets = new ArrayList<>();
559
560 @Override
561 public void addProcessor(PacketProcessor processor, int priority) {
562 }
563
564 @Override
565 public void removeProcessor(PacketProcessor processor) {
566 }
567
568 @Override
569 public void emit(OutboundPacket packet) {
570 packets.add(packet);
571 }
572 }
573}