blob: 7cd566f007bcf54877d171cff87fcd338b1a50d0 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.provider.host.impl;
alshabib4a179dc2014-10-17 17:17:01 -070017
Yi Tseng7a38f9a2017-06-09 14:36:40 -070018import com.google.common.collect.ImmutableList;
Thomas Vachuska27bee092015-06-23 19:03:10 -070019import com.google.common.collect.ImmutableSet;
Charles Chan420e7372016-11-17 10:58:17 -080020import com.google.common.collect.Lists;
Madan Jampania3770c32015-12-11 12:07:41 -080021import com.google.common.util.concurrent.MoreExecutors;
alshabib4a179dc2014-10-17 17:17:01 -070022import org.junit.After;
23import org.junit.Before;
24import org.junit.Test;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070025import org.onlab.junit.TestUtils;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080026import org.onlab.osgi.ComponentContextAdapter;
27import org.onlab.packet.ARP;
28import org.onlab.packet.ChassisId;
Charles Chane6067892016-11-17 10:23:46 -080029import org.onlab.packet.DHCP;
Yi Tsengfcf5dce2017-07-26 14:30:41 -070030import org.onlab.packet.DHCP6;
31import org.onlab.packet.dhcp.Dhcp6ClientIdOption;
32import org.onlab.packet.dhcp.Dhcp6Duid;
33import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
34import org.onlab.packet.dhcp.Dhcp6IaNaOption;
35import org.onlab.packet.dhcp.Dhcp6Option;
Yi Tsengc7403c22017-06-19 16:23:22 -070036import org.onlab.packet.dhcp.DhcpOption;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080037import org.onlab.packet.Ethernet;
Charles Chan5d5e0622015-09-25 13:00:06 -070038import org.onlab.packet.ICMP6;
39import org.onlab.packet.IPv4;
40import org.onlab.packet.IPv6;
41import org.onlab.packet.Ip6Address;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080042import org.onlab.packet.IpAddress;
43import org.onlab.packet.MacAddress;
Charles Chane6067892016-11-17 10:23:46 -080044import org.onlab.packet.UDP;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080045import org.onlab.packet.VlanId;
Charles Chan5d5e0622015-09-25 13:00:06 -070046import org.onlab.packet.ndp.NeighborAdvertisement;
47import org.onlab.packet.ndp.NeighborSolicitation;
48import org.onlab.packet.ndp.RouterAdvertisement;
49import org.onlab.packet.ndp.RouterSolicitation;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070050import org.onosproject.cfg.ComponentConfigAdapter;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080051import org.onosproject.core.ApplicationId;
52import org.onosproject.core.CoreService;
53import org.onosproject.core.DefaultApplicationId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070054import org.onosproject.incubator.net.intf.Interface;
55import org.onosproject.incubator.net.intf.InterfaceListener;
56import org.onosproject.incubator.net.intf.InterfaceService;
Brian O'Connorabafb502014-12-02 22:26:20 -080057import org.onosproject.net.ConnectPoint;
58import org.onosproject.net.DefaultDevice;
59import org.onosproject.net.DefaultHost;
60import org.onosproject.net.DefaultPort;
61import org.onosproject.net.Device;
62import org.onosproject.net.DeviceId;
63import org.onosproject.net.Host;
64import org.onosproject.net.HostId;
65import org.onosproject.net.HostLocation;
66import org.onosproject.net.device.DeviceEvent;
67import org.onosproject.net.device.DeviceListener;
68import org.onosproject.net.device.DeviceServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080069import org.onosproject.net.host.HostDescription;
70import org.onosproject.net.host.HostProvider;
71import org.onosproject.net.host.HostProviderRegistry;
72import org.onosproject.net.host.HostProviderService;
73import org.onosproject.net.host.HostServiceAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070074import org.onosproject.net.host.InterfaceIpAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080075import org.onosproject.net.packet.DefaultInboundPacket;
76import org.onosproject.net.packet.InboundPacket;
Andrey Komarov2398d962016-09-26 15:11:23 +030077import org.onosproject.net.packet.PacketContextAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080078import org.onosproject.net.packet.PacketProcessor;
Thomas Vachuska27bee092015-06-23 19:03:10 -070079import org.onosproject.net.packet.PacketServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080080import org.onosproject.net.provider.AbstractProviderService;
81import org.onosproject.net.provider.ProviderId;
82import org.onosproject.net.topology.Topology;
83import org.onosproject.net.topology.TopologyServiceAdapter;
alshabib4a179dc2014-10-17 17:17:01 -070084
Thomas Vachuska27bee092015-06-23 19:03:10 -070085import java.nio.ByteBuffer;
86import java.util.Collections;
87import java.util.Dictionary;
88import java.util.Hashtable;
Charles Chan420e7372016-11-17 10:58:17 -080089import java.util.List;
Thomas Vachuska27bee092015-06-23 19:03:10 -070090import java.util.Set;
91
Michele Santuari72f6bee2016-11-18 12:56:30 +010092import static org.easymock.EasyMock.createMock;
93import static org.easymock.EasyMock.expect;
94import static org.easymock.EasyMock.replay;
Charles Chan5d5e0622015-09-25 13:00:06 -070095import static org.hamcrest.Matchers.is;
Michele Santuari72f6bee2016-11-18 12:56:30 +010096import static org.junit.Assert.assertEquals;
97import static org.junit.Assert.assertNotEquals;
98import static org.junit.Assert.assertNotNull;
99import static org.junit.Assert.assertThat;
Thomas Vachuska27bee092015-06-23 19:03:10 -0700100import static org.onlab.packet.VlanId.vlanId;
101import static org.onosproject.net.Device.Type.SWITCH;
102import static org.onosproject.net.DeviceId.deviceId;
103import static org.onosproject.net.HostId.hostId;
104import static org.onosproject.net.PortNumber.portNumber;
Michele Santuari72f6bee2016-11-18 12:56:30 +0100105import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
106import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
107import static org.onosproject.net.device.DeviceEvent.Type.PORT_UPDATED;
Thomas Vachuska33601602014-11-19 03:32:15 -0800108
alshabib4a179dc2014-10-17 17:17:01 -0700109public class HostLocationProviderTest {
Charles Chan8b0fdaa2016-02-23 18:35:27 -0800110 private static final ProviderId PROVIDER_ID =
111 new ProviderId("of", "org.onosproject.provider.host");
112
alshabib4a179dc2014-10-17 17:17:01 -0700113 private static final Integer INPORT = 10;
Charles Chane6067892016-11-17 10:23:46 -0800114 private static final Integer INPORT2 = 11;
alshabib4a179dc2014-10-17 17:17:01 -0700115 private static final String DEV1 = "of:1";
116 private static final String DEV2 = "of:2";
117 private static final String DEV3 = "of:3";
Charles Chan5d5e0622015-09-25 13:00:06 -0700118 private static final String DEV4 = "of:4";
119 private static final String DEV5 = "of:5";
120 private static final String DEV6 = "of:6";
alshabib4a179dc2014-10-17 17:17:01 -0700121
Thomas Vachuska33601602014-11-19 03:32:15 -0800122 private static final VlanId VLAN = vlanId();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700123 private static final VlanId VLAN_100 = VlanId.vlanId("100");
Charles Chan5d5e0622015-09-25 13:00:06 -0700124
125 // IPv4 Host
alshabib4a179dc2014-10-17 17:17:01 -0700126 private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01");
127 private static final MacAddress BCMAC = MacAddress.valueOf("ff:ff:ff:ff:ff:ff");
128 private static final byte[] IP = new byte[]{10, 0, 0, 1};
Thomas Vachuska33601602014-11-19 03:32:15 -0800129 private static final IpAddress IP_ADDRESS =
130 IpAddress.valueOf(IpAddress.Version.INET, IP);
131 private static final HostLocation LOCATION =
132 new HostLocation(deviceId(DEV1), portNumber(INPORT), 0L);
Thomas Vachuska33601602014-11-19 03:32:15 -0800133 private static final DefaultHost HOST =
Charles Chan8b0fdaa2016-02-23 18:35:27 -0800134 new DefaultHost(PROVIDER_ID, hostId(MAC), MAC,
Charles Chane6067892016-11-17 10:23:46 -0800135 VLAN, LOCATION,
136 ImmutableSet.of(IP_ADDRESS));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700137 private static final DefaultHost HOST_VLAN_100 =
138 new DefaultHost(PROVIDER_ID, hostId(MAC, VLAN_100), MAC,
139 VLAN_100, LOCATION,
140 ImmutableSet.of(IP_ADDRESS));
Thomas Vachuska33601602014-11-19 03:32:15 -0800141
Charles Chan5d5e0622015-09-25 13:00:06 -0700142 // IPv6 Host
143 private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
144 private static final MacAddress BCMAC2 = MacAddress.valueOf("33:33:00:00:00:01");
145 private static final byte[] IP2 = Ip6Address.valueOf("1000::1").toOctets();
146 private static final IpAddress IP_ADDRESS2 =
147 IpAddress.valueOf(IpAddress.Version.INET6, IP2);
148 private static final HostLocation LOCATION2 =
149 new HostLocation(deviceId(DEV4), portNumber(INPORT), 0L);
150 private static final DefaultHost HOST2 =
Charles Chan8b0fdaa2016-02-23 18:35:27 -0800151 new DefaultHost(PROVIDER_ID, hostId(MAC2), MAC2,
Charles Chane6067892016-11-17 10:23:46 -0800152 VLAN, LOCATION2,
153 ImmutableSet.of(IP_ADDRESS2));
154
155 // DHCP Server
156 private static final MacAddress MAC3 = MacAddress.valueOf("00:00:33:00:00:03");
157 private static final byte[] IP3 = new byte[]{10, 0, 0, 2};
158 private static final IpAddress IP_ADDRESS3 =
159 IpAddress.valueOf(IpAddress.Version.INET, IP3);
Charles Chane6067892016-11-17 10:23:46 -0800160 private static final HostLocation LOCATION3 =
161 new HostLocation(deviceId(DEV1), portNumber(INPORT2), 0L);
162 private static final DefaultHost HOST3 =
163 new DefaultHost(PROVIDER_ID, hostId(MAC3), MAC3,
164 VLAN, LOCATION3,
165 ImmutableSet.of(IP_ADDRESS3));
Charles Chan5d5e0622015-09-25 13:00:06 -0700166
Yi Tsengfcf5dce2017-07-26 14:30:41 -0700167 // DHCP6 Server
168 private static final MacAddress DHCP6_SERVER_MAC = MacAddress.valueOf("00:00:44:00:00:04");
169 private static final IpAddress DHCP6_SERVER_IP =
170 IpAddress.valueOf("2000::1:1000");
171
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700172 // Gateway information for relay agent
173 private static final InterfaceIpAddress GW_IFACE_ADDR = InterfaceIpAddress.valueOf("10.0.1.1/32");
174 private static final Interface GW_IFACE = new Interface("gateway",
175 LOCATION,
176 ImmutableList.of(GW_IFACE_ADDR),
177 null,
178 VLAN_100);
179
Thomas Vachuska33601602014-11-19 03:32:15 -0800180 private static final ComponentContextAdapter CTX_FOR_REMOVE =
181 new ComponentContextAdapter() {
182 @Override
183 public Dictionary getProperties() {
184 Hashtable<String, String> props = new Hashtable<>();
185 props.put("hostRemovalEnabled", "true");
186 return props;
187 }
188 };
189
190 public static final ComponentContextAdapter CTX_FOR_NO_REMOVE =
191 new ComponentContextAdapter() {
192 @Override
193 public Dictionary getProperties() {
194 return new Hashtable();
195 }
196 };
197
alshabib4a179dc2014-10-17 17:17:01 -0700198 private final HostLocationProvider provider = new HostLocationProvider();
Thomas Vachuska33601602014-11-19 03:32:15 -0800199 private final TestHostRegistry hostRegistry = new TestHostRegistry();
alshabib4a179dc2014-10-17 17:17:01 -0700200 private final TestTopologyService topoService = new TestTopologyService();
Thomas Vachuska33601602014-11-19 03:32:15 -0800201 private final TestDeviceService deviceService = new TestDeviceService();
202 private final TestHostService hostService = new TestHostService();
alshabib4a179dc2014-10-17 17:17:01 -0700203 private final TestPacketService packetService = new TestPacketService();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700204 private final TestInterfaceService interfaceService = new TestInterfaceService();
alshabib4a179dc2014-10-17 17:17:01 -0700205
206 private PacketProcessor testProcessor;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800207 private CoreService coreService;
alshabib4a179dc2014-10-17 17:17:01 -0700208 private TestHostProviderService providerService;
209
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800210 private ApplicationId appId =
211 new DefaultApplicationId(100, "org.onosproject.provider.host");
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800212
alshabib4a179dc2014-10-17 17:17:01 -0700213 @Before
214 public void setUp() {
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800215 coreService = createMock(CoreService.class);
216 expect(coreService.registerApplication(appId.name()))
Thomas Vachuska27bee092015-06-23 19:03:10 -0700217 .andReturn(appId).anyTimes();
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800218 replay(coreService);
219
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700220 provider.cfgService = new ComponentConfigAdapter();
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800221 provider.coreService = coreService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800222
Thomas Vachuska33601602014-11-19 03:32:15 -0800223 provider.providerRegistry = hostRegistry;
alshabib4a179dc2014-10-17 17:17:01 -0700224 provider.topologyService = topoService;
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800225 provider.packetService = packetService;
Thomas Vachuska33601602014-11-19 03:32:15 -0800226 provider.deviceService = deviceService;
227 provider.hostService = hostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700228 provider.interfaceService = interfaceService;
alshabib4a179dc2014-10-17 17:17:01 -0700229
Thomas Vachuska33601602014-11-19 03:32:15 -0800230 provider.activate(CTX_FOR_NO_REMOVE);
Madan Jampania3770c32015-12-11 12:07:41 -0800231
232 provider.eventHandler = MoreExecutors.newDirectExecutorService();
alshabib4a179dc2014-10-17 17:17:01 -0700233 }
234
235 @Test
236 public void basics() {
237 assertNotNull("registration expected", providerService);
238 assertEquals("incorrect provider", provider, providerService.provider());
239 }
240
241 @Test
242 public void events() {
Charles Chan420e7372016-11-17 10:58:17 -0800243 // New host. Expect one additional host description.
Charles Chan5d5e0622015-09-25 13:00:06 -0700244 testProcessor.process(new TestArpPacketContext(DEV1));
Charles Chan420e7372016-11-17 10:58:17 -0800245 assertThat("New host expected", providerService.descriptions.size(), is(1));
alshabib4a179dc2014-10-17 17:17:01 -0700246
Charles Chan420e7372016-11-17 10:58:17 -0800247 // The host moved to new switch. Expect one additional host description.
248 // The second host description should have a different location.
Charles Chan5d5e0622015-09-25 13:00:06 -0700249 testProcessor.process(new TestArpPacketContext(DEV2));
Charles Chan420e7372016-11-17 10:58:17 -0800250 assertThat("Host motion expected", providerService.descriptions.size(), is(2));
251 HostLocation loc1 = providerService.descriptions.get(0).location();
252 HostLocation loc2 = providerService.descriptions.get(1).location();
253 assertNotEquals("Host location should be different", loc1, loc2);
alshabib4a179dc2014-10-17 17:17:01 -0700254
Charles Chan420e7372016-11-17 10:58:17 -0800255 // The host was misheard on a spine. Expect no additional host description.
Charles Chan5d5e0622015-09-25 13:00:06 -0700256 testProcessor.process(new TestArpPacketContext(DEV3));
Charles Chan420e7372016-11-17 10:58:17 -0800257 assertThat("Host misheard on spine switch", providerService.descriptions.size(), is(2));
Charles Chan5d5e0622015-09-25 13:00:06 -0700258
259 providerService.clear();
260
Charles Chan420e7372016-11-17 10:58:17 -0800261 // New host. Expect one additional host description.
Jonathan Hartb35540a2015-11-17 09:30:56 -0800262 testProcessor.process(new TestNaPacketContext(DEV4));
Charles Chan420e7372016-11-17 10:58:17 -0800263 assertThat("New host expected", providerService.descriptions.size(), is(1));
Charles Chan5d5e0622015-09-25 13:00:06 -0700264
Charles Chan420e7372016-11-17 10:58:17 -0800265 // The host moved to new switch. Expect one additional host description.
266 // The second host description should have a different location.
Jonathan Hartb35540a2015-11-17 09:30:56 -0800267 testProcessor.process(new TestNaPacketContext(DEV5));
Charles Chan420e7372016-11-17 10:58:17 -0800268 assertThat("Host motion expected", providerService.descriptions.size(), is(2));
269 loc1 = providerService.descriptions.get(0).location();
270 loc2 = providerService.descriptions.get(1).location();
271 assertNotEquals("Host location should be different", loc1, loc2);
Charles Chan5d5e0622015-09-25 13:00:06 -0700272
Charles Chan420e7372016-11-17 10:58:17 -0800273 // The host was misheard on a spine. Expect no additional host description.
Jonathan Hartb35540a2015-11-17 09:30:56 -0800274 testProcessor.process(new TestNaPacketContext(DEV6));
Charles Chan420e7372016-11-17 10:58:17 -0800275 assertThat("Host misheard on spine switch", providerService.descriptions.size(), is(2));
alshabib4a179dc2014-10-17 17:17:01 -0700276 }
277
Thomas Vachuska33601602014-11-19 03:32:15 -0800278 @Test
279 public void removeHostByDeviceRemove() {
280 provider.modified(CTX_FOR_REMOVE);
Charles Chan5d5e0622015-09-25 13:00:06 -0700281 testProcessor.process(new TestArpPacketContext(DEV1));
Jonathan Hartb35540a2015-11-17 09:30:56 -0800282 testProcessor.process(new TestNaPacketContext(DEV4));
Charles Chan5d5e0622015-09-25 13:00:06 -0700283
Thomas Vachuska33601602014-11-19 03:32:15 -0800284 Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH,
285 "m", "h", "s", "n", new ChassisId(0L));
286 deviceService.listener.event(new DeviceEvent(DEVICE_REMOVED, device));
Charles Chan888e20a2017-05-01 15:44:23 -0700287 assertEquals("incorrect remove count", 2, providerService.locationRemoveCount);
Charles Chan5d5e0622015-09-25 13:00:06 -0700288
289 device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH,
290 "m", "h", "s", "n", new ChassisId(0L));
291 deviceService.listener.event(new DeviceEvent(DEVICE_REMOVED, device));
Charles Chan888e20a2017-05-01 15:44:23 -0700292 assertEquals("incorrect remove count", 3, providerService.locationRemoveCount);
Thomas Vachuska33601602014-11-19 03:32:15 -0800293 }
294
295 @Test
296 public void removeHostByDeviceOffline() {
297 provider.modified(CTX_FOR_REMOVE);
Charles Chan5d5e0622015-09-25 13:00:06 -0700298 testProcessor.process(new TestArpPacketContext(DEV1));
299 testProcessor.process(new TestArpPacketContext(DEV4));
300
Thomas Vachuska33601602014-11-19 03:32:15 -0800301 Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH,
302 "m", "h", "s", "n", new ChassisId(0L));
303 deviceService.listener.event(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device));
Charles Chan888e20a2017-05-01 15:44:23 -0700304 assertEquals("incorrect remove count", 2, providerService.locationRemoveCount);
Charles Chan5d5e0622015-09-25 13:00:06 -0700305
306 device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH,
307 "m", "h", "s", "n", new ChassisId(0L));
308 deviceService.listener.event(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device));
Charles Chan888e20a2017-05-01 15:44:23 -0700309 assertEquals("incorrect remove count", 3, providerService.locationRemoveCount);
Thomas Vachuska33601602014-11-19 03:32:15 -0800310 }
311
312 @Test
313 public void removeHostByDevicePortDown() {
314 provider.modified(CTX_FOR_REMOVE);
Charles Chan5d5e0622015-09-25 13:00:06 -0700315 testProcessor.process(new TestArpPacketContext(DEV1));
316 testProcessor.process(new TestArpPacketContext(DEV4));
317
Thomas Vachuska33601602014-11-19 03:32:15 -0800318 Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH,
319 "m", "h", "s", "n", new ChassisId(0L));
320 deviceService.listener.event(new DeviceEvent(PORT_UPDATED, device,
Charles Chan5d5e0622015-09-25 13:00:06 -0700321 new DefaultPort(device, portNumber(INPORT), false)));
Charles Chan888e20a2017-05-01 15:44:23 -0700322 assertEquals("incorrect remove count", 1, providerService.locationRemoveCount);
Charles Chan5d5e0622015-09-25 13:00:06 -0700323
324 device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH,
325 "m", "h", "s", "n", new ChassisId(0L));
326 deviceService.listener.event(new DeviceEvent(PORT_UPDATED, device,
327 new DefaultPort(device, portNumber(INPORT), false)));
Charles Chan888e20a2017-05-01 15:44:23 -0700328 assertEquals("incorrect remove count", 2, providerService.locationRemoveCount);
Thomas Vachuska33601602014-11-19 03:32:15 -0800329 }
330
Charles Chan5d5e0622015-09-25 13:00:06 -0700331 /**
332 * When receiving ARP, updates location and IP.
333 */
334 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300335 public void receiveArp() {
Charles Chan5d5e0622015-09-25 13:00:06 -0700336 testProcessor.process(new TestArpPacketContext(DEV1));
Andrey Komarov2398d962016-09-26 15:11:23 +0300337 assertThat("receiveArp. One host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800338 providerService.descriptions.size(), is(1));
339 HostDescription descr = providerService.descriptions.get(0);
Charles Chan5d5e0622015-09-25 13:00:06 -0700340 assertThat(descr.location(), is(LOCATION));
341 assertThat(descr.hwAddress(), is(MAC));
342 assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS));
343 assertThat(descr.vlan(), is(VLAN));
344 }
345
346 /**
347 * When receiving IPv4, updates location only.
348 */
349 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300350 public void receiveIpv4() {
Charles Chan5d5e0622015-09-25 13:00:06 -0700351 testProcessor.process(new TestIpv4PacketContext(DEV1));
Andrey Komarov2398d962016-09-26 15:11:23 +0300352 assertThat("receiveIpv4. One host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800353 providerService.descriptions.size(), is(1));
354 HostDescription descr = providerService.descriptions.get(0);
Charles Chan5d5e0622015-09-25 13:00:06 -0700355 assertThat(descr.location(), is(LOCATION));
356 assertThat(descr.hwAddress(), is(MAC));
357 assertThat(descr.ipAddress().size(), is(0));
358 assertThat(descr.vlan(), is(VLAN));
359 }
360
361 /**
Charles Chane6067892016-11-17 10:23:46 -0800362 * When receiving DHCP REQUEST, update MAC, location of client.
363 * When receiving DHCP ACK, update MAC, location of server and IP of client.
364 */
365 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300366 public void receiveDhcp() {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700367 TestUtils.setField(provider, "useDhcp", true);
Charles Chane6067892016-11-17 10:23:46 -0800368 // DHCP Request
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700369 testProcessor.process(new TestDhcpRequestPacketContext(DEV1, VLAN));
Andrey Komarov2398d962016-09-26 15:11:23 +0300370 assertThat("receiveDhcpRequest. One host description expected",
Charles Chane6067892016-11-17 10:23:46 -0800371 providerService.descriptions.size(), is(1));
372 // Should learn the MAC and location of DHCP client
373 HostDescription descr = providerService.descriptions.get(0);
374 assertThat(descr.location(), is(LOCATION));
375 assertThat(descr.hwAddress(), is(MAC));
376 assertThat(descr.ipAddress().size(), is(0));
377 assertThat(descr.vlan(), is(VLAN));
378
379 // DHCP Ack
Yi Tsengfcf5dce2017-07-26 14:30:41 -0700380 testProcessor.process(new TestDhcpAckPacketContext(DEV1));
Andrey Komarov2398d962016-09-26 15:11:23 +0300381 assertThat("receiveDhcpAck. Two additional host descriptions expected",
Yi Tsengcfa637a2017-07-26 17:24:10 -0700382 providerService.descriptions.size(), is(3));
Charles Chane6067892016-11-17 10:23:46 -0800383
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700384 // Should also learn the MAC, location of DHCP server
385 HostDescription descr2 = providerService.descriptions.get(1);
386 assertThat(descr2.location(), is(LOCATION3));
387 assertThat(descr2.hwAddress(), is(MAC3));
388 assertThat(descr2.ipAddress().size(), is(0));
389 assertThat(descr2.vlan(), is(VLAN));
390
Yi Tsengcfa637a2017-07-26 17:24:10 -0700391 // Should update the IP address of the client.
392 HostDescription descr3 = providerService.descriptions.get(2);
393 assertThat(descr3.location(), is(LOCATION));
394 assertThat(descr3.hwAddress(), is(MAC));
395 assertThat(descr3.ipAddress().size(), is(1));
396 IpAddress ip = descr3.ipAddress().iterator().next();
397 assertThat(ip, is(IP_ADDRESS.getIp4Address()));
398 assertThat(descr3.vlan(), is(VLAN));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700399 }
400
401 /**
Yi Tsengfcf5dce2017-07-26 14:30:41 -0700402 * When receiving DHCPv6 REQUEST, update MAC, location of client.
403 * When receiving DHCPv6 ACK, update MAC, location of server and IP of client.
404 */
405 @Test
406 public void receiveDhcp6() {
407 TestUtils.setField(provider, "useDhcp6", true);
408 // DHCP Request
409 testProcessor.process(new TestDhcp6RequestPacketContext(DEV4, VLAN));
410 assertThat("receiveDhcpRequest. One host description expected",
411 providerService.descriptions.size(), is(1));
412 // Should learn the MAC and location of DHCP client
413 HostDescription descr = providerService.descriptions.get(0);
414 assertThat(descr.location(), is(LOCATION2));
415 assertThat(descr.hwAddress(), is(MAC2));
416 assertThat(descr.ipAddress().size(), is(0));
417 assertThat(descr.vlan(), is(VLAN));
418
419 // DHCP Ack
420 testProcessor.process(new TestDhcp6AckPacketContext(DEV1));
421 assertThat("receiveDhcpAck. Two additional host descriptions expected",
422 providerService.descriptions.size(), is(3));
423
424 // Should also learn the MAC, location of DHCP server
425 HostDescription descr2 = providerService.descriptions.get(1);
426 assertThat(descr2.location(), is(LOCATION3));
427 assertThat(descr2.hwAddress(), is(DHCP6_SERVER_MAC));
428 assertThat(descr2.ipAddress().size(), is(0));
429 assertThat(descr2.vlan(), is(VLAN));
430
431 // Should update the IP address of the DHCP client.
432 HostDescription descr3 = providerService.descriptions.get(2);
433 assertThat(descr3.location(), is(LOCATION2));
434 assertThat(descr3.hwAddress(), is(MAC2));
435 assertThat(descr3.ipAddress().size(), is(1));
436 IpAddress ip = descr3.ipAddress().iterator().next();
437 assertThat(ip, is(IP_ADDRESS2.getIp6Address()));
438 assertThat(descr3.vlan(), is(VLAN));
439 }
440
441 /**
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700442 * The host store should not updated when we disabled "useDhcp".
443 */
444 @Test
445 public void receiveDhcpButNotEnabled() {
446 TestUtils.setField(provider, "useDhcp", false);
447 // DHCP Request
448 testProcessor.process(new TestDhcpRequestPacketContext(DEV1, VLAN));
449 assertThat("receiveDhcpButNotEnabled. No host description expected",
450 providerService.descriptions.size(), is(0));
Charles Chane6067892016-11-17 10:23:46 -0800451 }
452
453 /**
Charles Chan5d5e0622015-09-25 13:00:06 -0700454 * When receiving NeighborAdvertisement, updates location and IP.
455 */
456 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300457 public void receiveNa() {
Jonathan Hartb35540a2015-11-17 09:30:56 -0800458 testProcessor.process(new TestNaPacketContext(DEV4));
Andrey Komarov2398d962016-09-26 15:11:23 +0300459 assertThat("receiveNa. One host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800460 providerService.descriptions.size(), is(1));
461 HostDescription descr = providerService.descriptions.get(0);
Charles Chan5d5e0622015-09-25 13:00:06 -0700462 assertThat(descr.location(), is(LOCATION2));
463 assertThat(descr.hwAddress(), is(MAC2));
464 assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS2));
465 assertThat(descr.vlan(), is(VLAN));
466 }
467
468 /**
469 * When receiving NeighborSolicitation, updates location and IP.
470 */
471 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300472 public void receiveNs() {
Jonathan Hartb35540a2015-11-17 09:30:56 -0800473 testProcessor.process(new TestNsPacketContext(DEV4));
Andrey Komarov2398d962016-09-26 15:11:23 +0300474 assertThat("receiveNs. One host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800475 providerService.descriptions.size(), is(1));
476 HostDescription descr = providerService.descriptions.get(0);
Charles Chan5d5e0622015-09-25 13:00:06 -0700477 assertThat(descr.location(), is(LOCATION2));
478 assertThat(descr.hwAddress(), is(MAC2));
479 assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS2));
480 assertThat(descr.vlan(), is(VLAN));
481 }
482
483 /**
484 * When receiving RouterAdvertisement, ignores it.
485 */
486 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300487 public void receivesRa() {
Charles Chan5d5e0622015-09-25 13:00:06 -0700488 testProcessor.process(new TestRAPacketContext(DEV4));
Andrey Komarov2398d962016-09-26 15:11:23 +0300489 assertThat("receivesRa. No host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800490 providerService.descriptions.size(), is(0));
Charles Chan5d5e0622015-09-25 13:00:06 -0700491 }
492
493 /**
494 * When receiving RouterSolicitation, ignores it.
495 */
496 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300497 public void receiveRs() {
Charles Chan5d5e0622015-09-25 13:00:06 -0700498 testProcessor.process(new TestRSPacketContext(DEV4));
Andrey Komarov2398d962016-09-26 15:11:23 +0300499 assertThat("receiveRs. No host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800500 providerService.descriptions.size(), is(0));
Charles Chan5d5e0622015-09-25 13:00:06 -0700501 }
502
503 /**
504 * When receiving Duplicate Address Detection (DAD), ignores it.
505 */
506 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300507 public void receiveDad() {
Jonathan Hartb35540a2015-11-17 09:30:56 -0800508 testProcessor.process(new TestDadPacketContext(DEV4));
Andrey Komarov2398d962016-09-26 15:11:23 +0300509 assertThat("receiveDad. No host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800510 providerService.descriptions.size(), is(0));
Charles Chan5d5e0622015-09-25 13:00:06 -0700511 }
512
513 /**
514 * When receiving IPv6 multicast packet, ignores it.
515 */
516 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300517 public void receiveIpv6Multicast() {
Charles Chan5d5e0622015-09-25 13:00:06 -0700518 testProcessor.process(new TestIpv6McastPacketContext(DEV4));
Andrey Komarov2398d962016-09-26 15:11:23 +0300519 assertThat("receiveIpv6Multicast. No host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800520 providerService.descriptions.size(), is(0));
Charles Chan5d5e0622015-09-25 13:00:06 -0700521 }
522
523 /**
524 * When receiving IPv6 unicast packet, updates location only.
525 */
526 @Test
Andrey Komarov2398d962016-09-26 15:11:23 +0300527 public void receiveIpv6Unicast() {
Charles Chan5d5e0622015-09-25 13:00:06 -0700528 testProcessor.process(new TestIpv6PacketContext(DEV4));
Andrey Komarov2398d962016-09-26 15:11:23 +0300529 assertThat("receiveIpv6Unicast. One host description expected",
Charles Chan420e7372016-11-17 10:58:17 -0800530 providerService.descriptions.size(), is(1));
531 HostDescription descr = providerService.descriptions.get(0);
Charles Chan5d5e0622015-09-25 13:00:06 -0700532 assertThat(descr.location(), is(LOCATION2));
533 assertThat(descr.hwAddress(), is(MAC2));
534 assertThat(descr.ipAddress().size(), is(0));
535 assertThat(descr.vlan(), is(VLAN));
536 }
Thomas Vachuska33601602014-11-19 03:32:15 -0800537
alshabib4a179dc2014-10-17 17:17:01 -0700538 @After
539 public void tearDown() {
540 provider.deactivate();
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800541 provider.coreService = null;
alshabib4a179dc2014-10-17 17:17:01 -0700542 provider.providerRegistry = null;
alshabib4a179dc2014-10-17 17:17:01 -0700543 }
544
545 private class TestHostRegistry implements HostProviderRegistry {
546
547 @Override
548 public HostProviderService register(HostProvider provider) {
549 providerService = new TestHostProviderService(provider);
550 return providerService;
551 }
552
553 @Override
554 public void unregister(HostProvider provider) {
555 }
556
557 @Override
558 public Set<ProviderId> getProviders() {
559 return null;
560 }
561
562 }
563
564 private class TestHostProviderService
565 extends AbstractProviderService<HostProvider>
566 implements HostProviderService {
567
Charles Chan420e7372016-11-17 10:58:17 -0800568 List<HostDescription> descriptions = Lists.newArrayList();
Charles Chan888e20a2017-05-01 15:44:23 -0700569 int hostRemoveCount;
570 int ipRemoveCount;
571 int locationRemoveCount;
alshabib4a179dc2014-10-17 17:17:01 -0700572
Charles Chan5d5e0622015-09-25 13:00:06 -0700573 public void clear() {
Charles Chan420e7372016-11-17 10:58:17 -0800574 descriptions.clear();
Charles Chan888e20a2017-05-01 15:44:23 -0700575 hostRemoveCount = 0;
576 ipRemoveCount = 0;
577 locationRemoveCount = 0;
Charles Chan5d5e0622015-09-25 13:00:06 -0700578 }
579
alshabib4a179dc2014-10-17 17:17:01 -0700580 protected TestHostProviderService(HostProvider provider) {
581 super(provider);
582 }
583
584 @Override
Brian O'Connorf107bd72015-09-21 15:31:03 -0700585 public void hostDetected(HostId hostId, HostDescription hostDescription, boolean replaceIps) {
Charles Chan420e7372016-11-17 10:58:17 -0800586 descriptions.add(hostDescription);
alshabib4a179dc2014-10-17 17:17:01 -0700587 }
588
589 @Override
590 public void hostVanished(HostId hostId) {
Charles Chan888e20a2017-05-01 15:44:23 -0700591 hostRemoveCount++;
alshabib4a179dc2014-10-17 17:17:01 -0700592 }
593
samanwita palc40e5ed2015-09-24 11:01:51 -0700594 @Override
595 public void removeIpFromHost(HostId hostId, IpAddress ipAddress) {
Charles Chan888e20a2017-05-01 15:44:23 -0700596 ipRemoveCount++;
597 }
598
599 @Override
600 public void removeLocationFromHost(HostId hostId, HostLocation location) {
601 locationRemoveCount++;
samanwita palc40e5ed2015-09-24 11:01:51 -0700602 }
603
alshabib4a179dc2014-10-17 17:17:01 -0700604 }
605
Thomas Vachuska27bee092015-06-23 19:03:10 -0700606 private class TestPacketService extends PacketServiceAdapter {
alshabib4a179dc2014-10-17 17:17:01 -0700607 @Override
608 public void addProcessor(PacketProcessor processor, int priority) {
609 testProcessor = processor;
610 }
alshabib4a179dc2014-10-17 17:17:01 -0700611 }
612
alshabib4a179dc2014-10-17 17:17:01 -0700613 private class TestTopologyService extends TopologyServiceAdapter {
614 @Override
615 public boolean isInfrastructure(Topology topology,
616 ConnectPoint connectPoint) {
617 //simulate DPID3 as an infrastructure switch
Charles Chan5d5e0622015-09-25 13:00:06 -0700618 if ((connectPoint.deviceId()).equals(deviceId(DEV3)) ||
619 connectPoint.deviceId().equals(deviceId(DEV6))) {
alshabib4a179dc2014-10-17 17:17:01 -0700620 return true;
621 }
622 return false;
623 }
624 }
625
Charles Chan5d5e0622015-09-25 13:00:06 -0700626 /**
627 * Generates ARP packet.
628 */
Andrey Komarov2398d962016-09-26 15:11:23 +0300629 private class TestArpPacketContext extends PacketContextAdapter {
alshabib4a179dc2014-10-17 17:17:01 -0700630 private final String deviceId;
631
Charles Chan5d5e0622015-09-25 13:00:06 -0700632 public TestArpPacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300633 super(0, null, null, false);
alshabib4a179dc2014-10-17 17:17:01 -0700634 this.deviceId = deviceId;
635 }
636
637 @Override
alshabib4a179dc2014-10-17 17:17:01 -0700638 public InboundPacket inPacket() {
639 ARP arp = new ARP();
640 arp.setSenderProtocolAddress(IP)
641 .setSenderHardwareAddress(MAC.toBytes())
642 .setTargetHardwareAddress(BCMAC.toBytes())
643 .setTargetProtocolAddress(IP);
644
645 Ethernet eth = new Ethernet();
646 eth.setEtherType(Ethernet.TYPE_ARP)
647 .setVlanID(VLAN.toShort())
648 .setSourceMACAddress(MAC.toBytes())
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800649 .setDestinationMACAddress(BCMAC)
alshabib4a179dc2014-10-17 17:17:01 -0700650 .setPayload(arp);
Thomas Vachuska33601602014-11-19 03:32:15 -0800651 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
652 portNumber(INPORT));
alshabib4a179dc2014-10-17 17:17:01 -0700653 return new DefaultInboundPacket(receivedFrom, eth,
654 ByteBuffer.wrap(eth.serialize()));
655 }
alshabib4a179dc2014-10-17 17:17:01 -0700656 }
Thomas Vachuska33601602014-11-19 03:32:15 -0800657
Charles Chan5d5e0622015-09-25 13:00:06 -0700658 /**
Charles Chane6067892016-11-17 10:23:46 -0800659 * Generates IPv4 Unicast packet.
Charles Chan5d5e0622015-09-25 13:00:06 -0700660 */
Andrey Komarov2398d962016-09-26 15:11:23 +0300661 private class TestIpv4PacketContext extends PacketContextAdapter {
Charles Chan5d5e0622015-09-25 13:00:06 -0700662 private final String deviceId;
663
664 public TestIpv4PacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300665 super(0, null, null, false);
Charles Chan5d5e0622015-09-25 13:00:06 -0700666 this.deviceId = deviceId;
667 }
668
669 @Override
Charles Chan5d5e0622015-09-25 13:00:06 -0700670 public InboundPacket inPacket() {
671 IPv4 ipv4 = new IPv4();
672 ipv4.setDestinationAddress("10.0.0.1");
673 ipv4.setSourceAddress(IP_ADDRESS.toString());
674 Ethernet eth = new Ethernet();
675 eth.setEtherType(Ethernet.TYPE_IPV4)
676 .setVlanID(VLAN.toShort())
677 .setSourceMACAddress(MAC)
678 .setDestinationMACAddress(MacAddress.valueOf("00:00:00:00:00:01"))
679 .setPayload(ipv4);
680 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
681 portNumber(INPORT));
682 return new DefaultInboundPacket(receivedFrom, eth,
683 ByteBuffer.wrap(eth.serialize()));
684 }
Charles Chan5d5e0622015-09-25 13:00:06 -0700685 }
Yi Tsengfcf5dce2017-07-26 14:30:41 -0700686
Charles Chane6067892016-11-17 10:23:46 -0800687 /**
688 * Generates DHCP REQUEST packet.
689 */
Andrey Komarov2398d962016-09-26 15:11:23 +0300690 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
Charles Chane6067892016-11-17 10:23:46 -0800691 private final String deviceId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700692 private final VlanId vlanId;
Charles Chane6067892016-11-17 10:23:46 -0800693
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700694 public TestDhcpRequestPacketContext(String deviceId, VlanId vlanId) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300695 super(0, null, null, false);
Charles Chane6067892016-11-17 10:23:46 -0800696 this.deviceId = deviceId;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700697 this.vlanId = vlanId;
Charles Chane6067892016-11-17 10:23:46 -0800698 }
699
700 @Override
Charles Chane6067892016-11-17 10:23:46 -0800701 public InboundPacket inPacket() {
702 byte[] dhcpMsgType = new byte[1];
Yi Tsengc7403c22017-06-19 16:23:22 -0700703 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
Charles Chane6067892016-11-17 10:23:46 -0800704
Yi Tsengc7403c22017-06-19 16:23:22 -0700705 DhcpOption dhcpOption = new DhcpOption();
Charles Chane6067892016-11-17 10:23:46 -0800706 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
707 dhcpOption.setData(dhcpMsgType);
708 dhcpOption.setLength((byte) 1);
709 DHCP dhcp = new DHCP();
710 dhcp.setOptions(Collections.singletonList(dhcpOption));
711 dhcp.setClientHardwareAddress(MAC.toBytes());
712 UDP udp = new UDP();
713 udp.setPayload(dhcp);
714 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
715 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
716 IPv4 ipv4 = new IPv4();
717 ipv4.setPayload(udp);
718 ipv4.setDestinationAddress(IP_ADDRESS3.toString());
719 ipv4.setSourceAddress(IP_ADDRESS.toString());
720 Ethernet eth = new Ethernet();
721 eth.setEtherType(Ethernet.TYPE_IPV4)
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700722 .setVlanID(this.vlanId.toShort())
Charles Chane6067892016-11-17 10:23:46 -0800723 .setSourceMACAddress(MAC)
724 .setDestinationMACAddress(MAC3)
725 .setPayload(ipv4);
726 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
727 portNumber(INPORT));
728 return new DefaultInboundPacket(receivedFrom, eth,
729 ByteBuffer.wrap(eth.serialize()));
730 }
Charles Chane6067892016-11-17 10:23:46 -0800731 }
732
733 /**
734 * Generates DHCP ACK packet.
735 */
Andrey Komarov2398d962016-09-26 15:11:23 +0300736 private class TestDhcpAckPacketContext extends PacketContextAdapter {
Charles Chane6067892016-11-17 10:23:46 -0800737 private final String deviceId;
738
Yi Tsengfcf5dce2017-07-26 14:30:41 -0700739 public TestDhcpAckPacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300740 super(0, null, null, false);
Charles Chane6067892016-11-17 10:23:46 -0800741 this.deviceId = deviceId;
742 }
743
744 @Override
Charles Chane6067892016-11-17 10:23:46 -0800745 public InboundPacket inPacket() {
746 byte[] dhcpMsgType = new byte[1];
Yi Tsengc7403c22017-06-19 16:23:22 -0700747 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
Charles Chane6067892016-11-17 10:23:46 -0800748
Yi Tsengc7403c22017-06-19 16:23:22 -0700749 DhcpOption dhcpOption = new DhcpOption();
Charles Chane6067892016-11-17 10:23:46 -0800750 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
751 dhcpOption.setData(dhcpMsgType);
752 dhcpOption.setLength((byte) 1);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700753
Charles Chane6067892016-11-17 10:23:46 -0800754 DHCP dhcp = new DHCP();
Yi Tsengfcf5dce2017-07-26 14:30:41 -0700755 dhcp.setOptions(ImmutableList.of(dhcpOption));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700756
Charles Chane6067892016-11-17 10:23:46 -0800757 dhcp.setClientHardwareAddress(MAC.toBytes());
758 dhcp.setYourIPAddress(IP_ADDRESS.getIp4Address().toInt());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700759
Charles Chane6067892016-11-17 10:23:46 -0800760 UDP udp = new UDP();
761 udp.setPayload(dhcp);
762 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
763 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
764 IPv4 ipv4 = new IPv4();
765 ipv4.setPayload(udp);
766 ipv4.setDestinationAddress(IP_ADDRESS.toString());
767 ipv4.setSourceAddress(IP_ADDRESS3.toString());
768 Ethernet eth = new Ethernet();
769 eth.setEtherType(Ethernet.TYPE_IPV4)
770 .setVlanID(VLAN.toShort())
771 .setSourceMACAddress(MAC3)
772 .setDestinationMACAddress(MAC)
773 .setPayload(ipv4);
774 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
775 portNumber(INPORT2));
776 return new DefaultInboundPacket(receivedFrom, eth,
777 ByteBuffer.wrap(eth.serialize()));
778 }
Charles Chane6067892016-11-17 10:23:46 -0800779 }
Charles Chan5d5e0622015-09-25 13:00:06 -0700780
781 /**
Yi Tsengfcf5dce2017-07-26 14:30:41 -0700782 * Generates DHCPv6 REQUEST packet.
783 */
784 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
785 private final String deviceId;
786 private final VlanId vlanId;
787
788 public TestDhcp6RequestPacketContext(String deviceId, VlanId vlanId) {
789 super(0, null, null, false);
790 this.deviceId = deviceId;
791 this.vlanId = vlanId;
792 }
793
794 @Override
795 public InboundPacket inPacket() {
796
797 DHCP6 dhcp6 = new DHCP6();
798 dhcp6.setMsgType(DHCP6.MsgType.REQUEST.value());
799 List<Dhcp6Option> options = Lists.newArrayList();
800
801 // IA address
802 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
803 iaAddressOption.setIp6Address(IP_ADDRESS2.getIp6Address());
804
805 // IA NA
806 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
807 iaNaOption.setOptions(ImmutableList.of(iaAddressOption));
808 options.add(iaNaOption);
809
810 dhcp6.setOptions(options);
811
812 UDP udp = new UDP();
813 udp.setPayload(dhcp6);
814 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
815 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
816 IPv6 ipv6 = new IPv6();
817 ipv6.setPayload(udp);
818 ipv6.setDestinationAddress(Ip6Address.ZERO.toOctets());
819 ipv6.setSourceAddress(Ip6Address.ZERO.toOctets());
820 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
821 Ethernet eth = new Ethernet();
822 eth.setEtherType(Ethernet.TYPE_IPV6)
823 .setVlanID(this.vlanId.toShort())
824 .setSourceMACAddress(MAC2)
825 .setDestinationMACAddress(DHCP6_SERVER_MAC)
826 .setPayload(ipv6);
827 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
828 portNumber(INPORT));
829 return new DefaultInboundPacket(receivedFrom, eth,
830 ByteBuffer.wrap(eth.serialize()));
831 }
832 }
833
834 /**
835 * Generates DHCPv6 ACK packet.
836 */
837 private class TestDhcp6AckPacketContext extends PacketContextAdapter {
838 private final String deviceId;
839
840 public TestDhcp6AckPacketContext(String deviceId) {
841 super(0, null, null, false);
842 this.deviceId = deviceId;
843 }
844
845 @Override
846 public InboundPacket inPacket() {
847 DHCP6 dhcp6 = new DHCP6();
848 dhcp6.setMsgType(DHCP6.MsgType.REPLY.value());
849 List<Dhcp6Option> options = Lists.newArrayList();
850
851 // IA address
852 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
853 iaAddressOption.setIp6Address(IP_ADDRESS2.getIp6Address());
854
855 // IA NA
856 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
857 iaNaOption.setOptions(ImmutableList.of(iaAddressOption));
858 options.add(iaNaOption);
859
860 // Client ID
861 Dhcp6Duid duid = new Dhcp6Duid();
862 duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
863 duid.setHardwareType((short) 1);
864 duid.setDuidTime(0);
865 duid.setLinkLayerAddress(MAC2.toBytes());
866 Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
867 clientIdOption.setDuid(duid);
868 options.add(clientIdOption);
869 dhcp6.setOptions(options);
870
871 UDP udp = new UDP();
872 udp.setPayload(dhcp6);
873 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
874 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
875 IPv6 ipv6 = new IPv6();
876 ipv6.setPayload(udp);
877 ipv6.setDestinationAddress(Ip6Address.ZERO.toOctets());
878 ipv6.setSourceAddress(Ip6Address.ZERO.toOctets());
879 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
880 Ethernet eth = new Ethernet();
881 eth.setEtherType(Ethernet.TYPE_IPV6)
882 .setVlanID(VLAN.toShort())
883 .setSourceMACAddress(DHCP6_SERVER_MAC)
884 .setDestinationMACAddress(MAC2)
885 .setPayload(ipv6);
886 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
887 portNumber(INPORT2));
888 return new DefaultInboundPacket(receivedFrom, eth,
889 ByteBuffer.wrap(eth.serialize()));
890 }
891 }
892
893 /**
Charles Chan5d5e0622015-09-25 13:00:06 -0700894 * Generates NeighborAdvertisement packet.
895 */
Andrey Komarov2398d962016-09-26 15:11:23 +0300896 private class TestNaPacketContext extends PacketContextAdapter {
Charles Chan5d5e0622015-09-25 13:00:06 -0700897 private final String deviceId;
898
Jonathan Hartb35540a2015-11-17 09:30:56 -0800899 public TestNaPacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300900 super(0, null, null, false);
Charles Chan5d5e0622015-09-25 13:00:06 -0700901 this.deviceId = deviceId;
902 }
903
904 @Override
Charles Chan5d5e0622015-09-25 13:00:06 -0700905 public InboundPacket inPacket() {
906 NeighborAdvertisement na = new NeighborAdvertisement();
907 ICMP6 icmp6 = new ICMP6();
908 icmp6.setPayload(na);
909 IPv6 ipv6 = new IPv6();
910 ipv6.setPayload(icmp6);
911 ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets());
912 ipv6.setSourceAddress(IP2);
913 Ethernet eth = new Ethernet();
914 eth.setEtherType(Ethernet.TYPE_IPV6)
915 .setVlanID(VLAN.toShort())
916 .setSourceMACAddress(MAC2.toBytes())
917 .setDestinationMACAddress(BCMAC2)
918 .setPayload(ipv6);
919 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
920 portNumber(INPORT));
921 return new DefaultInboundPacket(receivedFrom, eth,
922 ByteBuffer.wrap(eth.serialize()));
923 }
Charles Chan5d5e0622015-09-25 13:00:06 -0700924 }
925
926 /**
927 * Generates NeighborSolicitation packet.
928 */
Andrey Komarov2398d962016-09-26 15:11:23 +0300929 private class TestNsPacketContext extends PacketContextAdapter {
Charles Chan5d5e0622015-09-25 13:00:06 -0700930 private final String deviceId;
931
Jonathan Hartb35540a2015-11-17 09:30:56 -0800932 public TestNsPacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300933 super(0, null, null, false);
Charles Chan5d5e0622015-09-25 13:00:06 -0700934 this.deviceId = deviceId;
935 }
936
937 @Override
Charles Chan5d5e0622015-09-25 13:00:06 -0700938 public InboundPacket inPacket() {
939 NeighborSolicitation ns = new NeighborSolicitation();
940 ICMP6 icmp6 = new ICMP6();
941 icmp6.setPayload(ns);
942 IPv6 ipv6 = new IPv6();
943 ipv6.setPayload(icmp6);
944 ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1:ff00:0000").toOctets());
945 ipv6.setSourceAddress(IP2);
946 Ethernet eth = new Ethernet();
947 eth.setEtherType(Ethernet.TYPE_IPV6)
948 .setVlanID(VLAN.toShort())
949 .setSourceMACAddress(MAC2.toBytes())
950 .setDestinationMACAddress(BCMAC2)
951 .setPayload(ipv6);
952 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
953 portNumber(INPORT));
954 return new DefaultInboundPacket(receivedFrom, eth,
955 ByteBuffer.wrap(eth.serialize()));
956 }
Charles Chan5d5e0622015-09-25 13:00:06 -0700957 }
958
959 /**
960 * Generates Duplicate Address Detection packet.
961 */
Andrey Komarov2398d962016-09-26 15:11:23 +0300962 private class TestDadPacketContext extends PacketContextAdapter {
Charles Chan5d5e0622015-09-25 13:00:06 -0700963 private final String deviceId;
964
Jonathan Hartb35540a2015-11-17 09:30:56 -0800965 public TestDadPacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300966 super(0, null, null, false);
Charles Chan5d5e0622015-09-25 13:00:06 -0700967 this.deviceId = deviceId;
968 }
969
970 @Override
Charles Chan5d5e0622015-09-25 13:00:06 -0700971 public InboundPacket inPacket() {
972 NeighborSolicitation ns = new NeighborSolicitation();
973 ICMP6 icmp6 = new ICMP6();
974 icmp6.setPayload(ns);
975 IPv6 ipv6 = new IPv6();
976 ipv6.setPayload(icmp6);
977 ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets());
978 ipv6.setSourceAddress(Ip6Address.valueOf("::").toOctets());
979 Ethernet eth = new Ethernet();
980 eth.setEtherType(Ethernet.TYPE_IPV6)
981 .setVlanID(VLAN.toShort())
982 .setSourceMACAddress(MAC2.toBytes())
983 .setDestinationMACAddress(BCMAC2)
984 .setPayload(ipv6);
985 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
986 portNumber(INPORT));
987 return new DefaultInboundPacket(receivedFrom, eth,
988 ByteBuffer.wrap(eth.serialize()));
989 }
Charles Chan5d5e0622015-09-25 13:00:06 -0700990 }
991
992 /**
993 * Generates Router Solicitation packet.
994 */
Andrey Komarov2398d962016-09-26 15:11:23 +0300995 private class TestRSPacketContext extends PacketContextAdapter {
Charles Chan5d5e0622015-09-25 13:00:06 -0700996 private final String deviceId;
997
998 public TestRSPacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +0300999 super(0, null, null, false);
Charles Chan5d5e0622015-09-25 13:00:06 -07001000 this.deviceId = deviceId;
1001 }
1002
1003 @Override
Charles Chan5d5e0622015-09-25 13:00:06 -07001004 public InboundPacket inPacket() {
1005 RouterSolicitation ns = new RouterSolicitation();
1006 ICMP6 icmp6 = new ICMP6();
1007 icmp6.setPayload(ns);
1008 IPv6 ipv6 = new IPv6();
1009 ipv6.setPayload(icmp6);
1010 ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::2").toOctets());
1011 ipv6.setSourceAddress(Ip6Address.valueOf("::").toOctets());
1012 Ethernet eth = new Ethernet();
1013 eth.setEtherType(Ethernet.TYPE_IPV6)
1014 .setVlanID(VLAN.toShort())
1015 .setSourceMACAddress(MAC2.toBytes())
1016 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:02"))
1017 .setPayload(ipv6);
1018 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
1019 portNumber(INPORT));
1020 return new DefaultInboundPacket(receivedFrom, eth,
1021 ByteBuffer.wrap(eth.serialize()));
1022 }
Charles Chan5d5e0622015-09-25 13:00:06 -07001023 }
1024
1025 /**
1026 * Generates Router Advertisement packet.
1027 */
Andrey Komarov2398d962016-09-26 15:11:23 +03001028 private class TestRAPacketContext extends PacketContextAdapter {
Charles Chan5d5e0622015-09-25 13:00:06 -07001029 private final String deviceId;
1030
1031 public TestRAPacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +03001032 super(0, null, null, false);
Charles Chan5d5e0622015-09-25 13:00:06 -07001033 this.deviceId = deviceId;
1034 }
1035
1036 @Override
Charles Chan5d5e0622015-09-25 13:00:06 -07001037 public InboundPacket inPacket() {
1038 RouterAdvertisement ns = new RouterAdvertisement();
1039 ICMP6 icmp6 = new ICMP6();
1040 icmp6.setPayload(ns);
1041 IPv6 ipv6 = new IPv6();
1042 ipv6.setPayload(icmp6);
1043 ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets());
1044 ipv6.setSourceAddress(IP2);
1045 Ethernet eth = new Ethernet();
1046 eth.setEtherType(Ethernet.TYPE_IPV6)
1047 .setVlanID(VLAN.toShort())
1048 .setSourceMACAddress(MAC2.toBytes())
1049 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:01"))
1050 .setPayload(ipv6);
1051 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
1052 portNumber(INPORT));
1053 return new DefaultInboundPacket(receivedFrom, eth,
1054 ByteBuffer.wrap(eth.serialize()));
1055 }
Charles Chan5d5e0622015-09-25 13:00:06 -07001056 }
1057
1058 /**
1059 * Generates IPv6 Multicast packet.
1060 */
Andrey Komarov2398d962016-09-26 15:11:23 +03001061 private class TestIpv6McastPacketContext extends PacketContextAdapter {
Charles Chan5d5e0622015-09-25 13:00:06 -07001062 private final String deviceId;
1063
1064 public TestIpv6McastPacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +03001065 super(0, null, null, false);
Charles Chan5d5e0622015-09-25 13:00:06 -07001066 this.deviceId = deviceId;
1067 }
1068
1069 @Override
Charles Chan5d5e0622015-09-25 13:00:06 -07001070 public InboundPacket inPacket() {
1071 IPv6 ipv6 = new IPv6();
1072 ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets());
1073 ipv6.setSourceAddress(IP2);
1074 Ethernet eth = new Ethernet();
1075 eth.setEtherType(Ethernet.TYPE_IPV6)
1076 .setVlanID(VLAN.toShort())
1077 .setSourceMACAddress(MAC2.toBytes())
1078 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:01"))
1079 .setPayload(ipv6);
1080 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
1081 portNumber(INPORT));
1082 return new DefaultInboundPacket(receivedFrom, eth,
1083 ByteBuffer.wrap(eth.serialize()));
1084 }
Charles Chan5d5e0622015-09-25 13:00:06 -07001085 }
1086
1087 /**
1088 * Generates IPv6 Unicast packet.
1089 */
Andrey Komarov2398d962016-09-26 15:11:23 +03001090 private class TestIpv6PacketContext extends PacketContextAdapter {
Charles Chan5d5e0622015-09-25 13:00:06 -07001091 private final String deviceId;
1092
1093 public TestIpv6PacketContext(String deviceId) {
Andrey Komarov2398d962016-09-26 15:11:23 +03001094 super(0, null, null, false);
Charles Chan5d5e0622015-09-25 13:00:06 -07001095 this.deviceId = deviceId;
1096 }
1097
1098 @Override
Charles Chan5d5e0622015-09-25 13:00:06 -07001099 public InboundPacket inPacket() {
1100 IPv6 ipv6 = new IPv6();
1101 ipv6.setDestinationAddress(Ip6Address.valueOf("1000::1").toOctets());
1102 ipv6.setSourceAddress(IP2);
1103 Ethernet eth = new Ethernet();
1104 eth.setEtherType(Ethernet.TYPE_IPV6)
1105 .setVlanID(VLAN.toShort())
1106 .setSourceMACAddress(MAC2)
1107 .setDestinationMACAddress(MacAddress.valueOf("00:00:00:00:00:01"))
1108 .setPayload(ipv6);
1109 ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId),
1110 portNumber(INPORT));
1111 return new DefaultInboundPacket(receivedFrom, eth,
1112 ByteBuffer.wrap(eth.serialize()));
1113 }
Charles Chan5d5e0622015-09-25 13:00:06 -07001114 }
1115
Thomas Vachuska33601602014-11-19 03:32:15 -08001116 private class TestDeviceService extends DeviceServiceAdapter {
1117 private DeviceListener listener;
1118
1119 @Override
1120 public void addListener(DeviceListener listener) {
1121 this.listener = listener;
1122 }
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -08001123
1124 @Override
1125 public Iterable<Device> getDevices() {
1126 return Collections.emptyList();
1127 }
Thomas Vachuska33601602014-11-19 03:32:15 -08001128 }
1129
1130 private class TestHostService extends HostServiceAdapter {
1131 @Override
1132 public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
Charles Chan5d5e0622015-09-25 13:00:06 -07001133 ConnectPoint cp1 = new ConnectPoint(deviceId(DEV1), portNumber(INPORT));
1134 ConnectPoint cp2 = new ConnectPoint(deviceId(DEV4), portNumber(INPORT));
Charles Chane6067892016-11-17 10:23:46 -08001135 ConnectPoint cp3 = new ConnectPoint(deviceId(DEV1), portNumber(INPORT2));
Charles Chan5d5e0622015-09-25 13:00:06 -07001136 if (connectPoint.equals(cp1)) {
1137 return ImmutableSet.of(HOST);
1138 } else if (connectPoint.equals(cp2)) {
1139 return ImmutableSet.of(HOST2);
Charles Chane6067892016-11-17 10:23:46 -08001140 } else if (connectPoint.equals(cp3)) {
1141 return ImmutableSet.of(HOST3);
Charles Chan5d5e0622015-09-25 13:00:06 -07001142 } else {
1143 return ImmutableSet.of();
1144 }
Thomas Vachuska33601602014-11-19 03:32:15 -08001145 }
1146
1147 @Override
1148 public Set<Host> getConnectedHosts(DeviceId deviceId) {
Charles Chan5d5e0622015-09-25 13:00:06 -07001149 if (deviceId.equals(deviceId(DEV1))) {
Charles Chane6067892016-11-17 10:23:46 -08001150 return ImmutableSet.of(HOST, HOST3);
Charles Chan5d5e0622015-09-25 13:00:06 -07001151 } else if (deviceId.equals(deviceId(DEV4))) {
1152 return ImmutableSet.of(HOST2);
1153 } else {
1154 return ImmutableSet.of();
1155 }
Thomas Vachuska33601602014-11-19 03:32:15 -08001156 }
1157
Charles Chane6067892016-11-17 10:23:46 -08001158 @Override
1159 public Host getHost(HostId hostId) {
1160 if (hostId.equals(HostId.hostId(MAC, VLAN))) {
1161 return HOST;
1162 } else if (hostId.equals(HostId.hostId(MAC2, VLAN))) {
1163 return HOST2;
1164 } else if (hostId.equals(HostId.hostId(MAC3, VLAN))) {
1165 return HOST3;
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001166 } else if (hostId.equals(HostId.hostId(MAC, VLAN_100))) {
1167 return HOST_VLAN_100;
Charles Chane6067892016-11-17 10:23:46 -08001168 }
1169 return null;
1170 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001171 }
Charles Chane6067892016-11-17 10:23:46 -08001172
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001173 private class TestInterfaceService implements InterfaceService {
1174 @Override
1175 public Set<Interface> getInterfaces() {
1176 return null;
1177 }
1178
1179 @Override
1180 public Interface getInterfaceByName(ConnectPoint connectPoint, String name) {
1181 return null;
1182 }
1183
1184 @Override
1185 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
1186 return null;
1187 }
1188
1189 public Set<Interface> getInterfacesByIp(IpAddress ip) {
1190 if (ip.equals(GW_IFACE_ADDR.ipAddress())) {
1191 return ImmutableSet.of(GW_IFACE);
1192 } else {
1193 return ImmutableSet.of();
1194 }
1195 }
1196
1197 @Override
1198 public Set<Interface> getInterfacesByVlan(VlanId vlan) {
1199 return null;
1200 }
1201
1202 @Override
1203 public Interface getMatchingInterface(IpAddress ip) {
1204 return null;
1205 }
1206
1207 @Override
1208 public Set<Interface> getMatchingInterfaces(IpAddress ip) {
1209 return null;
1210 }
1211
1212 @Override
1213 public void addListener(InterfaceListener listener) {
1214
1215 }
1216
1217 @Override
1218 public void removeListener(InterfaceListener listener) {
1219
1220 }
Thomas Vachuska33601602014-11-19 03:32:15 -08001221 }
alshabib4a179dc2014-10-17 17:17:01 -07001222}