blob: 314fef69326638a5ccb5b51eb0c370701baab39b [file] [log] [blame]
Charles Chan2e2e3402017-06-19 14:00:53 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Charles Chan2e2e3402017-06-19 14:00:53 -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 */
16
17package org.onosproject.segmentrouting;
18
Charles Chan65238242017-06-22 18:03:14 -070019import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.ObjectMapper;
Charles Chan9f08b102017-08-09 16:50:15 -070021import com.google.common.collect.ImmutableSet;
Charles Chan2e2e3402017-06-19 14:00:53 -070022import com.google.common.collect.Lists;
23import com.google.common.collect.Maps;
24import com.google.common.collect.Sets;
25import org.junit.Before;
26import org.junit.Test;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.IpPrefix;
29import org.onlab.packet.MacAddress;
30import org.onlab.packet.VlanId;
31import org.onosproject.core.DefaultApplicationId;
Charles Chan9f08b102017-08-09 16:50:15 -070032import org.onosproject.mastership.MastershipServiceAdapter;
Ray Milkeyfacf2862017-08-03 11:58:29 -070033import org.onosproject.net.intf.Interface;
34import org.onosproject.net.intf.InterfaceServiceAdapter;
Charles Chan2e2e3402017-06-19 14:00:53 -070035import org.onosproject.net.ConnectPoint;
36import org.onosproject.net.DefaultHost;
37import org.onosproject.net.DeviceId;
38import org.onosproject.net.Host;
39import org.onosproject.net.HostId;
40import org.onosproject.net.HostLocation;
41import org.onosproject.net.PortNumber;
Charles Chan65238242017-06-22 18:03:14 -070042import org.onosproject.net.config.Config;
43import org.onosproject.net.config.ConfigApplyDelegate;
Charles Chan2e2e3402017-06-19 14:00:53 -070044import org.onosproject.net.config.NetworkConfigRegistryAdapter;
45import org.onosproject.net.flow.TrafficSelector;
46import org.onosproject.net.flow.TrafficTreatment;
47import org.onosproject.net.flow.criteria.Criterion;
48import org.onosproject.net.flow.criteria.EthCriterion;
49import org.onosproject.net.flow.criteria.VlanIdCriterion;
50import org.onosproject.net.flow.instructions.Instruction;
51import org.onosproject.net.flow.instructions.Instructions;
52import org.onosproject.net.flow.instructions.L2ModificationInstruction;
53import org.onosproject.net.flowobjective.FlowObjectiveServiceAdapter;
54import org.onosproject.net.flowobjective.ForwardingObjective;
55import org.onosproject.net.flowobjective.Objective;
56import org.onosproject.net.host.HostEvent;
Charles Chanf9a52702017-06-16 15:19:24 -070057import org.onosproject.net.host.HostServiceAdapter;
Charles Chan2e2e3402017-06-19 14:00:53 -070058import org.onosproject.net.host.InterfaceIpAddress;
59import org.onosproject.net.provider.ProviderId;
60import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan65238242017-06-22 18:03:14 -070061import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chan2e2e3402017-06-19 14:00:53 -070062
63import java.util.Map;
64import java.util.Objects;
65import java.util.Set;
66import java.util.concurrent.atomic.AtomicInteger;
67
68import static org.junit.Assert.*;
69
70/**
71 * Unit test for {@link HostHandler}.
72 */
73public class HostHandlerTest {
74 private SegmentRoutingManager srManager;
75 private HostHandler hostHandler;
76
77 // Mocked routing and bridging tables
78 private Map<BridingTableKey, BridingTableValue> bridgingTable = Maps.newConcurrentMap();
79 private Map<RoutingTableKey, RoutingTableValue> routingTable = Maps.newConcurrentMap();
80 // Mocked Next Id
81 private Map<Integer, TrafficTreatment> nextTable = Maps.newConcurrentMap();
82 private AtomicInteger atomicNextId = new AtomicInteger();
83
Charles Chanf9a52702017-06-16 15:19:24 -070084 // Host Mac, VLAN
Charles Chan2e2e3402017-06-19 14:00:53 -070085 private static final ProviderId PROVIDER_ID = ProviderId.NONE;
86 private static final MacAddress HOST_MAC = MacAddress.valueOf("00:00:00:00:00:01");
87 private static final VlanId HOST_VLAN_UNTAGGED = VlanId.NONE;
88 private static final HostId HOST_ID_UNTAGGED = HostId.hostId(HOST_MAC, HOST_VLAN_UNTAGGED);
89 private static final VlanId HOST_VLAN_TAGGED = VlanId.vlanId((short) 20);
90 private static final HostId HOST_ID_TAGGED = HostId.hostId(HOST_MAC, HOST_VLAN_TAGGED);
Charles Chanf9a52702017-06-16 15:19:24 -070091 // Host IP
92 private static final IpAddress HOST_IP11 = IpAddress.valueOf("10.0.1.1");
93 private static final IpAddress HOST_IP21 = IpAddress.valueOf("10.0.2.1");
94 private static final IpAddress HOST_IP12 = IpAddress.valueOf("10.0.1.2");
95 private static final IpAddress HOST_IP13 = IpAddress.valueOf("10.0.1.3");
96 private static final IpAddress HOST_IP14 = IpAddress.valueOf("10.0.1.4");
97 // Device
98 private static final DeviceId DEV1 = DeviceId.deviceId("of:0000000000000001");
99 private static final DeviceId DEV2 = DeviceId.deviceId("of:0000000000000002");
Charles Chan9f08b102017-08-09 16:50:15 -0700100 private static final DeviceId DEV3 = DeviceId.deviceId("of:0000000000000003");
101 private static final DeviceId DEV4 = DeviceId.deviceId("of:0000000000000004");
102 private static final DeviceId DEV5 = DeviceId.deviceId("of:0000000000000005");
103 private static final DeviceId DEV6 = DeviceId.deviceId("of:0000000000000006");
Charles Chanf9a52702017-06-16 15:19:24 -0700104 // Port
105 private static final PortNumber P1 = PortNumber.portNumber(1);
106 private static final PortNumber P2 = PortNumber.portNumber(2);
107 private static final PortNumber P3 = PortNumber.portNumber(3);
Charles Chan65238242017-06-22 18:03:14 -0700108 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanf9a52702017-06-16 15:19:24 -0700109 // Connect Point
110 private static final ConnectPoint CP11 = new ConnectPoint(DEV1, P1);
111 private static final HostLocation HOST_LOC11 = new HostLocation(CP11, 0);
112 private static final ConnectPoint CP12 = new ConnectPoint(DEV1, P2);
113 private static final HostLocation HOST_LOC12 = new HostLocation(CP12, 0);
114 private static final ConnectPoint CP13 = new ConnectPoint(DEV1, P3);
115 private static final HostLocation HOST_LOC13 = new HostLocation(CP13, 0);
116 private static final ConnectPoint CP21 = new ConnectPoint(DEV2, P1);
117 private static final HostLocation HOST_LOC21 = new HostLocation(CP21, 0);
118 private static final ConnectPoint CP22 = new ConnectPoint(DEV2, P2);
119 private static final HostLocation HOST_LOC22 = new HostLocation(CP22, 0);
Charles Chan65238242017-06-22 18:03:14 -0700120 // Connect Point for dual-homed host failover
121 private static final ConnectPoint CP31 = new ConnectPoint(DEV3, P1);
122 private static final HostLocation HOST_LOC31 = new HostLocation(CP31, 0);
123 private static final ConnectPoint CP41 = new ConnectPoint(DEV4, P1);
124 private static final HostLocation HOST_LOC41 = new HostLocation(CP41, 0);
125 private static final ConnectPoint CP39 = new ConnectPoint(DEV3, P9);
126 private static final ConnectPoint CP49 = new ConnectPoint(DEV4, P9);
Charles Chan9f08b102017-08-09 16:50:15 -0700127 // Conenct Point for mastership test
128 private static final ConnectPoint CP51 = new ConnectPoint(DEV5, P1);
129 private static final HostLocation HOST_LOC51 = new HostLocation(CP51, 0);
130 private static final ConnectPoint CP61 = new ConnectPoint(DEV6, P1);
131 private static final HostLocation HOST_LOC61 = new HostLocation(CP61, 0);
Charles Chanf9a52702017-06-16 15:19:24 -0700132 // Interface VLAN
Charles Chan2e2e3402017-06-19 14:00:53 -0700133 private static final VlanId INTF_VLAN_UNTAGGED = VlanId.vlanId((short) 10);
Charles Chan2e2e3402017-06-19 14:00:53 -0700134 private static final Set<VlanId> INTF_VLAN_TAGGED = Sets.newHashSet(VlanId.vlanId((short) 20));
135 private static final VlanId INTF_VLAN_NATIVE = VlanId.vlanId((short) 30);
Charles Chan65238242017-06-22 18:03:14 -0700136 private static final Set<VlanId> INTF_VLAN_PAIR = Sets.newHashSet(VlanId.vlanId((short) 10),
137 VlanId.vlanId((short) 20), VlanId.vlanId((short) 30));
Charles Chanf9a52702017-06-16 15:19:24 -0700138 // Interface subnet
139 private static final IpPrefix INTF_PREFIX1 = IpPrefix.valueOf("10.0.1.254/24");
140 private static final IpPrefix INTF_PREFIX2 = IpPrefix.valueOf("10.0.2.254/24");
141 private static final InterfaceIpAddress INTF_IP1 =
142 new InterfaceIpAddress(INTF_PREFIX1.address(), INTF_PREFIX1);
143 private static final InterfaceIpAddress INTF_IP2 =
144 new InterfaceIpAddress(INTF_PREFIX2.address(), INTF_PREFIX2);
145 // Host
146 private static final Host HOST1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC,
147 HOST_VLAN_UNTAGGED, Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11),
148 false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700149
150 @Before
151 public void setUp() throws Exception {
152 srManager = new MockSegmentRoutingManager();
153 srManager.cfgService = new NetworkConfigRegistryAdapter();
154 srManager.deviceConfiguration = new DeviceConfiguration(srManager);
155 srManager.flowObjectiveService = new MockFlowObjectiveService();
156 srManager.routingRulePopulator = new MockRoutingRulePopulator();
157 srManager.interfaceService = new MockInterfaceService();
Charles Chan9f08b102017-08-09 16:50:15 -0700158 srManager.mastershipService = new MockMastershipService();
Charles Chanf9a52702017-06-16 15:19:24 -0700159 srManager.hostService = new MockHostService();
Charles Chan65238242017-06-22 18:03:14 -0700160 srManager.cfgService = new MockNetworkConfigRegistry();
Charles Chan2e2e3402017-06-19 14:00:53 -0700161
162 hostHandler = new HostHandler(srManager);
163
164 routingTable.clear();
165 bridgingTable.clear();
166 }
167
168 @Test
169 public void init() throws Exception {
Charles Chanf9a52702017-06-16 15:19:24 -0700170 hostHandler.init(DEV1);
171 assertEquals(1, routingTable.size());
172 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
173 assertEquals(1, bridgingTable.size());
174 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
175
176 hostHandler.init(DEV2);
177 assertEquals(2, routingTable.size());
178 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
179 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
180 assertEquals(2, bridgingTable.size());
181 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
182 assertNotNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
183 }
184
185 @Test(expected = IllegalArgumentException.class)
186 public void testHostAddedAtWrongLocation() throws Exception {
187 hostHandler.processHostAddedAtLocation(HOST1, HOST_LOC13);
188 }
189
190
191 @Test()
192 public void testHostAddedAtCorrectLocation() throws Exception {
193 hostHandler.processHostAddedAtLocation(HOST1, HOST_LOC11);
194 assertEquals(1, routingTable.size());
195 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
196 assertEquals(1, bridgingTable.size());
197 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700198 }
199
200 @Test
201 public void testHostAdded() throws Exception {
202 Host subject;
203
204 // Untagged host discovered on untagged port
205 // Expect: add one routing rule and one bridging rule
206 subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700207 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700208 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
209 assertEquals(1, routingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700210 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
Charles Chan2e2e3402017-06-19 14:00:53 -0700211 assertEquals(1, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700212 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700213
214 // Untagged host discovered on tagged/native port
215 // Expect: add one routing rule and one bridging rule
216 subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700217 Sets.newHashSet(HOST_LOC13), Sets.newHashSet(HOST_IP21), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700218 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
219 assertEquals(2, routingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700220 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
Charles Chan2e2e3402017-06-19 14:00:53 -0700221 assertEquals(2, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700222 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_NATIVE)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700223
224 // Tagged host discovered on untagged port
225 // Expect: ignore the host. No rule is added.
226 subject = new DefaultHost(PROVIDER_ID, HOST_ID_TAGGED, HOST_MAC, HOST_VLAN_TAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700227 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700228 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
229 assertEquals(2, routingTable.size());
230 assertEquals(2, bridgingTable.size());
231
232 // Tagged host discovered on tagged port with the same IP
233 // Expect: update existing route, add one bridging rule
234 subject = new DefaultHost(PROVIDER_ID, HOST_ID_TAGGED, HOST_MAC, HOST_VLAN_TAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700235 Sets.newHashSet(HOST_LOC13), Sets.newHashSet(HOST_IP21), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700236 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
237 assertEquals(2, routingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700238 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
239 assertEquals(HOST_VLAN_TAGGED, routingTable.get(new RoutingTableKey(HOST_LOC13.deviceId(),
240 HOST_IP21.toIpPrefix())).vlanId);
Charles Chan2e2e3402017-06-19 14:00:53 -0700241 assertEquals(3, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700242 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, HOST_VLAN_TAGGED)));
243 }
244
245 @Test
246 public void testDualHomedHostAdded() throws Exception {
247 // Add a dual-homed host that has 2 locations
248 // Expect: add two routing rules and two bridging rules
249 Host subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
250 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11), false);
251 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
252 assertEquals(2, routingTable.size());
253 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
254 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
255 assertEquals(2, bridgingTable.size());
256 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
257 assertNotNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700258 }
259
260 @Test
261 public void testHostRemoved() throws Exception {
262 Host subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700263 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700264
265 // Add a host
266 // Expect: add one routing rule and one bridging rule
267 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
268 assertEquals(1, routingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700269 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
Charles Chan2e2e3402017-06-19 14:00:53 -0700270 assertEquals(1, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700271 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700272
273 // Remove the host
274 // Expect: add the routing rule and the bridging rule
Charles Chanf9a52702017-06-16 15:19:24 -0700275 hostHandler.processHostRemovedEvent(new HostEvent(HostEvent.Type.HOST_REMOVED, subject));
Charles Chan2e2e3402017-06-19 14:00:53 -0700276 assertEquals(0, routingTable.size());
Charles Chan2e2e3402017-06-19 14:00:53 -0700277 assertEquals(0, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700278 }
279
280 @Test
281 public void testDualHomedHostRemoved() throws Exception {
282 // Add a dual-homed host that has 2 locations
283 // Expect: add two routing rules and two bridging rules
284 Host subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
285 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11), false);
286 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
287 assertEquals(2, routingTable.size());
288 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
289 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
290 assertEquals(2, bridgingTable.size());
291 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
292 assertNotNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
293
294 // Remove a dual-homed host that has 2 locations
295 // Expect: all routing and bridging rules are removed
296 hostHandler.processHostRemovedEvent(new HostEvent(HostEvent.Type.HOST_REMOVED, subject));
297 assertEquals(0, routingTable.size());
298 assertEquals(0, bridgingTable.size());
Charles Chan2e2e3402017-06-19 14:00:53 -0700299 }
300
301 @Test
302 public void testHostMoved() throws Exception {
303 Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700304 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700305 Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700306 Sets.newHashSet(HOST_LOC21), Sets.newHashSet(HOST_IP11), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700307 Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700308 Sets.newHashSet(HOST_LOC13), Sets.newHashSet(HOST_IP11), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700309
310 // Add a host
Charles Chan65238242017-06-22 18:03:14 -0700311 // Expect: add one new routing rule, one new bridging rule
Charles Chan2e2e3402017-06-19 14:00:53 -0700312 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
313 assertEquals(1, routingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700314 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
315 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
316 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP13.toIpPrefix())));
Charles Chan2e2e3402017-06-19 14:00:53 -0700317 assertEquals(1, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700318 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
319 assertNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700320
Charles Chanf9a52702017-06-16 15:19:24 -0700321 // Move the host to CP13, which has different subnet setting
Charles Chan2e2e3402017-06-19 14:00:53 -0700322 // Expect: remove routing rule. Change vlan in bridging rule.
Charles Chanf9a52702017-06-16 15:19:24 -0700323 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host3, host1));
Charles Chan2e2e3402017-06-19 14:00:53 -0700324 assertEquals(0, routingTable.size());
Charles Chan2e2e3402017-06-19 14:00:53 -0700325 assertEquals(1, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700326 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_NATIVE)));
327 assertNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700328
Charles Chanf9a52702017-06-16 15:19:24 -0700329 // Move the host to CP21, which has same subnet setting
Charles Chan2e2e3402017-06-19 14:00:53 -0700330 // Expect: add a new routing rule. Change vlan in bridging rule.
Charles Chanf9a52702017-06-16 15:19:24 -0700331 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host3));
Charles Chan2e2e3402017-06-19 14:00:53 -0700332 assertEquals(1, routingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700333 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
334 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
335 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
Charles Chan2e2e3402017-06-19 14:00:53 -0700336 assertEquals(1, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700337 assertNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
338 assertNotNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
339 }
340
341 @Test
342 public void testDualHomedHostMoved() throws Exception {
343 Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
344 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
345 Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
346 Sets.newHashSet(HOST_LOC12, HOST_LOC22), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
347 Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
348 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP13, HOST_IP14), false);
349 Host host4 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
350 Sets.newHashSet(HOST_LOC11, HOST_LOC22), Sets.newHashSet(HOST_IP12, HOST_IP13), false);
351
352 // Add a host with IP11, IP12 and LOC11, LOC21
353 // Expect: 4 routing rules and 2 bridging rules
354 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
355 assertEquals(4, routingTable.size());
356 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
357 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
358 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
359 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV2, HOST_IP12.toIpPrefix())).portNumber);
360 assertEquals(2, bridgingTable.size());
361 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
362 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
363
364 // Move the host to LOC12, LOC22 and keep the IP
365 // Expect: 4 routing rules and 2 bridging rules all at the new location
366 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
367 assertEquals(4, routingTable.size());
368 assertEquals(P2, routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
369 assertEquals(P2, routingTable.get(new RoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
370 assertEquals(P2, routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
371 assertEquals(P2, routingTable.get(new RoutingTableKey(DEV2, HOST_IP12.toIpPrefix())).portNumber);
372 assertEquals(2, bridgingTable.size());
373 assertEquals(P2, bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
374 assertEquals(P2, bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
375
376 // Move the host to LOC11, LOC21 and change the IP to IP13, IP14 at the same time
377 // Expect: 4 routing rules and 2 bridging rules all at the new location
378 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host3, host2));
379 assertEquals(4, routingTable.size());
380 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP13.toIpPrefix())).portNumber);
381 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP14.toIpPrefix())).portNumber);
382 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV2, HOST_IP13.toIpPrefix())).portNumber);
383 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV2, HOST_IP14.toIpPrefix())).portNumber);
384 assertEquals(2, bridgingTable.size());
385 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
386 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
387
388 // Move the host to LOC11, LOC22 and change the IP to IP12, IP13 at the same time
389 // Expect: 4 routing rules and 2 bridging rules all at the new location
390 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host4, host3));
391 assertEquals(4, routingTable.size());
392 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
393 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP13.toIpPrefix())).portNumber);
394 assertEquals(P2, routingTable.get(new RoutingTableKey(DEV2, HOST_IP12.toIpPrefix())).portNumber);
395 assertEquals(P2, routingTable.get(new RoutingTableKey(DEV2, HOST_IP13.toIpPrefix())).portNumber);
396 assertEquals(2, bridgingTable.size());
397 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
398 assertEquals(P2, bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
Charles Chan2e2e3402017-06-19 14:00:53 -0700399 }
400
401 @Test
Charles Chan9f08b102017-08-09 16:50:15 -0700402 public void testHostMoveToInvalidLocation() throws Exception {
403 Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
404 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
405 Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
406 Sets.newHashSet(HOST_LOC51), Sets.newHashSet(HOST_IP11), false);
407
408 // Add a host
409 // Expect: add one new routing rule, one new bridging rule
410 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
411 assertEquals(1, routingTable.size());
412 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
413 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
414 assertEquals(1, bridgingTable.size());
415 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
416 assertNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
417
418 // Move the host to an invalid location
419 // Expect: Old flow is removed. New flow is not created
420 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
421 assertEquals(0, routingTable.size());
422 assertEquals(0, bridgingTable.size());
423
424 // Move the host to a valid location
425 // Expect: add one new routing rule, one new bridging rule
426 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host1, host2));
427 assertEquals(1, routingTable.size());
428 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
429 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
430 assertEquals(1, bridgingTable.size());
431 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
432 assertNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
433 }
434
435 @Test
436 public void testDualHomedHostMoveToInvalidLocation() throws Exception {
437 Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
438 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11), false);
439 Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
440 Sets.newHashSet(HOST_LOC11, HOST_LOC51), Sets.newHashSet(HOST_IP11), false);
441 Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
442 Sets.newHashSet(HOST_LOC61, HOST_LOC51), Sets.newHashSet(HOST_IP11), false);
443
444 // Add a host
445 // Expect: add two new routing rules, two new bridging rules
446 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
447 assertEquals(2, routingTable.size());
448 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
449 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
450 assertEquals(2, bridgingTable.size());
451 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
452 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
453
454 // Move first host location to an invalid location
455 // Expect: One routing and one bridging flow
456 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
457 assertEquals(1, routingTable.size());
458 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
459 assertEquals(1, bridgingTable.size());
460 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
461
462 // Move second host location to an invalid location
463 // Expect: No routing or bridging rule
464 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host3, host2));
465 assertEquals(0, routingTable.size());
466 assertEquals(0, bridgingTable.size());
467
468 // Move second host location back to a valid location
469 // Expect: One routing and one bridging flow
470 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host3));
471 assertEquals(1, routingTable.size());
472 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
473 assertEquals(1, bridgingTable.size());
474 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
475
476 // Move first host location back to a valid location
477 // Expect: Two routing and two bridging flow
478 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host1, host2));
479 assertEquals(2, routingTable.size());
480 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
481 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
482 assertEquals(2, bridgingTable.size());
483 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
484 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
485 }
486
487 @Test
Charles Chan65238242017-06-22 18:03:14 -0700488 public void testDualHomingSingleLocationFail() throws Exception {
489 Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
490 Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
491 Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
492 Sets.newHashSet(HOST_LOC31), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
493
494 // Add a host
495 // Expect: add four new routing rules, two new bridging rules
496 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
497 assertEquals(4, routingTable.size());
498 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
499 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
500 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
501 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
502 assertEquals(2, bridgingTable.size());
503 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
504 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
505
506 // Host becomes single-homed
507 // Expect: redirect flows from host location to pair link
508 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
509 assertEquals(4, routingTable.size());
510 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
511 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
512 assertEquals(P9, routingTable.get(new RoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
513 assertEquals(P9, routingTable.get(new RoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
514 assertEquals(2, bridgingTable.size());
515 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
516 assertEquals(P9, bridgingTable.get(new BridingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
517
518 // Host becomes dual-homed again
519 // Expect: Redirect flows from pair link back to host location
520 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host1, host2));
521 assertEquals(4, routingTable.size());
522 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
523 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
524 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
525 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
526 assertEquals(2, bridgingTable.size());
527 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
528 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
529 }
530
531 @Test
532 public void testDualHomingBothLocationFail() throws Exception {
533 Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
534 Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
535 Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
536 Sets.newHashSet(HOST_LOC31), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
537
538 // Add a host
539 // Expect: add four new routing rules, two new bridging rules
540 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
541 assertEquals(4, routingTable.size());
542 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
543 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
544 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
545 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
546 assertEquals(2, bridgingTable.size());
547 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
548 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
549
550 // Host becomes single-homed
551 // Expect: redirect flows from host location to pair link
552 hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
553 assertEquals(4, routingTable.size());
554 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
555 assertEquals(P1, routingTable.get(new RoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
556 assertEquals(P9, routingTable.get(new RoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
557 assertEquals(P9, routingTable.get(new RoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
558 assertEquals(2, bridgingTable.size());
559 assertEquals(P1, bridgingTable.get(new BridingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
560 assertEquals(P9, bridgingTable.get(new BridingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
561
562 // Host loses both locations
563 // Expect: Remove last location and all previous redirection flows
564 hostHandler.processHostRemovedEvent(new HostEvent(HostEvent.Type.HOST_REMOVED, host2));
565 assertEquals(0, routingTable.size());
566 assertEquals(0, bridgingTable.size());
567 }
568
569 @Test
Charles Chan2e2e3402017-06-19 14:00:53 -0700570 public void testHostUpdated() throws Exception {
571 Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700572 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700573 Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700574 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP21), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700575 Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
Charles Chanf9a52702017-06-16 15:19:24 -0700576 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP12), false);
Charles Chan2e2e3402017-06-19 14:00:53 -0700577
578 // Add a host
Charles Chanf9a52702017-06-16 15:19:24 -0700579 // Expect: add one new routing rule. Add one new bridging rule.
Charles Chan2e2e3402017-06-19 14:00:53 -0700580 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
581 assertEquals(1, routingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700582 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
583 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
584 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
Charles Chan2e2e3402017-06-19 14:00:53 -0700585 assertEquals(1, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700586 assertNotNull(bridgingTable.get(new BridingTableKey(HOST_LOC11.deviceId(), HOST_MAC, INTF_VLAN_UNTAGGED)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700587
588 // Update the host IP to same subnet
589 // Expect: update routing rule with new IP. No change to bridging rule.
590 hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host3, host1));
591 assertEquals(1, routingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700592 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
593 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
594 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
Charles Chan2e2e3402017-06-19 14:00:53 -0700595 assertEquals(1, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700596 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
Charles Chan2e2e3402017-06-19 14:00:53 -0700597
598 // Update the host IP to different subnet
599 // Expect: Remove routing rule. No change to bridging rule.
600 hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host2, host3));
601 assertEquals(0, routingTable.size());
Charles Chan2e2e3402017-06-19 14:00:53 -0700602 assertEquals(1, bridgingTable.size());
Charles Chanf9a52702017-06-16 15:19:24 -0700603 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
604 }
605
606 @Test
607 public void testDualHomedHostUpdated() throws Exception {
608 Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
609 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
610 Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
611 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11, HOST_IP21), false);
612 Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
613 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP13, HOST_IP14), false);
614
615 // Add a dual-homed host with two locations and two IPs
616 // Expect: add four new routing rules. Add two new bridging rules
617 hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
618 assertEquals(4, routingTable.size());
619 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
620 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
621 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
622 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP12.toIpPrefix())));
623 assertEquals(2, bridgingTable.size());
624 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
625 assertNotNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
626
627 // Update both host IPs
628 // Expect: update routing rules with new IP. No change to bridging rule.
629 hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host3, host1));
630 assertEquals(4, routingTable.size());
631 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
632 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
633 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP13.toIpPrefix())));
634 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP14.toIpPrefix())));
635 assertNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
636 assertNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP12.toIpPrefix())));
637 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP13.toIpPrefix())));
638 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP14.toIpPrefix())));
639 assertEquals(2, bridgingTable.size());
640 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
641 assertNotNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
642
643 // Update one of the host IP to different subnet
644 // Expect: update routing rule with new IP. No change to bridging rule.
645 hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host2, host3));
646 assertEquals(2, routingTable.size());
647 assertNotNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
648 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
649 assertNull(routingTable.get(new RoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
650 assertNotNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
651 assertNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP21.toIpPrefix())));
652 assertNull(routingTable.get(new RoutingTableKey(DEV2, HOST_IP12.toIpPrefix())));
653 assertEquals(2, bridgingTable.size());
654 assertNotNull(bridgingTable.get(new BridingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
655 assertNotNull(bridgingTable.get(new BridingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
656 }
657
658 @Test
659 public void testBridgingFwdObjBuilder() throws Exception {
660 assertNotNull(hostHandler.bridgingFwdObjBuilder(DEV2, HOST_MAC, HOST_VLAN_UNTAGGED, P1, false));
661 assertNull(hostHandler.bridgingFwdObjBuilder(DEV2, HOST_MAC, HOST_VLAN_UNTAGGED, P3, false));
Charles Chan2e2e3402017-06-19 14:00:53 -0700662 }
663
664 class MockSegmentRoutingManager extends SegmentRoutingManager {
665 MockSegmentRoutingManager() {
666 appId = new DefaultApplicationId(1, SegmentRoutingManager.APP_NAME);
667 }
668
669 @Override
670 public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
671 TrafficTreatment treatment,
672 TrafficSelector meta,
673 boolean createIfMissing) {
674 int nextId = atomicNextId.incrementAndGet();
675 nextTable.put(nextId, treatment);
676 return nextId;
677 }
678 }
679
680 class MockInterfaceService extends InterfaceServiceAdapter {
681 @Override
682 public Set<Interface> getInterfacesByPort(ConnectPoint cp) {
683 Interface intf = null;
684
Charles Chanf9a52702017-06-16 15:19:24 -0700685 if (CP11.equals(cp)) {
686 intf = new Interface(null, CP11, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
Charles Chan2e2e3402017-06-19 14:00:53 -0700687 INTF_VLAN_UNTAGGED, null, null);
Charles Chanf9a52702017-06-16 15:19:24 -0700688 } else if (CP12.equals(cp)) {
689 intf = new Interface(null, CP12, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
690 INTF_VLAN_UNTAGGED, null, null);
691 } else if (CP13.equals(cp)) {
692 intf = new Interface(null, CP13, Lists.newArrayList(INTF_IP2), MacAddress.NONE, null,
Charles Chan2e2e3402017-06-19 14:00:53 -0700693 null, INTF_VLAN_TAGGED, INTF_VLAN_NATIVE);
Charles Chanf9a52702017-06-16 15:19:24 -0700694 } else if (CP21.equals(cp)) {
695 intf = new Interface(null, CP21, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
696 INTF_VLAN_UNTAGGED, null, null);
697 } else if (CP22.equals(cp)) {
698 intf = new Interface(null, CP22, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
Charles Chan2e2e3402017-06-19 14:00:53 -0700699 INTF_VLAN_UNTAGGED, null, null);
Charles Chan65238242017-06-22 18:03:14 -0700700 } else if (CP31.equals(cp)) {
701 intf = new Interface(null, CP31, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
702 INTF_VLAN_UNTAGGED, null, null);
703 } else if (CP39.equals(cp)) {
704 intf = new Interface(null, CP39, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
705 null, INTF_VLAN_PAIR, null);
706 } else if (CP41.equals(cp)) {
707 intf = new Interface(null, CP41, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
708 INTF_VLAN_UNTAGGED, null, null);
709 } else if (CP49.equals(cp)) {
710 intf = new Interface(null, CP49, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
711 null, INTF_VLAN_PAIR, null);
Charles Chan2e2e3402017-06-19 14:00:53 -0700712 }
Charles Chan2e2e3402017-06-19 14:00:53 -0700713 return Objects.nonNull(intf) ? Sets.newHashSet(intf) : Sets.newHashSet();
714 }
715 }
716
Charles Chan9f08b102017-08-09 16:50:15 -0700717 class MockMastershipService extends MastershipServiceAdapter {
718 @Override
719 public boolean isLocalMaster(DeviceId deviceId) {
720 Set<DeviceId> localDevices = ImmutableSet.of(DEV1, DEV2, DEV3, DEV4);
721 return localDevices.contains(deviceId);
722 }
723 }
724
Charles Chan65238242017-06-22 18:03:14 -0700725 class MockNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
726 @Override
727 public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
728 if (subject instanceof DeviceId) {
729 DeviceId deviceId = (DeviceId) subject;
730 ObjectMapper mapper = new ObjectMapper();
731 ConfigApplyDelegate delegate = new MockCfgDelegate();
732 JsonNode emptyTree = new ObjectMapper().createObjectNode();
733
734 SegmentRoutingDeviceConfig config = new SegmentRoutingDeviceConfig();
735 config.init(deviceId, "host-handler-test", emptyTree, mapper, delegate);
736 config.setPairDeviceId(subject.equals(DEV3) ? DEV4 : DEV3)
737 .setPairLocalPort(P9);
738
739 return (C) config;
740 } else {
741 return null;
742 }
743 }
744 }
745
746 class MockCfgDelegate implements ConfigApplyDelegate {
747 @Override
748 public void onApply(@SuppressWarnings("rawtypes") Config config) {
749 config.apply();
750 }
751 }
752
Charles Chan2e2e3402017-06-19 14:00:53 -0700753 class MockFlowObjectiveService extends FlowObjectiveServiceAdapter {
754 @Override
755 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
756 TrafficSelector selector = forwardingObjective.selector();
757 TrafficTreatment treatment = nextTable.get(forwardingObjective.nextId());
758 MacAddress macAddress = ((EthCriterion) selector.getCriterion(Criterion.Type.ETH_DST)).mac();
759 VlanId vlanId = ((VlanIdCriterion) selector.getCriterion(Criterion.Type.VLAN_VID)).vlanId();
760
761 boolean popVlan = treatment.allInstructions().stream()
762 .filter(instruction -> instruction.type().equals(Instruction.Type.L2MODIFICATION))
763 .anyMatch(instruction -> ((L2ModificationInstruction) instruction).subtype()
764 .equals(L2ModificationInstruction.L2SubType.VLAN_POP));
765 PortNumber portNumber = treatment.allInstructions().stream()
766 .filter(instruction -> instruction.type().equals(Instruction.Type.OUTPUT))
767 .map(instruction -> ((Instructions.OutputInstruction) instruction).port()).findFirst().orElse(null);
768 if (portNumber == null) {
769 throw new IllegalArgumentException();
770 }
771
772 Objective.Operation op = forwardingObjective.op();
773
774 BridingTableKey btKey = new BridingTableKey(deviceId, macAddress, vlanId);
775 BridingTableValue btValue = new BridingTableValue(popVlan, portNumber);
776
777 if (op.equals(Objective.Operation.ADD)) {
778 bridgingTable.put(btKey, btValue);
779 } else if (op.equals(Objective.Operation.REMOVE)) {
780 bridgingTable.remove(btKey, btValue);
781 } else {
782 throw new IllegalArgumentException();
783 }
784 }
785 }
786
Charles Chanf9a52702017-06-16 15:19:24 -0700787 class MockHostService extends HostServiceAdapter {
788 @Override
789 public Set<Host> getHosts() {
790 return Sets.newHashSet(HOST1);
791 }
792 }
793
Charles Chan2e2e3402017-06-19 14:00:53 -0700794 class MockRoutingRulePopulator extends RoutingRulePopulator {
795 MockRoutingRulePopulator() {
796 super(srManager);
797 }
798
799 @Override
800 public void populateRoute(DeviceId deviceId, IpPrefix prefix,
801 MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
802 RoutingTableKey rtKey = new RoutingTableKey(deviceId, prefix);
803 RoutingTableValue rtValue = new RoutingTableValue(outPort, hostMac, hostVlanId);
804 routingTable.put(rtKey, rtValue);
805 }
806
807 @Override
808 public void revokeRoute(DeviceId deviceId, IpPrefix prefix,
809 MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
810 RoutingTableKey rtKey = new RoutingTableKey(deviceId, prefix);
811 RoutingTableValue rtValue = new RoutingTableValue(outPort, hostMac, hostVlanId);
812 routingTable.remove(rtKey, rtValue);
813 }
814 }
815
816 class BridingTableKey {
817 DeviceId deviceId;
818 MacAddress macAddress;
819 VlanId vlanId;
820
821 BridingTableKey(DeviceId deviceId, MacAddress macAddress, VlanId vlanId) {
822 this.deviceId = deviceId;
823 this.macAddress = macAddress;
824 this.vlanId = vlanId;
825 }
826
827 @Override
828 public boolean equals(final Object obj) {
829 if (this == obj) {
830 return true;
831 }
832 if (!(obj instanceof BridingTableKey)) {
833 return false;
834 }
835 final BridingTableKey other = (BridingTableKey) obj;
836 return Objects.equals(this.macAddress, other.macAddress) &&
837 Objects.equals(this.deviceId, other.deviceId) &&
838 Objects.equals(this.vlanId, other.vlanId);
839 }
840
841 @Override
842 public int hashCode() {
843 return Objects.hash(macAddress, vlanId);
844 }
845 }
846
847 class BridingTableValue {
848 boolean popVlan;
849 PortNumber portNumber;
850
851 BridingTableValue(boolean popVlan, PortNumber portNumber) {
852 this.popVlan = popVlan;
853 this.portNumber = portNumber;
854 }
855
856 @Override
857 public boolean equals(final Object obj) {
858 if (this == obj) {
859 return true;
860 }
861 if (!(obj instanceof BridingTableValue)) {
862 return false;
863 }
864 final BridingTableValue other = (BridingTableValue) obj;
865 return Objects.equals(this.popVlan, other.popVlan) &&
866 Objects.equals(this.portNumber, other.portNumber);
867 }
868
869 @Override
870 public int hashCode() {
871 return Objects.hash(popVlan, portNumber);
872 }
873 }
874
875 class RoutingTableKey {
876 DeviceId deviceId;
877 IpPrefix ipPrefix;
878
879 RoutingTableKey(DeviceId deviceId, IpPrefix ipPrefix) {
880 this.deviceId = deviceId;
881 this.ipPrefix = ipPrefix;
882 }
883
884 @Override
885 public boolean equals(final Object obj) {
886 if (this == obj) {
887 return true;
888 }
889 if (!(obj instanceof RoutingTableKey)) {
890 return false;
891 }
892 final RoutingTableKey other = (RoutingTableKey) obj;
893 return Objects.equals(this.deviceId, other.deviceId) &&
894 Objects.equals(this.ipPrefix, other.ipPrefix);
895 }
896
897 @Override
898 public int hashCode() {
899 return Objects.hash(deviceId, ipPrefix);
900 }
901 }
902
903 class RoutingTableValue {
904 PortNumber portNumber;
905 MacAddress macAddress;
906 VlanId vlanId;
907
908 RoutingTableValue(PortNumber portNumber, MacAddress macAddress, VlanId vlanId) {
909 this.portNumber = portNumber;
910 this.macAddress = macAddress;
911 this.vlanId = vlanId;
912 }
913
914 @Override
915 public boolean equals(final Object obj) {
916 if (this == obj) {
917 return true;
918 }
919 if (!(obj instanceof RoutingTableValue)) {
920 return false;
921 }
922 final RoutingTableValue other = (RoutingTableValue) obj;
923 return Objects.equals(this.portNumber, other.portNumber) &&
924 Objects.equals(this.macAddress, other.macAddress) &&
925 Objects.equals(this.vlanId, other.vlanId);
926 }
927
928 @Override
929 public int hashCode() {
930 return Objects.hash(portNumber, macAddress, vlanId);
931 }
932 }
933
Ray Milkeyfacf2862017-08-03 11:58:29 -0700934}