Praseed Balakrishnan

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

Conflicts:
	apps/optical/src/main/java/org/onlab/onos/optical/cfg/OpticalConfigProvider.java
Showing 22 changed files with 297 additions and 63 deletions
......@@ -13,7 +13,7 @@ public interface DeviceProvider extends Provider {
/**
* Triggers an asynchronous probe of the specified device, intended to
* determine whether the host is present or not. An indirect result of this
* determine whether the device is present or not. An indirect result of this
* should be invocation of
* {@link org.onlab.onos.net.device.DeviceProviderService#deviceConnected} )} or
* {@link org.onlab.onos.net.device.DeviceProviderService#deviceDisconnected}
......
......@@ -161,6 +161,17 @@ public class DeviceManager
}
}
// Queries a device for port information.
private void queryPortInfo(DeviceId deviceId) {
Device device = store.getDevice(deviceId);
// FIXME: Device might not be there yet. (eventual consistent)
if (device == null) {
return;
}
DeviceProvider provider = getProvider(device.providerId());
provider.triggerProbe(device);
}
@Override
public void removeDevice(DeviceId deviceId) {
checkNotNull(deviceId, DEVICE_ID_NULL);
......@@ -210,8 +221,6 @@ public class DeviceManager
log.info("Device {} connected", deviceId);
// check my Role
MastershipRole role = mastershipService.requestRoleFor(deviceId);
log.info("## - our role for {} is {} [master is {}]", deviceId, role,
mastershipService.getMasterFor(deviceId));
if (role != MastershipRole.MASTER) {
// TODO: Do we need to explicitly tell the Provider that
// this instance is no longer the MASTER? probably not
......@@ -265,7 +274,6 @@ public class DeviceManager
// but if I was the last STANDBY connection, etc. and no one else
// was there to mark the device offline, this instance may need to
// temporarily request for Master Role and mark offline.
log.info("## for {} role is {}", deviceId, mastershipService.getLocalRole(deviceId));
if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) {
log.debug("Device {} disconnected, but I am not the master", deviceId);
//let go of ability to be backup
......@@ -373,7 +381,6 @@ public class DeviceManager
final DeviceId did = event.subject();
final NodeId myNodeId = clusterService.getLocalNode().id();
log.info("## got Mastershipevent for dev {}", did);
if (myNodeId.equals(event.roleInfo().master())) {
MastershipTerm term = termService.getMastershipTerm(did);
......@@ -384,7 +391,6 @@ public class DeviceManager
return;
}
log.info("## setting term for CPS as new master for {}", did);
// only set the new term if I am the master
deviceClockProviderService.setMastershipTerm(did, term);
......@@ -404,6 +410,7 @@ public class DeviceManager
device.serialNumber(), device.chassisId()));
}
//TODO re-collect device information to fix potential staleness
queryPortInfo(did);
applyRole(did, MastershipRole.MASTER);
} else if (event.roleInfo().backups().contains(myNodeId)) {
applyRole(did, MastershipRole.STANDBY);
......
......@@ -299,7 +299,8 @@ public class FlowRuleManager
private void extraneousFlow(FlowRule flowRule) {
checkNotNull(flowRule, FLOW_RULE_NULL);
checkValidity();
removeFlowRules(flowRule);
FlowRuleProvider frp = getProvider(flowRule.deviceId());
frp.removeFlowRule(flowRule);
log.debug("Flow {} is on switch but not in store.", flowRule);
}
......
......@@ -9,6 +9,7 @@ import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleEvent;
import org.onlab.onos.net.flow.FlowRuleListener;
......@@ -35,12 +36,14 @@ public class StatisticManager implements StatisticService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StatisticStore statisticStore;
private final InternalFlowRuleListener listener = new InternalFlowRuleListener();
@Activate
public void activate() {
flowRuleService.addListener(listener);
log.info("Started");
}
@Deactivate
......@@ -81,7 +84,22 @@ public class StatisticManager implements StatisticService {
@Override
public void event(FlowRuleEvent event) {
// FlowRule rule = event.subject();
// switch (event.type()) {
// case RULE_ADDED:
// case RULE_UPDATED:
// if (rule instanceof FlowEntry) {
// statisticStore.addOrUpdateStatistic((FlowEntry) rule);
// }
// break;
// case RULE_ADD_REQUESTED:
// statisticStore.prepareForStatistics(rule);
// break;
// case RULE_REMOVE_REQUESTED:
// case RULE_REMOVED:
// statisticStore.removeFromStatistics(rule);
// break;
// }
}
}
......
......@@ -15,6 +15,7 @@ public class TestEventDispatcher extends DefaultEventSinkRegistry
implements EventDeliveryService {
@Override
@SuppressWarnings("unchecked")
public void post(Event event) {
EventSink sink = getSink(event.getClass());
checkState(sink != null, "No sink for event %s", event);
......
package org.onlab.onos.net.flow.impl;
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 java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
......@@ -65,6 +55,16 @@ 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;
/**
* Test codifying the flow rule service & flow rule provider service contracts.
*/
......@@ -176,6 +176,7 @@ 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);
......@@ -539,6 +540,7 @@ public class FlowRuleManagerTest {
}
@Override
@SuppressWarnings("unchecked")
public CompletedBatchOperation get()
throws InterruptedException, ExecutionException {
return new CompletedBatchOperation(true, EMPTY_LIST);
......
......@@ -35,6 +35,8 @@ public class InternalDeviceEventSerializer extends Serializer<InternalDeviceEven
Class<InternalDeviceEvent> type) {
ProviderId providerId = (ProviderId) kryo.readClassAndObject(input);
DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
@SuppressWarnings("unchecked")
Timestamped<DeviceDescription> deviceDescription
= (Timestamped<DeviceDescription>) kryo.readClassAndObject(input);
......
......@@ -37,6 +37,8 @@ public class InternalPortEventSerializer extends Serializer<InternalPortEvent> {
Class<InternalPortEvent> type) {
ProviderId providerId = (ProviderId) kryo.readClassAndObject(input);
DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
@SuppressWarnings("unchecked")
Timestamped<List<PortDescription>> portDescriptions
= (Timestamped<List<PortDescription>>) kryo.readClassAndObject(input);
......
......@@ -177,6 +177,7 @@ public class SimpleFlowRuleStore
public boolean deleteFlowRule(FlowRule rule) {
List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id());
synchronized (entries) {
for (StoredFlowEntry entry : entries) {
if (entry.equals(rule)) {
......
......@@ -82,12 +82,28 @@ public class SimpleIntentStore
public IntentEvent setState(Intent intent, IntentState state) {
IntentId id = intent.id();
states.put(id, state);
IntentEvent.Type type = (state == SUBMITTED ? IntentEvent.Type.SUBMITTED :
(state == INSTALLED ? IntentEvent.Type.INSTALLED :
(state == FAILED ? IntentEvent.Type.FAILED :
state == WITHDRAWN ? IntentEvent.Type.WITHDRAWN :
null)));
return type == null ? null : new IntentEvent(type, intent);
IntentEvent.Type type = null;
switch (state) {
case SUBMITTED:
type = IntentEvent.Type.SUBMITTED;
break;
case INSTALLED:
type = IntentEvent.Type.INSTALLED;
break;
case FAILED:
type = IntentEvent.Type.FAILED;
break;
case WITHDRAWN:
type = IntentEvent.Type.WITHDRAWN;
break;
default:
break;
}
if (type == null) {
return null;
}
return new IntentEvent(type, intent);
}
@Override
......
......@@ -110,8 +110,7 @@ public interface OpenFlowSwitch {
*
* @param role the failed role
*/
void returnRoleAssertFailure(RoleState role);
public void returnRoleAssertFailure(RoleState role);
/**
* Indicates if this switch is optical.
......@@ -120,5 +119,4 @@ public interface OpenFlowSwitch {
*/
public boolean isOptical();
}
......
......@@ -20,6 +20,12 @@ public interface OpenFlowSwitchListener {
public void switchRemoved(Dpid dpid);
/**
* Notify that the switch has changed in some way.
* @param dpid the switch that changed
*/
public void switchChanged(Dpid dpid);
/**
* Notify that a port has changed.
* @param dpid the switch on which the change happened.
* @param status the new state of the port.
......
......@@ -565,6 +565,9 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
@Override
void processOFStatisticsReply(OFChannelHandler h,
OFStatsReply m) {
if (m.getStatsType().equals(OFStatsType.PORT_DESC)) {
h.sw.setPortDescReply((OFPortDescStatsReply) m);
}
h.dispatchMessage(m);
}
......@@ -608,6 +611,12 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
h.dispatchMessage(m);
}
@Override
void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply m) {
h.sw.setFeaturesReply(m);
h.dispatchMessage(m);
}
};
private final boolean handshakeComplete;
......
......@@ -27,6 +27,8 @@ import org.onlab.onos.openflow.controller.driver.OpenFlowAgent;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -146,6 +148,11 @@ public class OpenFlowControllerImpl implements OpenFlowController {
l.portChanged(dpid, (OFPortStatus) msg);
}
break;
case FEATURES_REPLY:
for (OpenFlowSwitchListener l : ofSwitchListener) {
l.switchChanged(dpid);
}
break;
case PACKET_IN:
OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
.packetContextFromPacketIn(this.getSwitch(dpid),
......@@ -154,9 +161,15 @@ public class OpenFlowControllerImpl implements OpenFlowController {
p.handlePacket(pktCtx);
}
break;
case STATS_REPLY:
OFStatsReply reply = (OFStatsReply) msg;
if (reply.getStatsType().equals(OFStatsType.PORT_DESC)) {
for (OpenFlowSwitchListener l : ofSwitchListener) {
l.switchChanged(dpid);
}
}
case FLOW_REMOVED:
case ERROR:
case STATS_REPLY:
case BARRIER_REPLY:
executor.submit(new OFMessageHandler(dpid, msg));
break;
......
......@@ -344,7 +344,8 @@ public class LinkDiscovery implements TimerTask {
}
private void sendProbes(Long portNumber) {
if (mastershipService.getLocalRole(this.device.id()) ==
if (device.type() != Device.Type.ROADM &&
mastershipService.getLocalRole(this.device.id()) ==
MastershipRole.MASTER) {
OutboundPacket pkt = this.createOutBoundLLDP(portNumber);
pktService.emit(pkt);
......
......@@ -23,7 +23,9 @@ import org.onlab.onos.openflow.controller.OpenFlowController;
import org.onlab.onos.openflow.controller.OpenFlowSwitch;
import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
import org.onlab.onos.openflow.controller.RoleState;
import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriver;
import org.onlab.packet.ChassisId;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFPortConfig;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortState;
......@@ -89,6 +91,28 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
@Override
public void triggerProbe(Device device) {
LOG.info("Triggering probe on device {}", device.id());
// 1. check device liveness
// FIXME if possible, we might want this to be part of
// OpenFlowSwitch interface so the driver interface isn't misused.
OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri()));
if (!((OpenFlowSwitchDriver) sw).isConnected()) {
providerService.deviceDisconnected(device.id());
return;
}
// 2. Prompt an update of port information. Do we have an XID for this?
OFFactory fact = sw.factory();
switch (fact.getVersion()) {
case OF_10:
sw.sendMsg(fact.buildFeaturesRequest().setXid(0).build());
break;
case OF_13:
sw.sendMsg(fact.buildPortDescStatsRequest().setXid(0).build());
break;
default:
LOG.warn("Unhandled protocol version");
}
}
@Override
......@@ -141,6 +165,17 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
providerService.deviceDisconnected(deviceId(uri(dpid)));
}
@Override
public void switchChanged(Dpid dpid) {
if (providerService == null) {
return;
}
DeviceId did = deviceId(uri(dpid));
OpenFlowSwitch sw = controller.getSwitch(dpid);
providerService.updatePorts(did, buildPortDescriptions(sw.getPorts()));
}
@Override
public void portChanged(Dpid dpid, OFPortStatus status) {
PortDescription portDescription = buildPortDescription(status.getDesc());
......
......@@ -233,6 +233,10 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
}
@Override
public void switchChanged(Dpid dpid) {
}
@Override
public void portChanged(Dpid dpid, OFPortStatus status) {
//TODO: Decide whether to evict flows internal store.
}
......@@ -313,6 +317,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
}
return false;
}
}
private class InstallationFuture implements Future<CompletedBatchOperation> {
......
......@@ -118,6 +118,12 @@ public class OpenFlowLinkProvider extends AbstractProvider implements LinkProvid
DeviceId.deviceId("of:" + Long.toHexString(dpid.value())));
}
@Override
public void switchChanged(Dpid dpid) {
//might not need to do anything since DeviceManager is notified
}
@Override
public void portChanged(Dpid dpid, OFPortStatus status) {
LinkDiscovery ld = discoverers.get(dpid);
......
......@@ -6,6 +6,7 @@ import com.google.common.collect.MutableClassToInstanceMap;
/**
* Service directory implementation suitable for testing.
*/
@SuppressWarnings("unchecked")
public class TestServiceDirectory implements ServiceDirectory {
private ClassToInstanceMap<Object> services = MutableClassToInstanceMap.create();
......
......@@ -32,20 +32,20 @@
<div id="view"></div>
</div>
// Initialize the UI...
<!-- Initialize the UI...-->
<script type="text/javascript">
var ONOS = $.onos({note: "config, if needed"});
</script>
// include module files
// + mast.js
// + nav.js
// + .... application views
<!-- include module files-->
<!-- + mast.js-->
<!-- + nav.js-->
<!-- + .... application views-->
// for now, we are just bootstrapping the network visualization
<!-- for now, we are just bootstrapping the network visualization-->
<script src="network.js" type="text/javascript"></script>
// finally, build the UI
<!-- finally, build the UI-->
<script type="text/javascript">
$(ONOS.buildUi);
</script>
......
......@@ -100,7 +100,7 @@
network.data.nodes.forEach(function(n) {
var ypc = yPosConstraintForNode(n),
ix = Math.random() * 0.8 * nw + 0.1 * nw,
ix = Math.random() * 0.6 * nw + 0.2 * nw,
iy = ypc * nh,
node = {
id: n.id,
......@@ -152,11 +152,49 @@
.attr('width', view.width)
.attr('height', view.height)
.append('g')
.attr('transform', config.force.translate());
// .attr('id', 'zoomable')
.attr('transform', config.force.translate())
// .call(d3.behavior.zoom().on("zoom", zoomRedraw));
// function zoomRedraw() {
// d3.select("#zoomable").attr("transform",
// "translate(" + d3.event.translate + ")"
// + " scale(" + d3.event.scale + ")");
// }
// TODO: svg.append('defs') for markers?
// TODO: move glow/blur stuff to util script
var glow = network.svg.append('filter')
.attr('x', '-50%')
.attr('y', '-50%')
.attr('width', '200%')
.attr('height', '200%')
.attr('id', 'blue-glow');
glow.append('feColorMatrix')
.attr('type', 'matrix')
.attr('values', '0 0 0 0 0 ' +
'0 0 0 0 0 ' +
'0 0 0 0 .7 ' +
'0 0 0 1 0 ');
glow.append('feGaussianBlur')
.attr('stdDeviation', 3)
.attr('result', 'coloredBlur');
glow.append('feMerge').selectAll('feMergeNode')
.data(['coloredBlur', 'SourceGraphic'])
.enter().append('feMergeNode')
.attr('in', String);
// TODO: svg.append('defs')
// TODO: glow/blur stuff
// TODO: legend (and auto adjust on scroll)
// $('#view').on('scroll', function() {
//
// });
network.link = network.svg.append('g').selectAll('.link')
.data(network.force.links(), function(d) {return d.id})
......@@ -164,27 +202,90 @@
.attr('class', 'link');
// TODO: drag behavior
// TODO: closest node deselect
network.draggedThreshold = d3.scale.linear()
.domain([0, 0.1])
.range([5, 20])
.clamp(true);
function dragged(d) {
var threshold = network.draggedThreshold(network.force.alpha()),
dx = d.oldX - d.px,
dy = d.oldY - d.py;
if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
d.dragged = true;
}
return d.dragged;
}
network.drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on('dragstart', function(d) {
d.oldX = d.x;
d.oldY = d.y;
d.dragged = false;
d.fixed |= 2;
})
.on('drag', function(d) {
d.px = d3.event.x;
d.py = d3.event.y;
if (dragged(d)) {
if (!network.force.alpha()) {
network.force.alpha(.025);
}
}
})
.on('dragend', function(d) {
if (!dragged(d)) {
selectObject(d, this);
}
d.fixed &= ~6;
});
$('#view').on('click', function(e) {
if (!$(e.target).closest('.node').length) {
deselectObject();
}
});
// TODO: add drag, mouseover, mouseout behaviors
network.node = network.svg.selectAll('.node')
.data(network.force.nodes(), function(d) {return d.id})
.enter().append('g')
.attr('class', 'node')
.attr('class', function(d) {
return 'node ' + d.type;
})
.attr('transform', function(d) {
return translate(d.x, d.y);
})
// .call(network.drag)
.on('mouseover', function(d) {})
.on('mouseout', function(d) {});
.call(network.drag)
.on('mouseover', function(d) {
if (!selected.obj) {
if (network.mouseoutTimeout) {
clearTimeout(network.mouseoutTimeout);
network.mouseoutTimeout = null;
}
highlightObject(d);
}
})
.on('mouseout', function(d) {
if (!selected.obj) {
if (network.mouseoutTimeout) {
clearTimeout(network.mouseoutTimeout);
network.mouseoutTimeout = null;
}
network.mouseoutTimeout = setTimeout(function() {
highlightObject(null);
}, 160);
}
});
// TODO: augment stroke and fill functions
network.nodeRect = network.node.append('rect')
// TODO: css for node rects
.attr('rx', 5)
.attr('ry', 5)
.attr('stroke', function(d) { return '#000'})
.attr('fill', function(d) { return '#ddf'})
// .attr('stroke', function(d) { return '#000'})
// .attr('fill', function(d) { return '#ddf'})
.attr('width', 60)
.attr('height', 24);
......
......@@ -13,7 +13,7 @@ body, html {
*/
span.title {
color: red;
color: darkblue;
font-size: 16pt;
font-style: italic;
}
......@@ -30,7 +30,7 @@ span.right {
* === DEBUGGING ======
*/
svg {
border: 1px dashed red;
/*border: 1px dashed red;*/
}
......@@ -64,36 +64,45 @@ marker#end {
-moz-transition: opacity 250ms;
}
.node text {
fill: #000;
/*differentiate between packet and optical nodes*/
svg .node.pkt rect {
fill: #77a;
}
svg .node.opt rect {
fill: #7a7;
}
svg .node text {
fill: white;
font: 10px sans-serif;
pointer-events: none;
}
.node.selected rect {
svg .node.selected rect {
filter: url(#blue-glow);
}
.link.inactive,
.node.inactive rect,
.node.inactive text {
svg .link.inactive,
svg .node.inactive rect,
svg .node.inactive text {
opacity: .2;
}
.node.inactive.selected rect,
.node.inactive.selected text {
svg .node.inactive.selected rect,
svg .node.inactive.selected text {
opacity: .6;
}
.legend {
svg .legend {
position: fixed;
}
.legend .category rect {
svg .legend .category rect {
stroke-width: 1px;
}
.legend .category text {
svg .legend .category text {
fill: #000;
font: 10px sans-serif;
pointer-events: none;
......@@ -110,15 +119,15 @@ marker#end {
#frame {
width: 100%;
height: 100%;
background-color: #ffd;
background-color: #cdf;
}
#mast {
height: 32px;
background-color: #dda;
background-color: #abe;
vertical-align: baseline;
}
#main {
background-color: #99b;
background-color: #99c;
}
......