Jonathan Hart

Fixed a few intent synchronization issues.

Also added a CLI command to test SDN-IP primary switchover.

Change-Id: Id31f79262a2b607f987adad2fdb3eb54eb939fea
...@@ -46,6 +46,7 @@ import org.onlab.onos.net.host.HostListener; ...@@ -46,6 +46,7 @@ import org.onlab.onos.net.host.HostListener;
46 import org.onlab.onos.net.host.HostService; 46 import org.onlab.onos.net.host.HostService;
47 import org.onlab.onos.net.intent.Intent; 47 import org.onlab.onos.net.intent.Intent;
48 import org.onlab.onos.net.intent.IntentService; 48 import org.onlab.onos.net.intent.IntentService;
49 +import org.onlab.onos.net.intent.IntentState;
49 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; 50 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
50 import org.onlab.onos.sdnip.config.BgpPeer; 51 import org.onlab.onos.sdnip.config.BgpPeer;
51 import org.onlab.onos.sdnip.config.Interface; 52 import org.onlab.onos.sdnip.config.Interface;
...@@ -145,11 +146,6 @@ public class Router implements RouteListener { ...@@ -145,11 +146,6 @@ public class Router implements RouteListener {
145 * Starts the Router. 146 * Starts the Router.
146 */ 147 */
147 public void start() { 148 public void start() {
148 -
149 - // TODO hack to enable SDN-IP now for testing
150 - isElectedLeader = true;
151 - isActivatedLeader = true;
152 -
153 bgpUpdatesExecutor.execute(new Runnable() { 149 bgpUpdatesExecutor.execute(new Runnable() {
154 @Override 150 @Override
155 public void run() { 151 public void run() {
...@@ -277,30 +273,21 @@ public class Router implements RouteListener { ...@@ -277,30 +273,21 @@ public class Router implements RouteListener {
277 // based on the matching prefix. 273 // based on the matching prefix.
278 // 274 //
279 for (Intent intent : intentService.getIntents()) { 275 for (Intent intent : intentService.getIntents()) {
280 - // 276 +
281 - // TODO: Ignore all intents that are not installed by 277 + if (!(intent instanceof MultiPointToSinglePointIntent)
282 - // the SDN-IP application. 278 + || !intent.appId().equals(appId)) {
283 - //
284 - if (!(intent instanceof MultiPointToSinglePointIntent)) {
285 continue; 279 continue;
286 } 280 }
287 MultiPointToSinglePointIntent mp2pIntent = 281 MultiPointToSinglePointIntent mp2pIntent =
288 (MultiPointToSinglePointIntent) intent; 282 (MultiPointToSinglePointIntent) intent;
289 - /*Match match = mp2pIntent.getMatch(); 283 +
290 - if (!(match instanceof PacketMatch)) { 284 + Criterion c = mp2pIntent.selector().getCriterion(Type.IPV4_DST);
291 - continue; 285 + if (c != null && c instanceof IPCriterion) {
292 - } 286 + IPCriterion ipCriterion = (IPCriterion) c;
293 - PacketMatch packetMatch = (PacketMatch) match; 287 + fetchedIntents.put(ipCriterion.ip(), mp2pIntent);
294 - Ip4Prefix prefix = packetMatch.getDstIpAddress(); 288 + } else {
295 - if (prefix == null) { 289 + log.warn("No IPV4_DST criterion found for intent {}",
296 - continue; 290 + mp2pIntent.id());
297 - }
298 - fetchedIntents.put(prefix, mp2pIntent);*/
299 - for (Criterion criterion : mp2pIntent.selector().criteria()) {
300 - if (criterion.type() == Type.IPV4_DST) {
301 - IPCriterion ipCriterion = (IPCriterion) criterion;
302 - fetchedIntents.put(ipCriterion.ip(), mp2pIntent);
303 - }
304 } 291 }
305 292
306 } 293 }
...@@ -344,6 +331,14 @@ public class Router implements RouteListener { ...@@ -344,6 +331,14 @@ public class Router implements RouteListener {
344 continue; 331 continue;
345 } 332 }
346 333
334 + IntentState state = intentService.getIntentState(fetchedIntent.id());
335 + if (state == IntentState.WITHDRAWING ||
336 + state == IntentState.WITHDRAWN) {
337 + // The intent has been withdrawn but according to our route
338 + // table it should be installed. We'll reinstall it.
339 + addIntents.add(Pair.of(prefix, inMemoryIntent));
340 + }
341 +
347 // 342 //
348 // If IN-MEMORY Intent is same as the FETCHED Intent, 343 // If IN-MEMORY Intent is same as the FETCHED Intent,
349 // store the FETCHED Intent in the local memory. 344 // store the FETCHED Intent in the local memory.
...@@ -434,19 +429,7 @@ public class Router implements RouteListener { ...@@ -434,19 +429,7 @@ public class Router implements RouteListener {
434 private boolean compareMultiPointToSinglePointIntents( 429 private boolean compareMultiPointToSinglePointIntents(
435 MultiPointToSinglePointIntent intent1, 430 MultiPointToSinglePointIntent intent1,
436 MultiPointToSinglePointIntent intent2) { 431 MultiPointToSinglePointIntent intent2) {
437 - /*Match match1 = intent1.getMatch(); 432 +
438 - Match match2 = intent2.getMatch();
439 - Action action1 = intent1.getAction();
440 - Action action2 = intent2.getAction();
441 - Set<SwitchPort> ingressPorts1 = intent1.getIngressPorts();
442 - Set<SwitchPort> ingressPorts2 = intent2.getIngressPorts();
443 - SwitchPort egressPort1 = intent1.getEgressPort();
444 - SwitchPort egressPort2 = intent2.getEgressPort();
445 -
446 - return Objects.equal(match1, match2) &&
447 - Objects.equal(action1, action2) &&
448 - Objects.equal(egressPort1, egressPort2) &&
449 - Objects.equal(ingressPorts1, ingressPorts2);*/
450 return Objects.equal(intent1.appId(), intent2.appId()) && 433 return Objects.equal(intent1.appId(), intent2.appId()) &&
451 Objects.equal(intent1.selector(), intent2.selector()) && 434 Objects.equal(intent1.selector(), intent2.selector()) &&
452 Objects.equal(intent1.treatment(), intent2.treatment()) && 435 Objects.equal(intent1.treatment(), intent2.treatment()) &&
......
...@@ -77,6 +77,10 @@ public class SdnIp implements SdnIpService { ...@@ -77,6 +77,10 @@ public class SdnIp implements SdnIpService {
77 router = new Router(appId, intentService, hostService, config, interfaceService); 77 router = new Router(appId, intentService, hostService, config, interfaceService);
78 router.start(); 78 router.start();
79 79
80 + // Manually set the router as the leader to allow testing
81 + // TODO change this when we get a leader election
82 + router.leaderChanged(true);
83 +
80 bgpSessionManager = new BgpSessionManager(router); 84 bgpSessionManager = new BgpSessionManager(router);
81 bgpSessionManager.startUp(2000); // TODO 85 bgpSessionManager.startUp(2000); // TODO
82 86
...@@ -99,6 +103,11 @@ public class SdnIp implements SdnIpService { ...@@ -99,6 +103,11 @@ public class SdnIp implements SdnIpService {
99 return router.getRoutes(); 103 return router.getRoutes();
100 } 104 }
101 105
106 + @Override
107 + public void modifyPrimary(boolean isPrimary) {
108 + router.leaderChanged(isPrimary);
109 + }
110 +
102 static String dpidToUri(String dpid) { 111 static String dpidToUri(String dpid) {
103 return "of:" + dpid.replace(":", ""); 112 return "of:" + dpid.replace(":", "");
104 } 113 }
......
...@@ -36,4 +36,12 @@ public interface SdnIpService { ...@@ -36,4 +36,12 @@ public interface SdnIpService {
36 * @return the SDN-IP routes 36 * @return the SDN-IP routes
37 */ 37 */
38 public Collection<RouteEntry> getRoutes(); 38 public Collection<RouteEntry> getRoutes();
39 +
40 + /**
41 + * Changes whether this SDN-IP instance is the primary or not based on the
42 + * boolean parameter.
43 + *
44 + * @param isPrimary true if the instance is primary, false if it is not
45 + */
46 + public void modifyPrimary(boolean isPrimary);
39 } 47 }
......
...@@ -1594,7 +1594,7 @@ public class BgpSession extends SimpleChannelHandler { ...@@ -1594,7 +1594,7 @@ public class BgpSession extends SimpleChannelHandler {
1594 // 1594 //
1595 // Parse the KEEPALIVE message: nothing to do 1595 // Parse the KEEPALIVE message: nothing to do
1596 // 1596 //
1597 - log.debug("BGP RX KEEPALIVE message from {}", remoteAddress); 1597 + log.trace("BGP RX KEEPALIVE message from {}", remoteAddress);
1598 1598
1599 // Start the Session Timeout timer 1599 // Start the Session Timeout timer
1600 restartSessionTimeoutTimer(ctx); 1600 restartSessionTimeoutTimer(ctx);
......
1 +package org.onlab.onos.sdnip.cli;
2 +
3 +import org.apache.karaf.shell.commands.Argument;
4 +import org.apache.karaf.shell.commands.Command;
5 +import org.onlab.onos.cli.AbstractShellCommand;
6 +import org.onlab.onos.sdnip.SdnIpService;
7 +
8 +/**
9 + * Command to change whether this SDNIP instance is primary or not.
10 + */
11 +@Command(scope = "onos", name = "sdnip-set-primary",
12 + description = "Changes the primary status of this SDN-IP instance")
13 +public class PrimaryChangeCommand extends AbstractShellCommand {
14 +
15 + @Argument(index = 0, name = "isPrimary",
16 + description = "True if this instance should be primary, false if not",
17 + required = true, multiValued = false)
18 + boolean isPrimary = false;
19 +
20 + @Override
21 + protected void execute() {
22 + get(SdnIpService.class).modifyPrimary(isPrimary);
23 + }
24 +
25 +}
...@@ -22,5 +22,8 @@ ...@@ -22,5 +22,8 @@
22 <command> 22 <command>
23 <action class="org.onlab.onos.sdnip.cli.RoutesListCommand"/> 23 <action class="org.onlab.onos.sdnip.cli.RoutesListCommand"/>
24 </command> 24 </command>
25 + <command>
26 + <action class="org.onlab.onos.sdnip.cli.PrimaryChangeCommand"/>
27 + </command>
25 </command-bundle> 28 </command-bundle>
26 </blueprint> 29 </blueprint>
......
...@@ -8,6 +8,7 @@ import static org.easymock.EasyMock.replay; ...@@ -8,6 +8,7 @@ import static org.easymock.EasyMock.replay;
8 import static org.easymock.EasyMock.reset; 8 import static org.easymock.EasyMock.reset;
9 import static org.easymock.EasyMock.verify; 9 import static org.easymock.EasyMock.verify;
10 import static org.junit.Assert.assertEquals; 10 import static org.junit.Assert.assertEquals;
11 +import static org.junit.Assert.assertFalse;
11 import static org.junit.Assert.assertTrue; 12 import static org.junit.Assert.assertTrue;
12 13
13 import java.util.HashSet; 14 import java.util.HashSet;
...@@ -35,6 +36,7 @@ import org.onlab.onos.net.host.HostService; ...@@ -35,6 +36,7 @@ import org.onlab.onos.net.host.HostService;
35 import org.onlab.onos.net.host.InterfaceIpAddress; 36 import org.onlab.onos.net.host.InterfaceIpAddress;
36 import org.onlab.onos.net.intent.Intent; 37 import org.onlab.onos.net.intent.Intent;
37 import org.onlab.onos.net.intent.IntentService; 38 import org.onlab.onos.net.intent.IntentService;
39 +import org.onlab.onos.net.intent.IntentState;
38 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; 40 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
39 import org.onlab.onos.net.provider.ProviderId; 41 import org.onlab.onos.net.provider.ProviderId;
40 import org.onlab.onos.sdnip.config.Interface; 42 import org.onlab.onos.sdnip.config.Interface;
...@@ -234,6 +236,10 @@ public class IntentSyncTest { ...@@ -234,6 +236,10 @@ public class IntentSyncTest {
234 IpPrefix.valueOf("6.6.6.0/24"), 236 IpPrefix.valueOf("6.6.6.0/24"),
235 IpAddress.valueOf("192.168.10.1")); 237 IpAddress.valueOf("192.168.10.1"));
236 238
239 + RouteEntry routeEntry7 = new RouteEntry(
240 + IpPrefix.valueOf("7.7.7.0/24"),
241 + IpAddress.valueOf("192.168.10.1"));
242 +
237 MultiPointToSinglePointIntent intent1 = intentBuilder( 243 MultiPointToSinglePointIntent intent1 = intentBuilder(
238 routeEntry1.prefix(), "00:00:00:00:00:01", SW1_ETH1); 244 routeEntry1.prefix(), "00:00:00:00:00:01", SW1_ETH1);
239 MultiPointToSinglePointIntent intent2 = intentBuilder( 245 MultiPointToSinglePointIntent intent2 = intentBuilder(
...@@ -246,6 +252,8 @@ public class IntentSyncTest { ...@@ -246,6 +252,8 @@ public class IntentSyncTest {
246 routeEntry4Update.prefix(), "00:00:00:00:00:02", SW2_ETH1); 252 routeEntry4Update.prefix(), "00:00:00:00:00:02", SW2_ETH1);
247 MultiPointToSinglePointIntent intent5 = intentBuilder( 253 MultiPointToSinglePointIntent intent5 = intentBuilder(
248 routeEntry5.prefix(), "00:00:00:00:00:01", SW1_ETH1); 254 routeEntry5.prefix(), "00:00:00:00:00:01", SW1_ETH1);
255 + MultiPointToSinglePointIntent intent7 = intentBuilder(
256 + routeEntry7.prefix(), "00:00:00:00:00:01", SW1_ETH1);
249 257
250 // Compose a intent, which is equal to intent5 but the id is different. 258 // Compose a intent, which is equal to intent5 but the id is different.
251 MultiPointToSinglePointIntent intent5New = 259 MultiPointToSinglePointIntent intent5New =
...@@ -255,7 +263,7 @@ public class IntentSyncTest { ...@@ -255,7 +263,7 @@ public class IntentSyncTest {
255 new Class<?>[] {MultiPointToSinglePointIntent.class, 263 new Class<?>[] {MultiPointToSinglePointIntent.class,
256 MultiPointToSinglePointIntent.class}, 264 MultiPointToSinglePointIntent.class},
257 intent5, intent5New).equals(true)); 265 intent5, intent5New).equals(true));
258 - assertTrue(!intent5.equals(intent5New)); 266 + assertFalse(intent5.equals(intent5New));
259 267
260 MultiPointToSinglePointIntent intent6 = intentBuilder( 268 MultiPointToSinglePointIntent intent6 = intentBuilder(
261 routeEntry6.prefix(), "00:00:00:00:00:01", SW1_ETH1); 269 routeEntry6.prefix(), "00:00:00:00:00:01", SW1_ETH1);
...@@ -274,6 +282,8 @@ public class IntentSyncTest { ...@@ -274,6 +282,8 @@ public class IntentSyncTest {
274 routeEntry5); 282 routeEntry5);
275 bgpRoutes.put(RouteEntry.createBinaryString(routeEntry6.prefix()), 283 bgpRoutes.put(RouteEntry.createBinaryString(routeEntry6.prefix()),
276 routeEntry6); 284 routeEntry6);
285 + bgpRoutes.put(RouteEntry.createBinaryString(routeEntry7.prefix()),
286 + routeEntry7);
277 TestUtils.setField(router, "bgpRoutes", bgpRoutes); 287 TestUtils.setField(router, "bgpRoutes", bgpRoutes);
278 288
279 ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent> 289 ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent>
...@@ -283,15 +293,27 @@ public class IntentSyncTest { ...@@ -283,15 +293,27 @@ public class IntentSyncTest {
283 pushedRouteIntents.put(routeEntry4Update.prefix(), intent4Update); 293 pushedRouteIntents.put(routeEntry4Update.prefix(), intent4Update);
284 pushedRouteIntents.put(routeEntry5.prefix(), intent5New); 294 pushedRouteIntents.put(routeEntry5.prefix(), intent5New);
285 pushedRouteIntents.put(routeEntry6.prefix(), intent6); 295 pushedRouteIntents.put(routeEntry6.prefix(), intent6);
296 + pushedRouteIntents.put(routeEntry7.prefix(), intent7);
286 TestUtils.setField(router, "pushedRouteIntents", pushedRouteIntents); 297 TestUtils.setField(router, "pushedRouteIntents", pushedRouteIntents);
287 298
288 // Set up expectation 299 // Set up expectation
289 reset(intentService); 300 reset(intentService);
290 Set<Intent> intents = new HashSet<Intent>(); 301 Set<Intent> intents = new HashSet<Intent>();
291 intents.add(intent1); 302 intents.add(intent1);
303 + expect(intentService.getIntentState(intent1.id()))
304 + .andReturn(IntentState.INSTALLED).anyTimes();
292 intents.add(intent2); 305 intents.add(intent2);
306 + expect(intentService.getIntentState(intent2.id()))
307 + .andReturn(IntentState.INSTALLED).anyTimes();
293 intents.add(intent4); 308 intents.add(intent4);
309 + expect(intentService.getIntentState(intent4.id()))
310 + .andReturn(IntentState.INSTALLED).anyTimes();
294 intents.add(intent5); 311 intents.add(intent5);
312 + expect(intentService.getIntentState(intent5.id()))
313 + .andReturn(IntentState.INSTALLED).anyTimes();
314 + intents.add(intent7);
315 + expect(intentService.getIntentState(intent7.id()))
316 + .andReturn(IntentState.WITHDRAWING).anyTimes();
295 expect(intentService.getIntents()).andReturn(intents).anyTimes(); 317 expect(intentService.getIntents()).andReturn(intents).anyTimes();
296 318
297 intentService.withdraw(intent2); 319 intentService.withdraw(intent2);
...@@ -299,6 +321,7 @@ public class IntentSyncTest { ...@@ -299,6 +321,7 @@ public class IntentSyncTest {
299 intentService.withdraw(intent4); 321 intentService.withdraw(intent4);
300 intentService.submit(intent4Update); 322 intentService.submit(intent4Update);
301 intentService.submit(intent6); 323 intentService.submit(intent6);
324 + intentService.submit(intent7);
302 replay(intentService); 325 replay(intentService);
303 326
304 // Start the test 327 // Start the test
...@@ -306,14 +329,14 @@ public class IntentSyncTest { ...@@ -306,14 +329,14 @@ public class IntentSyncTest {
306 TestUtils.callMethod(router, "syncIntents", new Class<?>[] {}); 329 TestUtils.callMethod(router, "syncIntents", new Class<?>[] {});
307 330
308 // Verify 331 // Verify
309 - assertEquals(router.getRoutes().size(), 5); 332 + assertEquals(router.getRoutes().size(), 6);
310 assertTrue(router.getRoutes().contains(routeEntry1)); 333 assertTrue(router.getRoutes().contains(routeEntry1));
311 assertTrue(router.getRoutes().contains(routeEntry3)); 334 assertTrue(router.getRoutes().contains(routeEntry3));
312 assertTrue(router.getRoutes().contains(routeEntry4Update)); 335 assertTrue(router.getRoutes().contains(routeEntry4Update));
313 assertTrue(router.getRoutes().contains(routeEntry5)); 336 assertTrue(router.getRoutes().contains(routeEntry5));
314 assertTrue(router.getRoutes().contains(routeEntry6)); 337 assertTrue(router.getRoutes().contains(routeEntry6));
315 338
316 - assertEquals(router.getPushedRouteIntents().size(), 5); 339 + assertEquals(router.getPushedRouteIntents().size(), 6);
317 assertTrue(router.getPushedRouteIntents().contains(intent1)); 340 assertTrue(router.getPushedRouteIntents().contains(intent1));
318 assertTrue(router.getPushedRouteIntents().contains(intent3)); 341 assertTrue(router.getPushedRouteIntents().contains(intent3));
319 assertTrue(router.getPushedRouteIntents().contains(intent4Update)); 342 assertTrue(router.getPushedRouteIntents().contains(intent4Update));
......