alshabib

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

Showing 61 changed files with 1772 additions and 401 deletions
......@@ -15,18 +15,29 @@
*/
package org.onlab.onos.calendar;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.rest.BaseResource;
import java.net.URI;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
import java.net.URI;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.core.CoreService;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import org.onlab.packet.Ethernet;
import org.onlab.rest.BaseResource;
import static org.onlab.onos.net.PortNumber.portNumber;
import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
/**
* Web resource for triggering calendared intents.
......@@ -47,12 +58,33 @@ public class BandwidthCalendarResource extends BaseResource {
ConnectPoint srcPoint = new ConnectPoint(deviceId(src), portNumber(srcPort));
ConnectPoint dstPoint = new ConnectPoint(deviceId(dst), portNumber(dstPort));
TrafficSelector selector = buildTrafficSelector();
TrafficTreatment treatment = builder().build();
Intent intent = new PointToPointIntentWithBandwidthConstraint(
appId(), selector, treatment,
srcPoint, dstPoint, new BandwidthResourceRequest(Double.parseDouble(bandwidth)));
service.submit(intent);
return Response.ok("Yo! We got src=" + srcPoint + "; dst=" + dstPoint +
"; bw=" + bandwidth + "; intent service " + service).build();
}
private TrafficSelector buildTrafficSelector() {
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
Short ethType = Ethernet.TYPE_IPV4;
selectorBuilder.matchEthType(ethType);
return selectorBuilder.build();
}
private DeviceId deviceId(String dpid) {
return DeviceId.deviceId(URI.create("of:" + dpid));
}
protected ApplicationId appId() {
return get(CoreService.class).registerApplication("org.onlab.onos.calendar");
}
}
......
......@@ -76,7 +76,7 @@
"nodeName1": "ROUTER1",
"nodeName2": "ROADM1",
"bandWidth": 100000,
"port1": 1,
"port1": 2,
"port2": 10
},
"type": "pktOptLink"
......@@ -90,7 +90,7 @@
"nodeName1": "ROUTER2",
"nodeName2": "ROADM2",
"bandWidth": 100000,
"port1": 1,
"port1": 2,
"port2": 11
},
"type": "pktOptLink"
......
/*
* 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 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.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
/**
* Installs point-to-point connectivity intents.
*/
@Command(scope = "onos", name = "add-point-intent-bw",
description = "Installs point-to-point connectivity intent with bandwidth constraint")
public class AddPointToPointIntentWithBandwidthConstraintCommand 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;
@Argument(index = 2, name = "bandwidth",
description = "Bandwidth",
required = true, multiValued = false)
String bandwidthString = 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);
long bandwidth = Long.parseLong(bandwidthString);
TrafficSelector selector = buildTrafficSelector();
TrafficTreatment treatment = builder().build();
Intent intent = new PointToPointIntentWithBandwidthConstraint(
appId(), selector, treatment,
ingress, egress, new BandwidthResourceRequest(bandwidth));
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);
}
}
......@@ -47,8 +47,8 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
*/
protected TrafficSelector buildTrafficSelector() {
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
Short ethType = Ethernet.TYPE_IPV4;
if (!Strings.isNullOrEmpty(ethTypeString)) {
EthType ethTypeParameter = EthType.valueOf(ethTypeString);
ethType = ethTypeParameter.value();
......
......@@ -40,7 +40,7 @@ import static org.onlab.onos.net.DeviceId.deviceId;
description = "Lists all ports or all ports of a device")
public class DevicePortsListCommand extends DevicesListCommand {
private static final String FMT = " port=%s, state=%s%s";
private static final String FMT = " port=%s, state=%s, type=%s, speed=%s%s";
@Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports",
required = false, multiValued = false)
......@@ -110,10 +110,14 @@ public class DevicePortsListCommand extends DevicesListCommand {
ports.add(mapper.createObjectNode()
.put("port", port.number().toString())
.put("isEnabled", port.isEnabled())
.put("type", port.type().toString().toLowerCase())
.put("portSpeed", port.portSpeed())
.set("annotations", annotations(mapper, port.annotations())));
}
}
return result.put("device", device.id().toString()).set("ports", ports);
result.set("device", json(service, mapper, device));
result.set("ports", ports);
return result;
}
// Determines if a port should be included in output.
......@@ -130,6 +134,7 @@ public class DevicePortsListCommand extends DevicesListCommand {
for (Port port : ports) {
if (isIncluded(port)) {
print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled",
port.type().toString().toLowerCase(), port.portSpeed(),
annotations(port.annotations()));
}
}
......
......@@ -116,6 +116,17 @@
</optional-completers>
</command>
<command>
<action class="org.onlab.onos.cli.net.AddPointToPointIntentWithBandwidthConstraintCommand"/>
<completers>
<ref component-id="connectPointCompleter"/>
<ref component-id="connectPointCompleter"/>
<null/>
</completers>
<optional-completers>
<entry key="-t" value-ref="ethTypeCompleter"/>
</optional-completers>
</command>
<command>
<action class="org.onlab.onos.cli.net.AddOpticalIntentCommand"/>
<completers>
<ref component-id="connectPointCompleter"/>
......
......@@ -35,6 +35,11 @@ public class RoleInfo {
this.backups = ImmutableList.copyOf(backups);
}
public RoleInfo() {
this.master = null;
this.backups = ImmutableList.of();
}
public NodeId master() {
return master;
}
......@@ -63,7 +68,7 @@ public class RoleInfo {
@Override
public int hashCode() {
return Objects.hash(master, backups.hashCode());
return Objects.hash(master, backups);
}
@Override
......
......@@ -24,9 +24,27 @@ import static com.google.common.base.MoreObjects.toStringHelper;
*/
public class DefaultPort extends AbstractAnnotated implements Port {
/** Default port speed in Mbps. */
public static final long DEFAULT_SPEED = 1_000;
private final Element element;
private final PortNumber number;
private final boolean isEnabled;
private final Type type;
private final long portSpeed;
/**
* Creates a network element attributed to the specified provider.
*
* @param element parent network element
* @param number port number
* @param isEnabled indicator whether the port is up and active
* @param annotations optional key/value annotations
*/
public DefaultPort(Element element, PortNumber number, boolean isEnabled,
Annotations... annotations) {
this(element, number, isEnabled, Type.COPPER, DEFAULT_SPEED, annotations);
}
/**
* Creates a network element attributed to the specified provider.
......@@ -34,19 +52,49 @@ public class DefaultPort extends AbstractAnnotated implements Port {
* @param element parent network element
* @param number port number
* @param isEnabled indicator whether the port is up and active
* @param type port type
* @param portSpeed port speed in Mbs
* @param annotations optional key/value annotations
*/
public DefaultPort(Element element, PortNumber number,
boolean isEnabled, Annotations... annotations) {
public DefaultPort(Element element, PortNumber number, boolean isEnabled,
Type type, long portSpeed, Annotations... annotations) {
super(annotations);
this.element = element;
this.number = number;
this.isEnabled = isEnabled;
this.type = type;
this.portSpeed = portSpeed;
}
@Override
public Element element() {
return element;
}
@Override
public PortNumber number() {
return number;
}
@Override
public boolean isEnabled() {
return isEnabled;
}
@Override
public Type type() {
return type;
}
@Override
public long portSpeed() {
return portSpeed;
}
@Override
public int hashCode() {
return Objects.hash(number, isEnabled);
return Objects.hash(number, isEnabled, type, portSpeed);
}
@Override
......@@ -58,7 +106,9 @@ public class DefaultPort extends AbstractAnnotated implements Port {
final DefaultPort other = (DefaultPort) obj;
return Objects.equals(this.element.id(), other.element.id()) &&
Objects.equals(this.number, other.number) &&
Objects.equals(this.isEnabled, other.isEnabled);
Objects.equals(this.isEnabled, other.isEnabled) &&
Objects.equals(this.type, other.type) &&
Objects.equals(this.portSpeed, other.portSpeed);
}
return false;
}
......@@ -69,22 +119,9 @@ public class DefaultPort extends AbstractAnnotated implements Port {
.add("element", element.id())
.add("number", number)
.add("isEnabled", isEnabled)
.add("type", type)
.add("portSpeed", portSpeed)
.toString();
}
@Override
public PortNumber number() {
return number;
}
@Override
public boolean isEnabled() {
return isEnabled;
}
@Override
public Element element() {
return element;
}
}
......
......@@ -21,6 +21,26 @@ package org.onlab.onos.net;
*/
public interface Port extends Annotated {
/** Represents coarse port type classification. */
public enum Type {
/**
* Signifies copper-based connectivity.
*/
COPPER,
/**
* Signifies optical fiber-based connectivity.
*/
FIBER
}
/**
* Returns the parent network element to which this port belongs.
*
* @return parent network element
*/
Element element();
/**
* Returns the port number.
*
......@@ -36,12 +56,18 @@ public interface Port extends Annotated {
boolean isEnabled();
/**
* Returns the parent network element to which this port belongs.
* Returns the port type.
*
* @return parent network element
* @return port type
*/
Element element();
Type type();
// set of port attributes
/**
* Returns the current port speed in Mbps.
*
* @return current port speed
*/
long portSpeed();
// TODO: more attributes?
}
......
......@@ -15,11 +15,12 @@
*/
package org.onlab.onos.net.device;
import com.google.common.base.MoreObjects;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.SparseAnnotations;
import com.google.common.base.MoreObjects;
import static org.onlab.onos.net.Port.Type;
/**
* Default implementation of immutable port description.
......@@ -27,32 +28,62 @@ import com.google.common.base.MoreObjects;
public class DefaultPortDescription extends AbstractDescription
implements PortDescription {
private static final long DEFAULT_SPEED = 1_000;
private final PortNumber number;
private final boolean isEnabled;
private final Type type;
private final long portSpeed;
/**
* Creates a port description using the supplied information.
*
* @param number port number
* @param isEnabled port enabled state
* @param annotations optional key/value annotations map
* @param number port number
* @param isEnabled port enabled state
* @param annotations optional key/value annotations map
*/
public DefaultPortDescription(PortNumber number, boolean isEnabled,
SparseAnnotations... annotations) {
SparseAnnotations... annotations) {
this(number, isEnabled, Type.COPPER, DEFAULT_SPEED, annotations);
}
/**
* Creates a port description using the supplied information.
*
* @param number port number
* @param isEnabled port enabled state
* @param type port type
* @param portSpeed port speed in Mbps
* @param annotations optional key/value annotations map
*/
public DefaultPortDescription(PortNumber number, boolean isEnabled,
Type type, long portSpeed,
SparseAnnotations...annotations) {
super(annotations);
this.number = number;
this.isEnabled = isEnabled;
this.type = type;
this.portSpeed = portSpeed;
}
// Default constructor for serialization
private DefaultPortDescription() {
this.number = null;
this.isEnabled = false;
this.portSpeed = DEFAULT_SPEED;
this.type = Type.COPPER;
}
/**
* Creates a port description using the supplied information.
*
* @param base PortDescription to get basic information from
* @param annotations optional key/value annotations map
* @param base PortDescription to get basic information from
* @param annotations optional key/value annotations map
*/
public DefaultPortDescription(PortDescription base,
SparseAnnotations annotations) {
this(base.portNumber(), base.isEnabled(), annotations);
SparseAnnotations annotations) {
this(base.portNumber(), base.isEnabled(), base.type(), base.portSpeed(),
annotations);
}
@Override
......@@ -66,17 +97,24 @@ public class DefaultPortDescription extends AbstractDescription
}
@Override
public Type type() {
return type;
}
@Override
public long portSpeed() {
return portSpeed;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("number", number)
.add("isEnabled", isEnabled)
.add("type", type)
.add("portSpeed", portSpeed)
.add("annotations", annotations())
.toString();
}
// default constructor for serialization
private DefaultPortDescription() {
this.number = null;
this.isEnabled = false;
}
}
......
......@@ -18,13 +18,13 @@ package org.onlab.onos.net.device;
import org.onlab.onos.net.Description;
import org.onlab.onos.net.PortNumber;
import static org.onlab.onos.net.Port.Type;
/**
* Information about a port.
*/
public interface PortDescription extends Description {
// TODO: possibly relocate this to a common ground so that this can also used by host tracking if required
/**
* Returns the port number.
*
......@@ -39,4 +39,18 @@ public interface PortDescription extends Description {
*/
boolean isEnabled();
/**
* Returns the port type.
*
* @return port type
*/
Type type();
/**
* Returns the current port speed in Mbps.
*
* @return current port speed
*/
long portSpeed();
}
......
......@@ -20,6 +20,7 @@ import org.onlab.onos.core.ApplicationId;
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.resource.LinkResourceRequest;
/**
* Abstraction of explicitly path specified connectivity intent.
......@@ -27,6 +28,7 @@ import org.onlab.onos.net.flow.TrafficTreatment;
public class PathIntent extends ConnectivityIntent {
private final Path path;
private final LinkResourceRequest[] resourceRequests;
/**
* Creates a new point-to-point intent with the supplied ingress/egress
......@@ -39,10 +41,11 @@ public class PathIntent extends ConnectivityIntent {
* @throws NullPointerException {@code path} is null
*/
public PathIntent(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment, Path path) {
TrafficTreatment treatment, Path path, LinkResourceRequest[] resourceRequests) {
super(id(PathIntent.class, selector, treatment, path), appId,
resources(path.links()), selector, treatment);
this.path = path;
this.resourceRequests = resourceRequests;
}
/**
......@@ -51,6 +54,7 @@ public class PathIntent extends ConnectivityIntent {
protected PathIntent() {
super();
this.path = null;
this.resourceRequests = new LinkResourceRequest[0];
}
/**
......@@ -67,6 +71,10 @@ public class PathIntent extends ConnectivityIntent {
return true;
}
public LinkResourceRequest[] resourceRequests() {
return resourceRequests;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
......
/*
* 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.net.intent;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import com.google.common.base.MoreObjects;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Abstraction of point-to-point connectivity.
*/
public class PointToPointIntentWithBandwidthConstraint extends ConnectivityIntent {
private final ConnectPoint ingressPoint;
private final ConnectPoint egressPoint;
private final BandwidthResourceRequest bandwidthResourceRequest;
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports.
*
* @param appId application identifier
* @param selector traffic selector
* @param treatment treatment
* @param ingressPoint ingress port
* @param egressPoint egress port
* @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
*/
public PointToPointIntentWithBandwidthConstraint(ApplicationId appId, TrafficSelector selector,
TrafficTreatment treatment,
ConnectPoint ingressPoint,
ConnectPoint egressPoint,
BandwidthResourceRequest bandwidthResourceRequest) {
super(id(PointToPointIntentWithBandwidthConstraint.class, selector,
treatment, ingressPoint, egressPoint, bandwidthResourceRequest.bandwidth()),
appId, null, selector, treatment);
this.ingressPoint = checkNotNull(ingressPoint);
this.egressPoint = checkNotNull(egressPoint);
this.bandwidthResourceRequest = bandwidthResourceRequest;
}
/**
* Constructor for serializer.
*/
protected PointToPointIntentWithBandwidthConstraint() {
super();
this.ingressPoint = null;
this.egressPoint = null;
bandwidthResourceRequest = new BandwidthResourceRequest(0.0);
}
/**
* Returns the port on which the ingress traffic should be connected to
* the egress.
*
* @return ingress port
*/
public ConnectPoint ingressPoint() {
return ingressPoint;
}
/**
* Returns the port on which the traffic should egress.
*
* @return egress port
*/
public ConnectPoint egressPoint() {
return egressPoint;
}
public BandwidthResourceRequest bandwidthRequest() {
return this.bandwidthResourceRequest;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", id())
.add("appId", appId())
.add("selector", selector())
.add("treatment", treatment())
.add("ingress", ingressPoint)
.add("egress", egressPoint)
.add("bandwidth", bandwidthResourceRequest.bandwidth().toString())
.toString();
}
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed 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.net.resource;
import java.util.Set;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
/**
* Manages link resources.
*/
public interface LinkResourceStore {
Set<ResourceAllocation> getFreeResources(Link link);
void allocateResources(LinkResourceAllocations allocations);
void releaseResources(LinkResourceAllocations allocations);
LinkResourceAllocations getAllocations(IntentId intentId);
Iterable<LinkResourceAllocations> getAllocations(Link link);
Iterable<LinkResourceAllocations> getAllocations();
}
......@@ -23,6 +23,8 @@ import org.onlab.packet.ChassisId;
import static org.junit.Assert.assertEquals;
import static org.onlab.onos.net.Device.Type.SWITCH;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.Port.Type.COPPER;
import static org.onlab.onos.net.Port.Type.FIBER;
import static org.onlab.onos.net.PortNumber.portNumber;
/**
......@@ -35,15 +37,16 @@ public class DefaultPortTest {
private static final DeviceId DID2 = deviceId("of:bar");
private static final PortNumber P1 = portNumber(1);
private static final PortNumber P2 = portNumber(2);
private static final long SP1 = 1_000_000;
@Test
public void testEquality() {
Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n",
new ChassisId());
Port p1 = new DefaultPort(device, portNumber(1), true);
Port p2 = new DefaultPort(device, portNumber(1), true);
Port p3 = new DefaultPort(device, portNumber(2), true);
Port p4 = new DefaultPort(device, portNumber(2), true);
Port p1 = new DefaultPort(device, portNumber(1), true, COPPER, SP1);
Port p2 = new DefaultPort(device, portNumber(1), true, COPPER, SP1);
Port p3 = new DefaultPort(device, portNumber(2), true, FIBER, SP1);
Port p4 = new DefaultPort(device, portNumber(2), true, FIBER, SP1);
Port p5 = new DefaultPort(device, portNumber(1), false);
new EqualsTester().addEqualityGroup(p1, p2)
......@@ -56,10 +59,12 @@ public class DefaultPortTest {
public void basics() {
Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n",
new ChassisId());
Port port = new DefaultPort(device, portNumber(1), true);
Port port = new DefaultPort(device, portNumber(1), true, FIBER, SP1);
assertEquals("incorrect element", device, port.element());
assertEquals("incorrect number", portNumber(1), port.number());
assertEquals("incorrect state", true, port.isEnabled());
assertEquals("incorrect speed", SP1, port.portSpeed());
assertEquals("incorrect type", FIBER, port.type());
}
}
......
......@@ -15,11 +15,12 @@
*/
package org.onlab.onos.net.intent;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.onlab.onos.net.NetTestTools;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.resource.LinkResourceRequest;
import static org.junit.Assert.assertEquals;
public class PathIntentTest extends ConnectivityIntentTest {
// 111:11 --> 222:22
......@@ -39,11 +40,11 @@ public class PathIntentTest extends ConnectivityIntentTest {
@Override
protected PathIntent createOne() {
return new PathIntent(APPID, MATCH, NOP, PATH1);
return new PathIntent(APPID, MATCH, NOP, PATH1, new LinkResourceRequest[0]);
}
@Override
protected PathIntent createAnother() {
return new PathIntent(APPID, MATCH, NOP, PATH2);
return new PathIntent(APPID, MATCH, NOP, PATH2, new LinkResourceRequest[0]);
}
}
......
......@@ -67,8 +67,8 @@ import com.google.common.collect.HashMultimap;
@Component(immediate = true)
@Service
public class DeviceManager
extends AbstractProviderRegistry<DeviceProvider, DeviceProviderService>
implements DeviceService, DeviceAdminService, DeviceProviderRegistry {
extends AbstractProviderRegistry<DeviceProvider, DeviceProviderService>
implements DeviceService, DeviceAdminService, DeviceProviderRegistry {
private static final String DEVICE_ID_NULL = "Device ID cannot be null";
private static final String PORT_NUMBER_NULL = "Port number cannot be null";
......@@ -227,8 +227,8 @@ public class DeviceManager
// Personalized device provider service issued to the supplied provider.
private class InternalDeviceProviderService
extends AbstractProviderService<DeviceProvider>
implements DeviceProviderService {
extends AbstractProviderService<DeviceProvider>
implements DeviceProviderService {
InternalDeviceProviderService(DeviceProvider provider) {
super(provider);
......@@ -236,7 +236,7 @@ public class DeviceManager
@Override
public void deviceConnected(DeviceId deviceId,
DeviceDescription deviceDescription) {
DeviceDescription deviceDescription) {
checkNotNull(deviceId, DEVICE_ID_NULL);
checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL);
checkValidity();
......@@ -267,7 +267,7 @@ public class DeviceManager
deviceClockProviderService.setMastershipTerm(deviceId, term);
DeviceEvent event = store.createOrUpdateDevice(provider().id(),
deviceId, deviceDescription);
deviceId, deviceDescription);
// If there was a change of any kind, tell the provider
// that this instance is the master.
......@@ -337,14 +337,14 @@ public class DeviceManager
@Override
public void updatePorts(DeviceId deviceId,
List<PortDescription> portDescriptions) {
List<PortDescription> portDescriptions) {
checkNotNull(deviceId, DEVICE_ID_NULL);
checkNotNull(portDescriptions,
"Port descriptions list cannot be null");
"Port descriptions list cannot be null");
checkValidity();
List<DeviceEvent> events = store.updatePorts(this.provider().id(),
deviceId, portDescriptions);
deviceId, portDescriptions);
for (DeviceEvent event : events) {
post(event);
}
......@@ -352,13 +352,13 @@ public class DeviceManager
@Override
public void portStatusChanged(DeviceId deviceId,
PortDescription portDescription) {
PortDescription portDescription) {
checkNotNull(deviceId, DEVICE_ID_NULL);
checkNotNull(portDescription, PORT_DESCRIPTION_NULL);
checkValidity();
final DeviceEvent event = store.updatePortStatus(this.provider().id(),
deviceId, portDescription);
deviceId, portDescription);
if (event != null) {
log.info("Device {} port {} status changed", deviceId, event
.port().number());
......@@ -370,7 +370,7 @@ public class DeviceManager
public void unableToAssertRole(DeviceId deviceId, MastershipRole role) {
// FIXME: implement response to this notification
log.warn("Failed to assert role [{}] onto Device {}", role,
deviceId);
deviceId);
if (role == MastershipRole.MASTER) {
mastershipService.relinquishMastership(deviceId);
// TODO: Shouldn't we be triggering event?
......@@ -393,7 +393,7 @@ public class DeviceManager
// random cache size
private final int cacheSize = 5;
// temporarily stores term number + events to check for duplicates. A hack.
private HashMultimap<Integer, RoleInfo> eventCache =
private HashMultimap<Integer, RoleInfo> eventCache =
HashMultimap.create();
@Override
......@@ -407,14 +407,14 @@ public class DeviceManager
// TODO duplicate suppression should probably occur in the MastershipManager
// itself, so listeners that can't deal with duplicates don't have to
// so this check themselves.
if (checkDuplicate(event.roleInfo(), term.termNumber())) {
return;
}
// if (checkDuplicate(event.roleInfo(), term.termNumber())) {
// return;
// }
if (!myNodeId.equals(term.master())) {
// something went wrong in consistency, let go
log.warn("Mastership has changed after this event."
+ "Term Service suggests {} for {}", term, did);
+ "Term Service suggests {} for {}", term, did);
// FIXME: Is it possible to let go of MASTER role
// but remain on STANDBY list?
mastershipService.relinquishMastership(did);
......@@ -435,11 +435,12 @@ public class DeviceManager
return;
}
//flag the device as online. Is there a better way to do this?
DeviceEvent devEvent = store.createOrUpdateDevice(device.providerId(), did,
new DefaultDeviceDescription(
did.uri(), device.type(), device.manufacturer(),
device.hwVersion(), device.swVersion(),
device.serialNumber(), device.chassisId()));
DeviceEvent devEvent =
store.createOrUpdateDevice(device.providerId(), did,
new DefaultDeviceDescription(
did.uri(), device.type(), device.manufacturer(),
device.hwVersion(), device.swVersion(),
device.serialNumber(), device.chassisId()));
post(devEvent);
}
applyRole(did, MastershipRole.MASTER);
......@@ -476,7 +477,7 @@ public class DeviceManager
// Store delegate to re-post events emitted from the store.
private class InternalStoreDelegate
implements DeviceStoreDelegate {
implements DeviceStoreDelegate {
@Override
public void notify(DeviceEvent event) {
post(event);
......
......@@ -15,6 +15,10 @@
*/
package org.onlab.onos.net.intent.impl;
import java.util.Arrays;
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;
......@@ -32,13 +36,10 @@ import org.onlab.onos.net.intent.IntentCompiler;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.topology.PathService;
import org.onlab.onos.net.topology.TopologyEdge;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder;
/**
......@@ -85,7 +86,7 @@ public class HostToHostIntentCompiler
TrafficSelector selector = builder(intent.selector())
.matchEthSrc(src.mac()).matchEthDst(dst.mac()).build();
return new PathIntent(intent.appId(), selector, intent.treatment(),
path);
path, new LinkResourceRequest[0]);
}
private Path getPath(HostId one, HostId two) {
......
......@@ -15,9 +15,6 @@
*/
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.Iterator;
import java.util.List;
......@@ -41,10 +38,15 @@ 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.PathIntent;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceService;
import org.slf4j.Logger;
import com.google.common.collect.Lists;
import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Installer for {@link PathIntent packet path connectivity intents}.
*/
......@@ -59,6 +61,9 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
private ApplicationId appId;
@Activate
......@@ -74,6 +79,14 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
@Override
public List<FlowRuleBatchOperation> install(PathIntent intent) {
if (intent.resourceRequests().length > 0) {
LinkResourceAllocations allocations = allocateBandwidth(intent);
if (allocations == null) {
log.debug("Insufficient bandwidth available to install path intent {}", intent);
return null;
}
}
TrafficSelector.Builder builder =
DefaultTrafficSelector.builder(intent.selector());
Iterator<Link> links = intent.path().links().iterator();
......@@ -117,6 +130,10 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
private LinkResourceAllocations allocateBandwidth(PathIntent intent) {
return resourceService.requestResources(intent.resourceRequests()[0]);
}
// TODO refactor below this line... ----------------------------
/**
......
......@@ -15,6 +15,10 @@
*/
package org.onlab.onos.net.intent.impl;
import java.util.ArrayList;
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;
......@@ -31,15 +35,12 @@ import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.resource.LinkResourceRequest;
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 java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static java.util.Arrays.asList;
/**
......@@ -76,7 +77,7 @@ public class PointToPointIntentCompiler
links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false));
return asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2,
path.annotations()), intent));
path.annotations()), intent));
}
/**
......@@ -89,7 +90,8 @@ public class PointToPointIntentCompiler
private Intent createPathIntent(Path path,
PointToPointIntent intent) {
return new PathIntent(intent.appId(),
intent.selector(), intent.treatment(), path);
intent.selector(), intent.treatment(), path,
new LinkResourceRequest[0]);
}
/**
......
package org.onlab.onos.net.intent.impl;
import java.util.ArrayList;
import java.util.Arrays;
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.net.ConnectPoint;
import org.onlab.onos.net.DefaultEdgeLink;
import org.onlab.onos.net.DefaultPath;
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.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import org.onlab.onos.net.resource.DefaultLinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceRequest;
import org.onlab.onos.net.resource.ResourceType;
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;
/**
* A intent compiler for {@link org.onlab.onos.net.intent.HostToHostIntent}.
*/
@Component(immediate = true)
public class PointToPointIntentWithBandwidthConstraintCompiler
implements IntentCompiler<PointToPointIntentWithBandwidthConstraint> {
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 TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
@Activate
public void activate() {
intentManager.registerCompiler(PointToPointIntentWithBandwidthConstraint.class, this);
}
@Deactivate
public void deactivate() {
intentManager.unregisterCompiler(PointToPointIntent.class);
}
@Override
public List<Intent> compile(PointToPointIntentWithBandwidthConstraint intent) {
Path path = getPath(intent.ingressPoint(), intent.egressPoint(), intent.bandwidthRequest());
List<Link> links = new ArrayList<>();
links.add(DefaultEdgeLink.createEdgeLink(intent.ingressPoint(), true));
links.addAll(path.links());
links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false));
return Arrays.asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2,
path.annotations()),
intent));
}
/**
* Creates a path intent from the specified path and original
* connectivity intent.
*
* @param path path to create an intent for
* @param intent original intent
*/
private Intent createPathIntent(Path path,
PointToPointIntentWithBandwidthConstraint intent) {
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
path.links())
// TODO - this seems awkward, maybe allow directly attaching a BandwidthRequest
.addBandwidthRequest(intent.bandwidthRequest().bandwidth().toDouble());
LinkResourceRequest bandwidthRequest = request.build();
LinkResourceRequest[] bandwidthRequests = {bandwidthRequest};
return new PathIntent(intent.appId(),
intent.selector(), intent.treatment(), path,
bandwidthRequests);
}
/**
* Computes a path between two ConnectPoints.
*
* @param one start of the path
* @param two end of the path
* @return Path between the two
* @throws org.onlab.onos.net.intent.impl.PathNotFoundException if a path cannot be found
*/
private Path getPath(ConnectPoint one, ConnectPoint two, final BandwidthResourceRequest bandwidthRequest) {
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
public double weight(TopologyEdge edge) {
if (bandwidthRequest != null) {
double allocatedBandwidth = 0.0;
Iterable<ResourceRequest> availableResources = resourceService.getAvailableResources(edge.link());
for (ResourceRequest availableResource : availableResources) {
if (availableResource.type() == ResourceType.BANDWIDTH) {
BandwidthResourceRequest bandwidthRequest = (BandwidthResourceRequest) availableResource;
allocatedBandwidth += bandwidthRequest.bandwidth().toDouble();
}
}
// TODO this needs to be discovered from switch/ports somehow
double maxBandwidth = 1000;
double availableBandwidth = maxBandwidth - allocatedBandwidth;
if (availableBandwidth >= bandwidthRequest.bandwidth().toDouble()) {
return 1;
} else {
return -1;
}
} else {
return 1;
}
}
};
Set<Path> paths = topologyService.getPaths(topology,
one.deviceId(),
two.deviceId(),
weight);
if (paths.isEmpty()) {
throw new PathNotFoundException("No packet path from " + one + " to " + two);
}
// TODO: let's be more intelligent about this eventually
return paths.iterator().next();
}
}
......@@ -15,9 +15,13 @@
*/
package org.onlab.onos.net.resource.impl;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
......@@ -25,6 +29,8 @@ 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.apache.felix.scr.annotations.Service;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
......@@ -32,15 +38,16 @@ 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.LambdaResourceRequest;
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.LinkResourceStore;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceRequest;
import org.onlab.onos.net.resource.ResourceType;
import org.slf4j.Logger;
import com.google.common.collect.Sets;
/**
* Provides basic implementation of link resources allocation.
*/
......@@ -50,6 +57,9 @@ public class LinkResourceManager implements LinkResourceService {
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private LinkResourceStore store;
@Activate
public void activate() {
log.info("Started");
......@@ -60,27 +70,65 @@ public class LinkResourceManager implements LinkResourceService {
log.info("Stopped");
}
/**
* Returns available lambdas on specified link.
*
* @param link the link
* @return available lambdas on specified link
*/
private Set<Lambda> getAvailableLambdas(Link link) {
checkNotNull(link);
Set<ResourceAllocation> resAllocs = store.getFreeResources(link);
if (resAllocs == null) {
return Collections.emptySet();
}
Set<Lambda> lambdas = new HashSet<>();
for (ResourceAllocation res : resAllocs) {
if (res.type() == ResourceType.LAMBDA) {
lambdas.add(((LambdaResourceAllocation) res).lambda());
}
}
return lambdas;
}
/**
* Returns available lambdas on specified links.
*
* @param links the links
* @return available lambdas on specified links
*/
private Iterable<Lambda> getAvailableLambdas(Iterable<Link> links) {
return Sets.newHashSet(Lambda.valueOf(7));
checkNotNull(links);
Iterator<Link> i = links.iterator();
checkArgument(i.hasNext());
Set<Lambda> lambdas = new HashSet<>(getAvailableLambdas(i.next()));
while (i.hasNext()) {
lambdas.retainAll(getAvailableLambdas(i.next()));
}
return lambdas;
}
@Override
public LinkResourceAllocations requestResources(LinkResourceRequest req) {
// TODO implement it using a resource data store.
// TODO Concatenate multiple bandwidth requests.
// TODO Support multiple lambda resource requests.
// TODO Throw appropriate exception.
ResourceAllocation alloc = null;
Set<ResourceAllocation> allocs = new HashSet<>();
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());
allocs.add(new BandwidthResourceAllocation(br.bandwidth()));
break;
case LAMBDA:
log.info("requestResources() always returns lambda 7");
Iterator<Lambda> lambdaIterator = getAvailableLambdas(req.links()).iterator();
Iterator<Lambda> lambdaIterator =
getAvailableLambdas(req.links()).iterator();
if (lambdaIterator.hasNext()) {
alloc = new LambdaResourceAllocation(lambdaIterator.next());
allocs.add(new LambdaResourceAllocation(lambdaIterator.next()));
} else {
log.info("Failed to allocate lambda resource.");
return null;
}
break;
default:
......@@ -90,50 +138,66 @@ public class LinkResourceManager implements LinkResourceService {
Map<Link, Set<ResourceAllocation>> allocations = new HashMap<>();
for (Link link : req.links()) {
allocations.put(link, Sets.newHashSet(alloc));
allocations.put(link, allocs);
}
return new DefaultLinkResourceAllocations(req, allocations);
LinkResourceAllocations result =
new DefaultLinkResourceAllocations(req, allocations);
store.allocateResources(result);
return result;
}
@Override
public void releaseResources(LinkResourceAllocations allocations) {
// TODO Auto-generated method stub
store.releaseResources(allocations);
}
@Override
public LinkResourceAllocations updateResources(LinkResourceRequest req,
LinkResourceAllocations oldAllocations) {
LinkResourceAllocations oldAllocations) {
// TODO
return null;
}
@Override
public Iterable<LinkResourceAllocations> getAllocations() {
// TODO Auto-generated method stub
return null;
return store.getAllocations();
}
@Override
public Iterable<LinkResourceAllocations> getAllocations(Link link) {
// TODO Auto-generated method stub
return null;
return store.getAllocations(link);
}
@Override
public LinkResourceAllocations getAllocations(IntentId intentId) {
// TODO Auto-generated method stub
return null;
return store.getAllocations(intentId);
}
@Override
public Iterable<ResourceRequest> getAvailableResources(Link link) {
// TODO Auto-generated method stub
return null;
Set<ResourceAllocation> freeRes = store.getFreeResources(link);
Set<ResourceRequest> result = new HashSet<>();
for (ResourceAllocation alloc : freeRes) {
switch (alloc.type()) {
case BANDWIDTH:
result.add(new BandwidthResourceRequest(
((BandwidthResourceAllocation) alloc).bandwidth()));
break;
case LAMBDA:
result.add(new LambdaResourceRequest());
break;
default:
break;
}
}
return result;
}
@Override
public ResourceRequest getAvailableResources(Link link,
LinkResourceAllocations allocations) {
LinkResourceAllocations allocations) {
// TODO
return null;
}
......
......@@ -543,8 +543,9 @@ public class GossipDeviceStore
Port newPort,
Map<PortNumber, Port> ports) {
if (oldPort.isEnabled() != newPort.isEnabled() ||
!AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) {
oldPort.type() != newPort.type() ||
oldPort.portSpeed() != newPort.portSpeed() ||
!AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) {
ports.put(oldPort.number(), newPort);
return new DeviceEvent(PORT_UPDATED, device, newPort);
}
......@@ -867,7 +868,10 @@ public class GossipDeviceStore
}
}
return new DefaultPort(device, number, isEnabled, annotations);
return portDesc == null ?
new DefaultPort(device, number, false, annotations) :
new DefaultPort(device, number, isEnabled, portDesc.value().type(),
portDesc.value().portSpeed(), annotations);
}
/**
......
......@@ -16,7 +16,9 @@
package org.onlab.onos.store.mastership.impl;
import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED;
import static org.apache.commons.lang3.concurrent.ConcurrentUtils.putIfAbsent;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
......@@ -41,7 +43,6 @@ import org.onlab.onos.store.serializers.KryoNamespaces;
import org.onlab.onos.store.serializers.KryoSerializer;
import org.onlab.util.KryoNamespace;
import com.google.common.collect.ImmutableSet;
import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.EntryListener;
import com.hazelcast.core.IAtomicLong;
......@@ -105,46 +106,50 @@ implements MastershipStore {
@Override
public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
final RoleValue roleInfo = getRoleValue(deviceId);
if (roleInfo.contains(MASTER, nodeId)) {
return MASTER;
}
if (roleInfo.contains(STANDBY, nodeId)) {
return STANDBY;
final RoleValue roleInfo = roleMap.get(deviceId);
if (roleInfo != null) {
return roleInfo.getRole(nodeId);
}
return NONE;
}
@Override
public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) {
MastershipRole role = getRole(nodeId, deviceId);
roleMap.lock(deviceId);
try {
RoleValue rv = getRoleValue(deviceId);
switch (role) {
final RoleValue rv = getRoleValue(deviceId);
final MastershipRole currentRole = rv.getRole(newMaster);
switch (currentRole) {
case MASTER:
//reinforce mastership
rv.reassign(nodeId, STANDBY, NONE);
roleMap.put(deviceId, rv);
// RoleInfo integrity check
boolean modified = rv.reassign(newMaster, STANDBY, NONE);
if (modified) {
roleMap.put(deviceId, rv);
// should never reach here.
log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId);
// trigger BACKUPS_CHANGED?
}
return null;
case STANDBY:
case NONE:
NodeId current = rv.get(MASTER);
if (current != null) {
//backup and replace current master
rv.reassign(current, NONE, STANDBY);
rv.replace(current, nodeId, MASTER);
final NodeId currentMaster = rv.get(MASTER);
if (currentMaster != null) {
// place current master in STANDBY
rv.reassign(currentMaster, NONE, STANDBY);
rv.replace(currentMaster, newMaster, MASTER);
} else {
//no master before so just add.
rv.add(MASTER, nodeId);
rv.add(MASTER, newMaster);
}
rv.reassign(nodeId, STANDBY, NONE);
roleMap.put(deviceId, rv);
// remove newMaster from STANDBY
rv.reassign(newMaster, STANDBY, NONE);
updateTerm(deviceId);
roleMap.put(deviceId, rv);
return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
default:
log.warn("unknown Mastership Role {}", role);
log.warn("unknown Mastership Role {}", currentRole);
return null;
}
} finally {
......@@ -160,66 +165,83 @@ implements MastershipStore {
@Override
public RoleInfo getNodes(DeviceId deviceId) {
roleMap.lock(deviceId);
try {
RoleValue rv = getRoleValue(deviceId);
RoleValue rv = roleMap.get(deviceId);
if (rv != null) {
return rv.roleInfo();
} finally {
roleMap.unlock(deviceId);
} else {
return new RoleInfo();
}
}
@Override
public Set<DeviceId> getDevices(NodeId nodeId) {
ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder();
Set<DeviceId> devices = new HashSet<>();
for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) {
if (nodeId.equals(el.getValue().get(MASTER))) {
builder.add(el.getKey());
devices.add(el.getKey());
}
}
return builder.build();
return devices;
}
@Override
public MastershipRole requestRole(DeviceId deviceId) {
NodeId local = clusterService.getLocalNode().id();
// if no master => become master
// if there already exists a master:
// if I was the master return MASTER
// else put myself in STANDBY and return STANDBY
final NodeId local = clusterService.getLocalNode().id();
boolean modified = false;
roleMap.lock(deviceId);
try {
RoleValue rv = getRoleValue(deviceId);
MastershipRole role = getRole(local, deviceId);
switch (role) {
final RoleValue rv = getRoleValue(deviceId);
if (rv.get(MASTER) == null) {
// there's no master become one
// move out from STANDBY
rv.reassign(local, STANDBY, NONE);
rv.add(MASTER, local);
updateTerm(deviceId);
roleMap.put(deviceId, rv);
return MASTER;
}
final MastershipRole currentRole = rv.getRole(local);
switch (currentRole) {
case MASTER:
rv.reassign(local, STANDBY, NONE);
terms.putIfAbsent(deviceId, INIT);
roleMap.put(deviceId, rv);
break;
// RoleInfo integrity check
modified = rv.reassign(local, STANDBY, NONE);
if (modified) {
log.warn("{} was in both MASTER and STANDBY for {}", local, deviceId);
// should never reach here,
// but heal if we happened to be there
roleMap.put(deviceId, rv);
// trigger BACKUPS_CHANGED?
}
return currentRole;
case STANDBY:
rv.reassign(local, NONE, STANDBY);
roleMap.put(deviceId, rv);
terms.putIfAbsent(deviceId, INIT);
break;
case NONE:
//either we're the first standby, or first to device.
//for latter, claim mastership.
if (rv.get(MASTER) == null) {
rv.add(MASTER, local);
rv.reassign(local, STANDBY, NONE);
updateTerm(deviceId);
role = MastershipRole.MASTER;
} else {
rv.add(STANDBY, local);
rv.reassign(local, NONE, STANDBY);
role = MastershipRole.STANDBY;
// RoleInfo integrity check
modified = rv.reassign(local, NONE, STANDBY);
if (modified) {
log.warn("{} was in both NONE and STANDBY for {}", local, deviceId);
// should never reach here,
// but heal if we happened to be there
roleMap.put(deviceId, rv);
// trigger BACKUPS_CHANGED?
}
return currentRole;
case NONE:
rv.reassign(local, NONE, STANDBY);
roleMap.put(deviceId, rv);
break;
// TODO: notifyDelegate BACKUPS_CHANGED
return STANDBY;
default:
log.warn("unknown Mastership Role {}", role);
log.warn("unknown Mastership Role {}", currentRole);
}
return role;
return currentRole;
} finally {
roleMap.unlock(deviceId);
}
......@@ -227,35 +249,58 @@ implements MastershipStore {
@Override
public MastershipTerm getTermFor(DeviceId deviceId) {
RoleValue rv = getRoleValue(deviceId);
if ((rv.get(MASTER) == null) || (terms.get(deviceId) == null)) {
return null;
// term information and role must be read atomically
// acquiring write lock for the device
roleMap.lock(deviceId);
try {
RoleValue rv = getRoleValue(deviceId);
final Integer term = terms.get(deviceId);
final NodeId master = rv.get(MASTER);
if ((master == null) || (term == null)) {
return null;
}
return MastershipTerm.of(master, term);
} finally {
roleMap.unlock(deviceId);
}
return MastershipTerm.of(rv.get(MASTER), terms.get(deviceId));
}
@Override
public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) {
MastershipEvent event = null;
// if nodeId was MASTER, rotate STANDBY
// if nodeId was STANDBY no-op
// if nodeId was NONE, add to STANDBY
roleMap.lock(deviceId);
try {
RoleValue rv = getRoleValue(deviceId);
MastershipRole role = getRole(nodeId, deviceId);
switch (role) {
final RoleValue rv = getRoleValue(deviceId);
final MastershipRole currentRole = getRole(nodeId, deviceId);
switch (currentRole) {
case MASTER:
event = reelect(nodeId, deviceId, rv);
//fall through to reinforce role
NodeId newMaster = reelect(nodeId, deviceId, rv);
rv.reassign(nodeId, NONE, STANDBY);
if (newMaster != null) {
updateTerm(deviceId);
roleMap.put(deviceId, rv);
return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
} else {
// no master candidate
roleMap.put(deviceId, rv);
// FIXME: Should there be new event type?
// or should we issue null Master event?
return null;
}
case STANDBY:
//fall through to reinforce role
return null;
case NONE:
rv.reassign(nodeId, NONE, STANDBY);
roleMap.put(deviceId, rv);
break;
// TODO: BACKUPS_CHANGED?
return null;
default:
log.warn("unknown Mastership Role {}", role);
log.warn("unknown Mastership Role {}", currentRole);
}
return event;
return null;
} finally {
roleMap.unlock(deviceId);
}
......@@ -263,57 +308,71 @@ implements MastershipStore {
@Override
public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) {
MastershipEvent event = null;
// relinquishRole is basically set to None
// If nodeId was master reelect next and remove nodeId
// else remove from STANDBY
roleMap.lock(deviceId);
try {
RoleValue rv = getRoleValue(deviceId);
MastershipRole role = getRole(nodeId, deviceId);
switch (role) {
final RoleValue rv = getRoleValue(deviceId);
final MastershipRole currentRole = rv.getRole(nodeId);
switch (currentRole) {
case MASTER:
event = reelect(nodeId, deviceId, rv);
if (event != null) {
Integer term = terms.get(deviceId);
terms.put(deviceId, ++term);
NodeId newMaster = reelect(nodeId, deviceId, rv);
if (newMaster != null) {
updateTerm(deviceId);
roleMap.put(deviceId, rv);
return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
} else {
// no master candidate
roleMap.put(deviceId, rv);
// Should there be new event type?
return null;
}
//fall through to reinforce relinquishment
case STANDBY:
//fall through to reinforce relinquishment
case NONE:
rv.reassign(nodeId, STANDBY, NONE);
roleMap.put(deviceId, rv);
break;
boolean modified = rv.reassign(nodeId, STANDBY, NONE);
if (modified) {
roleMap.put(deviceId, rv);
// TODO: BACKUPS_CHANGED?
return null;
}
return null;
default:
log.warn("unknown Mastership Role {}", role);
log.warn("unknown Mastership Role {}", currentRole);
}
return event;
return null;
} finally {
roleMap.unlock(deviceId);
}
}
// TODO: Consider moving this to RoleValue method
//helper to fetch a new master candidate for a given device.
private MastershipEvent reelect(
private NodeId reelect(
NodeId current, DeviceId deviceId, RoleValue rv) {
//if this is an queue it'd be neater.
NodeId backup = null;
NodeId candidate = null;
for (NodeId n : rv.nodesOfRole(STANDBY)) {
if (!current.equals(n)) {
backup = n;
candidate = n;
break;
}
}
if (backup == null) {
if (candidate == null) {
log.info("{} giving up and going to NONE for {}", current, deviceId);
rv.remove(MASTER, current);
// master did change, but there is no master candidate.
return null;
} else {
log.info("{} trying to pass mastership for {} to {}", current, deviceId, backup);
rv.replace(current, backup, MASTER);
rv.reassign(backup, STANDBY, NONE);
return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate);
rv.replace(current, candidate, MASTER);
rv.reassign(candidate, STANDBY, NONE);
return candidate;
}
}
......@@ -340,17 +399,30 @@ implements MastershipStore {
}
//adds or updates term information.
// must be guarded by roleMap.lock(deviceId)
private void updateTerm(DeviceId deviceId) {
terms.lock(deviceId);
try {
Integer term = terms.get(deviceId);
Integer term = terms.get(deviceId);
if (term == null) {
term = terms.putIfAbsent(deviceId, INIT);
if (term == null) {
terms.put(deviceId, INIT);
} else {
terms.put(deviceId, ++term);
// initial term set successfully
return;
}
} finally {
terms.unlock(deviceId);
// concurrent initialization detected,
// fall through to try incrementing
}
Integer nextTerm = term + 1;
boolean success = terms.replace(deviceId, term, nextTerm);
while (!success) {
term = terms.get(deviceId);
if (term == null) {
// something is very wrong, but write something to avoid
// infinite loop.
log.warn("Term info for {} disappeared.", deviceId);
term = putIfAbsent(terms, deviceId, nextTerm);
}
nextTerm = term + 1;
success = terms.replace(deviceId, term, nextTerm);
}
}
......
......@@ -15,6 +15,10 @@
*/
package org.onlab.onos.store.mastership.impl;
import static org.onlab.onos.net.MastershipRole.MASTER;
import static org.onlab.onos.net.MastershipRole.NONE;
import static org.onlab.onos.net.MastershipRole.STANDBY;
import java.util.Collections;
import java.util.EnumMap;
import java.util.LinkedList;
......@@ -59,18 +63,30 @@ final class RoleValue {
return value.get(type).contains(nodeId);
}
public MastershipRole getRole(NodeId nodeId) {
if (contains(MASTER, nodeId)) {
return MASTER;
}
if (contains(STANDBY, nodeId)) {
return STANDBY;
}
return NONE;
}
/**
* Associates a node to a certain role.
*
* @param type the role
* @param nodeId the node ID of the node to associate
* @return true if modified
*/
public void add(MastershipRole type, NodeId nodeId) {
public boolean add(MastershipRole type, NodeId nodeId) {
List<NodeId> nodes = value.get(type);
if (!nodes.contains(nodeId)) {
nodes.add(nodeId);
return nodes.add(nodeId);
}
return false;
}
/**
......@@ -78,7 +94,7 @@ final class RoleValue {
*
* @param type the role
* @param nodeId the ID of the node to remove
* @return
* @return true if modified
*/
public boolean remove(MastershipRole type, NodeId nodeId) {
List<NodeId> nodes = value.get(type);
......@@ -96,10 +112,12 @@ final class RoleValue {
* @param nodeId the Node ID of node changing roles
* @param from the old role
* @param to the new role
* @return true if modified
*/
public void reassign(NodeId nodeId, MastershipRole from, MastershipRole to) {
remove(from, nodeId);
add(to, nodeId);
public boolean reassign(NodeId nodeId, MastershipRole from, MastershipRole to) {
boolean modified = remove(from, nodeId);
modified |= add(to, nodeId);
return modified;
}
/**
......@@ -109,10 +127,12 @@ final class RoleValue {
* @param from the old NodeId to replace
* @param to the new NodeId
* @param type the role associated with the old NodeId
* @return true if modified
*/
public void replace(NodeId from, NodeId to, MastershipRole type) {
remove(type, from);
add(type, to);
public boolean replace(NodeId from, NodeId to, MastershipRole type) {
boolean modified = remove(type, from);
modified |= add(type, to);
return modified;
}
/**
......
......@@ -142,7 +142,7 @@ public class DistributedMastershipStoreTest {
testStore.setCurrent(CN1);
//if already MASTER, nothing should happen
testStore.put(DID2, N1, true, false, false);
testStore.put(DID2, N1, true, false, true);
assertEquals("wrong role for MASTER:", MASTER, dms.requestRole(DID2));
//populate maps with DID1, N1 thru NONE case
......
......@@ -22,11 +22,11 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import org.onlab.onos.core.DefaultApplicationId;
import org.onlab.onos.cluster.ControllerNode;
import org.onlab.onos.cluster.DefaultControllerNode;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.cluster.RoleInfo;
import org.onlab.onos.core.DefaultApplicationId;
import org.onlab.onos.mastership.MastershipTerm;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultAnnotations;
......@@ -59,6 +59,9 @@ 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;
import org.onlab.onos.net.flow.instructions.L0ModificationInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
import org.onlab.onos.net.host.DefaultHostDescription;
import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.intent.ConnectivityIntent;
......@@ -66,6 +69,7 @@ import org.onlab.onos.net.intent.HostToHostIntent;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.intent.IntentState;
import org.onlab.onos.net.intent.LinkCollectionIntent;
import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
......@@ -115,6 +119,7 @@ public final class KryoNamespaces {
//
ControllerNode.State.class,
Device.Type.class,
Port.Type.class,
ChassisId.class,
DefaultAnnotations.class,
DefaultControllerNode.class,
......@@ -149,6 +154,17 @@ public final class KryoNamespaces {
DefaultTrafficTreatment.class,
Instructions.DropInstruction.class,
Instructions.OutputInstruction.class,
L0ModificationInstruction.class,
L0ModificationInstruction.L0SubType.class,
L0ModificationInstruction.ModLambdaInstruction.class,
L2ModificationInstruction.class,
L2ModificationInstruction.L2SubType.class,
L2ModificationInstruction.ModEtherInstruction.class,
L2ModificationInstruction.ModVlanIdInstruction.class,
L2ModificationInstruction.ModVlanPcpInstruction.class,
L3ModificationInstruction.class,
L3ModificationInstruction.L3SubType.class,
L3ModificationInstruction.ModIPInstruction.class,
RoleInfo.class,
FlowRuleBatchOperation.class,
CompletedBatchOperation.class,
......@@ -163,7 +179,8 @@ public final class KryoNamespaces {
DefaultEdgeLink.class,
HostToHostIntent.class,
PointToPointIntent.class,
MultiPointToSinglePointIntent.class
MultiPointToSinglePointIntent.class,
LinkCollectionIntent.class
)
.register(DefaultApplicationId.class, new DefaultApplicationIdSerializer())
.register(URI.class, new URISerializer())
......
......@@ -15,13 +15,10 @@
*/
package org.onlab.onos.store.serializers;
import static org.junit.Assert.assertEquals;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
import static java.util.Arrays.asList;
import java.nio.ByteBuffer;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.testing.EqualsTester;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
......@@ -50,10 +47,12 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.util.KryoNamespace;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.testing.EqualsTester;
import java.nio.ByteBuffer;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
public class KryoSerializerTest {
......
......@@ -291,8 +291,9 @@ public class SimpleDeviceStore
Port newPort,
Map<PortNumber, Port> ports) {
if (oldPort.isEnabled() != newPort.isEnabled() ||
oldPort.type() != newPort.type() ||
oldPort.portSpeed() != newPort.portSpeed() ||
!AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) {
ports.put(oldPort.number(), newPort);
return new DeviceEvent(PORT_UPDATED, device, newPort);
}
......@@ -510,7 +511,10 @@ public class SimpleDeviceStore
}
}
return new DefaultPort(device, number, isEnabled, annotations);
return portDesc == null ?
new DefaultPort(device, number, false, annotations) :
new DefaultPort(device, number, isEnabled, portDesc.type(),
portDesc.portSpeed(), annotations);
}
/**
......
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed 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.store.trivial.impl;
import static com.google.common.base.Preconditions.*;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
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.Bandwidth;
import org.onlab.onos.net.resource.BandwidthResourceAllocation;
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.LinkResourceStore;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceType;
import org.slf4j.Logger;
/**
* Manages link resources using trivial in-memory structures implementation.
*/
@Component(immediate = true)
@Service
public class SimpleLinkResourceStore implements LinkResourceStore {
private final Logger log = getLogger(getClass());
private Map<IntentId, LinkResourceAllocations> linkResourceAllocationsMap;
private Map<Link, Set<LinkResourceAllocations>> allocatedResources;
private Map<Link, Set<ResourceAllocation>> freeResources;
@Activate
public void activate() {
linkResourceAllocationsMap = new HashMap<>();
allocatedResources = new HashMap<>();
freeResources = new HashMap<>();
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
private Set<ResourceAllocation> readOriginalFreeResources(Link link) {
// TODO read capacity and lambda resources from topology
Set<ResourceAllocation> allocations = new HashSet<>();
for (int i = 1; i <= 100; i++) {
allocations.add(new LambdaResourceAllocation(Lambda.valueOf(i)));
}
allocations.add(new BandwidthResourceAllocation(Bandwidth.valueOf(1000000)));
return allocations;
}
private BandwidthResourceAllocation getBandwidth(Set<ResourceAllocation> freeRes) {
for (ResourceAllocation res : freeRes) {
if (res.type() == ResourceType.BANDWIDTH) {
return (BandwidthResourceAllocation) res;
}
}
return new BandwidthResourceAllocation(Bandwidth.valueOf(0));
}
private void subtractFreeResources(Link link, LinkResourceAllocations allocations) {
// TODO Use lock or version for updating freeResources.
checkNotNull(link);
Set<ResourceAllocation> freeRes = freeResources.get(link);
checkNotNull(freeRes);
freeRes = new HashSet<>(freeRes);
Set<ResourceAllocation> subRes = allocations.getResourceAllocation(link);
for (ResourceAllocation res : subRes) {
switch (res.type()) {
case BANDWIDTH:
BandwidthResourceAllocation ba = getBandwidth(freeRes);
double requestedBandwidth =
((BandwidthResourceAllocation) res).bandwidth().toDouble();
double newBandwidth = ba.bandwidth().toDouble() - requestedBandwidth;
checkState(newBandwidth >= 0.0);
freeRes.remove(ba);
freeRes.add(new BandwidthResourceAllocation(
Bandwidth.valueOf(newBandwidth)));
break;
case LAMBDA:
checkState(freeRes.remove(res));
break;
default:
break;
}
}
freeResources.put(link, freeRes);
}
private void addFreeResources(Link link, LinkResourceAllocations allocations) {
// TODO Use lock or version for updating freeResources.
Set<ResourceAllocation> freeRes = freeResources.get(link);
checkNotNull(freeRes);
freeRes = new HashSet<>(freeRes);
Set<ResourceAllocation> addRes = allocations.getResourceAllocation(link);
for (ResourceAllocation res : addRes) {
switch (res.type()) {
case BANDWIDTH:
BandwidthResourceAllocation ba = getBandwidth(freeRes);
double requestedBandwidth =
((BandwidthResourceAllocation) res).bandwidth().toDouble();
double newBandwidth = ba.bandwidth().toDouble() + requestedBandwidth;
freeRes.remove(ba);
freeRes.add(new BandwidthResourceAllocation(
Bandwidth.valueOf(newBandwidth)));
break;
case LAMBDA:
checkState(freeRes.add(res));
break;
default:
break;
}
}
freeResources.put(link, freeRes);
}
@Override
public Set<ResourceAllocation> getFreeResources(Link link) {
checkNotNull(link);
Set<ResourceAllocation> freeRes = freeResources.get(link);
if (freeRes == null) {
freeRes = readOriginalFreeResources(link);
}
return freeRes;
}
@Override
public void allocateResources(LinkResourceAllocations allocations) {
checkNotNull(allocations);
linkResourceAllocationsMap.put(allocations.intendId(), allocations);
for (Link link : allocations.links()) {
subtractFreeResources(link, allocations);
Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link);
if (linkAllocs == null) {
linkAllocs = new HashSet<>();
}
linkAllocs.add(allocations);
allocatedResources.put(link, linkAllocs);
}
}
@Override
public void releaseResources(LinkResourceAllocations allocations) {
checkNotNull(allocations);
linkResourceAllocationsMap.remove(allocations);
for (Link link : allocations.links()) {
addFreeResources(link, allocations);
Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link);
if (linkAllocs == null) {
log.error("Missing resource allocation.");
} else {
linkAllocs.remove(allocations);
}
allocatedResources.put(link, linkAllocs);
}
}
@Override
public LinkResourceAllocations getAllocations(IntentId intentId) {
checkNotNull(intentId);
return linkResourceAllocationsMap.get(intentId);
}
@Override
public Iterable<LinkResourceAllocations> getAllocations(Link link) {
checkNotNull(link);
Set<LinkResourceAllocations> result = allocatedResources.get(link);
if (result == null) {
result = Collections.emptySet();
}
return Collections.unmodifiableSet(result);
}
@Override
public Iterable<LinkResourceAllocations> getAllocations() {
return Collections.unmodifiableCollection(linkResourceAllocationsMap.values());
}
}
......@@ -15,6 +15,22 @@
*/
package org.onlab.onos.provider.lldp.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.onlab.onos.net.MastershipRole.MASTER;
import static org.onlab.onos.net.PortNumber.portNumber;
import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
import static org.slf4j.LoggerFactory.getLogger;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.TimerTask;
import org.onlab.onos.mastership.MastershipService;
......@@ -36,22 +52,6 @@ import org.onlab.packet.ONOSLLDP;
import org.onlab.util.Timer;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.onlab.onos.net.MastershipRole.MASTER;
import static org.onlab.onos.net.PortNumber.portNumber;
import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Run discovery process from a physical switch. Ports are initially labeled as
* slow ports. When an LLDP is successfully received, label the remote port as
......@@ -336,7 +336,7 @@ public class LinkDiscovery implements TimerTask {
private void sendProbes(Long portNumber) {
// TODO: should have suppression port configuration, not by type
if (device.type() != Device.Type.ROADM) {
log.debug("Sending probes out to {}@{}", portNumber, device.id());
log.trace("Sending probes out to {}@{}", portNumber, device.id());
OutboundPacket pkt = this.createOutBoundLLDP(portNumber);
pktService.emit(pkt);
if (useBDDP) {
......
......@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.MastershipRole;
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;
......@@ -43,14 +44,19 @@ 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.OFPortFeatures;
import org.projectfloodlight.openflow.protocol.OFPortState;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.PortSpeed;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.List;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.Port.Type.COPPER;
import static org.onlab.onos.net.Port.Type.FIBER;
import static org.onlab.onos.openflow.controller.Dpid.dpid;
import static org.onlab.onos.openflow.controller.Dpid.uri;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -63,6 +69,7 @@ import static org.slf4j.LoggerFactory.getLogger;
public class OpenFlowDeviceProvider extends AbstractProvider implements DeviceProvider {
private static final Logger LOG = getLogger(OpenFlowDeviceProvider.class);
private static final long MBPS = 1_000 * 1_000;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceProviderRegistry providerRegistry;
......@@ -122,9 +129,9 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri()));
//if (!checkChannel(device, sw)) {
// LOG.error("Failed to probe device {} on sw={}", device, sw);
// LOG.error("Failed to probe device {} on sw={}", device, sw);
// providerService.deviceDisconnected(device.id());
//return;
//return;
//}
// Prompt an update of port information. We can use any XID for this.
......@@ -143,13 +150,13 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
// Checks if the OF channel is connected.
//private boolean checkChannel(Device device, OpenFlowSwitch sw) {
// FIXME if possible, we might want this to be part of
// OpenFlowSwitch interface so the driver interface isn't misused.
// FIXME if possible, we might want this to be part of
// OpenFlowSwitch interface so the driver interface isn't misused.
// if (sw == null || !((OpenFlowSwitchDriver) sw).isConnected()) {
// return false;
// }
// return false;
// }
// return true;
// }
// }
@Override
public void roleChanged(Device device, MastershipRole newRole) {
......@@ -188,7 +195,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
sw.hardwareDescription(),
sw.softwareDescription(),
sw.serialNumber(),
cId);
cId);
providerService.deviceConnected(did, description);
providerService.updatePorts(did, buildPortDescriptions(sw.getPorts()));
}
......@@ -244,8 +251,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
* @param ports the list of ports
* @return list of portdescriptions
*/
private List<PortDescription> buildPortDescriptions(
List<OFPortDesc> ports) {
private List<PortDescription> buildPortDescriptions(List<OFPortDesc> ports) {
final List<PortDescription> portDescs = new ArrayList<>(ports.size());
for (OFPortDesc port : ports) {
portDescs.add(buildPortDescription(port));
......@@ -260,12 +266,25 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
* @return portDescription for the port.
*/
private PortDescription buildPortDescription(OFPortDesc port) {
final PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
final boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN) &&
!port.getConfig().contains(OFPortConfig.PORT_DOWN);
return new DefaultPortDescription(portNo, enabled);
PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber());
boolean enabled =
!port.getState().contains(OFPortState.LINK_DOWN) &&
!port.getConfig().contains(OFPortConfig.PORT_DOWN);
Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER;
return new DefaultPortDescription(portNo, enabled, type, portSpeed(port));
}
private long portSpeed(OFPortDesc port) {
if (port.getVersion() == OFVersion.OF_13) {
return port.getCurrSpeed() / MBPS;
}
PortSpeed portSpeed = PortSpeed.SPEED_NONE;
for (OFPortFeatures feat : port.getCurr()) {
portSpeed = PortSpeed.max(portSpeed, feat.getPortSpeed());
}
return portSpeed.getSpeedBps() / MBPS;
}
}
}
......
......@@ -6,4 +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 && cd docs && mvn javadoc:aggregate
cd $ONOS_ROOT && mvn clean install "$@" && cd docs && mvn javadoc:aggregate
......
......@@ -34,6 +34,7 @@ alias mci='mvn clean install'
# Short-hand for ONOS build, package and test.
alias ob='onos-build'
alias obi='onos-build -Dmaven.test.failure.ignore=true'
alias obs='onos-build-selective'
alias op='onos-package'
alias ot='onos-test'
......
# Local VirtualBox-based single ONOS instance & ONOS mininet box
export ONOS_CELL="cbench"
export ONOS_NIC=192.168.56.*
export OC1="192.168.56.103"
export OCN="192.168.56.103"
......
# Local VirtualBox-based ONOS instances 1,2 & ONOS mininet box
export ONOS_CELL="local"
export ONOS_NIC=192.168.56.*
export OC1="192.168.56.101"
export OC2="192.168.56.102"
......
# ProxMox-based cell of ONOS instance; no mininet-box
export ONOS_CELL="office"
export ONOS_NIC="10.1.10.*"
export OC1="10.1.10.223"
export OCI="${OC1}"
......
# ProxMox-based cell of ONOS instances 1,2 & ONOS mininet box
export ONOS_CELL="prox"
export ONOS_NIC="10.1.9.*"
export OC1="10.1.9.94"
export OC2="10.1.9.82"
......
# Local VirtualBox-based single ONOS instance & ONOS mininet box
export ONOS_CELL="single"
export ONOS_NIC=192.168.56.*
export OC1="192.168.56.101"
export OCN="192.168.56.103"
......
# Local VirtualBox-based ONOS instances 1,2,3 & ONOS mininet box
export ONOS_CELL="triple"
export ONOS_NIC=192.168.56.*
export OC1="192.168.56.101"
export OC2="192.168.56.102"
......
......@@ -3,28 +3,33 @@
{
"uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM1",
"annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 }
"annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 },
"ports": [ { "port": 10, "speed": 100000, "type": "FIBER" }, { "port": 20, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM2",
"annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 }
"annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 },
"ports": [ { "port": 11, "speed": 100000, "type": "FIBER" }, { "port": 21, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM3",
"annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 2 }
"annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 2 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0001", "mac": "ffffffffff0003", "type": "SWITCH",
"uri": "of:0000ffffffff0001", "mac": "ffffffffff0001", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER1",
"annotations": { "latitude": 37.6, "longitude": 122.3 }
"annotations": { "latitude": 37.6, "longitude": 122.3 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0002", "mac": "ffffffffff0002", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER2",
"annotations": { "latitude": 37.3, "longitude": 121.9 }
"annotations": { "latitude": 37.3, "longitude": 121.9 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
}
],
......@@ -36,10 +41,8 @@
{ "src": "of:0000ffffffff0002/2", "dst": "of:0000ffffffffff02/11", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }
],
"Xhosts" : [
{ "mac": "a0:00:00:00:00:11", "vlan": -1, "location": "of:0000ffffffff0001/11", "ip": "1.2.3.4" },
{ "mac": "a0:00:00:00:00:12", "vlan": -1, "location": "of:0000ffffffff0001/12", "ip": "1.2.3.5" },
{ "mac": "a0:00:00:00:00:21", "vlan": -1, "location": "of:0000ffffffff0002/11", "ip": "2.2.3.4" },
{ "mac": "a0:00:00:00:00:22", "vlan": -1, "location": "of:0000ffffffff0002/12", "ip": "2.2.3.5" }
"hosts" : [
{ "mac": "00:00:00:00:00:01", "vlan": -1, "location": "of:0000ffffffff0001/1", "ip": "10.0.0.1" },
{ "mac": "00:00:00:00:00:02", "vlan": -1, "location": "of:0000ffffffff0002/1", "ip": "10.0.0.2" }
]
}
\ No newline at end of file
......
{
"devices" : [
{
"uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SFO-W10",
"annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 },
"ports": [ { "port": 10, "speed": 100000, "type": "FIBER" }, { "port": 20, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SJC-W10",
"annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 },
"ports": [ { "port": 11, "speed": 100000, "type": "FIBER" }, { "port": 21, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "LAX-W10",
"annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 0 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff04", "mac": "ffffffffffff04", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SDG-W10",
"annotations": { "latitude": 32.8, "longitude": 117.1, "optical.regens": 3 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff05", "mac": "ffffffffffff05", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "MSP-M10",
"annotations": { "latitude": 44.8, "longitude": 93.1, "optical.regens": 3 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff06", "mac": "ffffffffffff06", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "DFW-M10",
"annotations": { "latitude": 32.8, "longitude": 97.1, "optical.regens": 3 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff07", "mac": "ffffffffffff07", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "CHG-N10",
"annotations": { "latitude": 41.8, "longitude": 120.1, "optical.regens": 3 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff08", "mac": "ffffffffffff08", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "IAD-M10",
"annotations": { "latitude": 38.8, "longitude": 77.1, "optical.regens": 3 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff09", "mac": "ffffffffffff09", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "JFK-M10",
"annotations": { "latitude": 40.8, "longitude": 73.1, "optical.regens": 0 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff0A", "mac": "ffffffffffff0A", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ATL-S10",
"annotations": { "latitude": 33.8, "longitude": 84.1, "optical.regens": 0 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff06", "mac": "ffffffffffff06", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "DFW-M10",
"annotations": { "latitude": 32.8, "longitude": 97.1, "optical.regens": 3 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0001", "mac": "ffffffffff0001", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "SFO-R10",
"annotations": { "latitude": 37.6, "longitude": 122.3 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0003", "mac": "ffffffffff0003", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "LAX-R10",
"annotations": { "latitude": 33.9, "longitude": 118.4 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0004", "mac": "ffffffffff0004", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "SDG-R10",
"annotations": { "latitude": 32.8, "longitude": 117.1 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0007", "mac": "ffffffffff0007", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "CHG-R10",
"annotations": { "latitude": 41.8, "longitude": 120.1 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0009", "mac": "ffffffffff0009", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "JFK-R10",
"annotations": { "latitude": 40.8, "longitude": 73.1 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff000A", "mac": "ffffffffff000A", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ATL-R10",
"annotations": { "latitude": 33.8, "longitude": 84.1 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
}
],
"links" : [
{ "src": "of:0000ffffffffff01/10", "dst": "of:0000ffffffffff02/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff02/10", "dst": "of:0000ffffffffff03/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff03/30", "dst": "of:0000ffffffffff04/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff02/20", "dst": "of:0000ffffffffff05/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff03/20", "dst": "of:0000ffffffffff06/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff05/30", "dst": "of:0000ffffffffff06/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff05/20", "dst": "of:0000ffffffffff07/21", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff06/30", "dst": "of:0000ffffffffff08/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff07/30", "dst": "of:0000ffffffffff08/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff07/20", "dst": "of:0000ffffffffff09/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff08/30", "dst": "of:0000ffffffffff0A/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffffff09/20", "dst": "of:0000ffffffffff0A/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } },
{ "src": "of:0000ffffffff0001/2", "dst": "of:0000ffffffffff01/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } },
{ "src": "of:0000ffffffff0003/2", "dst": "of:0000ffffffffff03/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } },
{ "src": "of:0000ffffffff0004/2", "dst": "of:0000ffffffffff04/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } },
{ "src": "of:0000ffffffff0007/2", "dst": "of:0000ffffffffff07/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } },
{ "src": "of:0000ffffffff0009/2", "dst": "of:0000ffffffffff09/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } },
{ "src": "of:0000ffffffff000A/2", "dst": "of:0000ffffffffff0A/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }
],
"hosts" : [
{ "mac": "00:00:00:00:00:01", "vlan": -1, "location": "of:0000ffffffff0001/1", "ip": "10.0.0.1" },
{ "mac": "00:00:00:00:00:03", "vlan": -1, "location": "of:0000ffffffff0003/1", "ip": "10.0.0.3" },
{ "mac": "00:00:00:00:00:04", "vlan": -1, "location": "of:0000ffffffff0004/1", "ip": "10.0.0.4" },
{ "mac": "00:00:00:00:00:07", "vlan": -1, "location": "of:0000ffffffff0007/1", "ip": "10.0.0.7" },
{ "mac": "00:00:00:00:00:09", "vlan": -1, "location": "of:0000ffffffff0009/1", "ip": "10.0.0.9" },
{ "mac": "00:00:00:00:00:0A", "vlan": -1, "location": "of:0000ffffffff000A/1", "ip": "10.0.0.10" }
]
}
\ No newline at end of file
......@@ -101,20 +101,6 @@ public final class Ip4Prefix {
return this.address.toString() + "/" + this.prefixLen;
}
/**
* Compares the value of two Ip4Prefix objects.
* <p/>
* Note the value of the IPv4 address is compared directly between the
* objects, and must match exactly for the objects to be considered equal.
* This may result in objects which represent the same IP prefix being
* classified as unequal, because the unsignificant bits of the address
* field don't match (the bits to the right of the prefix length).
* <p/>
* TODO Change this behavior so that objects that represent the same prefix
* are classified as equal according to this equals method.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(Object other) {
if (other == this) {
......
......@@ -101,20 +101,6 @@ public final class Ip6Prefix {
return this.address.toString() + "/" + this.prefixLen;
}
/**
* Compares the value of two Ip6Prefix objects.
* <p/>
* Note the value of the IPv6 address is compared directly between the
* objects, and must match exactly for the objects to be considered equal.
* This may result in objects which represent the same IP prefix being
* classified as unequal, because the unsignificant bits of the address
* field don't match (the bits to the right of the prefix length).
* <p/>
* TODO Change this behavior so that objects that represent the same prefix
* are classified as equal according to this equals method.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(Object other) {
if (other == this) {
......
......@@ -17,6 +17,8 @@ package org.onlab.packet;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A class representing an IPv4 address.
......@@ -37,35 +39,68 @@ public final class IpAddress implements Comparable<IpAddress> {
/**
* Constructor for given IP address version and address octets.
*
* @param ver the IP address version
* @param octets the IP address octets
* @param value the IP address value stored in network byte order
* (i.e., the most significant byte first)
* @param value the IP address value
*/
private IpAddress(Version ver, byte[] octets) {
this.version = ver;
this.octets = Arrays.copyOf(octets, INET_BYTE_LENGTH);
private IpAddress(Version version, byte[] value) {
checkNotNull(value);
this.version = version;
this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH);
}
/**
* Converts an integer into an IPv4 address.
*
* @param value an integer representing an IPv4 value
* @return an IP address
*/
public static IpAddress valueOf(int value) {
byte[] bytes =
ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array();
return new IpAddress(Version.INET, bytes);
}
/**
* Converts a byte array into an IP address.
*
* @param address the IP address value stored in network byte order
* @param value the IP address value stored in network byte order
* (i.e., the most significant byte first)
* @return an IP address
*/
public static IpAddress valueOf(byte[] address) {
return new IpAddress(Version.INET, address);
public static IpAddress valueOf(byte[] value) {
return new IpAddress(Version.INET, value);
}
/**
* Converts an integer into an IPv4 address.
* Converts a byte array and a given offset from the beginning of the
* array into an IP address.
* <p/>
* The IP address is stored in network byte order (i.e., the most
* significant byte first).
*
* @param address an integer representing an IPv4 value
* @param value the value to use
* @param offset the offset in bytes from the beginning of the byte array
* @return an IP address
*/
public static IpAddress valueOf(int address) {
byte[] bytes =
ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(address).array();
return new IpAddress(Version.INET, bytes);
public static IpAddress valueOf(byte[] value, int offset) {
// Verify the arguments
if ((offset < 0) || (offset + INET_BYTE_LENGTH > value.length)) {
String msg;
if (value.length < INET_BYTE_LENGTH) {
msg = "Invalid IPv4 address array: array length: " +
value.length + ". Must be at least " + INET_BYTE_LENGTH;
} else {
msg = "Invalid IPv4 address array: array offset: " +
offset + ". Must be in the interval [0, " +
(value.length - INET_BYTE_LENGTH) + "]";
}
throw new IllegalArgumentException(msg);
}
byte[] bc = Arrays.copyOfRange(value, offset, value.length);
return IpAddress.valueOf(bc);
}
/**
......@@ -77,8 +112,9 @@ public final class IpAddress implements Comparable<IpAddress> {
public static IpAddress valueOf(String address) {
final String[] net = address.split("\\.");
if (net.length != INET_BYTE_LENGTH) {
throw new IllegalArgumentException("Malformed IP address string; "
+ "Address must have four decimal values separated by dots (.)");
String msg = "Malformed IPv4 address string; " +
"Address must have four decimal values separated by dots (.)";
throw new IllegalArgumentException(msg);
}
final byte[] bytes = new byte[INET_BYTE_LENGTH];
for (int i = 0; i < INET_BYTE_LENGTH; i++) {
......@@ -115,6 +151,48 @@ public final class IpAddress implements Comparable<IpAddress> {
return bb.getInt();
}
/**
* Creates an IP network mask prefix.
*
* @param prefixLen the length of the mask prefix. Must be in the interval
* [0, 32] for IPv4
* @return a new IP address that contains a mask prefix of the
* specified length
*/
public static IpAddress makeMaskPrefix(int prefixLen) {
// Verify the prefix length
if ((prefixLen < 0) || (prefixLen > INET_BIT_LENGTH)) {
final String msg = "Invalid IPv4 prefix length: " + prefixLen +
". Must be in the interval [0, 32].";
throw new IllegalArgumentException(msg);
}
long v = (0xffffffffL << (INET_BIT_LENGTH - prefixLen)) & 0xffffffffL;
return IpAddress.valueOf((int) v);
}
/**
* Creates an IP address by masking it with a network mask of given
* mask length.
*
* @param addr the address to mask
* @param prefixLen the length of the mask prefix. Must be in the interval
* [0, 32] for IPv4
* @return a new IP address that is masked with a mask prefix of the
* specified length
*/
public static IpAddress makeMaskedAddress(final IpAddress addr,
int prefixLen) {
IpAddress mask = IpAddress.makeMaskPrefix(prefixLen);
byte[] net = new byte[INET_BYTE_LENGTH];
// Mask each byte
for (int i = 0; i < INET_BYTE_LENGTH; i++) {
net[i] = (byte) (addr.octets[i] & mask.octets[i]);
}
return IpAddress.valueOf(net);
}
@Override
public int compareTo(IpAddress o) {
Long lv = ((long) this.toInt()) & 0xffffffffL;
......@@ -124,32 +202,20 @@ public final class IpAddress implements Comparable<IpAddress> {
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(octets);
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
return Objects.hash(version, Arrays.hashCode(octets));
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
IpAddress other = (IpAddress) obj;
if (!Arrays.equals(octets, other.octets)) {
return false;
}
if (version != other.version) {
return false;
}
return true;
return (version == other.version) &&
Arrays.equals(octets, other.octets);
}
@Override
......
......@@ -19,17 +19,21 @@ import com.fasterxml.jackson.databind.JsonNode;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultAnnotations;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.MastershipRole;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.SparseAnnotations;
import org.onlab.onos.net.device.DefaultDeviceDescription;
import org.onlab.onos.net.device.DefaultPortDescription;
import org.onlab.onos.net.device.DeviceDescription;
import org.onlab.onos.net.device.DeviceProvider;
import org.onlab.onos.net.device.DeviceProviderRegistry;
import org.onlab.onos.net.device.DeviceProviderService;
import org.onlab.onos.net.device.PortDescription;
import org.onlab.onos.net.host.DefaultHostDescription;
import org.onlab.onos.net.host.HostProvider;
import org.onlab.onos.net.host.HostProviderRegistry;
......@@ -45,7 +49,9 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.onos.net.DeviceId.deviceId;
......@@ -120,7 +126,30 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
DeviceDescription desc =
new DefaultDeviceDescription(uri, type, mfr, hw, sw, serial,
cid, annotations);
dps.deviceConnected(deviceId(uri), desc);
DeviceId deviceId = deviceId(uri);
dps.deviceConnected(deviceId, desc);
JsonNode ports = node.get("ports");
if (ports != null) {
parsePorts(dps, deviceId, ports);
}
}
// Parses the given node with list of device ports.
private void parsePorts(DeviceProviderService dps, DeviceId deviceId, JsonNode nodes) {
List<PortDescription> ports = new ArrayList<>();
for (JsonNode node : nodes) {
ports.add(parsePort(node));
}
dps.updatePorts(deviceId, ports);
}
// Parses the given node with port information.
private PortDescription parsePort(JsonNode node) {
Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER"));
return new DefaultPortDescription(portNumber(node.path("port").asLong(0)),
node.path("enabled").asBoolean(true),
type, node.path("speed").asLong(1_000));
}
// Parses the given JSON and provides links as configured.
......
......@@ -18,9 +18,12 @@ package org.onlab.onos.gui;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.onos.net.Annotations;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.device.DeviceService;
......@@ -35,6 +38,7 @@ import org.onlab.packet.MacAddress;
import org.onlab.rest.BaseResource;
import javax.ws.rs.GET;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.util.HashMap;
......@@ -43,12 +47,17 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.HostId.hostId;
/**
* Topology viewer resource.
*/
@javax.ws.rs.Path("topology")
public class TopologyResource extends BaseResource {
private static final String HOST_SEP = "/";
@javax.ws.rs.Path("/graph")
@GET
@Produces("application/json")
......@@ -70,6 +79,66 @@ public class TopologyResource extends BaseResource {
return Response.ok(rootNode.toString()).build();
}
@javax.ws.rs.Path("/graph/{id}")
@GET
@Produces("application/json")
public Response details(@PathParam("id") String id) {
if (id.contains(HOST_SEP)) {
return hostDetails(hostId(id));
}
return deviceDetails(deviceId(id));
}
// Returns device details response.
private Response deviceDetails(DeviceId deviceId) {
DeviceService deviceService = get(DeviceService.class);
Device device = deviceService.getDevice(deviceId);
Annotations annot = device.annotations();
int portCount = deviceService.getPorts(deviceId).size();
ObjectNode r = json(deviceId.toString(),
device.type().toString().toLowerCase(),
new Prop("Name", annot.value("name")),
new Prop("Vendor", device.manufacturer()),
new Prop("H/W Version", device.hwVersion()),
new Prop("S/W Version", device.swVersion()),
new Prop("S/W Version", device.serialNumber()),
new Separator(),
new Prop("Latitude", annot.value("latitude")),
new Prop("Longitude", annot.value("longitude")),
new Prop("Ports", Integer.toString(portCount)));
return Response.ok(r.toString()).build();
}
// Returns host details response.
private Response hostDetails(HostId hostId) {
HostService hostService = get(HostService.class);
Host host = hostService.getHost(hostId);
Annotations annot = host.annotations();
ObjectNode r = json(hostId.toString(), "host",
new Prop("MAC", host.mac().toString()),
new Prop("IP", host.ipAddresses().toString()),
new Separator(),
new Prop("Latitude", annot.value("latitude")),
new Prop("Longitude", annot.value("longitude")));
return Response.ok(r.toString()).build();
}
// Produces JSON property details.
private ObjectNode json(String id, String type, Prop... props) {
ObjectMapper mapper = new ObjectMapper();
ObjectNode result = mapper.createObjectNode()
.put("id", id).put("type", type);
ObjectNode pnode = mapper.createObjectNode();
ArrayNode porder = mapper.createArrayNode();
for (Prop p : props) {
porder.add(p.key);
pnode.put(p.key, p.value);
}
result.set("propOrder", porder);
result.set("props", pnode);
return result;
}
// Encodes all infrastructure devices.
private ArrayNode getDevices(ObjectMapper mapper, DeviceService deviceService,
TopologyGraph graph) {
......@@ -209,4 +278,20 @@ public class TopologyResource extends BaseResource {
return cp.elementId().toString();
}
// Auxiliary key/value carrier.
private class Prop {
private final String key;
private final String value;
protected Prop(String key, String value) {
this.key = key;
this.value = value;
}
}
private class Separator extends Prop {
protected Separator() {
super("-", "");
}
}
}
......

74.1 KB | W: | H:

37.7 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
......@@ -39,7 +39,7 @@
<body>
<div id="frame">
<div id="mast">
<img id="logo" src="img/onos-logo.png" width="60" height="38">
<img id="logo" src="img/onos-logo.png">
<span class="title">Open Network Operating System</span>
<span id="displayModes" class="right">
<span id="showAll" class="radio active">All Layers</span>
......
......@@ -59,54 +59,72 @@
"src": "of:0000000000000001",
"dst": "of:0000000000000002",
"type": "optical",
"srcPort": 1,
"dstPort": 2,
"linkWidth": 1.5
},
{
"src": "of:0000000000000001",
"dst": "of:0000000000000003",
"type": "optical",
"srcPort": 2,
"dstPort": 5,
"linkWidth": 1.5
},
{
"src": "of:0000000000000001",
"dst": "of:0000000000000004",
"type": "optical",
"srcPort": 3,
"dstPort": 2,
"linkWidth": 1.5
},
{
"src": "of:0000000000000002",
"dst": "of:0000000000000003",
"type": "optical",
"srcPort": 3,
"dstPort": 4,
"linkWidth": 1.5
},
{
"src": "of:0000000000000002",
"dst": "of:0000000000000004",
"type": "optical",
"srcPort": 4,
"dstPort": 1,
"linkWidth": 1.5
},
{
"src": "of:0000000000000003",
"dst": "of:0000000000000004",
"type": "optical",
"srcPort": 3,
"dstPort": 3,
"linkWidth": 1.5
},
{
"src": "of:0000000000000013",
"dst": "of:0000000000000003",
"type": "direct",
"srcPort": 1,
"dstPort": 7,
"linkWidth": 1.0
},
{
"src": "of:0000000000000012",
"dst": "of:0000000000000002",
"type": "direct",
"srcPort": 1,
"dstPort": 9,
"linkWidth": 1.0
},
{
"src": "of:0000000000000011",
"dst": "of:0000000000000001",
"type": "direct",
"srcPort": 1,
"dstPort": 6,
"linkWidth": 1.0
}
],
......
{
"comment": "sample device properties",
"id": "of:0000000000000001",
"propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
"type": "roadm",
"propOrder": [ "name", "type", "-", "dpid", "latitude", "longitude", "allowed" ],
"props": {
"allowed": true,
"latitude": 37.6,
"longitude": 122.3,
"name": "SFO-W10",
"dpid": "00:00:00:00:00:00:00:01",
"type": "Roadm"
"dpid": "00:00:00:00:00:00:00:01"
}
}
......
{
"comment": "sample device properties",
"id": "of:0000000000000002",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
"props": {
"allowed": true,
......
{
"comment": "sample device properties",
"id": "of:0000000000000003",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
"props": {
"allowed": true,
......
{
"comment": "sample device properties",
"id": "of:0000000000000004",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ],
"props": {
"allowed": true,
......
{
"comment": "sample device properties",
"id": "of:0000000000000011",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "optLink" ],
"props": {
"name": "SFO-pkt",
......
{
"comment": "sample device properties",
"id": "of:0000000000000012",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "optLink" ],
"props": {
"name": "SJC-pkt",
......
{
"comment": "sample device properties",
"id": "of:0000000000000013",
"type": "switch",
"propOrder": [ "name", "type", "dpid", "optLink" ],
"props": {
"name": "LAX-pkt",
......
......@@ -37,9 +37,10 @@
layering: true,
collisionPrevention: true
},
XjsonUrl: 'rs/topology/graph',
jsonUrl: 'json/network.json',
jsonPrefix: 'json/',
jsonUrl: 'rs/topology/graph',
jsonPrefix: '',
XjsonUrl: 'json/network.json',
XjsonPrefix: 'json/',
iconUrl: {
device: 'img/device.png',
host: 'img/host.png',
......@@ -238,6 +239,9 @@
function processKeyEvent() {
var code = d3.event.keyCode;
switch (code) {
case 71: // G
cycleLayout();
break;
case 76: // L
cycleLabels();
break;
......@@ -251,6 +255,11 @@
}
function cycleLayout() {
config.options.layering = !config.options.layering;
network.force.resume();
}
function cycleLabels() {
console.log('Cycle Labels - context = ' + contextLabel());
}
......@@ -688,7 +697,8 @@
}
function iconUrl(d) {
return config.iconUrl[d.icon];
return 'img/' + d.type + '.png';
// return config.iconUrl[d.icon];
}
function translate(x, y) {
......@@ -889,8 +899,11 @@
}
function detailUrl(id) {
var safeId = id.replace(/[^a-z0-9]/gi, '_');
return config.jsonPrefix + safeId + '.json';
if (config.jsonPrefix) {
var safeId = id.replace(/[^a-z0-9]/gi, '_');
return config.jsonPrefix + safeId + '.json';
}
return config.jsonUrl + '/' + encodeURIComponent(id);
}
function flyinPane(obj) {
......@@ -924,17 +937,29 @@
function displayDetails(data, pane) {
$('#flyout').empty();
pane.append('h2').text(data.id);
var table = pane.append("table"),
var title = pane.append("h2"),
table = pane.append("table"),
tbody = table.append("tbody");
$('<img src="img/' + data.type + '.png">').appendTo(title);
$('<span>').attr('class', 'icon').text(data.id).appendTo(title);
// TODO: consider using d3 data bind to TR/TD
data.propOrder.forEach(function(p) {
addProp(tbody, p, data.props[p]);
if (p === '-') {
addSep(tbody);
} else {
addProp(tbody, p, data.props[p]);
}
});
function addSep(tbody) {
var tr = tbody.append('tr');
$('<hr>').appendTo(tr.append('td').attr('colspan', 2));
}
function addProp(tbody, label, value) {
var tr = tbody.append('tr');
......
......@@ -28,11 +28,17 @@ body, html {
* Classes
*/
img#logo {
height: 38px;
padding-left: 8px;
padding-right: 8px;
}
span.title {
color: #37b;
color: #369;
font-size: 14pt;
font-style: italic;
vertical-align: 10px;
vertical-align: 12px;
}
span.radio {
......@@ -41,6 +47,8 @@ span.radio {
}
span.right {
padding-top: 8px;
padding-right: 16px;
float: right;
}
......@@ -89,14 +97,13 @@ svg .link {
}
svg .link.host {
stroke: #6a6;
stroke-dasharray: 3,3;
stroke: #666;
stroke-width: 1px;
Xstroke-dasharray: 3,3;
}
svg .node.device rect {
stroke-width: 3.0px;
stroke: white;
stroke-dasharray: 2,2;
stroke-width: 1.5px;
transition: opacity 250ms;
-webkit-transition: opacity 250ms;
......@@ -104,19 +111,21 @@ svg .node.device rect {
}
svg .node.device.fixed rect {
stroke-width: 0;
stroke-width: 1.5;
stroke: #ccc;
Xstroke-dasharray: 4,2;
}
svg .node.device.roadm rect {
fill: #229;
fill: #03c;
}
svg .node.device.switch rect {
fill: #55f;
fill: #06f;
}
svg .node.host circle {
fill: #898;
fill: #c96;
stroke: #000;
}
......@@ -148,7 +157,7 @@ svg .node.inactive rect,
svg .node.inactive circle,
svg .node.inactive text,
svg .node.inactive image {
opacity: .05;
opacity: .1;
}
svg .node.inactive.selected rect,
......@@ -199,8 +208,9 @@ body {
#mast {
height: 36px;
padding: 4px;
background-color: #ccc;
background-color: #bbb;
vertical-align: baseline;
box-shadow: 0px 2px 8px #777;
}
#frame {
......@@ -214,19 +224,27 @@ body {
z-index: 100;
display: block;
top: 10%;
width: 300px;
height: 80%;
right: -320px;
width: 280px;
right: -300px;
opacity: 0;
background-color: rgba(0,0,0,0.5);
background-color: rgba(255,255,255,0.5);
padding: 10px;
color: white;
color: black;
font-size: 10pt;
box-shadow: 2px 2px 16px #777;
}
#flyout h2 {
margin: 8px 4px;
color: yellow;
color: black;
vertical-align: middle;
}
#flyout h2 img {
height: 32px;
padding-right: 8px;
vertical-align: middle;
}
#flyout p, table {
......@@ -235,7 +253,7 @@ body {
#flyout td.label {
font-style: italic;
color: #ccf;
color: #777;
padding-right: 12px;
}
......@@ -243,3 +261,10 @@ body {
}
#flyout hr {
height: 1px;
color: #ccc;
background-color: #ccc;
border: 0;
}
......