Praseed Balakrishnan

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

Conflicts:
	providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
Showing 253 changed files with 3570 additions and 142 deletions
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-apps</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-app-calendar</artifactId>
<packaging>bundle</packaging>
<description>ONOS simple calendaring REST interface for intents</description>
<properties>
<web.context>/onos/calendar</web.context>
</properties>
<dependencies>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-rest</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>1.18.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>1.18.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<_wab>src/main/webapp/</_wab>
<Bundle-SymbolicName>
${project.groupId}.${project.artifactId}
</Bundle-SymbolicName>
<Import-Package>
org.osgi.framework,
javax.ws.rs,javax.ws.rs.core,
com.sun.jersey.api.core,
com.sun.jersey.spi.container.servlet,
com.sun.jersey.server.impl.container.servlet,
org.onlab.packet.*,
org.onlab.rest.*,
org.onlab.onos.*
</Import-Package>
<Web-ContextPath>${web.context}</Web-ContextPath>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
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 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 static org.onlab.onos.net.PortNumber.portNumber;
/**
* Web resource for triggering calendared intents.
*/
@Path("intent")
public class BandwidthCalendarResource extends BaseResource {
@POST
@Path("{src}/{dst}/{srcPort}/{dstPort}/{bandwidth}")
public Response createIntent(@PathParam("src") String src,
@PathParam("dst") String dst,
@PathParam("srcPort") String srcPort,
@PathParam("dstPort") String dstPort,
@PathParam("bandwidth") String bandwidth) {
// TODO: implement calls to intent framework
IntentService service = get(IntentService.class);
ConnectPoint srcPoint = new ConnectPoint(deviceId(src), portNumber(srcPort));
ConnectPoint dstPoint = new ConnectPoint(deviceId(dst), portNumber(dstPort));
return Response.ok("Yo! We got src=" + srcPoint + "; dst=" + dstPoint +
"; bw=" + bandwidth + "; intent service " + service).build();
}
private DeviceId deviceId(String dpid) {
return DeviceId.deviceId(URI.create("of:" + dpid));
}
}
/**
* Application providing integration between OSCARS and ONOS intent
* framework via REST API.
*/
package org.onlab.onos.calendar;
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="ONOS" version="2.5">
<display-name>ONOS GUI</display-name>
<servlet>
<servlet-name>JAX-RS Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>org.onlab.onos.calendar</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Service</servlet-name>
<url-pattern>/rs/*</url-pattern>
</servlet-mapping>
</web-app>
\ No newline at end of file
......@@ -16,4 +16,11 @@
<description>ONOS simple reactive forwarding app</description>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
</dependencies>
</project>
......
package org.onlab.onos.fwd;
import static org.slf4j.LoggerFactory.getLogger;
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.Modified;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.ApplicationId;
......@@ -29,8 +27,14 @@ import org.onlab.onos.net.packet.PacketProcessor;
import org.onlab.onos.net.packet.PacketService;
import org.onlab.onos.net.topology.TopologyService;
import org.onlab.packet.Ethernet;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import java.util.Dictionary;
import java.util.Set;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Sample reactive forwarding application.
*/
......@@ -61,6 +65,10 @@ public class ReactiveForwarding {
private ApplicationId appId;
@Property(name = "enabled", boolValue = true,
label = "Enable forwarding; default is true")
private boolean isEnabled = true;
@Activate
public void activate() {
appId = coreService.registerApplication("org.onlab.onos.fwd");
......@@ -76,6 +84,22 @@ public class ReactiveForwarding {
log.info("Stopped");
}
@Modified
public void modified(ComponentContext context) {
Dictionary properties = context.getProperties();
String flag = (String) properties.get("enabled");
if (flag != null) {
boolean enabled = flag.equals("true");
if (isEnabled != enabled) {
isEnabled = enabled;
if (!isEnabled) {
flowRuleService.removeFlowRulesById(appId);
}
log.info("Reconfigured. Forwarding is {}",
isEnabled ? "enabled" : "disabled");
}
}
}
/**
* Packet processor responsible for forwarding packets along their paths.
......@@ -86,7 +110,7 @@ public class ReactiveForwarding {
public void process(PacketContext context) {
// Stop processing if the packet has been handled, since we
// can't do any more to it.
if (context.isHandled()) {
if (!isEnabled || context.isHandled()) {
return;
}
......@@ -185,7 +209,6 @@ public class ReactiveForwarding {
builder.build(), treat.build(), PRIORITY, appId, TIMEOUT);
flowRuleService.applyFlowRules(f);
}
}
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-apps</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-app-optical</artifactId>
<packaging>bundle</packaging>
<description>ONOS application for packet/optical deployments</description>
<dependencies>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-cli</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.console</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
package org.onlab.onos.optical.cfg;
import java.util.Map;
import org.codehaus.jackson.JsonNode;
import org.onlab.util.HexString;
/**
* Public class corresponding to JSON described data model.
*/
public class OpticalLinkDescription {
protected String type;
protected Boolean allowed;
protected long dpid1;
protected long dpid2;
protected String nodeDpid1;
protected String nodeDpid2;
protected Map<String, JsonNode> params;
protected Map<String, String> publishAttributes;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Boolean isAllowed() {
return allowed;
}
public void setAllowed(Boolean allowed) {
this.allowed = allowed;
}
public String getNodeDpid1() {
return nodeDpid1;
}
public void setNodeDpid1(String nodeDpid1) {
this.nodeDpid1 = nodeDpid1;
this.dpid1 = HexString.toLong(nodeDpid1);
}
public String getNodeDpid2() {
return nodeDpid2;
}
public void setNodeDpid2(String nodeDpid2) {
this.nodeDpid2 = nodeDpid2;
this.dpid2 = HexString.toLong(nodeDpid2);
}
public long getDpid1() {
return dpid1;
}
public void setDpid1(long dpid1) {
this.dpid1 = dpid1;
this.nodeDpid1 = HexString.toHexString(dpid1);
}
public long getDpid2() {
return dpid2;
}
public void setDpid2(long dpid2) {
this.dpid2 = dpid2;
this.nodeDpid2 = HexString.toHexString(dpid2);
}
public Map<String, JsonNode> getParams() {
return params;
}
public void setParams(Map<String, JsonNode> params) {
this.params = params;
}
public Map<String, String> getPublishAttributes() {
return publishAttributes;
}
public void setPublishAttributes(Map<String, String> publishAttributes) {
this.publishAttributes = publishAttributes;
}
}
package org.onlab.onos.optical.cfg;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Public class corresponding to JSON described data model.
*/
public class OpticalNetworkConfig {
protected static final Logger log = LoggerFactory.getLogger(OpticalNetworkConfig.class);
private List<OpticalSwitchDescription> opticalSwitches;
private List<OpticalLinkDescription> opticalLinks;
public OpticalNetworkConfig() {
opticalSwitches = new ArrayList<OpticalSwitchDescription>();
opticalLinks = new ArrayList<OpticalLinkDescription>();
}
public List<OpticalSwitchDescription> getOpticalSwitches() {
return opticalSwitches;
}
public void setOpticalSwitches(List<OpticalSwitchDescription> switches) {
this.opticalSwitches = switches;
}
public List<OpticalLinkDescription> getOpticalLinks() {
return opticalLinks;
}
public void setOpticalLinks(List<OpticalLinkDescription> links) {
this.opticalLinks = links;
}
}
package org.onlab.onos.optical.cfg;
import java.util.Map;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonProperty;
import org.onlab.util.HexString;
/**
* Public class corresponding to JSON described data model.
*/
public class OpticalSwitchDescription {
protected String name;
protected long dpid;
protected String nodeDpid;
protected String type;
protected double latitude;
protected double longitude;
protected boolean allowed;
protected Map<String, JsonNode> params;
protected Map<String, String> publishAttributes;
public String getName() {
return name;
}
@JsonProperty("name")
public void setName(String name) {
this.name = name;
}
public long getDpid() {
return dpid;
}
@JsonProperty("dpid")
public void setDpid(long dpid) {
this.dpid = dpid;
this.nodeDpid = HexString.toHexString(dpid);
}
public String getNodeDpid() {
return nodeDpid;
}
public String getHexDpid() {
return nodeDpid;
}
public void setNodeDpid(String nodeDpid) {
this.nodeDpid = nodeDpid;
this.dpid = HexString.toLong(nodeDpid);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public boolean isAllowed() {
return allowed;
}
public void setAllowed(boolean allowed) {
this.allowed = allowed;
}
public Map<String, JsonNode> getParams() {
return params;
}
public void setParams(Map<String, JsonNode> params) {
this.params = params;
}
public Map<String, String> getPublishAttributes() {
return publishAttributes;
}
public void setPublishAttributes(Map<String, String> publishAttributes) {
this.publishAttributes = publishAttributes;
}
}
package org.onlab.onos.optical.cfg;
/**
* Packet-optical link Java data object.
*/
class PktOptLink {
private String srcNodeName;
private String snkNodeName;
private String srcNodeId;
private String snkNodeId;
private int srcPort;
private int snkPort;
private double bandwidth;
private double cost;
private long adminWeight;
public PktOptLink(String srcName, String snkName) {
this.srcNodeName = srcName;
this.snkNodeName = snkName;
}
public PktOptLink() {
// TODO Auto-generated constructor stub
}
public void setSrcNodeName(String name) {
this.srcNodeName = name;
}
public String getSrcNodeName() {
return this.srcNodeName;
}
public void setSnkNodeName(String name) {
this.snkNodeName = name;
}
public String getSnkNodeName() {
return this.snkNodeName;
}
public void setSrcNodeId(String nodeId) {
this.srcNodeId = nodeId;
}
public String getSrcNodeId() {
return this.srcNodeId;
}
public void setSnkNodeId(String nodeId) {
this.snkNodeId = nodeId;
}
public String getSnkNodeId() {
return this.snkNodeId;
}
public void setSrcPort(int port) {
this.srcPort = port;
}
public int getSrcPort() {
return this.srcPort;
}
public void setSnkPort(int port) {
this.snkPort = port;
}
public int getSnkPort() {
return this.snkPort;
}
public void setBandwdith(double x) {
this.bandwidth = x;
}
public double getBandwidth() {
return this.bandwidth;
}
public void setCost(double x) {
this.cost = x;
}
public double getCost() {
return this.cost;
}
public void setAdminWeight(long x) {
this.adminWeight = x;
}
public long getAdminWeight() {
return this.adminWeight;
}
@Override
public String toString() {
return new StringBuilder(" srcNodeName: ").append(this.srcNodeName)
.append(" snkNodeName: ").append(this.snkNodeName)
.append(" srcNodeId: ").append(this.srcNodeId)
.append(" snkNodeId: ").append(this.snkNodeId)
.append(" srcPort: ").append(this.srcPort)
.append(" snkPort: ").append(this.snkPort)
.append(" bandwidth: ").append(this.bandwidth)
.append(" cost: ").append(this.cost)
.append(" adminWeight: ").append(this.adminWeight).toString();
}
}
package org.onlab.onos.optical.cfg;
/**
* ROADM java data object converted from a JSON file.
*/
class Roadm {
private String name;
private String nodeID;
private double longtitude;
private double latitude;
private int regenNum;
//TODO use the following attributes when needed for configurations
private int tPort10G;
private int tPort40G;
private int tPort100G;
private int wPort;
public Roadm() {
}
public Roadm(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setNodeId(String nameId) {
this.nodeID = nameId;
}
public String getNodeId() {
return this.nodeID;
}
public void setLongtitude(double x) {
this.longtitude = x;
}
public double getLongtitude() {
return this.longtitude;
}
public void setLatitude(double y) {
this.latitude = y;
}
public double getLatitude() {
return this.latitude;
}
public void setRegenNum(int num) {
this.regenNum = num;
}
public int getRegenNum() {
return this.regenNum;
}
public void setTport10GNum(int num) {
this.tPort10G = num;
}
public int getTport10GNum() {
return this.tPort10G;
}
public void setTport40GNum(int num) {
this.tPort40G = num;
}
public int getTport40GNum() {
return this.tPort40G;
}
public void setTport100GNum(int num) {
this.tPort100G = num;
}
public int getTport100GNum() {
return this.tPort100G;
}
public void setWportNum(int num) {
this.wPort = num;
}
public int getWportNum() {
return this.wPort;
}
@Override
public String toString() {
return new StringBuilder(" ROADM Name: ").append(this.name)
.append(" nodeID: ").append(this.nodeID)
.append(" longtitude: ").append(this.longtitude)
.append(" latitude: ").append(this.latitude)
.append(" regenNum: ").append(this.regenNum)
.append(" 10GTportNum: ").append(this.tPort10G)
.append(" 40GTportNum: ").append(this.tPort40G)
.append(" 100GTportNum: ").append(this.tPort100G)
.append(" WportNum: ").append(this.wPort).toString();
}
}
package org.onlab.onos.optical.cfg;
/**
* WDM Link Java data object converted from a JSON file.
*/
class WdmLink {
private String srcNodeName;
private String snkNodeName;
private String srcNodeId;
private String snkNodeId;
private int srcPort;
private int snkPort;
private double distance;
private double cost;
private int wavelengthNumber;
private long adminWeight;
public WdmLink(String name1, String name2) {
this.srcNodeName = name1;
this.snkNodeName = name2;
}
public WdmLink() {
// TODO Auto-generated constructor stub
}
public void setSrcNodeName(String name) {
this.srcNodeName = name;
}
public String getSrcNodeName() {
return this.srcNodeName;
}
public void setSnkNodeName(String name) {
this.snkNodeName = name;
}
public String getSnkNodeName() {
return this.snkNodeName;
}
public void setSrcNodeId(String nodeId) {
this.srcNodeId = nodeId;
}
public String getSrcNodeId() {
return this.srcNodeId;
}
public void setSnkNodeId(String nodeId) {
this.snkNodeId = nodeId;
}
public String getSnkNodeId() {
return this.snkNodeId;
}
public void setSrcPort(int port) {
this.srcPort = port;
}
public int getSrcPort() {
return this.srcPort;
}
public void setSnkPort(int port) {
this.snkPort = port;
}
public int getSnkPort() {
return this.snkPort;
}
public void setDistance(double x) {
this.distance = x;
}
public double getDistance() {
return this.distance;
}
public void setCost(double x) {
this.cost = x;
}
public double getCost() {
return this.cost;
}
public void setWavelengthNumber(int x) {
this.wavelengthNumber = x;
}
public int getWavelengthNumber() {
return this.wavelengthNumber;
}
public void setAdminWeight(long x) {
this.adminWeight = x;
}
public long getAdminWeight() {
return this.adminWeight;
}
@Override
public String toString() {
return new StringBuilder(" srcNodeName: ").append(this.srcNodeName)
.append(" snkNodeName: ").append(this.snkNodeName)
.append(" srcNodeId: ").append(this.srcNodeId)
.append(" snkNodeId: ").append(this.snkNodeId)
.append(" srcPort: ").append(this.srcPort)
.append(" snkPort: ").append(this.snkPort)
.append(" distance: ").append(this.distance)
.append(" cost: ").append(this.cost)
.append(" wavelengthNumber: ").append(this.wavelengthNumber)
.append(" adminWeight: ").append(this.adminWeight).toString();
}
}
{
"opticalSwitches": [
{
"allowed": true,
"latitude": 37.6,
"longitude": 122.3,
"name": "SFO-W10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:01",
"params": {
"numRegen": 0
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 37.3,
"longitude": 121.9,
"name": "SJC-W10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:02",
"params": {
"numRegen": 0
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 33.9,
"longitude": 118.4
"name": "LAX-W10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:03",
"params": {
"numRegen": 0
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 32.8,
"longitude": 117.1,
"name": "SDG-W10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:04",
"params": {
"numRegen": 3
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 44.8,
"longitude": 93.1,
"name": "MSP-M10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:05",
"params": {
"numRegen": 3
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 32.8,
"longitude": 97.1,
"name": "DFW-M10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:06",
"params": {
"numRegen": 3
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 41.8,
"longitude": 120.1,
"name": "CHG-N10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:07",
"params": {
"numRegen": 3
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 38.8,
"longitude": 77.1,
"name": "IAD-M10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:08",
"params": {
"numRegen": 3
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 40.8,
"longitude": 73.1,
"name": "JFK-E10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:09",
"params": {
"numRegen": 0
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 33.8,
"longitude": 84.1,
"name": "ATL-S10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:0A",
"params": {
"numRegen": 0
},
"type": "Roadm"
}
],
"opticalLinks": [
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:01",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:02",
"params": {
"distKms": 1000,
"nodeName1": "SFO-W10",
"nodeName2": "SJC-W10",
"numWaves": 80,
"port1": 10,
"port2": 10
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:02",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:03",
"params": {
"distKms": 1000,
"nodeName1": "SJC-W10",
"nodeName2": "LAX-W10",
"numWaves": 80,
"port1": 20,
"port2": 10
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:03",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:04",
"params": {
"distKms": 1000,
"nodeName1": "LAX-W10",
"nodeName2": "SDG-W10",
"numWaves": 80,
"port1": 30,
"port2": 10
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:02",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:05",
"params": {
"distKms": 4000,
"nodeName1": "SJC-W10",
"nodeName2": "MSP-M10",
"numWaves": 80,
"port1": 20,
"port2": 10
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:03",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:06",
"params": {
"distKms": 5000,
"nodeName1": "LAX-W10",
"nodeName2": "DFW-M10",
"numWaves": 80,
"port1": 20,
"port2": 10
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:05",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:06",
"params": {
"distKms": 3000,
"nodeName1": "MSP-M10",
"nodeName2": "DFW-M10",
"numWaves": 80,
"port1": 30,
"port2": 20
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:05",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:07",
"params": {
"distKms": 3000,
"nodeName1": "MSP-M10",
"nodeName2": "CHG-N10",
"numWaves": 80,
"port1": 20,
"port2": 21
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:06",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:08",
"params": {
"distKms": 4000,
"nodeName1": "DFW-M10",
"nodeName2": "IAD-M10",
"numWaves": 80,
"port1": 30,
"port2": 10
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:07",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:08",
"params": {
"distKms": 4000,
"nodeName1": "CHG-M10",
"nodeName2": "IAD-M10",
"numWaves": 80,
"port1": 30,
"port2": 20
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:07",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:09",
"params": {
"distKms": 5000,
"nodeName1": "CHG-M10",
"nodeName2": "JFK-E10",
"numWaves": 80,
"port1": 20,
"port2": 10
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:08",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:0A",
"params": {
"distKms": 3000,
"nodeName1": "IAD-M10",
"nodeName2": "ATL-S10",
"numWaves": 80,
"port1": 30,
"port2": 10
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:09",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:0A",
"params": {
"distKms": 4000,
"nodeName1": "JFK-E10",
"nodeName2": "ATL-S10",
"numWaves": 80,
"port1": 20,
"port2": 20
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:00:01",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:01",
"params": {
"nodeName1": "SFO-R10",
"nodeName2": "SFO-W10",
"port1": 10,
"port2": 1
},
"type": "pktOptLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:00:03",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:03",
"params": {
"nodeName1": "LAX-R10",
"nodeName2": "LAX-W10",
"port1": 10,
"port2": 1
},
"type": "pktOptLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:00:04",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:04",
"params": {
"nodeName1": "SDG-R10",
"nodeName2": "SDG-W10",
"port1": 10,
"port2": 1
},
"type": "pktOptLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:00:07",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:07",
"params": {
"nodeName1": "CHG-R10",
"nodeName2": "CHG-W10",
"port1": 10,
"port2": 1
},
"type": "pktOptLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:00:09",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:09",
"params": {
"nodeName1": "JFK-R10",
"nodeName2": "JFK-W10",
"port1": 10,
"port2": 1
},
"type": "pktOptLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:00:0A",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:0A",
"params": {
"nodeName1": "ATL-R10",
"nodeName2": "ATL-W10",
"port1": 10,
"port2": 1
},
"type": "pktOptLink"
},
]
}
{
"opticalSwitches": [
{
"allowed": true,
"latitude": 37.6,
"longitude": 122.3,
"name": "ROADM1",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:01",
"params": {
"numRegen": 0
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 37.3,
"longitude": 121.9,
"name": "ROADM2",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:02",
"params": {
"numRegen": 0
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 33.9,
"longitude": 118.4,
"name": "ROADM3",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:03",
"params": {
"numRegen": 2
},
"type": "Roadm"
}
],
"opticalLinks": [
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:01",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:03",
"params": {
"distKms": 1000,
"nodeName1": "ROADM1",
"nodeName2": "ROADM3",
"numWaves": 80,
"port1": 10,
"port2": 30
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:03",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:02",
"params": {
"distKms": 2000,
"nodeName1": "ROADM3",
"nodeName2": "ROADM2",
"numWaves": 80,
"port1": 31,
"port2": 20
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:00:01",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:01",
"params": {
"nodeName1": "ROUTER1",
"nodeName2": "ROADM1",
"bandWidth": 100000,
"port1": 10,
"port2": 11
},
"type": "pktOptLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:00:02",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:02",
"params": {
"nodeName1": "ROUTER2",
"nodeName2": "ROADM2",
"bandWidth": 100000,
"port1": 10,
"port2": 21
},
"type": "pktOptLink"
}
]
}
......@@ -25,6 +25,8 @@
<module>proxyarp</module>
<module>config</module>
<module>sdnip</module>
<module>calendar</module>
<module>optical</module>
</modules>
<properties>
......
......@@ -36,6 +36,36 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-thirdparty</artifactId>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-misc</artifactId>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-cli</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.console</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
......
......@@ -18,11 +18,11 @@ import com.google.common.collect.Sets;
/**
* Provides IntefaceService using PortAddresses data from the HostService.
*/
public class HostServiceBasedInterfaceService implements InterfaceService {
public class HostToInterfaceAdaptor implements InterfaceService {
private final HostService hostService;
public HostServiceBasedInterfaceService(HostService hostService) {
public HostToInterfaceAdaptor(HostService hostService) {
this.hostService = checkNotNull(hostService);
}
......
......@@ -25,10 +25,10 @@ import org.slf4j.LoggerFactory;
/**
* Manages the connectivity requirements between peers.
*/
public class PeerConnectivity {
public class PeerConnectivityManager {
private static final Logger log = LoggerFactory.getLogger(
PeerConnectivity.class);
PeerConnectivityManager.class);
// TODO these shouldn't be defined here
private static final short BGP_PORT = 179;
......@@ -41,7 +41,7 @@ public class PeerConnectivity {
// TODO this sucks.
private int intentId = 0;
public PeerConnectivity(SdnIpConfigService configInfoService,
public PeerConnectivityManager(SdnIpConfigService configInfoService,
InterfaceService interfaceService, IntentService intentService) {
this.configInfoService = configInfoService;
this.interfaceService = interfaceService;
......@@ -126,8 +126,8 @@ public class PeerConnectivity {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_TCP)
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchTcpDst(BGP_PORT)
.build();
......@@ -147,8 +147,8 @@ public class PeerConnectivity {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_TCP)
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchTcpSrc(BGP_PORT)
.build();
......@@ -165,8 +165,8 @@ public class PeerConnectivity {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_TCP)
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchTcpDst(BGP_PORT)
.build();
......@@ -183,8 +183,8 @@ public class PeerConnectivity {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_TCP)
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchTcpSrc(BGP_PORT)
.build();
......@@ -251,8 +251,8 @@ public class PeerConnectivity {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_ICMP)
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
......@@ -269,8 +269,8 @@ public class PeerConnectivity {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_ICMP)
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH))
.matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH))
.matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
.build();
PointToPointIntent reversedIntent = new PointToPointIntent(
......
package org.onlab.onos.sdnip;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Objects;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import com.google.common.base.MoreObjects;
/**
* Represents a route entry for an IP prefix.
*/
public class RouteEntry {
private final IpPrefix prefix; // The IP prefix
private final IpAddress nextHop; // Next-hop IP address
/**
* Class constructor.
*
* @param prefix the IP prefix of the route
* @param nextHop the next hop IP address for the route
*/
public RouteEntry(IpPrefix prefix, IpAddress nextHop) {
this.prefix = checkNotNull(prefix);
this.nextHop = checkNotNull(nextHop);
}
/**
* Returns the IP prefix of the route.
*
* @return the IP prefix of the route
*/
public IpPrefix prefix() {
return prefix;
}
/**
* Returns the next hop IP address for the route.
*
* @return the next hop IP address for the route
*/
public IpAddress nextHop() {
return nextHop;
}
/**
* Creates the binary string representation of an IPv4 prefix.
* The string length is equal to the prefix length.
*
* @param ip4Prefix the IPv4 prefix to use
* @return the binary string representation
*/
static String createBinaryString(IpPrefix ip4Prefix) {
if (ip4Prefix.prefixLength() == 0) {
return "";
}
StringBuilder result = new StringBuilder(ip4Prefix.prefixLength());
long value = ip4Prefix.toInt();
for (int i = 0; i < ip4Prefix.prefixLength(); i++) {
long mask = 1 << (IpAddress.MAX_INET_MASK - 1 - i);
result.append(((value & mask) == 0) ? "0" : "1");
}
return result.toString();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
//
// NOTE: Subclasses are considered as change of identity, hence
// equals() will return false if the class type doesn't match.
//
if (other == null || getClass() != other.getClass()) {
return false;
}
RouteEntry otherRoute = (RouteEntry) other;
return Objects.equals(this.prefix, otherRoute.prefix) &&
Objects.equals(this.nextHop, otherRoute.nextHop);
}
@Override
public int hashCode() {
return Objects.hash(prefix, nextHop);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("prefix", prefix)
.add("nextHop", nextHop)
.toString();
}
}
package org.onlab.onos.sdnip;
/**
* An interface to receive route updates from route providers.
*/
public interface RouteListener {
/**
* Receives a route update from a route provider.
*
* @param routeUpdate the updated route information
*/
public void update(RouteUpdate routeUpdate);
}
package org.onlab.onos.sdnip;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Objects;
import com.google.common.base.MoreObjects;
/**
* Represents a change in routing information.
*/
public class RouteUpdate {
private final Type type; // The route update type
private final RouteEntry routeEntry; // The updated route entry
/**
* Specifies the type of a route update.
* <p/>
* Route updates can either provide updated information for a route, or
* withdraw a previously updated route.
*/
public enum Type {
/**
* The update contains updated route information for a route.
*/
UPDATE,
/**
* The update withdraws the route, meaning any previous information is
* no longer valid.
*/
DELETE
}
/**
* Class constructor.
*
* @param type the type of the route update
* @param routeEntry the route entry with the update
*/
public RouteUpdate(Type type, RouteEntry routeEntry) {
this.type = type;
this.routeEntry = checkNotNull(routeEntry);
}
/**
* Returns the type of the route update.
*
* @return the type of the update
*/
public Type type() {
return type;
}
/**
* Returns the route entry the route update is for.
*
* @return the route entry the route update is for
*/
public RouteEntry routeEntry() {
return routeEntry;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof RouteUpdate)) {
return false;
}
RouteUpdate otherUpdate = (RouteUpdate) other;
return Objects.equals(this.type, otherUpdate.type) &&
Objects.equals(this.routeEntry, otherUpdate.routeEntry);
}
@Override
public int hashCode() {
return Objects.hash(type, routeEntry);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("type", type)
.add("routeEntry", routeEntry)
.toString();
}
}
This diff is collapsed. Click to expand it.
......@@ -2,21 +2,30 @@ package org.onlab.onos.sdnip;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collection;
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.host.HostService;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.sdnip.RouteUpdate.Type;
import org.onlab.onos.sdnip.bgp.BgpRouteEntry;
import org.onlab.onos.sdnip.bgp.BgpSessionManager;
import org.onlab.onos.sdnip.config.SdnIpConfigReader;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.slf4j.Logger;
/**
* Placeholder SDN-IP component.
* Component for the SDN-IP peering application.
*/
@Component(immediate = true)
public class SdnIp {
@Service
public class SdnIp implements SdnIpService {
private final Logger log = getLogger(getClass());
......@@ -27,7 +36,9 @@ public class SdnIp {
protected HostService hostService;
private SdnIpConfigReader config;
private PeerConnectivity peerConnectivity;
private PeerConnectivityManager peerConnectivity;
private Router router;
private BgpSessionManager bgpSessionManager;
@Activate
protected void activate() {
......@@ -36,15 +47,40 @@ public class SdnIp {
config = new SdnIpConfigReader();
config.init();
InterfaceService interfaceService = new HostServiceBasedInterfaceService(hostService);
InterfaceService interfaceService = new HostToInterfaceAdaptor(hostService);
peerConnectivity = new PeerConnectivity(config, interfaceService, intentService);
peerConnectivity = new PeerConnectivityManager(config, interfaceService, intentService);
peerConnectivity.start();
router = new Router(intentService, hostService, config, interfaceService);
router.start();
bgpSessionManager = new BgpSessionManager(router);
bgpSessionManager.startUp(2000); // TODO
// TODO need to disable link discovery on external ports
router.update(new RouteUpdate(Type.UPDATE, new RouteEntry(
IpPrefix.valueOf("172.16.20.0/24"),
IpAddress.valueOf("192.168.10.1"))));
}
@Deactivate
protected void deactivate() {
log.info("Stopped");
}
@Override
public Collection<BgpRouteEntry> getBgpRoutes() {
return bgpSessionManager.getBgpRoutes();
}
@Override
public Collection<RouteEntry> getRoutes() {
return router.getRoutes();
}
static String dpidToUri(String dpid) {
return "of:" + dpid.replace(":", "");
}
}
......
package org.onlab.onos.sdnip;
import java.util.Collection;
import org.onlab.onos.sdnip.bgp.BgpRouteEntry;
/**
* Service interface exported by SDN-IP.
*/
public interface SdnIpService {
/**
* Gets the BGP routes.
*
* @return the BGP routes
*/
public Collection<BgpRouteEntry> getBgpRoutes();
/**
* Gets all the routes known to SDN-IP.
*
* @return the SDN-IP routes
*/
public Collection<RouteEntry> getRoutes();
}
package org.onlab.onos.sdnip.bgp;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class for handling the decoding of the BGP messages.
*/
class BgpFrameDecoder extends FrameDecoder {
private static final Logger log =
LoggerFactory.getLogger(BgpFrameDecoder.class);
private final BgpSession bgpSession;
/**
* Constructor for a given BGP Session.
*
* @param bgpSession the BGP session state to use.
*/
BgpFrameDecoder(BgpSession bgpSession) {
this.bgpSession = bgpSession;
}
@Override
protected Object decode(ChannelHandlerContext ctx,
Channel channel,
ChannelBuffer buf) throws Exception {
//
// NOTE: If we close the channel during the decoding, we might still
// see some incoming messages while the channel closing is completed.
//
if (bgpSession.isClosed()) {
return null;
}
log.trace("BGP Peer: decode(): remoteAddr = {} localAddr = {} " +
"messageSize = {}",
ctx.getChannel().getRemoteAddress(),
ctx.getChannel().getLocalAddress(),
buf.readableBytes());
// Test for minimum length of the BGP message
if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) {
// No enough data received
return null;
}
//
// Mark the current buffer position in case we haven't received
// the whole message.
//
buf.markReaderIndex();
//
// Read and check the BGP message Marker field: it must be all ones
// (See RFC 4271, Section 4.1)
//
byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH];
buf.readBytes(marker);
for (int i = 0; i < marker.length; i++) {
if (marker[i] != (byte) 0xff) {
log.debug("BGP RX Error: invalid marker {} at position {}",
marker[i], i);
//
// ERROR: Connection Not Synchronized
//
// Send NOTIFICATION and close the connection
int errorCode = MessageHeaderError.ERROR_CODE;
int errorSubcode =
MessageHeaderError.CONNECTION_NOT_SYNCHRONIZED;
ChannelBuffer txMessage =
bgpSession.prepareBgpNotification(errorCode, errorSubcode,
null);
ctx.getChannel().write(txMessage);
bgpSession.closeChannel(ctx);
return null;
}
}
//
// Read and check the BGP message Length field
//
int length = buf.readUnsignedShort();
if ((length < BgpConstants.BGP_HEADER_LENGTH) ||
(length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) {
log.debug("BGP RX Error: invalid Length field {}. " +
"Must be between {} and {}",
length,
BgpConstants.BGP_HEADER_LENGTH,
BgpConstants.BGP_MESSAGE_MAX_LENGTH);
//
// ERROR: Bad Message Length
//
// Send NOTIFICATION and close the connection
ChannelBuffer txMessage =
bgpSession.prepareBgpNotificationBadMessageLength(length);
ctx.getChannel().write(txMessage);
bgpSession.closeChannel(ctx);
return null;
}
//
// Test whether the rest of the message is received:
// So far we have read the Marker (16 octets) and the
// Length (2 octets) fields.
//
int remainingMessageLen =
length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2;
if (buf.readableBytes() < remainingMessageLen) {
// No enough data received
buf.resetReaderIndex();
return null;
}
//
// Read the BGP message Type field, and process based on that type
//
int type = buf.readUnsignedByte();
remainingMessageLen--; // Adjust after reading the type
ChannelBuffer message = buf.readBytes(remainingMessageLen);
//
// Process the remaining of the message based on the message type
//
switch (type) {
case BgpConstants.BGP_TYPE_OPEN:
bgpSession.processBgpOpen(ctx, message);
break;
case BgpConstants.BGP_TYPE_UPDATE:
bgpSession.processBgpUpdate(ctx, message);
break;
case BgpConstants.BGP_TYPE_NOTIFICATION:
bgpSession.processBgpNotification(ctx, message);
break;
case BgpConstants.BGP_TYPE_KEEPALIVE:
bgpSession.processBgpKeepalive(ctx, message);
break;
default:
//
// ERROR: Bad Message Type
//
// Send NOTIFICATION and close the connection
int errorCode = MessageHeaderError.ERROR_CODE;
int errorSubcode = MessageHeaderError.BAD_MESSAGE_TYPE;
ChannelBuffer data = ChannelBuffers.buffer(1);
data.writeByte(type);
ChannelBuffer txMessage =
bgpSession.prepareBgpNotification(errorCode, errorSubcode,
data);
ctx.getChannel().write(txMessage);
bgpSession.closeChannel(ctx);
return null;
}
return null;
}
}
/**
* Implementation of the BGP protocol.
*/
package org.onlab.onos.sdnip.bgp;
\ No newline at end of file
package org.onlab.onos.sdnip.cli;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.sdnip.SdnIpService;
import org.onlab.onos.sdnip.bgp.BgpConstants;
import org.onlab.onos.sdnip.bgp.BgpRouteEntry;
/**
* Command to show the routes learned through BGP.
*/
@Command(scope = "onos", name = "bgp-routes",
description = "Lists all routes received from BGP")
public class BgpRoutesListCommand extends AbstractShellCommand {
private static final String FORMAT =
"prefix=%s, nexthop=%s, origin=%s, localpref=%s, med=%s, aspath=%s, bgpid=%s";
@Override
protected void execute() {
SdnIpService service = get(SdnIpService.class);
for (BgpRouteEntry route : service.getBgpRoutes()) {
printRoute(route);
}
}
private void printRoute(BgpRouteEntry route) {
if (route != null) {
print(FORMAT, route.prefix(), route.nextHop(),
originToString(route.getOrigin()), route.getLocalPref(),
route.getMultiExitDisc(), route.getAsPath(),
route.getBgpSession().getRemoteBgpId());
}
}
private static String originToString(int origin) {
String originString = "UNKNOWN";
switch (origin) {
case BgpConstants.Update.Origin.IGP:
originString = "IGP";
break;
case BgpConstants.Update.Origin.EGP:
originString = "EGP";
break;
case BgpConstants.Update.Origin.INCOMPLETE:
originString = "INCOMPLETE";
break;
default:
break;
}
return originString;
}
}
package org.onlab.onos.sdnip.cli;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.sdnip.RouteEntry;
import org.onlab.onos.sdnip.SdnIpService;
/**
* Command to show the list of routes in SDN-IP's routing table.
*/
@Command(scope = "onos", name = "routes",
description = "Lists all routes known to SDN-IP")
public class RoutesListCommand extends AbstractShellCommand {
private static final String FORMAT =
"prefix=%s, nexthop=%s";
@Override
protected void execute() {
SdnIpService service = get(SdnIpService.class);
for (RouteEntry route : service.getRoutes()) {
printRoute(route);
}
}
private void printRoute(RouteEntry route) {
if (route != null) {
print(FORMAT, route.prefix(), route.nextHop());
}
}
}
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
<command>
<action class="org.onlab.onos.sdnip.cli.BgpRoutesListCommand"/>
</command>
<command>
<action class="org.onlab.onos.sdnip.cli.RoutesListCommand"/>
</command>
</command-bundle>
</blueprint>
package org.onlab.onos.sdnip;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
/**
* Unit tests for the RouteEntry class.
*/
public class RouteEntryTest {
/**
* Tests valid class constructor.
*/
@Test
public void testConstructor() {
IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
assertThat(routeEntry.toString(),
is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
}
/**
* Tests invalid class constructor for null IPv4 prefix.
*/
@Test(expected = NullPointerException.class)
public void testInvalidConstructorNullPrefix() {
IpPrefix prefix = null;
IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
new RouteEntry(prefix, nextHop);
}
/**
* Tests invalid class constructor for null IPv4 next-hop.
*/
@Test(expected = NullPointerException.class)
public void testInvalidConstructorNullNextHop() {
IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop = null;
new RouteEntry(prefix, nextHop);
}
/**
* Tests getting the fields of a route entry.
*/
@Test
public void testGetFields() {
IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
assertThat(routeEntry.prefix(), is(prefix));
assertThat(routeEntry.nextHop(), is(nextHop));
}
/**
* Tests creating a binary string from IPv4 prefix.
*/
@Test
public void testCreateBinaryString() {
IpPrefix prefix;
prefix = IpPrefix.valueOf("0.0.0.0/0");
assertThat(RouteEntry.createBinaryString(prefix), is(""));
prefix = IpPrefix.valueOf("192.168.166.0/22");
assertThat(RouteEntry.createBinaryString(prefix),
is("1100000010101000101001"));
prefix = IpPrefix.valueOf("192.168.166.0/23");
assertThat(RouteEntry.createBinaryString(prefix),
is("11000000101010001010011"));
prefix = IpPrefix.valueOf("192.168.166.0/24");
assertThat(RouteEntry.createBinaryString(prefix),
is("110000001010100010100110"));
prefix = IpPrefix.valueOf("130.162.10.1/25");
assertThat(RouteEntry.createBinaryString(prefix),
is("1000001010100010000010100"));
prefix = IpPrefix.valueOf("255.255.255.255/32");
assertThat(RouteEntry.createBinaryString(prefix),
is("11111111111111111111111111111111"));
}
/**
* Tests equality of {@link RouteEntry}.
*/
@Test
public void testEquality() {
IpPrefix prefix1 = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop1 = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry1 = new RouteEntry(prefix1, nextHop1);
IpPrefix prefix2 = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop2 = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2);
assertThat(routeEntry1, is(routeEntry2));
}
/**
* Tests non-equality of {@link RouteEntry}.
*/
@Test
public void testNonEquality() {
IpPrefix prefix1 = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop1 = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry1 = new RouteEntry(prefix1, nextHop1);
IpPrefix prefix2 = IpPrefix.valueOf("1.2.3.0/25"); // Different
IpAddress nextHop2 = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2);
IpPrefix prefix3 = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop3 = IpAddress.valueOf("5.6.7.9"); // Different
RouteEntry routeEntry3 = new RouteEntry(prefix3, nextHop3);
assertThat(routeEntry1, is(not(routeEntry2)));
assertThat(routeEntry1, is(not(routeEntry3)));
}
/**
* Tests object string representation.
*/
@Test
public void testToString() {
IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
assertThat(routeEntry.toString(),
is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
}
}
package org.onlab.onos.sdnip.bgp;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import org.junit.Test;
/**
* Unit tests for the BgpRouteEntry.AsPath class.
*/
public class AsPathTest {
/**
* Generates an AS Path.
*
* @return a generated AS Path
*/
private BgpRouteEntry.AsPath generateAsPath() {
ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
segmentAsNumbers1.add((long) 1);
segmentAsNumbers1.add((long) 2);
segmentAsNumbers1.add((long) 3);
BgpRouteEntry.PathSegment pathSegment1 =
new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
pathSegments.add(pathSegment1);
//
byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
segmentAsNumbers2.add((long) 4);
segmentAsNumbers2.add((long) 5);
segmentAsNumbers2.add((long) 6);
BgpRouteEntry.PathSegment pathSegment2 =
new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
pathSegments.add(pathSegment2);
//
BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
return asPath;
}
/**
* Tests valid class constructor.
*/
@Test
public void testConstructor() {
BgpRouteEntry.AsPath asPath = generateAsPath();
String expectedString =
"AsPath{pathSegments=" +
"[PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}, " +
"PathSegment{type=1, segmentAsNumbers=[4, 5, 6]}]}";
assertThat(asPath.toString(), is(expectedString));
}
/**
* Tests invalid class constructor for null Path Segments.
*/
@Test(expected = NullPointerException.class)
public void testInvalidConstructorNullPathSegments() {
ArrayList<BgpRouteEntry.PathSegment> pathSegments = null;
new BgpRouteEntry.AsPath(pathSegments);
}
/**
* Tests getting the fields of an AS Path.
*/
@Test
public void testGetFields() {
// Create the fields to compare against
ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
segmentAsNumbers1.add((long) 1);
segmentAsNumbers1.add((long) 2);
segmentAsNumbers1.add((long) 3);
BgpRouteEntry.PathSegment pathSegment1 =
new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
pathSegments.add(pathSegment1);
//
byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
segmentAsNumbers2.add((long) 4);
segmentAsNumbers2.add((long) 5);
segmentAsNumbers2.add((long) 6);
BgpRouteEntry.PathSegment pathSegment2 =
new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
pathSegments.add(pathSegment2);
// Generate the entry to test
BgpRouteEntry.AsPath asPath = generateAsPath();
assertThat(asPath.getPathSegments(), is(pathSegments));
}
/**
* Tests getting the AS Path Length.
*/
@Test
public void testGetAsPathLength() {
BgpRouteEntry.AsPath asPath = generateAsPath();
assertThat(asPath.getAsPathLength(), is(4));
// Create an empty AS Path
ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
asPath = new BgpRouteEntry.AsPath(pathSegments);
assertThat(asPath.getAsPathLength(), is(0));
}
/**
* Tests equality of {@link BgpRouteEntry.AsPath}.
*/
@Test
public void testEquality() {
BgpRouteEntry.AsPath asPath1 = generateAsPath();
BgpRouteEntry.AsPath asPath2 = generateAsPath();
assertThat(asPath1, is(asPath2));
}
/**
* Tests non-equality of {@link BgpRouteEntry.AsPath}.
*/
@Test
public void testNonEquality() {
BgpRouteEntry.AsPath asPath1 = generateAsPath();
// Setup AS Path 2
ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
segmentAsNumbers1.add((long) 1);
segmentAsNumbers1.add((long) 2);
segmentAsNumbers1.add((long) 3);
BgpRouteEntry.PathSegment pathSegment1 =
new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
pathSegments.add(pathSegment1);
//
byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
segmentAsNumbers2.add((long) 4);
segmentAsNumbers2.add((long) 55); // Different
segmentAsNumbers2.add((long) 6);
BgpRouteEntry.PathSegment pathSegment2 =
new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
pathSegments.add(pathSegment2);
//
BgpRouteEntry.AsPath asPath2 = new BgpRouteEntry.AsPath(pathSegments);
assertThat(asPath1, is(not(asPath2)));
}
/**
* Tests object string representation.
*/
@Test
public void testToString() {
BgpRouteEntry.AsPath asPath = generateAsPath();
String expectedString =
"AsPath{pathSegments=" +
"[PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}, " +
"PathSegment{type=1, segmentAsNumbers=[4, 5, 6]}]}";
assertThat(asPath.toString(), is(expectedString));
}
}
package org.onlab.onos.sdnip.bgp;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import org.junit.Test;
/**
* Unit tests for the BgpRouteEntry.PathSegment class.
*/
public class PathSegmentTest {
/**
* Generates a Path Segment.
*
* @return a generated PathSegment
*/
private BgpRouteEntry.PathSegment generatePathSegment() {
byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
ArrayList<Long> segmentAsNumbers = new ArrayList<>();
segmentAsNumbers.add((long) 1);
segmentAsNumbers.add((long) 2);
segmentAsNumbers.add((long) 3);
BgpRouteEntry.PathSegment pathSegment =
new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
return pathSegment;
}
/**
* Tests valid class constructor.
*/
@Test
public void testConstructor() {
BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
String expectedString =
"PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}";
assertThat(pathSegment.toString(), is(expectedString));
}
/**
* Tests invalid class constructor for null Segment AS Numbers.
*/
@Test(expected = NullPointerException.class)
public void testInvalidConstructorNullSegmentAsNumbers() {
byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
ArrayList<Long> segmentAsNumbers = null;
new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
}
/**
* Tests getting the fields of a Path Segment.
*/
@Test
public void testGetFields() {
// Create the fields to compare against
byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
ArrayList<Long> segmentAsNumbers = new ArrayList<>();
segmentAsNumbers.add((long) 1);
segmentAsNumbers.add((long) 2);
segmentAsNumbers.add((long) 3);
// Generate the entry to test
BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
assertThat(pathSegment.getType(), is(pathSegmentType));
assertThat(pathSegment.getSegmentAsNumbers(), is(segmentAsNumbers));
}
/**
* Tests equality of {@link BgpRouteEntry.PathSegment}.
*/
@Test
public void testEquality() {
BgpRouteEntry.PathSegment pathSegment1 = generatePathSegment();
BgpRouteEntry.PathSegment pathSegment2 = generatePathSegment();
assertThat(pathSegment1, is(pathSegment2));
}
/**
* Tests non-equality of {@link BgpRouteEntry.PathSegment}.
*/
@Test
public void testNonEquality() {
BgpRouteEntry.PathSegment pathSegment1 = generatePathSegment();
// Setup Path Segment 2
byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
ArrayList<Long> segmentAsNumbers = new ArrayList<>();
segmentAsNumbers.add((long) 1);
segmentAsNumbers.add((long) 22); // Different
segmentAsNumbers.add((long) 3);
//
BgpRouteEntry.PathSegment pathSegment2 =
new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
assertThat(pathSegment1, is(not(pathSegment2)));
}
/**
* Tests object string representation.
*/
@Test
public void testToString() {
BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
String expectedString =
"PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}";
assertThat(pathSegment.toString(), is(expectedString));
}
}
package org.onlab.onos.sdnip.bgp;
import java.util.Collection;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
/**
* Class for handling the remote BGP Peer session.
*/
class TestBgpPeerChannelHandler extends SimpleChannelHandler {
static final long PEER_AS = 65001;
static final int PEER_HOLDTIME = 120; // 120 seconds
final IpAddress bgpId; // The BGP ID
final long localPref; // Local preference for routes
final long multiExitDisc = 20; // MED value
ChannelHandlerContext savedCtx;
/**
* Constructor for given BGP ID.
*
* @param bgpId the BGP ID to use
* @param localPref the local preference for the routes to use
*/
TestBgpPeerChannelHandler(IpAddress bgpId,
long localPref) {
this.bgpId = bgpId;
this.localPref = localPref;
}
/**
* Closes the channel.
*/
void closeChannel() {
savedCtx.getChannel().close();
}
@Override
public void channelConnected(ChannelHandlerContext ctx,
ChannelStateEvent channelEvent) {
this.savedCtx = ctx;
// Prepare and transmit BGP OPEN message
ChannelBuffer message = prepareBgpOpen();
ctx.getChannel().write(message);
// Prepare and transmit BGP KEEPALIVE message
message = prepareBgpKeepalive();
ctx.getChannel().write(message);
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx,
ChannelStateEvent channelEvent) {
// Nothing to do
}
/**
* Prepares BGP OPEN message.
*
* @return the message to transmit (BGP header included)
*/
ChannelBuffer prepareBgpOpen() {
ChannelBuffer message =
ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
message.writeByte(BgpConstants.BGP_VERSION);
message.writeShort((int) PEER_AS);
message.writeShort(PEER_HOLDTIME);
message.writeInt(bgpId.toInt());
message.writeByte(0); // No Optional Parameters
return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
}
/**
* Prepares BGP UPDATE message.
*
* @param nextHopRouter the next-hop router address for the routes to add
* @param addedRoutes the routes to add
* @param withdrawnRoutes the routes to withdraw
* @return the message to transmit (BGP header included)
*/
ChannelBuffer prepareBgpUpdate(IpAddress nextHopRouter,
Collection<IpPrefix> addedRoutes,
Collection<IpPrefix> withdrawnRoutes) {
int attrFlags;
ChannelBuffer message =
ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
ChannelBuffer pathAttributes =
ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
// Encode the Withdrawn Routes
ChannelBuffer encodedPrefixes = encodePackedPrefixes(withdrawnRoutes);
message.writeShort(encodedPrefixes.readableBytes());
message.writeBytes(encodedPrefixes);
// Encode the Path Attributes
// ORIGIN: IGP
attrFlags = 0x40; // Transitive flag
pathAttributes.writeByte(attrFlags);
pathAttributes.writeByte(BgpConstants.Update.Origin.TYPE);
pathAttributes.writeByte(1); // Data length
pathAttributes.writeByte(BgpConstants.Update.Origin.IGP);
// AS_PATH: Two Path Segments of 3 ASes each
attrFlags = 0x40; // Transitive flag
pathAttributes.writeByte(attrFlags);
pathAttributes.writeByte(BgpConstants.Update.AsPath.TYPE);
pathAttributes.writeByte(16); // Data length
byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
pathAttributes.writeByte(pathSegmentType1);
pathAttributes.writeByte(3); // Three ASes
pathAttributes.writeShort(65010); // AS=65010
pathAttributes.writeShort(65020); // AS=65020
pathAttributes.writeShort(65030); // AS=65030
byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
pathAttributes.writeByte(pathSegmentType2);
pathAttributes.writeByte(3); // Three ASes
pathAttributes.writeShort(65041); // AS=65041
pathAttributes.writeShort(65042); // AS=65042
pathAttributes.writeShort(65043); // AS=65043
// NEXT_HOP: nextHopRouter
attrFlags = 0x40; // Transitive flag
pathAttributes.writeByte(attrFlags);
pathAttributes.writeByte(BgpConstants.Update.NextHop.TYPE);
pathAttributes.writeByte(4); // Data length
pathAttributes.writeInt(nextHopRouter.toInt()); // Next-hop router
// LOCAL_PREF: localPref
attrFlags = 0x40; // Transitive flag
pathAttributes.writeByte(attrFlags);
pathAttributes.writeByte(BgpConstants.Update.LocalPref.TYPE);
pathAttributes.writeByte(4); // Data length
pathAttributes.writeInt((int) localPref); // Preference value
// MULTI_EXIT_DISC: multiExitDisc
attrFlags = 0x80; // Optional
// Non-Transitive flag
pathAttributes.writeByte(attrFlags);
pathAttributes.writeByte(BgpConstants.Update.MultiExitDisc.TYPE);
pathAttributes.writeByte(4); // Data length
pathAttributes.writeInt((int) multiExitDisc); // Preference value
// The NLRI prefixes
encodedPrefixes = encodePackedPrefixes(addedRoutes);
// Write the Path Attributes, beginning with its length
message.writeShort(pathAttributes.readableBytes());
message.writeBytes(pathAttributes);
message.writeBytes(encodedPrefixes);
return prepareBgpMessage(BgpConstants.BGP_TYPE_UPDATE, message);
}
/**
* Encodes a collection of IPv4 network prefixes in a packed format.
* <p>
* The IPv4 prefixes are encoded in the form:
* <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
* and Prefix is the IPv4 prefix (padded with trailing bits to the end
* of an octet).
*
* @param prefixes the prefixes to encode
* @return the buffer with the encoded prefixes
*/
private ChannelBuffer encodePackedPrefixes(Collection<IpPrefix> prefixes) {
ChannelBuffer message =
ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
// Write each of the prefixes
for (IpPrefix prefix : prefixes) {
int prefixBitlen = prefix.prefixLength();
int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
message.writeByte(prefixBitlen);
IpAddress address = prefix.toIpAddress();
long value = address.toInt() & 0xffffffffL;
for (int i = 0; i < IpAddress.INET_LEN; i++) {
if (prefixBytelen-- == 0) {
break;
}
long nextByte =
(value >> ((IpAddress.INET_LEN - i - 1) * 8)) & 0xff;
message.writeByte((int) nextByte);
}
}
return message;
}
/**
* Prepares BGP KEEPALIVE message.
*
* @return the message to transmit (BGP header included)
*/
ChannelBuffer prepareBgpKeepalive() {
ChannelBuffer message =
ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
}
/**
* Prepares BGP NOTIFICATION message.
*
* @param errorCode the BGP NOTIFICATION Error Code
* @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
* otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
* @param payload the BGP NOTIFICATION Data if applicable, otherwise null
* @return the message to transmit (BGP header included)
*/
ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
ChannelBuffer data) {
ChannelBuffer message =
ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
// Prepare the NOTIFICATION message payload
message.writeByte(errorCode);
message.writeByte(errorSubcode);
if (data != null) {
message.writeBytes(data);
}
return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
}
/**
* Prepares BGP message.
*
* @param type the BGP message type
* @param payload the message payload to transmit (BGP header excluded)
* @return the message to transmit (BGP header included)
*/
private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
ChannelBuffer message =
ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
payload.readableBytes());
// Write the marker
for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
message.writeByte(0xff);
}
// Write the rest of the BGP header
message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
payload.readableBytes());
message.writeByte(type);
// Write the payload
message.writeBytes(payload);
return message;
}
}
package org.onlab.onos.sdnip.bgp;
import java.util.concurrent.CountDownLatch;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import org.onlab.packet.IpAddress;
/**
* Class for handling the decoding of the BGP messages at the remote
* BGP peer session.
*/
class TestBgpPeerFrameDecoder extends FrameDecoder {
int remoteBgpVersion; // 1 octet
long remoteAs; // 2 octets
long remoteHoldtime; // 2 octets
IpAddress remoteBgpIdentifier; // 4 octets -> IPv4 address
final CountDownLatch receivedOpenMessageLatch = new CountDownLatch(1);
final CountDownLatch receivedKeepaliveMessageLatch = new CountDownLatch(1);
@Override
protected Object decode(ChannelHandlerContext ctx,
Channel channel,
ChannelBuffer buf) throws Exception {
// Test for minimum length of the BGP message
if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) {
// No enough data received
return null;
}
//
// Mark the current buffer position in case we haven't received
// the whole message.
//
buf.markReaderIndex();
//
// Read and check the BGP message Marker field: it must be all ones
//
byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH];
buf.readBytes(marker);
for (int i = 0; i < marker.length; i++) {
if (marker[i] != (byte) 0xff) {
// ERROR: Connection Not Synchronized. Close the channel.
ctx.getChannel().close();
return null;
}
}
//
// Read and check the BGP message Length field
//
int length = buf.readUnsignedShort();
if ((length < BgpConstants.BGP_HEADER_LENGTH) ||
(length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) {
// ERROR: Bad Message Length. Close the channel.
ctx.getChannel().close();
return null;
}
//
// Test whether the rest of the message is received:
// So far we have read the Marker (16 octets) and the
// Length (2 octets) fields.
//
int remainingMessageLen =
length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2;
if (buf.readableBytes() < remainingMessageLen) {
// No enough data received
buf.resetReaderIndex();
return null;
}
//
// Read the BGP message Type field, and process based on that type
//
int type = buf.readUnsignedByte();
remainingMessageLen--; // Adjust after reading the type
ChannelBuffer message = buf.readBytes(remainingMessageLen);
//
// Process the remaining of the message based on the message type
//
switch (type) {
case BgpConstants.BGP_TYPE_OPEN:
processBgpOpen(ctx, message);
break;
case BgpConstants.BGP_TYPE_UPDATE:
// NOTE: Not used as part of the test, because ONOS does not
// originate UPDATE messages.
break;
case BgpConstants.BGP_TYPE_NOTIFICATION:
// NOTE: Not used as part of the testing (yet)
break;
case BgpConstants.BGP_TYPE_KEEPALIVE:
processBgpKeepalive(ctx, message);
break;
default:
// ERROR: Bad Message Type. Close the channel.
ctx.getChannel().close();
return null;
}
return null;
}
/**
* Processes BGP OPEN message.
*
* @param ctx the Channel Handler Context.
* @param message the message to process.
*/
private void processBgpOpen(ChannelHandlerContext ctx,
ChannelBuffer message) {
int minLength =
BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
if (message.readableBytes() < minLength) {
// ERROR: Bad Message Length. Close the channel.
ctx.getChannel().close();
return;
}
//
// Parse the OPEN message
//
remoteBgpVersion = message.readUnsignedByte();
remoteAs = message.readUnsignedShort();
remoteHoldtime = message.readUnsignedShort();
remoteBgpIdentifier = IpAddress.valueOf((int) message.readUnsignedInt());
// Optional Parameters
int optParamLen = message.readUnsignedByte();
if (message.readableBytes() < optParamLen) {
// ERROR: Bad Message Length. Close the channel.
ctx.getChannel().close();
return;
}
message.readBytes(optParamLen); // NOTE: data ignored
// BGP OPEN message successfully received
receivedOpenMessageLatch.countDown();
}
/**
* Processes BGP KEEPALIVE message.
*
* @param ctx the Channel Handler Context.
* @param message the message to process.
*/
private void processBgpKeepalive(ChannelHandlerContext ctx,
ChannelBuffer message) {
if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
// ERROR: Bad Message Length. Close the channel.
ctx.getChannel().close();
return;
}
// BGP KEEPALIVE message successfully received
receivedKeepaliveMessageLatch.countDown();
}
}
......@@ -26,6 +26,16 @@
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-osgi</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
......
package org.onlab.onos.cli;
import org.apache.karaf.shell.commands.Option;
import org.apache.karaf.shell.console.OsgiCommandSupport;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceNotFoundException;
......@@ -9,6 +10,10 @@ import org.onlab.osgi.ServiceNotFoundException;
*/
public abstract class AbstractShellCommand extends OsgiCommandSupport {
@Option(name = "-j", aliases = "--json", description = "Output JSON",
required = false, multiValued = false)
private boolean json = false;
/**
* Returns the reference to the implementation of the specified service.
*
......@@ -46,6 +51,15 @@ public abstract class AbstractShellCommand extends OsgiCommandSupport {
*/
protected abstract void execute();
/**
* Indicates whether JSON format should be output.
*
* @return true if JSON is requested
*/
protected boolean outputJson() {
return json;
}
@Override
protected Object doExecute() throws Exception {
try {
......
package org.onlab.onos.cli;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cluster.ClusterService;
import org.onlab.onos.cluster.ControllerNode;
......@@ -26,7 +28,10 @@ public class MastersListCommand extends AbstractShellCommand {
MastershipService mastershipService = get(MastershipService.class);
List<ControllerNode> nodes = newArrayList(service.getNodes());
Collections.sort(nodes, Comparators.NODE_COMPARATOR);
ControllerNode self = service.getLocalNode();
if (outputJson()) {
print("%s", json(service, mastershipService, nodes));
} else {
for (ControllerNode node : nodes) {
List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id()));
Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR);
......@@ -36,5 +41,37 @@ public class MastersListCommand extends AbstractShellCommand {
}
}
}
}
// Produces JSON structure.
private JsonNode json(ClusterService service, MastershipService mastershipService,
List<ControllerNode> nodes) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
ControllerNode self = service.getLocalNode();
for (ControllerNode node : nodes) {
List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id()));
result.add(mapper.createObjectNode()
.put("id", node.id().toString())
.put("size", ids.size())
.set("devices", json(mapper, ids)));
}
return result;
}
/**
* Produces a JSON array containing the specified device identifiers.
*
* @param mapper object mapper
* @param ids collection of device identifiers
* @return JSON array
*/
public static JsonNode json(ObjectMapper mapper, Iterable<DeviceId> ids) {
ArrayNode result = mapper.createArrayNode();
for (DeviceId deviceId : ids) {
result.add(deviceId.toString());
}
return result;
}
}
......
package org.onlab.onos.cli;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cluster.ClusterService;
import org.onlab.onos.cluster.ControllerNode;
......@@ -24,6 +27,9 @@ public class NodesListCommand extends AbstractShellCommand {
ClusterService service = get(ClusterService.class);
List<ControllerNode> nodes = newArrayList(service.getNodes());
Collections.sort(nodes, Comparators.NODE_COMPARATOR);
if (outputJson()) {
print("%s", json(service, nodes));
} else {
ControllerNode self = service.getLocalNode();
for (ControllerNode node : nodes) {
print(FMT, node.id(), node.ip(), node.tcpPort(),
......@@ -31,5 +37,22 @@ public class NodesListCommand extends AbstractShellCommand {
node.equals(self) ? "*" : "");
}
}
}
// Produces JSON structure.
private JsonNode json(ClusterService service, List<ControllerNode> nodes) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
ControllerNode self = service.getLocalNode();
for (ControllerNode node : nodes) {
result.add(mapper.createObjectNode()
.put("id", node.id().toString())
.put("ip", node.ip().toString())
.put("tcpPort", node.tcpPort())
.put("state", service.getState(node.id()).toString())
.put("self", node.equals(self)));
}
return result;
}
}
......
package org.onlab.onos.cli;
import static com.google.common.collect.Lists.newArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.mastership.MastershipService;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.device.DeviceService;
/**
* Lists mastership roles of nodes for each device.
*/
@Command(scope = "onos", name = "roles",
description = "Lists mastership roles of nodes for each device.")
public class RolesCommand extends AbstractShellCommand {
private static final String FMT_HDR = "%s: master=%s\nstandbys: %s nodes";
private static final String FMT_SB = "\t%s";
@Override
protected void execute() {
DeviceService deviceService = get(DeviceService.class);
MastershipService roleService = get(MastershipService.class);
for (Device d : getSortedDevices(deviceService)) {
DeviceId did = d.id();
printRoles(roleService, did);
}
}
/**
* Returns the list of devices sorted using the device ID URIs.
*
* @param service device service
* @return sorted device list
*/
protected static List<Device> getSortedDevices(DeviceService service) {
List<Device> devices = newArrayList(service.getDevices());
Collections.sort(devices, Comparators.ELEMENT_COMPARATOR);
return devices;
}
/**
* Prints the role information for a device.
*
* @param deviceId the ID of the device
* @param master the current master
*/
protected void printRoles(MastershipService service, DeviceId deviceId) {
List<NodeId> nodes = service.getNodesFor(deviceId);
NodeId first = null;
NodeId master = null;
if (!nodes.isEmpty()) {
first = nodes.get(0);
}
if (first != null &&
first.equals(service.getMasterFor(deviceId))) {
master = nodes.get(0);
nodes.remove(master);
}
print(FMT_HDR, deviceId, master == null ? "NONE" : master, nodes.size());
for (NodeId nid : nodes) {
print(FMT_SB, nid);
}
}
}
package org.onlab.onos.cli;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.CoreService;
import org.onlab.onos.cluster.ClusterService;
......@@ -22,6 +23,19 @@ public class SummaryCommand extends AbstractShellCommand {
protected void execute() {
TopologyService topologyService = get(TopologyService.class);
Topology topology = topologyService.currentTopology();
if (outputJson()) {
print("%s", new ObjectMapper().createObjectNode()
.put("node", get(ClusterService.class).getLocalNode().ip().toString())
.put("version", get(CoreService.class).version().toString())
.put("nodes", get(ClusterService.class).getNodes().size())
.put("devices", get(DeviceService.class).getDeviceCount())
.put("links", get(LinkService.class).getLinkCount())
.put("hosts", get(HostService.class).getHostCount())
.put("clusters", topologyService.getClusters(topology).size())
.put("paths", topology.pathCount())
.put("flows", get(FlowRuleService.class).getFlowRuleCount())
.put("intents", get(IntentService.class).getIntentCount()));
} else {
print("node=%s, version=%s",
get(ClusterService.class).getLocalNode().ip(),
get(CoreService.class).version().toString());
......@@ -35,5 +49,6 @@ public class SummaryCommand extends AbstractShellCommand {
get(FlowRuleService.class).getFlowRuleCount(),
get(IntentService.class).getIntentCount());
}
}
}
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
......@@ -10,6 +11,7 @@ import org.onlab.onos.net.topology.TopologyCluster;
import java.util.Collections;
import java.util.List;
import static org.onlab.onos.cli.MastersListCommand.json;
import static org.onlab.onos.net.topology.ClusterId.clusterId;
/**
......@@ -33,11 +35,14 @@ public class ClusterDevicesCommand extends ClustersListCommand {
} else {
List<DeviceId> ids = Lists.newArrayList(service.getClusterDevices(topology, cluster));
Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR);
if (outputJson()) {
print("%s", json(new ObjectMapper(), ids));
} else {
for (DeviceId deviceId : ids) {
print("%s", deviceId);
}
}
}
}
}
......
......@@ -5,6 +5,7 @@ import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.topology.TopologyCluster;
import static org.onlab.onos.cli.net.LinksListCommand.json;
import static org.onlab.onos.cli.net.LinksListCommand.linkString;
import static org.onlab.onos.net.topology.ClusterId.clusterId;
......@@ -26,6 +27,8 @@ public class ClusterLinksCommand extends ClustersListCommand {
TopologyCluster cluster = service.getCluster(topology, clusterId(cid));
if (cluster == null) {
error("No such cluster %s", cid);
} else if (outputJson()) {
print("%s", json(service.getClusterLinks(topology, cluster)));
} else {
for (Link link : service.getClusterLinks(topology, cluster)) {
print(linkString(link));
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.Comparators;
......@@ -24,9 +27,26 @@ public class ClustersListCommand extends TopologyCommand {
List<TopologyCluster> clusters = Lists.newArrayList(service.getClusters(topology));
Collections.sort(clusters, Comparators.CLUSTER_COMPARATOR);
if (outputJson()) {
print("%s", json(clusters));
} else {
for (TopologyCluster cluster : clusters) {
print(FMT, cluster.id().index(), cluster.deviceCount(), cluster.linkCount());
}
}
}
// Produces a JSON result.
private JsonNode json(Iterable<TopologyCluster> clusters) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (TopologyCluster cluster : clusters) {
result.add(mapper.createObjectNode()
.put("id", cluster.id().index())
.put("deviceCount", cluster.deviceCount())
.put("linkCount", cluster.linkCount()));
}
return result;
}
}
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
import org.onlab.onos.cli.Comparators;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.Port;
......@@ -22,6 +27,14 @@ public class DevicePortsListCommand extends DevicesListCommand {
private static final String FMT = " port=%s, state=%s";
@Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports",
required = false, multiValued = false)
private boolean enabled = false;
@Option(name = "-d", aliases = "--disabled", description = "Show only disabled ports",
required = false, multiValued = false)
private boolean disabled = false;
@Argument(index = 0, name = "uri", description = "Device ID",
required = false, multiValued = false)
String uri = null;
......@@ -30,27 +43,79 @@ public class DevicePortsListCommand extends DevicesListCommand {
protected void execute() {
DeviceService service = get(DeviceService.class);
if (uri == null) {
if (outputJson()) {
print("%s", jsonPorts(service, getSortedDevices(service)));
} else {
for (Device device : getSortedDevices(service)) {
printDevice(service, device);
}
}
} else {
Device device = service.getDevice(deviceId(uri));
if (device == null) {
error("No such device %s", uri);
} else if (outputJson()) {
print("%s", jsonPorts(service, new ObjectMapper(), device));
} else {
printDevice(service, device);
}
}
}
/**
* Produces JSON array containing ports of the specified devices.
*
* @param service device service
* @param devices collection of devices
* @return JSON array
*/
public JsonNode jsonPorts(DeviceService service, Iterable<Device> devices) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Device device : devices) {
result.add(jsonPorts(service, mapper, device));
}
return result;
}
/**
* Produces JSON array containing ports of the specified device.
*
* @param service device service
* @param mapper object mapper
* @param device infrastructure devices
* @return JSON array
*/
public JsonNode jsonPorts(DeviceService service, ObjectMapper mapper, Device device) {
ObjectNode result = mapper.createObjectNode();
ArrayNode ports = mapper.createArrayNode();
for (Port port : service.getPorts(device.id())) {
if (isIncluded(port)) {
ports.add(mapper.createObjectNode()
.put("port", port.number().toString())
.put("isEnabled", port.isEnabled()));
}
}
return result.put("device", device.id().toString()).set("ports", ports);
}
// Determines if a port should be included in output.
private boolean isIncluded(Port port) {
return enabled && port.isEnabled() || disabled && !port.isEnabled() ||
!enabled && !disabled;
}
@Override
protected void printDevice(DeviceService service, Device device) {
super.printDevice(service, device);
List<Port> ports = new ArrayList<>(service.getPorts(device.id()));
Collections.sort(ports, Comparators.PORT_COMPARATOR);
for (Port port : ports) {
if (isIncluded(port)) {
print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled");
}
}
}
}
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.cli.Comparators;
......@@ -24,10 +28,53 @@ public class DevicesListCommand extends AbstractShellCommand {
@Override
protected void execute() {
DeviceService service = get(DeviceService.class);
if (outputJson()) {
print("%s", json(service, getSortedDevices(service)));
} else {
for (Device device : getSortedDevices(service)) {
printDevice(service, device);
}
}
}
/**
* Returns JSON node representing the specified devices.
*
* @param service device service
* @param devices collection of devices
* @return JSON node
*/
public static JsonNode json(DeviceService service, Iterable<Device> devices) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Device device : devices) {
result.add(json(service, mapper, device));
}
return result;
}
/**
* Returns JSON node representing the specified device.
*
* @param service device service
* @param mapper object mapper
* @param device infrastructure device
* @return JSON node
*/
public static ObjectNode json(DeviceService service, ObjectMapper mapper,
Device device) {
ObjectNode result = mapper.createObjectNode();
if (device != null) {
result.put("id", device.id().toString())
.put("available", service.isAvailable(device.id()))
.put("role", service.getRole(device.id()).toString())
.put("mfr", device.manufacturer())
.put("hw", device.hwVersion())
.put("sw", device.swVersion())
.put("serial", device.serialNumber());
}
return result;
}
/**
* Returns the list of devices sorted using the device ID URIs.
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Maps;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
......@@ -12,6 +16,8 @@ import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.flow.FlowEntry;
import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
import org.onlab.onos.net.flow.FlowRuleService;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.onos.net.flow.instructions.Instruction;
import java.util.Collections;
import java.util.List;
......@@ -48,10 +54,74 @@ public class FlowsListCommand extends AbstractShellCommand {
DeviceService deviceService = get(DeviceService.class);
FlowRuleService service = get(FlowRuleService.class);
Map<Device, List<FlowEntry>> flows = getSortedFlows(deviceService, service);
if (outputJson()) {
print("%s", json(coreService, getSortedDevices(deviceService), flows));
} else {
for (Device d : getSortedDevices(deviceService)) {
printFlows(d, flows.get(d), coreService);
}
}
}
/**
* Produces a JSON array of flows grouped by the each device.
*
* @param coreService core service
* @param devices collection of devices to group flow by
* @param flows collection of flows per each device
* @return JSON array
*/
private JsonNode json(CoreService coreService, Iterable<Device> devices,
Map<Device, List<FlowEntry>> flows) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Device device : devices) {
result.add(json(coreService, mapper, device, flows.get(device)));
}
return result;
}
// Produces JSON object with the flows of the given device.
private ObjectNode json(CoreService coreService, ObjectMapper mapper,
Device device, List<FlowEntry> flows) {
ObjectNode result = mapper.createObjectNode();
ArrayNode array = mapper.createArrayNode();
for (FlowEntry flow : flows) {
array.add(json(coreService, mapper, flow));
}
result.put("device", device.id().toString())
.put("flowCount", flows.size())
.set("flows", array);
return result;
}
// Produces JSON structure with the specified flow data.
private ObjectNode json(CoreService coreService, ObjectMapper mapper,
FlowEntry flow) {
ObjectNode result = mapper.createObjectNode();
ArrayNode crit = mapper.createArrayNode();
for (Criterion c : flow.selector().criteria()) {
crit.add(c.toString());
}
ArrayNode instr = mapper.createArrayNode();
for (Instruction i : flow.treatment().instructions()) {
instr.add(i.toString());
}
result.put("flowId", Long.toHexString(flow.id().value()))
.put("state", flow.state().toString())
.put("bytes", flow.bytes())
.put("packets", flow.packets())
.put("life", flow.life())
.put("appId", coreService.getAppId(flow.appId()).name());
result.set("selector", crit);
result.set("treatment", instr);
return result;
}
/**
* Returns the list of devices sorted using the device ID URIs.
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.cli.Comparators;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.host.HostService;
import org.onlab.packet.IpPrefix;
import java.util.Collections;
import java.util.List;
......@@ -24,10 +29,41 @@ public class HostsListCommand extends AbstractShellCommand {
@Override
protected void execute() {
HostService service = get(HostService.class);
if (outputJson()) {
print("%s", json(getSortedHosts(service)));
} else {
for (Host host : getSortedHosts(service)) {
printHost(host);
}
}
}
// Produces JSON structure.
private static JsonNode json(Iterable<Host> hosts) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Host host : hosts) {
result.add(json(mapper, host));
}
return result;
}
// Produces JSON structure.
private static JsonNode json(ObjectMapper mapper, Host host) {
ObjectNode loc = LinksListCommand.json(mapper, host.location())
.put("time", host.location().time());
ArrayNode ips = mapper.createArrayNode();
for (IpPrefix ip : host.ipAddresses()) {
ips.add(ip.toString());
}
ObjectNode result = mapper.createObjectNode()
.put("id", host.id().toString())
.put("mac", host.mac().toString())
.put("vlan", host.vlan().toString());
result.set("location", loc);
result.set("ips", ips);
return result;
}
/**
* Returns the list of devices sorted using the device ID URIs.
......@@ -44,7 +80,7 @@ public class HostsListCommand extends AbstractShellCommand {
/**
* Prints information about a host.
*
* @param host
* @param host end-station host
*/
protected void printHost(Host host) {
if (host != null) {
......@@ -54,4 +90,4 @@ public class HostsListCommand extends AbstractShellCommand {
host.vlan(), host.ipAddresses());
}
}
}
}
......
......@@ -90,11 +90,15 @@ public class IntentPushTestCommand extends AbstractShellCommand
service.submit(intent);
}
try {
latch.await(5, TimeUnit.SECONDS);
if (latch.await(10, TimeUnit.SECONDS)) {
printResults(count);
} else {
print("I FAIL MISERABLY -> %d", latch.getCount());
}
} catch (InterruptedException e) {
print(e.toString());
}
service.removeListener(this);
}
......@@ -140,6 +144,8 @@ public class IntentPushTestCommand extends AbstractShellCommand
} else {
log.warn("install event latch is null");
}
} else {
log.info("I FAIL -> {}", event);
}
}
}
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.link.LinkService;
......@@ -27,10 +32,56 @@ public class LinksListCommand extends AbstractShellCommand {
LinkService service = get(LinkService.class);
Iterable<Link> links = uri != null ?
service.getDeviceLinks(deviceId(uri)) : service.getLinks();
if (outputJson()) {
print("%s", json(links));
} else {
for (Link link : links) {
print(linkString(link));
}
}
}
/**
* Produces a JSON array containing the specified links.
*
* @param links collection of links
* @return JSON array
*/
public static JsonNode json(Iterable<Link> links) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Link link : links) {
result.add(json(mapper, link));
}
return result;
}
/**
* Produces a JSON object for the specified link.
*
* @param mapper object mapper
* @param link link to encode
* @return JSON object
*/
public static ObjectNode json(ObjectMapper mapper, Link link) {
ObjectNode result = mapper.createObjectNode();
result.set("src", json(mapper, link.src()));
result.set("dst", json(mapper, link.dst()));
return result;
}
/**
* Produces a JSON object for the specified connect point.
*
* @param mapper object mapper
* @param connectPoint connection point to encode
* @return JSON object
*/
public static ObjectNode json(ObjectMapper mapper, ConnectPoint connectPoint) {
return mapper.createObjectNode()
.put("device", connectPoint.deviceId().toString())
.put("port", connectPoint.port().toString());
}
/**
* Returns a formatted string representing the given link.
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.net.Link;
......@@ -32,10 +35,31 @@ public class PathListCommand extends TopologyCommand {
protected void execute() {
init();
Set<Path> paths = service.getPaths(topology, deviceId(src), deviceId(dst));
if (outputJson()) {
print("%s", json(paths));
} else {
for (Path path : paths) {
print(pathString(path));
}
}
}
/**
* Produces a JSON array containing the specified paths.
*
* @param paths collection of paths
* @return JSON array
*/
public static JsonNode json(Iterable<Path> paths) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (Path path : paths) {
result.add(LinksListCommand.json(mapper, path)
.put("cost", path.cost())
.set("links", LinksListCommand.json(path.links())));
}
return result;
}
/**
* Produces a formatted string representing the specified path.
......
package org.onlab.onos.cli.net;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.net.topology.Topology;
......@@ -30,8 +31,17 @@ public class TopologyCommand extends AbstractShellCommand {
@Override
protected void execute() {
init();
if (outputJson()) {
print("%s", new ObjectMapper().createObjectNode()
.put("time", topology.time())
.put("deviceCount", topology.deviceCount())
.put("linkCount", topology.linkCount())
.put("clusterCount", topology.clusterCount())
.put("pathCount", topology.pathCount()));
} else {
print(FMT, topology.time(), topology.deviceCount(), topology.linkCount(),
topology.clusterCount(), topology.pathCount());
}
}
}
......
......@@ -13,6 +13,10 @@
<command>
<action class="org.onlab.onos.cli.NodeRemoveCommand"/>
</command>
<command>
<action class="org.onlab.onos.cli.RolesCommand"/>
</command>
<command>
<action class="org.onlab.onos.cli.MastersListCommand"/>
<completers>
......
......@@ -12,8 +12,12 @@ public final class ControllerNodeToNodeId
@Override
public NodeId apply(ControllerNode input) {
if (input == null) {
return null;
} else {
return input.id();
}
}
/**
* Returns a Function to convert ControllerNode to NodeId.
......
package org.onlab.onos.mastership;
import java.util.List;
import java.util.Set;
import org.onlab.onos.cluster.NodeId;
......@@ -50,6 +51,15 @@ public interface MastershipService {
NodeId getMasterFor(DeviceId deviceId);
/**
* Returns controllers connected to a given device, in order of
* preference. The first entry in the list is the current master.
*
* @param deviceId the identifier of the device
* @return a list of controller IDs
*/
List<NodeId> getNodesFor(DeviceId deviceId);
/**
* Returns the devices for which a controller is master.
*
* @param nodeId the ID of the controller
......
package org.onlab.onos.mastership;
import java.util.List;
import java.util.Set;
import org.onlab.onos.cluster.NodeId;
......@@ -41,6 +42,15 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD
NodeId getMaster(DeviceId deviceId);
/**
* Returns the controllers connected to a device, in mastership-
* preference order.
*
* @param deviceId the device identifier
* @return an ordered list of controller IDs
*/
List<NodeId> getNodes(DeviceId deviceId);
/**
* Returns the devices that a controller instance is master of.
*
* @param nodeId the instance identifier
......@@ -48,6 +58,7 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD
*/
Set<DeviceId> getDevices(NodeId nodeId);
/**
* Sets a device's role for a specified controller instance.
*
......
package org.onlab.onos.net;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.packet.ChassisId;
import java.util.Objects;
......@@ -16,6 +17,7 @@ public class DefaultDevice extends AbstractElement implements Device {
private final String serialNumber;
private final String hwVersion;
private final String swVersion;
private final ChassisId chassisId;
// For serialization
private DefaultDevice() {
......@@ -24,6 +26,7 @@ public class DefaultDevice extends AbstractElement implements Device {
this.hwVersion = null;
this.swVersion = null;
this.serialNumber = null;
this.chassisId = null;
}
/**
......@@ -40,13 +43,15 @@ public class DefaultDevice extends AbstractElement implements Device {
*/
public DefaultDevice(ProviderId providerId, DeviceId id, Type type,
String manufacturer, String hwVersion, String swVersion,
String serialNumber, Annotations... annotations) {
String serialNumber, ChassisId chassisId,
Annotations... annotations) {
super(providerId, id, annotations);
this.type = type;
this.manufacturer = manufacturer;
this.hwVersion = hwVersion;
this.swVersion = swVersion;
this.serialNumber = serialNumber;
this.chassisId = chassisId;
}
@Override
......@@ -80,6 +85,11 @@ public class DefaultDevice extends AbstractElement implements Device {
}
@Override
public ChassisId chassisId() {
return chassisId;
}
@Override
public int hashCode() {
return Objects.hash(id, type, manufacturer, hwVersion, swVersion, serialNumber);
}
......
package org.onlab.onos.net;
import org.onlab.packet.ChassisId;
/**
* Representation of a network infrastructure device.
*/
......@@ -54,6 +56,13 @@ public interface Device extends Element {
*/
String serialNumber();
/**
* Returns the device chassis id.
*
* @return chassis id
*/
ChassisId chassisId();
// Device realizedBy(); ?
// ports are not provided directly, but rather via DeviceService.getPorts(Device device);
......
......@@ -2,6 +2,7 @@ package org.onlab.onos.net.device;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.SparseAnnotations;
import org.onlab.packet.ChassisId;
import java.net.URI;
......@@ -20,6 +21,7 @@ public class DefaultDeviceDescription extends AbstractDescription
private final String hwVersion;
private final String swVersion;
private final String serialNumber;
private final ChassisId chassisId;
/**
* Creates a device description using the supplied information.
......@@ -34,7 +36,7 @@ public class DefaultDeviceDescription extends AbstractDescription
*/
public DefaultDeviceDescription(URI uri, Type type, String manufacturer,
String hwVersion, String swVersion,
String serialNumber,
String serialNumber, ChassisId chassis,
SparseAnnotations... annotations) {
super(annotations);
this.uri = checkNotNull(uri, "Device URI cannot be null");
......@@ -43,6 +45,7 @@ public class DefaultDeviceDescription extends AbstractDescription
this.hwVersion = hwVersion;
this.swVersion = swVersion;
this.serialNumber = serialNumber;
this.chassisId = chassis;
}
/**
......@@ -54,7 +57,7 @@ public class DefaultDeviceDescription extends AbstractDescription
SparseAnnotations... annotations) {
this(base.deviceURI(), base.type(), base.manufacturer(),
base.hwVersion(), base.swVersion(), base.serialNumber(),
annotations);
base.chassisId(), annotations);
}
@Override
......@@ -88,6 +91,11 @@ public class DefaultDeviceDescription extends AbstractDescription
}
@Override
public ChassisId chassisId() {
return chassisId;
}
@Override
public String toString() {
return toStringHelper(this)
.add("uri", uri).add("type", type).add("mfr", manufacturer)
......@@ -104,5 +112,6 @@ public class DefaultDeviceDescription extends AbstractDescription
this.hwVersion = null;
this.swVersion = null;
this.serialNumber = null;
this.chassisId = null;
}
}
......
......@@ -2,6 +2,7 @@ package org.onlab.onos.net.device;
import org.onlab.onos.net.Description;
import org.onlab.onos.net.Device;
import org.onlab.packet.ChassisId;
import java.net.URI;
......@@ -54,4 +55,11 @@ public interface DeviceDescription extends Description {
*/
String serialNumber();
/**
* Returns a device chassis id.
*
* @return chassis id
*/
ChassisId chassisId();
}
......
......@@ -6,9 +6,10 @@ import static org.slf4j.LoggerFactory.getLogger;
import org.onlab.onos.net.DeviceId;
import org.slf4j.Logger;
public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
public class DefaultFlowEntry extends DefaultFlowRule
implements FlowEntry, StoredFlowEntry {
private final Logger log = getLogger(getClass());
private static final Logger log = getLogger(DefaultFlowEntry.class);
private long life;
private long packets;
......
......@@ -11,7 +11,7 @@ import org.slf4j.Logger;
public class DefaultFlowRule implements FlowRule {
private final Logger log = getLogger(getClass());
private static final Logger log = getLogger(DefaultFlowRule.class);
private final DeviceId deviceId;
private final int priority;
......
......@@ -65,6 +65,7 @@ public interface FlowEntry extends FlowRule {
*/
long bytes();
// TODO: consider removing this attribute
/**
* When this flow entry was last deemed active.
* @return epoch time of last activity
......@@ -72,35 +73,6 @@ public interface FlowEntry extends FlowRule {
long lastSeen();
/**
* Sets the last active epoch time.
*/
void setLastSeen();
/**
* Sets the new state for this entry.
* @param newState new flow entry state.
*/
void setState(FlowEntryState newState);
/**
* Sets how long this entry has been entered in the system.
* @param life epoch time
*/
void setLife(long life);
/**
* Number of packets seen by this entry.
* @param packets a long value
*/
void setPackets(long packets);
/**
* Number of bytes seen by this rule.
* @param bytes a long value
*/
void setBytes(long bytes);
/**
* Indicates the error type.
* @return an integer value of the error
*/
......
package org.onlab.onos.net.flow;
public interface StoredFlowEntry extends FlowEntry {
/**
* Sets the last active epoch time.
*/
void setLastSeen();
/**
* Sets the new state for this entry.
* @param newState new flow entry state.
*/
void setState(FlowEntryState newState);
/**
* Sets how long this entry has been entered in the system.
* @param life epoch time
*/
void setLife(long life);
/**
* Number of packets seen by this entry.
* @param packets a long value
*/
void setPackets(long packets);
/**
* Number of bytes seen by this rule.
* @param bytes a long value
*/
void setBytes(long bytes);
}
package org.onlab.onos.net.host;
import java.util.Collections;
import java.util.Set;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.SparseAnnotations;
......@@ -7,6 +10,8 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.collect.ImmutableSet;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
......@@ -18,7 +23,7 @@ public class DefaultHostDescription extends AbstractDescription
private final MacAddress mac;
private final VlanId vlan;
private final HostLocation location;
private final IpPrefix ip;
private final Set<IpPrefix> ip;
/**
* Creates a host description using the supplied information.
......@@ -31,7 +36,7 @@ public class DefaultHostDescription extends AbstractDescription
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location,
SparseAnnotations... annotations) {
this(mac, vlan, location, null, annotations);
this(mac, vlan, location, Collections.<IpPrefix>emptySet(), annotations);
}
/**
......@@ -46,11 +51,26 @@ public class DefaultHostDescription extends AbstractDescription
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location, IpPrefix ip,
SparseAnnotations... annotations) {
this(mac, vlan, location, ImmutableSet.of(ip), annotations);
}
/**
* Creates a host description using the supplied information.
*
* @param mac host MAC address
* @param vlan host VLAN identifier
* @param location host location
* @param ip host IP addresses
* @param annotations optional key/value annotations map
*/
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location, Set<IpPrefix> ip,
SparseAnnotations... annotations) {
super(annotations);
this.mac = mac;
this.vlan = vlan;
this.location = location;
this.ip = ip;
this.ip = ImmutableSet.copyOf(ip);
}
@Override
......@@ -69,7 +89,7 @@ public class DefaultHostDescription extends AbstractDescription
}
@Override
public IpPrefix ipAddress() {
public Set<IpPrefix> ipAddress() {
return ip;
}
......
package org.onlab.onos.net.host;
import java.util.Set;
import org.onlab.onos.net.Description;
import org.onlab.onos.net.HostLocation;
import org.onlab.packet.IpPrefix;
......@@ -38,6 +40,6 @@ public interface HostDescription extends Description {
* @return host IP address
*/
// FIXME: Switch to IpAddress
IpPrefix ipAddress();
Set<IpPrefix> ipAddress();
}
......
......@@ -12,7 +12,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Abstraction of end-station to end-station bidirectional connectivity.
*/
public class HostToHostIntent extends ConnectivityIntent {
public final class HostToHostIntent extends ConnectivityIntent {
private final HostId one;
private final HostId two;
......
......@@ -4,6 +4,7 @@ import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
......@@ -14,10 +15,12 @@ import com.google.common.base.MoreObjects;
* Abstraction of a connectivity intent that is implemented by a set of path
* segments.
*/
public class LinkCollectionIntent extends ConnectivityIntent implements InstallableIntent {
public final class LinkCollectionIntent extends ConnectivityIntent implements InstallableIntent {
private final Set<Link> links;
private final ConnectPoint egressPoint;
/**
* Creates a new point-to-point intent with the supplied ingress/egress
* ports and using the specified explicit path.
......@@ -26,19 +29,23 @@ public class LinkCollectionIntent extends ConnectivityIntent implements Installa
* @param selector traffic match
* @param treatment action
* @param links traversed links
* @param egressPoint egress point
* @throws NullPointerException {@code path} is null
*/
public LinkCollectionIntent(IntentId id,
TrafficSelector selector,
TrafficTreatment treatment,
Set<Link> links) {
Set<Link> links,
ConnectPoint egressPoint) {
super(id, selector, treatment);
this.links = links;
this.egressPoint = egressPoint;
}
protected LinkCollectionIntent() {
super();
this.links = null;
this.egressPoint = null;
}
@Override
......@@ -46,10 +53,25 @@ public class LinkCollectionIntent extends ConnectivityIntent implements Installa
return links;
}
/**
* Returns the set of links that represent the network connections needed
* by this intent.
*
* @return Set of links for the network hops needed by this intent
*/
public Set<Link> links() {
return links;
}
/**
* Returns the egress point of the intent.
*
* @return the egress point
*/
public ConnectPoint egressPoint() {
return egressPoint;
}
@Override
public boolean equals(Object o) {
if (this == o) {
......@@ -64,12 +86,13 @@ public class LinkCollectionIntent extends ConnectivityIntent implements Installa
LinkCollectionIntent that = (LinkCollectionIntent) o;
return Objects.equals(this.links, that.links);
return Objects.equals(this.links, that.links) &&
Objects.equals(this.egressPoint, that.egressPoint);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), links);
return Objects.hash(super.hashCode(), links, egressPoint);
}
@Override
......@@ -79,6 +102,7 @@ public class LinkCollectionIntent extends ConnectivityIntent implements Installa
.add("match", selector())
.add("action", treatment())
.add("links", links())
.add("egress", egressPoint())
.toString();
}
}
......
......@@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Abstraction of multiple source to single destination connectivity intent.
*/
public class MultiPointToSinglePointIntent extends ConnectivityIntent {
public final class MultiPointToSinglePointIntent extends ConnectivityIntent {
private final Set<ConnectPoint> ingressPoints;
private final ConnectPoint egressPoint;
......
......@@ -62,6 +62,9 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro
((AbstractProviderService) service).invalidate();
services.remove(provider.id());
providers.remove(provider.id());
if (!provider.id().isAncillary()) {
providersByScheme.remove(provider.id().scheme());
}
}
}
......
......@@ -7,6 +7,8 @@ import org.onlab.onos.net.Provided;
*/
public interface Topology extends Provided {
// FIXME: Following is not true right now. It is actually System.nanoTime(),
// which has no relation to epoch time, wall clock, etc.
/**
* Returns the time, specified in milliseconds since start of epoch,
* when the topology became active and made available.
......
......@@ -37,6 +37,15 @@ public interface ClusterCommunicationService {
boolean multicast(ClusterMessage message, Set<NodeId> nodeIds) throws IOException;
/**
* Sends a message synchronously.
* @param message message to send
* @param toNodeId recipient node identifier
* @return ClusterMessageResponse which is reply future.
* @throws IOException
*/
ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException;
/**
* Adds a new subscriber for the specified message subject.
*
* @param subject message subject
......
package org.onlab.onos.store.cluster.messaging;
import java.io.IOException;
import org.onlab.onos.cluster.NodeId;
// TODO: Should payload type be ByteBuffer?
......@@ -49,4 +51,14 @@ public class ClusterMessage {
public byte[] payload() {
return payload;
}
/**
* Sends a response to the sender.
*
* @param data payload response.
* @throws IOException
*/
public void respond(byte[] data) throws IOException {
throw new IllegalStateException("One can only repond to message recived from others.");
}
}
......
package org.onlab.onos.store.cluster.messaging;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.onlab.onos.cluster.NodeId;
public interface ClusterMessageResponse {
public NodeId sender();
public byte[] get(long timeout, TimeUnit timeunit) throws TimeoutException;
public byte[] get(long timeout) throws InterruptedException;
}
package org.onlab.onos.cluster;
import static com.google.common.base.Predicates.notNull;
import static org.junit.Assert.*;
import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId;
......@@ -30,12 +31,13 @@ public class ControllerNodeToNodeIdTest {
@Test
public final void testToNodeId() {
final Iterable<ControllerNode> nodes = Arrays.asList(CN1, CN2, CN3);
final Iterable<ControllerNode> nodes = Arrays.asList(CN1, CN2, CN3, null);
final List<NodeId> nodeIds = Arrays.asList(NID1, NID2, NID3);
assertEquals(nodeIds,
FluentIterable.from(nodes)
.transform(toNodeId())
.filter(notNull())
.toList());
}
......
......@@ -4,6 +4,7 @@ import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.MastershipRole;
import java.util.List;
import java.util.Set;
/**
......@@ -46,4 +47,9 @@ public class MastershipServiceAdapter implements MastershipService {
public MastershipTermService requestTermService() {
return null;
}
@Override
public List<NodeId> getNodesFor(DeviceId deviceId) {
return null;
}
}
......
......@@ -3,6 +3,7 @@ package org.onlab.onos.net;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.packet.ChassisId;
import static org.junit.Assert.assertEquals;
import static org.onlab.onos.net.Device.Type.SWITCH;
......@@ -21,14 +22,15 @@ public class DefaultDeviceTest {
static final String SW = "3.9.1";
static final String SN1 = "43311-12345";
static final String SN2 = "42346-43512";
static final ChassisId CID = new ChassisId();
@Test
public void testEquality() {
Device d1 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1);
Device d2 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1);
Device d3 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2);
Device d4 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2);
Device d5 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN1);
Device d1 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID);
Device d2 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID);
Device d3 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2, CID);
Device d4 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2, CID);
Device d5 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN1, CID);
new EqualsTester().addEqualityGroup(d1, d2)
.addEqualityGroup(d3, d4)
......@@ -38,13 +40,13 @@ public class DefaultDeviceTest {
@Test
public void basics() {
Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1);
Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID);
validate(device);
}
@Test
public void annotations() {
Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1,
Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID,
DefaultAnnotations.builder().set("foo", "bar").build());
validate(device);
assertEquals("incorrect provider", "bar", device.annotations().value("foo"));
......
......@@ -3,6 +3,7 @@ package org.onlab.onos.net;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.packet.ChassisId;
import static org.junit.Assert.assertEquals;
import static org.onlab.onos.net.Device.Type.SWITCH;
......@@ -22,7 +23,8 @@ public class DefaultPortTest {
@Test
public void testEquality() {
Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n");
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);
......@@ -37,7 +39,8 @@ public class DefaultPortTest {
@Test
public void basics() {
Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n");
Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n",
new ChassisId());
Port port = new DefaultPort(device, portNumber(1), true);
assertEquals("incorrect element", device, port.element());
assertEquals("incorrect number", portNumber(1), port.number());
......
package org.onlab.onos.net;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.packet.ChassisId;
import org.onlab.packet.IpPrefix;
import java.util.ArrayList;
......@@ -37,7 +38,7 @@ public final class NetTestTools {
// Crates a new device with the specified id
public static Device device(String id) {
return new DefaultDevice(PID, did(id), Device.Type.SWITCH,
"mfg", "1.0", "1.1", "1234");
"mfg", "1.0", "1.1", "1234", new ChassisId());
}
// Crates a new host with the specified id
......@@ -47,10 +48,16 @@ public final class NetTestTools {
new HashSet<IpPrefix>());
}
// Short-hand for creating a connection point.
public static ConnectPoint connectPoint(String id, int port) {
return new ConnectPoint(did(id), portNumber(port));
}
// Short-hand for creating a link.
public static Link link(String src, int sp, String dst, int dp) {
return new DefaultLink(PID, new ConnectPoint(did(src), portNumber(sp)),
new ConnectPoint(did(dst), portNumber(dp)),
return new DefaultLink(PID,
connectPoint(src, sp),
connectPoint(dst, dp),
Link.Type.DIRECT);
}
......
package org.onlab.onos.net.device;
import org.junit.Test;
import org.onlab.packet.ChassisId;
import java.net.URI;
......@@ -18,12 +19,13 @@ public class DefaultDeviceDescriptionTest {
private static final String HW = "1.1.x";
private static final String SW = "3.9.1";
private static final String SN = "43311-12345";
private static final ChassisId CID = new ChassisId();
@Test
public void basics() {
DeviceDescription device =
new DefaultDeviceDescription(DURI, SWITCH, MFR, HW, SW, SN);
new DefaultDeviceDescription(DURI, SWITCH, MFR, HW, SW, SN, CID);
assertEquals("incorrect uri", DURI, device.deviceURI());
assertEquals("incorrect type", SWITCH, device.type());
assertEquals("incorrect manufacturer", MFR, device.manufacturer());
......@@ -31,6 +33,7 @@ public class DefaultDeviceDescriptionTest {
assertEquals("incorrect sw", SW, device.swVersion());
assertEquals("incorrect serial", SN, device.serialNumber());
assertTrue("incorrect toString", device.toString().contains("uri=of:foo"));
assertTrue("Incorrect chassis", device.chassisId().value() == 0);
}
}
......
......@@ -11,6 +11,7 @@ import org.onlab.onos.net.Device;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.packet.ChassisId;
/**
* Tests of the device event.
......@@ -19,7 +20,7 @@ public class DeviceEventTest extends AbstractEventTest {
private Device createDevice() {
return new DefaultDevice(new ProviderId("of", "foo"), deviceId("of:foo"),
Device.Type.SWITCH, "box", "hw", "sw", "sn");
Device.Type.SWITCH, "box", "hw", "sw", "sn", new ChassisId());
}
@Override
......
......@@ -8,6 +8,8 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.collect.ImmutableSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
......@@ -33,7 +35,7 @@ public class DefualtHostDecriptionTest {
assertEquals("incorrect mac", MAC, host.hwAddress());
assertEquals("incorrect vlan", VLAN, host.vlan());
assertEquals("incorrect location", LOC, host.location());
assertEquals("incorrect ip's", IP, host.ipAddress());
assertEquals("incorrect ip's", ImmutableSet.of(IP), host.ipAddress());
assertTrue("incorrect toString", host.toString().contains("vlan=10"));
}
......
......@@ -18,9 +18,9 @@ public class DefaultGraphDescriptionTest {
private static final DeviceId D3 = deviceId("3");
static final Device DEV1 = new DefaultDevice(PID, D1, SWITCH, "", "", "", "");
static final Device DEV2 = new DefaultDevice(PID, D2, SWITCH, "", "", "", "");
static final Device DEV3 = new DefaultDevice(PID, D3, SWITCH, "", "", "", "");
static final Device DEV1 = new DefaultDevice(PID, D1, SWITCH, "", "", "", "", null);
static final Device DEV2 = new DefaultDevice(PID, D2, SWITCH, "", "", "", "", null);
static final Device DEV3 = new DefaultDevice(PID, D3, SWITCH, "", "", "", "", null);
@Test
public void basics() {
......
......@@ -6,15 +6,15 @@
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-core-hz</artifactId>
<artifactId>onos-core</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-core-hz-net</artifactId>
<artifactId>onos-json</artifactId>
<packaging>bundle</packaging>
<description>ONOS Hazelcast based distributed store subsystems</description>
<description>ONOS JSON encode/decode facilities</description>
<dependencies>
<dependency>
......@@ -23,24 +23,22 @@
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-core-hz-common</artifactId>
<version>${project.version}</version>
<artifactId>onos-api</artifactId>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-core-hz-common</artifactId>
<classifier>tests</classifier>
<scope>test</scope>
<artifactId>onos-core-trivial</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</dependency>
</dependencies>
<build>
......
package org.onlab.onos.json.impl;
/**
* Created by tom on 10/16/14.
*/
public class DeleteMe {
}
/**
* Implementation of JSON codec factory and of the builtin codecs.
*/
package org.onlab.onos.json.impl;
\ No newline at end of file
......@@ -42,23 +42,6 @@
<scope>test</scope>
</dependency>
<!-- TODO Consider removing store dependency.
Currently required for DistributedDeviceManagerTest. -->
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-core-hz-net</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<!-- FIXME: should be somewhere else -->
<artifactId>onos-core-hz-common</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
......
......@@ -3,6 +3,7 @@ package org.onlab.onos.cluster.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
......@@ -103,7 +104,6 @@ implements MastershipService, MastershipAdminService {
MastershipEvent event = null;
event = store.relinquishRole(
clusterService.getLocalNode().id(), deviceId);
if (event != null) {
post(event);
}
......@@ -127,6 +127,11 @@ implements MastershipService, MastershipAdminService {
return store.getDevices(nodeId);
}
@Override
public List<NodeId> getNodesFor(DeviceId deviceId) {
checkNotNull(deviceId, DEVICE_ID_NULL);
return store.getNodes(deviceId);
}
@Override
public MastershipTermService requestTermService() {
......@@ -223,7 +228,8 @@ implements MastershipService, MastershipAdminService {
return true;
}
//else {
//FIXME: break tie for equal-sized clusters, can we use hz's functions?
//FIXME: break tie for equal-sized clusters,
// maybe by number of connected switches
// }
return false;
}
......
/**
*
* Miscellaneous core system implementations.
*/
package org.onlab.onos.impl;
\ No newline at end of file
......
......@@ -144,7 +144,7 @@ public class DeviceManager
// Applies the specified role to the device; ignores NONE
private void applyRole(DeviceId deviceId, MastershipRole newRole) {
if (newRole.equals(MastershipRole.NONE)) {
if (!newRole.equals(MastershipRole.NONE)) {
Device device = store.getDevice(deviceId);
// FIXME: Device might not be there yet. (eventual consistent)
if (device == null) {
......@@ -161,6 +161,9 @@ public class DeviceManager
@Override
public void removeDevice(DeviceId deviceId) {
checkNotNull(deviceId, DEVICE_ID_NULL);
// XXX is this intended to apply to the full global topology?
// if so, we probably don't want the fact that we aren't
// MASTER to get in the way, as it would do now.
DeviceEvent event = store.removeDevice(deviceId);
if (event != null) {
log.info("Device {} administratively removed", deviceId);
......@@ -203,19 +206,21 @@ public class DeviceManager
log.info("Device {} connected", deviceId);
// check my Role
MastershipRole role = mastershipService.requestRoleFor(deviceId);
log.info("## - our role for {} is {} [master is {}]", deviceId, role,
mastershipService.getMasterFor(deviceId));
if (role != MastershipRole.MASTER) {
// TODO: Do we need to explicitly tell the Provider that
// this instance is no longer the MASTER? probably not
return;
}
MastershipTerm term = mastershipService.requestTermService()
.getMastershipTerm(deviceId);
if (!term.master().equals(clusterService.getLocalNode().id())) {
// lost mastership after requestRole told this instance was MASTER.
return;
}
// tell clock provider if this instance is the master
deviceClockProviderService.setMastershipTerm(deviceId, term);
......@@ -256,13 +261,31 @@ public class DeviceManager
// but if I was the last STANDBY connection, etc. and no one else
// was there to mark the device offline, this instance may need to
// temporarily request for Master Role and mark offline.
log.info("## for {} role is {}", deviceId, mastershipService.getLocalRole(deviceId));
if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) {
log.debug("Device {} disconnected, but I am not the master", deviceId);
//let go of ability to be backup
mastershipService.relinquishMastership(deviceId);
return;
}
DeviceEvent event = store.markOffline(deviceId);
DeviceEvent event = null;
try {
event = store.markOffline(deviceId);
} catch (IllegalStateException e) {
//there are times when this node will correctly have mastership, BUT
//that isn't reflected in the ClockManager before the device disconnects.
//we want to let go of the device anyways, so make sure this happens.
// FIXME: Come up with workaround for above scenario.
MastershipTerm term = termService.getMastershipTerm(deviceId);
final NodeId myNodeId = clusterService.getLocalNode().id();
// TODO: Move this type of check inside device clock manager, etc.
if (myNodeId.equals(term.master())) {
deviceClockProviderService.setMastershipTerm(deviceId, term);
event = store.markOffline(deviceId);
}
} finally {
//relinquish master role and ability to be backup.
mastershipService.relinquishMastership(deviceId);
......@@ -271,6 +294,7 @@ public class DeviceManager
post(event);
}
}
}
@Override
public void updatePorts(DeviceId deviceId,
......@@ -279,7 +303,15 @@ public class DeviceManager
checkNotNull(portDescriptions,
"Port descriptions list cannot be null");
checkValidity();
//XXX what's this doing here?
this.provider().id();
if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) {
// TODO If we become master, then we'll trigger something to update this
// info to fix any inconsistencies that may result during the handoff.
return;
}
List<DeviceEvent> events = store.updatePorts(this.provider().id(),
deviceId, portDescriptions);
for (DeviceEvent event : events) {
......@@ -293,6 +325,12 @@ public class DeviceManager
checkNotNull(deviceId, DEVICE_ID_NULL);
checkNotNull(portDescription, PORT_DESCRIPTION_NULL);
checkValidity();
if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) {
// TODO If we become master, then we'll trigger something to update this
// info to fix any inconsistencies that may result during the handoff.
return;
}
DeviceEvent event = store.updatePortStatus(this.provider().id(),
deviceId, portDescription);
if (event != null) {
......@@ -328,27 +366,37 @@ public class DeviceManager
final DeviceId did = event.subject();
final NodeId myNodeId = clusterService.getLocalNode().id();
log.info("## got Mastershipevent for dev {}", did);
if (myNodeId.equals(event.master())) {
MastershipTerm term = termService.getMastershipTerm(did);
if (term.master().equals(myNodeId)) {
if (!myNodeId.equals(term.master())) {
// something went wrong in consistency, let go
mastershipService.relinquishMastership(did);
applyRole(did, MastershipRole.STANDBY);
return;
}
log.info("## setting term for CPS as new master for {}", did);
// only set the new term if I am the master
deviceClockProviderService.setMastershipTerm(did, term);
}
// FIXME: we should check that the device is connected on our end.
// currently, this is not straight forward as the actual switch
// implementation is hidden from the registry.
if (!isAvailable(did)) {
//flag the device as online. Is there a better way to do this?
// implementation is hidden from the registry. Maybe we can ask the
// provider.
// if the device is null here, we are the first master to claim the
// device. No worries, the DeviceManager will create one soon.
Device device = getDevice(did);
if ((device != null) && !isAvailable(did)) {
//flag the device as online. Is there a better way to do this?
store.createOrUpdateDevice(device.providerId(), did,
new DefaultDeviceDescription(
did.uri(), device.type(), device.manufacturer(),
device.hwVersion(), device.swVersion(),
device.serialNumber()));
device.serialNumber(), device.chassisId()));
}
//TODO re-collect device information to fix potential staleness
applyRole(did, MastershipRole.MASTER);
} else {
applyRole(did, MastershipRole.STANDBY);
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.