Thomas Vachuska

Fixing an issue where intents fail to re-route after a node is restarted; caused…

… by failure to register intent resources correctly.

Change-Id: I239e3b538d5b9134422fa629514e095e4914bb0c
......@@ -66,6 +66,13 @@ public interface IntentService {
Iterable<Intent> getIntents();
/**
* Returns an iterable of intent data objects currently in the system.
*
* @return set of intent data objects
*/
Iterable<IntentData> getIntentData();
/**
* Returns the number of intents currently in the system.
*
* @return number of intents
......
......@@ -29,4 +29,12 @@ public interface IntentStoreDelegate extends StoreDelegate<IntentEvent> {
* @param intentData intent data object
*/
void process(IntentData intentData);
/**
* Called when a new intent has been updated for which this node is the master.
*
* @param intentData intent data object
*/
default void onUpdate(IntentData intentData) {
}
}
......
......@@ -183,6 +183,11 @@ public class FakeIntentManager implements TestableIntentService {
}
@Override
public Iterable<IntentData> getIntentData() {
throw new UnsupportedOperationException();
}
@Override
public long getIntentCount() {
return intents.size();
}
......
......@@ -43,6 +43,11 @@ public class IntentServiceAdapter implements IntentService {
}
@Override
public Iterable<IntentData> getIntentData() {
return null;
}
@Override
public long getIntentCount() {
return 0;
}
......
......@@ -182,6 +182,12 @@ public class IntentManager
}
@Override
public Iterable<IntentData> getIntentData() {
checkPermission(Permission.INTENT_READ);
return store.getIntentData(false, 0);
}
@Override
public long getIntentCount() {
checkPermission(Permission.INTENT_READ);
......@@ -258,6 +264,11 @@ public class IntentManager
public void process(IntentData data) {
accumulator.add(data);
}
@Override
public void onUpdate(IntentData intentData) {
trackerService.trackIntent(intentData);
}
}
private void buildAndSubmitBatches(Iterable<Key> intentKeys,
......
......@@ -17,6 +17,7 @@ package org.onosproject.net.intent.impl;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
......@@ -40,6 +41,7 @@ import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.PartitionEvent;
......@@ -57,7 +59,9 @@ import org.slf4j.Logger;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
......@@ -69,7 +73,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onlab.util.Tools.isNullOrEmpty;
import static org.onosproject.net.LinkKey.linkKey;
import static org.onosproject.net.intent.IntentState.INSTALLED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_UPDATED;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -84,6 +90,8 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
private final Logger log = getLogger(getClass());
private final ConcurrentMap<Key, Intent> intents = Maps.newConcurrentMap();
private final SetMultimap<LinkKey, Key> intentsByLink =
//TODO this could be slow as a point of synchronization
synchronizedSetMultimap(HashMultimap.<LinkKey, Key>create());
......@@ -195,6 +203,46 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
}
}
@Override
public void trackIntent(IntentData intentData) {
//NOTE: This will be called for intents that are being added to the store
// locally (i.e. every intent update)
Key key = intentData.key();
Intent intent = intentData.intent();
boolean isLocal = intentService.isLocal(key);
List<Intent> installables = intentData.installables();
if (log.isTraceEnabled()) {
log.trace("intent {}, old: {}, new: {}, installableCount: {}, resourceCount: {}",
key,
intentsByDevice.values().contains(key),
isLocal,
installables.size(),
intent.resources().size() +
installables.stream()
.mapToLong(i -> i.resources().size()).sum());
}
if (isNullOrEmpty(installables) && intentData.state() == INSTALLED) {
log.warn("Intent {} is INSTALLED with no installables", key);
}
if (isLocal) {
addTrackedResources(key, intent.resources());
for (Intent installable : installables) {
addTrackedResources(key, installable.resources());
}
// FIXME check all resources against current topo service(s); recompile if necessary
} else {
removeTrackedResources(key, intent.resources());
for (Intent installable : installables) {
removeTrackedResources(key, installable.resources());
}
}
}
// Internal re-actor to topology change events.
private class InternalTopologyListener implements TopologyListener {
@Override
......@@ -371,25 +419,11 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
}
try {
//FIXME very inefficient
for (Intent intent : intentService.getIntents()) {
for (IntentData intentData : intentService.getIntentData()) {
try {
if (intentService.isLocal(intent.key())) {
log.trace("intent {}, old: {}, new: {}",
intent.key(), intentsByDevice.values().contains(intent.key()), true);
addTrackedResources(intent.key(), intent.resources());
intentService.getInstallableIntents(intent.key()).stream()
.forEach(installable ->
addTrackedResources(intent.key(), installable.resources()));
} else {
log.trace("intent {}, old: {}, new: {}",
intent.key(), intentsByDevice.values().contains(intent.key()), false);
removeTrackedResources(intent.key(), intent.resources());
intentService.getInstallableIntents(intent.key()).stream()
.forEach(installable ->
removeTrackedResources(intent.key(), installable.resources()));
}
trackIntent(intentData);
} catch (NullPointerException npe) {
log.warn("intent error {}", intent.key(), npe);
log.warn("intent error {}", intentData.key(), npe);
}
}
} catch (Exception e) {
......
......@@ -15,11 +15,12 @@
*/
package org.onosproject.net.intent.impl;
import java.util.Collection;
import org.onosproject.net.NetworkResource;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.Key;
import java.util.Collection;
/**
* Auxiliary service for tracking intent path flows and for notifying the
* intent service of environment changes via topology change delegate.
......@@ -59,4 +60,10 @@ public interface ObjectiveTrackerService {
void removeTrackedResources(Key intentKey,
Collection<NetworkResource> resources);
/**
* Submits the specified intent data to be tracked.
*
* @param intentData intent data object to be tracked
*/
void trackIntent(IntentData intentData);
}
......
......@@ -28,13 +28,14 @@ import org.junit.Ignore;
import org.junit.Test;
import org.onosproject.TestApplicationId;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.common.event.impl.TestEventDispatcher;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.impl.TestCoreManager;
import org.onosproject.common.event.impl.TestEventDispatcher;
import org.onosproject.net.NetworkResource;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
import org.onosproject.net.intent.IntentEvent.Type;
import org.onosproject.net.intent.IntentExtensionService;
......@@ -145,6 +146,11 @@ public class IntentManagerTest {
public void removeTrackedResources(Key key, Collection<NetworkResource> resources) {
//TODO
}
@Override
public void trackIntent(IntentData intentData) {
//TODO
}
}
private static class MockInstallableIntent extends FlowRuleIntent {
......
......@@ -288,11 +288,16 @@ public class GossipIntentStore
private final class InternalCurrentListener implements
EventuallyConsistentMapListener<Key, IntentData> {
@Override
public void event(
EventuallyConsistentMapEvent<Key, IntentData> event) {
if (event.type() == EventuallyConsistentMapEvent.Type.PUT) {
public void event(EventuallyConsistentMapEvent<Key, IntentData> event) {
IntentData intentData = event.value();
if (event.type() == EventuallyConsistentMapEvent.Type.PUT) {
// The current intents map has been updated. If we are master for
// this intent's partition, notify the Manager that it should
// emit notifications about updated tracked resources.
if (delegate != null && isMaster(event.value().intent().key())) {
delegate.onUpdate(new IntentData(intentData)); // copy for safety, likely unnecessary
}
notifyDelegateIfNotNull(IntentEvent.getEvent(intentData));
}
}
......
......@@ -7,3 +7,4 @@ export OC3="10.128.11.3"
export OCN="10.128.11.4"
export OCT=$OC1
export ONOS_APPS=drivers,openflow,proxyarp
\ No newline at end of file
......