mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-16 09:51:38 +02:00
[ONOS-4530] Allow to specify appId when insert FlowRule through REST
- Augment FlowRuleCodec to encode FlowRule - Add unit test for encode method of FlowRuleCodec - Add getFlowByAppId and removeFlowByAppId methods in FlowsWebResource - Add more unit tests for FlowWebResource - Add FlowRules.json swagger doc - Rename Flows.json to FlowEntries.json, correct FlowEntries.json Change-Id: Ic3ec390c13a349e51ae4208adbc478564b6724ba
This commit is contained in:
parent
c0e04846a2
commit
2907ad2941
@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import org.onosproject.codec.CodecContext;
|
import org.onosproject.codec.CodecContext;
|
||||||
import org.onosproject.codec.JsonCodec;
|
import org.onosproject.codec.JsonCodec;
|
||||||
|
import org.onosproject.core.ApplicationId;
|
||||||
import org.onosproject.core.CoreService;
|
import org.onosproject.core.CoreService;
|
||||||
import org.onosproject.net.DeviceId;
|
import org.onosproject.net.DeviceId;
|
||||||
import org.onosproject.net.flow.DefaultFlowRule;
|
import org.onosproject.net.flow.DefaultFlowRule;
|
||||||
@ -26,6 +27,7 @@ import org.onosproject.net.flow.FlowRule;
|
|||||||
import org.onosproject.net.flow.TrafficSelector;
|
import org.onosproject.net.flow.TrafficSelector;
|
||||||
import org.onosproject.net.flow.TrafficTreatment;
|
import org.onosproject.net.flow.TrafficTreatment;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.onlab.util.Tools.nullIsIllegal;
|
import static org.onlab.util.Tools.nullIsIllegal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,14 +38,46 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> {
|
|||||||
private static final String PRIORITY = "priority";
|
private static final String PRIORITY = "priority";
|
||||||
private static final String TIMEOUT = "timeout";
|
private static final String TIMEOUT = "timeout";
|
||||||
private static final String IS_PERMANENT = "isPermanent";
|
private static final String IS_PERMANENT = "isPermanent";
|
||||||
|
private static final String APP_ID = "appId";
|
||||||
private static final String TABLE_ID = "tableId";
|
private static final String TABLE_ID = "tableId";
|
||||||
private static final String DEVICE_ID = "deviceId";
|
private static final String DEVICE_ID = "deviceId";
|
||||||
private static final String TREATMENT = "treatment";
|
private static final String TREATMENT = "treatment";
|
||||||
private static final String SELECTOR = "selector";
|
private static final String SELECTOR = "selector";
|
||||||
private static final String MISSING_MEMBER_MESSAGE =
|
private static final String MISSING_MEMBER_MESSAGE =
|
||||||
" member is required in FlowRule";
|
" member is required in FlowRule";
|
||||||
public static final String REST_APP_ID = "org.onosproject.rest";
|
public static final String REST_APP_ID = "org.onosproject.rest";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectNode encode(FlowRule flowRule, CodecContext context) {
|
||||||
|
checkNotNull(flowRule, "Flow rule cannot be null");
|
||||||
|
|
||||||
|
CoreService service = context.getService(CoreService.class);
|
||||||
|
ApplicationId appId = service.getAppId(flowRule.appId());
|
||||||
|
String strAppId = (appId == null) ? "<none>" : appId.name();
|
||||||
|
|
||||||
|
final ObjectNode result = context.mapper().createObjectNode()
|
||||||
|
.put("id", Long.toString(flowRule.id().value()))
|
||||||
|
.put("tableId", flowRule.tableId())
|
||||||
|
.put("appId", strAppId)
|
||||||
|
.put("priority", flowRule.priority())
|
||||||
|
.put("timeout", flowRule.timeout())
|
||||||
|
.put("isPermanent", flowRule.isPermanent())
|
||||||
|
.put("deviceId", flowRule.deviceId().toString());
|
||||||
|
|
||||||
|
if (flowRule.treatment() != null) {
|
||||||
|
final JsonCodec<TrafficTreatment> treatmentCodec =
|
||||||
|
context.codec(TrafficTreatment.class);
|
||||||
|
result.set("treatment", treatmentCodec.encode(flowRule.treatment(), context));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flowRule.selector() != null) {
|
||||||
|
final JsonCodec<TrafficSelector> selectorCodec =
|
||||||
|
context.codec(TrafficSelector.class);
|
||||||
|
result.set("selector", selectorCodec.encode(flowRule.selector(), context));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FlowRule decode(ObjectNode json, CodecContext context) {
|
public FlowRule decode(ObjectNode json, CodecContext context) {
|
||||||
@ -54,8 +88,9 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> {
|
|||||||
FlowRule.Builder resultBuilder = new DefaultFlowRule.Builder();
|
FlowRule.Builder resultBuilder = new DefaultFlowRule.Builder();
|
||||||
|
|
||||||
CoreService coreService = context.getService(CoreService.class);
|
CoreService coreService = context.getService(CoreService.class);
|
||||||
resultBuilder.fromApp(coreService
|
JsonNode appIdJson = json.get(APP_ID);
|
||||||
.registerApplication(REST_APP_ID));
|
String appId = appIdJson != null ? appIdJson.asText() : REST_APP_ID;
|
||||||
|
resultBuilder.fromApp(coreService.registerApplication(appId));
|
||||||
|
|
||||||
int priority = nullIsIllegal(json.get(PRIORITY),
|
int priority = nullIsIllegal(json.get(PRIORITY),
|
||||||
PRIORITY + MISSING_MEMBER_MESSAGE).asInt();
|
PRIORITY + MISSING_MEMBER_MESSAGE).asInt();
|
||||||
|
@ -17,6 +17,8 @@ package org.onosproject.codec.impl;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.TypeSafeDiagnosingMatcher;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.onlab.packet.EthType;
|
import org.onlab.packet.EthType;
|
||||||
@ -29,12 +31,14 @@ import org.onlab.packet.VlanId;
|
|||||||
import org.onosproject.codec.JsonCodec;
|
import org.onosproject.codec.JsonCodec;
|
||||||
import org.onosproject.core.CoreService;
|
import org.onosproject.core.CoreService;
|
||||||
import org.onosproject.net.ChannelSpacing;
|
import org.onosproject.net.ChannelSpacing;
|
||||||
|
import org.onosproject.net.DeviceId;
|
||||||
import org.onosproject.net.GridType;
|
import org.onosproject.net.GridType;
|
||||||
import org.onosproject.net.Lambda;
|
import org.onosproject.net.Lambda;
|
||||||
import org.onosproject.net.OchSignal;
|
import org.onosproject.net.OchSignal;
|
||||||
import org.onosproject.net.OchSignalType;
|
import org.onosproject.net.OchSignalType;
|
||||||
import org.onosproject.net.OduSignalType;
|
import org.onosproject.net.OduSignalType;
|
||||||
import org.onosproject.net.PortNumber;
|
import org.onosproject.net.PortNumber;
|
||||||
|
import org.onosproject.net.flow.DefaultFlowRule;
|
||||||
import org.onosproject.net.flow.FlowRule;
|
import org.onosproject.net.flow.FlowRule;
|
||||||
import org.onosproject.net.flow.criteria.Criterion;
|
import org.onosproject.net.flow.criteria.Criterion;
|
||||||
import org.onosproject.net.flow.criteria.EthCriterion;
|
import org.onosproject.net.flow.criteria.EthCriterion;
|
||||||
@ -75,6 +79,7 @@ import java.io.InputStream;
|
|||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.anyShort;
|
||||||
import static org.easymock.EasyMock.createMock;
|
import static org.easymock.EasyMock.createMock;
|
||||||
import static org.easymock.EasyMock.expect;
|
import static org.easymock.EasyMock.expect;
|
||||||
import static org.easymock.EasyMock.replay;
|
import static org.easymock.EasyMock.replay;
|
||||||
@ -105,6 +110,7 @@ public class FlowRuleCodecTest {
|
|||||||
|
|
||||||
expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID))
|
expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID))
|
||||||
.andReturn(APP_ID).anyTimes();
|
.andReturn(APP_ID).anyTimes();
|
||||||
|
expect(mockCoreService.getAppId(anyShort())).andReturn(APP_ID).anyTimes();
|
||||||
replay(mockCoreService);
|
replay(mockCoreService);
|
||||||
context.registerService(CoreService.class, mockCoreService);
|
context.registerService(CoreService.class, mockCoreService);
|
||||||
}
|
}
|
||||||
@ -165,6 +171,118 @@ public class FlowRuleCodecTest {
|
|||||||
|
|
||||||
SortedMap<String, Instruction> instructions = new TreeMap<>();
|
SortedMap<String, Instruction> instructions = new TreeMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that a simple rule encodes properly.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testFlowRuleEncode() {
|
||||||
|
|
||||||
|
DeviceId deviceId = DeviceId.deviceId("of:000000000000000a");
|
||||||
|
FlowRule permFlowRule = DefaultFlowRule.builder()
|
||||||
|
.withCookie(1)
|
||||||
|
.forTable(1)
|
||||||
|
.withPriority(1)
|
||||||
|
.makePermanent()
|
||||||
|
.forDevice(deviceId).build();
|
||||||
|
|
||||||
|
FlowRule tempFlowRule = DefaultFlowRule.builder()
|
||||||
|
.withCookie(1)
|
||||||
|
.forTable(1)
|
||||||
|
.withPriority(1)
|
||||||
|
.makeTemporary(1000)
|
||||||
|
.forDevice(deviceId).build();
|
||||||
|
|
||||||
|
ObjectNode permFlowRuleJson = flowRuleCodec.encode(permFlowRule, context);
|
||||||
|
ObjectNode tempFlowRuleJson = flowRuleCodec.encode(tempFlowRule, context);
|
||||||
|
|
||||||
|
assertThat(permFlowRuleJson, FlowRuleJsonMatcher.matchesFlowRule(permFlowRule));
|
||||||
|
assertThat(tempFlowRuleJson, FlowRuleJsonMatcher.matchesFlowRule(tempFlowRule));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class FlowRuleJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
|
||||||
|
|
||||||
|
private final FlowRule flowRule;
|
||||||
|
|
||||||
|
private FlowRuleJsonMatcher(FlowRule flowRule) {
|
||||||
|
this.flowRule = flowRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean matchesSafely(JsonNode jsonNode, Description description) {
|
||||||
|
|
||||||
|
// check id
|
||||||
|
long jsonId = jsonNode.get("id").asLong();
|
||||||
|
long id = flowRule.id().id();
|
||||||
|
if (jsonId != id) {
|
||||||
|
description.appendText("flow rule id was " + jsonId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: need to check application ID
|
||||||
|
|
||||||
|
// check tableId
|
||||||
|
int jsonTableId = jsonNode.get("tableId").asInt();
|
||||||
|
int tableId = flowRule.tableId();
|
||||||
|
if (jsonTableId != tableId) {
|
||||||
|
description.appendText("table id was " + jsonId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check priority
|
||||||
|
int jsonPriority = jsonNode.get("priority").asInt();
|
||||||
|
int priority = flowRule.priority();
|
||||||
|
if (jsonPriority != priority) {
|
||||||
|
description.appendText("priority was " + jsonPriority);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check timeout
|
||||||
|
int jsonTimeout = jsonNode.get("timeout").asInt();
|
||||||
|
int timeout = flowRule.timeout();
|
||||||
|
if (jsonTimeout != timeout) {
|
||||||
|
description.appendText("timeout was " + jsonTimeout);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check isPermanent
|
||||||
|
boolean jsonIsPermanent = jsonNode.get("isPermanent").asBoolean();
|
||||||
|
boolean isPermanent = flowRule.isPermanent();
|
||||||
|
if (jsonIsPermanent != isPermanent) {
|
||||||
|
description.appendText("isPermanent was " + jsonIsPermanent);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check deviceId
|
||||||
|
String jsonDeviceId = jsonNode.get("deviceId").asText();
|
||||||
|
String deviceId = flowRule.deviceId().toString();
|
||||||
|
if (!jsonDeviceId.equals(deviceId)) {
|
||||||
|
description.appendText("deviceId was " + jsonDeviceId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: need to check traffic treatment
|
||||||
|
|
||||||
|
// TODO: need to check selector
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendText(flowRule.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory to allocate a flow rule matcher.
|
||||||
|
*
|
||||||
|
* @param flowRule flow rule object we are looking for
|
||||||
|
* @return matcher
|
||||||
|
*/
|
||||||
|
public static FlowRuleJsonMatcher matchesFlowRule(FlowRule flowRule) {
|
||||||
|
return new FlowRuleJsonMatcher(flowRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up an instruction in the instruction map based on type and subtype.
|
* Looks up an instruction in the instruction map based on type and subtype.
|
||||||
*
|
*
|
||||||
|
@ -21,6 +21,8 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
|||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.ListMultimap;
|
import com.google.common.collect.ListMultimap;
|
||||||
import org.onlab.util.ItemNotFoundException;
|
import org.onlab.util.ItemNotFoundException;
|
||||||
|
import org.onosproject.app.ApplicationService;
|
||||||
|
import org.onosproject.core.ApplicationId;
|
||||||
import org.onosproject.net.Device;
|
import org.onosproject.net.Device;
|
||||||
import org.onosproject.net.DeviceId;
|
import org.onosproject.net.DeviceId;
|
||||||
import org.onosproject.net.device.DeviceService;
|
import org.onosproject.net.device.DeviceService;
|
||||||
@ -36,6 +38,7 @@ import javax.ws.rs.POST;
|
|||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
@ -61,6 +64,7 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
|
|
||||||
private static final String DEVICE_NOT_FOUND = "Device is not found";
|
private static final String DEVICE_NOT_FOUND = "Device is not found";
|
||||||
private static final String FLOW_NOT_FOUND = "Flow is not found";
|
private static final String FLOW_NOT_FOUND = "Flow is not found";
|
||||||
|
private static final String APP_ID_NOT_FOUND = "Application Id is not found";
|
||||||
private static final String FLOWS = "flows";
|
private static final String FLOWS = "flows";
|
||||||
private static final String DEVICE_ID = "deviceId";
|
private static final String DEVICE_ID = "deviceId";
|
||||||
private static final String FLOW_ID = "flowId";
|
private static final String FLOW_ID = "flowId";
|
||||||
@ -73,7 +77,7 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
* Gets all flow entries. Returns array of all flow rules in the system.
|
* Gets all flow entries. Returns array of all flow rules in the system.
|
||||||
*
|
*
|
||||||
* @return 200 OK with a collection of flows
|
* @return 200 OK with a collection of flows
|
||||||
* @onos.rsModel Flows
|
* @onos.rsModel FlowEntries
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@ -107,10 +111,15 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Response createFlows(InputStream stream) {
|
public Response createFlows(@QueryParam("appId") String appId, InputStream stream) {
|
||||||
try {
|
try {
|
||||||
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
|
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
|
||||||
ArrayNode flowsArray = (ArrayNode) jsonTree.get(FLOWS);
|
ArrayNode flowsArray = (ArrayNode) jsonTree.get(FLOWS);
|
||||||
|
|
||||||
|
if (appId != null) {
|
||||||
|
flowsArray.forEach(flowJson -> ((ObjectNode) flowJson).put("appId", appId));
|
||||||
|
}
|
||||||
|
|
||||||
List<FlowRule> rules = codec(FlowRule.class).decode(flowsArray, this);
|
List<FlowRule> rules = codec(FlowRule.class).decode(flowsArray, this);
|
||||||
service.applyFlowRules(rules.toArray(new FlowRule[rules.size()]));
|
service.applyFlowRules(rules.toArray(new FlowRule[rules.size()]));
|
||||||
rules.forEach(flowRule -> {
|
rules.forEach(flowRule -> {
|
||||||
@ -131,10 +140,11 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
*
|
*
|
||||||
* @param deviceId device identifier
|
* @param deviceId device identifier
|
||||||
* @return 200 OK with a collection of flows of given device
|
* @return 200 OK with a collection of flows of given device
|
||||||
* @onos.rsModel Flows
|
* @onos.rsModel FlowEntries
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
// TODO: we need to add "/device" suffix to the path to differentiate with appId
|
||||||
@Path("{deviceId}")
|
@Path("{deviceId}")
|
||||||
public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
|
public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
|
||||||
final Iterable<FlowEntry> flowEntries =
|
final Iterable<FlowEntry> flowEntries =
|
||||||
@ -150,13 +160,13 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets flow rule. Returns the flow entry specified by the device id and
|
* Gets flow rules. Returns the flow entry specified by the device id and
|
||||||
* flow rule id.
|
* flow rule id.
|
||||||
*
|
*
|
||||||
* @param deviceId device identifier
|
* @param deviceId device identifier
|
||||||
* @param flowId flow rule identifier
|
* @param flowId flow rule identifier
|
||||||
* @return 200 OK with a flows of given device and flow
|
* @return 200 OK with a collection of flows of given device and flow
|
||||||
* @onos.rsModel Flows
|
* @onos.rsModel FlowEntries
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@ -177,6 +187,43 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
return ok(root).build();
|
return ok(root).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets flow rules generated by an application.
|
||||||
|
* Returns the flow rule specified by the application id.
|
||||||
|
*
|
||||||
|
* @param appId application identifier
|
||||||
|
* @return 200 OK with a collection of flows of given application id
|
||||||
|
* @onos.rsModel FlowRules
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Path("application/{appId}")
|
||||||
|
public Response getFlowByAppId(@PathParam("appId") String appId) {
|
||||||
|
final ApplicationService appService = get(ApplicationService.class);
|
||||||
|
final ApplicationId idInstant = nullIsNotFound(appService.getId(appId), APP_ID_NOT_FOUND);
|
||||||
|
final Iterable<FlowRule> flowRules = service.getFlowRulesById(idInstant);
|
||||||
|
|
||||||
|
flowRules.forEach(flow -> flowsNode.add(codec(FlowRule.class).encode(flow, this)));
|
||||||
|
return ok(root).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes flow rules by application ID.
|
||||||
|
* Removes a collection of flow rules generated by the given application.
|
||||||
|
*
|
||||||
|
* @param appId application identifier
|
||||||
|
* @return 204 NO CONTENT
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Path("application/{appId}")
|
||||||
|
public Response removeFlowByAppId(@PathParam("appId") String appId) {
|
||||||
|
final ApplicationService appService = get(ApplicationService.class);
|
||||||
|
final ApplicationId idInstant = nullIsNotFound(appService.getId(appId), APP_ID_NOT_FOUND);
|
||||||
|
service.removeFlowRulesById(idInstant);
|
||||||
|
return Response.noContent().build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new flow rule. Creates and installs a new flow rule for the
|
* Creates new flow rule. Creates and installs a new flow rule for the
|
||||||
* specified device. <br>
|
* specified device. <br>
|
||||||
@ -187,6 +234,7 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
* https://wiki.onosproject.org/display/ONOS/Flow+Rule+Criteria
|
* https://wiki.onosproject.org/display/ONOS/Flow+Rule+Criteria
|
||||||
*
|
*
|
||||||
* @param deviceId device identifier
|
* @param deviceId device identifier
|
||||||
|
* @param appId application identifier
|
||||||
* @param stream flow rule JSON
|
* @param stream flow rule JSON
|
||||||
* @return status of the request - CREATED if the JSON is correct,
|
* @return status of the request - CREATED if the JSON is correct,
|
||||||
* BAD_REQUEST if the JSON is invalid
|
* BAD_REQUEST if the JSON is invalid
|
||||||
@ -197,6 +245,7 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Response createFlow(@PathParam("deviceId") String deviceId,
|
public Response createFlow(@PathParam("deviceId") String deviceId,
|
||||||
|
@QueryParam("appId") String appId,
|
||||||
InputStream stream) {
|
InputStream stream) {
|
||||||
try {
|
try {
|
||||||
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
|
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
|
||||||
@ -207,6 +256,11 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
"Invalid deviceId in flow creation request");
|
"Invalid deviceId in flow creation request");
|
||||||
}
|
}
|
||||||
jsonTree.put("deviceId", deviceId);
|
jsonTree.put("deviceId", deviceId);
|
||||||
|
|
||||||
|
if (appId != null) {
|
||||||
|
jsonTree.put("appId", appId);
|
||||||
|
}
|
||||||
|
|
||||||
FlowRule rule = codec(FlowRule.class).decode(jsonTree, this);
|
FlowRule rule = codec(FlowRule.class).decode(jsonTree, this);
|
||||||
service.applyFlowRules(rule);
|
service.applyFlowRules(rule);
|
||||||
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
|
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
|
||||||
@ -223,7 +277,7 @@ public class FlowsWebResource extends AbstractWebResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove flow rule. Removes the specified flow rule.
|
* Removes flow rule. Removes the specified flow rule.
|
||||||
*
|
*
|
||||||
* @param deviceId device identifier
|
* @param deviceId device identifier
|
||||||
* @param flowId flow rule identifier
|
* @param flowId flow rule identifier
|
||||||
|
373
web/api/src/main/resources/definitions/FlowEntries.json
Normal file
373
web/api/src/main/resources/definitions/FlowEntries.json
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"title": "flows",
|
||||||
|
"required": [
|
||||||
|
"flows"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"flows": {
|
||||||
|
"type": "array",
|
||||||
|
"xml": {
|
||||||
|
"name": "flows",
|
||||||
|
"wrapped": true
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "flow",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"tableId",
|
||||||
|
"appId",
|
||||||
|
"groupId",
|
||||||
|
"priority",
|
||||||
|
"timeout",
|
||||||
|
"isPermanent",
|
||||||
|
"deviceId",
|
||||||
|
"state",
|
||||||
|
"life",
|
||||||
|
"packets",
|
||||||
|
"bytes",
|
||||||
|
"lastSeen"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "12103425214920339"
|
||||||
|
},
|
||||||
|
"tableId": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"example": 3
|
||||||
|
},
|
||||||
|
"appId": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "org.onosproject.core"
|
||||||
|
},
|
||||||
|
"groupId": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"example": 0
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"example": 40000
|
||||||
|
},
|
||||||
|
"timeout": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"example": 0
|
||||||
|
},
|
||||||
|
"isPermanent": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"deviceId": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "of:0000000000000003"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "ADDED"
|
||||||
|
},
|
||||||
|
"life": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"example": 69889
|
||||||
|
},
|
||||||
|
"packets": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"example": 22546
|
||||||
|
},
|
||||||
|
"bytes": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"example": 1826226
|
||||||
|
},
|
||||||
|
"lastSeen": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"example": 1447892365670
|
||||||
|
},
|
||||||
|
"treatment": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "treatment",
|
||||||
|
"required": [
|
||||||
|
"instructions",
|
||||||
|
"deferred"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"instructions": {
|
||||||
|
"type": "array",
|
||||||
|
"title": "treatment",
|
||||||
|
"required": [
|
||||||
|
"properties",
|
||||||
|
"port"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "instruction",
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"port"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "OUTPUT"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "CONTROLLER"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deferred": {
|
||||||
|
"type": "array",
|
||||||
|
"xml": {
|
||||||
|
"name": "deferred",
|
||||||
|
"wrapped": true
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
344
web/api/src/main/resources/definitions/FlowRules.json
Normal file
344
web/api/src/main/resources/definitions/FlowRules.json
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"title": "flows",
|
||||||
|
"required": [
|
||||||
|
"flows"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"flows": {
|
||||||
|
"type": "array",
|
||||||
|
"xml": {
|
||||||
|
"name": "flows",
|
||||||
|
"wrapped": true
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "flow",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"tableId",
|
||||||
|
"appId",
|
||||||
|
"groupId",
|
||||||
|
"priority",
|
||||||
|
"timeout",
|
||||||
|
"isPermanent",
|
||||||
|
"deviceId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "12103425214920339"
|
||||||
|
},
|
||||||
|
"tableId": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"example": 3
|
||||||
|
},
|
||||||
|
"appId": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "org.onosproject.core"
|
||||||
|
},
|
||||||
|
"groupId": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"example": 0
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"example": 40000
|
||||||
|
},
|
||||||
|
"timeout": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"example": 0
|
||||||
|
},
|
||||||
|
"isPermanent": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"deviceId": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "of:0000000000000003"
|
||||||
|
},
|
||||||
|
"treatment": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "treatment",
|
||||||
|
"required": [
|
||||||
|
"instructions",
|
||||||
|
"deferred"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"instructions": {
|
||||||
|
"type": "array",
|
||||||
|
"title": "treatment",
|
||||||
|
"required": [
|
||||||
|
"properties",
|
||||||
|
"port"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "instruction",
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"port"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "OUTPUT"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "CONTROLLER"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deferred": {
|
||||||
|
"type": "array",
|
||||||
|
"xml": {
|
||||||
|
"name": "deferred",
|
||||||
|
"wrapped": true
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,373 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"title": "flows",
|
|
||||||
"required": [
|
|
||||||
"flows"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"flows": {
|
|
||||||
"type": "array",
|
|
||||||
"xml": {
|
|
||||||
"name": "flows",
|
|
||||||
"wrapped": true
|
|
||||||
},
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"title": "flow",
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"tableId",
|
|
||||||
"appId",
|
|
||||||
"groupId",
|
|
||||||
"priority",
|
|
||||||
"timeout",
|
|
||||||
"isPermanent",
|
|
||||||
"deviceId",
|
|
||||||
"state",
|
|
||||||
"life",
|
|
||||||
"packets",
|
|
||||||
"bytes",
|
|
||||||
"lastSeen"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "12103425214920339"
|
|
||||||
},
|
|
||||||
"tableId": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int32",
|
|
||||||
"example": 3
|
|
||||||
},
|
|
||||||
"appId": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "org.onosproject.core"
|
|
||||||
},
|
|
||||||
"groupId": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64",
|
|
||||||
"example": 0
|
|
||||||
},
|
|
||||||
"priority": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int32",
|
|
||||||
"example": 40000
|
|
||||||
},
|
|
||||||
"timeout": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int32",
|
|
||||||
"example": 0
|
|
||||||
},
|
|
||||||
"isPermanent": {
|
|
||||||
"type": "boolean",
|
|
||||||
"example": true
|
|
||||||
},
|
|
||||||
"deviceId": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "of:0000000000000003"
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "ADDED"
|
|
||||||
},
|
|
||||||
"life": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64",
|
|
||||||
"example": 69889
|
|
||||||
},
|
|
||||||
"packets": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64",
|
|
||||||
"example": 22546
|
|
||||||
},
|
|
||||||
"bytes": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64",
|
|
||||||
"example": 1826226
|
|
||||||
},
|
|
||||||
"lastSeen": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64",
|
|
||||||
"example": 1447892365670
|
|
||||||
},
|
|
||||||
"treatment": {
|
|
||||||
"type": "object",
|
|
||||||
"title": "treatment",
|
|
||||||
"required": [
|
|
||||||
"instructions",
|
|
||||||
"deferred"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"instructions": {
|
|
||||||
"type": "array",
|
|
||||||
"title": "treatment",
|
|
||||||
"required": [
|
|
||||||
"properties",
|
|
||||||
"port"
|
|
||||||
],
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"title": "instruction",
|
|
||||||
"required": [
|
|
||||||
"type",
|
|
||||||
"port"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"type": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "OUTPUT"
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "CONTROLLER"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"deferred": {
|
|
||||||
"type": "array",
|
|
||||||
"xml": {
|
|
||||||
"name": "deferred",
|
|
||||||
"wrapped": true
|
|
||||||
},
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,6 +19,7 @@ import com.eclipsesource.json.Json;
|
|||||||
import com.eclipsesource.json.JsonArray;
|
import com.eclipsesource.json.JsonArray;
|
||||||
import com.eclipsesource.json.JsonObject;
|
import com.eclipsesource.json.JsonObject;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
@ -29,6 +30,7 @@ import org.onlab.osgi.ServiceDirectory;
|
|||||||
import org.onlab.osgi.TestServiceDirectory;
|
import org.onlab.osgi.TestServiceDirectory;
|
||||||
import org.onlab.packet.MacAddress;
|
import org.onlab.packet.MacAddress;
|
||||||
import org.onlab.rest.BaseResource;
|
import org.onlab.rest.BaseResource;
|
||||||
|
import org.onosproject.app.ApplicationService;
|
||||||
import org.onosproject.codec.CodecService;
|
import org.onosproject.codec.CodecService;
|
||||||
import org.onosproject.codec.impl.CodecManager;
|
import org.onosproject.codec.impl.CodecManager;
|
||||||
import org.onosproject.codec.impl.FlowRuleCodec;
|
import org.onosproject.codec.impl.FlowRuleCodec;
|
||||||
@ -65,6 +67,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import static org.easymock.EasyMock.anyObject;
|
import static org.easymock.EasyMock.anyObject;
|
||||||
import static org.easymock.EasyMock.anyShort;
|
import static org.easymock.EasyMock.anyShort;
|
||||||
|
import static org.easymock.EasyMock.anyString;
|
||||||
import static org.easymock.EasyMock.createMock;
|
import static org.easymock.EasyMock.createMock;
|
||||||
import static org.easymock.EasyMock.expect;
|
import static org.easymock.EasyMock.expect;
|
||||||
import static org.easymock.EasyMock.expectLastCall;
|
import static org.easymock.EasyMock.expectLastCall;
|
||||||
@ -98,6 +101,8 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
final Device device2 = new DefaultDevice(null, deviceId2, Device.Type.OTHER,
|
final Device device2 = new DefaultDevice(null, deviceId2, Device.Type.OTHER,
|
||||||
"", "", "", "", null);
|
"", "", "", "", null);
|
||||||
|
|
||||||
|
final ApplicationService mockApplicationService = createMock(ApplicationService.class);
|
||||||
|
|
||||||
final MockFlowEntry flow1 = new MockFlowEntry(deviceId1, 1);
|
final MockFlowEntry flow1 = new MockFlowEntry(deviceId1, 1);
|
||||||
final MockFlowEntry flow2 = new MockFlowEntry(deviceId1, 2);
|
final MockFlowEntry flow2 = new MockFlowEntry(deviceId1, 2);
|
||||||
|
|
||||||
@ -107,6 +112,14 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
final MockFlowEntry flow5 = new MockFlowEntry(deviceId2, 5);
|
final MockFlowEntry flow5 = new MockFlowEntry(deviceId2, 5);
|
||||||
final MockFlowEntry flow6 = new MockFlowEntry(deviceId2, 6);
|
final MockFlowEntry flow6 = new MockFlowEntry(deviceId2, 6);
|
||||||
|
|
||||||
|
final MockFlowRule flowRule1 = new MockFlowRule(deviceId1, 1);
|
||||||
|
final MockFlowRule flowRule2 = new MockFlowRule(deviceId1, 2);
|
||||||
|
|
||||||
|
final MockFlowRule flowRule3 = new MockFlowRule(deviceId2, 3);
|
||||||
|
final MockFlowRule flowRule4 = new MockFlowRule(deviceId2, 4);
|
||||||
|
|
||||||
|
final Set<FlowRule> flowRules = Sets.newHashSet();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mock class for a flow entry.
|
* Mock class for a flow entry.
|
||||||
*/
|
*/
|
||||||
@ -218,6 +231,83 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock class for a flow rule.
|
||||||
|
*/
|
||||||
|
private static class MockFlowRule implements FlowRule {
|
||||||
|
|
||||||
|
final DeviceId deviceId;
|
||||||
|
final long baseValue;
|
||||||
|
TrafficTreatment treatment;
|
||||||
|
TrafficSelector selector;
|
||||||
|
|
||||||
|
public MockFlowRule(DeviceId deviceId, long id) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.baseValue = id * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FlowId id() {
|
||||||
|
final long id = baseValue + 55;
|
||||||
|
return FlowId.valueOf(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short appId() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupId groupId() {
|
||||||
|
return new DefaultGroupId(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int priority() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeviceId deviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TrafficSelector selector() {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TrafficTreatment treatment() {
|
||||||
|
return treatment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int timeout() {
|
||||||
|
return (int) (baseValue + 77);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPermanent() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int tableId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exactMatch(FlowRule rule) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FlowRuleExtPayLoad payLoad() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates some flows used as testing data.
|
* Populates some flows used as testing data.
|
||||||
*/
|
*/
|
||||||
@ -248,6 +338,26 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
.andReturn(rules.get(deviceId2)).anyTimes();
|
.andReturn(rules.get(deviceId2)).anyTimes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates some flow rules used as testing data.
|
||||||
|
*/
|
||||||
|
private void setupMockFlowRules() {
|
||||||
|
flowRule2.treatment = DefaultTrafficTreatment.builder()
|
||||||
|
.setEthDst(MacAddress.BROADCAST)
|
||||||
|
.build();
|
||||||
|
flowRule2.selector = DefaultTrafficSelector.builder()
|
||||||
|
.matchEthType((short) 3)
|
||||||
|
.matchIPProtocol((byte) 9)
|
||||||
|
.build();
|
||||||
|
flowRule4.treatment = DefaultTrafficTreatment.builder()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
flowRules.add(flowRule1);
|
||||||
|
flowRules.add(flowRule2);
|
||||||
|
flowRules.add(flowRule3);
|
||||||
|
flowRules.add(flowRule4);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the global values for all the tests.
|
* Sets up the global values for all the tests.
|
||||||
*/
|
*/
|
||||||
@ -264,6 +374,8 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
// Mock Core Service
|
// Mock Core Service
|
||||||
expect(mockCoreService.getAppId(anyShort()))
|
expect(mockCoreService.getAppId(anyShort()))
|
||||||
.andReturn(NetTestTools.APP_ID).anyTimes();
|
.andReturn(NetTestTools.APP_ID).anyTimes();
|
||||||
|
expect(mockCoreService.getAppId(anyString()))
|
||||||
|
.andReturn(NetTestTools.APP_ID).anyTimes();
|
||||||
expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID))
|
expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID))
|
||||||
.andReturn(APP_ID).anyTimes();
|
.andReturn(APP_ID).anyTimes();
|
||||||
replay(mockCoreService);
|
replay(mockCoreService);
|
||||||
@ -276,7 +388,8 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
.add(FlowRuleService.class, mockFlowService)
|
.add(FlowRuleService.class, mockFlowService)
|
||||||
.add(DeviceService.class, mockDeviceService)
|
.add(DeviceService.class, mockDeviceService)
|
||||||
.add(CodecService.class, codecService)
|
.add(CodecService.class, codecService)
|
||||||
.add(CoreService.class, mockCoreService);
|
.add(CoreService.class, mockCoreService)
|
||||||
|
.add(ApplicationService.class, mockApplicationService);
|
||||||
|
|
||||||
BaseResource.setServiceDirectory(testDirectory);
|
BaseResource.setServiceDirectory(testDirectory);
|
||||||
}
|
}
|
||||||
@ -294,12 +407,12 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
* Hamcrest matcher to check that a flow representation in JSON matches
|
* Hamcrest matcher to check that a flow representation in JSON matches
|
||||||
* the actual flow entry.
|
* the actual flow entry.
|
||||||
*/
|
*/
|
||||||
public static class FlowJsonMatcher extends TypeSafeMatcher<JsonObject> {
|
public static class FlowEntryJsonMatcher extends TypeSafeMatcher<JsonObject> {
|
||||||
private final FlowEntry flow;
|
private final FlowEntry flow;
|
||||||
private final String expectedAppId;
|
private final String expectedAppId;
|
||||||
private String reason = "";
|
private String reason = "";
|
||||||
|
|
||||||
public FlowJsonMatcher(FlowEntry flowValue, String expectedAppIdValue) {
|
public FlowEntryJsonMatcher(FlowEntry flowValue, String expectedAppIdValue) {
|
||||||
flow = flowValue;
|
flow = flowValue;
|
||||||
expectedAppId = expectedAppIdValue;
|
expectedAppId = expectedAppIdValue;
|
||||||
}
|
}
|
||||||
@ -398,19 +511,19 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
* @param flow flow object we are looking for
|
* @param flow flow object we are looking for
|
||||||
* @return matcher
|
* @return matcher
|
||||||
*/
|
*/
|
||||||
private static FlowJsonMatcher matchesFlow(FlowEntry flow, String expectedAppName) {
|
private static FlowEntryJsonMatcher matchesFlow(FlowEntry flow, String expectedAppName) {
|
||||||
return new FlowJsonMatcher(flow, expectedAppName);
|
return new FlowEntryJsonMatcher(flow, expectedAppName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hamcrest matcher to check that a flow is represented properly in a JSON
|
* Hamcrest matcher to check that a flow is represented properly in a JSON
|
||||||
* array of flows.
|
* array of flows.
|
||||||
*/
|
*/
|
||||||
public static class FlowJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
|
public static class FlowEntryJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
|
||||||
private final FlowEntry flow;
|
private final FlowEntry flow;
|
||||||
private String reason = "";
|
private String reason = "";
|
||||||
|
|
||||||
public FlowJsonArrayMatcher(FlowEntry flowValue) {
|
public FlowEntryJsonArrayMatcher(FlowEntry flowValue) {
|
||||||
flow = flowValue;
|
flow = flowValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,8 +565,174 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
* @param flow flow object we are looking for
|
* @param flow flow object we are looking for
|
||||||
* @return matcher
|
* @return matcher
|
||||||
*/
|
*/
|
||||||
private static FlowJsonArrayMatcher hasFlow(FlowEntry flow) {
|
private static FlowEntryJsonArrayMatcher hasFlow(FlowEntry flow) {
|
||||||
return new FlowJsonArrayMatcher(flow);
|
return new FlowEntryJsonArrayMatcher(flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hamcrest matcher to check that a flow representation in JSON matches
|
||||||
|
* the actual flow rule.
|
||||||
|
*/
|
||||||
|
public static class FlowRuleJsonMatcher extends TypeSafeMatcher<JsonObject> {
|
||||||
|
private final FlowRule flow;
|
||||||
|
private final String expectedAppId;
|
||||||
|
private String reason = "";
|
||||||
|
|
||||||
|
public FlowRuleJsonMatcher(FlowRule flowValue, String expectedAppIdValue) {
|
||||||
|
flow = flowValue;
|
||||||
|
expectedAppId = expectedAppIdValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matchesSafely(JsonObject jsonFlow) {
|
||||||
|
// check id
|
||||||
|
final String jsonId = jsonFlow.get("id").asString();
|
||||||
|
final String flowId = Long.toString(flow.id().value());
|
||||||
|
if (!jsonId.equals(flowId)) {
|
||||||
|
reason = "id " + flow.id().toString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check application id
|
||||||
|
final String jsonAppId = jsonFlow.get("appId").asString();
|
||||||
|
if (!jsonAppId.equals(expectedAppId)) {
|
||||||
|
reason = "appId " + Short.toString(flow.appId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check device id
|
||||||
|
final String jsonDeviceId = jsonFlow.get("deviceId").asString();
|
||||||
|
if (!jsonDeviceId.equals(flow.deviceId().toString())) {
|
||||||
|
reason = "deviceId " + flow.deviceId();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check treatment and instructions array
|
||||||
|
if (flow.treatment() != null) {
|
||||||
|
final JsonObject jsonTreatment = jsonFlow.get("treatment").asObject();
|
||||||
|
final JsonArray jsonInstructions = jsonTreatment.get("instructions").asArray();
|
||||||
|
if (flow.treatment().immediate().size() != jsonInstructions.size()) {
|
||||||
|
reason = "instructions array size of " +
|
||||||
|
Integer.toString(flow.treatment().immediate().size());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (final Instruction instruction : flow.treatment().immediate()) {
|
||||||
|
boolean instructionFound = false;
|
||||||
|
for (int instructionIndex = 0; instructionIndex < jsonInstructions.size(); instructionIndex++) {
|
||||||
|
final String jsonType =
|
||||||
|
jsonInstructions.get(instructionIndex)
|
||||||
|
.asObject().get("type").asString();
|
||||||
|
final String instructionType = instruction.type().name();
|
||||||
|
if (jsonType.equals(instructionType)) {
|
||||||
|
instructionFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!instructionFound) {
|
||||||
|
reason = "instruction " + instruction.toString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check selector and criteria array
|
||||||
|
if (flow.selector() != null) {
|
||||||
|
final JsonObject jsonTreatment = jsonFlow.get("selector").asObject();
|
||||||
|
final JsonArray jsonCriteria = jsonTreatment.get("criteria").asArray();
|
||||||
|
if (flow.selector().criteria().size() != jsonCriteria.size()) {
|
||||||
|
reason = "criteria array size of " +
|
||||||
|
Integer.toString(flow.selector().criteria().size());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (final Criterion criterion : flow.selector().criteria()) {
|
||||||
|
boolean criterionFound = false;
|
||||||
|
|
||||||
|
for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) {
|
||||||
|
final String jsonType =
|
||||||
|
jsonCriteria.get(criterionIndex)
|
||||||
|
.asObject().get("type").asString();
|
||||||
|
final String criterionType = criterion.type().name();
|
||||||
|
if (jsonType.equals(criterionType)) {
|
||||||
|
criterionFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!criterionFound) {
|
||||||
|
reason = "criterion " + criterion.toString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendText(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory to allocate a flow matcher.
|
||||||
|
*
|
||||||
|
* @param flow flow rule object we are looking for
|
||||||
|
* @return matcher
|
||||||
|
*/
|
||||||
|
private static FlowRuleJsonMatcher matchesFlowRule(FlowRule flow, String expectedAppName) {
|
||||||
|
return new FlowRuleJsonMatcher(flow, expectedAppName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hamcrest matcher to check that a flow is represented properly in a JSON
|
||||||
|
* array of flow rules.
|
||||||
|
*/
|
||||||
|
public static class FlowRuleJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
|
||||||
|
private final FlowRule flow;
|
||||||
|
private String reason = "";
|
||||||
|
|
||||||
|
public FlowRuleJsonArrayMatcher(FlowRule flowValue) {
|
||||||
|
flow = flowValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matchesSafely(JsonArray json) {
|
||||||
|
boolean flowFound = false;
|
||||||
|
|
||||||
|
for (int jsonFlowIndex = 0; jsonFlowIndex < json.size();
|
||||||
|
jsonFlowIndex++) {
|
||||||
|
|
||||||
|
final JsonObject jsonFlow = json.get(jsonFlowIndex).asObject();
|
||||||
|
|
||||||
|
final String flowId = Long.toString(flow.id().value());
|
||||||
|
final String jsonFlowId = jsonFlow.get("id").asString();
|
||||||
|
if (jsonFlowId.equals(flowId)) {
|
||||||
|
flowFound = true;
|
||||||
|
|
||||||
|
// We found the correct flow, check attribute values
|
||||||
|
assertThat(jsonFlow, matchesFlowRule(flow, APP_ID.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!flowFound) {
|
||||||
|
reason = "Flow with id " + flow.id().toString() + " not found";
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendText(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory to allocate a flow array matcher.
|
||||||
|
*
|
||||||
|
* @param flow flow rule object we are looking for
|
||||||
|
* @return matcher
|
||||||
|
*/
|
||||||
|
private static FlowRuleJsonArrayMatcher hasFlowRule(FlowRule flow) {
|
||||||
|
return new FlowRuleJsonArrayMatcher(flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -572,7 +851,7 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
* Tests creating a flow with POST.
|
* Tests creating a flow with POST.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testPost() {
|
public void testPostWithoutAppId() {
|
||||||
mockFlowService.applyFlowRules(anyObject());
|
mockFlowService.applyFlowRules(anyObject());
|
||||||
expectLastCall();
|
expectLastCall();
|
||||||
replay(mockFlowService);
|
replay(mockFlowService);
|
||||||
@ -589,6 +868,28 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/"));
|
assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests creating a flow with POST while specifying application identifier.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPostWithAppId() {
|
||||||
|
mockFlowService.applyFlowRules(anyObject());
|
||||||
|
expectLastCall();
|
||||||
|
replay(mockFlowService);
|
||||||
|
|
||||||
|
WebTarget wt = target();
|
||||||
|
InputStream jsonStream = FlowsResourceTest.class
|
||||||
|
.getResourceAsStream("post-flow.json");
|
||||||
|
|
||||||
|
Response response = wt.path("flows/of:0000000000000001")
|
||||||
|
.queryParam("appId", "org.onosproject.rest")
|
||||||
|
.request(MediaType.APPLICATION_JSON_TYPE)
|
||||||
|
.post(Entity.json(jsonStream));
|
||||||
|
assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
|
||||||
|
String location = response.getLocation().getPath();
|
||||||
|
assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests deleting a flow.
|
* Tests deleting a flow.
|
||||||
*/
|
*/
|
||||||
@ -609,4 +910,55 @@ public class FlowsResourceTest extends ResourceTest {
|
|||||||
assertThat(deleteResponse.getStatus(),
|
assertThat(deleteResponse.getStatus(),
|
||||||
is(HttpURLConnection.HTTP_NO_CONTENT));
|
is(HttpURLConnection.HTTP_NO_CONTENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the result of a rest api GET for an application.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetFlowByAppId() {
|
||||||
|
setupMockFlowRules();
|
||||||
|
|
||||||
|
expect(mockApplicationService.getId(anyObject())).andReturn(APP_ID).anyTimes();
|
||||||
|
replay(mockApplicationService);
|
||||||
|
|
||||||
|
expect(mockFlowService.getFlowRulesById(APP_ID)).andReturn(flowRules).anyTimes();
|
||||||
|
replay(mockFlowService);
|
||||||
|
|
||||||
|
final WebTarget wt = target();
|
||||||
|
final String response = wt.path("flows/application/1").request().get(String.class);
|
||||||
|
final JsonObject result = Json.parse(response).asObject();
|
||||||
|
assertThat(result, notNullValue());
|
||||||
|
|
||||||
|
assertThat(result.names(), hasSize(1));
|
||||||
|
assertThat(result.names().get(0), is("flows"));
|
||||||
|
final JsonArray jsonFlows = result.get("flows").asArray();
|
||||||
|
assertThat(jsonFlows, notNullValue());
|
||||||
|
assertThat(jsonFlows, hasFlowRule(flowRule1));
|
||||||
|
assertThat(jsonFlows, hasFlowRule(flowRule2));
|
||||||
|
assertThat(jsonFlows, hasFlowRule(flowRule3));
|
||||||
|
assertThat(jsonFlows, hasFlowRule(flowRule4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the result of a rest api DELETE for an application.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRemoveFlowByAppId() {
|
||||||
|
expect(mockApplicationService.getId(anyObject())).andReturn(APP_ID).anyTimes();
|
||||||
|
replay(mockApplicationService);
|
||||||
|
|
||||||
|
mockFlowService.removeFlowRulesById(APP_ID);
|
||||||
|
expectLastCall();
|
||||||
|
replay(mockFlowService);
|
||||||
|
|
||||||
|
WebTarget wt = target();
|
||||||
|
|
||||||
|
String location = "/flows/application/1";
|
||||||
|
|
||||||
|
Response deleteResponse = wt.path(location)
|
||||||
|
.request()
|
||||||
|
.delete();
|
||||||
|
assertThat(deleteResponse.getStatus(),
|
||||||
|
is(HttpURLConnection.HTTP_NO_CONTENT));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user