blob: 81bff46c31c38b653716b978c0624a3c15d4764c [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.host.impl;
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070017
Jonathan Hart46080b62015-08-31 11:10:21 +020018import com.google.common.collect.Lists;
19import com.google.common.collect.Sets;
20import org.junit.After;
21import org.junit.Before;
22import org.junit.Test;
Charles Chan009c3082015-11-10 14:18:04 -080023import org.onlab.junit.TestTools;
soumya3e6f05e2016-08-05 15:11:11 -070024import org.onlab.osgi.ComponentContextAdapter;
Jonathan Hart46080b62015-08-31 11:10:21 +020025import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
27import org.onlab.packet.VlanId;
soumya3e6f05e2016-08-05 15:11:11 -070028import org.onosproject.cfg.ComponentConfigAdapter;
Jonathan Hart46080b62015-08-31 11:10:21 +020029import org.onosproject.common.event.impl.TestEventDispatcher;
30import org.onosproject.event.Event;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.Host;
33import org.onosproject.net.HostId;
34import org.onosproject.net.HostLocation;
35import org.onosproject.net.PortNumber;
36import org.onosproject.net.config.NetworkConfigServiceAdapter;
37import org.onosproject.net.host.DefaultHostDescription;
38import org.onosproject.net.host.HostDescription;
39import org.onosproject.net.host.HostEvent;
40import org.onosproject.net.host.HostListener;
41import org.onosproject.net.host.HostProvider;
42import org.onosproject.net.host.HostProviderRegistry;
43import org.onosproject.net.host.HostProviderService;
44import org.onosproject.net.provider.AbstractProvider;
45import org.onosproject.net.provider.ProviderId;
46import org.onosproject.store.trivial.SimpleHostStore;
47
Charles Chan29ecdee2017-02-22 18:46:56 -080048import java.util.Collections;
soumya3e6f05e2016-08-05 15:11:11 -070049import java.util.Dictionary;
50import java.util.Hashtable;
Jonathan Hart46080b62015-08-31 11:10:21 +020051import java.util.List;
52import java.util.Set;
53
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070054import static org.junit.Assert.assertEquals;
55import static org.junit.Assert.assertFalse;
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070056import static org.junit.Assert.assertNotNull;
Jonathan Hartc884f1b2014-09-24 11:53:33 -070057import static org.junit.Assert.assertNull;
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070058import static org.junit.Assert.assertTrue;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070059import static org.onosproject.net.NetTestTools.injectEventDispatcher;
Brian O'Connorabafb502014-12-02 22:26:20 -080060import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
61import static org.onosproject.net.host.HostEvent.Type.HOST_MOVED;
62import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
63import static org.onosproject.net.host.HostEvent.Type.HOST_UPDATED;
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070064
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070065/**
66 * Test codifying the host service & host provider service contracts.
67 */
tom202175a2014-09-19 19:00:11 -070068public class HostManagerTest {
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070069
Charles Chan29ecdee2017-02-22 18:46:56 -080070 private static final ProviderId PID = new ProviderId("host", "foo");
71 private static final ProviderId PID2 = new ProviderId("host2", "foo2");
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070072
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070073 private static final VlanId VLAN1 = VlanId.vlanId((short) 1);
74 private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
75 private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01");
76 private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
Kunihiro Ishiguro1eab7d52015-02-10 10:38:18 +090077 private static final MacAddress MAC3 = MacAddress.valueOf("00:00:33:00:00:03");
78 private static final MacAddress MAC4 = MacAddress.valueOf("00:00:44:00:00:04");
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070079 private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
80 private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
Kunihiro Ishiguro1eab7d52015-02-10 10:38:18 +090081 private static final HostId HID3 = HostId.hostId(MAC3, VLAN1);
82 private static final HostId HID4 = HostId.hostId(MAC4, VLAN1);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070083
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -070084 private static final IpAddress IP1 = IpAddress.valueOf("10.0.0.1");
85 private static final IpAddress IP2 = IpAddress.valueOf("10.0.0.2");
Kunihiro Ishiguro1eab7d52015-02-10 10:38:18 +090086 private static final IpAddress IP3 = IpAddress.valueOf("2001::1");
87 private static final IpAddress IP4 = IpAddress.valueOf("2001::2");
Ayaka Koshibeac8e7292014-09-16 16:08:31 -070088
89 private static final DeviceId DID1 = DeviceId.deviceId("of:001");
90 private static final DeviceId DID2 = DeviceId.deviceId("of:002");
91 private static final PortNumber P1 = PortNumber.portNumber(100);
92 private static final PortNumber P2 = PortNumber.portNumber(200);
93 private static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L);
94 private static final HostLocation LOC2 = new HostLocation(DID1, P2, 123L);
95
sdn94b00152016-08-30 02:12:32 -070096 public static final ComponentContextAdapter REMOVE_DUPS_MONITOR = new ComponentContextAdapter() {
97 @Override
98 public Dictionary getProperties() {
99 Hashtable<String, String> props = new Hashtable<String, String>();
100 props.put("allowDuplicateIps", "true");
101 props.put("monitorHosts", "true");
102 props.put("probeRate", "40000");
103 return props;
104 }
105 };
106
tom202175a2014-09-19 19:00:11 -0700107 private HostManager mgr;
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700108
109 protected TestListener listener = new TestListener();
110 protected HostProviderRegistry registry;
111 protected TestHostProvider provider;
Charles Chan29ecdee2017-02-22 18:46:56 -0800112 protected TestHostProvider provider2;
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700113 protected HostProviderService providerService;
Charles Chan29ecdee2017-02-22 18:46:56 -0800114 protected HostProviderService providerService2;
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700115
116 @Before
117 public void setUp() {
tom202175a2014-09-19 19:00:11 -0700118 mgr = new HostManager();
tom5bcc9462014-09-19 10:11:31 -0700119 mgr.store = new SimpleHostStore();
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700120 injectEventDispatcher(mgr, new TestEventDispatcher());
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700121 registry = mgr;
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700122 mgr.networkConfigService = new TestNetworkConfigService();
soumya3e6f05e2016-08-05 15:11:11 -0700123 mgr.cfgService = new ComponentConfigAdapter();
sdn94b00152016-08-30 02:12:32 -0700124
125 mgr.activate(REMOVE_DUPS_MONITOR);
126
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700127 mgr.addListener(listener);
128
Charles Chan29ecdee2017-02-22 18:46:56 -0800129 provider = new TestHostProvider(PID);
130 provider2 = new TestHostProvider(PID2);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700131 providerService = registry.register(provider);
Charles Chan29ecdee2017-02-22 18:46:56 -0800132 providerService2 = registry.register(provider2);
Jonathan Hart38feb6e2016-08-29 22:54:16 +0000133 assertTrue("provider should be registered",
134 registry.getProviders().contains(provider.id()));
Charles Chan29ecdee2017-02-22 18:46:56 -0800135 assertTrue("provider2 should be registered",
136 registry.getProviders().contains(provider2.id()));
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700137 }
138
139 @After
140 public void tearDown() {
141 registry.unregister(provider);
Charles Chan29ecdee2017-02-22 18:46:56 -0800142 registry.unregister(provider2);
Jonathan Hart38feb6e2016-08-29 22:54:16 +0000143 assertFalse("provider should not be registered",
144 registry.getProviders().contains(provider.id()));
Charles Chan29ecdee2017-02-22 18:46:56 -0800145 assertFalse("provider2 should not be registered",
146 registry.getProviders().contains(provider2.id()));
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700147
148 mgr.removeListener(listener);
149 mgr.deactivate();
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700150 injectEventDispatcher(mgr, null);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700151 }
152
Jonathan Hart38feb6e2016-08-29 22:54:16 +0000153 private void detect(HostId hid, MacAddress mac, VlanId vlan,
154 HostLocation loc, IpAddress ip) {
tom093340b2014-10-10 00:15:36 -0700155 HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip);
Ray Milkeydc083442016-02-22 11:27:57 -0800156 providerService.hostDetected(hid, descr, false);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700157 assertNotNull("host should be found", mgr.getHost(hid));
158 }
159
Charles Chan29ecdee2017-02-22 18:46:56 -0800160 private void configured(HostId hid, MacAddress mac, VlanId vlan,
161 HostLocation loc, IpAddress ip) {
162 HostDescription descr = new DefaultHostDescription(mac, vlan, loc, Collections.singleton(ip), true);
163 providerService2.hostDetected(hid, descr, false);
164 assertNotNull("host should be found", mgr.getHost(hid));
165 }
166
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700167 private void validateEvents(Enum... types) {
Charles Chan009c3082015-11-10 14:18:04 -0800168 TestTools.assertAfter(100, () -> {
169 int i = 0;
170 assertEquals("wrong events received", types.length, listener.events.size());
171 for (Event event : listener.events) {
172 assertEquals("incorrect event type", types[i], event.type());
173 i++;
174 }
175 listener.events.clear();
176 });
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700177 }
178
179 @Test
180 public void hostDetected() {
181 assertNull("host shouldn't be found", mgr.getHost(HID1));
182
183 // host addition
tom093340b2014-10-10 00:15:36 -0700184 detect(HID1, MAC1, VLAN1, LOC1, IP1);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700185 assertEquals("exactly one should be found", 1, mgr.getHostCount());
tom093340b2014-10-10 00:15:36 -0700186 detect(HID2, MAC2, VLAN2, LOC2, IP1);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700187 assertEquals("two hosts should be found", 2, mgr.getHostCount());
188 validateEvents(HOST_ADDED, HOST_ADDED);
189
190 // host motion
tom093340b2014-10-10 00:15:36 -0700191 detect(HID1, MAC1, VLAN1, LOC2, IP1);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700192 validateEvents(HOST_MOVED);
193 assertEquals("only two hosts should be found", 2, mgr.getHostCount());
194
195 // host update
tom093340b2014-10-10 00:15:36 -0700196 detect(HID1, MAC1, VLAN1, LOC2, IP2);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700197 validateEvents(HOST_UPDATED);
198 assertEquals("only two hosts should be found", 2, mgr.getHostCount());
199 }
200
201 @Test
Kunihiro Ishiguro1eab7d52015-02-10 10:38:18 +0900202 public void hostDetectedIPv6() {
203 assertNull("host shouldn't be found", mgr.getHost(HID3));
204
205 // host addition
206 detect(HID3, MAC3, VLAN1, LOC1, IP3);
207 assertEquals("exactly one should be found", 1, mgr.getHostCount());
208 detect(HID4, MAC4, VLAN2, LOC2, IP3);
209 assertEquals("two hosts should be found", 2, mgr.getHostCount());
210 validateEvents(HOST_ADDED, HOST_ADDED);
211
212 // host motion
213 detect(HID3, MAC3, VLAN1, LOC2, IP3);
214 validateEvents(HOST_MOVED);
215 assertEquals("only two hosts should be found", 2, mgr.getHostCount());
216
217 // host update
218 detect(HID3, MAC3, VLAN1, LOC2, IP4);
219 validateEvents(HOST_UPDATED);
220 assertEquals("only two hosts should be found", 2, mgr.getHostCount());
221 }
222
Charles Chan29ecdee2017-02-22 18:46:56 -0800223 /**
224 * If configured host and learnt host are both provided, we should always use
225 * the configured one.
226 */
227 @Test
228 public void hostDetectedWithMultipleProviders() {
229 detect(HID1, MAC1, VLAN1, LOC1, IP1);
230 assertEquals("Expect ProviderId to be PID", PID, mgr.getHost(HID1).providerId());
231 assertTrue("Expect IP to be IP1", mgr.getHost(HID1).ipAddresses().contains(IP1));
232 assertEquals("Expect 1 host in the store", 1, mgr.getHostCount());
233 configured(HID1, MAC1, VLAN1, LOC1, IP2);
234 assertEquals("Expect ProviderId get overridden by PID2", PID2, mgr.getHost(HID1).providerId());
235 assertTrue("Expect IP to be IP2", mgr.getHost(HID1).ipAddresses().contains(IP2));
236 assertEquals("Expect 1 hosts in the store", 1, mgr.getHostCount());
237 detect(HID1, MAC1, VLAN1, LOC1, IP1);
238 assertEquals("Expect ProviderId doesn't get overridden by PID", PID2, mgr.getHost(HID1).providerId());
239 assertTrue("Expect IP to be IP2", mgr.getHost(HID1).ipAddresses().contains(IP2));
240 assertEquals("Expect 1 host in the store", 1, mgr.getHostCount());
241 }
242
Kunihiro Ishiguro1eab7d52015-02-10 10:38:18 +0900243 @Test
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700244 public void hostVanished() {
tom093340b2014-10-10 00:15:36 -0700245 detect(HID1, MAC1, VLAN1, LOC1, IP1);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700246 providerService.hostVanished(HID1);
247 validateEvents(HOST_ADDED, HOST_REMOVED);
248
249 assertNull("host should have been removed", mgr.getHost(HID1));
250 }
251
Kunihiro Ishiguro1eab7d52015-02-10 10:38:18 +0900252 @Test
253 public void hostVanishedIPv6() {
254 detect(HID3, MAC3, VLAN1, LOC1, IP3);
255 providerService.hostVanished(HID3);
256 validateEvents(HOST_ADDED, HOST_REMOVED);
257
258 assertNull("host should have been removed", mgr.getHost(HID3));
259 }
260
Charles Chan29ecdee2017-02-22 18:46:56 -0800261 /**
262 * Providers should only be able to remove a host provided by itself.
263 */
264 @Test
265 public void hostVanishedWithMultipleProviders() {
266 detect(HID1, MAC1, VLAN1, LOC1, IP1);
267 configured(HID2, MAC2, VLAN2, LOC2, IP2);
268
269 providerService2.hostVanished(HID1);
270 assertNotNull("host should not be removed", mgr.getHost(HID1));
271
272 providerService.hostVanished(HID2);
273 assertNotNull("host should not be removed", mgr.getHost(HID2));
274
275 providerService.hostVanished(HID1);
276 assertNull("host should be removed", mgr.getHost(HID1));
277
278 providerService2.hostVanished(HID2);
279 assertNull("host should be removed", mgr.getHost(HID2));
280 }
281
Jonathan Hart38feb6e2016-08-29 22:54:16 +0000282 private void validateHosts(
283 String msg, Iterable<Host> hosts, HostId... ids) {
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700284 Set<HostId> hids = Sets.newHashSet(ids);
285 for (Host h : hosts) {
286 assertTrue(msg, hids.remove(h.id()));
287 }
288 assertTrue("expected hosts not fetched from store", hids.isEmpty());
289 }
290
291 @Test
292 public void getHosts() {
tom093340b2014-10-10 00:15:36 -0700293 detect(HID1, MAC1, VLAN1, LOC1, IP1);
294 detect(HID2, MAC2, VLAN1, LOC2, IP2);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700295
296 validateHosts("host not properly stored", mgr.getHosts(), HID1, HID2);
297 validateHosts("can't get hosts by VLAN", mgr.getHostsByVlan(VLAN1), HID1, HID2);
298 validateHosts("can't get hosts by MAC", mgr.getHostsByMac(MAC1), HID1);
299 validateHosts("can't get hosts by IP", mgr.getHostsByIp(IP1), HID1);
300 validateHosts("can't get hosts by location", mgr.getConnectedHosts(LOC1), HID1);
301 assertTrue("incorrect host location", mgr.getConnectedHosts(DID2).isEmpty());
302 }
303
Kunihiro Ishiguro1eab7d52015-02-10 10:38:18 +0900304 @Test
305 public void getHostsIPv6() {
306 detect(HID3, MAC3, VLAN1, LOC1, IP3);
307 detect(HID4, MAC4, VLAN1, LOC2, IP4);
308
309 validateHosts("host not properly stored", mgr.getHosts(), HID3, HID4);
310 validateHosts("can't get hosts by VLAN", mgr.getHostsByVlan(VLAN1), HID3, HID4);
311 validateHosts("can't get hosts by MAC", mgr.getHostsByMac(MAC3), HID3);
312 validateHosts("can't get hosts by IP", mgr.getHostsByIp(IP3), HID3);
313 validateHosts("can't get hosts by location", mgr.getConnectedHosts(LOC1), HID3);
314 assertTrue("incorrect host location", mgr.getConnectedHosts(DID2).isEmpty());
315 }
316
Jonathan Hart38feb6e2016-08-29 22:54:16 +0000317 private static class TestHostProvider extends AbstractProvider
318 implements HostProvider {
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700319
Charles Chan29ecdee2017-02-22 18:46:56 -0800320 protected TestHostProvider(ProviderId pid) {
321 super(pid);
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700322 }
323
324 @Override
325 public void triggerProbe(Host host) {
326 }
327
328 }
329
330 private static class TestListener implements HostListener {
331
332 protected List<HostEvent> events = Lists.newArrayList();
333
334 @Override
335 public void event(HostEvent event) {
336 events.add(event);
337 }
338
339 }
Jonathan Hartc884f1b2014-09-24 11:53:33 -0700340
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700341 private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
342 }
Ayaka Koshibeac8e7292014-09-16 16:08:31 -0700343}