blob: 6eca77c8d4d6796a45c57009a9ec89e60eb1c057 [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;
22import static org.junit.Assert.assertEquals;
23import static org.junit.Assert.assertFalse;
24import static org.junit.Assert.assertTrue;
25
26import java.util.ArrayList;
27import java.util.Arrays;
28import java.util.Collections;
29import java.util.Comparator;
30import java.util.List;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070031import java.util.Set;
Jonathan Hart704ca142014-10-09 09:34:39 -070032
33import org.junit.Before;
34import org.junit.Test;
35import org.onlab.onos.net.ConnectPoint;
36import org.onlab.onos.net.DefaultHost;
37import org.onlab.onos.net.Device;
38import org.onlab.onos.net.DeviceId;
39import org.onlab.onos.net.Host;
40import org.onlab.onos.net.HostId;
41import org.onlab.onos.net.HostLocation;
42import org.onlab.onos.net.Link;
43import org.onlab.onos.net.Port;
44import org.onlab.onos.net.PortNumber;
45import org.onlab.onos.net.device.DeviceListener;
46import org.onlab.onos.net.device.DeviceService;
47import org.onlab.onos.net.flow.instructions.Instruction;
48import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
49import org.onlab.onos.net.host.HostService;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070050import org.onlab.onos.net.host.InterfaceIpAddress;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070051import org.onlab.onos.net.host.PortAddresses;
Jonathan Hart704ca142014-10-09 09:34:39 -070052import org.onlab.onos.net.link.LinkListener;
53import org.onlab.onos.net.link.LinkService;
54import org.onlab.onos.net.packet.OutboundPacket;
55import org.onlab.onos.net.packet.PacketProcessor;
56import org.onlab.onos.net.packet.PacketService;
57import org.onlab.onos.net.provider.ProviderId;
58import org.onlab.packet.ARP;
59import org.onlab.packet.Ethernet;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070060import org.onlab.packet.IpAddress;
Jonathan Hart704ca142014-10-09 09:34:39 -070061import org.onlab.packet.IpPrefix;
62import org.onlab.packet.MacAddress;
63import org.onlab.packet.VlanId;
64
65import com.google.common.collect.Sets;
66
67/**
68 * Tests for the {@link ProxyArpManager} class.
69 */
70public class ProxyArpManagerTest {
71
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070072 private static final int NUM_DEVICES = 6;
Jonathan Hart704ca142014-10-09 09:34:39 -070073 private static final int NUM_PORTS_PER_DEVICE = 3;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070074 private static final int NUM_ADDRESS_PORTS = NUM_DEVICES / 2;
75 private static final int NUM_FLOOD_PORTS = 3;
Jonathan Hart704ca142014-10-09 09:34:39 -070076
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -070077 private static final IpAddress IP1 = IpAddress.valueOf("192.168.1.1");
78 private static final IpAddress IP2 = IpAddress.valueOf("192.168.1.2");
Jonathan Hart704ca142014-10-09 09:34:39 -070079
80 private static final ProviderId PID = new ProviderId("of", "foo");
81
82 private static final VlanId VLAN1 = VlanId.vlanId((short) 1);
83 private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
84 private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01");
85 private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
86 private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
87 private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
88
89 private static final DeviceId DID1 = getDeviceId(1);
90 private static final DeviceId DID2 = getDeviceId(2);
91 private static final PortNumber P1 = PortNumber.portNumber(1);
92 private static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L);
93 private static final HostLocation LOC2 = new HostLocation(DID2, P1, 123L);
94
95 private ProxyArpManager proxyArp;
96
97 private TestPacketService packetService;
98
99 private DeviceService deviceService;
100 private LinkService linkService;
101 private HostService hostService;
102
103 @Before
104 public void setUp() throws Exception {
105 proxyArp = new ProxyArpManager();
106 packetService = new TestPacketService();
107 proxyArp.packetService = packetService;
108
109 // Create a host service mock here. Must be replayed by tests once the
110 // expectations have been set up
111 hostService = createMock(HostService.class);
112 proxyArp.hostService = hostService;
113
114 createTopology();
115 proxyArp.deviceService = deviceService;
116 proxyArp.linkService = linkService;
117
118 proxyArp.activate();
119 }
120
121 /**
122 * Creates a fake topology to feed into the ARP module.
123 * <p/>
124 * The default topology is a unidirectional ring topology. Each switch has
125 * 3 ports. Ports 2 and 3 have the links to neighbor switches, and port 1
126 * is free (edge port).
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700127 * The first half of the switches have IP addresses configured on their
128 * free ports (port 1). The second half of the switches have no IP
129 * addresses configured.
Jonathan Hart704ca142014-10-09 09:34:39 -0700130 */
131 private void createTopology() {
132 deviceService = createMock(DeviceService.class);
133 linkService = createMock(LinkService.class);
134
135 deviceService.addListener(anyObject(DeviceListener.class));
136 linkService.addListener(anyObject(LinkListener.class));
137
138 createDevices(NUM_DEVICES, NUM_PORTS_PER_DEVICE);
139 createLinks(NUM_DEVICES);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700140 addAddressBindings();
Jonathan Hart704ca142014-10-09 09:34:39 -0700141 }
142
143 /**
144 * Creates the devices for the fake topology.
145 */
146 private void createDevices(int numDevices, int numPorts) {
147 List<Device> devices = new ArrayList<>();
148
149 for (int i = 1; i <= numDevices; i++) {
150 DeviceId devId = getDeviceId(i);
151 Device device = createMock(Device.class);
152 expect(device.id()).andReturn(devId).anyTimes();
153 replay(device);
154
155 devices.add(device);
156
157 List<Port> ports = new ArrayList<>();
158 for (int j = 1; j <= numPorts; j++) {
159 Port port = createMock(Port.class);
160 expect(port.number()).andReturn(PortNumber.portNumber(j)).anyTimes();
161 replay(port);
162 ports.add(port);
163 }
164
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700165 expect(deviceService.getPorts(devId)).andReturn(ports).anyTimes();
166 expect(deviceService.getDevice(devId)).andReturn(device).anyTimes();
Jonathan Hart704ca142014-10-09 09:34:39 -0700167 }
168
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700169 expect(deviceService.getDevices()).andReturn(devices).anyTimes();
Jonathan Hart704ca142014-10-09 09:34:39 -0700170 replay(deviceService);
171 }
172
173 /**
174 * Creates the links for the fake topology.
175 * NB: Only unidirectional links are created, as for this purpose all we
176 * need is to occupy the ports with some link.
177 */
178 private void createLinks(int numDevices) {
179 List<Link> links = new ArrayList<Link>();
180
181 for (int i = 1; i <= numDevices; i++) {
182 ConnectPoint src = new ConnectPoint(
183 getDeviceId(i),
184 PortNumber.portNumber(2));
185 ConnectPoint dst = new ConnectPoint(
186 getDeviceId((i + 1 > numDevices) ? 1 : i + 1),
187 PortNumber.portNumber(3));
188
189 Link link = createMock(Link.class);
190 expect(link.src()).andReturn(src).anyTimes();
191 expect(link.dst()).andReturn(dst).anyTimes();
192 replay(link);
193
194 links.add(link);
195 }
196
197 expect(linkService.getLinks()).andReturn(links).anyTimes();
198 replay(linkService);
199 }
200
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700201 private void addAddressBindings() {
202 Set<PortAddresses> addresses = Sets.newHashSet();
203
204 for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) {
205 ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700206 IpPrefix prefix1 = IpPrefix.valueOf("10.0." + (2 * i - 1) + ".0/24");
207 IpAddress addr1 = IpAddress.valueOf("10.0." + (2 * i - 1) + ".1");
208 IpPrefix prefix2 = IpPrefix.valueOf("10.0." + (2 * i) + ".0/24");
209 IpAddress addr2 = IpAddress.valueOf("10.0." + (2 * i) + ".1");
210 InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
211 InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
212 PortAddresses pa =
213 new PortAddresses(cp, Sets.newHashSet(ia1, ia2),
214 MacAddress.valueOf(i));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700215 addresses.add(pa);
216
217 expect(hostService.getAddressBindingsForPort(cp))
218 .andReturn(pa).anyTimes();
219 }
220
221 expect(hostService.getAddressBindings()).andReturn(addresses).anyTimes();
222
223 for (int i = 1; i <= NUM_FLOOD_PORTS; i++) {
224 ConnectPoint cp = new ConnectPoint(getDeviceId(i + NUM_ADDRESS_PORTS),
225 P1);
226 expect(hostService.getAddressBindingsForPort(cp))
227 .andReturn(new PortAddresses(cp, null, null)).anyTimes();
228 }
229 }
230
Jonathan Hart704ca142014-10-09 09:34:39 -0700231 /**
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700232 * Tests {@link ProxyArpManager#known(IpAddress)} in the case where the
Jonathan Hart704ca142014-10-09 09:34:39 -0700233 * IP address is not known.
234 * Verifies the method returns false.
235 */
236 @Test
237 public void testNotKnown() {
238 expect(hostService.getHostsByIp(IP1)).andReturn(Collections.<Host>emptySet());
239 replay(hostService);
240
241 assertFalse(proxyArp.known(IP1));
242 }
243
244 /**
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700245 * Tests {@link ProxyArpManager#known(IpAddress)} in the case where the
Jonathan Hart704ca142014-10-09 09:34:39 -0700246 * IP address is known.
247 * Verifies the method returns true.
248 */
249 @Test
250 public void testKnown() {
251 Host host1 = createMock(Host.class);
252 Host host2 = createMock(Host.class);
253
254 expect(hostService.getHostsByIp(IP1))
255 .andReturn(Sets.newHashSet(host1, host2));
256 replay(hostService);
257
258 assertTrue(proxyArp.known(IP1));
259 }
260
261 /**
262 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
263 * destination host is known.
264 * Verifies the correct ARP reply is sent out the correct port.
265 */
266 @Test
267 public void testReplyKnown() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700268 Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(4),
Jonathan Hart704ca142014-10-09 09:34:39 -0700269 Collections.singleton(IP1));
270
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700271 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700272 Collections.singleton(IP2));
273
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700274 expect(hostService.getHostsByIp(IP1))
275 .andReturn(Collections.singleton(replyer));
Jonathan Hart704ca142014-10-09 09:34:39 -0700276 expect(hostService.getHost(HID2)).andReturn(requestor);
277
278 replay(hostService);
279
280 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
281
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700282 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700283
284 assertEquals(1, packetService.packets.size());
285 Ethernet arpReply = buildArp(ARP.OP_REPLY, MAC1, MAC2, IP1, IP2);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700286 verifyPacketOut(arpReply, getLocation(5), packetService.packets.get(0));
Jonathan Hart704ca142014-10-09 09:34:39 -0700287 }
288
289 /**
290 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
291 * destination host is not known.
292 * Verifies the ARP request is flooded out the correct edge ports.
293 */
294 @Test
295 public void testReplyUnknown() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700296 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700297 Collections.singleton(IP2));
298
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700299 expect(hostService.getHostsByIp(IP1))
Jonathan Hart704ca142014-10-09 09:34:39 -0700300 .andReturn(Collections.<Host>emptySet());
301 expect(hostService.getHost(HID2)).andReturn(requestor);
302
303 replay(hostService);
304
305 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
306
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700307 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700308
309 verifyFlood(arpRequest);
310 }
311
312 /**
313 * Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
314 * destination host is known for that IP address, but is not on the same
315 * VLAN as the source host.
316 * Verifies the ARP request is flooded out the correct edge ports.
317 */
318 @Test
319 public void testReplyDifferentVlan() {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700320 Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN2, getLocation(4),
Jonathan Hart704ca142014-10-09 09:34:39 -0700321 Collections.singleton(IP1));
322
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700323 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
Jonathan Hart704ca142014-10-09 09:34:39 -0700324 Collections.singleton(IP2));
325
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700326 expect(hostService.getHostsByIp(IP1))
Jonathan Hart704ca142014-10-09 09:34:39 -0700327 .andReturn(Collections.singleton(replyer));
328 expect(hostService.getHost(HID2)).andReturn(requestor);
329
330 replay(hostService);
331
332 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
333
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700334 proxyArp.reply(arpRequest, getLocation(5));
Jonathan Hart704ca142014-10-09 09:34:39 -0700335
336 verifyFlood(arpRequest);
337 }
338
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700339 @Test
340 public void testReplyToRequestForUs() {
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700341 IpAddress theirIp = IpAddress.valueOf("10.0.1.254");
342 IpAddress ourFirstIp = IpAddress.valueOf("10.0.1.1");
343 IpAddress ourSecondIp = IpAddress.valueOf("10.0.2.1");
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700344 MacAddress ourMac = MacAddress.valueOf(1L);
345
346 Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
347 Collections.singleton(theirIp));
348
349 expect(hostService.getHost(HID2)).andReturn(requestor);
350 replay(hostService);
351
352 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourFirstIp);
353
354 proxyArp.reply(arpRequest, LOC1);
355
356 assertEquals(1, packetService.packets.size());
357 Ethernet arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourFirstIp, theirIp);
358 verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
359
360 // Test a request for the second address on that port
361 packetService.packets.clear();
362 arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourSecondIp);
363
364 proxyArp.reply(arpRequest, LOC1);
365
366 assertEquals(1, packetService.packets.size());
367 arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourSecondIp, theirIp);
368 verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
369 }
370
371 @Test
372 public void testReplyExternalPortBadRequest() {
373 replay(hostService); // no further host service expectations
374
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700375 IpAddress theirIp = IpAddress.valueOf("10.0.1.254");
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700376
377 // Request for a valid external IP address but coming in the wrong port
378 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp,
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700379 IpAddress.valueOf("10.0.3.1"));
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700380 proxyArp.reply(arpRequest, LOC1);
381 assertEquals(0, packetService.packets.size());
382
383 // Request for a valid internal IP address but coming in an external port
384 packetService.packets.clear();
385 arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp, IP1);
386 proxyArp.reply(arpRequest, LOC1);
387 assertEquals(0, packetService.packets.size());
388 }
389
390 @Test
391 public void testReplyToRequestFromUs() {
392 replay(hostService); // no further host service expectations
393
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700394 IpAddress ourIp = IpAddress.valueOf("10.0.1.1");
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700395 MacAddress ourMac = MacAddress.valueOf(1L);
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700396 IpAddress theirIp = IpAddress.valueOf("10.0.1.100");
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700397
398 // This is a request from something inside our network (like a BGP
399 // daemon) to an external host.
400 Ethernet arpRequest = buildArp(ARP.OP_REQUEST, ourMac, null, ourIp, theirIp);
401 proxyArp.reply(arpRequest, getLocation(5));
402
403 assertEquals(1, packetService.packets.size());
404 verifyPacketOut(arpRequest, getLocation(1), packetService.packets.get(0));
405
406 // The same request from a random external port should fail
407 packetService.packets.clear();
408 proxyArp.reply(arpRequest, getLocation(2));
409 assertEquals(0, packetService.packets.size());
410 }
411
Jonathan Hart704ca142014-10-09 09:34:39 -0700412 /**
413 * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
414 * destination host is known.
415 * Verifies the correct ARP request is sent out the correct port.
416 */
417 @Test
418 public void testForwardToHost() {
419 Host host1 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1,
420 Collections.singleton(IP1));
421
422 expect(hostService.getHost(HID1)).andReturn(host1);
423 replay(hostService);
424
425 Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
426
427 proxyArp.forward(arpRequest);
428
429 assertEquals(1, packetService.packets.size());
430 OutboundPacket packet = packetService.packets.get(0);
431
432 verifyPacketOut(arpRequest, LOC1, packet);
433 }
434
435 /**
436 * Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
437 * destination host is not known.
438 * Verifies the correct ARP request is flooded out the correct edge ports.
439 */
440 @Test
441 public void testForwardFlood() {
442 expect(hostService.getHost(HID1)).andReturn(null);
443 replay(hostService);
444
445 Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
446
447 proxyArp.forward(arpRequest);
448
449 verifyFlood(arpRequest);
450 }
451
452 /**
453 * Verifies that the given packet was flooded out all available edge ports.
454 *
455 * @param packet the packet that was expected to be flooded
456 */
457 private void verifyFlood(Ethernet packet) {
458 assertEquals(NUM_FLOOD_PORTS, packetService.packets.size());
459
460 Collections.sort(packetService.packets,
461 new Comparator<OutboundPacket>() {
462 @Override
463 public int compare(OutboundPacket o1, OutboundPacket o2) {
464 return o1.sendThrough().uri().compareTo(o2.sendThrough().uri());
465 }
466 });
467
468 for (int i = 0; i < NUM_FLOOD_PORTS; i++) {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700469 ConnectPoint cp = new ConnectPoint(getDeviceId(NUM_ADDRESS_PORTS + i + 1),
470 PortNumber.portNumber(1));
Jonathan Hart704ca142014-10-09 09:34:39 -0700471
472 OutboundPacket outboundPacket = packetService.packets.get(i);
473 verifyPacketOut(packet, cp, outboundPacket);
474 }
475 }
476
477 /**
478 * Verifies the given packet was sent out the given port.
479 *
480 * @param expected the packet that was expected to be sent
481 * @param outPort the port the packet was expected to be sent out
482 * @param actual the actual OutboundPacket to verify
483 */
484 private void verifyPacketOut(Ethernet expected, ConnectPoint outPort,
485 OutboundPacket actual) {
486 assertTrue(Arrays.equals(expected.serialize(), actual.data().array()));
487 assertEquals(1, actual.treatment().instructions().size());
488 assertEquals(outPort.deviceId(), actual.sendThrough());
489 Instruction instruction = actual.treatment().instructions().get(0);
490 assertTrue(instruction instanceof OutputInstruction);
491 assertEquals(outPort.port(), ((OutputInstruction) instruction).port());
492 }
493
494 /**
495 * Returns the device ID of the ith device.
496 *
497 * @param i device to get the ID of
498 * @return the device ID
499 */
500 private static DeviceId getDeviceId(int i) {
501 return DeviceId.deviceId("" + i);
502 }
503
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700504 private static HostLocation getLocation(int i) {
505 return new HostLocation(new ConnectPoint(getDeviceId(i), P1), 123L);
506 }
507
Jonathan Hart704ca142014-10-09 09:34:39 -0700508 /**
509 * Builds an ARP packet with the given parameters.
510 *
511 * @param opcode opcode of the ARP packet
512 * @param srcMac source MAC address
513 * @param dstMac destination MAC address, or null if this is a request
514 * @param srcIp source IP address
515 * @param dstIp destination IP address
516 * @return the ARP packet
517 */
518 private Ethernet buildArp(short opcode, MacAddress srcMac, MacAddress dstMac,
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700519 IpAddress srcIp, IpAddress dstIp) {
Jonathan Hart704ca142014-10-09 09:34:39 -0700520 Ethernet eth = new Ethernet();
521
522 if (dstMac == null) {
523 eth.setDestinationMACAddress(MacAddress.BROADCAST_MAC);
524 } else {
525 eth.setDestinationMACAddress(dstMac.getAddress());
526 }
527
528 eth.setSourceMACAddress(srcMac.getAddress());
529 eth.setEtherType(Ethernet.TYPE_ARP);
530 eth.setVlanID(VLAN1.toShort());
531
532 ARP arp = new ARP();
533 arp.setOpCode(opcode);
534 arp.setProtocolType(ARP.PROTO_TYPE_IP);
535 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
536
537 arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN);
538 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
539 arp.setSenderHardwareAddress(srcMac.getAddress());
540
541 if (dstMac == null) {
542 arp.setTargetHardwareAddress(MacAddress.ZERO_MAC_ADDRESS);
543 } else {
544 arp.setTargetHardwareAddress(dstMac.getAddress());
545 }
546
547 arp.setSenderProtocolAddress(srcIp.toOctets());
548 arp.setTargetProtocolAddress(dstIp.toOctets());
549
550 eth.setPayload(arp);
551 return eth;
552 }
553
554 /**
555 * Test PacketService implementation that simply stores OutboundPackets
556 * passed to {@link #emit(OutboundPacket)} for later verification.
557 */
558 class TestPacketService implements PacketService {
559
560 List<OutboundPacket> packets = new ArrayList<>();
561
562 @Override
563 public void addProcessor(PacketProcessor processor, int priority) {
564 }
565
566 @Override
567 public void removeProcessor(PacketProcessor processor) {
568 }
569
570 @Override
571 public void emit(OutboundPacket packet) {
572 packets.add(packet);
573 }
574 }
575}