tom

Merge remote-tracking branch 'origin/master'

......@@ -34,7 +34,7 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class);
System.exit(0);
}
public static void startStandalone(String... args) throws Exception {
public static void startStandalone(String[] args) throws Exception {
String host = args.length > 0 ? args[0] : "localhost";
int port = args.length > 1 ? Integer.parseInt(args[1]) : 8081;
int warmup = args.length > 2 ? Integer.parseInt(args[2]) : 1000;
......@@ -46,7 +46,7 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class);
metrics.activate();
MetricsFeature feature = new MetricsFeature("latency");
MetricsComponent component = metrics.registerComponent("NettyMessaging");
log.info("warmup....");
log.info("connecting " + host + ":" + port + " warmup:" + warmup + " iterations:" + iterations);
for (int i = 0; i < warmup; i++) {
messaging.sendAsync(endpoint, "simple", "Hello World".getBytes());
......@@ -73,6 +73,7 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class);
// System.out.println("Got back:" + new String(response.get(2, TimeUnit.SECONDS)));
context.stop();
}
metrics.deactivate();
}
public static class TestNettyMessagingService extends NettyMessagingService {
......
......@@ -18,15 +18,15 @@ public class SimpleNettyClientCommand extends AbstractShellCommand {
required = false, multiValued = false)
String hostname = "localhost";
@Argument(index = 3, name = "port", description = "Port",
@Argument(index = 1, name = "port", description = "Port",
required = false, multiValued = false)
String port = "8081";
@Argument(index = 1, name = "warmupCount", description = "Warm-up count",
@Argument(index = 2, name = "warmupCount", description = "Warm-up count",
required = false, multiValued = false)
String warmupCount = "1000";
@Argument(index = 2, name = "messageCount", description = "Message count",
@Argument(index = 3, name = "messageCount", description = "Message count",
required = false, multiValued = false)
String messageCount = "100000";
......
package org.onlab.onos.net.intent;
import java.util.concurrent.Future;
import org.onlab.onos.net.flow.CompletedBatchOperation;
/**
* Abstraction of entity capable of installing intents to the environment.
*/
......@@ -10,7 +14,7 @@ public interface IntentInstaller<T extends InstallableIntent> {
* @param intent intent to be installed
* @throws IntentException if issues are encountered while installing the intent
*/
void install(T intent);
Future<CompletedBatchOperation> install(T intent);
/**
* Uninstalls the specified intent from the environment.
......@@ -18,5 +22,5 @@ public interface IntentInstaller<T extends InstallableIntent> {
* @param intent intent to be uninstalled
* @throws IntentException if issues are encountered while uninstalling the intent
*/
void uninstall(T intent);
Future<CompletedBatchOperation> uninstall(T intent);
}
......
package org.onlab.onos.net.intent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.onlab.onos.net.intent.IntentEvent.Type.FAILED;
import static org.onlab.onos.net.intent.IntentEvent.Type.INSTALLED;
import static org.onlab.onos.net.intent.IntentEvent.Type.SUBMITTED;
import static org.onlab.onos.net.intent.IntentEvent.Type.WITHDRAWN;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Future;
import static org.junit.Assert.*;
import static org.onlab.onos.net.intent.IntentEvent.Type.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.onos.net.flow.CompletedBatchOperation;
/**
* Suite of tests for the intent service contract.
......@@ -290,17 +298,19 @@ public class IntentServiceTest {
}
@Override
public void install(TestInstallableIntent intent) {
public Future<CompletedBatchOperation> install(TestInstallableIntent intent) {
if (fail) {
throw new IntentException("install failed by design");
}
return null;
}
@Override
public void uninstall(TestInstallableIntent intent) {
public Future<CompletedBatchOperation> uninstall(TestInstallableIntent intent) {
if (fail) {
throw new IntentException("remove failed by design");
}
return null;
}
}
......
......@@ -13,12 +13,14 @@ import static org.onlab.util.Tools.namedThreads;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
......@@ -28,6 +30,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.event.AbstractListenerRegistry;
import org.onlab.onos.event.EventDeliveryService;
import org.onlab.onos.net.flow.CompletedBatchOperation;
import org.onlab.onos.net.intent.InstallableIntent;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentCompiler;
......@@ -44,7 +47,9 @@ import org.onlab.onos.net.intent.IntentStore;
import org.onlab.onos.net.intent.IntentStoreDelegate;
import org.slf4j.Logger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
/**
* An implementation of Intent Manager.
......@@ -67,7 +72,8 @@ public class IntentManager
private final AbstractListenerRegistry<IntentEvent, IntentListener>
listenerRegistry = new AbstractListenerRegistry<>();
private final ExecutorService executor = newSingleThreadExecutor(namedThreads("onos-intents"));
private ExecutorService executor;
private ExecutorService monitorExecutor;
private final IntentStoreDelegate delegate = new InternalStoreDelegate();
private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
......@@ -86,6 +92,8 @@ public class IntentManager
store.setDelegate(delegate);
trackerService.setDelegate(topoDelegate);
eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
executor = newSingleThreadExecutor(namedThreads("onos-intents"));
monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor"));
log.info("Started");
}
......@@ -94,6 +102,8 @@ public class IntentManager
store.unsetDelegate(delegate);
trackerService.unsetDelegate(topoDelegate);
eventDispatcher.removeSink(IntentEvent.class);
executor.shutdown();
monitorExecutor.shutdown();
log.info("Stopped");
}
......@@ -240,14 +250,23 @@ public class IntentManager
}
}
// FIXME: To make SDN-IP workable ASAP, only single level compilation is implemented
// TODO: implement compilation traversing tree structure
/**
* Compiles an intent recursively.
*
* @param intent intent
* @return result of compilation
*/
private List<InstallableIntent> compileIntent(Intent intent) {
if (intent instanceof InstallableIntent) {
return ImmutableList.of((InstallableIntent) intent);
}
List<InstallableIntent> installable = new ArrayList<>();
// TODO do we need to registerSubclassCompiler?
for (Intent compiled : getCompiler(intent).compile(intent)) {
InstallableIntent installableIntent = (InstallableIntent) compiled;
installable.add(installableIntent);
installable.addAll(compileIntent(compiled));
}
return installable;
}
......@@ -261,6 +280,7 @@ public class IntentManager
// Indicate that the intent is entering the installing phase.
store.setState(intent, INSTALLING);
List<Future<CompletedBatchOperation>> installFutures = Lists.newArrayList();
try {
List<InstallableIntent> installables = store.getInstallableIntents(intent.id());
if (installables != null) {
......@@ -268,17 +288,20 @@ public class IntentManager
registerSubclassInstallerIfNeeded(installable);
trackerService.addTrackedResources(intent.id(),
installable.requiredLinks());
getInstaller(installable).install(installable);
Future<CompletedBatchOperation> future = getInstaller(installable).install(installable);
installFutures.add(future);
}
}
eventDispatcher.post(store.setState(intent, INSTALLED));
// FIXME we have to wait for the installable intents
//eventDispatcher.post(store.setState(intent, INSTALLED));
monitorExecutor.execute(new IntentInstallMonitor(intent, installFutures, INSTALLED));
} catch (Exception e) {
log.warn("Unable to install intent {} due to: {}", intent.id(), e);
uninstallIntent(intent);
uninstallIntent(intent, RECOMPILING);
// If compilation failed, kick off the recompiling phase.
executeRecompilingPhase(intent);
// FIXME
//executeRecompilingPhase(intent);
}
}
......@@ -327,12 +350,14 @@ public class IntentManager
private void executeWithdrawingPhase(Intent intent) {
// Indicate that the intent is being withdrawn.
store.setState(intent, WITHDRAWING);
uninstallIntent(intent);
uninstallIntent(intent, WITHDRAWN);
// If all went well, disassociate the top-level intent with its
// installable derivatives and mark it as withdrawn.
store.removeInstalledIntents(intent.id());
eventDispatcher.post(store.setState(intent, WITHDRAWN));
// FIXME need to clean up
//store.removeInstalledIntents(intent.id());
// FIXME
//eventDispatcher.post(store.setState(intent, WITHDRAWN));
}
/**
......@@ -340,14 +365,17 @@ public class IntentManager
*
* @param intent intent to be uninstalled
*/
private void uninstallIntent(Intent intent) {
private void uninstallIntent(Intent intent, IntentState nextState) {
List<Future<CompletedBatchOperation>> uninstallFutures = Lists.newArrayList();
try {
List<InstallableIntent> installables = store.getInstallableIntents(intent.id());
if (installables != null) {
for (InstallableIntent installable : installables) {
getInstaller(installable).uninstall(installable);
Future<CompletedBatchOperation> future = getInstaller(installable).uninstall(installable);
uninstallFutures.add(future);
}
}
monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallFutures, nextState));
} catch (IntentException e) {
log.warn("Unable to uninstall intent {} due to: {}", intent.id(), e);
}
......@@ -422,9 +450,10 @@ public class IntentManager
// Attempt recompilation of the specified intents first.
for (IntentId intentId : intentIds) {
Intent intent = getIntent(intentId);
uninstallIntent(intent);
uninstallIntent(intent, RECOMPILING);
executeRecompilingPhase(intent);
//FIXME
//executeRecompilingPhase(intent);
}
if (compileAllFailed) {
......@@ -460,4 +489,44 @@ public class IntentManager
}
}
private class IntentInstallMonitor implements Runnable {
private final Intent intent;
private final List<Future<CompletedBatchOperation>> futures;
private final IntentState nextState;
public IntentInstallMonitor(Intent intent,
List<Future<CompletedBatchOperation>> futures, IntentState nextState) {
this.intent = intent;
this.futures = futures;
this.nextState = nextState;
}
private void updateIntent(Intent intent) {
if (nextState == RECOMPILING) {
executor.execute(new IntentTask(nextState, intent));
} else if (nextState == INSTALLED || nextState == WITHDRAWN) {
eventDispatcher.post(store.setState(intent, nextState));
} else {
log.warn("Invalid next intent state {} for intent {}", nextState, intent);
}
}
@Override
public void run() {
for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
Future<CompletedBatchOperation> future = i.next();
if (future.isDone()) {
// TODO: we may want to get the future here
i.remove();
}
}
if (futures.isEmpty()) {
updateIntent(intent);
} else {
// resubmit ourselves if we are not done yet
monitorExecutor.submit(this);
}
}
}
}
......
......@@ -5,7 +5,7 @@ import static org.slf4j.LoggerFactory.getLogger;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
......@@ -15,6 +15,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.flow.CompletedBatchOperation;
import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.FlowRule;
......@@ -57,8 +58,26 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
intentManager.unregisterInstaller(PathIntent.class);
}
/**
* Apply a list of FlowRules.
*
* @param rules rules to apply
*/
private Future<CompletedBatchOperation> applyBatch(List<FlowRuleBatchEntry> rules) {
FlowRuleBatchOperation batch = new FlowRuleBatchOperation(rules);
Future<CompletedBatchOperation> future = flowRuleService.applyBatch(batch);
return future;
// try {
// //FIXME don't do this here
// future.get();
// } catch (InterruptedException | ExecutionException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
@Override
public void install(PathIntent intent) {
public Future<CompletedBatchOperation> install(PathIntent intent) {
TrafficSelector.Builder builder =
DefaultTrafficSelector.builder(intent.selector());
Iterator<Link> links = intent.path().links().iterator();
......@@ -74,20 +93,14 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
builder.build(), treatment,
123, appId, 600);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
//flowRuleService.applyFlowRules(rule);
prev = link.dst();
}
FlowRuleBatchOperation batch = new FlowRuleBatchOperation(rules);
try {
flowRuleService.applyBatch(batch).get();
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return applyBatch(rules);
}
@Override
public void uninstall(PathIntent intent) {
public Future<CompletedBatchOperation> uninstall(PathIntent intent) {
TrafficSelector.Builder builder =
DefaultTrafficSelector.builder(intent.selector());
Iterator<Link> links = intent.path().links().iterator();
......@@ -103,15 +116,131 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
builder.build(), treatment,
123, appId, 600);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
//flowRuleService.removeFlowRules(rule);
prev = link.dst();
}
FlowRuleBatchOperation batch = new FlowRuleBatchOperation(rules);
try {
flowRuleService.applyBatch(batch).get();
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return applyBatch(rules);
}
// TODO refactor below this line... ----------------------------
/**
* Generates the series of MatchActionOperations from the
* {@link FlowBatchOperation}.
* <p>
* FIXME: Currently supporting PacketPathFlow and SingleDstTreeFlow only.
* <p>
* FIXME: MatchActionOperations should have dependency field to the other
* match action operations, and this method should use this.
*
* @param op the {@link FlowBatchOperation} object
* @return the list of {@link MatchActionOperations} objects
*/
/*
private List<MatchActionOperations>
generateMatchActionOperationsList(FlowBatchOperation op) {
// MatchAction operations at head (ingress) switches.
MatchActionOperations headOps = matchActionService.createOperationsList();
// MatchAction operations at rest of the switches.
MatchActionOperations tailOps = matchActionService.createOperationsList();
MatchActionOperations removeOps = matchActionService.createOperationsList();
for (BatchOperationEntry<Operator, ?> e : op.getOperations()) {
if (e.getOperator() == FlowBatchOperation.Operator.ADD) {
generateInstallMatchActionOperations(e, tailOps, headOps);
} else if (e.getOperator() == FlowBatchOperation.Operator.REMOVE) {
generateRemoveMatchActionOperations(e, removeOps);
} else {
throw new UnsupportedOperationException(
"FlowManager supports ADD and REMOVE operations only.");
}
}
return Arrays.asList(tailOps, headOps, removeOps);
}
*/
/**
* Generates MatchActionOperations for an INSTALL FlowBatchOperation.
* <p/>
* FIXME: Currently only supports flows that generate exactly two match
* action operation sets.
*
* @param e Flow BatchOperationEntry
* @param tailOps MatchActionOperation set that the tail
* MatchActionOperations will be placed in
* @param headOps MatchActionOperation set that the head
* MatchActionOperations will be placed in
*/
/*
private void generateInstallMatchActionOperations(
BatchOperationEntry<Operator, ?> e,
MatchActionOperations tailOps,
MatchActionOperations headOps) {
if (!(e.getTarget() instanceof Flow)) {
throw new IllegalStateException(
"The target is not Flow object: " + e.getTarget());
}
// Compile flows to match-actions
Flow flow = (Flow) e.getTarget();
List<MatchActionOperations> maOps = flow.compile(
e.getOperator(), matchActionService);
verifyNotNull(maOps, "Could not compile the flow: " + flow);
verify(maOps.size() == 2,
"The flow generates unspported match-action operations.");
// Map FlowId to MatchActionIds
for (MatchActionOperations maOp : maOps) {
for (MatchActionOperationEntry entry : maOp.getOperations()) {
flowMatchActionsMap.put(
KryoFactory.serialize(flow.getId()),
KryoFactory.serialize(entry.getTarget()));
}
}
// Merge match-action operations
for (MatchActionOperationEntry mae : maOps.get(0).getOperations()) {
verify(mae.getOperator() == MatchActionOperations.Operator.INSTALL);
tailOps.addOperation(mae);
}
for (MatchActionOperationEntry mae : maOps.get(1).getOperations()) {
verify(mae.getOperator() == MatchActionOperations.Operator.INSTALL);
headOps.addOperation(mae);
}
}
*/
/**
* Generates MatchActionOperations for a REMOVE FlowBatchOperation.
*
* @param e Flow BatchOperationEntry
* @param removeOps MatchActionOperation set that the remove
* MatchActionOperations will be placed in
*/
/*
private void generateRemoveMatchActionOperations(
BatchOperationEntry<Operator, ?> e,
MatchActionOperations removeOps) {
if (!(e.getTarget() instanceof FlowId)) {
throw new IllegalStateException(
"The target is not a FlowId object: " + e.getTarget());
}
// Compile flows to match-actions
FlowId flowId = (FlowId) e.getTarget();
for (byte[] matchActionIdBytes :
flowMatchActionsMap.remove(KryoFactory.serialize(flowId))) {
MatchActionId matchActionId = KryoFactory.deserialize(matchActionIdBytes);
removeOps.addOperation(new MatchActionOperationEntry(
MatchActionOperations.Operator.REMOVE, matchActionId));
}
}
*/
}
......