tom

Added a set of abstractions for flow rule subsystem.

Added an apps source subtree.
Showing 23 changed files with 809 additions and 41 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</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-apps</artifactId>
<packaging>pom</packaging>
<description>ONOS sample applications</description>
<modules>
<module>tvue</module>
</modules>
<properties>
<web.context>default</web.context>
</properties>
<dependencies>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-api</artifactId>
</dependency>
<dependency>
<groupId>org.onlab.onos</groupId>
<artifactId>onlab-osgi</artifactId>
<version>${project.version}</version>
</dependency>
<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>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>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</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,
com.fasterxml.jackson.databind,
com.fasterxml.jackson.databind.node,
org.onlab.rest.*,
org.onlab.onos.*
</Import-Package>
<Web-ContextPath>${web.context}</Web-ContextPath>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onlab.onos</groupId>
<artifactId>onos-apps</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-tvue</artifactId>
<packaging>bundle</packaging>
<description>ONOS simple topology viewer</description>
<properties>
<web.context>/onos/tvue</web.context>
</properties>
</project>
package org.onlab.onos.tvue;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.ElementId;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.host.HostService;
import org.onlab.onos.net.link.LinkService;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyGraph;
import org.onlab.onos.net.topology.TopologyService;
import org.onlab.onos.net.topology.TopologyVertex;
import org.onlab.rest.BaseResource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Topology viewer resource.
*/
@Path("topology")
public class TopologyResource extends BaseResource {
@Path("/graph")
@GET
@Produces("application/json")
public Response graph() {
ObjectMapper mapper = new ObjectMapper();
// Fetch the services we'll be using.
DeviceService deviceService = get(DeviceService.class);
HostService hostService = get(HostService.class);
TopologyService topologyService = get(TopologyService.class);
// Fetch the current topology and its graph that we'll use to render.
Topology topo = topologyService.currentTopology();
TopologyGraph graph = topologyService.getGraph(topo);
// Build all interior vertexes, i.e. no end-station hosts yet
ArrayNode vertexesNode = mapper.createArrayNode();
for (TopologyVertex vertex : graph.getVertexes()) {
vertexesNode.add(json(mapper, vertex.deviceId(), 2,
deviceService.isAvailable(vertex.deviceId())));
}
// Now scan all links and count number of them between the same devices
// using a normalized link key.
Map<String, AggLink> linkRecords = aggregateLinks();
// Now build all interior edges using the aggregated links.
ArrayNode edgesNode = mapper.createArrayNode();
for (AggLink lr : linkRecords.values()) {
edgesNode.add(json(mapper, lr.links.size(), lr.link.src(), lr.link.dst()));
}
// Merge the exterior and interior vertexes and inject host links as
// the exterior edges.
// Iterator<Host> hosts = hostService.getHosts();
// while (hosts.hasNext()) {
// Host host = hosts.next();
// vertexesNode.add(json(mapper, host.id().ip().toString(), 3, true));
// edgesNode.add(json(mapper, 1, host.ip().toString(),
// host.location().elementId().uri()));
// }
// Now put the vertexes and edges into a root node and ship them off
ObjectNode rootNode = mapper.createObjectNode();
rootNode.put("vertexes", vertexesNode);
rootNode.put("edges", edgesNode);
return Response.ok(rootNode.toString()).build();
}
// Scan all links and counts number of them between the same devices
// using a normalized link key.
private Map<String, AggLink> aggregateLinks() {
Map<String, AggLink> aggLinks = new HashMap<>();
LinkService linkService = get(LinkService.class);
for (Link link : linkService.getLinks()) {
String key = key(link);
AggLink lr = aggLinks.get(key);
if (lr == null) {
lr = new AggLink(key);
aggLinks.put(key, lr);
}
lr.addLink(link);
}
return aggLinks;
}
// Produces JSON for a graph vertex.
private ObjectNode json(ObjectMapper mapper, ElementId id, int group,
boolean isOnline) {
return mapper.createObjectNode()
.put("name", id.uri().toString())
.put("group", group)
.put("online", isOnline);
}
// Produces JSON for a graph edge.
private ObjectNode json(ObjectMapper mapper, int count,
ConnectPoint src, ConnectPoint dst) {
return json(mapper, count, id(src), id(dst));
}
// Produces JSON for a graph edge.
private ObjectNode json(ObjectMapper mapper, int count, String src, String dst) {
return mapper.createObjectNode()
.put("source", src).put("target", dst).put("value", count);
}
// Aggregate link of all links between the same devices regardless of
// their direction.
private class AggLink {
Link link; // representative links
final String key;
final Set<Link> links = new HashSet<>();
AggLink(String key) {
this.key = key;
}
void addLink(Link link) {
links.add(link);
if (this.link == null) {
this.link = link;
}
}
}
// Returns a canonical key for the specified link.
static String key(Link link) {
String s = id(link.src());
String d = id(link.dst());
return s.compareTo(d) > 0 ? d + s : s + d;
}
// Returns a formatted string for the element associated with the given
// connection point.
private static String id(ConnectPoint cp) {
return cp.elementId().uri().toString();
}
}
<?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>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<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.gui</param-value>
</init-param>
<load-on-startup>1</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
<!DOCTYPE html>
<html>
<head>
<title>ONOS GUI</title>
</head>
<body>
<h1>ONOS GUI</h1>
Sort of...
</body>
</html>
\ No newline at end of file
package org.onlab.onos.net.flow;
/**
* Factory class to create various traffic selection criteria.
*/
public final class Criteria {
// Ban construction
private Criteria() {
}
/**
* Creates a match on ETH_SRC field using the specified value. This value
* may be a wildcard mask.
*
* @param macValue MAC address value or wildcard mask
* @return match criterion
*/
public static Criterion matchEthSrc(MACValue macValue) {
return null;
}
// Dummy to illustrate the concept for now; delete ASAP
private static class MACValue { }
}
package org.onlab.onos.net.flow;
/**
* Representation of a single header field selection.
*/
public interface Criterion {
/**
* Types of fields to which the selection criterion may apply.
*/
// From page 42 of OpenFlow 1.3.x spec
public enum Type {
/** Switch input port. */
IN_PORT,
/** Switch physical input port. */
IN_PHY_PORT,
/** Metadata passed between tables. */
METADATA,
/** Ethernet destination address. */
ETH_DST,
/** Ethernet source address. */
ETH_SRC,
/** Ethernet frame type. */
ETH_TYPE,
/** VLAN id. */
VLAN_VID,
/** VLAN priority. */
VLAN_PCP,
/** IP DSCP (6 bits in ToS field). */
IP_DSCP,
/** IP ECN (2 bits in ToS field). */
IP_ECN,
/** IP protocol. */
IP_PROTO,
/** IPv4 source address. */
IPV4_SRC,
/** IPv4 destination address. */
IPV4_DST,
/** TCP source port. */
TCP_SRC,
/** TCP destination port. */
TCP_DST,
/** UDP source port. */
UDP_SRC,
/** UDP destination port. */
UDP_DST,
/** SCTP source port. */
SCTP_SRC,
/** SCTP destination port. */
SCTP_DST,
/** ICMP type. */
ICMPV4_TYPE,
/** ICMP code. */
ICMPV4_CODE,
/** ARP opcode. */
ARP_OP,
/** ARP source IPv4 address. */
ARP_SPA,
/** ARP target IPv4 address. */
ARP_TPA,
/** ARP source hardware address. */
ARP_SHA,
/** ARP target hardware address. */
ARP_THA,
/** IPv6 source address. */
IPV6_SRC,
/** IPv6 destination address. */
IPV6_DST,
/** IPv6 Flow Label. */
IPV6_FLABEL,
/** ICMPv6 type. */
ICMPV6_TYPE,
/** ICMPv6 code. */
ICMPV6_CODE,
/** Target address for ND. */
IPV6_ND_TARGET,
/** Source link-layer for ND. */
IPV6_ND_SLL,
/** Target link-layer for ND. */
IPV6_ND_TLL,
/** MPLS label. */
MPLS_LABEL,
/** MPLS TC. */
MPLS_TC,
/** MPLS BoS bit. */
MPLS_BOS,
/** PBB I-SID. */
PBB_ISID,
/** Logical Port Metadata. */
TUNNEL_ID,
/** IPv6 Extension Header pseudo-field. */
IPV6_EXTHDR
}
// TODO: Create factory class 'Criteria' that will have various factory
// to create specific criterions.
}
package org.onlab.onos.net.flow;
/**
* Represents a flow rule and its associated accumulated metrics.
*/
public interface FlowEntry extends FlowRule {
/**
* Returns the number of milliseconds this flow rule has been applied.
*
* @return number of millis
*/
long lifeMillis();
/**
* Returns the number of milliseconds this flow rule has been idle.
*
* @return number of millis
*/
long idleMillis();
/**
* Returns the number of packets this flow rule has matched.
*
* @return number of packets
*/
long packets();
/**
* Returns the number of bytes this flow rule has matched.
*
* @return number of bytes
*/
long bytes();
}
package org.onlab.onos.net.flow;
import org.onlab.onos.net.DeviceId;
import java.util.List;
/**
* Represents a generalized match &amp; action pair to be applied to
* an infrastucture device.
*/
public interface FlowRule {
/**
* Returns the flow rule priority given in natural order; higher numbers
* mean higher priorities.
*
* @return flow rule priority
*/
int priority();
/**
* Returns the identity of the device where this rule applies.
*
* @return device identifier
*/
DeviceId deviceId();
/**
* Returns the traffic selector that identifies what traffic this
* rule should apply to.
*
* @return traffic selector
*/
TrafficSelector selector();
/**
* Returns the traffic treatment that applies to selected traffic.
*
* @return traffic treatment
*/
List<Treatment> treatments();
}
package org.onlab.onos.net.flow;
import org.onlab.onos.event.AbstractEvent;
/**
* Describes flow rule event.
*/
public class FlowRuleEvent extends AbstractEvent<FlowRuleEvent.Type, FlowRule> {
/**
* Type of flow rule events.
*/
public enum Type {
/**
* Signifies that a new flow rule has been detected.
*/
RULE_ADDED,
/**
* Signifies that a flow rule has been removed.
*/
RULE_REMOVED,
}
/**
* Creates an event of a given type and for the specified flow rule and the
* current time.
*
* @param type flow rule event type
* @param flowRule event flow rule subject
*/
public FlowRuleEvent(Type type, FlowRule flowRule) {
super(type, flowRule);
}
/**
* Creates an event of a given type and for the specified flow rule and time.
*
* @param type flow rule event type
* @param flowRule event flow rule subject
* @param time occurrence time
*/
public FlowRuleEvent(Type type, FlowRule flowRule, long time) {
super(type, flowRule, time);
}
}
package org.onlab.onos.net.flow;
import org.onlab.onos.net.Description;
import org.onlab.onos.event.EventListener;
/**
* Information about a flow rule.
* Entity capable of receiving flow rule related events.
*/
public interface FlowDescription extends Description {
// Match and action, possibly reason for flow rule, unless reason is too OF-specific.
public interface FlowRuleListener extends EventListener<FlowRuleEvent> {
}
......
package org.onlab.onos.net.flow;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.provider.Provider;
/**
......@@ -7,6 +8,23 @@ import org.onlab.onos.net.provider.Provider;
*/
public interface FlowRuleProvider extends Provider {
// TODO: pushFlowRule
/**
* Instructs the provider to apply the specified flow rules to their
* respective devices.
* @param flowRules one or more flow rules
* throws SomeKindOfException that indicates which ones were applied and
* which ones failed
*/
void applyFlowRule(FlowRule... flowRules);
/**
* Returns the collection of flow entries currently applied on the given
* device.
*
* @param deviceId device identifier
* @return collection of flow entries
*/
Iterable<FlowEntry> getFlowMetrics(DeviceId deviceId);
}
......
......@@ -3,33 +3,23 @@ package org.onlab.onos.net.flow;
import org.onlab.onos.net.provider.ProviderService;
/**
* Service through which flowrule providers can inject flowrule information into
* Service through which flow rule providers can inject information into
* the core.
*/
public interface FlowRuleProviderService extends ProviderService<FlowRuleProvider> {
/**
* Signals that a flow that was previously installed has been removed.
* Signals that a flow rule that was previously installed has been removed.
*
* @param flowDescription information about the removed flow
* @param flowRule information about the removed flow
*/
void flowRemoved(FlowDescription flowDescription);
void flowRemoved(FlowRule flowRule);
/**
* Signals that a flowrule is missing for some network traffic.
* Signals that a flow rule is missing for some network traffic.
*
* @param flowDescription information about traffic in need of flow rule(s)
* @param flowRule information about traffic in need of flow rule(s)
*/
void flowMissing(FlowDescription flowDescription);
/**
* Signals that a flowrule has been added.
*
* TODO think about if this really makes sense, e.g. if stats collection or
* something can leverage it.
*
* @param flowDescription the rule that was added
*/
void flowAdded(FlowDescription flowDescription);
void flowMissing(FlowRule flowRule);
}
......
package org.onlab.onos.net.flow;
import org.onlab.onos.net.DeviceId;
/**
* Service for injecting flow rules into the environment and for obtaining
* information about flow rules already in the environment.
*/
public interface FlowRuleService {
/**
* Returns the collection of flow entries applied on the specified device.
*
* @param deviceId device identifier
* @return collection of flow rules
*/
Iterable<FlowEntry> getFlowEntries(DeviceId deviceId);
/**
* Applies the specified flow rules onto their respective devices.
*
* @param flowRules one or more flow rules
* throws SomeKindOfException that indicates which ones were applied and
* which ones failed
*/
void applyFlowRules(FlowRule... flowRules);
/**
* Adds the specified flow rule listener.
*
* @param listener flow rule listener
*/
void addListener(FlowRuleListener listener);
/**
* Removes the specified flow rule listener.
*
* @param listener flow rule listener
*/
void removeListener(FlowRuleListener listener);
}
package org.onlab.onos.net.flow;
/**
* Abstraction of a single traffic treatment step.
*/
public interface Instruction {
/**
* Represents the type of traffic treatment.
*/
public enum Type {
/**
* Signifies that the traffic should be dropped.
*/
DROP,
/**
* Signifies that the traffic should be output to a port.
*/
OUTPUT,
/**
* Signifies that.... (do we need this?)
*/
GROUP,
/**
* Signifies that the traffic should be modified in some way.
*/
MODIFICATION
}
// TODO: Create factory class 'Instructions' that will have various factory
// to create specific instructions.
}
package org.onlab.onos.net.flow;
import org.onlab.onos.net.PortNumber;
/**
* Factory class for creating various traffic treatment instructions.
*/
public final class Instructions {
// Ban construction
private Instructions() {
}
/**
* Creates an output instruction using the specified port number. This can
* include logical ports such as CONTROLLER, FLOOD, etc.
*
* @param number port number
* @return output instruction
*/
public static Instruction createOutput(PortNumber number) {
return null;
}
// TODO: add create methods
}
package org.onlab.onos.net.flow;
import java.util.List;
/**
* Abstraction of a slice of network traffic.
*/
public interface TrafficSelector {
/**
* Returns selection criteria as an ordered list.
*
* @return list of criteria
*/
List<Criterion> criteria();
/**
* Builder of traffic selector entities.
*/
public interface Builder {
/**
* Adds a traffic selection criterion. If a same type criterion has
* already been added, it will be replaced by this one.
*
* @param criterion new criterion
*/
void add(Criterion criterion);
/**
* Builds an immutable traffic selector.
*
* @return traffic selector
*/
TrafficSelector build();
}
}
package org.onlab.onos.net.flow;
import java.util.List;
/**
* Abstraction of network traffic treatment.
*/
public interface TrafficTreatment {
/**
* Returns list of instructions on how to treat traffic.
*
* @return list of treatment instructions
*/
List<Instruction> instructions();
/**
* Builder of traffic treatment entities.
*/
public interface Builder {
/**
* Adds a traffic treatment instruction. If a same type instruction has
* already been added, it will be replaced by this one.
*
* @param instruction new instruction
*/
void add(Instruction instruction);
/**
* Builds an immutable traffic treatment descriptor.
*
* @return traffic treatment
*/
TrafficTreatment build();
}
}
package org.onlab.onos.net.packet;
package org.onlab.onos.net.flow;
import org.onlab.onos.net.PortNumber;
......
package org.onlab.onos.net.packet;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.nio.ByteBuffer;
import java.util.List;
/**
* Default implementation of an immutable outbound packet.
*/
public class DefaultOutboundPacket implements OutboundPacket {
private final DeviceId sendThrough;
private final List<Treatment> treatments;
private final TrafficTreatment treatment;
private final ByteBuffer data;
/**
* Creates an immutable outbound packet.
*
* @param sendThrough identifier through which to send the packet
* @param treatments list of packet treatments
* @param treatment list of packet treatments
* @param data raw packet data
*/
public DefaultOutboundPacket(DeviceId sendThrough,
List<Treatment> treatments, ByteBuffer data) {
TrafficTreatment treatment, ByteBuffer data) {
this.sendThrough = sendThrough;
this.treatments = ImmutableList.copyOf(treatments);
this.treatment = treatment;
this.data = data;
}
......@@ -35,8 +34,8 @@ public class DefaultOutboundPacket implements OutboundPacket {
}
@Override
public List<Treatment> treatments() {
return treatments;
public TrafficTreatment treatment() {
return treatment;
}
@Override
......@@ -49,7 +48,7 @@ public class DefaultOutboundPacket implements OutboundPacket {
public String toString() {
return MoreObjects.toStringHelper(this)
.add("sendThrough", sendThrough)
.add("treatments", treatments)
.add("treatment", treatment)
.toString();
}
}
......
package org.onlab.onos.net.packet;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.flow.TrafficTreatment;
import java.nio.ByteBuffer;
import java.util.List;
/**
* Represents an outbound data packet that is to be emitted to network via
......@@ -20,14 +20,14 @@ public interface OutboundPacket {
DeviceId sendThrough();
/**
* Returns list of treatments for the outbound packet.
* Returns how the outbound packet should be treated.
*
* @return output treatment
*/
List<Treatment> treatments();
TrafficTreatment treatment();
/**
* Returns the raw data to be sent.
* Returns immutable view of the raw data to be sent.
*
* @return data to emit
*/
......
package org.onlab.onos.net.packet;
import org.onlab.onos.net.flow.TrafficTreatment;
/**
* Represents context for processing an inbound packet, and (optionally)
* emitting a corresponding outbound packet.
......@@ -28,11 +30,11 @@ public interface PacketContext {
OutboundPacket outPacket();
/**
* Appends a new treatment to be applied to the outbound packet.
* Returns a builder for constructing traffic treatment.
*
* @param treatment output treatment
* @return traffic treatment builder
*/
void appendTreatment(Treatment treatment);
TrafficTreatment.Builder treatmentBuilder();
/**
* Triggers the outbound packet to be sent.
......
......@@ -19,6 +19,7 @@
<module>cli</module>
<module>providers</module>
<module>of</module>
<module>apps</module>
<module>features</module>
</modules>
......@@ -355,6 +356,12 @@
org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli:org.onlab.onos.gui.*:org.onlab.onos.rest.*:org.onlab.onos.cli.*
</packages>
</group>
<group>
<title>Sample Applications</title>
<packages>
org.onlab.onos.tvue
</packages>
</group>
</groups>
</configuration>
</plugin>
......