summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/acl
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/apps/acl')
-rw-r--r--framework/src/onos/apps/acl/pom.xml30
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclRule.java290
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclService.java56
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclStore.java146
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclWebResource.java191
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/RuleId.java85
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/AclManager.java338
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/DistributedAclStore.java251
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/package-info.java20
-rw-r--r--framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/package-info.java20
-rw-r--r--framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml2
-rw-r--r--framework/src/onos/apps/acl/src/test/java/org/onosproject/acl/AclWebResourceTest.java142
12 files changed, 1563 insertions, 8 deletions
diff --git a/framework/src/onos/apps/acl/pom.xml b/framework/src/onos/apps/acl/pom.xml
index 54dee432..454ac7e6 100644
--- a/framework/src/onos/apps/acl/pom.xml
+++ b/framework/src/onos/apps/acl/pom.xml
@@ -18,7 +18,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -36,10 +38,10 @@
<url>http://onosproject.org</url>
<properties>
- <onos.version>1.4.0-SNAPSHOT</onos.version>
<onos.app.name>org.onosproject.acl</onos.app.name>
<onos.app.origin>DLUT</onos.app.origin>
- <web.context>/onos/acl</web.context>
+
+ <web.context>/onos/v1/acl</web.context>
<api.version>1.0.0</api.version>
<api.title>ONOS ACL Application REST API</api.title>
<api.description>
@@ -64,19 +66,34 @@
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onlab-junit</artifactId>
- <version>${onos.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-rest</artifactId>
- <version>${onos.version}</version>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-rest</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-core-serializers</artifactId>
- <version>${onos.version}</version>
+ <version>${project.version}</version>
</dependency>
<dependency>
@@ -100,7 +117,6 @@
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onlab-misc</artifactId>
- <version>${onos.version}</version>
</dependency>
</dependencies>
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclRule.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclRule.java
new file mode 100644
index 00000000..8c91da4c
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclRule.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import com.google.common.base.MoreObjects;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Prefix;
+import org.onosproject.core.IdGenerator;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * ACL rule class.
+ */
+public final class AclRule {
+
+ private final RuleId id;
+
+ private final Ip4Prefix srcIp;
+ private final Ip4Prefix dstIp;
+ private final byte ipProto;
+ private final short dstTpPort;
+ private final Action action;
+
+ private static IdGenerator idGenerator;
+
+ /**
+ * Enum type for ACL rule's action.
+ */
+ public enum Action {
+ DENY, ALLOW
+ }
+
+ /**
+ * Constructor for serializer.
+ */
+ private AclRule() {
+ this.id = null;
+ this.srcIp = null;
+ this.dstIp = null;
+ this.ipProto = 0;
+ this.dstTpPort = 0;
+ this.action = null;
+ }
+
+ /**
+ * Create a new ACL rule.
+ *
+ * @param srcIp source IP address
+ * @param dstIp destination IP address
+ * @param ipProto IP protocol
+ * @param dstTpPort destination transport layer port
+ * @param action ACL rule's action
+ */
+ private AclRule(Ip4Prefix srcIp, Ip4Prefix dstIp, byte ipProto,
+ short dstTpPort, Action action) {
+ checkState(idGenerator != null, "Id generator is not bound.");
+ this.id = RuleId.valueOf(idGenerator.getNewId());
+ this.srcIp = srcIp;
+ this.dstIp = dstIp;
+ this.ipProto = ipProto;
+ this.dstTpPort = dstTpPort;
+ this.action = action;
+ }
+
+ /**
+ * Check if the first CIDR address is in (or the same as) the second CIDR address.
+ */
+ private boolean checkCIDRinCIDR(Ip4Prefix cidrAddr1, Ip4Prefix cidrAddr2) {
+ if (cidrAddr2 == null) {
+ return true;
+ } else if (cidrAddr1 == null) {
+ return false;
+ }
+ if (cidrAddr1.prefixLength() < cidrAddr2.prefixLength()) {
+ return false;
+ }
+ int offset = 32 - cidrAddr2.prefixLength();
+
+ int cidr1Prefix = cidrAddr1.address().toInt();
+ int cidr2Prefix = cidrAddr2.address().toInt();
+ cidr1Prefix = cidr1Prefix >> offset;
+ cidr2Prefix = cidr2Prefix >> offset;
+ cidr1Prefix = cidr1Prefix << offset;
+ cidr2Prefix = cidr2Prefix << offset;
+
+ return (cidr1Prefix == cidr2Prefix);
+ }
+
+ /**
+ * Check if this ACL rule match the given ACL rule.
+ *
+ * @param r ACL rule to check against
+ * @return true if this ACL rule matches the given ACL ruleule.
+ */
+ public boolean checkMatch(AclRule r) {
+ return (this.dstTpPort == r.dstTpPort || r.dstTpPort == 0)
+ && (this.ipProto == r.ipProto || r.ipProto == 0)
+ && (checkCIDRinCIDR(this.srcIp(), r.srcIp()))
+ && (checkCIDRinCIDR(this.dstIp(), r.dstIp()));
+ }
+
+ /**
+ * Returns a new ACL rule builder.
+ *
+ * @return ACL rule builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder of an ACL rule.
+ */
+ public static final class Builder {
+
+ private Ip4Prefix srcIp = null;
+ private Ip4Prefix dstIp = null;
+ private byte ipProto = 0;
+ private short dstTpPort = 0;
+ private Action action = Action.DENY;
+
+ private Builder() {
+ // Hide constructor
+ }
+
+ /**
+ * Sets the source IP address for the ACL rule that will be built.
+ *
+ * @param srcIp source IP address to use for built ACL rule
+ * @return this builder
+ */
+ public Builder srcIp(Ip4Prefix srcIp) {
+ this.srcIp = srcIp;
+ return this;
+ }
+
+ /**
+ * Sets the destination IP address for the ACL rule that will be built.
+ *
+ * @param dstIp destination IP address to use for built ACL rule
+ * @return this builder
+ */
+ public Builder dstIp(Ip4Prefix dstIp) {
+ this.dstIp = dstIp;
+ return this;
+ }
+
+ /**
+ * Sets the IP protocol for the ACL rule that will be built.
+ *
+ * @param ipProto IP protocol to use for built ACL rule
+ * @return this builder
+ */
+ public Builder ipProto(byte ipProto) {
+ this.ipProto = ipProto;
+ return this;
+ }
+
+ /**
+ * Sets the destination transport layer port for the ACL rule that will be built.
+ *
+ * @param dstTpPort destination transport layer port to use for built ACL rule
+ * @return this builder
+ */
+ public Builder dstTpPort(short dstTpPort) {
+ if ((ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP)) {
+ this.dstTpPort = dstTpPort;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the action for the ACL rule that will be built.
+ *
+ * @param action action to use for built ACL rule
+ * @return this builder
+ */
+ public Builder action(Action action) {
+ this.action = action;
+ return this;
+ }
+
+ /**
+ * Builds an ACL rule from the accumulated parameters.
+ *
+ * @return ACL rule instance
+ */
+ public AclRule build() {
+ checkState(srcIp != null && dstIp != null, "Either srcIp or dstIp must be assigned.");
+ checkState(ipProto == 0 || ipProto == IPv4.PROTOCOL_ICMP
+ || ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP,
+ "ipProto must be assigned to TCP, UDP, or ICMP.");
+ return new AclRule(srcIp, dstIp, ipProto, dstTpPort, action);
+ }
+
+ }
+
+ /**
+ * Binds an id generator for unique ACL rule id generation.
+ * <p>
+ * Note: A generator cannot be bound if there is already a generator bound.
+ *
+ * @param newIdGenerator id generator
+ */
+ public static void bindIdGenerator(IdGenerator newIdGenerator) {
+ checkState(idGenerator == null, "Id generator is already bound.");
+ idGenerator = checkNotNull(newIdGenerator);
+ }
+
+ public RuleId id() {
+ return id;
+ }
+
+ public Ip4Prefix srcIp() {
+ return srcIp;
+ }
+
+ public Ip4Prefix dstIp() {
+ return this.dstIp;
+ }
+
+ public byte ipProto() {
+ return ipProto;
+ }
+
+ public short dstTpPort() {
+ return dstTpPort;
+ }
+
+ public Action action() {
+ return action;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(action, id.fingerprint(), ipProto, srcIp, dstIp, dstTpPort);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof AclRule) {
+ AclRule that = (AclRule) obj;
+ return Objects.equals(id, that.id) &&
+ Objects.equals(srcIp, that.srcIp) &&
+ Objects.equals(dstIp, that.dstIp) &&
+ Objects.equals(ipProto, that.ipProto) &&
+ Objects.equals(dstTpPort, that.dstTpPort) &&
+ Objects.equals(action, that.action);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .omitNullValues()
+ .add("id", id)
+ .add("srcIp", srcIp)
+ .add("dstIp", dstIp)
+ .add("ipProto", ipProto)
+ .add("dstTpPort", dstTpPort)
+ .add("action", action)
+ .toString();
+ }
+
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclService.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclService.java
new file mode 100644
index 00000000..487a6761
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import java.util.List;
+
+/**
+ * Service interface exported by ACL application.
+ */
+public interface AclService {
+
+ /**
+ * Gets a list containing all ACL rules.
+ *
+ * @return a list containing all ACL rules
+ */
+ List<AclRule> getAclRules();
+
+ /**
+ * Adds a new ACL rule.
+ *
+ * @param rule ACL rule
+ * @return true if successfully added, otherwise false
+ */
+ boolean addAclRule(AclRule rule);
+
+ /**
+ * Removes an exsiting ACL rule by rule id.
+ *
+ * @param ruleId ACL rule identifier
+ */
+ void removeAclRule(RuleId ruleId);
+
+ /**
+ * Clears ACL and resets all.
+ */
+ void clearAcl();
+
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclStore.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclStore.java
new file mode 100644
index 00000000..ff9e25f6
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclStore.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.store.Store;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Service interface exported by ACL distributed store.
+ */
+public interface AclStore extends Store {
+
+ /**
+ * Gets a list containing all ACL rules.
+ *
+ * @return a list containing all ACL rules
+ */
+ List<AclRule> getAclRules();
+
+ /**
+ * Adds a new ACL rule.
+ *
+ * @param rule new ACL rule
+ */
+ void addAclRule(AclRule rule);
+
+ /**
+ * Gets an existing ACL rule.
+ *
+ * @param ruleId ACL rule id
+ * @return ACL rule with the given id
+ */
+ AclRule getAclRule(RuleId ruleId);
+
+ /**
+ * Removes an existing ACL rule by rule id.
+ *
+ * @param ruleId ACL rule id
+ */
+ void removeAclRule(RuleId ruleId);
+
+ /**
+ * Clears ACL and reset all.
+ */
+ void clearAcl();
+
+ /**
+ * Gets the current priority for new ACL flow rule by device id.
+ *
+ * @param deviceId device id
+ * @return new ACL flow rule's priority in the given device
+ */
+ int getPriorityByDevice(DeviceId deviceId);
+
+ /**
+ * Gets a set containing all ACL flow rules belonging to a given ACL rule.
+ *
+ * @param ruleId ACL rule id
+ * @return a set containing all ACL flow rules belonging to the given ACL rule
+ */
+ Set<FlowRule> getFlowByRule(RuleId ruleId);
+
+ /**
+ * Adds a new mapping from ACL rule to ACL flow rule.
+ *
+ * @param ruleId ACL rule id
+ * @param flowRule ACL flow rule
+ */
+ void addRuleToFlowMapping(RuleId ruleId, FlowRule flowRule);
+
+ /**
+ * Removes an existing mapping from ACL rule to ACL flow rule.
+ *
+ * @param ruleId ACL rule id
+ */
+ void removeRuleToFlowMapping(RuleId ruleId);
+
+ /**
+ * Gets a list containing all allowing ACL rules matching a given denying ACL rule.
+ *
+ * @param denyingRuleId denying ACL rule id
+ * @return a list containing all allowing ACL rules matching the given denying ACL rule
+ */
+ List<RuleId> getAllowingRuleByDenyingRule(RuleId denyingRuleId);
+
+ /**
+ * Adds a new mapping from denying ACL rule to allowing ACL rule.
+ *
+ * @param denyingRuleId denying ACL rule id
+ * @param allowingRuleId allowing ACL rule id
+ */
+ void addDenyToAllowMapping(RuleId denyingRuleId, RuleId allowingRuleId);
+
+ /**
+ * Removes an exsiting mapping from denying ACL rule to allowing ACL rule.
+ *
+ * @param denyingRuleId denying ACL rule id
+ */
+ void removeDenyToAllowMapping(RuleId denyingRuleId);
+
+ /**
+ * Checks if an existing ACL rule already works in a given device.
+ *
+ * @param ruleId ACL rule id
+ * @param deviceId devide id
+ * @return true if the given ACL rule works in the given device
+ */
+ boolean checkIfRuleWorksInDevice(RuleId ruleId, DeviceId deviceId);
+
+ /**
+ * Adds a new mapping from ACL rule to device.
+ *
+ * @param ruleId ACL rule id
+ * @param deviceId device id
+ */
+ void addRuleToDeviceMapping(RuleId ruleId, DeviceId deviceId);
+
+ /**
+ * Removes an existing mapping from ACL rule to device.
+ *
+ * @param ruleId ACL rule id
+ */
+ void removeRuleToDeviceMapping(RuleId ruleId);
+
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclWebResource.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclWebResource.java
new file mode 100644
index 00000000..e792efba
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/AclWebResource.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Prefix;
+import org.onosproject.rest.AbstractWebResource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+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;
+import java.util.List;
+
+/**
+ * Manage ACL rules.
+ */
+@Path("rules")
+public class AclWebResource extends AbstractWebResource {
+
+ /**
+ * Get all ACL rules.
+ * Returns array of all ACL rules.
+ *
+ * @return 200 OK
+ */
+ @GET
+ public Response queryAclRule() {
+ List<AclRule> rules = get(AclService.class).getAclRules();
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode root = mapper.createObjectNode();
+ ArrayNode arrayNode = mapper.createArrayNode();
+ for (AclRule rule : rules) {
+ ObjectNode node = mapper.createObjectNode();
+ node.put("id", rule.id().toString());
+ if (rule.srcIp() != null) {
+ node.put("srcIp", rule.srcIp().toString());
+ }
+ if (rule.dstIp() != null) {
+ node.put("dstIp", rule.dstIp().toString());
+ }
+ if (rule.ipProto() != 0) {
+ switch (rule.ipProto()) {
+ case IPv4.PROTOCOL_ICMP:
+ node.put("ipProto", "ICMP");
+ break;
+ case IPv4.PROTOCOL_TCP:
+ node.put("ipProto", "TCP");
+ break;
+ case IPv4.PROTOCOL_UDP:
+ node.put("ipProto", "UDP");
+ break;
+ default:
+ break;
+ }
+ }
+ if (rule.dstTpPort() != 0) {
+ node.put("dstTpPort", rule.dstTpPort());
+ }
+ node.put("action", rule.action().toString());
+ arrayNode.add(node);
+ }
+ root.set("aclRules", arrayNode);
+ return Response.ok(root.toString(), MediaType.APPLICATION_JSON_TYPE).build();
+ }
+
+ /**
+ * Add a new ACL rule.
+ *
+ * @param stream JSON data describing the rule
+ * @return 200 OK
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response addAclRule(InputStream stream) throws URISyntaxException {
+ AclRule newRule = jsonToRule(stream);
+ return get(AclService.class).addAclRule(newRule) ?
+ Response.created(new URI(newRule.id().toString())).build() :
+ Response.serverError().build();
+ }
+
+ /**
+ * Remove ACL rule.
+ *
+ * @param id ACL rule id (in hex string format)
+ * @return 200 OK
+ */
+ @DELETE
+ @Path("{id}")
+ public Response removeAclRule(@PathParam("id") String id) {
+ RuleId ruleId = new RuleId(Long.parseLong(id.substring(2), 16));
+ get(AclService.class).removeAclRule(ruleId);
+ return Response.ok().build();
+ }
+
+ /**
+ * Remove all ACL rules.
+ *
+ * @return 200 OK
+ */
+ @DELETE
+ public Response clearACL() {
+ get(AclService.class).clearAcl();
+ return Response.ok().build();
+ }
+
+ /**
+ * Turns a JSON string into an ACL rule instance.
+ */
+ private AclRule jsonToRule(InputStream stream) {
+ JsonNode node;
+ try {
+ node = mapper().readTree(stream);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Unable to parse ACL request", e);
+ }
+
+ AclRule.Builder rule = AclRule.builder();
+
+ String s = node.path("srcIp").asText(null);
+ if (s != null) {
+ rule.srcIp(Ip4Prefix.valueOf(s));
+ }
+
+ s = node.path("dstIp").asText(null);
+ if (s != null) {
+ rule.dstIp(Ip4Prefix.valueOf(s));
+ }
+
+ s = node.path("ipProto").asText(null);
+ if (s != null) {
+ if ("TCP".equalsIgnoreCase(s)) {
+ rule.ipProto(IPv4.PROTOCOL_TCP);
+ } else if ("UDP".equalsIgnoreCase(s)) {
+ rule.ipProto(IPv4.PROTOCOL_UDP);
+ } else if ("ICMP".equalsIgnoreCase(s)) {
+ rule.ipProto(IPv4.PROTOCOL_ICMP);
+ } else {
+ throw new IllegalArgumentException("ipProto must be assigned to TCP, UDP, or ICMP");
+ }
+ }
+
+ int port = node.path("dstTpPort").asInt(0);
+ if (port > 0) {
+ rule.dstTpPort((short) port);
+ }
+
+ s = node.path("action").asText(null);
+ if (s != null) {
+ if ("allow".equalsIgnoreCase(s)) {
+ rule.action(AclRule.Action.ALLOW);
+ } else if ("deny".equalsIgnoreCase(s)) {
+ rule.action(AclRule.Action.DENY);
+ } else {
+ throw new IllegalArgumentException("action must be ALLOW or DENY");
+ }
+ }
+
+ return rule.build();
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/RuleId.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/RuleId.java
new file mode 100644
index 00000000..468dab5c
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/RuleId.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li and Heng Qi
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+/**
+ * ACL rule identifier suitable as an external key.
+ * <p>This class is immutable.</p>
+ */
+public final class RuleId {
+ private final long value;
+
+ /**
+ * Creates an ACL rule identifier from the specified long value.
+ *
+ * @param value long value
+ * @return ACL rule identifier
+ */
+ public static RuleId valueOf(long value) {
+ return new RuleId(value);
+ }
+
+ /**
+ * Constructor for serializer.
+ */
+ RuleId() {
+ this.value = 0;
+ }
+
+ /**
+ * Constructs the ID corresponding to a given long value.
+ *
+ * @param value the underlying value of this ID
+ */
+ RuleId(long value) {
+ this.value = value;
+ }
+
+ /**
+ * Returns the backing value.
+ *
+ * @return the value
+ */
+ public long fingerprint() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RuleId)) {
+ return false;
+ }
+ RuleId that = (RuleId) obj;
+ return this.value == that.value;
+ }
+
+ @Override
+ public String toString() {
+ return "0x" + Long.toHexString(value);
+ }
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/AclManager.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/AclManager.java
new file mode 100644
index 00000000..f5c0c204
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/AclManager.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl.impl;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.acl.AclRule;
+import org.onosproject.acl.AclService;
+import org.onosproject.acl.AclStore;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.acl.RuleId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.slf4j.Logger;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the ACL service.
+ */
+@Component(immediate = true)
+@Service
+public class AclManager implements AclService {
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowRuleService flowRuleService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected AclStore aclStore;
+
+ private final Logger log = getLogger(getClass());
+ private ApplicationId appId;
+ private final HostListener hostListener = new InternalHostListener();
+ private IdGenerator idGenerator;
+
+ /**
+ * Checks if the given IP address is in the given CIDR address.
+ */
+ private boolean checkIpInCIDR(Ip4Address ip, Ip4Prefix cidr) {
+ int offset = 32 - cidr.prefixLength();
+ int cidrPrefix = cidr.address().toInt();
+ int ipIntValue = ip.toInt();
+ cidrPrefix = cidrPrefix >> offset;
+ ipIntValue = ipIntValue >> offset;
+ cidrPrefix = cidrPrefix << offset;
+ ipIntValue = ipIntValue << offset;
+
+ return (cidrPrefix == ipIntValue);
+ }
+
+ private class InternalHostListener implements HostListener {
+
+ /**
+ * Generate new ACL flow rules for new host following the given ACL rule.
+ */
+ private void processHostAddedEvent(HostEvent event, AclRule rule) {
+ DeviceId deviceId = event.subject().location().deviceId();
+ for (IpAddress address : event.subject().ipAddresses()) {
+ if ((rule.srcIp() != null) ?
+ (checkIpInCIDR(address.getIp4Address(), rule.srcIp())) :
+ (checkIpInCIDR(address.getIp4Address(), rule.dstIp()))) {
+ if (!aclStore.checkIfRuleWorksInDevice(rule.id(), deviceId)) {
+ List<RuleId> allowingRuleList = aclStore
+ .getAllowingRuleByDenyingRule(rule.id());
+ if (allowingRuleList != null) {
+ for (RuleId allowingRuleId : allowingRuleList) {
+ generateACLFlow(aclStore.getAclRule(allowingRuleId), deviceId);
+ }
+ }
+ generateACLFlow(rule, deviceId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void event(HostEvent event) {
+ // if a new host appears and an existing rule denies
+ // its traffic, a new ACL flow rule is generated.
+ if (event.type() == HostEvent.Type.HOST_ADDED) {
+ DeviceId deviceId = event.subject().location().deviceId();
+ if (mastershipService.getLocalRole(deviceId) == MastershipRole.MASTER) {
+ for (AclRule rule : aclStore.getAclRules()) {
+ if (rule.action() != AclRule.Action.ALLOW) {
+ processHostAddedEvent(event, rule);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication("org.onos.acl");
+ hostService.addListener(hostListener);
+ idGenerator = coreService.getIdGenerator("acl-ids");
+ AclRule.bindIdGenerator(idGenerator);
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ hostService.removeListener(hostListener);
+ flowRuleService.removeFlowRulesById(appId);
+ aclStore.clearAcl();
+ log.info("Stopped");
+ }
+
+ @Override
+ public List<AclRule> getAclRules() {
+ return aclStore.getAclRules();
+ }
+
+ /**
+ * Checks if the new ACL rule matches an existing rule.
+ * If existing allowing rules matches the new denying rule, store the mappings.
+ *
+ * @return true if the new ACL rule matches an existing rule, false otherwise
+ */
+ private boolean matchCheck(AclRule newRule) {
+ for (AclRule existingRule : aclStore.getAclRules()) {
+ if (newRule.checkMatch(existingRule)) {
+ return true;
+ }
+
+ if (existingRule.action() == AclRule.Action.ALLOW
+ && newRule.action() == AclRule.Action.DENY) {
+ if (existingRule.checkMatch(newRule)) {
+ aclStore.addDenyToAllowMapping(newRule.id(), existingRule.id());
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean addAclRule(AclRule rule) {
+ if (matchCheck(rule)) {
+ return false;
+ }
+ aclStore.addAclRule(rule);
+ log.info("ACL rule(id:{}) is added.", rule.id());
+ if (rule.action() != AclRule.Action.ALLOW) {
+ enforceRuleAdding(rule);
+ }
+ return true;
+ }
+
+ /**
+ * Gets a set containing all devices connecting with the hosts
+ * whose IP address is in the given CIDR IP address.
+ */
+ private Set<DeviceId> getDeviceIdSet(Ip4Prefix cidrAddr) {
+ Set<DeviceId> deviceIdSet = new HashSet<>();
+ final Iterable<Host> hosts = hostService.getHosts();
+
+ if (cidrAddr.prefixLength() != 32) {
+ for (Host h : hosts) {
+ for (IpAddress a : h.ipAddresses()) {
+ if (checkIpInCIDR(a.getIp4Address(), cidrAddr)) {
+ deviceIdSet.add(h.location().deviceId());
+ }
+ }
+ }
+ } else {
+ for (Host h : hosts) {
+ for (IpAddress a : h.ipAddresses()) {
+ if (checkIpInCIDR(a.getIp4Address(), cidrAddr)) {
+ deviceIdSet.add(h.location().deviceId());
+ return deviceIdSet;
+ }
+ }
+ }
+ }
+ return deviceIdSet;
+ }
+
+ /**
+ * Enforces denying ACL rule by ACL flow rules.
+ */
+ private void enforceRuleAdding(AclRule rule) {
+ Set<DeviceId> dpidSet;
+ if (rule.srcIp() != null) {
+ dpidSet = getDeviceIdSet(rule.srcIp());
+ } else {
+ dpidSet = getDeviceIdSet(rule.dstIp());
+ }
+
+ for (DeviceId deviceId : dpidSet) {
+ List<RuleId> allowingRuleList = aclStore.getAllowingRuleByDenyingRule(rule.id());
+ if (allowingRuleList != null) {
+ for (RuleId allowingRuleId : allowingRuleList) {
+ generateACLFlow(aclStore.getAclRule(allowingRuleId), deviceId);
+ }
+ }
+ generateACLFlow(rule, deviceId);
+ }
+ }
+
+ /**
+ * Generates ACL flow rule according to ACL rule
+ * and install it into related device.
+ */
+ private void generateACLFlow(AclRule rule, DeviceId deviceId) {
+ if (rule == null || aclStore.checkIfRuleWorksInDevice(rule.id(), deviceId)) {
+ return;
+ }
+
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ FlowEntry.Builder flowEntry = DefaultFlowEntry.builder();
+
+ selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
+ if (rule.srcIp() != null) {
+ selectorBuilder.matchIPSrc(rule.srcIp());
+ if (rule.dstIp() != null) {
+ selectorBuilder.matchIPDst(rule.dstIp());
+ }
+ } else {
+ selectorBuilder.matchIPDst(rule.dstIp());
+ }
+ if (rule.ipProto() != 0) {
+ selectorBuilder.matchIPProtocol(Integer.valueOf(rule.ipProto()).byteValue());
+ }
+ if (rule.dstTpPort() != 0) {
+ switch (rule.ipProto()) {
+ case IPv4.PROTOCOL_TCP:
+ selectorBuilder.matchTcpDst(TpPort.tpPort(rule.dstTpPort()));
+ break;
+ case IPv4.PROTOCOL_UDP:
+ selectorBuilder.matchUdpDst(TpPort.tpPort(rule.dstTpPort()));
+ break;
+ default:
+ break;
+ }
+ }
+ if (rule.action() == AclRule.Action.ALLOW) {
+ treatment.add(Instructions.createOutput(PortNumber.CONTROLLER));
+ }
+ flowEntry.forDevice(deviceId);
+ flowEntry.withPriority(aclStore.getPriorityByDevice(deviceId));
+ flowEntry.withSelector(selectorBuilder.build());
+ flowEntry.withTreatment(treatment.build());
+ flowEntry.fromApp(appId);
+ flowEntry.makePermanent();
+ // install flow rule
+ flowRuleService.applyFlowRules(flowEntry.build());
+ log.debug("ACL flow rule {} is installed in {}.", flowEntry.build(), deviceId);
+ aclStore.addRuleToFlowMapping(rule.id(), flowEntry.build());
+ aclStore.addRuleToDeviceMapping(rule.id(), deviceId);
+ }
+
+ @Override
+ public void removeAclRule(RuleId ruleId) {
+ aclStore.removeAclRule(ruleId);
+ log.info("ACL rule(id:{}) is removed.", ruleId);
+ enforceRuleRemoving(ruleId);
+ }
+
+ /**
+ * Enforces removing an existing ACL rule.
+ */
+ private void enforceRuleRemoving(RuleId ruleId) {
+ Set<FlowRule> flowSet = aclStore.getFlowByRule(ruleId);
+ if (flowSet != null) {
+ for (FlowRule flowRule : flowSet) {
+ flowRuleService.removeFlowRules(flowRule);
+ log.debug("ACL flow rule {} is removed from {}.", flowRule.toString(), flowRule.deviceId().toString());
+ }
+ }
+ aclStore.removeRuleToFlowMapping(ruleId);
+ aclStore.removeRuleToDeviceMapping(ruleId);
+ aclStore.removeDenyToAllowMapping(ruleId);
+ }
+
+ @Override
+ public void clearAcl() {
+ aclStore.clearAcl();
+ flowRuleService.removeFlowRulesById(appId);
+ log.info("ACL is cleared.");
+ }
+
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/DistributedAclStore.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/DistributedAclStore.java
new file mode 100644
index 00000000..a5fcfcc7
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/DistributedAclStore.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl.impl;
+
+import com.google.common.collect.Collections2;
+import org.onosproject.acl.AclRule;
+import org.onosproject.acl.AclStore;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.acl.RuleId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the ACL store service.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedAclStore extends AbstractStore implements AclStore {
+
+ private final Logger log = getLogger(getClass());
+ private final int defaultFlowMaxPriority = 30000;
+
+ private ConsistentMap<RuleId, AclRule> ruleSet;
+ private ConsistentMap<DeviceId, Integer> deviceToPriority;
+ private ConsistentMap<RuleId, Set<DeviceId>> ruleToDevice;
+ private ConsistentMap<RuleId, Set<FlowRule>> ruleToFlow;
+ private ConsistentMap<RuleId, List<RuleId>> denyRuleToAllowRule;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Activate
+ public void activate() {
+ ApplicationId appId = coreService.getAppId("org.onosproject.acl");
+
+ KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(AclRule.class)
+ .register(AclRule.Action.class)
+ .register(RuleId.class);
+
+ ruleSet = storageService.<RuleId, AclRule>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("acl-rule-set")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ deviceToPriority = storageService.<DeviceId, Integer>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("device-to-priority")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ ruleToFlow = storageService.<RuleId, Set<FlowRule>>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("rule-to-flow")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ denyRuleToAllowRule = storageService.<RuleId, List<RuleId>>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("deny-to-allow")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ ruleToDevice = storageService.<RuleId, Set<DeviceId>>consistentMapBuilder()
+ .withSerializer(Serializer.using(serializer.build()))
+ .withName("rule-to-device")
+ .withApplicationId(appId)
+ .withPurgeOnUninstall()
+ .build();
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactive() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public List<AclRule> getAclRules() {
+ List<AclRule> aclRules = new ArrayList<>();
+ aclRules.addAll(Collections2.transform(ruleSet.values(), Versioned::value));
+ return aclRules;
+ }
+
+ @Override
+ public void addAclRule(AclRule rule) {
+ ruleSet.putIfAbsent(rule.id(), rule);
+ }
+
+ @Override
+ public AclRule getAclRule(RuleId ruleId) {
+ Versioned<AclRule> rule = ruleSet.get(ruleId);
+ if (rule != null) {
+ return rule.value();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void removeAclRule(RuleId ruleId) {
+ ruleSet.remove(ruleId);
+ }
+
+ @Override
+ public void clearAcl() {
+ ruleSet.clear();
+ deviceToPriority.clear();
+ ruleToFlow.clear();
+ denyRuleToAllowRule.clear();
+ ruleToDevice.clear();
+ }
+
+ @Override
+ public int getPriorityByDevice(DeviceId deviceId) {
+ return deviceToPriority.compute(deviceId,
+ (id, priority) -> (priority == null) ? defaultFlowMaxPriority : (priority - 1))
+ .value();
+ }
+
+ @Override
+ public Set<FlowRule> getFlowByRule(RuleId ruleId) {
+ Versioned<Set<FlowRule>> flowRuleSet = ruleToFlow.get(ruleId);
+ if (flowRuleSet != null) {
+ return flowRuleSet.value();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void addRuleToFlowMapping(RuleId ruleId, FlowRule flowRule) {
+ ruleToFlow.computeIf(ruleId,
+ flowRuleSet -> (flowRuleSet == null || !flowRuleSet.contains(flowRule)),
+ (id, flowRuleSet) -> {
+ Set<FlowRule> newSet = new HashSet<>();
+ if (flowRuleSet != null) {
+ newSet.addAll(flowRuleSet);
+ }
+ newSet.add(flowRule);
+ return newSet;
+ });
+ }
+
+ @Override
+ public void removeRuleToFlowMapping(RuleId ruleId) {
+ ruleToFlow.remove(ruleId);
+ }
+
+ @Override
+ public List<RuleId> getAllowingRuleByDenyingRule(RuleId denyingRuleId) {
+ Versioned<List<RuleId>> allowRuleIdSet = denyRuleToAllowRule.get(denyingRuleId);
+ if (allowRuleIdSet != null) {
+ return allowRuleIdSet.value();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void addDenyToAllowMapping(RuleId denyingRuleId, RuleId allowingRuleId) {
+ denyRuleToAllowRule.computeIf(denyingRuleId,
+ ruleIdList -> (ruleIdList == null || !ruleIdList.contains(allowingRuleId)),
+ (id, ruleIdList) -> {
+ ArrayList<RuleId> newList = new ArrayList<>();
+ if (ruleIdList != null) {
+ newList.addAll(ruleIdList);
+ }
+ newList.add(allowingRuleId);
+ return newList;
+ });
+ }
+
+ @Override
+ public void removeDenyToAllowMapping(RuleId denyingRuleId) {
+ denyRuleToAllowRule.remove(denyingRuleId);
+ }
+
+ @Override
+ public boolean checkIfRuleWorksInDevice(RuleId ruleId, DeviceId deviceId) {
+ return ruleToDevice.containsKey(ruleId) && ruleToDevice.get(ruleId).value().contains(deviceId);
+ }
+
+ @Override
+ public void addRuleToDeviceMapping(RuleId ruleId, DeviceId deviceId) {
+ ruleToDevice.computeIf(ruleId,
+ deviceIdSet -> (deviceIdSet == null || !deviceIdSet.contains(deviceId)),
+ (id, deviceIdSet) -> {
+ Set<DeviceId> newSet = new HashSet<>();
+ if (deviceIdSet != null) {
+ newSet.addAll(deviceIdSet);
+ }
+ newSet.add(deviceId);
+ return newSet;
+ });
+ }
+
+ @Override
+ public void removeRuleToDeviceMapping(RuleId ruleId) {
+ ruleToDevice.remove(ruleId);
+ }
+
+}
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/package-info.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/package-info.java
new file mode 100644
index 00000000..9da9b3b7
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 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.
+ */
+
+/**
+ * ACL application implementation.
+ */
+package org.onosproject.acl.impl;
diff --git a/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/package-info.java b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/package-info.java
new file mode 100644
index 00000000..67f755c6
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/main/java/org/onosproject/acl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 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.
+ */
+
+/**
+ * ACL application.
+ */
+package org.onosproject.acl;
diff --git a/framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml
index 2c2d5cf3..fc188b7f 100644
--- a/framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml
+++ b/framework/src/onos/apps/acl/src/main/webapp/WEB-INF/web.xml
@@ -33,7 +33,7 @@
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.classnames</param-name>
- <param-value>org.onos.acl.AclWebResource</param-value>
+ <param-value>org.onosproject.acl.AclWebResource</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
diff --git a/framework/src/onos/apps/acl/src/test/java/org/onosproject/acl/AclWebResourceTest.java b/framework/src/onos/apps/acl/src/test/java/org/onosproject/acl/AclWebResourceTest.java
new file mode 100644
index 00000000..c554db6e
--- /dev/null
+++ b/framework/src/onos/apps/acl/src/test/java/org/onosproject/acl/AclWebResourceTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
+ * Advisers: Keqiu Li and Heng Qi
+ * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
+ * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
+ *
+ * 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.acl;
+
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.test.framework.AppDescriptor;
+import com.sun.jersey.test.framework.WebAppDescriptor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.rest.BaseResource;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.rest.ResourceTest;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test class for ACL application REST resource.
+ */
+public class AclWebResourceTest extends ResourceTest {
+
+ final AclService mockAclService = createMock(AclService.class);
+ final AclStore mockAclStore = createMock(AclStore.class);
+ final List<AclRule> rules = new ArrayList<>();
+
+ @Before
+ public void setUp() {
+ expect(mockAclService.getAclRules()).andReturn(rules).anyTimes();
+ ServiceDirectory testDirectory = new TestServiceDirectory().add(AclService.class, mockAclService)
+ .add(AclStore.class, mockAclStore);
+ BaseResource.setServiceDirectory(testDirectory);
+
+ IdGenerator idGenerator = new MockIdGenerator();
+ AclRule.bindIdGenerator(idGenerator);
+ }
+
+ @After
+ public void tearDown() {
+ verify(mockAclService);
+ }
+
+ /**
+ * Mock id generator for testing.
+ */
+ private class MockIdGenerator implements IdGenerator {
+ private AtomicLong nextId = new AtomicLong(0);
+
+ @Override
+ public long getNewId() {
+ return nextId.getAndIncrement();
+ }
+ }
+
+ @Override
+ public AppDescriptor configure() {
+ return new WebAppDescriptor.Builder("org.onosproject.acl").build();
+ }
+
+ @Test
+ @Ignore("FIXME: This needs to get reworked")
+ public void addRule() throws IOException {
+ WebResource.Builder rs = resource().path("rules").header("Content-type", "application/json");
+ String response;
+ String json;
+
+ replay(mockAclService);
+
+ // input a invalid JSON string that contains neither nw_src and nw_dst
+ json = "{\"ipProto\":\"TCP\",\"dstTpPort\":\"80\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Failed! Either srcIp or dstIp must be assigned."));
+
+ // input a invalid JSON string that doesn't contain CIDR mask bits
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Malformed IPv4 prefix string: 10.0.0.1. " +
+ "Address must take form \"x.x.x.x/y\""));
+
+ // input a invalid JSON string that contains a invalid IP address
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.256/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Invalid IP address string: 10.0.0.256"));
+
+ // input a invalid JSON string that contains a invalid IP address
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.01/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Invalid IP address string: 10.0.01"));
+
+ // input a invalid JSON string that contains a invalid CIDR mask bits
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/a\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Failed! For input string: \"a\""));
+
+ // input a invalid JSON string that contains a invalid CIDR mask bits
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/33\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("Invalid prefix length 33. The value must be in the interval [0, 32]"));
+
+ // input a invalid JSON string that contains a invalid ipProto value
+ json = "{\"ipProto\":\"ARP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("ipProto must be assigned to TCP, UDP, or ICMP."));
+
+ // input a invalid JSON string that contains a invalid dstTpPort value
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"a\",\"action\":\"DENY\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("dstTpPort must be assigned to a numerical value."));
+
+ // input a invalid JSON string that contains a invalid action value
+ json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"80\",\"action\":\"PERMIT\"}";
+ response = rs.post(String.class, json);
+ assertThat(response, containsString("action must be assigned to ALLOW or DENY."));
+ }
+}