Fixed a few intent synchronization issues.
Also added a CLI command to test SDN-IP primary switchover. Change-Id: Id31f79262a2b607f987adad2fdb3eb54eb939fea
Showing
7 changed files
with
93 additions
and
42 deletions
... | @@ -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)); | ... | ... |
-
Please register or login to post a comment