blob: 1560b0ef99d5feacce86035a9e391bbceb8b91a9 [file] [log] [blame]
alshabibab984662014-12-04 18:56:18 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
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 Hart470ed4f2017-01-31 16:52:28 -080016
17package org.onosproject.intentsync;
Pingpingf5d90932014-10-27 10:50:04 -070018
Jonathan Hart9a426f82015-09-03 15:43:13 +020019import com.google.common.util.concurrent.MoreExecutors;
Jonathan Hart470ed4f2017-01-31 16:52:28 -080020import org.easymock.EasyMock;
Pingpingf5d90932014-10-27 10:50:04 -070021import org.junit.Before;
22import org.junit.Test;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080023import org.onlab.packet.Ethernet;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080024import org.onlab.packet.Ip4Prefix;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.IpPrefix;
27import org.onlab.packet.MacAddress;
Jonathan Hart9a426f82015-09-03 15:43:13 +020028import org.onosproject.TestApplicationId;
Madan Jampani620f70d2016-01-30 22:22:47 -080029import org.onosproject.cluster.ClusterServiceAdapter;
30import org.onosproject.cluster.ControllerNode;
31import org.onosproject.cluster.DefaultControllerNode;
Jonathan Hart365335e2015-12-10 11:09:53 -080032import org.onosproject.cluster.LeadershipServiceAdapter;
Madan Jampani620f70d2016-01-30 22:22:47 -080033import org.onosproject.cluster.NodeId;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.core.ApplicationId;
Jonathan Hart365335e2015-12-10 11:09:53 -080035import org.onosproject.core.CoreServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.ConnectPoint;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.DeviceId;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.PortNumber;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.intent.AbstractIntentTest;
44import org.onosproject.net.intent.Intent;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.intent.IntentService;
46import org.onosproject.net.intent.IntentState;
Jonathan Hart9a426f82015-09-03 15:43:13 +020047import org.onosproject.net.intent.Key;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.intent.MultiPointToSinglePointIntent;
Pingpingf5d90932014-10-27 10:50:04 -070049
Jonathan Hart41349e92015-02-09 14:14:02 -080050import java.util.Collections;
Jonathan Hart552e31f2015-02-06 11:11:59 -080051import java.util.HashSet;
52import java.util.Set;
Jonathan Hart365335e2015-12-10 11:09:53 -080053import java.util.concurrent.ExecutorService;
Jonathan Hart552e31f2015-02-06 11:11:59 -080054
Pingpingf5d90932014-10-27 10:50:04 -070055/**
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080056 * This class tests the intent synchronization function in the
57 * IntentSynchronizer class.
Pingpingf5d90932014-10-27 10:50:04 -070058 */
Jonathan Hart6af92be2016-01-05 20:52:25 -080059public class IntentSynchronizerTest extends AbstractIntentTest {
Pingpingf5d90932014-10-27 10:50:04 -070060
Pingpingf5d90932014-10-27 10:50:04 -070061 private IntentService intentService;
Pingpingf5d90932014-10-27 10:50:04 -070062
63 private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
64 DeviceId.deviceId("of:0000000000000001"),
65 PortNumber.portNumber(1));
66
67 private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
68 DeviceId.deviceId("of:0000000000000002"),
69 PortNumber.portNumber(1));
70
71 private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
72 DeviceId.deviceId("of:0000000000000003"),
73 PortNumber.portNumber(1));
74
Jonathan Hart41349e92015-02-09 14:14:02 -080075 private static final ConnectPoint SW4_ETH1 = new ConnectPoint(
76 DeviceId.deviceId("of:0000000000000004"),
77 PortNumber.portNumber(1));
78
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080079 private IntentSynchronizer intentSynchronizer;
Jonathan Hartde6e2032016-04-15 13:28:02 -070080 private final Set<ConnectPoint> connectPoints = new HashSet<>();
Pingpingf5d90932014-10-27 10:50:04 -070081
Jonathan Hart365335e2015-12-10 11:09:53 -080082 private static final ApplicationId APPID =
83 TestApplicationId.create("intent-sync-test");
Pingpingf5d90932014-10-27 10:50:04 -070084
Madan Jampani620f70d2016-01-30 22:22:47 -080085 private static final ControllerNode LOCAL_NODE =
86 new DefaultControllerNode(new NodeId("foo"), IpAddress.valueOf("127.0.0.1"));
87
Pingpingf5d90932014-10-27 10:50:04 -070088 @Before
89 public void setUp() throws Exception {
Brian O'Connor520c0522014-11-23 23:50:47 -080090 super.setUp();
Jonathan Hart41349e92015-02-09 14:14:02 -080091
Jonathan Hartde6e2032016-04-15 13:28:02 -070092 setUpConnectPoints();
Jonathan Hart90a02c22015-02-13 11:52:07 -080093
Jonathan Hart470ed4f2017-01-31 16:52:28 -080094 intentService = EasyMock.createMock(IntentService.class);
Pingpingf5d90932014-10-27 10:50:04 -070095
Jonathan Hart365335e2015-12-10 11:09:53 -080096 intentSynchronizer = new TestIntentSynchronizer();
97
98 intentSynchronizer.coreService = new TestCoreService();
Madan Jampani620f70d2016-01-30 22:22:47 -080099 intentSynchronizer.clusterService = new TestClusterService();
Jonathan Hartde6e2032016-04-15 13:28:02 -0700100 intentSynchronizer.leadershipService = new LeadershipServiceAdapter();
Jonathan Hart365335e2015-12-10 11:09:53 -0800101 intentSynchronizer.intentService = intentService;
102
103 intentSynchronizer.activate();
Pingpingf5d90932014-10-27 10:50:04 -0700104 }
105
106 /**
Jonathan Hartde6e2032016-04-15 13:28:02 -0700107 * Sets up connect points.
Pingpingf5d90932014-10-27 10:50:04 -0700108 */
Jonathan Hartde6e2032016-04-15 13:28:02 -0700109 private void setUpConnectPoints() {
110 connectPoints.add(SW1_ETH1);
111 connectPoints.add(SW2_ETH1);
112 connectPoints.add(SW3_ETH1);
113 connectPoints.add(SW4_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700114 }
115
116 /**
Jonathan Hart9a426f82015-09-03 15:43:13 +0200117 * Tests the synchronization behavior of intent synchronizer. We set up
118 * a discrepancy between the intent service state and the intent
119 * synchronizer's state and ensure that this is reconciled correctly.
Pingpingf5d90932014-10-27 10:50:04 -0700120 */
121 @Test
Jonathan Hartde6e2032016-04-15 13:28:02 -0700122 public void testIntentSync() {
Pingpingf5d90932014-10-27 10:50:04 -0700123
Pingpingf5d90932014-10-27 10:50:04 -0700124 // Construct routes and intents.
125 // This test simulates the following cases during the master change
126 // time interval:
Jonathan Hartde6e2032016-04-15 13:28:02 -0700127 // 1. intent1 did not change and the intent also did not change.
128 // 2. intent2 was deleted, but the intent was not deleted.
129 // 3. intent3 was newly added, and the intent was also submitted.
130 // 4. intent4 was updated to RouteEntry4Update, and the intent was
Pingpingf5d90932014-10-27 10:50:04 -0700131 // also updated to a new one.
Jonathan Hartde6e2032016-04-15 13:28:02 -0700132 // 5. intent5 did not change, but its intent id changed.
133 // 6. intent6 was newly added, but the intent was not submitted.
Jonathan Hartec2df012014-10-23 16:40:24 -0700134
Pingpingf5d90932014-10-27 10:50:04 -0700135 MultiPointToSinglePointIntent intent1 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700136 Ip4Prefix.valueOf("1.1.1.0/24"), "00:00:00:00:00:01", SW1_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700137 MultiPointToSinglePointIntent intent2 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700138 Ip4Prefix.valueOf("2.2.2.0/24"), "00:00:00:00:00:02", SW2_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700139 MultiPointToSinglePointIntent intent3 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700140 Ip4Prefix.valueOf("3.3.3.0/24"), "00:00:00:00:00:03", SW3_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700141 MultiPointToSinglePointIntent intent4 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700142 Ip4Prefix.valueOf("4.4.4.0/24"), "00:00:00:00:00:03", SW3_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700143 MultiPointToSinglePointIntent intent4Update = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700144 Ip4Prefix.valueOf("4.4.4.0/24"), "00:00:00:00:00:02", SW2_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700145 MultiPointToSinglePointIntent intent5 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700146 Ip4Prefix.valueOf("5.5.5.0/24"), "00:00:00:00:00:01", SW1_ETH1);
Jonathan Hartec2df012014-10-23 16:40:24 -0700147 MultiPointToSinglePointIntent intent7 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700148 Ip4Prefix.valueOf("7.7.7.0/24"), "00:00:00:00:00:01", SW1_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700149
150 MultiPointToSinglePointIntent intent6 = intentBuilder(
Jonathan Hartde6e2032016-04-15 13:28:02 -0700151 Ip4Prefix.valueOf("6.6.6.0/24"), "00:00:00:00:00:01", SW1_ETH1);
Pingpingf5d90932014-10-27 10:50:04 -0700152
Pingpingf5d90932014-10-27 10:50:04 -0700153 // Set up expectation
Jonathan Hart90a02c22015-02-13 11:52:07 -0800154 Set<Intent> intents = new HashSet<>();
Pingpingf5d90932014-10-27 10:50:04 -0700155 intents.add(intent1);
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800156 EasyMock.expect(intentService.getIntentState(intent1.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700157 .andReturn(IntentState.INSTALLED).anyTimes();
Pingpingf5d90932014-10-27 10:50:04 -0700158 intents.add(intent2);
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800159 EasyMock.expect(intentService.getIntentState(intent2.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700160 .andReturn(IntentState.INSTALLED).anyTimes();
Pingpingf5d90932014-10-27 10:50:04 -0700161 intents.add(intent4);
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800162 EasyMock.expect(intentService.getIntentState(intent4.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700163 .andReturn(IntentState.INSTALLED).anyTimes();
Pingpingf5d90932014-10-27 10:50:04 -0700164 intents.add(intent5);
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800165 EasyMock.expect(intentService.getIntentState(intent5.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700166 .andReturn(IntentState.INSTALLED).anyTimes();
167 intents.add(intent7);
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800168 EasyMock.expect(intentService.getIntentState(intent7.key()))
Jonathan Hartec2df012014-10-23 16:40:24 -0700169 .andReturn(IntentState.WITHDRAWING).anyTimes();
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800170 EasyMock.expect(intentService.getIntents()).andReturn(intents).anyTimes();
Pingpingf5d90932014-10-27 10:50:04 -0700171
Jonathan Hart9a426f82015-09-03 15:43:13 +0200172 // These are the operations that should be done to the intentService
173 // during synchronization
Brian O'Connor03406a42015-02-03 17:28:57 -0800174 intentService.withdraw(intent2);
Brian O'Connor03406a42015-02-03 17:28:57 -0800175 intentService.submit(intent3);
176 intentService.submit(intent4Update);
177 intentService.submit(intent6);
178 intentService.submit(intent7);
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800179 EasyMock.replay(intentService);
Pingpingf5d90932014-10-27 10:50:04 -0700180
181 // Start the test
Pingpingf5d90932014-10-27 10:50:04 -0700182
Jonathan Hart9a426f82015-09-03 15:43:13 +0200183 // Simulate some input from the clients. The intent synchronizer has not
184 // gained the global leadership yet, but it will remember this input for
185 // when it does.
186 intentSynchronizer.submit(intent1);
187 intentSynchronizer.submit(intent2);
188 intentSynchronizer.withdraw(intent2);
189 intentSynchronizer.submit(intent3);
190 intentSynchronizer.submit(intent4);
191 intentSynchronizer.submit(intent4Update);
192 intentSynchronizer.submit(intent5);
193 intentSynchronizer.submit(intent6);
194 intentSynchronizer.submit(intent7);
195
196 // Give the leadership to the intent synchronizer. It will now attempt
197 // to synchronize the intents in the store with the intents it has
198 // recorded based on the earlier user input.
Jonathan Hart365335e2015-12-10 11:09:53 -0800199 intentSynchronizer.modifyPrimary(true);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200200
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800201 EasyMock.verify(intentService);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200202 }
203
204 /**
205 * Tests the behavior of the submit API, both when the synchronizer has
206 * leadership and when it does not.
207 */
208 @Test
209 public void testSubmit() {
210 IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
211 Intent intent = intentBuilder(prefix, "00:00:00:00:00:01", SW1_ETH1);
212
213 // Set up expectations
214 intentService.submit(intent);
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800215 EasyMock.expect(intentService.getIntents()).andReturn(Collections.emptyList())
Jonathan Hart9a426f82015-09-03 15:43:13 +0200216 .anyTimes();
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800217 EasyMock.replay(intentService);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200218
219 // Give the intent synchronizer leadership so it will submit intents
220 // to the intent service
Jonathan Hart365335e2015-12-10 11:09:53 -0800221 intentSynchronizer.modifyPrimary(true);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200222
223 // Test the submit
224 intentSynchronizer.submit(intent);
225
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800226 EasyMock.verify(intentService);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200227
228 // Now we'll remove leadership from the intent synchronizer and verify
229 // that it does not submit any intents to the intent service when we
230 // call the submit API
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800231 EasyMock.reset(intentService);
232 EasyMock.replay(intentService);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200233
Jonathan Hart365335e2015-12-10 11:09:53 -0800234 intentSynchronizer.modifyPrimary(false);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200235
236 intentSynchronizer.submit(intent);
237
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800238 EasyMock.verify(intentService);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200239 }
240
241 /**
242 * Tests the behavior of the withdraw API, both when the synchronizer has
243 * leadership and when it does not.
244 */
245 @Test
246 public void testWithdraw() {
247 IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
248 Intent intent = intentBuilder(prefix, "00:00:00:00:00:01", SW1_ETH1);
249
250 // Submit an intent first so we can withdraw it later
251 intentService.submit(intent);
252 intentService.withdraw(intent);
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800253 EasyMock.expect(intentService.getIntents()).andReturn(Collections.emptyList())
Jonathan Hart9a426f82015-09-03 15:43:13 +0200254 .anyTimes();
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800255 EasyMock.replay(intentService);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200256
257 // Give the intent synchronizer leadership so it will submit intents
258 // to the intent service
Jonathan Hart365335e2015-12-10 11:09:53 -0800259 intentSynchronizer.modifyPrimary(true);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200260
261 // Test the submit then withdraw
262 intentSynchronizer.submit(intent);
263 intentSynchronizer.withdraw(intent);
264
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800265 EasyMock.verify(intentService);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200266
267 // Now we'll remove leadership from the intent synchronizer and verify
268 // that it does not withdraw any intents to the intent service when we
269 // call the withdraw API
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800270 EasyMock.reset(intentService);
271 EasyMock.replay(intentService);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200272
Jonathan Hart365335e2015-12-10 11:09:53 -0800273 intentSynchronizer.modifyPrimary(false);
Jonathan Hart9a426f82015-09-03 15:43:13 +0200274
275 intentSynchronizer.submit(intent);
276 intentSynchronizer.withdraw(intent);
Pingpingf5d90932014-10-27 10:50:04 -0700277
Jonathan Hart470ed4f2017-01-31 16:52:28 -0800278 EasyMock.verify(intentService);
Pingpingf5d90932014-10-27 10:50:04 -0700279 }
280
281 /**
282 * MultiPointToSinglePointIntent builder.
283 *
284 * @param ipPrefix the ipPrefix to match
285 * @param nextHopMacAddress to which the destination MAC address in packet
286 * should be rewritten
287 * @param egressPoint to which packets should be sent
288 * @return the constructed MultiPointToSinglePointIntent
289 */
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800290 private MultiPointToSinglePointIntent intentBuilder(IpPrefix ipPrefix,
Pingpingf5d90932014-10-27 10:50:04 -0700291 String nextHopMacAddress, ConnectPoint egressPoint) {
292
293 TrafficSelector.Builder selectorBuilder =
294 DefaultTrafficSelector.builder();
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700295 if (ipPrefix.isIp4()) {
Jonathan Hart9a426f82015-09-03 15:43:13 +0200296 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
Pavlin Radoslavova8537092015-02-23 10:15:20 -0800297 selectorBuilder.matchIPDst(ipPrefix);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800298 } else {
Jonathan Hart9a426f82015-09-03 15:43:13 +0200299 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
Pavlin Radoslavova8537092015-02-23 10:15:20 -0800300 selectorBuilder.matchIPv6Dst(ipPrefix);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800301 }
Pingpingf5d90932014-10-27 10:50:04 -0700302
303 TrafficTreatment.Builder treatmentBuilder =
304 DefaultTrafficTreatment.builder();
305 treatmentBuilder.setEthDst(MacAddress.valueOf(nextHopMacAddress));
306
Jonathan Hartde6e2032016-04-15 13:28:02 -0700307 Set<ConnectPoint> ingressPoints = new HashSet<>(connectPoints);
308 ingressPoints.remove(egressPoint);
309
Pingpingf5d90932014-10-27 10:50:04 -0700310 MultiPointToSinglePointIntent intent =
Ray Milkeyebc5d222015-03-18 15:45:36 -0700311 MultiPointToSinglePointIntent.builder()
312 .appId(APPID)
Jonathan Hart9a426f82015-09-03 15:43:13 +0200313 .key(Key.of(ipPrefix.toString(), APPID))
Ray Milkeyebc5d222015-03-18 15:45:36 -0700314 .selector(selectorBuilder.build())
315 .treatment(treatmentBuilder.build())
316 .ingressPoints(ingressPoints)
317 .egressPoint(egressPoint)
318 .build();
Pingpingf5d90932014-10-27 10:50:04 -0700319 return intent;
320 }
321
Jonathan Hart365335e2015-12-10 11:09:53 -0800322 private class TestIntentSynchronizer extends IntentSynchronizer {
323 @Override
324 protected ExecutorService createExecutor() {
325 return MoreExecutors.newDirectExecutorService();
326 }
327 }
328
329 private class TestCoreService extends CoreServiceAdapter {
330 @Override
331 public ApplicationId registerApplication(String name) {
332 return APPID;
333 }
334 }
335
Madan Jampani620f70d2016-01-30 22:22:47 -0800336 private class TestClusterService extends ClusterServiceAdapter {
337 @Override
338 public ControllerNode getLocalNode() {
339 return LOCAL_NODE;
340 }
341 }
Pingpingf5d90932014-10-27 10:50:04 -0700342}