Praseed Balakrishnan

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 94 changed files with 3033 additions and 519 deletions
package org.onlab.onos.metrics.intent;
import java.util.List;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Meter;
import org.onlab.metrics.EventMetric;
import org.onlab.onos.net.intent.IntentEvent;
/**
......@@ -18,68 +16,32 @@ public interface IntentMetricsService {
public List<IntentEvent> getEvents();
/**
* Gets the Metrics' Gauge for the intent SUBMITTED event timestamp
* (ms from the epoch).
* Gets the Event Metric for the intent SUBMITTED events.
*
* @return the Metrics' Gauge for the intent SUBMITTED event timestamp
* (ms from the epoch)
* @return the Event Metric for the intent SUBMITTED events.
*/
public Gauge<Long> intentSubmittedTimestampEpochMsGauge();
public EventMetric intentSubmittedEventMetric();
/**
* Gets the Metrics' Gauge for the intent INSTALLED event timestamp
* (ms from the epoch).
* Gets the Event Metric for the intent INSTALLED events.
*
* @return the Metrics' Gauge for the intent INSTALLED event timestamp
* (ms from the epoch)
* @return the Event Metric for the intent INSTALLED events.
*/
public Gauge<Long> intentInstalledTimestampEpochMsGauge();
public EventMetric intentInstalledEventMetric();
/**
* Gets the Metrics' Gauge for the intent WITHDRAW_REQUESTED event
* timestamp (ms from the epoch).
* Gets the Event Metric for the intent WITHDRAW_REQUESTED events.
*
* TODO: This intent event is not implemented yet.
*
* @return the Metrics' Gauge for the intent WITHDRAW_REQUESTED event
* timestamp (ms from the epoch)
*/
public Gauge<Long> intentWithdrawRequestedTimestampEpochMsGauge();
/**
* Gets the Metrics' Gauge for the intent WITHDRAWN event timestamp
* (ms from the epoch).
*
* @return the Metrics' Gauge for the intent WITHDRAWN event timestamp
* (ms from the epoch)
*/
public Gauge<Long> intentWithdrawnTimestampEpochMsGauge();
/**
* Gets the Metrics' Meter for the submitted intents event rate.
*
* @return the Metrics' Meter for the submitted intents event rate
*/
public Meter intentSubmittedRateMeter();
/**
* Gets the Metrics' Meter for the installed intents event rate.
*
* @return the Metrics' Meter for the installed intent event rate
*/
public Meter intentInstalledRateMeter();
/**
* Gets the Metrics' Meter for the withdraw requested intents event rate.
*
* @return the Metrics' Meter for the withdraw requested intents event rate
* @return the Event Metric for the intent WITHDRAW_REQUESTED events.
*/
public Meter intentWithdrawRequestedRateMeter();
public EventMetric intentWithdrawRequestedEventMetric();
/**
* Gets the Metrics' Meter for the withdraw completed intents event rate.
* Gets the Event Metric for the intent WITHDRAWN events.
*
* @return the Metrics' Meter for the withdraw completed intents event rate
* @return the Event Metric for the intent WITHDRAWN events.
*/
public Meter intentWithdrawnRateMeter();
public EventMetric intentWithdrawnEventMetric();
}
......
......@@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Command;
import org.onlab.metrics.EventMetric;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.metrics.intent.IntentMetricsService;
......@@ -29,8 +30,6 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand {
@Override
protected void execute() {
IntentMetricsService service = get(IntentMetricsService.class);
Gauge<Long> gauge;
Meter meter;
if (outputJson()) {
ObjectMapper mapper = new ObjectMapper()
......@@ -38,49 +37,49 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand {
TimeUnit.MILLISECONDS,
false));
ObjectNode result = mapper.createObjectNode();
//
gauge = service.intentSubmittedTimestampEpochMsGauge();
result.put("intentSubmittedTimestamp", json(mapper, gauge));
gauge = service.intentInstalledTimestampEpochMsGauge();
result.put("intentInstalledTimestamp", json(mapper, gauge));
gauge = service.intentWithdrawRequestedTimestampEpochMsGauge();
result.put("intentWithdrawRequestedTimestamp",
json(mapper, gauge));
gauge = service.intentWithdrawnTimestampEpochMsGauge();
result.put("intentWithdrawnTimestamp", json(mapper, gauge));
//
meter = service.intentSubmittedRateMeter();
result.put("intentSubmittedRate", json(mapper, meter));
meter = service.intentInstalledRateMeter();
result.put("intentInstalledRate", json(mapper, meter));
meter = service.intentWithdrawRequestedRateMeter();
result.put("intentWithdrawRequestedRate", json(mapper, meter));
meter = service.intentWithdrawnRateMeter();
result.put("intentWithdrawnRate", json(mapper, meter));
//
result = json(mapper, result, "intentSubmitted",
service.intentSubmittedEventMetric());
result = json(mapper, result, "intentInstalled",
service.intentInstalledEventMetric());
result = json(mapper, result, "intentWithdrawRequested",
service.intentWithdrawRequestedEventMetric());
result = json(mapper, result, "intentWithdrawn",
service.intentWithdrawnEventMetric());
print("%s", result);
} else {
gauge = service.intentSubmittedTimestampEpochMsGauge();
printGauge("Submitted", gauge);
gauge = service.intentInstalledTimestampEpochMsGauge();
printGauge("Installed", gauge);
gauge = service.intentWithdrawRequestedTimestampEpochMsGauge();
printGauge("Withdraw Requested", gauge);
gauge = service.intentWithdrawnTimestampEpochMsGauge();
printGauge("Withdrawn", gauge);
//
meter = service.intentSubmittedRateMeter();
printMeter("Submitted", meter);
meter = service.intentInstalledRateMeter();
printMeter("Installed", meter);
meter = service.intentWithdrawRequestedRateMeter();
printMeter("Withdraw Requested", meter);
meter = service.intentWithdrawnRateMeter();
printMeter("Withdrawn", meter);
printEventMetric("Submitted",
service.intentSubmittedEventMetric());
printEventMetric("Installed",
service.intentInstalledEventMetric());
printEventMetric("Withdraw Requested",
service.intentWithdrawRequestedEventMetric());
printEventMetric("Withdrawn",
service.intentWithdrawnEventMetric());
}
}
/**
* Produces JSON node for an Event Metric.
*
* @param mapper the JSON object mapper to use
* @param objectNode the JSON object node to use
* @param propertyPrefix the property prefix to use
* @param eventMetric the Event Metric with the data
* @return JSON object node for the Event Metric
*/
private ObjectNode json(ObjectMapper mapper, ObjectNode objectNode,
String propertyPrefix, EventMetric eventMetric) {
String gaugeName = propertyPrefix + "Timestamp";
String meterName = propertyPrefix + "Rate";
Gauge<Long> gauge = eventMetric.lastEventTimestampGauge();
Meter meter = eventMetric.eventRateMeter();
objectNode.put(gaugeName, json(mapper, gauge));
objectNode.put(meterName, json(mapper, meter));
return objectNode;
}
/**
* Produces JSON node for an Object.
*
* @param mapper the JSON object mapper to use
......@@ -94,8 +93,8 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand {
//
try {
final String objectJson = mapper.writeValueAsString(object);
JsonNode objectNode = mapper.readTree(objectJson);
return objectNode;
JsonNode jsonNode = mapper.readTree(objectJson);
return jsonNode;
} catch (JsonProcessingException e) {
log.error("Error writing value as JSON string", e);
} catch (IOException e) {
......@@ -105,28 +104,26 @@ public class IntentEventsMetricsCommand extends AbstractShellCommand {
}
/**
* Prints a Gauge.
* Prints an Event Metric.
*
* @param operationStr the string with the intent operation to print
* @param gauge the Gauge to print
* @param eventMetric the Event Metric to print
*/
private void printGauge(String operationStr, Gauge<Long> gauge) {
private void printEventMetric(String operationStr,
EventMetric eventMetric) {
Gauge<Long> gauge = eventMetric.lastEventTimestampGauge();
Meter meter = eventMetric.eventRateMeter();
TimeUnit rateUnit = TimeUnit.SECONDS;
double rateFactor = rateUnit.toSeconds(1);
// Print the Gauge
print(FORMAT_GAUGE, operationStr, gauge.getValue());
}
/**
* Prints a Meter.
*
* @param operationStr the string with the intent operation to print
* @param meter the Meter to print
*/
private void printMeter(String operationStr, Meter meter) {
TimeUnit rateUnit = TimeUnit.SECONDS;
double rateFactor = rateUnit.toSeconds(1);
print(FORMAT_METER, operationStr, meter.getCount(),
meter.getMeanRate() * rateFactor,
meter.getOneMinuteRate() * rateFactor,
meter.getFiveMinuteRate() * rateFactor,
meter.getFifteenMinuteRate() * rateFactor);
// Print the Meter
print(FORMAT_METER, operationStr, meter.getCount(),
meter.getMeanRate() * rateFactor,
meter.getOneMinuteRate() * rateFactor,
meter.getFiveMinuteRate() * rateFactor,
meter.getFifteenMinuteRate() * rateFactor);
}
}
......
......@@ -5,8 +5,6 @@ import static org.slf4j.LoggerFactory.getLogger;
import java.util.LinkedList;
import java.util.List;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Meter;
import com.google.common.collect.ImmutableList;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
......@@ -14,8 +12,7 @@ import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.metrics.MetricsComponent;
import org.onlab.metrics.MetricsFeature;
import org.onlab.metrics.EventMetric;
import org.onlab.metrics.MetricsService;
import org.onlab.onos.event.Event;
import org.onlab.onos.net.device.DeviceEvent;
......@@ -48,6 +45,8 @@ public class TopologyMetrics implements TopologyMetricsService {
protected LinkService linkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MetricsService metricsService;
private LinkedList<Event> lastEvents = new LinkedList<>();
private static final int LAST_EVENTS_MAX_N = 100;
......@@ -61,22 +60,22 @@ public class TopologyMetrics implements TopologyMetricsService {
//
// Metrics
//
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MetricsService metricsService;
//
private static final String COMPONENT_NAME = "Topology";
private static final String FEATURE_NAME = "EventNotification";
private static final String GAUGE_NAME = "LastEventTimestamp.EpochMs";
private static final String METER_NAME = "EventRate";
private static final String FEATURE_DEVICE_NAME = "DeviceEvent";
private static final String FEATURE_HOST_NAME = "HostEvent";
private static final String FEATURE_LINK_NAME = "LinkEvent";
private static final String FEATURE_GRAPH_NAME = "GraphEvent";
//
private MetricsComponent metricsComponent;
private MetricsFeature metricsFeatureEventNotification;
// Event metrics:
// - Device events
// - Host events
// - Link events
// - Topology Graph events
//
// Timestamp of the last Topology event (ms from the Epoch)
private volatile long lastEventTimestampEpochMs = 0;
private Gauge<Long> lastEventTimestampEpochMsGauge;
// Rate of the Topology events published to the Topology listeners
private Meter eventRateMeter;
private EventMetric topologyDeviceEventMetric;
private EventMetric topologyHostEventMetric;
private EventMetric topologyLinkEventMetric;
private EventMetric topologyGraphEventMetric;
@Activate
protected void activate() {
......@@ -113,27 +112,34 @@ public class TopologyMetrics implements TopologyMetricsService {
}
@Override
public Gauge<Long> lastEventTimestampEpochMsGauge() {
return lastEventTimestampEpochMsGauge;
public EventMetric topologyDeviceEventMetric() {
return topologyDeviceEventMetric;
}
@Override
public EventMetric topologyHostEventMetric() {
return topologyHostEventMetric;
}
@Override
public Meter eventRateMeter() {
return eventRateMeter;
public EventMetric topologyLinkEventMetric() {
return topologyLinkEventMetric;
}
@Override
public EventMetric topologyGraphEventMetric() {
return topologyGraphEventMetric;
}
/**
* Records an event.
*
* @param event the event to record
* @param updateEventRateMeter if true, update the Event Rate Meter
* @param eventMetric the Event Metric to use
*/
private void recordEvent(Event event, boolean updateEventRateMeter) {
private void recordEvent(Event event, EventMetric eventMetric) {
synchronized (lastEvents) {
lastEventTimestampEpochMs = System.currentTimeMillis();
if (updateEventRateMeter) {
eventRateMeter.mark(1);
}
eventMetric.eventReceived();
//
// Keep only the last N events, where N = LAST_EVENTS_MAX_N
......@@ -151,7 +157,7 @@ public class TopologyMetrics implements TopologyMetricsService {
private class InnerDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
recordEvent(event, true);
recordEvent(event, topologyDeviceEventMetric);
log.debug("Device Event: time = {} type = {} event = {}",
event.time(), event.type(), event);
}
......@@ -163,7 +169,7 @@ public class TopologyMetrics implements TopologyMetricsService {
private class InnerHostListener implements HostListener {
@Override
public void event(HostEvent event) {
recordEvent(event, true);
recordEvent(event, topologyHostEventMetric);
log.debug("Host Event: time = {} type = {} event = {}",
event.time(), event.type(), event);
}
......@@ -175,7 +181,7 @@ public class TopologyMetrics implements TopologyMetricsService {
private class InnerLinkListener implements LinkListener {
@Override
public void event(LinkEvent event) {
recordEvent(event, true);
recordEvent(event, topologyLinkEventMetric);
log.debug("Link Event: time = {} type = {} event = {}",
event.time(), event.type(), event);
}
......@@ -187,11 +193,7 @@ public class TopologyMetrics implements TopologyMetricsService {
private class InnerTopologyListener implements TopologyListener {
@Override
public void event(TopologyEvent event) {
//
// NOTE: Don't update the eventRateMeter, because the real
// events are already captured/counted.
//
recordEvent(event, false);
recordEvent(event, topologyGraphEventMetric);
log.debug("Topology Event: time = {} type = {} event = {}",
event.time(), event.type(), event);
for (Event reason : event.reasons()) {
......@@ -206,7 +208,6 @@ public class TopologyMetrics implements TopologyMetricsService {
*/
private void clear() {
synchronized (lastEvents) {
lastEventTimestampEpochMs = 0;
lastEvents.clear();
}
}
......@@ -215,35 +216,32 @@ public class TopologyMetrics implements TopologyMetricsService {
* Registers the metrics.
*/
private void registerMetrics() {
metricsComponent = metricsService.registerComponent(COMPONENT_NAME);
metricsFeatureEventNotification =
metricsComponent.registerFeature(FEATURE_NAME);
lastEventTimestampEpochMsGauge =
metricsService.registerMetric(metricsComponent,
metricsFeatureEventNotification,
GAUGE_NAME,
new Gauge<Long>() {
@Override
public Long getValue() {
return lastEventTimestampEpochMs;
}
});
eventRateMeter =
metricsService.createMeter(metricsComponent,
metricsFeatureEventNotification,
METER_NAME);
topologyDeviceEventMetric =
new EventMetric(metricsService, COMPONENT_NAME,
FEATURE_DEVICE_NAME);
topologyHostEventMetric =
new EventMetric(metricsService, COMPONENT_NAME,
FEATURE_HOST_NAME);
topologyLinkEventMetric =
new EventMetric(metricsService, COMPONENT_NAME,
FEATURE_LINK_NAME);
topologyGraphEventMetric =
new EventMetric(metricsService, COMPONENT_NAME,
FEATURE_GRAPH_NAME);
topologyDeviceEventMetric.registerMetrics();
topologyHostEventMetric.registerMetrics();
topologyLinkEventMetric.registerMetrics();
topologyGraphEventMetric.registerMetrics();
}
/**
* Removes the metrics.
*/
private void removeMetrics() {
metricsService.removeMetric(metricsComponent,
metricsFeatureEventNotification,
GAUGE_NAME);
metricsService.removeMetric(metricsComponent,
metricsFeatureEventNotification,
METER_NAME);
topologyDeviceEventMetric.removeMetrics();
topologyHostEventMetric.removeMetrics();
topologyLinkEventMetric.removeMetrics();
topologyGraphEventMetric.removeMetrics();
}
}
......
package org.onlab.onos.metrics.topology;
import java.util.List;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Meter;
import org.onlab.metrics.EventMetric;
import org.onlab.onos.event.Event;
/**
......@@ -18,18 +16,30 @@ public interface TopologyMetricsService {
public List<Event> getEvents();
/**
* Gets the Metrics' Gauge for the last topology event timestamp
* (ms from the epoch).
* Gets the Event Metric for the Device Events.
*
* @return the Event Metric for the Device Events.
*/
public EventMetric topologyDeviceEventMetric();
/**
* Gets the Event Metric for the Host Events.
*
* @return the Event Metric for the Host Events.
*/
public EventMetric topologyHostEventMetric();
/**
* Gets the Event Metric for the Link Events.
*
* @return the Metrics' Gauge for the last topology event timestamp
* (ms from the epoch)
* @return the Event Metric for the Link Events.
*/
public Gauge<Long> lastEventTimestampEpochMsGauge();
public EventMetric topologyLinkEventMetric();
/**
* Gets the Metrics' Meter for the topology events rate.
* Gets the Event Metric for the Topology Graph Events.
*
* @return the Metrics' Meter for the topology events rate
* @return the Event Metric for the Topology Graph Events.
*/
public Meter eventRateMeter();
public EventMetric topologyGraphEventMetric();
}
......
......@@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Command;
import org.onlab.metrics.EventMetric;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.metrics.topology.TopologyMetricsService;
......@@ -22,15 +23,13 @@ import org.onlab.onos.metrics.topology.TopologyMetricsService;
public class TopologyEventsMetricsCommand extends AbstractShellCommand {
private static final String FORMAT_GAUGE =
"Last Topology Event Timestamp (ms from epoch)=%d";
"Topology %s Event Timestamp (ms from epoch)=%d";
private static final String FORMAT_METER =
"Topology Events count=%d rate(events/sec) mean=%f m1=%f m5=%f m15=%f";
"Topology %s Events count=%d rate(events/sec) mean=%f m1=%f m5=%f m15=%f";
@Override
protected void execute() {
TopologyMetricsService service = get(TopologyMetricsService.class);
Gauge<Long> gauge = service.lastEventTimestampEpochMsGauge();
Meter meter = service.eventRateMeter();
if (outputJson()) {
ObjectMapper mapper = new ObjectMapper()
......@@ -38,32 +37,89 @@ public class TopologyEventsMetricsCommand extends AbstractShellCommand {
TimeUnit.MILLISECONDS,
false));
ObjectNode result = mapper.createObjectNode();
try {
//
// NOTE: The API for custom serializers is incomplete,
// hence we have to parse the JSON string to create JsonNode.
//
final String gaugeJson = mapper.writeValueAsString(gauge);
final String meterJson = mapper.writeValueAsString(meter);
JsonNode gaugeNode = mapper.readTree(gaugeJson);
JsonNode meterNode = mapper.readTree(meterJson);
result.put("lastTopologyEventTimestamp", gaugeNode);
result.put("topologyEventRate", meterNode);
} catch (JsonProcessingException e) {
log.error("Error writing value as JSON string", e);
} catch (IOException e) {
log.error("Error writing value as JSON string", e);
}
result = json(mapper, result, "topologyDeviceEvent",
service.topologyDeviceEventMetric());
result = json(mapper, result, "topologyHostEvent",
service.topologyHostEventMetric());
result = json(mapper, result, "topologyLinkEvent",
service.topologyLinkEventMetric());
result = json(mapper, result, "topologyGraphEvent",
service.topologyGraphEventMetric());
print("%s", result);
} else {
TimeUnit rateUnit = TimeUnit.SECONDS;
double rateFactor = rateUnit.toSeconds(1);
print(FORMAT_GAUGE, gauge.getValue());
print(FORMAT_METER, meter.getCount(),
meter.getMeanRate() * rateFactor,
meter.getOneMinuteRate() * rateFactor,
meter.getFiveMinuteRate() * rateFactor,
meter.getFifteenMinuteRate() * rateFactor);
printEventMetric("Device", service.topologyDeviceEventMetric());
printEventMetric("Host", service.topologyHostEventMetric());
printEventMetric("Link", service.topologyLinkEventMetric());
printEventMetric("Graph", service.topologyGraphEventMetric());
}
}
/**
* Produces JSON node for an Event Metric.
*
* @param mapper the JSON object mapper to use
* @param objectNode the JSON object node to use
* @param propertyPrefix the property prefix to use
* @param eventMetric the Event Metric with the data
* @return JSON object node for the Event Metric
*/
private ObjectNode json(ObjectMapper mapper, ObjectNode objectNode,
String propertyPrefix, EventMetric eventMetric) {
String gaugeName = propertyPrefix + "Timestamp";
String meterName = propertyPrefix + "Rate";
Gauge<Long> gauge = eventMetric.lastEventTimestampGauge();
Meter meter = eventMetric.eventRateMeter();
objectNode.put(gaugeName, json(mapper, gauge));
objectNode.put(meterName, json(mapper, meter));
return objectNode;
}
/**
* Produces JSON node for an Object.
*
* @param mapper the JSON object mapper to use
* @param object the Object with the data
* @return JSON node for the Object
*/
private JsonNode json(ObjectMapper mapper, Object object) {
//
// NOTE: The API for custom serializers is incomplete,
// hence we have to parse the JSON string to create JsonNode.
//
try {
final String objectJson = mapper.writeValueAsString(object);
JsonNode jsonNode = mapper.readTree(objectJson);
return jsonNode;
} catch (JsonProcessingException e) {
log.error("Error writing value as JSON string", e);
} catch (IOException e) {
log.error("Error writing value as JSON string", e);
}
return null;
}
/**
* Prints an Event Metric.
*
* @param operationStr the string with the intent operation to print
* @param eventMetric the Event Metric to print
*/
private void printEventMetric(String operationStr,
EventMetric eventMetric) {
Gauge<Long> gauge = eventMetric.lastEventTimestampGauge();
Meter meter = eventMetric.eventRateMeter();
TimeUnit rateUnit = TimeUnit.SECONDS;
double rateFactor = rateUnit.toSeconds(1);
// Print the Gauge
print(FORMAT_GAUGE, operationStr, gauge.getValue());
// Print the Meter
print(FORMAT_METER, operationStr, meter.getCount(),
meter.getMeanRate() * rateFactor,
meter.getOneMinuteRate() * rateFactor,
meter.getFiveMinuteRate() * rateFactor,
meter.getFifteenMinuteRate() * rateFactor);
}
}
......
package org.onlab.onos.optical.provisioner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.CoreService;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentEvent;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.IntentListener;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.link.LinkService;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyEdge;
import org.onlab.onos.net.topology.TopologyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* OpticalPathProvisioner listens event notifications from the Intent F/W.
* It generates one or more opticalConnectivityIntent(s) and submits (or withdraws) to Intent F/W
* for adding/releasing capacity at the packet layer.
*
*/
@Component(immediate = true)
public class OpticalPathProvisioner {
protected static final Logger log = LoggerFactory
.getLogger(OpticalPathProvisioner.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private IntentService intentService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private IntentExtensionService intentExtensionService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkService linkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
private ApplicationId appId;
//protected <IntentId> intentIdGenerator;
private final InternalOpticalPathProvisioner pathProvisioner = new InternalOpticalPathProvisioner();
@Activate
protected void activate() {
intentService.addListener(pathProvisioner);
appId = coreService.registerApplication("org.onlab.onos.optical");
log.info("Starting optical path provisoning...");
}
@Deactivate
protected void deactivate() {
intentService.removeListener(pathProvisioner);
}
public class InternalOpticalPathProvisioner implements IntentListener {
@Override
public void event(IntentEvent event) {
switch (event.type()) {
case SUBMITTED:
break;
case INSTALLED:
break;
case FAILED:
log.info("intent {} failed, calling optical path provisioning APP.", event.subject());
setuplightpath(event.subject());
break;
case WITHDRAWN:
log.info("intent {} withdrawn.", event.subject());
teardownLightpath(event.subject());
break;
default:
break;
}
}
private void setuplightpath(Intent intent) {
// TODO: considering user policies and optical reach
if (!intent.equals(PointToPointIntent.class)) {
return;
}
PointToPointIntent pktIntent = (PointToPointIntent) intent;
if (pktIntent.ingressPoint() == null || pktIntent.egressPoint() == null) {
return;
}
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
public double weight(TopologyEdge edge) {
boolean isOptical = false;
String t = edge.link().annotations().value("linkType");
if (t.equals("WDM")) {
isOptical = true;
}
if (isOptical) {
return 1000; // optical links
} else {
return 10; // packet links
}
}
};
Set<Path> paths = topologyService.getPaths(topology,
pktIntent.ingressPoint().deviceId(),
pktIntent.egressPoint().deviceId(),
weight);
if (paths.isEmpty()) {
return;
}
ConnectPoint srcWdmPoint = null;
ConnectPoint dstWdmPoint = null;
Iterator<Path> itrPath = paths.iterator();
Path firstPath = itrPath.next();
log.info(firstPath.toString());
ArrayList<Map<ConnectPoint, ConnectPoint>> connectionList = new ArrayList<>();
Iterator<Link> itrLink = firstPath.links().iterator();
while (itrLink.hasNext()) {
Link link1 = itrLink.next();
if (!isOpticalLink(link1)) {
continue;
} else {
srcWdmPoint = link1.dst();
dstWdmPoint = srcWdmPoint;
}
while (true) {
if (itrLink.hasNext()) {
Link link2 = itrLink.next();
dstWdmPoint = link2.src();
} else {
break;
}
if (itrLink.hasNext()) {
Link link3 = itrLink.next();
if (!isOpticalLink(link3)) {
break;
}
} else {
break;
}
}
Map<ConnectPoint, ConnectPoint> pair =
new HashMap<ConnectPoint, ConnectPoint>();
pair.put(srcWdmPoint, dstWdmPoint);
connectionList.add(pair);
}
for (Map<ConnectPoint, ConnectPoint> map : connectionList) {
for (Entry<ConnectPoint, ConnectPoint> entry : map.entrySet()) {
ConnectPoint src = entry.getKey();
ConnectPoint dst = entry.getValue();
Intent opticalIntent = new OpticalConnectivityIntent(appId,
srcWdmPoint,
dstWdmPoint);
intentService.submit(opticalIntent);
log.info(opticalIntent.toString());
}
}
}
private boolean isOpticalLink(Link link) {
boolean isOptical = false;
String t = link.annotations().value("linkType");
if (t.equals("WDM") || t.equals("PktOptLink")) {
isOptical = true;
}
return isOptical;
}
private void teardownLightpath(Intent intent) {
// TODO: tear down the idle lightpath if the utilization is close to zero.
}
}
}
package org.onlab.onos.optical.testapp;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.HashMap;
import java.util.Map;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.CoreService;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.device.DeviceEvent;
import org.onlab.onos.net.device.DeviceListener;
import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleService;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.slf4j.Logger;
/**
* Sample reactive forwarding application.
*/
//@Component(immediate = true)
public class LambdaForwarding {
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
private ApplicationId appId;
private final InternalDeviceListener listener = new InternalDeviceListener();
private final Map<DeviceId, Integer> uglyMap = new HashMap<>();
@Activate
public void activate() {
appId = coreService.registerApplication("org.onlab.onos.fwd");
uglyMap.put(DeviceId.deviceId("of:0000ffffffffff01"), 1);
uglyMap.put(DeviceId.deviceId("of:0000ffffffffff02"), 2);
uglyMap.put(DeviceId.deviceId("of:0000ffffffffff03"), 3);
deviceService.addListener(listener);
for (Device d : deviceService.getDevices()) {
pushRules(d);
}
log.info("Started with Application ID {}", appId.id());
}
@Deactivate
public void deactivate() {
flowRuleService.removeFlowRulesById(appId);
log.info("Stopped");
}
private void pushRules(Device device) {
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
int inport;
int outport;
short lambda = 10;
byte sigType = 1;
Integer switchNumber = uglyMap.get(device.id());
if (switchNumber == null) {
return;
}
switch (switchNumber) {
case 1:
inport = 10;
outport = 20;
sbuilder.matchInport(PortNumber.portNumber(inport));
tbuilder.setOutput(PortNumber.portNumber(outport)).setLambda(lambda);
break;
case 2:
inport = 21;
outport = 11;
sbuilder.matchLambda(lambda).
matchInport(PortNumber.portNumber(inport)); // match sigtype
tbuilder.setOutput(PortNumber.portNumber(outport));
break;
case 3:
inport = 30;
outport = 31;
sbuilder.matchLambda(lambda).
matchInport(PortNumber.portNumber(inport));
tbuilder.setOutput(PortNumber.portNumber(outport)).setLambda(lambda);
break;
default:
}
TrafficTreatment treatement = tbuilder.build();
TrafficSelector selector = sbuilder.build();
FlowRule f = new DefaultFlowRule(device.id(), selector,
treatement, 100, appId, 600, false);
flowRuleService.applyFlowRules(f);
}
public class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
switch (event.type()) {
case DEVICE_ADDED:
pushRules(event.subject());
break;
case DEVICE_AVAILABILITY_CHANGED:
break;
case DEVICE_MASTERSHIP_CHANGED:
break;
case DEVICE_REMOVED:
break;
case DEVICE_SUSPENDED:
break;
case DEVICE_UPDATED:
break;
case PORT_ADDED:
break;
case PORT_REMOVED:
break;
case PORT_UPDATED:
break;
default:
break;
}
}
}
}
......@@ -14,6 +14,16 @@
"attachmentDpid" : "00:00:00:00:00:00:00:a2",
"attachmentPort" : "1",
"ipAddress" : "192.168.30.1"
},
{
"attachmentDpid" : "00:00:00:00:00:00:00:a6",
"attachmentPort" : "1",
"ipAddress" : "192.168.40.1"
},
{
"attachmentDpid" : "00:00:00:00:00:00:00:a4",
"attachmentPort" : "4",
"ipAddress" : "192.168.60.1"
}
],
"bgpSpeakers" : [
......
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.onlab.onos.cli.net;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
/**
* Installs optical connectivity intents.
*/
@Command(scope = "onos", name = "add-optical-intent",
description = "Installs optical connectivity intent")
public class AddOpticalIntentCommand extends ConnectivityIntentCommand {
@Argument(index = 0, name = "ingressDevice",
description = "Ingress Device/Port Description",
required = true, multiValued = false)
String ingressDeviceString = null;
@Argument(index = 1, name = "egressDevice",
description = "Egress Device/Port Description",
required = true, multiValued = false)
String egressDeviceString = null;
@Override
protected void execute() {
IntentService service = get(IntentService.class);
DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
Intent intent = new OpticalConnectivityIntent(appId(), ingress, egress);
service.submit(intent);
}
/**
* Extracts the port number portion of the ConnectPoint.
*
* @param deviceString string representing the device/port
* @return port number as a string, empty string if the port is not found
*/
private String getPortNumber(String deviceString) {
int slash = deviceString.indexOf('/');
if (slash <= 0) {
return "";
}
return deviceString.substring(slash + 1, deviceString.length());
}
/**
* Extracts the device ID portion of the ConnectPoint.
*
* @param deviceString string representing the device/port
* @return device ID string
*/
private String getDeviceId(String deviceString) {
int slash = deviceString.indexOf('/');
if (slash <= 0) {
return "";
}
return deviceString.substring(0, slash);
}
}
......@@ -119,6 +119,14 @@
</optional-completers>
</command>
<command>
<action class="org.onlab.onos.cli.net.AddOpticalIntentCommand"/>
<completers>
<ref component-id="connectPointCompleter"/>
<ref component-id="connectPointCompleter"/>
<null/>
</completers>
</command>
<command>
<action class="org.onlab.onos.cli.net.GetStatistics"/>
<completers>
<ref component-id="connectPointCompleter"/>
......
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.onlab.onos.codec;
import java.util.Set;
/**
* Service for registering and retrieving JSON codecs for various entities.
*/
public interface CodecService {
/**
* Returns the set of classes with currently registered codecs.
*
* @return set of entity classes
*/
Set<Class<?>> getCodecs();
/**
* Returns the JSON codec for the specified entity class.
*
* @param entityClass entity class
* @return JSON codec; null if no codec available for the class
*/
JsonCodec getCodec(Class<?> entityClass);
/**
* Registers the specified JSON codec for the given entity class.
*
* @param entityClass entity class
* @param codec JSON codec
*/
void registerCodec(Class<?> entityClass, JsonCodec codec);
/**
* Unregisters the JSON codec for the specified entity class.
*
* @param entityClass entity class
*/
void unregisterCodec(Class<?> entityClass);
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.onlab.onos.codec;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.ArrayList;
import java.util.List;
/**
* Abstraction of a codec capable for encoding/decoding arbitrary objects to/from JSON.
*/
public abstract class JsonCodec<T> {
/**
* Encodes the specified entity into JSON.
*
* @param entity entity to encode
* @param mapper object mapper
* @return JSON node
* @throws java.lang.UnsupportedOperationException if the codec does not
* support encode operations
*/
public abstract ObjectNode encode(T entity, ObjectMapper mapper);
/**
* Decodes the specified entity from JSON.
*
* @param json JSON to decode
* @return decoded entity
* @throws java.lang.UnsupportedOperationException if the codec does not
* support decode operations
*/
public abstract T decode(ObjectNode json);
/**
* Encodes the collection of the specified entities.
*
* @param entities collection of entities to encode
* @param mapper object mapper
* @return JSON array
* @throws java.lang.UnsupportedOperationException if the codec does not
* support encode operations
*/
public ArrayNode encode(Iterable<T> entities, ObjectMapper mapper) {
ArrayNode result = mapper.createArrayNode();
for (T entity : entities) {
result.add(encode(entity, mapper));
}
return result;
}
/**
* Decodes the specified JSON array into a collection of entities.
*
* @param json JSON array to decode
* @return collection of decoded entities
* @throws java.lang.UnsupportedOperationException if the codec does not
* support decode operations
*/
public List<T> decode(ArrayNode json) {
List<T> result = new ArrayList<>();
for (JsonNode node : json) {
result.add(decode((ObjectNode) node));
}
return result;
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Base JSON codec abstraction and a service for tracking various JSON codecs.
*/
package org.onlab.onos.codec;
\ No newline at end of file
......@@ -18,7 +18,7 @@
*/
package org.onlab.onos.net.flow;
import java.util.List;
import java.util.Set;
/**
* Interface capturing the result of a batch operation.
......@@ -33,9 +33,9 @@ public interface BatchOperationResult<T> {
boolean isSuccess();
/**
* Obtains a list of items which failed.
* @return a list of failures
* Obtains a set of items which failed.
* @return a set of failures
*/
List<T> failedItems();
Set<T> failedItems();
}
......
......@@ -18,19 +18,19 @@
*/
package org.onlab.onos.net.flow;
import java.util.List;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
public class CompletedBatchOperation implements BatchOperationResult<FlowEntry> {
private final boolean success;
private final List<FlowEntry> failures;
private final Set<FlowEntry> failures;
public CompletedBatchOperation(boolean success, List<FlowEntry> failures) {
public CompletedBatchOperation(boolean success, Set<FlowEntry> failures) {
this.success = success;
this.failures = ImmutableList.copyOf(failures);
this.failures = ImmutableSet.copyOf(failures);
}
@Override
......@@ -39,7 +39,7 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowEntry>
}
@Override
public List<FlowEntry> failedItems() {
public Set<FlowEntry> failedItems() {
return failures;
}
......
......@@ -55,6 +55,16 @@ public final class DefaultTrafficSelector implements TrafficSelector {
}
@Override
public Criterion getCriterion(Criterion.Type type) {
for (Criterion c : criteria) {
if (c.type() == type) {
return c;
}
}
return null;
}
@Override
public int hashCode() {
return Objects.hash(criteria);
}
......@@ -176,6 +186,17 @@ public final class DefaultTrafficSelector implements TrafficSelector {
}
@Override
public Builder matchLambda(Short lambda) {
return add(Criteria.matchLambda(lambda));
}
@Override
public Builder matchOpticalSignalType(Byte signalType) {
return add(Criteria.matchOpticalSignalType(signalType));
}
@Override
public TrafficSelector build() {
return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values()));
}
......
......@@ -137,6 +137,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
case OUTPUT:
outputs.add(instruction);
break;
case L0MODIFICATION:
case L2MODIFICATION:
case L3MODIFICATION:
// TODO: enforce modification order if any
......@@ -193,6 +194,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
}
@Override
public Builder setLambda(short lambda) {
return add(Instructions.modL0Lambda(lambda));
}
@Override
public TrafficTreatment build() {
//If we are dropping should we just return an emptry list?
......
package org.onlab.onos.net.flow;
import org.onlab.onos.event.AbstractEvent;
/**
* Describes flow rule batch event.
*/
public final class FlowRuleBatchEvent extends AbstractEvent<FlowRuleBatchEvent.Type, FlowRuleBatchRequest> {
/**
* Type of flow rule events.
*/
public enum Type {
/**
* Signifies that a batch operation has been initiated.
*/
BATCH_OPERATION_REQUESTED,
/**
* Signifies that a batch operation has completed.
*/
BATCH_OPERATION_COMPLETED,
}
private final CompletedBatchOperation result;
/**
* Constructs a new FlowRuleBatchEvent.
* @param request batch operation request.
* @return event.
*/
public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request) {
FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, null);
return event;
}
/**
* Constructs a new FlowRuleBatchEvent.
* @param request batch operation request.
* @param result completed batch operation result.
* @return event.
*/
public static FlowRuleBatchEvent completed(FlowRuleBatchRequest request, CompletedBatchOperation result) {
FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_COMPLETED, request, result);
return event;
}
/**
* Returns the result of this batch operation.
* @return batch operation result.
*/
public CompletedBatchOperation result() {
return result;
}
/**
* Creates an event of a given type and for the specified flow rule batch.
*
* @param type flow rule batch event type
* @param batch event flow rule batch subject
*/
private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) {
super(type, request);
this.result = result;
}
}
package org.onlab.onos.net.flow;
import java.util.Collections;
import java.util.List;
import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
import com.google.common.collect.Lists;
public class FlowRuleBatchRequest {
private final int batchId;
private final List<FlowEntry> toAdd;
private final List<FlowEntry> toRemove;
public FlowRuleBatchRequest(int batchId, List<FlowEntry> toAdd, List<FlowEntry> toRemove) {
this.batchId = batchId;
this.toAdd = Collections.unmodifiableList(toAdd);
this.toRemove = Collections.unmodifiableList(toRemove);
}
public List<FlowEntry> toAdd() {
return toAdd;
}
public List<FlowEntry> toRemove() {
return toRemove;
}
public FlowRuleBatchOperation asBatchOperation() {
List<FlowRuleBatchEntry> entries = Lists.newArrayList();
for (FlowEntry e : toAdd) {
entries.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, e));
}
for (FlowEntry e : toRemove) {
entries.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, e));
}
return new FlowRuleBatchOperation(entries);
}
public int batchId() {
return batchId;
}
}
......@@ -18,11 +18,11 @@
*/
package org.onlab.onos.net.flow;
import java.util.concurrent.Future;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.provider.Provider;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Abstraction of a flow rule provider.
*/
......@@ -60,6 +60,6 @@ public interface FlowRuleProvider extends Provider {
* @param batch a batch of flow rules
* @return a future indicating the status of this execution
*/
Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch);
ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch);
}
......
......@@ -18,6 +18,8 @@
*/
package org.onlab.onos.net.flow;
import java.util.concurrent.Future;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.store.Store;
......@@ -25,7 +27,7 @@ import org.onlab.onos.store.Store;
/**
* Manages inventory of flow rules; not intended for direct use.
*/
public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegate> {
public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDelegate> {
/**
* Returns the number of flow rule in the store.
......@@ -59,12 +61,26 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat
Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId);
/**
// TODO: Better description of method behavior.
* Stores a new flow rule without generating events.
*
* @param rule the flow rule to add
* @return true if the rule should be handled locally
*/
boolean storeFlowRule(FlowRule rule);
void storeFlowRule(FlowRule rule);
/**
* Stores a batch of flow rules.
* @param batchOperation batch of flow rules.
* @return Future response indicating success/failure of the batch operation
* all the way down to the device.
*/
Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation batchOperation);
/**
* Invoked on the completion of a storeBatch operation.
* @param result
*/
void batchOperationComplete(FlowRuleBatchEvent event);
/**
* Marks a flow rule for deletion. Actual deletion will occur
......@@ -73,7 +89,7 @@ public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegat
* @param rule the flow rule to delete
* @return true if the rule should be handled locally
*/
boolean deleteFlowRule(FlowRule rule);
void deleteFlowRule(FlowRule rule);
/**
* Stores a new flow rule, or updates an existing entry.
......
......@@ -23,5 +23,5 @@ import org.onlab.onos.store.StoreDelegate;
/**
* Flow rule store delegate abstraction.
*/
public interface FlowRuleStoreDelegate extends StoreDelegate<FlowRuleEvent> {
public interface FlowRuleStoreDelegate extends StoreDelegate<FlowRuleBatchEvent> {
}
......
......@@ -39,6 +39,15 @@ public interface TrafficSelector {
Set<Criterion> criteria();
/**
* Returns the selection criterion for a particular type, if it exists in
* this traffic selector.
*
* @param type criterion type to look up
* @return the criterion of the specified type if one exists, otherwise null
*/
Criterion getCriterion(Criterion.Type type);
/**
* Builder of traffic selector entities.
*/
public interface Builder {
......@@ -130,6 +139,20 @@ public interface TrafficSelector {
public Builder matchTcpDst(Short tcpPort);
/**
* Matches an optical signal ID or lambda.
* @param lambda
* @return a selection builder
*/
public Builder matchLambda(Short lambda);
/**
* Matches an optical Signal Type.
* @param signalType
* @return a selection builder
*/
public Builder matchOpticalSignalType(Byte signalType);
/**
* Builds an immutable traffic selector.
*
* @return traffic selector
......
......@@ -105,6 +105,13 @@ public interface TrafficTreatment {
public Builder setIpDst(IpPrefix addr);
/**
* Sets the optical channel ID or lambda.
* @param lambda optical channel ID
* @return a treatment builder
*/
public Builder setLambda(short lambda);
/**
* Builds an immutable traffic treatment descriptor.
*
* @return traffic treatment
......
......@@ -151,10 +151,30 @@ public final class Criteria {
return new TcpPortCriterion(tcpPort, Type.TCP_DST);
}
/*
* Implementations of criteria.
/**
* Creates a match on lambda field using the specified value.
*
* @param lambda
* @return match criterion
*/
public static Criterion matchLambda(Short lambda) {
return new LambdaCriterion(lambda, Type.OCH_SIGID);
}
/**
* Creates a match on lambda field using the specified value.
*
* @param lambda
* @return match criterion
*/
public static Criterion matchOpticalSignalType(Byte lambda) {
return new OpticalSignalTypeCriterion(lambda, Type.OCH_SIGTYPE);
}
/**
* Implementations of criteria.
*/
public static final class PortCriterion implements Criterion {
private final PortNumber port;
......@@ -523,4 +543,93 @@ public final class Criteria {
return false;
}
}
public static final class LambdaCriterion implements Criterion {
private final short lambda;
private final Type type;
public LambdaCriterion(short lambda, Type type) {
this.lambda = lambda;
this.type = type;
}
@Override
public Type type() {
return this.type;
}
public Short lambda() {
return this.lambda;
}
@Override
public String toString() {
return toStringHelper(type().toString())
.add("lambda", lambda).toString();
}
@Override
public int hashCode() {
return Objects.hash(lambda, type);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof LambdaCriterion) {
LambdaCriterion that = (LambdaCriterion) obj;
return Objects.equals(lambda, that.lambda) &&
Objects.equals(type, that.type);
}
return false;
}
}
public static final class OpticalSignalTypeCriterion implements Criterion {
private final byte signalType;
private final Type type;
public OpticalSignalTypeCriterion(byte signalType, Type type) {
this.signalType = signalType;
this.type = type;
}
@Override
public Type type() {
return this.type;
}
public Byte signalType() {
return this.signalType;
}
@Override
public String toString() {
return toStringHelper(type().toString())
.add("signalType", signalType).toString();
}
@Override
public int hashCode() {
return Objects.hash(signalType, type);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof OpticalSignalTypeCriterion) {
OpticalSignalTypeCriterion that = (OpticalSignalTypeCriterion) obj;
return Objects.equals(signalType, that.signalType) &&
Objects.equals(type, that.type);
}
return false;
}
}
}
......
......@@ -108,7 +108,11 @@ public interface Criterion {
/** Logical Port Metadata. */
TUNNEL_ID,
/** IPv6 Extension Header pseudo-field. */
IPV6_EXTHDR
IPV6_EXTHDR,
/** Optical channel signal ID (lambda). */
OCH_SIGID,
/** Optical channel signal type (fixed or flexible). */
OCH_SIGTYPE
}
/**
......
......@@ -43,6 +43,11 @@ public interface Instruction {
GROUP,
/**
* Signifies that the traffic should be modified in L0 way.
*/
L0MODIFICATION,
/**
* Signifies that the traffic should be modified in L2 way.
*/
L2MODIFICATION,
......
......@@ -24,6 +24,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Objects;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.L0SubType;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.L2SubType;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.L3SubType;
......@@ -62,6 +64,16 @@ public final class Instructions {
}
/**
* Creates a l0 modification.
* @param lambda the lambda to modify to.
* @return a l0 modification
*/
public static L0ModificationInstruction modL0Lambda(short lambda) {
checkNotNull(lambda, "L0 lambda cannot be null");
return new ModLambdaInstruction(L0SubType.LAMBDA, lambda);
}
/**
* Creates a l2 src modification.
* @param addr the mac address to modify to.
* @return a l2 modification
......
package org.onlab.onos.net.flow.instructions;
import static com.google.common.base.MoreObjects.toStringHelper;
import java.util.Objects;
public abstract class L0ModificationInstruction implements Instruction {
/**
* Represents the type of traffic treatment.
*/
public enum L0SubType {
/**
* Lambda modification.
*/
LAMBDA
//TODO: remaining types
}
public abstract L0SubType subtype();
@Override
public Type type() {
return Type.L0MODIFICATION;
}
/**
* Represents a L0 lambda modification instruction.
*/
public static final class ModLambdaInstruction extends L0ModificationInstruction {
private final L0SubType subtype;
private final short lambda;
public ModLambdaInstruction(L0SubType subType, short lambda) {
this.subtype = subType;
this.lambda = lambda;
}
@Override
public L0SubType subtype() {
return this.subtype;
}
public short lambda() {
return this.lambda;
}
@Override
public String toString() {
return toStringHelper(subtype().toString())
.add("lambda", lambda).toString();
}
@Override
public int hashCode() {
return Objects.hash(lambda, type(), subtype);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ModLambdaInstruction) {
ModLambdaInstruction that = (ModLambdaInstruction) obj;
return Objects.equals(lambda, that.lambda) &&
Objects.equals(this.type(), that.type()) &&
Objects.equals(subtype, that.subtype);
}
return false;
}
}
}
package org.onlab.onos.net.intent;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.ConnectPoint;
/**
* An optical layer Intent for a connectivity from one Transponder port to another
* Transponder port. No trafficSelector as well as trafficTreament are needed.
*
*/
public class OpticalConnectivityIntent extends Intent {
protected ConnectPoint src;
protected ConnectPoint dst;
/**
* Constructor.
*
* @param id ID for this new Intent object.
* @param src The source transponder port.
* @param dst The destination transponder port.
*/
public OpticalConnectivityIntent(ApplicationId appId, ConnectPoint src, ConnectPoint dst) {
super(id(OpticalConnectivityIntent.class, src, dst),
appId, null);
this.src = src;
this.dst = dst;
}
/**
* Constructor for serializer.
*/
protected OpticalConnectivityIntent() {
super();
this.src = null;
this.dst = null;
}
/**
* Gets source transponder port.
*
* @return The source transponder port.
*/
public ConnectPoint getSrcConnectPoint() {
return src;
}
/**
* Gets destination transponder port.
*
* @return The source transponder port.
*/
public ConnectPoint getDst() {
return dst;
}
}
package org.onlab.onos.net.intent;
import java.util.Collection;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.NetworkResource;
import org.onlab.onos.net.Path;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
public class OpticalPathIntent extends Intent {
private final ConnectPoint src;
private final ConnectPoint dst;
private final Path path;
public OpticalPathIntent(ApplicationId appId,
ConnectPoint src,
ConnectPoint dst,
Path path) {
super(id(OpticalPathIntent.class, src, dst),
appId,
ImmutableSet.<NetworkResource>copyOf(path.links()));
this.src = src;
this.dst = dst;
this.path = path;
}
protected OpticalPathIntent() {
this.src = null;
this.dst = null;
this.path = null;
}
public ConnectPoint src() {
return src;
}
public ConnectPoint dst() {
return dst;
}
public Path path() {
return path;
}
@Override
public boolean isInstallable() {
return true;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", id())
.add("ingressPort", src)
.add("egressPort", dst)
.add("path", path)
.toString();
}
public Collection<Link> requiredLinks() {
return path.links();
}
}
......@@ -3,6 +3,21 @@ package org.onlab.onos.net.resource;
/**
* Representation of allocated bandwidth resource.
*/
public interface BandwidthResourceAllocation extends BandwidthResourceRequest {
public class BandwidthResourceAllocation extends BandwidthResourceRequest
implements ResourceAllocation {
@Override
public ResourceType type() {
return ResourceType.BANDWIDTH;
}
/**
* Creates a new {@link BandwidthResourceAllocation} with {@link Bandwidth}
* object.
*
* @param bandwidth allocated bandwidth
*/
public BandwidthResourceAllocation(Bandwidth bandwidth) {
super(bandwidth);
}
}
......
......@@ -3,11 +3,39 @@ package org.onlab.onos.net.resource;
/**
* Representation of a request for bandwidth resource.
*/
public interface BandwidthResourceRequest {
public class BandwidthResourceRequest implements ResourceRequest {
private final Bandwidth bandwidth;
/**
* Creates a new {@link BandwidthResourceRequest} with {@link Bandwidth}
* object.
*
* @param bandwidth {@link Bandwidth} object to be requested
*/
public BandwidthResourceRequest(Bandwidth bandwidth) {
this.bandwidth = bandwidth;
}
/**
* Creates a new {@link BandwidthResourceRequest} with bandwidth value.
*
* @param bandwidth bandwidth value to be requested
*/
public BandwidthResourceRequest(double bandwidth) {
this.bandwidth = Bandwidth.valueOf(bandwidth);
}
/**
* Returns the bandwidth resource.
*
* @return the bandwidth resource
*/
Bandwidth bandwidth();
public Bandwidth bandwidth() {
return bandwidth;
}
@Override
public ResourceType type() {
return ResourceType.BANDWIDTH;
}
}
......
package org.onlab.onos.net.resource;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
import com.google.common.collect.ImmutableSet;
/**
* Implementation of {@link LinkResourceRequest}.
*/
public final class DefaultLinkResourceRequest implements LinkResourceRequest {
private final IntentId intentId;
private final Collection<Link> links;
private final Set<ResourceRequest> resources;
/**
* Creates a new link resource request with the given ID, links, and
* resource requests.
*
* @param intentId intent ID related to this request
* @param links a set of links for the request
* @param resources a set of resources to be requested
*/
private DefaultLinkResourceRequest(IntentId intentId,
Collection<Link> links,
Set<ResourceRequest> resources) {
this.intentId = intentId;
this.links = ImmutableSet.copyOf(links);
this.resources = ImmutableSet.copyOf(resources);
}
@Override
public ResourceType type() {
return null;
}
@Override
public IntentId intendId() {
return intentId;
}
@Override
public Collection<Link> links() {
return links;
}
@Override
public Set<ResourceRequest> resources() {
return resources;
}
/**
* Returns builder of link resource request.
*
* @param intentId intent ID related to this request
* @param links a set of links for the request
* @return builder of link resource request
*/
public static LinkResourceRequest.Builder builder(
IntentId intentId, Collection<Link> links) {
return new Builder(intentId, links);
}
/**
* Builder of link resource request.
*/
public static final class Builder implements LinkResourceRequest.Builder {
private IntentId intentId;
private Collection<Link> links;
private Set<ResourceRequest> resources;
/**
* Creates a new link resource request.
*
* @param intentId intent ID related to this request
* @param links a set of links for the request
*/
private Builder(IntentId intentId, Collection<Link> links) {
this.intentId = intentId;
this.links = links;
this.resources = new HashSet<>();
}
/**
* Adds lambda request.
*
* @return self
*/
@Override
public Builder addLambdaRequest() {
resources.add(new LambdaResourceRequest());
return this;
}
/**
* Adds bandwidth request with bandwidth value.
*
* @param bandwidth bandwidth value to be requested
* @return self
*/
@Override
public Builder addBandwidthRequest(double bandwidth) {
resources.add(new BandwidthResourceRequest(bandwidth));
return this;
}
/**
* Returns link resource request.
*
* @return link resource request
*/
@Override
public LinkResourceRequest build() {
return new DefaultLinkResourceRequest(intentId, links, resources);
}
}
}
......@@ -3,11 +3,31 @@ package org.onlab.onos.net.resource;
/**
* Representation of allocated lambda resource.
*/
public interface LambdaResourceAllocation extends LambdaResourceRequest {
public class LambdaResourceAllocation extends LambdaResourceRequest
implements ResourceAllocation {
private final Lambda lambda;
@Override
public ResourceType type() {
return ResourceType.LAMBDA;
}
/**
* Creates a new {@link LambdaResourceAllocation} with {@link Lambda}
* object.
*
* @param lambda allocated lambda
*/
public LambdaResourceAllocation(Lambda lambda) {
this.lambda = lambda;
}
/**
* Returns the lambda resource.
*
* @return the lambda resource
*/
Lambda lambda();
public Lambda lambda() {
return lambda;
}
}
......
......@@ -3,6 +3,11 @@ package org.onlab.onos.net.resource;
/**
* Representation of a request for lambda resource.
*/
public interface LambdaResourceRequest {
public class LambdaResourceRequest implements ResourceRequest {
@Override
public ResourceType type() {
return ResourceType.LAMBDA;
}
}
......
package org.onlab.onos.net.resource;
import java.util.Set;
import org.onlab.onos.net.Link;
/**
......@@ -12,5 +14,5 @@ public interface LinkResourceAllocations extends LinkResourceRequest {
* @param link the target link
* @return allocated resource for the link
*/
ResourceAllocation getResourceAllocation(Link link);
Set<ResourceAllocation> getResourceAllocation(Link link);
}
......
......@@ -31,4 +31,31 @@ public interface LinkResourceRequest extends ResourceRequest {
* @return the set of resource requests
*/
Set<ResourceRequest> resources();
/**
* Builder of link resource request.
*/
interface Builder {
/**
* Adds lambda request.
*
* @return self
*/
public Builder addLambdaRequest();
/**
* Adds bandwidth request with bandwidth value.
*
* @param bandwidth bandwidth value to be requested
* @return self
*/
public Builder addBandwidthRequest(double bandwidth);
/**
* Returns link resource request.
*
* @return link resource request
*/
public LinkResourceRequest build();
}
}
......
......@@ -31,6 +31,14 @@ public interface LinkResourceService {
Iterable<LinkResourceAllocations> getAllocations();
/**
* Returns the resources allocated for an Intent.
*
* @param intentId the target Intent's id
* @return allocated resources for Intent
*/
LinkResourceAllocations getAllocations(IntentId intentId);
/**
* Returns all allocated resources to given link.
*
* @param link a target link
......
......@@ -4,5 +4,11 @@ package org.onlab.onos.net.resource;
* Abstraction of resource request.
*/
public interface ResourceRequest {
/**
* Returns the resource type.
*
* @return the resource type
*/
ResourceType type();
}
......
package org.onlab.onos.net.resource;
public enum ResourceType {
LAMBDA,
BANDWIDTH,
}
/**
* Services for reserving network resources, e.g.&nbsp;bandwidth, lambdas.
*/
package org.onlab.onos.net.resource;
\ No newline at end of file
package org.onlab.onos.net.resource;
......
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.onlab.onos.codec;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import java.util.List;
import java.util.Objects;
import static org.junit.Assert.assertEquals;
/**
* Test of the base JSON codec abstraction.
*/
public class JsonCodecTest {
private static class Foo {
final String name;
Foo(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Foo other = (Foo) obj;
return Objects.equals(this.name, other.name);
}
}
private static class FooCodec extends JsonCodec<Foo> {
@Override
public ObjectNode encode(Foo entity, ObjectMapper mapper) {
return mapper.createObjectNode().put("name", entity.name);
}
@Override
public Foo decode(ObjectNode json) {
return new Foo(json.get("name").asText());
}
}
@Test
public void encode() {
Foo f1 = new Foo("foo");
Foo f2 = new Foo("bar");
FooCodec codec = new FooCodec();
ImmutableList<Foo> entities = ImmutableList.of(f1, f2);
ArrayNode json = codec.encode(entities, new ObjectMapper());
List<Foo> foos = codec.decode(json);
assertEquals("incorrect encode/decode", entities, foos);
}
}
\ No newline at end of file
......@@ -2,11 +2,15 @@ package org.onlab.onos.net.flow.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import static org.onlab.util.Tools.namedThreads;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
......@@ -30,7 +34,9 @@ import org.onlab.onos.net.flow.FlowEntry;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleBatchEntry;
import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
import org.onlab.onos.net.flow.FlowRuleBatchEvent;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
import org.onlab.onos.net.flow.FlowRuleBatchRequest;
import org.onlab.onos.net.flow.FlowRuleEvent;
import org.onlab.onos.net.flow.FlowRuleListener;
import org.onlab.onos.net.flow.FlowRuleProvider;
......@@ -47,6 +53,9 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides implementation of the flow NB &amp; SB APIs.
......@@ -67,6 +76,9 @@ public class FlowRuleManager
private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
private final ExecutorService futureListeners =
Executors.newCachedThreadPool(namedThreads("provider-future-listeners"));
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleStore store;
......@@ -85,6 +97,8 @@ public class FlowRuleManager
@Deactivate
public void deactivate() {
futureListeners.shutdownNow();
store.unsetDelegate(delegate);
eventDispatcher.removeSink(FlowRuleEvent.class);
log.info("Stopped");
......@@ -104,14 +118,7 @@ public class FlowRuleManager
public void applyFlowRules(FlowRule... flowRules) {
for (int i = 0; i < flowRules.length; i++) {
FlowRule f = flowRules[i];
boolean local = store.storeFlowRule(f);
if (local) {
// TODO: aggregate all local rules and push down once?
applyFlowRulesToProviders(f);
eventDispatcher.post(
new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADD_REQUESTED, f));
}
store.storeFlowRule(f);
}
}
......@@ -135,13 +142,7 @@ public class FlowRuleManager
FlowRule f;
for (int i = 0; i < flowRules.length; i++) {
f = flowRules[i];
boolean local = store.deleteFlowRule(f);
if (local) {
// TODO: aggregate all local rules and push down once?
removeFlowRulesFromProviders(f);
eventDispatcher.post(
new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, f));
}
store.deleteFlowRule(f);
}
}
......@@ -185,33 +186,21 @@ public class FlowRuleManager
@Override
public Future<CompletedBatchOperation> applyBatch(
FlowRuleBatchOperation batch) {
Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches =
Multimap<DeviceId, FlowRuleBatchEntry> perDeviceBatches =
ArrayListMultimap.create();
List<Future<CompletedBatchOperation>> futures = Lists.newArrayList();
for (FlowRuleBatchEntry fbe : batch.getOperations()) {
final FlowRule f = fbe.getTarget();
final Device device = deviceService.getDevice(f.deviceId());
final FlowRuleProvider frp = getProvider(device.providerId());
batches.put(frp, fbe);
switch (fbe.getOperator()) {
case ADD:
store.storeFlowRule(f);
break;
case REMOVE:
store.deleteFlowRule(f);
break;
case MODIFY:
default:
log.error("Batch operation type {} unsupported.", fbe.getOperator());
}
perDeviceBatches.put(f.deviceId(), fbe);
}
for (FlowRuleProvider provider : batches.keySet()) {
for (DeviceId deviceId : perDeviceBatches.keySet()) {
FlowRuleBatchOperation b =
new FlowRuleBatchOperation(batches.get(provider));
Future<CompletedBatchOperation> future = provider.executeBatch(b);
new FlowRuleBatchOperation(perDeviceBatches.get(deviceId));
Future<CompletedBatchOperation> future = store.storeBatch(b);
futures.add(future);
}
return new FlowRuleBatchFuture(futures, batches);
return new FlowRuleBatchFuture(futures, perDeviceBatches);
}
@Override
......@@ -324,6 +313,7 @@ public class FlowRuleManager
post(event);
}
} else {
log.info("Removing flow rules....");
removeFlowRules(flowEntry);
}
......@@ -391,21 +381,48 @@ public class FlowRuleManager
// Store delegate to re-post events emitted from the store.
private class InternalStoreDelegate implements FlowRuleStoreDelegate {
// TODO: Right now we only dispatch events at individual flowEntry level.
// It may be more efficient for also dispatch events as a batch.
@Override
public void notify(FlowRuleEvent event) {
public void notify(FlowRuleBatchEvent event) {
final FlowRuleBatchRequest request = event.subject();
switch (event.type()) {
case RULE_ADD_REQUESTED:
applyFlowRulesToProviders(event.subject());
break;
case RULE_REMOVE_REQUESTED:
removeFlowRulesFromProviders(event.subject());
break;
case BATCH_OPERATION_REQUESTED:
for (FlowEntry entry : request.toAdd()) {
eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADD_REQUESTED, entry));
}
for (FlowEntry entry : request.toRemove()) {
eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, entry));
}
// FIXME: what about op.equals(FlowRuleOperation.MODIFY) ?
FlowRuleBatchOperation batchOperation = request.asBatchOperation();
FlowRuleProvider flowRuleProvider =
getProvider(batchOperation.getOperations().get(0).getTarget().deviceId());
final ListenableFuture<CompletedBatchOperation> result =
flowRuleProvider.executeBatch(batchOperation);
result.addListener(new Runnable() {
@Override
public void run() {
store.batchOperationComplete(FlowRuleBatchEvent.completed(request,
Futures.getUnchecked(result)));
}
}, futureListeners);
case RULE_ADDED:
case RULE_REMOVED:
case RULE_UPDATED:
// only dispatch events related to switch
eventDispatcher.post(event);
break;
case BATCH_OPERATION_COMPLETED:
Set<FlowEntry> failedItems = event.result().failedItems();
for (FlowEntry entry : request.toAdd()) {
if (!failedItems.contains(entry)) {
eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADDED, entry));
}
}
for (FlowEntry entry : request.toRemove()) {
if (!failedItems.contains(entry)) {
eventDispatcher.post(new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVED, entry));
}
}
break;
default:
break;
......@@ -413,18 +430,15 @@ public class FlowRuleManager
}
}
private class FlowRuleBatchFuture
implements Future<CompletedBatchOperation> {
private class FlowRuleBatchFuture implements Future<CompletedBatchOperation> {
private final List<Future<CompletedBatchOperation>> futures;
private final Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches;
private final Multimap<DeviceId, FlowRuleBatchEntry> batches;
private final AtomicReference<BatchState> state;
private CompletedBatchOperation overall;
public FlowRuleBatchFuture(List<Future<CompletedBatchOperation>> futures,
Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches) {
Multimap<DeviceId, FlowRuleBatchEntry> batches) {
this.futures = futures;
this.batches = batches;
state = new AtomicReference<FlowRuleManager.BatchState>();
......@@ -466,7 +480,7 @@ public class FlowRuleManager
}
boolean success = true;
List<FlowEntry> failed = Lists.newLinkedList();
Set<FlowEntry> failed = Sets.newHashSet();
CompletedBatchOperation completed;
for (Future<CompletedBatchOperation> future : futures) {
completed = future.get();
......@@ -486,7 +500,7 @@ public class FlowRuleManager
return overall;
}
boolean success = true;
List<FlowEntry> failed = Lists.newLinkedList();
Set<FlowEntry> failed = Sets.newHashSet();
CompletedBatchOperation completed;
long start = System.nanoTime();
long end = start + unit.toNanos(timeout);
......@@ -500,7 +514,7 @@ public class FlowRuleManager
return finalizeBatchOperation(success, failed);
}
private boolean validateBatchOperation(List<FlowEntry> failed,
private boolean validateBatchOperation(Set<FlowEntry> failed,
CompletedBatchOperation completed) {
if (isCancelled()) {
......@@ -522,7 +536,7 @@ public class FlowRuleManager
}
private CompletedBatchOperation finalizeBatchOperation(boolean success,
List<FlowEntry> failed) {
Set<FlowEntry> failed) {
synchronized (this) {
if (!state.compareAndSet(BatchState.STARTED, BatchState.FINISHED)) {
if (state.get() == BatchState.FINISHED) {
......@@ -545,11 +559,6 @@ public class FlowRuleManager
store.storeFlowRule(fbe.getTarget());
}
}
}
}
}
......
package org.onlab.onos.net.intent.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.CoreService;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentCompiler;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
import org.onlab.onos.net.intent.OpticalPathIntent;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.topology.PathService;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyEdge;
import org.onlab.onos.net.topology.TopologyService;
import org.slf4j.Logger;
/**
* Optical compiler for OpticalConnectivityIntent.
* It firstly computes K-shortest paths in the optical-layer, then choose the optimal one to assign a wavelength.
* Finally, it generates one or more opticalPathintent(s) with opticalMatchs and opticalActions.
*/
@Component(immediate = true)
public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
private final Logger log = getLogger(getClass());
private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PathService pathService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Activate
public void activate() {
intentManager.registerCompiler(OpticalConnectivityIntent.class, this);
}
@Deactivate
public void deactivate() {
intentManager.unregisterCompiler(OpticalConnectivityIntent.class);
}
@Override
public List<Intent> compile(OpticalConnectivityIntent intent) {
// TODO: compute multiple paths using the K-shortest path algorithm
List<Intent> retList = new ArrayList<>();
Path path = calculatePath(intent.getSrcConnectPoint(), intent.getDst());
if (path == null) {
return retList;
} else {
log.info("the computed lightpath is : {}.", path.toString());
}
List<Link> links = new ArrayList<>();
// links.add(DefaultEdgeLink.createEdgeLink(intent.getSrcConnectPoint(), true));
links.addAll(path.links());
//links.add(DefaultEdgeLink.createEdgeLink(intent.getDst(), false));
// create a new opticalPathIntent
Intent newIntent = new OpticalPathIntent(intent.appId(),
intent.getSrcConnectPoint(),
intent.getDst(),
path);
retList.add(newIntent);
return retList;
}
private Path calculatePath(ConnectPoint start, ConnectPoint end) {
// TODO: support user policies
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
public double weight(TopologyEdge edge) {
boolean isOptical = false;
Link.Type lt = edge.link().type();
//String t = edge.link().annotations().value("linkType");
if (lt == Link.Type.OPTICAL) {
isOptical = true;
}
if (isOptical) {
return 1; // optical links
} else {
return 10000; // packet links
}
}
};
Set<Path> paths = topologyService.getPaths(topology,
start.deviceId(),
end.deviceId(),
weight);
Iterator<Path> itr = paths.iterator();
while (itr.hasNext()) {
Path path = itr.next();
if (path.cost() >= 10000) {
itr.remove();
}
}
if (paths.isEmpty()) {
log.info("No optical path found from " + start + " to " + end);
return null;
} else {
return paths.iterator().next();
}
}
}
package org.onlab.onos.net.intent.impl;
import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.List;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.CoreService;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleBatchEntry;
import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
import org.onlab.onos.net.flow.FlowRuleService;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.IntentInstaller;
import org.onlab.onos.net.intent.OpticalPathIntent;
import org.onlab.onos.net.resource.DefaultLinkResourceRequest;
import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LambdaResourceAllocation;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceType;
import org.onlab.onos.net.topology.TopologyService;
import org.slf4j.Logger;
import com.google.common.collect.Lists;
/**
* OpticaliIntentInstaller for optical path intents.
* It essentially generates optical FlowRules and
* call the flowRule service to execute them.
*/
@Component(immediate = true)
public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIntent> {
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
private ApplicationId appId;
//final short WAVELENGTH = 80;
@Activate
public void activate() {
appId = coreService.registerApplication("org.onlab.onos.net.intent");
intentManager.registerInstaller(OpticalPathIntent.class, this);
}
@Deactivate
public void deactivate() {
intentManager.unregisterInstaller(OpticalPathIntent.class);
}
@Override
public List<FlowRuleBatchOperation> install(OpticalPathIntent intent) {
LinkResourceAllocations allocations = assignWavelength(intent);
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
selectorBuilder.matchInport(intent.src().port());
List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
ConnectPoint prev = intent.src();
//TODO throw exception if the lambda was not assigned successfully
for (Link link : intent.path().links()) {
Lambda la = null;
for (ResourceAllocation allocation : allocations.getResourceAllocation(link)) {
if (allocation.type() == ResourceType.LAMBDA) {
la = ((LambdaResourceAllocation) allocation).lambda();
break;
}
}
if (la == null) {
log.info("Lambda was not assigned successfully");
return null;
}
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
treatmentBuilder.setOutput(link.src().port());
treatmentBuilder.setLambda((short) la.toInt());
FlowRule rule = new DefaultFlowRule(prev.deviceId(),
selectorBuilder.build(),
treatmentBuilder.build(),
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
prev = link.dst();
selectorBuilder.matchInport(link.dst().port());
selectorBuilder.matchLambda((short) la.toInt());
}
// build the last T port rule
TrafficTreatment treatmentLast = builder()
.setOutput(intent.dst().port()).build();
FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
selectorBuilder.build(),
treatmentLast,
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
intent.path().links())
.addLambdaRequest();
LinkResourceAllocations retLambda = resourceService.requestResources(request.build());
return retLambda;
}
/*private Lambda assignWavelength(List<Link> links) {
// TODO More wavelength assignment algorithm
int wavenum = 0;
Iterator<Link> itrlink = links.iterator();
for (int i = 1; i <= WAVELENGTH; i++) {
wavenum = i;
boolean found = true;
while (itrlink.hasNext()) {
Link link = itrlink.next();
if (isWavelengthUsed(link, i)) {
found = false;
break;
}
}
// First-Fit wavelength assignment algorithm
if (found) {
break;
}
}
if (wavenum == 0) {
return null;
}
Lambda wave = Lambda.valueOf(wavenum);
return wave;
}
private boolean isWavelengthUsed(Link link, int i) {
Iterable<LinkResourceAllocations> wave = resourceService.getAllocations(link);
for (LinkResourceAllocations ir : wave) {
//if ir.resources().contains(i) {
//}
}
return false;
}*/
@Override
public List<FlowRuleBatchOperation> uninstall(OpticalPathIntent intent) {
LinkResourceAllocations allocations = resourceService.getAllocations(intent.id());
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
selectorBuilder.matchInport(intent.src().port());
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
ConnectPoint prev = intent.src();
//TODO throw exception if the lambda was not retrieved successfully
for (Link link : intent.path().links()) {
Lambda la = null;
for (ResourceAllocation allocation : allocations.getResourceAllocation(link)) {
if (allocation.type() == ResourceType.LAMBDA) {
la = ((LambdaResourceAllocation) allocation).lambda();
break;
}
}
if (la == null) {
log.info("Lambda was not retrieved successfully");
return null;
}
treatmentBuilder.setOutput(link.src().port());
treatmentBuilder.setLambda((short) la.toInt());
FlowRule rule = new DefaultFlowRule(prev.deviceId(),
selectorBuilder.build(),
treatmentBuilder.build(),
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
prev = link.dst();
selectorBuilder.matchInport(link.dst().port());
selectorBuilder.matchLambda((short) la.toInt());
}
// build the last T port rule
TrafficTreatment treatmentLast = builder()
.setOutput(intent.dst().port()).build();
FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
selectorBuilder.build(),
treatmentLast,
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
}
package org.onlab.onos.net.resource.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceRequest;
import org.onlab.onos.net.resource.ResourceType;
/**
* Implementation of {@link LinkResourceAllocations}.
*/
public class DefaultLinkResourceAllocations implements LinkResourceAllocations {
private final LinkResourceRequest request;
private final Map<Link, Set<ResourceAllocation>> allocations;
/**
* Creates a new link resource allocations.
*
* @param request requested resources
* @param allocations allocated resources
*/
protected DefaultLinkResourceAllocations(LinkResourceRequest request,
Map<Link, Set<ResourceAllocation>> allocations) {
this.request = request;
this.allocations = allocations;
}
@Override
public IntentId intendId() {
return request.intendId();
}
@Override
public Collection<Link> links() {
return request.links();
}
@Override
public Set<ResourceRequest> resources() {
return request.resources();
}
@Override
public ResourceType type() {
return null;
}
@Override
public Set<ResourceAllocation> getResourceAllocation(Link link) {
Set<ResourceAllocation> result = allocations.get(link);
if (result == null) {
result = Collections.emptySet();
}
return result;
}
}
package org.onlab.onos.net.resource.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.resource.BandwidthResourceAllocation;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LambdaResourceAllocation;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceRequest;
import org.slf4j.Logger;
import com.google.common.collect.Sets;
/**
* Provides basic implementation of link resources allocation.
*/
@Component(immediate = true)
@Service
public class LinkResourceManager implements LinkResourceService {
private final Logger log = getLogger(getClass());
@Activate
public void activate() {
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
@Override
public LinkResourceAllocations requestResources(LinkResourceRequest req) {
// TODO implement it using a resource data store.
ResourceAllocation alloc = null;
for (ResourceRequest r: req.resources()) {
switch (r.type()) {
case BANDWIDTH:
log.info("requestResources() always returns requested bandwidth");
BandwidthResourceRequest br = (BandwidthResourceRequest) r;
alloc = new BandwidthResourceAllocation(br.bandwidth());
break;
case LAMBDA:
log.info("requestResources() always returns lambda 7");
alloc = new LambdaResourceAllocation(Lambda.valueOf(7));
break;
default:
break;
}
}
Map<Link, Set<ResourceAllocation>> allocations = new HashMap<>();
for (Link link: req.links()) {
allocations.put(link, Sets.newHashSet(alloc));
}
return new DefaultLinkResourceAllocations(req, allocations);
}
@Override
public void releaseResources(LinkResourceAllocations allocations) {
// TODO Auto-generated method stub
}
@Override
public Iterable<LinkResourceAllocations> getAllocations() {
// TODO Auto-generated method stub
return null;
}
@Override
public LinkResourceAllocations getAllocations(IntentId intentId) {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<LinkResourceAllocations> getAllocations(Link link) {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterable<IntentId> getIntents(Link link) {
// TODO Auto-generated method stub
return null;
}
@Override
public ResourceRequest getAvailableResources(Link link) {
// TODO Auto-generated method stub
return null;
}
}
/**
* Services for reserving network resources, e.g.&nbsp;bandwidth, lambdas.
*/
package org.onlab.onos.net.resource.impl;
......@@ -157,16 +157,12 @@ public class StatisticManager implements StatisticService {
case RULE_UPDATED:
if (rule instanceof FlowEntry) {
statisticStore.addOrUpdateStatistic((FlowEntry) rule);
} else {
log.warn("IT AIN'T A FLOWENTRY");
}
break;
case RULE_ADD_REQUESTED:
log.info("Preparing for stats");
statisticStore.prepareForStatistics(rule);
break;
case RULE_REMOVE_REQUESTED:
log.info("Removing stats");
statisticStore.removeFromStatistics(rule);
break;
case RULE_REMOVED:
......
package org.onlab.onos.net.flow.impl;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
import java.util.ArrayList;
import java.util.Collections;
......@@ -12,6 +18,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
......@@ -31,6 +38,7 @@ import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.device.DeviceListener;
import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.flow.BatchOperation;
import org.onlab.onos.net.flow.CompletedBatchOperation;
import org.onlab.onos.net.flow.DefaultFlowEntry;
import org.onlab.onos.net.flow.DefaultFlowRule;
......@@ -50,7 +58,6 @@ import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.flow.BatchOperation;
import org.onlab.onos.net.provider.AbstractProvider;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore;
......@@ -59,16 +66,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import static java.util.Collections.EMPTY_LIST;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Test codifying the flow rule service & flow rule provider service contracts.
......@@ -182,7 +180,6 @@ public class FlowRuleManagerTest {
// TODO: If preserving iteration order is a requirement, redo FlowRuleStore.
//backing store is sensitive to the order of additions/removals
@SuppressWarnings("unchecked")
private boolean validateState(Map<FlowRule, FlowEntryState> expected) {
Map<FlowRule, FlowEntryState> expectedToCheck = new HashMap<>(expected);
Iterable<FlowEntry> rules = service.getFlowEntries(DID);
......@@ -526,13 +523,13 @@ public class FlowRuleManagerTest {
}
@Override
public Future<CompletedBatchOperation> executeBatch(
public ListenableFuture<CompletedBatchOperation> executeBatch(
BatchOperation<FlowRuleBatchEntry> batch) {
return new TestInstallationFuture();
}
private class TestInstallationFuture
implements Future<CompletedBatchOperation> {
implements ListenableFuture<CompletedBatchOperation> {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
......@@ -550,10 +547,9 @@ public class FlowRuleManagerTest {
}
@Override
@SuppressWarnings("unchecked")
public CompletedBatchOperation get()
throws InterruptedException, ExecutionException {
return new CompletedBatchOperation(true, EMPTY_LIST);
return new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet());
}
@Override
......@@ -562,6 +558,11 @@ public class FlowRuleManagerTest {
ExecutionException, TimeoutException {
return null;
}
@Override
public void addListener(Runnable task, Executor executor) {
// TODO: add stuff.
}
}
}
......@@ -581,6 +582,12 @@ public class FlowRuleManagerTest {
}
@Override
public Criterion getCriterion(
org.onlab.onos.net.flow.criteria.Criterion.Type type) {
return null;
}
@Override
public int hashCode() {
return testval;
}
......@@ -592,6 +599,7 @@ public class FlowRuleManagerTest {
}
return false;
}
}
private class TestTreatment implements TrafficTreatment {
......
package org.onlab.onos.net.intent;
import static org.onlab.onos.net.NetTestTools.createPath;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -12,12 +14,11 @@ import org.onlab.onos.net.Path;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.onos.net.flow.criteria.Criterion.Type;
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.topology.PathService;
import static org.onlab.onos.net.NetTestTools.createPath;
/**
* Common mocks used by the intent framework tests.
*/
......@@ -30,6 +31,11 @@ public class IntentTestsMocks {
public Set<Criterion> criteria() {
return new HashSet<>();
}
@Override
public Criterion getCriterion(Type type) {
return null;
}
}
/**
......
......@@ -103,7 +103,7 @@ public class ClusterCommunicationManager
final ControllerNode localNode = clusterService.getLocalNode();
for (NodeId nodeId : nodes) {
if (!nodeId.equals(localNode.id())) {
ok = unicast(message, nodeId) && ok;
ok = unicastUnchecked(message, nodeId) && ok;
}
}
return ok;
......@@ -124,6 +124,14 @@ public class ClusterCommunicationManager
}
}
private boolean unicastUnchecked(ClusterMessage message, NodeId toNodeId) throws IOException {
try {
return unicast(message, toNodeId);
} catch (IOException e) {
return false;
}
}
@Override
public ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException {
ControllerNode node = clusterService.getNode(toNodeId);
......
......@@ -7,9 +7,10 @@ import org.onlab.onos.store.cluster.messaging.MessageSubject;
*/
public final class FlowStoreMessageSubjects {
private FlowStoreMessageSubjects() {}
public static final MessageSubject STORE_FLOW_RULE = new MessageSubject("peer-forward-store-flow-rule");
public static final MessageSubject DELETE_FLOW_RULE = new MessageSubject("peer-forward-delete-flow-rule");
public static final MessageSubject ADD_OR_UPDATE_FLOW_RULE =
new MessageSubject("peer-forward-add-or-update-flow-rule");
public static final MessageSubject REMOVE_FLOW_RULE = new MessageSubject("peer-forward-remove-flow-rule");
public static final MessageSubject APPLY_BATCH_FLOWS
= new MessageSubject("peer-forward-apply-batch");
public static final MessageSubject GET_FLOW_ENTRY
= new MessageSubject("peer-forward-get-flow-entry");
}
......
......@@ -399,7 +399,7 @@ public class GossipHostStore
}
// Auxiliary extension to allow location to mutate.
private class StoredHost extends DefaultHost {
private static final class StoredHost extends DefaultHost {
private Timestamped<HostLocation> location;
/**
......
......@@ -58,7 +58,6 @@ implements MastershipStore {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
@Activate
public void activate() {
......@@ -76,9 +75,9 @@ implements MastershipStore {
}
};
roleMap = new SMap(theInstance.getMap("nodeRoles"), this.serializer);
roleMap = new SMap<>(theInstance.<byte[], byte[]>getMap("nodeRoles"), this.serializer);
roleMap.addEntryListener((new RemoteMasterShipEventHandler()), true);
terms = new SMap(theInstance.getMap("terms"), this.serializer);
terms = new SMap<>(theInstance.<byte[], byte[]>getMap("terms"), this.serializer);
clusterSize = theInstance.getAtomicLong("clustersize");
log.info("Started");
......
package org.onlab.onos.store.mastership.impl;
import java.util.Collections;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
......@@ -17,9 +17,9 @@ import com.google.common.base.MoreObjects.ToStringHelper;
* A structure that holds node mastership roles associated with a
* {@link DeviceId}. This structure needs to be locked through IMap.
*/
public class RoleValue {
final class RoleValue {
protected Map<MastershipRole, List<NodeId>> value = new HashMap<>();
protected final Map<MastershipRole, List<NodeId>> value = new EnumMap<>(MastershipRole.class);
public RoleValue() {
value.put(MastershipRole.MASTER, new LinkedList<NodeId>());
......@@ -27,7 +27,8 @@ public class RoleValue {
value.put(MastershipRole.NONE, new LinkedList<NodeId>());
}
public Map<MastershipRole, List<NodeId>> value() {
// exposing internals for serialization purpose only
Map<MastershipRole, List<NodeId>> value() {
return Collections.unmodifiableMap(value);
}
......
......@@ -35,10 +35,10 @@ public class RoleValueSerializer extends Serializer<RoleValue> {
@Override
public void write(Kryo kryo, Output output, RoleValue type) {
output.writeInt(type.value().size());
final Map<MastershipRole, List<NodeId>> map = type.value();
output.writeInt(map.size());
for (Map.Entry<MastershipRole, List<NodeId>> el :
type.value().entrySet()) {
for (Map.Entry<MastershipRole, List<NodeId>> el : map.entrySet()) {
output.writeInt(el.getKey().ordinal());
List<NodeId> nodes = el.getValue();
......
......@@ -492,7 +492,10 @@ public class SMap<K, V> implements IMap<K, V> {
}
private V deserializeVal(byte[] val) {
return serializer.decode(val);
if (val == null) {
return null;
}
return serializer.decode(val.clone());
}
private Set<byte[]> serializeKeySet(Set<K> keys) {
......
......@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import org.onlab.onos.cluster.ControllerNode;
import org.onlab.onos.cluster.DefaultControllerNode;
......@@ -27,12 +28,16 @@ import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.device.DefaultDeviceDescription;
import org.onlab.onos.net.device.DefaultPortDescription;
import org.onlab.onos.net.flow.CompletedBatchOperation;
import org.onlab.onos.net.flow.DefaultFlowEntry;
import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.DefaultTrafficTreatment;
import org.onlab.onos.net.flow.FlowEntry;
import org.onlab.onos.net.flow.FlowId;
import org.onlab.onos.net.flow.FlowRuleBatchEntry;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
import org.onlab.onos.net.flow.StoredFlowEntry;
import org.onlab.onos.net.flow.criteria.Criteria;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.onos.net.flow.instructions.Instructions;
......@@ -79,6 +84,7 @@ public final class KryoNamespaces {
Arrays.asList().getClass(),
HashMap.class,
HashSet.class,
LinkedList.class,
//
//
ControllerNode.State.class,
......@@ -97,6 +103,8 @@ public final class KryoNamespaces {
HostId.class,
HostDescription.class,
DefaultHostDescription.class,
DefaultFlowEntry.class,
StoredFlowEntry.class,
DefaultFlowRule.class,
DefaultFlowEntry.class,
FlowEntry.FlowEntryState.class,
......@@ -115,7 +123,11 @@ public final class KryoNamespaces {
DefaultTrafficTreatment.class,
Instructions.DropInstruction.class,
Instructions.OutputInstruction.class,
RoleInfo.class
RoleInfo.class,
FlowRuleBatchOperation.class,
CompletedBatchOperation.class,
FlowRuleBatchEntry.class,
FlowRuleBatchEntry.FlowRuleOperation.class
)
.register(URI.class, new URISerializer())
.register(NodeId.class, new NodeIdSerializer())
......
package org.onlab.onos.store.trivial.impl;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
import static org.slf4j.LoggerFactory.getLogger;
import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.util.concurrent.Futures;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.flow.CompletedBatchOperation;
import org.onlab.onos.net.flow.DefaultFlowEntry;
import org.onlab.onos.net.flow.FlowEntry;
import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
import org.onlab.onos.net.flow.FlowId;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleBatchEntry;
import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
import org.onlab.onos.net.flow.FlowRuleBatchEvent;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
import org.onlab.onos.net.flow.FlowRuleBatchRequest;
import org.onlab.onos.net.flow.FlowRuleEvent;
import org.onlab.onos.net.flow.FlowRuleEvent.Type;
import org.onlab.onos.net.flow.FlowRuleStore;
......@@ -31,8 +29,19 @@ import org.onlab.onos.store.AbstractStore;
import org.onlab.util.NewConcurrentHashMap;
import org.slf4j.Logger;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Manages inventory of flow rules using trivial in-memory implementation.
......@@ -40,7 +49,7 @@ import com.google.common.collect.FluentIterable;
@Component(immediate = true)
@Service
public class SimpleFlowRuleStore
extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate>
extends AbstractStore<FlowRuleBatchEvent, FlowRuleStoreDelegate>
implements FlowRuleStore {
private final Logger log = getLogger(getClass());
......@@ -122,15 +131,15 @@ public class SimpleFlowRuleStore
public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
// flatten and make iterator unmodifiable
return FluentIterable.from(getFlowTable(deviceId).values())
.transformAndConcat(
new Function<List<StoredFlowEntry>, Iterable<? extends FlowEntry>>() {
.transformAndConcat(
new Function<List<StoredFlowEntry>, Iterable<? extends FlowEntry>>() {
@Override
public Iterable<? extends FlowEntry> apply(
List<StoredFlowEntry> input) {
return Collections.unmodifiableList(input);
}
});
@Override
public Iterable<? extends FlowEntry> apply(
List<StoredFlowEntry> input) {
return Collections.unmodifiableList(input);
}
});
}
@Override
......@@ -148,12 +157,11 @@ public class SimpleFlowRuleStore
}
@Override
public boolean storeFlowRule(FlowRule rule) {
final boolean added = storeFlowRuleInternal(rule);
return added;
public void storeFlowRule(FlowRule rule) {
storeFlowRuleInternal(rule);
}
private boolean storeFlowRuleInternal(FlowRule rule) {
private void storeFlowRuleInternal(FlowRule rule) {
StoredFlowEntry f = new DefaultFlowEntry(rule);
final DeviceId did = f.deviceId();
final FlowId fid = f.id();
......@@ -162,19 +170,20 @@ public class SimpleFlowRuleStore
for (StoredFlowEntry fe : existing) {
if (fe.equals(rule)) {
// was already there? ignore
return false;
return;
}
}
// new flow rule added
existing.add(f);
// TODO: Should we notify only if it's "remote" event?
//notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, rule));
return true;
notifyDelegate(FlowRuleBatchEvent.requested(
new FlowRuleBatchRequest(1, /* FIXME generate something */
Arrays.<FlowEntry>asList(f),
Collections.<FlowEntry>emptyList())));
}
}
@Override
public boolean deleteFlowRule(FlowRule rule) {
public void deleteFlowRule(FlowRule rule) {
List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id());
......@@ -184,14 +193,17 @@ public class SimpleFlowRuleStore
synchronized (entry) {
entry.setState(FlowEntryState.PENDING_REMOVE);
// TODO: Should we notify only if it's "remote" event?
//notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, rule));
return true;
notifyDelegate(FlowRuleBatchEvent.requested(
new FlowRuleBatchRequest(1, /* FIXME generate something */
Collections.<FlowEntry>emptyList(),
Arrays.<FlowEntry>asList(entry))));
}
}
}
}
//log.warn("Cannot find rule {}", rule);
return false;
}
@Override
......@@ -237,4 +249,24 @@ public class SimpleFlowRuleStore
}
return null;
}
@Override
public Future<CompletedBatchOperation> storeBatch(
FlowRuleBatchOperation batchOperation) {
for (FlowRuleBatchEntry entry : batchOperation.getOperations()) {
if (entry.getOperator().equals(FlowRuleOperation.ADD)) {
storeFlowRule(entry.getTarget());
} else if (entry.getOperator().equals(FlowRuleOperation.REMOVE)) {
deleteFlowRule(entry.getTarget());
} else {
throw new UnsupportedOperationException("Unsupported operation type");
}
}
return Futures.immediateFuture(new CompletedBatchOperation(true, Collections.<FlowEntry>emptySet()));
}
@Override
public void batchOperationComplete(FlowRuleBatchEvent event) {
notifyDelegate(event);
}
}
......
......@@ -269,7 +269,7 @@ public class SimpleHostStore
}
// Auxiliary extension to allow location to mutate.
private class StoredHost extends DefaultHost {
private static final class StoredHost extends DefaultHost {
private HostLocation location;
/**
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<prerequisites>
<maven>3.0.0</maven>
</prerequisites>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-docs-external</artifactId>
<packaging>pom</packaging>
<description>ONOS Java API documentation</description>
<modules>
<module>..</module>
</modules>
<url>http://onlab.us/</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
<configuration>
<show>package</show>
<excludePackageNames>org.onlab.thirdparty:*.impl:*.impl.*:org.onlab.onos.provider.*:org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli*:org.onlab.onos.tvue:org.onlab.onos.foo:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.optical:org.onlab.onos.config:org.onlab.onos.calendar:org.onlab.onos.sdnip*:org.onlab.onos.metrics</excludePackageNames>
<docfilessubdirs>true</docfilessubdirs>
<doctitle>ONOS Java API</doctitle>
<groups>
<group>
<title>Network Model &amp; Services</title>
<packages>
org.onlab.onos:org.onlab.onos.*
</packages>
</group>
<group>
<title>Utilities</title>
<packages>
org.onlab.*
</packages>
</group>
</groups>
</configuration>
</plugin>
</plugins>
</build>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<prerequisites>
<maven>3.0.0</maven>
</prerequisites>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-docs</artifactId>
<packaging>pom</packaging>
<description>ONOS Java API documentation</description>
<modules>
<module>..</module>
</modules>
<url>http://onlab.us/</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
<configuration>
<show>package</show>
<docfilessubdirs>true</docfilessubdirs>
<doctitle>ONOS Java API</doctitle>
<groups>
<group>
<title>Network Model &amp; Services</title>
<packages>
org.onlab.onos:org.onlab.onos.*
</packages>
</group>
<group>
<title>Core Subsystems</title>
<packages>
org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl:org.onlab.onos.mastership.impl:org.onlab.onos.json:org.onlab.onos.json.*:org.onlab.onos.provider.host.impl:org.onlab.onos.provider.lldp.impl:org.onlab.onos.net.statistic.impl
</packages>
</group>
<group>
<title>OpenFlow Providers &amp; Controller
</title>
<packages>
org.onlab.onos.provider.of.*:org.onlab.onos.openflow.*
</packages>
</group>
<group>
<title>Utilities</title>
<packages>
org.onlab.*
</packages>
</group>
<group>
<title>GUI, REST &amp; Command-Line</title>
<packages>
org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli:org.onlab.onos.gui.*:org.onlab.onos.rest.*:org.onlab.onos.cli.*
</packages>
</group>
<group>
<title>Sample Applications</title>
<packages>
org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo:org.onlab.onos.calendar:org.onlab.onos.sdnip:org.onlab.onos.sdnip.*:org.onlab.onos.optical:org.onlab.onos.optical.*:org.onlab.onos.metrics.*:org.onlab.onos.config
</packages>
</group>
</groups>
<excludePackageNames>org.onlab.thirdparty
</excludePackageNames>
</configuration>
</plugin>
</plugins>
</build>
</project>
......@@ -35,7 +35,7 @@
<bundle>mvn:io.netty/netty-transport-native-epoll/4.0.23.Final</bundle>
<bundle>mvn:commons-pool/commons-pool/1.6</bundle>
<bundle>mvn:com.hazelcast/hazelcast/3.3</bundle>
<bundle>mvn:com.hazelcast/hazelcast/3.3.2</bundle>
<bundle>mvn:io.dropwizard.metrics/metrics-core/3.1.0</bundle>
<bundle>mvn:io.dropwizard.metrics/metrics-json/3.1.0</bundle>
<bundle>mvn:com.eclipsesource.minimal-json/minimal-json/0.9.1</bundle>
......
......@@ -30,7 +30,7 @@
<groupId>org.projectfloodlight</groupId>
<artifactId>openflowj</artifactId>
<!-- FIXME once experimenter gets merged to upstream -->
<version>0.3.8-optical_experimenter3</version>
<version>0.3.8-optical_experimenter4</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
......
package org.onlab.onos.openflow.controller;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;
import org.onlab.packet.Ethernet;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPacketOut;
......@@ -9,9 +13,6 @@ import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;
public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext {
private final AtomicBoolean free = new AtomicBoolean(true);
......
......@@ -4,6 +4,10 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<prerequisites>
<maven>3.0.0</maven>
</prerequisites>
<groupId>org.onlab.onos</groupId>
<artifactId>onos</artifactId>
<packaging>pom</packaging>
......@@ -28,7 +32,6 @@
<licenses>
<license>
<!-- TODO: Is this really our license scheme? -->
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
......@@ -192,7 +195,7 @@
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>3.3</version>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.eclipsesource.minimal-json</groupId>
......@@ -528,59 +531,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
<configuration>
<show>package</show>
<docfilessubdirs>true</docfilessubdirs>
<doctitle>ONOS Java API</doctitle>
<groups>
<group>
<title>Network Model &amp; Services</title>
<packages>
org.onlab.onos:org.onlab.onos.*
</packages>
</group>
<group>
<title>Core Subsystems</title>
<packages>
org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl:org.onlab.onos.mastership.impl:org.onlab.onos.json:org.onlab.onos.json.*:org.onlab.onos.provider.host.impl:org.onlab.onos.provider.lldp.impl:org.onlab.onos.net.statistic.impl
</packages>
</group>
<group>
<title>OpenFlow Providers &amp; Controller
</title>
<packages>
org.onlab.onos.provider.of.*:org.onlab.onos.openflow.*
</packages>
</group>
<group>
<title>Utilities</title>
<packages>
org.onlab.*
</packages>
</group>
<group>
<title>GUI, REST &amp; Command-Line</title>
<packages>
org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli:org.onlab.onos.gui.*:org.onlab.onos.rest.*:org.onlab.onos.cli.*
</packages>
</group>
<group>
<title>Sample Applications</title>
<packages>
org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo:org.onlab.onos.calendar:org.onlab.onos.sdnip:org.onlab.onos.sdnip.*:org.onlab.onos.optical:org.onlab.onos.optical.*:org.onlab.onos.metrics.*
</packages>
</group>
</groups>
<excludePackageNames>org.onlab.thirdparty
</excludePackageNames>
</configuration>
</plugin>
</plugins>
</build>
......@@ -607,10 +557,6 @@
</rulesets>
</configuration>
</plugin>
</plugins>
</reporting>
<prerequisites>
<maven>3.0.0</maven>
</prerequisites>
</project>
......
......@@ -90,7 +90,7 @@ public class LinkDiscovery implements TimerTask {
* Instantiates discovery manager for the given physical switch. Creates a
* generic LLDP packet that will be customized for the port it is sent out on.
* Starts the the timer for the discovery process.
* @param device the physical switch
* @param device the physical switch
* @param masterService
* @param useBDDP flag to also use BDDP for discovery
*/
......@@ -217,7 +217,7 @@ public class LinkDiscovery implements TimerTask {
final PortNumber srcPort = PortNumber.portNumber(onoslldp.getPort());
final DeviceId srcDeviceId = DeviceId.deviceId(onoslldp.getDeviceString());
final DeviceId dstDeviceId = context.inPacket().receivedFrom().deviceId();
this.ackProbe(srcPort.toLong());
this.ackProbe(dstPort.toLong());
ConnectPoint src = new ConnectPoint(srcDeviceId, srcPort);
ConnectPoint dst = new ConnectPoint(dstDeviceId, dstPort);
......@@ -245,7 +245,7 @@ public class LinkDiscovery implements TimerTask {
*/
@Override
public void run(final Timeout t) {
this.log.debug("sending probes");
this.log.trace("sending probes");
synchronized (this) {
final Iterator<Long> fastIterator = this.fastPorts.iterator();
Long portNumber;
......@@ -256,7 +256,7 @@ public class LinkDiscovery implements TimerTask {
.getAndIncrement();
if (probeCount < LinkDiscovery.MAX_PROBE_COUNT) {
this.log.debug("sending fast probe to port");
this.log.trace("sending fast probe to port");
sendProbes(portNumber);
} else {
// Update fast and slow ports
......@@ -278,7 +278,7 @@ public class LinkDiscovery implements TimerTask {
Iterator<Long> slowIterator = this.slowPorts.iterator();
while (slowIterator.hasNext()) {
portNumber = slowIterator.next();
this.log.debug("sending slow probe to port {}", portNumber);
this.log.trace("sending slow probe to port {}", portNumber);
sendProbes(portNumber);
......
......@@ -23,6 +23,8 @@ import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
import org.projectfloodlight.openflow.protocol.OFInstructionType;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.action.OFActionCircuit;
import org.projectfloodlight.openflow.protocol.action.OFActionExperimenter;
import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
......@@ -34,6 +36,7 @@ import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.Masked;
import org.slf4j.Logger;
......@@ -166,6 +169,15 @@ public class FlowEntryBuilder {
builder.setIpSrc(IpPrefix.valueOf(si.getInt()));
}
break;
case EXPERIMENTER:
OFActionExperimenter exp = (OFActionExperimenter) act;
if (exp.getExperimenter() == 0x80005A06) {
OFActionCircuit ct = (OFActionCircuit) exp;
builder.setLambda(((OFOxmOchSigidBasic) ct.getField()).getValue().getChannelNumber());
} else {
log.warn("Unsupported OFActionExperimenter {}", exp.getExperimenter());
}
break;
case SET_TP_DST:
case SET_TP_SRC:
case POP_MPLS:
......@@ -188,7 +200,7 @@ public class FlowEntryBuilder {
case DEC_MPLS_TTL:
case DEC_NW_TTL:
case ENQUEUE:
case EXPERIMENTER:
case GROUP:
default:
log.warn("Action type {} not yet implemented.", act.getType());
......@@ -268,6 +280,10 @@ public class FlowEntryBuilder {
case TCP_SRC:
builder.matchTcpSrc((short) match.get(MatchField.TCP_SRC).getPort());
break;
case OCH_SIGID:
builder.matchLambda(match.get(MatchField.OCH_SIGID).getChannelNumber());
break;
case OCH_SIGTYPE_BASIC:
case ARP_OP:
case ARP_SHA:
case ARP_SPA:
......
......@@ -14,6 +14,7 @@ import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.IPProtocolCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.LambdaCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.PortCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.TcpPortCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
......@@ -21,6 +22,8 @@ import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
......@@ -35,6 +38,7 @@ import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.CircuitSignalID;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.IpProtocol;
......@@ -137,6 +141,9 @@ public class FlowModBuilder {
case DROP:
log.warn("Saw drop action; assigning drop action");
return new LinkedList<>();
case L0MODIFICATION:
acts.add(buildL0Modification(i));
break;
case L2MODIFICATION:
acts.add(buildL2Modification(i));
break;
......@@ -157,6 +164,20 @@ public class FlowModBuilder {
return acts;
}
private OFAction buildL0Modification(Instruction i) {
L0ModificationInstruction l0m = (L0ModificationInstruction) i;
switch (l0m.subtype()) {
case LAMBDA:
ModLambdaInstruction ml = (ModLambdaInstruction) i;
return factory.actions().circuit(factory.oxms().ochSigidBasic(
new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
default:
log.warn("Unimplemented action type {}.", l0m.subtype());
break;
}
return null;
}
private OFAction buildL3Modification(Instruction i) {
L3ModificationInstruction l3m = (L3ModificationInstruction) i;
ModIPInstruction ip;
......@@ -261,6 +282,11 @@ public class FlowModBuilder {
tp = (TcpPortCriterion) c;
mBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(tp.tcpPort()));
break;
case OCH_SIGID:
LambdaCriterion lc = (LambdaCriterion) c;
mBuilder.setExact(MatchField.OCH_SIGID,
new CircuitSignalID((byte) 1, (byte) 2, lc.lambda(), (short) 1));
break;
case ARP_OP:
case ARP_SHA:
case ARP_SPA:
......
......@@ -10,7 +10,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
......@@ -69,9 +69,11 @@ import org.projectfloodlight.openflow.types.U32;
import org.slf4j.Logger;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ExecutionList;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provider which uses an OpenFlow controller to detect network
......@@ -97,6 +99,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
private final InternalFlowProvider listener = new InternalFlowProvider();
// FIXME: This should be an expiring map to ensure futures that don't have
// a future eventually get garbage collected.
private final Map<Long, InstallationFuture> pendingFutures =
new ConcurrentHashMap<Long, InstallationFuture>();
......@@ -169,7 +173,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
}
@Override
public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
public ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
final Set<Dpid> sws =
Collections.newSetFromMap(new ConcurrentHashMap<Dpid, Boolean>());
final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>();
......@@ -330,18 +334,20 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
}
private class InstallationFuture implements Future<CompletedBatchOperation> {
private class InstallationFuture implements ListenableFuture<CompletedBatchOperation> {
private final Set<Dpid> sws;
private final AtomicBoolean ok = new AtomicBoolean(true);
private final Map<Long, FlowRuleBatchEntry> fms;
private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList();
private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
private final CountDownLatch countDownLatch;
private Long pendingXid;
private BatchState state;
private final ExecutionList executionList = new ExecutionList();
public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
this.state = BatchState.STARTED;
this.sws = sws;
......@@ -350,6 +356,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
}
public void fail(OFErrorMsg msg, Dpid dpid) {
ok.set(false);
removeRequirement(dpid);
FlowEntry fe = null;
......@@ -422,6 +429,9 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (isDone()) {
return false;
}
ok.set(false);
this.state = BatchState.CANCELLED;
cleanUp();
......@@ -434,7 +444,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
}
}
return isCancelled();
invokeCallbacks();
return true;
}
@Override
......@@ -444,14 +455,15 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
@Override
public boolean isDone() {
return this.state == BatchState.FINISHED;
return this.state == BatchState.FINISHED || isCancelled();
}
@Override
public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
countDownLatch.await();
this.state = BatchState.FINISHED;
return new CompletedBatchOperation(ok.get(), offendingFlowMods);
CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods);
return result;
}
@Override
......@@ -460,7 +472,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
TimeoutException {
if (countDownLatch.await(timeout, unit)) {
this.state = BatchState.FINISHED;
return new CompletedBatchOperation(ok.get(), offendingFlowMods);
CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods);
return result;
}
throw new TimeoutException();
}
......@@ -478,10 +491,21 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
private void removeRequirement(Dpid dpid) {
countDownLatch.countDown();
if (countDownLatch.getCount() == 0) {
invokeCallbacks();
}
sws.remove(dpid);
cleanUp();
}
@Override
public void addListener(Runnable runnable, Executor executor) {
executionList.add(runnable, executor);
}
private void invokeCallbacks() {
executionList.execute();
}
}
}
......
......@@ -6,5 +6,4 @@
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
cd $ONOS_ROOT
mvn clean install && mvn javadoc:aggregate
cd $ONOS_ROOT && mvn clean install && cd docs && mvn javadoc:aggregate
......
package org.onlab.metrics;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Meter;
/**
* Metric measurements for events.
*/
public class EventMetric {
private static final String GAUGE_TIMESTAMP_NAME = "Timestamp.EpochMs";
private static final String METER_RATE_NAME = "Rate";
private final MetricsService metricsService;
private final String componentName;
private final String featureName;
private MetricsComponent metricsComponent;
private MetricsFeature metricsFeature;
private volatile long lastEventTimestampEpochMs = 0;
private Gauge<Long> lastEventTimestampGauge;
private Meter eventRateMeter;
/**
* Constructor.
*
* @param metricsService the Metrics Service to use for Metrics
* registration and deregistration
* @param componentName the Metrics Component Name to use for Metrics
* registration and deregistration
* @param featureName the Metrics Feature Name to use for Metrics
* registration and deregistration
*/
public EventMetric(MetricsService metricsService, String componentName,
String featureName) {
this.metricsService = metricsService;
this.componentName = componentName;
this.featureName = featureName;
}
/**
* Registers the metrics.
*/
public void registerMetrics() {
metricsComponent = metricsService.registerComponent(componentName);
metricsFeature = metricsComponent.registerFeature(featureName);
lastEventTimestampEpochMs = 0;
lastEventTimestampGauge =
metricsService.registerMetric(metricsComponent,
metricsFeature,
GAUGE_TIMESTAMP_NAME,
new Gauge<Long>() {
@Override
public Long getValue() {
return lastEventTimestampEpochMs;
}
});
eventRateMeter = metricsService.createMeter(metricsComponent,
metricsFeature,
METER_RATE_NAME);
}
/**
* Removes the metrics.
*/
public void removeMetrics() {
lastEventTimestampEpochMs = 0;
metricsService.removeMetric(metricsComponent,
metricsFeature,
GAUGE_TIMESTAMP_NAME);
metricsService.removeMetric(metricsComponent,
metricsFeature,
METER_RATE_NAME);
}
/**
* Updates the metric measurements for a single event.
*/
public void eventReceived() {
lastEventTimestampEpochMs = System.currentTimeMillis();
eventRateMeter.mark(1);
}
/**
* Gets the last event timestamp Gauge (ms from the Epoch).
*
* @return the last event timestamp Gauge (ms from the Epoch)
*/
public Gauge<Long> lastEventTimestampGauge() {
return lastEventTimestampGauge;
}
/**
* Gets the event rate meter.
*
* @return the event rate meter
*/
public Meter eventRateMeter() {
return eventRateMeter;
}
}
......@@ -32,7 +32,7 @@ public final class ChassisId {
* @param value the value to use.
*/
public ChassisId(String value) {
this.value = Long.valueOf(value, 16);
this.value = Long.parseLong(value, 16);
}
/**
......
......@@ -379,7 +379,7 @@ public class DHCP extends BasePacket {
// 300
int optionsLength = 0;
for (final DHCPOption option : this.options) {
if (option.getCode() == 0 || option.getCode() == 255) {
if (option.getCode() == 0 || option.getCode() == ((byte) 255)) {
optionsLength += 1;
} else {
optionsLength += 2 + (0xff & option.getLength());
......
......@@ -438,7 +438,7 @@ public class IPv4 extends BasePacket {
int result = 0;
for (int i = 0; i < 4; ++i) {
result |= Integer.valueOf(octets[i]) << (3 - i) * 8;
result |= Integer.parseInt(octets[i]) << (3 - i) * 8;
}
return result;
}
......@@ -471,7 +471,7 @@ public class IPv4 extends BasePacket {
int result = 0;
for (int i = 0; i < 4; ++i) {
result = ipAddress >> (3 - i) * 8 & 0xff;
sb.append(Integer.valueOf(result).toString());
sb.append(result);
if (i != 3) {
sb.append(".");
}
......
......@@ -14,7 +14,7 @@ public final class HexString {
*/
public static String toHexString(final byte[] bytes) {
int i;
StringBuilder ret = new StringBuilder();
StringBuilder ret = new StringBuilder(bytes.length * 3 - 1);
String tmp;
for (i = 0; i < bytes.length; i++) {
if (i > 0) {
......@@ -31,22 +31,22 @@ public final class HexString {
public static String toHexString(final long val, final int padTo) {
char[] arr = Long.toHexString(val).toCharArray();
String ret = "";
StringBuilder ret = new StringBuilder(padTo * 3 - 1);
// prepend the right number of leading zeros
int i = 0;
for (; i < (padTo * 2 - arr.length); i++) {
ret += "0";
ret.append('0');
if ((i % 2) != 0) {
ret += ":";
ret.append(':');
}
}
for (int j = 0; j < arr.length; j++) {
ret += arr[j];
ret.append(arr[j]);
if ((((i + j) % 2) != 0) && (j < (arr.length - 1))) {
ret += ":";
ret.append(':');
}
}
return ret;
return ret.toString();
}
public static String toHexString(final long val) {
......
......@@ -163,6 +163,7 @@ public class NettyMessagingService implements MessagingService {
handlers.putIfAbsent(type, handler);
}
@Override
public void unregisterHandler(String type) {
handlers.remove(type);
}
......@@ -242,7 +243,7 @@ public class NettyMessagingService implements MessagingService {
}
}
private class WriteTask implements Runnable {
private static class WriteTask implements Runnable {
private final InternalMessage message;
private final Channel channel;
......
......@@ -15,19 +15,18 @@
<link rel="stylesheet" href="onos.css">
<script src="geometry.js"></script>
<script src="onosui.js"></script>
<script src="onos.js"></script>
</head>
<body>
<div id="frame">
<div id="mast">
<span class="title">
ONOS Web UI
</span>
<img id="logo" src="img/onos-logo.png" width="60" height="38">
<span class="title">Open Network Operating System</span>
<span class="right">
<span class="radio">[one]</span>
<span class="radio">[two]</span>
<span class="radio">[three]</span>
<span class="radio">[All Layers]</span>
<span class="radio">[Packet Only]</span>
<span class="radio">[Optical Only]</span>
</span>
</div>
<div id="view"></div>
......
......@@ -10,17 +10,32 @@
var api = onos.api;
var config = {
layering: false,
options: {
layering: true,
collisionPrevention: true
},
jsonUrl: 'network.json',
iconUrl: {
pkt: 'pkt.png',
opt: 'opt.png'
device: 'img/device.png',
host: 'img/host.png',
pkt: 'img/pkt.png',
opt: 'img/opt.png'
},
mastHeight: 32,
mastHeight: 36,
force: {
linkDistance: 240,
linkStrength: 0.8,
charge: -400,
note: 'node.class or link.class is used to differentiate',
linkDistance: {
infra: 240,
host: 100
},
linkStrength: {
infra: 1.0,
host: 0.4
},
charge: {
device: -800,
host: -400
},
ticksWithoutCollisions: 50,
marginLR: 20,
marginTB: 20,
......@@ -31,18 +46,27 @@
}
},
labels: {
imgPad: 22,
imgPad: 16,
padLR: 8,
padTB: 6,
marginLR: 3,
marginTB: 2
},
icons: {
w: 32,
h: 32,
xoff: -12,
yoff: -8
},
constraints: {
ypos: {
pkt: 0.3,
opt: 0.7
host: 0.15,
switch: 0.3,
roadm: 0.7
}
}
},
hostLinkWidth: 1.0,
mouseOutTimerDelayMs: 120
},
view = {},
network = {},
......@@ -104,14 +128,23 @@
var nw = network.forceWidth,
nh = network.forceHeight;
network.data.nodes.forEach(function(n) {
function yPosConstraintForNode(n) {
return config.constraints.ypos[n.type || 'host'];
}
// Note that both 'devices' and 'hosts' get mapped into the nodes array
// first, the devices...
network.data.devices.forEach(function(n) {
var ypc = yPosConstraintForNode(n),
ix = Math.random() * 0.6 * nw + 0.2 * nw,
iy = ypc * nh,
node = {
id: n.id,
labels: n.labels,
class: 'device',
icon: 'device',
type: n.type,
status: n.status,
x: ix,
y: iy,
constraint: {
......@@ -123,21 +156,61 @@
network.nodes.push(node);
});
function yPosConstraintForNode(n) {
return config.constraints.ypos[n.type] || 0.5;
}
// then, the hosts...
network.data.hosts.forEach(function(n) {
var ypc = yPosConstraintForNode(n),
ix = Math.random() * 0.6 * nw + 0.2 * nw,
iy = ypc * nh,
node = {
id: n.id,
labels: n.labels,
class: 'host',
icon: 'host',
type: n.type,
x: ix,
y: iy,
constraint: {
weight: 0.7,
y: iy
}
};
network.lookup[n.id] = node;
network.nodes.push(node);
});
// now, process the explicit links...
network.data.links.forEach(function(n) {
var src = network.lookup[n.src],
dst = network.lookup[n.dst],
id = src.id + "~" + dst.id;
var link = {
class: 'infra',
id: id,
type: n.type,
width: n.linkWidth,
source: src,
target: dst,
strength: config.force.linkStrength
strength: config.force.linkStrength.infra
};
network.links.push(link);
});
// finally, infer host links...
network.data.hosts.forEach(function(n) {
var src = network.lookup[n.id],
dst = network.lookup[n.cp.device],
id = src.id + "~" + dst.id;
var link = {
class: 'host',
id: id,
type: 'hostLink',
width: config.hostLinkWidth,
source: src,
target: dst,
strength: config.force.linkStrength.host
};
network.links.push(link);
});
......@@ -145,13 +218,15 @@
function createLayout() {
var cfg = config.force;
network.force = d3.layout.force()
.size([network.forceWidth, network.forceHeight])
.nodes(network.nodes)
.links(network.links)
.linkStrength(function(d) { return d.strength; })
.size([network.forceWidth, network.forceHeight])
.linkDistance(config.force.linkDistance)
.charge(config.force.charge)
.linkStrength(function(d) { return cfg.linkStrength[d.class]; })
.linkDistance(function(d) { return cfg.linkDistance[d.class]; })
.charge(function(d) { return cfg.charge[d.class]; })
.on('tick', tick);
network.svg = d3.select('#view').append('svg')
......@@ -205,9 +280,10 @@
network.link = network.svg.append('g').selectAll('.link')
.data(network.force.links(), function(d) {return d.id})
.enter().append('line')
.attr('class', 'link');
.attr('class', function(d) {return 'link ' + d.class});
// TODO: drag behavior
// == define node drag behavior...
network.draggedThreshold = d3.scale.linear()
.domain([0, 0.1])
.range([5, 20])
......@@ -258,7 +334,11 @@
.data(network.force.nodes(), function(d) {return d.id})
.enter().append('g')
.attr('class', function(d) {
return 'node ' + d.type;
var cls = 'node ' + d.class;
if (d.type) {
cls += ' ' + d.type;
}
return cls;
})
.attr('transform', function(d) {
return translate(d.x, d.y);
......@@ -281,29 +361,33 @@
}
network.mouseoutTimeout = setTimeout(function() {
highlightObject(null);
}, 160);
}, config.mouseOutTimerDelayMs);
}
});
network.nodeRect = network.node.append('rect')
.attr('rx', 5)
.attr('ry', 5)
.attr('width', 126)
.attr('height', 40);
.attr('ry', 5);
// note that width/height are adjusted to fit the label text
network.node.each(function(d) {
var node = d3.select(this),
rect = node.select('rect'),
img = node.append('svg:image')
.attr('x', -16)
.attr('y', -16)
.attr('width', 32)
.attr('height', 32)
.attr('xlink:href', iconUrl(d)),
icon = iconUrl(d),
text = node.append('text')
// TODO: add label cycle behavior
.text(d.id)
.attr('dy', '1.1em'),
dummy;
.attr('dy', '1.1em');
if (icon) {
var cfg = config.icons;
node.append('svg:image')
.attr('width', cfg.w)
.attr('height', cfg.h)
.attr('xlink:href', icon);
// note, icon relative positioning (x,y) is done after we have
// adjusted the bounds of the rectangle...
}
});
......@@ -352,7 +436,8 @@
.attr('height', bounds.y2 - bounds.y1);
node.select('image')
.attr('x', bounds.x1);
.attr('x', bounds.x1 + config.icons.xoff)
.attr('y', bounds.y1 + config.icons.yoff);
d.extent = {
left: bounds.x1 - lab.marginLR,
......@@ -384,7 +469,7 @@
}
function iconUrl(d) {
return config.iconUrl[d.type];
return config.iconUrl[d.icon];
}
function translate(x, y) {
......@@ -440,7 +525,7 @@
function tick(e) {
network.numTicks++;
if (config.layering) {
if (config.options.layering) {
// adjust the y-coord of each node, based on y-pos constraints
network.nodes.forEach(function (n) {
var z = e.alpha * n.constraint.weight;
......@@ -450,7 +535,7 @@
});
}
if (network.preventCollisions) {
if (config.options.collisionPrevention && network.preventCollisions) {
preventCollisions();
}
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.