blob: 76bf021ae4e96c42106144a16946ad689065ddf6 [file] [log] [blame]
Jonathan Hart704ca142014-10-09 09:34:39 -07001package org.onlab.onos.net.proxyarp.impl;
2
3import static org.easymock.EasyMock.anyObject;
4import static org.easymock.EasyMock.createMock;
5import static org.easymock.EasyMock.expect;
6import static org.easymock.EasyMock.replay;
7import static org.junit.Assert.assertEquals;
8import static org.junit.Assert.assertFalse;
9import static org.junit.Assert.assertTrue;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collections;
14import java.util.Comparator;
15import java.util.List;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070016import java.util.Set;
Jonathan Hart704ca142014-10-09 09:34:39 -070017
18import org.junit.Before;
19import org.junit.Test;
20import org.onlab.onos.net.ConnectPoint;
21import org.onlab.onos.net.DefaultHost;
22import org.onlab.onos.net.Device;
23import org.onlab.onos.net.DeviceId;
24import org.onlab.onos.net.Host;
25import org.onlab.onos.net.HostId;
26import org.onlab.onos.net.HostLocation;
27import org.onlab.onos.net.Link;
28import org.onlab.onos.net.Port;
29import org.onlab.onos.net.PortNumber;
30import org.onlab.onos.net.device.DeviceListener;
31import org.onlab.onos.net.device.DeviceService;
32import org.onlab.onos.net.flow.instructions.Instruction;
33import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
34import org.onlab.onos.net.host.HostService;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070035import org.onlab.onos.net.host.InterfaceIpAddress;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070036import org.onlab.onos.net.host.PortAddresses;
Jonathan Hart704ca142014-10-09 09:34:39 -070037import org.onlab.onos.net.link.LinkListener;
38import org.onlab.onos.net.link.LinkService;
39import org.onlab.onos.net.packet.OutboundPacket;
40import org.onlab.onos.net.packet.PacketProcessor;
41import org.onlab.onos.net.packet.PacketService;
42import org.onlab.onos.net.provider.ProviderId;
43import org.onlab.packet.ARP;
44import org.onlab.packet.Ethernet;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070045import org.onlab.packet.IpAddress;
Jonathan Hart704ca142014-10-09 09:34:39 -070046import org.onlab.packet.IpPrefix;
47import org.onlab.packet.MacAddress;
48import org.onlab.packet.VlanId;
49
50import com.google.common.collect.Sets;
51
52/**
53 * Tests for the {@link ProxyArpManager} class.
54 */
55public class ProxyArpManagerTest {
56
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070057 private static final int NUM_DEVICES = 6;
Jonathan Hart704ca142014-10-09 09:34:39 -070058 private static final int NUM_PORTS_PER_DEVICE = 3;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070059 private static final int NUM_ADDRESS_PORTS = NUM_DEVICES / 2;
60 private static final int NUM_FLOOD_PORTS = 3;
Jonathan Hart704ca142014-10-09 09:34:39 -070061
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070062 private static final IpPrefix IP1 = IpPrefix.valueOf("192.168.1.1/24");
63 private static final IpPrefix IP2 = IpPrefix.valueOf("192.168.1.2/24");
Jonathan Hart704ca142014-10-09 09:34:39 -070064
65 private static final ProviderId PID = new ProviderId("of", "foo");
66
67 private static final VlanId VLAN1 = VlanId.vlanId((short) 1);
68 private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
69 private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01");
70 private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
71 private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
72 private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
73
74 private static final DeviceId DID1 = getDeviceId(1);
75 private static final DeviceId DID2 = getDeviceId(2);
76 private static final PortNumber P1 = PortNumber.portNumber(1);
77 private static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L);
78 private static final HostLocation LOC2 = new HostLocation(DID2, P1, 123L);
79
80 private ProxyArpManager proxyArp;
81
82 private TestPacketService packetService;
83
84 private DeviceService deviceService;
85 private LinkService linkService;
86 private HostService hostService;
87
88 @Before
89 public void setUp() throws Exception {
90 proxyArp = new ProxyArpManager();
91 packetService = new TestPacketService();
92 proxyArp.packetService = packetService;
93
94 // Create a host service mock here. Must be replayed by tests once the
95 // expectations have been set up
96 hostService = createMock(HostService.class);
97 proxyArp.hostService = hostService;
98
99 createTopology();
100 proxyArp.deviceService = deviceService;
101 proxyArp.linkService = linkService;
102
103 proxyArp.activate();
104 }
105
106 /**
107 * Creates a fake topology to feed into the ARP module.
108 * <p/>
109 * The default topology is a unidirectional ring topology. Each switch has
110 * 3 ports. Ports 2 and 3 have the links to neighbor switches, and port 1
111 * is free (edge port).
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700112 * The first half of the switches have IP addresses configured on their
113 * free ports (port 1). The second half of the switches have no IP
114 * addresses configured.
Jonathan Hart704ca142014-10-09 09:34:39 -0700115 */
116 private void createTopology() {
117 deviceService = createMock(DeviceService.class);
118 linkService = createMock(LinkService.class);
119
120 deviceService.addListener(anyObject(DeviceListener.class));
121 linkService.addListener(anyObject(LinkListener.class));
122
123 createDevices(NUM_DEVICES, NUM_PORTS_PER_DEVICE);
124 createLinks(NUM_DEVICES);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700125 addAddressBindings();
Jonathan Hart704ca142014-10-09 09:34:39 -0700126 }
127
128 /**
129 * Creates the devices for the fake topology.
130 */
131 private void createDevices(int numDevices, int numPorts) {
132 List<Device> devices = new ArrayList<>();
133
134 for (int i = 1; i <= numDevices; i++) {
135 DeviceId devId = getDeviceId(i);
136 Device device = createMock(Device.class);
137 expect(device.id()).andReturn(devId).anyTimes();
138 replay(device);
139
140 devices.add(device);
141
142 List<Port> ports = new ArrayList<>();
143 for (int j = 1; j <= numPorts; j++) {
144 Port port = createMock(Port.class);
145 expect(port.number()).andReturn(PortNumber.portNumber(j)).anyTimes();
146 replay(port);
147 ports.add(port);
148 }
149
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700150 expect(deviceService.getPorts(devId)).andReturn(ports).anyTimes();
151 expect(deviceService.getDevice(devId)).andReturn(device).anyTimes();
Jonathan Hart704ca142014-10-09 09:34:39 -0700152 }
153
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700154 expect(deviceService.getDevices()).andReturn(devices).anyTimes();
Jonathan Hart704ca142014-10-09 09:34:39 -0700155 replay(deviceService);
156 }
157
158 /**
159 * Creates the links for the fake topology.
160 * NB: Only unidirectional links are created, as for this purpose all we
161 * need is to occupy the ports with some link.
162 */
163 private void createLinks(int numDevices) {
164 List<Link> links = new ArrayList<Link>();
165
166 for (int i = 1; i <= numDevices; i++) {
167 ConnectPoint src = new ConnectPoint(
168 getDeviceId(i),
169 PortNumber.portNumber(2));
170 ConnectPoint dst = new ConnectPoint(
171 getDeviceId((i + 1 > numDevices) ? 1 : i + 1),
172 PortNumber.portNumber(3));
173
174 Link link = createMock(Link.class);
175 expect(link.src()).andReturn(src).anyTimes();
176 expect(link.dst()).andReturn(dst).anyTimes();
177 replay(link);
178
179 links.add(link);
180 }
181
182 expect(linkService.getLinks()).andReturn(links).anyTimes();
183 replay(linkService);
184 }
185
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700186 private void addAddressBindings() {
187 Set<PortAddresses> addresses = Sets.newHashSet();
188
189 for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) {
190 ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700191 IpPrefix prefix1 = IpPrefix.valueOf("10.0." + (2 * i - 1) + ".0/24");
192 IpAddress addr1 = IpAddress.valueOf("10.0." + (2 * i - 1) + ".1");
193 IpPrefix prefix2 = IpPrefix.valueOf("10.0." + (2 * i) + ".0/24");
194 IpAddress addr2 = IpAddress.valueOf("10.0." + (2 * i) + ".1");
195 InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
196 InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
197 PortAddresses pa =
198 new PortAddresses(cp, Sets.newHashSet(ia1, ia2),
199 MacAddress.valueOf(i));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700200 addresses.add(pa);
201
202 expect(hostService.getAddressBindingsForPort(cp))
203 .andReturn(pa).anyTimes();
204 }
205
206 expect(hostService.getAddressBindings()).andReturn(addresses).anyTimes();
207
208 for (int i = 1; i <= NUM_FLOOD_PORTS; i++) {
209 ConnectPoint cp = new ConnectPoint(getDeviceId(i + NUM_ADDRESS_PORTS),
210 P1);
211 expect(hostService.getAddressBindingsForPort(cp))
212 .andReturn(new PortAddresses(cp, null, null)).anyTimes();
213 }
214 }
215
Jonathan Hart704ca142014-10-09 09:34:39 -0700216 /**
217 * Tests {@link ProxyArpManager#known(IpPrefix)} in the case where the
218 * IP address is not known.
219 * Verifies the method returns false.
220 */
221 @Test
222 public void testNotKnown() {
223 expect(hostService.getHostsByIp(IP1)).andReturn(Collections.<Host>emptySet());
224 replay(hostService);
225
226 assertFalse(proxyArp.known(IP1));
227 }
228
229 /**
230 * Tests {@link ProxyArpManager#known(IpPrefix)} in the case where the
231 * IP address is known.
232 * Verifies the method returns true.
233 */
234 @Test
235 public void testKnown() {
236 Host host1 = createMock(Host.class);
237 Host host2 = createMock(Host.class);
238
239 expect(hostService.getHostsByIp(IP1))
240 .andReturn(Sets.newHashSet(host1, host2));
241 replay(hostService);
242
243 assertTrue(proxyArp.known(IP1));
244 }
245
246 /**
247 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
248 * destination host is known.
249 * Verifies the correct ARP reply is sent out the correct port.
250 */
251 @Test
252 public void testReplyKnown() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700253 Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(4),
Jonathan Hart704ca142014-10-09 09:34:39 -0700254 Collections.singleton(IP1));
255
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700256 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700257 Collections.singleton(IP2));
258
259 expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets())))
260 .andReturn(Collections.singleton(replyer));
261 expect(hostService.getHost(HID2)).andReturn(requestor);
262
263 replay(hostService);
264
265 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
266
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700267 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700268
269 assertEquals(1, packetService.packets.size());
270 Ethernet arpReply = buildArp(ARP.OP_REPLY, MAC1, MAC2, IP1, IP2);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700271 verifyPacketOut(arpReply, getLocation(5), packetService.packets.get(0));
Jonathan Hart704ca142014-10-09 09:34:39 -0700272 }
273
274 /**
275 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
276 * destination host is not known.
277 * Verifies the ARP request is flooded out the correct edge ports.
278 */
279 @Test
280 public void testReplyUnknown() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700281 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700282 Collections.singleton(IP2));
283
284 expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets())))
285 .andReturn(Collections.<Host>emptySet());
286 expect(hostService.getHost(HID2)).andReturn(requestor);
287
288 replay(hostService);
289
290 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
291
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700292 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700293
294 verifyFlood(arpRequest);
295 }
296
297 /**
298 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
299 * destination host is known for that IP address, but is not on the same
300 * VLAN as the source host.
301 * Verifies the ARP request is flooded out the correct edge ports.
302 */
303 @Test
304 public void testReplyDifferentVlan() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700305 Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN2, getLocation(4),
Jonathan Hart704ca142014-10-09 09:34:39 -0700306 Collections.singleton(IP1));
307
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700308 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700309 Collections.singleton(IP2));
310
311 expect(hostService.getHostsByIp(IpPrefix.valueOf(IP1.toOctets())))
312 .andReturn(Collections.singleton(replyer));
313 expect(hostService.getHost(HID2)).andReturn(requestor);
314
315 replay(hostService);
316
317 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
318
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700319 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700320
321 verifyFlood(arpRequest);
322 }
323
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700324 @Test
325 public void testReplyToRequestForUs() {
326 IpPrefix theirIp = IpPrefix.valueOf("10.0.1.254/24");
327 IpPrefix ourFirstIp = IpPrefix.valueOf("10.0.1.1/24");
328 IpPrefix ourSecondIp = IpPrefix.valueOf("10.0.2.1/24");
329 MacAddress ourMac = MacAddress.valueOf(1L);
330
331 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
332 Collections.singleton(theirIp));
333
334 expect(hostService.getHost(HID2)).andReturn(requestor);
335 replay(hostService);
336
337 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourFirstIp);
338
339 proxyArp.reply(arpRequest, LOC1);
340
341 assertEquals(1, packetService.packets.size());
342 Ethernet arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourFirstIp, theirIp);
343 verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
344
345 // Test a request for the second address on that port
346 packetService.packets.clear();
347 arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourSecondIp);
348
349 proxyArp.reply(arpRequest, LOC1);
350
351 assertEquals(1, packetService.packets.size());
352 arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourSecondIp, theirIp);
353 verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
354 }
355
356 @Test
357 public void testReplyExternalPortBadRequest() {
358 replay(hostService); // no further host service expectations
359
360 IpPrefix theirIp = IpPrefix.valueOf("10.0.1.254/24");
361
362 // Request for a valid external IP address but coming in the wrong port
363 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp,
364 IpPrefix.valueOf("10.0.3.1"));
365 proxyArp.reply(arpRequest, LOC1);
366 assertEquals(0, packetService.packets.size());
367
368 // Request for a valid internal IP address but coming in an external port
369 packetService.packets.clear();
370 arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp, IP1);
371 proxyArp.reply(arpRequest, LOC1);
372 assertEquals(0, packetService.packets.size());
373 }
374
375 @Test
376 public void testReplyToRequestFromUs() {
377 replay(hostService); // no further host service expectations
378
379 IpPrefix ourIp = IpPrefix.valueOf("10.0.1.1/24");
380 MacAddress ourMac = MacAddress.valueOf(1L);
381 IpPrefix theirIp = IpPrefix.valueOf("10.0.1.100/24");
382
383 // This is a request from something inside our network (like a BGP
384 // daemon) to an external host.
385 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, ourMac, null, ourIp, theirIp);
386 proxyArp.reply(arpRequest, getLocation(5));
387
388 assertEquals(1, packetService.packets.size());
389 verifyPacketOut(arpRequest, getLocation(1), packetService.packets.get(0));
390
391 // The same request from a random external port should fail
392 packetService.packets.clear();
393 proxyArp.reply(arpRequest, getLocation(2));
394 assertEquals(0, packetService.packets.size());
395 }
396
Jonathan Hart704ca142014-10-09 09:34:39 -0700397 /**
398 * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
399 * destination host is known.
400 * Verifies the correct ARP request is sent out the correct port.
401 */
402 @Test
403 public void testForwardToHost() {
404 Host host1 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1,
405 Collections.singleton(IP1));
406
407 expect(hostService.getHost(HID1)).andReturn(host1);
408 replay(hostService);
409
410 Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
411
412 proxyArp.forward(arpRequest);
413
414 assertEquals(1, packetService.packets.size());
415 OutboundPacket packet = packetService.packets.get(0);
416
417 verifyPacketOut(arpRequest, LOC1, packet);
418 }
419
420 /**
421 * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
422 * destination host is not known.
423 * Verifies the correct ARP request is flooded out the correct edge ports.
424 */
425 @Test
426 public void testForwardFlood() {
427 expect(hostService.getHost(HID1)).andReturn(null);
428 replay(hostService);
429
430 Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
431
432 proxyArp.forward(arpRequest);
433
434 verifyFlood(arpRequest);
435 }
436
437 /**
438 * Verifies that the given packet was flooded out all available edge ports.
439 *
440 * @param packet the packet that was expected to be flooded
441 */
442 private void verifyFlood(Ethernet packet) {
443 assertEquals(NUM_FLOOD_PORTS, packetService.packets.size());
444
445 Collections.sort(packetService.packets,
446 new Comparator<OutboundPacket>() {
447 @Override
448 public int compare(OutboundPacket o1, OutboundPacket o2) {
449 return o1.sendThrough().uri().compareTo(o2.sendThrough().uri());
450 }
451 });
452
453 for (int i = 0; i < NUM_FLOOD_PORTS; i++) {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700454 ConnectPoint cp = new ConnectPoint(getDeviceId(NUM_ADDRESS_PORTS + i + 1),
455 PortNumber.portNumber(1));
Jonathan Hart704ca142014-10-09 09:34:39 -0700456
457 OutboundPacket outboundPacket = packetService.packets.get(i);
458 verifyPacketOut(packet, cp, outboundPacket);
459 }
460 }
461
462 /**
463 * Verifies the given packet was sent out the given port.
464 *
465 * @param expected the packet that was expected to be sent
466 * @param outPort the port the packet was expected to be sent out
467 * @param actual the actual OutboundPacket to verify
468 */
469 private void verifyPacketOut(Ethernet expected, ConnectPoint outPort,
470 OutboundPacket actual) {
471 assertTrue(Arrays.equals(expected.serialize(), actual.data().array()));
472 assertEquals(1, actual.treatment().instructions().size());
473 assertEquals(outPort.deviceId(), actual.sendThrough());
474 Instruction instruction = actual.treatment().instructions().get(0);
475 assertTrue(instruction instanceof OutputInstruction);
476 assertEquals(outPort.port(), ((OutputInstruction) instruction).port());
477 }
478
479 /**
480 * Returns the device ID of the ith device.
481 *
482 * @param i device to get the ID of
483 * @return the device ID
484 */
485 private static DeviceId getDeviceId(int i) {
486 return DeviceId.deviceId("" + i);
487 }
488
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700489 private static HostLocation getLocation(int i) {
490 return new HostLocation(new ConnectPoint(getDeviceId(i), P1), 123L);
491 }
492
Jonathan Hart704ca142014-10-09 09:34:39 -0700493 /**
494 * Builds an ARP packet with the given parameters.
495 *
496 * @param opcode opcode of the ARP packet
497 * @param srcMac source MAC address
498 * @param dstMac destination MAC address, or null if this is a request
499 * @param srcIp source IP address
500 * @param dstIp destination IP address
501 * @return the ARP packet
502 */
503 private Ethernet buildArp(short opcode, MacAddress srcMac, MacAddress dstMac,
504 IpPrefix srcIp, IpPrefix dstIp) {
505 Ethernet eth = new Ethernet();
506
507 if (dstMac == null) {
508 eth.setDestinationMACAddress(MacAddress.BROADCAST_MAC);
509 } else {
510 eth.setDestinationMACAddress(dstMac.getAddress());
511 }
512
513 eth.setSourceMACAddress(srcMac.getAddress());
514 eth.setEtherType(Ethernet.TYPE_ARP);
515 eth.setVlanID(VLAN1.toShort());
516
517 ARP arp = new ARP();
518 arp.setOpCode(opcode);
519 arp.setProtocolType(ARP.PROTO_TYPE_IP);
520 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
521
522 arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN);
523 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
524 arp.setSenderHardwareAddress(srcMac.getAddress());
525
526 if (dstMac == null) {
527 arp.setTargetHardwareAddress(MacAddress.ZERO_MAC_ADDRESS);
528 } else {
529 arp.setTargetHardwareAddress(dstMac.getAddress());
530 }
531
532 arp.setSenderProtocolAddress(srcIp.toOctets());
533 arp.setTargetProtocolAddress(dstIp.toOctets());
534
535 eth.setPayload(arp);
536 return eth;
537 }
538
539 /**
540 * Test PacketService implementation that simply stores OutboundPackets
541 * passed to {@link #emit(OutboundPacket)} for later verification.
542 */
543 class TestPacketService implements PacketService {
544
545 List<OutboundPacket> packets = new ArrayList<>();
546
547 @Override
548 public void addProcessor(PacketProcessor processor, int priority) {
549 }
550
551 @Override
552 public void removeProcessor(PacketProcessor processor) {
553 }
554
555 @Override
556 public void emit(OutboundPacket packet) {
557 packets.add(packet);
558 }
559 }
560}