Jian Li
Committed by Gerrit Code Review

[ONOS-2225] Implement REST API for Flow Objectives

This commit implements REST API for Flow Objective Service.
The corresponding unit test will be followed in a separated commit.

Change-Id: I94d1dc6cfc07fc9d07fcf8c303c8e395b40ed122
......@@ -43,7 +43,8 @@ public class CoreWebApplication extends AbstractWebApplication {
ConfigWebResource.class,
PathsWebResource.class,
StatisticsWebResource.class,
MetricsWebResource.class
MetricsWebResource.class,
FlowObjectiveWebResource.class
);
}
}
\ No newline at end of file
......
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.rest.resources;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.rest.AbstractWebResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
/**
* Manage flow objectives.
*/
@Path("flowobjectives")
public class FlowObjectiveWebResource extends AbstractWebResource {
public static final String DEVICE_INVALID =
"Invalid deviceId in objective creation request";
public static final String POLICY_INVALID = "Invalid policy";
final FlowObjectiveService flowObjectiveService = get(FlowObjectiveService.class);
final ObjectNode root = mapper().createObjectNode();
/**
* Creates and installs a new filtering objective for the specified device.
*
* @param deviceId device identifier
* @param stream filtering objective JSON
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel FilteringObjective
*/
@POST
@Path("{deviceId}/filter")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createFilteringObjective(@PathParam("deviceId") String deviceId,
InputStream stream) {
URI location = null;
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
if (validateDeviceId(deviceId, jsonTree)) {
DeviceId did = DeviceId.deviceId(deviceId);
FilteringObjective filteringObjective =
codec(FilteringObjective.class).decode(jsonTree, this);
flowObjectiveService.filter(did, filteringObjective);
location = new URI(Integer.toString(filteringObjective.id()));
}
} catch (IOException | URISyntaxException e) {
throw new IllegalArgumentException(e);
}
return Response
.created(location)
.build();
}
/**
* Creates and installs a new forwarding objective for the specified device.
*
* @param deviceId device identifier
* @param stream forwarding objective JSON
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel ForwardingObjective
*/
@POST
@Path("{deviceId}/forward")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createForwardingObjective(@PathParam("deviceId") String deviceId,
InputStream stream) {
URI location = null;
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
if (validateDeviceId(deviceId, jsonTree)) {
DeviceId did = DeviceId.deviceId(deviceId);
ForwardingObjective forwardingObjective =
codec(ForwardingObjective.class).decode(jsonTree, this);
flowObjectiveService.forward(did, forwardingObjective);
location = new URI(Integer.toString(forwardingObjective.id()));
}
} catch (IOException | URISyntaxException e) {
throw new IllegalArgumentException(e);
}
return Response
.created(location)
.build();
}
/**
* Creates and installs a new next objective for the specified device.
*
* @param deviceId device identifier
* @param stream next objective JSON
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel NextObjective
*/
@POST
@Path("{deviceId}/next")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createNextObjective(@PathParam("deviceId") String deviceId,
InputStream stream) {
URI location = null;
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
if (validateDeviceId(deviceId, jsonTree)) {
DeviceId did = DeviceId.deviceId(deviceId);
NextObjective nextObjective =
codec(NextObjective.class).decode(jsonTree, this);
flowObjectiveService.next(did, nextObjective);
location = new URI(Integer.toString(nextObjective.id()));
}
} catch (IOException | URISyntaxException e) {
throw new IllegalArgumentException(e);
}
return Response
.created(location)
.build();
}
/**
* Returns the globally unique nextId.
*
* @return nextId
* @onos.rsModel nextid
*/
@GET
@Path("next")
@Produces(MediaType.APPLICATION_JSON)
public Response getNextId() {
root.put("nextId", flowObjectiveService.allocateNextId());
return ok(root).build();
}
/**
* Installs the filtering rules onto the specified device.
*
* @param stream filtering rule JSON
* @return status of the request
* @onos.rsModel ObjectivePolicy
*/
@POST
@Path("policy")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public void initPolicy(InputStream stream) {
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
JsonNode policyJson = jsonTree.get("policy");
if (policyJson == null || policyJson.asText().isEmpty()) {
throw new IllegalArgumentException(POLICY_INVALID);
}
flowObjectiveService.initPolicy(policyJson.asText());
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Validate the deviceId that is contained in json string against the
* input deviceId.
*
* @param deviceId device identifier
* @param node object node
* @return validity
*/
private boolean validateDeviceId(String deviceId, ObjectNode node) {
JsonNode specifiedDeviceId = node.get("deviceId");
if (specifiedDeviceId != null &&
!specifiedDeviceId.asText().equals(deviceId)) {
throw new IllegalArgumentException(DEVICE_INVALID);
}
return true;
}
}
This diff is collapsed. Click to expand it.
{
"type": "object",
"title": "forwardingObjective",
"required": [
"flag",
"priority",
"timeout",
"isPermanent",
"deviceId",
"operation",
"selector",
"treatment"
],
"properties": {
"flag": {
"type": "string",
"example": "SPECIFIC"
},
"priority": {
"type": "integer",
"format": "int64",
"example": 400000
},
"timeout": {
"type": "integer",
"format": "int64",
"example": 0
},
"isPermanent": {
"type": "boolean",
"example": true
},
"deviceId": {
"type": "string",
"example": "of:0000000000000001"
},
"operation": {
"type": "string",
"example": "ADD"
},
"selector": {
"type": "object",
"title": "selector",
"required": [
"criteria"
],
"properties": {
"criteria": {
"type": "array",
"xml": {
"name": "criteria",
"wrapped": true
},
"items": {
"type": "object",
"title": "criteria",
"properties": {
"type": {
"type": "string",
"description": "Ethernet field name",
"example": "ETH_TYPE"
},
"ethType": {
"type": "int64",
"format": "int64",
"example": "0x88cc",
"description": "Ethernet frame type"
},
"mac": {
"type": "string",
"example": "00:00:11:00:00:01"
},
"port": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "Match port"
},
"metadata": {
"type": "Hex16",
"format": "Hex16",
"example": "0xabcdL",
"description": "Metadata passed between tables"
},
"vlanId": {
"type": "uint16",
"format": "uint16",
"example": "0x1000"
},
"priority": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "VLAN priority."
},
"ipDscp": {
"type": "byte",
"format": "byte",
"description": "IP DSCP (6 bits in ToS field)"
},
"ipEcn": {
"type": "byte",
"format": "byte",
"description": "IP ECN (2 bits in ToS field)."
},
"protocol": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "IP protocol"
},
"ip": {
"type": "string",
"example": "10.1.1.0/24",
"description": "IP source address"
},
"tcpPort": {
"type": "integer",
"format": "uint16",
"example": 1,
"description": "TCP source address"
},
"udpPort": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "UDP source address"
},
"sctpPort": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "SCTP source address"
},
"icmpType": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
},
"icmpCode": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
},
"flowLabel": {
"type": "Hex16",
"format": "Hex16",
"example": "0xffffe",
"description": "IPv6 Flow Label (RFC 6437)"
},
"icmpv6Type": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "Internet Control Message Protocol for IPV6 type (RFC2463)"
},
"icmpv6Code": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "Internet Control Message Protocol for IPV6 code (RFC2463)"
},
"targetAddress": {
"type": "String",
"example": "10.1.1.0/24",
"description": "IPv6 Neighbor discovery target address"
},
"label": {
"type": "int32",
"format": "int32",
"example": 1,
"description": "MPLS label"
},
"exthdrFlags": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "IPv6 extension header pseudo-field"
},
"lambda": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "wavelength abstraction"
},
"gridType": {
"type": "String",
"example": "DWDM",
"description": "Type of wavelength grid"
},
"channelSpacing": {
"type": "int64",
"format": "int64",
"example": 100,
"description": "Optical channel spacing"
},
"spacingMultiplier": {
"type": "integer",
"format": "int64",
"example": 4,
"description": "Optical channel spacing multiplier"
},
"slotGranularity": {
"type": "int64",
"format": "int64",
"example": 8
},
"ochSignalId": {
"type": "integer",
"format": "int64",
"example": 1,
"description": "Optical channel signal ID"
},
"tunnelId": {
"type": "int64",
"format": "int64",
"example": 5,
"description": "Tunnel ID"
},
"ochSignalType": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "Optical channel signal type"
},
"oduSignalId": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "ODU (Optical channel Data Unit) signal ID."
},
"tributaryPortNumber": {
"type": "int64",
"format": "int64",
"example": 11,
"description": "OPU (Optical channel Payload Unit) port number."
},
"tributarySlotLen": {
"type": "int64",
"format": "int64",
"example": 80,
"description": "OPU (Optical channel Payload Unit) slot length."
},
"tributarySlotBitmap": {
"type": "array",
"title": "tributarySlotBitmap",
"description": "OPU (Optical channel Payload Unit) slot bitmap.",
"required": [
"byte",
"port"
],
"items": {
"type": "byte",
"title": "byte",
"example": 1
}
},
"oduSignalType": {
"type": "int64",
"format": "int64",
"example": 4,
"description": "ODU (Optical channel Data Unit) signal type."
}
}
}
}
}
},
"treatment": {
"type": "object",
"title": "treatment",
"required": [
"instructions"
],
"properties": {
"instructions": {
"type": "array",
"title": "treatment",
"required": [
"properties",
"port"
],
"items": {
"type": "object",
"title": "instructions",
"required": [
"type",
"port"
],
"properties": {
"type": {
"type": "string",
"example": "OUTPUT"
},
"port": {
"type": "string",
"example": "CONTROLLER"
}
}
}
}
}
}
}
}
\ No newline at end of file
{
"type": "object",
"title": "nextId",
"required": [
"id"
],
"properties": {
"nextId": {
"type": "integer",
"format": "int64",
"example": 3
}
}
}
\ No newline at end of file
{
"type": "object",
"title": "nextObjective",
"required": [
"type",
"priority",
"timeout",
"isPermanent",
"deviceId",
"operation",
"meta",
"treatments"
],
"properties": {
"type": {
"type": "string",
"example": "HASHED"
},
"priority": {
"type": "integer",
"format": "int64",
"example": 400000
},
"timeout": {
"type": "integer",
"format": "int64",
"example": 0
},
"isPermanent": {
"type": "boolean",
"example": true
},
"deviceId": {
"type": "string",
"example": "of:0000000000000001"
},
"operation": {
"type": "string",
"example": "ADD"
},
"meta": {
"type": "object",
"title": "meta",
"required": [
"criteria"
],
"properties": {
"criteria": {
"type": "array",
"xml": {
"name": "criteria",
"wrapped": true
},
"items": {
"type": "object",
"title": "criteria",
"properties": {
"type": {
"type": "string",
"description": "Ethernet field name",
"example": "ETH_TYPE"
},
"ethType": {
"type": "int64",
"format": "int64",
"example": "0x88cc",
"description": "Ethernet frame type"
},
"mac": {
"type": "string",
"example": "00:00:11:00:00:01"
},
"port": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "Match port"
},
"metadata": {
"type": "Hex16",
"format": "Hex16",
"example": "0xabcdL",
"description": "Metadata passed between tables"
},
"vlanId": {
"type": "uint16",
"format": "uint16",
"example": "0x1000"
},
"priority": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "VLAN priority."
},
"ipDscp": {
"type": "byte",
"format": "byte",
"description": "IP DSCP (6 bits in ToS field)"
},
"ipEcn": {
"type": "byte",
"format": "byte",
"description": "IP ECN (2 bits in ToS field)."
},
"protocol": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "IP protocol"
},
"ip": {
"type": "string",
"example": "10.1.1.0/24",
"description": "IP source address"
},
"tcpPort": {
"type": "integer",
"format": "uint16",
"example": 1,
"description": "TCP source address"
},
"udpPort": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "UDP source address"
},
"sctpPort": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "SCTP source address"
},
"icmpType": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
},
"icmpCode": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
},
"flowLabel": {
"type": "Hex16",
"format": "Hex16",
"example": "0xffffe",
"description": "IPv6 Flow Label (RFC 6437)"
},
"icmpv6Type": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "Internet Control Message Protocol for IPV6 type (RFC2463)"
},
"icmpv6Code": {
"type": "uint16",
"format": "uint16",
"example": 1,
"description": "Internet Control Message Protocol for IPV6 code (RFC2463)"
},
"targetAddress": {
"type": "String",
"example": "10.1.1.0/24",
"description": "IPv6 Neighbor discovery target address"
},
"label": {
"type": "int32",
"format": "int32",
"example": 1,
"description": "MPLS label"
},
"exthdrFlags": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "IPv6 extension header pseudo-field"
},
"lambda": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "wavelength abstraction"
},
"gridType": {
"type": "String",
"example": "DWDM",
"description": "Type of wavelength grid"
},
"channelSpacing": {
"type": "int64",
"format": "int64",
"example": 100,
"description": "Optical channel spacing"
},
"spacingMultiplier": {
"type": "integer",
"format": "int64",
"example": 4,
"description": "Optical channel spacing multiplier"
},
"slotGranularity": {
"type": "int64",
"format": "int64",
"example": 8
},
"ochSignalId": {
"type": "integer",
"format": "int64",
"example": 1,
"description": "Optical channel signal ID"
},
"tunnelId": {
"type": "int64",
"format": "int64",
"example": 5,
"description": "Tunnel ID"
},
"ochSignalType": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "Optical channel signal type"
},
"oduSignalId": {
"type": "int64",
"format": "int64",
"example": 1,
"description": "ODU (Optical channel Data Unit) signal ID."
},
"tributaryPortNumber": {
"type": "int64",
"format": "int64",
"example": 11,
"description": "OPU (Optical channel Payload Unit) port number."
},
"tributarySlotLen": {
"type": "int64",
"format": "int64",
"example": 80,
"description": "OPU (Optical channel Payload Unit) slot length."
},
"tributarySlotBitmap": {
"type": "array",
"title": "tributarySlotBitmap",
"description": "OPU (Optical channel Payload Unit) slot bitmap.",
"required": [
"byte",
"port"
],
"items": {
"type": "byte",
"title": "byte",
"example": 1
}
},
"oduSignalType": {
"type": "int64",
"format": "int64",
"example": 4,
"description": "ODU (Optical channel Data Unit) signal type."
}
}
}
}
}
},
"treatments": {
"type": "array",
"xml": {
"name": "treatments",
"wrapped": true
},
"items": {
"type": "object",
"title": "treatments",
"properties": {
"instructions": {
"type": "array",
"title": "instructions",
"required": [
"properties",
"port"
],
"items": {
"type": "object",
"title": "instructions",
"required": [
"type",
"port"
],
"properties": {
"type": {
"type": "string",
"example": "OUTPUT"
},
"port": {
"type": "string",
"example": "CONTROLLER"
}
}
}
}
}
}
}
}
}
\ No newline at end of file
{
"type": "object",
"title": "objectivePolicy",
"required": [
"policy"
],
"properties": {
"policy": {
"type": "string",
"example": "policy expression"
}
}
}
\ No newline at end of file