blob: 4b7110a2f72f863324659acdd7cb59f33e58b091 [file] [log] [blame]
alshabibab984662014-12-04 18:56:18 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
alshabibab984662014-12-04 18:56:18 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jonathan Hart6af92be2016-01-05 20:52:25 -080016package org.onosproject.routing.impl;
Pingpingf5d90932014-10-27 10:50:04 -070017
Jonathan Hart9a426f82015-09-03 15:43:13 +020018import com.google.common.util.concurrent.MoreExecutors;
Pingpingf5d90932014-10-27 10:50:04 -070019import org.junit.Before;
20import org.junit.Test;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080021import org.onlab.packet.Ethernet;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080022import org.onlab.packet.Ip4Prefix;
23import org.onlab.packet.IpAddress;
24import org.onlab.packet.IpPrefix;
25import org.onlab.packet.MacAddress;
Jonathan Hart9a426f82015-09-03 15:43:13 +020026import org.onosproject.TestApplicationId;
Madan Jampani620f70d2016-01-30 22:22:47 -080027import org.onosproject.cluster.ClusterServiceAdapter;
28import org.onosproject.cluster.ControllerNode;
29import org.onosproject.cluster.DefaultControllerNode;
Jonathan Hart365335e2015-12-10 11:09:53 -080030import org.onosproject.cluster.LeadershipServiceAdapter;
Madan Jampani620f70d2016-01-30 22:22:47 -080031import org.onosproject.cluster.NodeId;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.core.ApplicationId;
Jonathan Hart365335e2015-12-10 11:09:53 -080033import org.onosproject.core.CoreServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.ConnectPoint;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.DeviceId;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.PortNumber;
37import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.intent.AbstractIntentTest;
42import org.onosproject.net.intent.Intent;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.intent.IntentService;
44import org.onosproject.net.intent.IntentState;
Jonathan Hart9a426f82015-09-03 15:43:13 +020045import org.onosproject.net.intent.Key;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.intent.MultiPointToSinglePointIntent;
Pingpingf5d90932014-10-27 10:50:04 -070047
Jonathan Hart41349e92015-02-09 14:14:02 -080048import java.util.Collections;
Jonathan Hart552e31f2015-02-06 11:11:59 -080049import java.util.HashSet;
50import java.util.Set;
Jonathan Hart365335e2015-12-10 11:09:53 -080051import java.util.concurrent.ExecutorService;
Jonathan Hart552e31f2015-02-06 11:11:59 -080052
Jonathan Hart4cb39882015-08-12 23:50:55 -040053import static org.easymock.EasyMock.createMock;
54import static org.easymock.EasyMock.expect;
55import static org.easymock.EasyMock.replay;
56import static org.easymock.EasyMock.reset;
57import static org.easymock.EasyMock.verify;
Pingpingf5d90932014-10-27 10:50:04 -070058
59/**
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080060 * This class tests the intent synchronization function in the
61 * IntentSynchronizer class.
Pingpingf5d90932014-10-27 10:50:04 -070062 */
Jonathan Hart6af92be2016-01-05 20:52:25 -080063public class IntentSynchronizerTest extends AbstractIntentTest {
Pingpingf5d90932014-10-27 10:50:04 -070064
Pingpingf5d90932014-10-27 10:50:04 -070065 private IntentService intentService;
Pingpingf5d90932014-10-27 10:50:04 -070066
67 private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
68 DeviceId.deviceId("of:0000000000000001"),
69 PortNumber.portNumber(1));
70
71 private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
72 DeviceId.deviceId("of:0000000000000002"),
73 PortNumber.portNumber(1));
74
75 private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
76 DeviceId.deviceId("of:0000000000000003"),
77 PortNumber.portNumber(1));
78
Jonathan Hart41349e92015-02-09 14:14:02 -080079 private static final ConnectPoint SW4_ETH1 = new ConnectPoint(
80 DeviceId.deviceId("of:0000000000000004"),
81 PortNumber.portNumber(1));
82
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080083 private IntentSynchronizer intentSynchronizer;
Jonathan Hartde6e2032016-04-15 13:28:02 -070084 private final Set<ConnectPoint> connectPoints = new HashSet<>();
Pingpingf5d90932014-10-27 10:50:04 -070085
Jonathan Hart365335e2015-12-10 11:09:53 -080086 private static final ApplicationId APPID =
87 TestApplicationId.create("intent-sync-test");
Pingpingf5d90932014-10-27 10:50:04 -070088
Madan Jampani620f70d2016-01-30 22:22:47 -080089 private static final ControllerNode LOCAL_NODE =
90 new DefaultControllerNode(new NodeId("foo"), IpAddress.valueOf("127.0.0.1"));
91
Pingpingf5d90932014-10-27 10:50:04 -070092 @Before
93 public void setUp() throws Exception {
Brian O'Connor520c0522014-11-23 23:50:47 -080094 super.setUp();
Jonathan Hart41349e92015-02-09 14:14:02 -080095
Jonathan Hartde6e2032016-04-15 13:28:02 -070096 setUpConnectPoints();
Jonathan Hart90a02c22015-02-13 11:52:07 -080097
Pingpingf5d90932014-10-27 10:50:04 -070098 intentService = createMock(IntentService.class);
99
Jonathan Hart365335e2015-12-10 11:09:53 -0800100 intentSynchronizer = new TestIntentSynchronizer();
101
102 intentSynchronizer.coreService = new TestCoreService();
Madan Jampani620f70d2016-01-30 22:22:47 -0800103 intentSynchronizer.clusterService = new TestClusterService();
Jonathan Hartde6e2032016-04-15 13:28:02 -0700104 intentSynchronizer.leadershipService = new LeadershipServiceAdapter();
Jonathan Hart365335e2015-12-10 11:09:53 -0800105 intentSynchronizer.intentService = intentService;
106
107 intentSynchronizer.activate();
Pingpingf5d90932014-10-27 10:50:04 -0700108 }
109
110 /**
Jonathan Hartde6e2032016-04-15 13:28:02 -0700111 * Sets up connect points.
Pingpingf5d90932014-10-27 10:50:04 -0700112 */
Jonathan Hartde6e2032016-04-15 13:28:02 -0700113 private void setUpConnectPoints() {
114 connectPoints.add(SW1_ETH1);
115 connectPoints.add(SW2_ETH1);
116 connectPoints.add(SW3_ETH1);
117 connectPoints.add(SW4_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700118 }
119
120 /**
Jonathan Hart9a426f82015-09-03 15:43:13 +0200121 * Tests the synchronization behavior of intent synchronizer. We set up
122 * a discrepancy between the intent service state and the intent
123 * synchronizer's state and ensure that this is reconciled correctly.
Pingpingf5d90932014-10-27 10:50:04 -0700124 */
125 @Test
Jonathan Hartde6e2032016-04-15 13:28:02 -0700126 public void testIntentSync() {
Pingpingf5d90932014-10-27 10:50:04 -0700127
Pingpingf5d90932014-10-27 10:50:04 -0700128 // Construct routes and intents.
129 // This test simulates the following cases during the master change
130 // time interval:
Jonathan Hartde6e2032016-04-15 13:28:02 -0700131 // 1. intent1 did not change and the intent also did not change.
132 // 2. intent2 was deleted, but the intent was not deleted.
133 // 3. intent3 was newly added, and the intent was also submitted.
134 // 4. intent4 was updated to RouteEntry4Update, and the intent was
Pingpingf5d90932014-10-27 10:50:04 -0700135 // also updated to a new one.
Jonathan Hartde6e2032016-04-15 13:28:02 -0700136 // 5. intent5 did not change, but its intent id changed.
137 // 6. intent6 was newly added, but the intent was not submitted.
Jonathan Hartec2df012014-10-23 16:40:24 -0700138
Pingpingf5d90932014-10-27 10:50:04 -0700139 MultiPointToSinglePointIntent intent1 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700140 Ip4Prefix.valueOf("1.1.1.0/24"), "00:00:00:00:00:01", SW1_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700141 MultiPointToSinglePointIntent intent2 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700142 Ip4Prefix.valueOf("2.2.2.0/24"), "00:00:00:00:00:02", SW2_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700143 MultiPointToSinglePointIntent intent3 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700144 Ip4Prefix.valueOf("3.3.3.0/24"), "00:00:00:00:00:03", SW3_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700145 MultiPointToSinglePointIntent intent4 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700146 Ip4Prefix.valueOf("4.4.4.0/24"), "00:00:00:00:00:03", SW3_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700147 MultiPointToSinglePointIntent intent4Update = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700148 Ip4Prefix.valueOf("4.4.4.0/24"), "00:00:00:00:00:02", SW2_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700149 MultiPointToSinglePointIntent intent5 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700150 Ip4Prefix.valueOf("5.5.5.0/24"), "00:00:00:00:00:01", SW1_ETH1);
Jonathan Hartec2df012014-10-23 16:40:24 -0700151 MultiPointToSinglePointIntent intent7 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700152 Ip4Prefix.valueOf("7.7.7.0/24"), "00:00:00:00:00:01", SW1_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700153
154 MultiPointToSinglePointIntent intent6 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700155 Ip4Prefix.valueOf("6.6.6.0/24"), "00:00:00:00:00:01", SW1_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700156
Pingpingf5d90932014-10-27 10:50:04 -0700157 // Set up expectation
Jonathan Hart90a02c22015-02-13 11:52:07 -0800158 Set<Intent> intents = new HashSet<>();
Pingpingf5d90932014-10-27 10:50:04 -0700159 intents.add(intent1);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800160 expect(intentService.getIntentState(intent1.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700161 .andReturn(IntentState.INSTALLED).anyTimes();
Pingpingf5d90932014-10-27 10:50:04 -0700162 intents.add(intent2);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800163 expect(intentService.getIntentState(intent2.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700164 .andReturn(IntentState.INSTALLED).anyTimes();
Pingpingf5d90932014-10-27 10:50:04 -0700165 intents.add(intent4);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800166 expect(intentService.getIntentState(intent4.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700167 .andReturn(IntentState.INSTALLED).anyTimes();
Pingpingf5d90932014-10-27 10:50:04 -0700168 intents.add(intent5);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800169 expect(intentService.getIntentState(intent5.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700170 .andReturn(IntentState.INSTALLED).anyTimes();
171 intents.add(intent7);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800172 expect(intentService.getIntentState(intent7.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700173 .andReturn(IntentState.WITHDRAWING).anyTimes();
Pingpingf5d90932014-10-27 10:50:04 -0700174 expect(intentService.getIntents()).andReturn(intents).anyTimes();
175
Jonathan Hart9a426f82015-09-03 15:43:13 +0200176 // These are the operations that should be done to the intentService
177 // during synchronization
Brian O'Connor03406a42015-02-03 17:28:57 -0800178 intentService.withdraw(intent2);
Brian O'Connor03406a42015-02-03 17:28:57 -0800179 intentService.submit(intent3);
180 intentService.submit(intent4Update);
181 intentService.submit(intent6);
182 intentService.submit(intent7);
Pingpingf5d90932014-10-27 10:50:04 -0700183 replay(intentService);
184
185 // Start the test
Pingpingf5d90932014-10-27 10:50:04 -0700186
Jonathan Hart9a426f82015-09-03 15:43:13 +0200187 // Simulate some input from the clients. The intent synchronizer has not
188 // gained the global leadership yet, but it will remember this input for
189 // when it does.
190 intentSynchronizer.submit(intent1);
191 intentSynchronizer.submit(intent2);
192 intentSynchronizer.withdraw(intent2);
193 intentSynchronizer.submit(intent3);
194 intentSynchronizer.submit(intent4);
195 intentSynchronizer.submit(intent4Update);
196 intentSynchronizer.submit(intent5);
197 intentSynchronizer.submit(intent6);
198 intentSynchronizer.submit(intent7);
199
200 // Give the leadership to the intent synchronizer. It will now attempt
201 // to synchronize the intents in the store with the intents it has
202 // recorded based on the earlier user input.
Jonathan Hart365335e2015-12-10 11:09:53 -0800203 intentSynchronizer.modifyPrimary(true);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200204
205 verify(intentService);
206 }
207
208 /**
209 * Tests the behavior of the submit API, both when the synchronizer has
210 * leadership and when it does not.
211 */
212 @Test
213 public void testSubmit() {
214 IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
215 Intent intent = intentBuilder(prefix, "00:00:00:00:00:01", SW1_ETH1);
216
217 // Set up expectations
218 intentService.submit(intent);
219 expect(intentService.getIntents()).andReturn(Collections.emptyList())
220 .anyTimes();
221 replay(intentService);
222
223 // Give the intent synchronizer leadership so it will submit intents
224 // to the intent service
Jonathan Hart365335e2015-12-10 11:09:53 -0800225 intentSynchronizer.modifyPrimary(true);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200226
227 // Test the submit
228 intentSynchronizer.submit(intent);
229
230 verify(intentService);
231
232 // Now we'll remove leadership from the intent synchronizer and verify
233 // that it does not submit any intents to the intent service when we
234 // call the submit API
235 reset(intentService);
236 replay(intentService);
237
Jonathan Hart365335e2015-12-10 11:09:53 -0800238 intentSynchronizer.modifyPrimary(false);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200239
240 intentSynchronizer.submit(intent);
241
242 verify(intentService);
243 }
244
245 /**
246 * Tests the behavior of the withdraw API, both when the synchronizer has
247 * leadership and when it does not.
248 */
249 @Test
250 public void testWithdraw() {
251 IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
252 Intent intent = intentBuilder(prefix, "00:00:00:00:00:01", SW1_ETH1);
253
254 // Submit an intent first so we can withdraw it later
255 intentService.submit(intent);
256 intentService.withdraw(intent);
257 expect(intentService.getIntents()).andReturn(Collections.emptyList())
258 .anyTimes();
259 replay(intentService);
260
261 // Give the intent synchronizer leadership so it will submit intents
262 // to the intent service
Jonathan Hart365335e2015-12-10 11:09:53 -0800263 intentSynchronizer.modifyPrimary(true);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200264
265 // Test the submit then withdraw
266 intentSynchronizer.submit(intent);
267 intentSynchronizer.withdraw(intent);
268
269 verify(intentService);
270
271 // Now we'll remove leadership from the intent synchronizer and verify
272 // that it does not withdraw any intents to the intent service when we
273 // call the withdraw API
274 reset(intentService);
275 replay(intentService);
276
Jonathan Hart365335e2015-12-10 11:09:53 -0800277 intentSynchronizer.modifyPrimary(false);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200278
279 intentSynchronizer.submit(intent);
280 intentSynchronizer.withdraw(intent);
Pingpingf5d90932014-10-27 10:50:04 -0700281
282 verify(intentService);
283 }
284
285 /**
286 * MultiPointToSinglePointIntent builder.
287 *
288 * @param ipPrefix the ipPrefix to match
289 * @param nextHopMacAddress to which the destination MAC address in packet
290 * should be rewritten
291 * @param egressPoint to which packets should be sent
292 * @return the constructed MultiPointToSinglePointIntent
293 */
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800294 private MultiPointToSinglePointIntent intentBuilder(IpPrefix ipPrefix,
Pingpingf5d90932014-10-27 10:50:04 -0700295 String nextHopMacAddress, ConnectPoint egressPoint) {
296
297 TrafficSelector.Builder selectorBuilder =
298 DefaultTrafficSelector.builder();
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700299 if (ipPrefix.isIp4()) {
Jonathan Hart9a426f82015-09-03 15:43:13 +0200300 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
Pavlin Radoslavova8537092015-02-23 10:15:20 -0800301 selectorBuilder.matchIPDst(ipPrefix);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800302 } else {
Jonathan Hart9a426f82015-09-03 15:43:13 +0200303 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
Pavlin Radoslavova8537092015-02-23 10:15:20 -0800304 selectorBuilder.matchIPv6Dst(ipPrefix);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800305 }
Pingpingf5d90932014-10-27 10:50:04 -0700306
307 TrafficTreatment.Builder treatmentBuilder =
308 DefaultTrafficTreatment.builder();
309 treatmentBuilder.setEthDst(MacAddress.valueOf(nextHopMacAddress));
310
Jonathan Hartde6e2032016-04-15 13:28:02 -0700311 Set<ConnectPoint> ingressPoints = new HashSet<>(connectPoints);
312 ingressPoints.remove(egressPoint);
313
Pingpingf5d90932014-10-27 10:50:04 -0700314 MultiPointToSinglePointIntent intent =
Ray Milkeyebc5d222015-03-18 15:45:36 -0700315 MultiPointToSinglePointIntent.builder()
316 .appId(APPID)
Jonathan Hart9a426f82015-09-03 15:43:13 +0200317 .key(Key.of(ipPrefix.toString(), APPID))
Ray Milkeyebc5d222015-03-18 15:45:36 -0700318 .selector(selectorBuilder.build())
319 .treatment(treatmentBuilder.build())
320 .ingressPoints(ingressPoints)
321 .egressPoint(egressPoint)
322 .build();
Pingpingf5d90932014-10-27 10:50:04 -0700323 return intent;
324 }
325
Jonathan Hart365335e2015-12-10 11:09:53 -0800326 private class TestIntentSynchronizer extends IntentSynchronizer {
327 @Override
328 protected ExecutorService createExecutor() {
329 return MoreExecutors.newDirectExecutorService();
330 }
331 }
332
333 private class TestCoreService extends CoreServiceAdapter {
334 @Override
335 public ApplicationId registerApplication(String name) {
336 return APPID;
337 }
338 }
339
Madan Jampani620f70d2016-01-30 22:22:47 -0800340 private class TestClusterService extends ClusterServiceAdapter {
341 @Override
342 public ControllerNode getLocalNode() {
343 return LOCAL_NODE;
344 }
345 }
Pingpingf5d90932014-10-27 10:50:04 -0700346}