Committed by
Gerrit Code Review
Add an ACL application
- change both of the constructors in AclRule.class to be private - change AclRule.class to be final - remove useless reference |URL|Notes| |-|-| |GET onos/v1/acl | Lists all existing ACL rules.| |GET onos/v1/acl/remove/{id} | Removes an existing ACL rule by id| |GET onos/v1/acl/clear | Clears ACL and reset all| |POST onos/v1/acl/add | Adds a new ACL rule| |Key|Value|Notes| |-|-|-| |ipProto | string | "TCP" or "UDP" or "ICMP" (ignoring case)| |srcIp | IPv4 address[/mask] | Either src-ip or dst-ip must be specified.| |dstIp | IPv4 address[/mask] | Either src-ip or dst-ip must be specified.| |dstTpPort | number | Valid when nw-proto == "TCP" or "UDP".| |action | string | "DENY" or "ALLOW" (ignoring case), set to "DENY" if not specified.| Change-Id: I55170d5f50814eabef43b1bf2ee33af41b5987e4
Showing
13 changed files
with
1512 additions
and
0 deletions
apps/acl/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2015 Open Networking Laboratory | ||
4 | + ~ Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
5 | + ~ Advisers: Keqiu Li and Heng Qi | ||
6 | + ~ This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
7 | + ~ and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
8 | + ~ | ||
9 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | + ~ you may not use this file except in compliance with the License. | ||
11 | + ~ You may obtain a copy of the License at | ||
12 | + ~ | ||
13 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | + ~ | ||
15 | + ~ Unless required by applicable law or agreed to in writing, software | ||
16 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | + ~ See the License for the specific language governing permissions and | ||
19 | + ~ limitations under the License. | ||
20 | + --> | ||
21 | +<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"> | ||
22 | + <modelVersion>4.0.0</modelVersion> | ||
23 | + | ||
24 | + <parent> | ||
25 | + <groupId>org.onosproject</groupId> | ||
26 | + <artifactId>onos-apps</artifactId> | ||
27 | + <version>1.3.0-SNAPSHOT</version> | ||
28 | + <relativePath>../pom.xml</relativePath> | ||
29 | + </parent> | ||
30 | + | ||
31 | + <artifactId>onos-app-acl</artifactId> | ||
32 | + <version>1.3.0-SNAPSHOT</version> | ||
33 | + <packaging>bundle</packaging> | ||
34 | + | ||
35 | + <description>ONOS ACL application</description> | ||
36 | + <url>http://onosproject.org</url> | ||
37 | + | ||
38 | + <properties> | ||
39 | + <onos.version>1.3.0-SNAPSHOT</onos.version> | ||
40 | + <onos.app.name>org.onosproject.acl</onos.app.name> | ||
41 | + <onos.app.origin>Pengfei Lu</onos.app.origin> | ||
42 | + <web.context>/onos/v1/acl</web.context> | ||
43 | + </properties> | ||
44 | + | ||
45 | + <dependencies> | ||
46 | + <dependency> | ||
47 | + <groupId>com.google.guava</groupId> | ||
48 | + <artifactId>guava</artifactId> | ||
49 | + <version>18.0</version> | ||
50 | + </dependency> | ||
51 | + | ||
52 | + <dependency> | ||
53 | + <groupId>javax.ws.rs</groupId> | ||
54 | + <artifactId>jsr311-api</artifactId> | ||
55 | + <version>1.1.1</version> | ||
56 | + </dependency> | ||
57 | + | ||
58 | + <dependency> | ||
59 | + <groupId>org.onosproject</groupId> | ||
60 | + <artifactId>onlab-junit</artifactId> | ||
61 | + <version>${onos.version}</version> | ||
62 | + </dependency> | ||
63 | + | ||
64 | + <dependency> | ||
65 | + <groupId>org.onosproject</groupId> | ||
66 | + <artifactId>onos-rest</artifactId> | ||
67 | + <version>${onos.version}</version> | ||
68 | + </dependency> | ||
69 | + | ||
70 | + <dependency> | ||
71 | + <groupId>org.onosproject</groupId> | ||
72 | + <artifactId>onos-core-serializers</artifactId> | ||
73 | + <version>${onos.version}</version> | ||
74 | + </dependency> | ||
75 | + | ||
76 | + <dependency> | ||
77 | + <groupId>com.sun.jersey.jersey-test-framework</groupId> | ||
78 | + <artifactId>jersey-test-framework-core</artifactId> | ||
79 | + <version>1.19</version> | ||
80 | + </dependency> | ||
81 | + | ||
82 | + <dependency> | ||
83 | + <groupId>org.easymock</groupId> | ||
84 | + <artifactId>easymock</artifactId> | ||
85 | + <version>3.2</version> | ||
86 | + </dependency> | ||
87 | + | ||
88 | + <dependency> | ||
89 | + <groupId>com.sun.jersey.jersey-test-framework</groupId> | ||
90 | + <artifactId>jersey-test-framework-grizzly2</artifactId> | ||
91 | + <version>1.19</version> | ||
92 | + </dependency> | ||
93 | + | ||
94 | + <dependency> | ||
95 | + <groupId>org.onosproject</groupId> | ||
96 | + <artifactId>onlab-misc</artifactId> | ||
97 | + <version>${onos.version}</version> | ||
98 | + </dependency> | ||
99 | + | ||
100 | + </dependencies> | ||
101 | + | ||
102 | + <build> | ||
103 | + <plugins> | ||
104 | + <plugin> | ||
105 | + <groupId>org.apache.felix</groupId> | ||
106 | + <artifactId>maven-bundle-plugin</artifactId> | ||
107 | + <version>2.5.3</version> | ||
108 | + <extensions>true</extensions> | ||
109 | + <configuration> | ||
110 | + <instructions> | ||
111 | + <_wab>src/main/webapp/</_wab> | ||
112 | + <Bundle-SymbolicName> | ||
113 | + ${project.groupId}.${project.artifactId} | ||
114 | + </Bundle-SymbolicName> | ||
115 | + <Import-Package> | ||
116 | + org.slf4j, | ||
117 | + org.osgi.framework, | ||
118 | + javax.ws.rs,javax.ws.rs.core, | ||
119 | + com.fasterxml.jackson*, | ||
120 | + com.sun.jersey.api.core, | ||
121 | + com.sun.jersey.spi.container.servlet, | ||
122 | + com.sun.jersey.server.impl.container.servlet, | ||
123 | + org.onlab.packet.*, | ||
124 | + org.onlab.rest.*, | ||
125 | + org.onosproject.*, | ||
126 | + org.onlab.util.*, | ||
127 | + com.google.common.*; | ||
128 | + </Import-Package> | ||
129 | + <Web-ContextPath>${web.context}</Web-ContextPath> | ||
130 | + </instructions> | ||
131 | + </configuration> | ||
132 | + </plugin> | ||
133 | + <plugin> | ||
134 | + <groupId>org.apache.maven.plugins</groupId> | ||
135 | + <artifactId>maven-compiler-plugin</artifactId> | ||
136 | + <version>2.5.1</version> | ||
137 | + <configuration> | ||
138 | + <source>1.8</source> | ||
139 | + <target>1.8</target> | ||
140 | + </configuration> | ||
141 | + </plugin> | ||
142 | + <plugin> | ||
143 | + <groupId>org.apache.felix</groupId> | ||
144 | + <artifactId>maven-scr-plugin</artifactId> | ||
145 | + <version>1.20.0</version> | ||
146 | + <executions> | ||
147 | + <execution> | ||
148 | + <id>generate-scr-srcdescriptor</id> | ||
149 | + <goals> | ||
150 | + <goal>scr</goal> | ||
151 | + </goals> | ||
152 | + </execution> | ||
153 | + </executions> | ||
154 | + <configuration> | ||
155 | + <supportedProjectTypes> | ||
156 | + <supportedProjectType>bundle</supportedProjectType> | ||
157 | + <supportedProjectType>war</supportedProjectType> | ||
158 | + </supportedProjectTypes> | ||
159 | + </configuration> | ||
160 | + </plugin> | ||
161 | + <plugin> | ||
162 | + <groupId>org.onosproject</groupId> | ||
163 | + <artifactId>onos-maven-plugin</artifactId> | ||
164 | + <version>1.4-SNAPSHOT</version> | ||
165 | + <executions> | ||
166 | + <execution> | ||
167 | + <id>cfg</id> | ||
168 | + <phase>generate-resources</phase> | ||
169 | + <goals> | ||
170 | + <goal>cfg</goal> | ||
171 | + </goals> | ||
172 | + </execution> | ||
173 | + <execution> | ||
174 | + <id>app</id> | ||
175 | + <phase>package</phase> | ||
176 | + <goals> | ||
177 | + <goal>app</goal> | ||
178 | + </goals> | ||
179 | + </execution> | ||
180 | + </executions> | ||
181 | + </plugin> | ||
182 | + </plugins> | ||
183 | + </build> | ||
184 | + | ||
185 | +</project> |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | +package org.onos.acl; | ||
21 | + | ||
22 | +import com.google.common.base.MoreObjects; | ||
23 | +import org.onlab.packet.IPv4; | ||
24 | +import org.onlab.packet.Ip4Prefix; | ||
25 | +import org.onosproject.core.IdGenerator; | ||
26 | + | ||
27 | +import java.util.Objects; | ||
28 | + | ||
29 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
30 | +import static com.google.common.base.Preconditions.checkState; | ||
31 | + | ||
32 | +/** | ||
33 | + * ACL rule class. | ||
34 | + */ | ||
35 | +public final class AclRule { | ||
36 | + | ||
37 | + private final RuleId id; | ||
38 | + | ||
39 | + private final Ip4Prefix srcIp; | ||
40 | + private final Ip4Prefix dstIp; | ||
41 | + private final byte ipProto; | ||
42 | + private final short dstTpPort; | ||
43 | + private final Action action; | ||
44 | + | ||
45 | + private static IdGenerator idGenerator; | ||
46 | + | ||
47 | + /** | ||
48 | + * Enum type for ACL rule's action. | ||
49 | + */ | ||
50 | + public enum Action { | ||
51 | + DENY, ALLOW | ||
52 | + } | ||
53 | + | ||
54 | + /** | ||
55 | + * Constructor for serializer. | ||
56 | + */ | ||
57 | + private AclRule() { | ||
58 | + this.id = null; | ||
59 | + this.srcIp = null; | ||
60 | + this.dstIp = null; | ||
61 | + this.ipProto = 0; | ||
62 | + this.dstTpPort = 0; | ||
63 | + this.action = null; | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * Create a new ACL rule. | ||
68 | + * | ||
69 | + * @param srcIp source IP address | ||
70 | + * @param dstIp destination IP address | ||
71 | + * @param ipProto IP protocol | ||
72 | + * @param dstTpPort destination transport layer port | ||
73 | + * @param action ACL rule's action | ||
74 | + */ | ||
75 | + private AclRule(Ip4Prefix srcIp, | ||
76 | + Ip4Prefix dstIp, | ||
77 | + byte ipProto, | ||
78 | + short dstTpPort, | ||
79 | + Action action) { | ||
80 | + checkState(idGenerator != null, "Id generator is not bound."); | ||
81 | + this.id = RuleId.valueOf(idGenerator.getNewId()); | ||
82 | + this.srcIp = srcIp; | ||
83 | + this.dstIp = dstIp; | ||
84 | + this.ipProto = ipProto; | ||
85 | + this.dstTpPort = dstTpPort; | ||
86 | + this.action = action; | ||
87 | + } | ||
88 | + | ||
89 | + /** | ||
90 | + * Check if the first CIDR address is in (or the same as) the second CIDR address. | ||
91 | + */ | ||
92 | + private boolean checkCIDRinCIDR(Ip4Prefix cidrAddr1, Ip4Prefix cidrAddr2) { | ||
93 | + if (cidrAddr2 == null) { | ||
94 | + return true; | ||
95 | + } else if (cidrAddr1 == null) { | ||
96 | + return false; | ||
97 | + } | ||
98 | + if (cidrAddr1.prefixLength() < cidrAddr2.prefixLength()) { | ||
99 | + return false; | ||
100 | + } | ||
101 | + int offset = 32 - cidrAddr2.prefixLength(); | ||
102 | + | ||
103 | + int cidr1Prefix = cidrAddr1.address().toInt(); | ||
104 | + int cidr2Prefix = cidrAddr2.address().toInt(); | ||
105 | + cidr1Prefix = cidr1Prefix >> offset; | ||
106 | + cidr2Prefix = cidr2Prefix >> offset; | ||
107 | + cidr1Prefix = cidr1Prefix << offset; | ||
108 | + cidr2Prefix = cidr2Prefix << offset; | ||
109 | + | ||
110 | + return (cidr1Prefix == cidr2Prefix); | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * Check if this ACL rule match the given ACL rule. | ||
115 | + * @param r ACL rule to check against | ||
116 | + * @return true if this ACL rule matches the given ACL ruleule. | ||
117 | + */ | ||
118 | + public boolean checkMatch(AclRule r) { | ||
119 | + return (this.dstTpPort == r.dstTpPort || r.dstTpPort == 0) | ||
120 | + && (this.ipProto == r.ipProto || r.ipProto == 0) | ||
121 | + && (checkCIDRinCIDR(this.srcIp(), r.srcIp())) | ||
122 | + && (checkCIDRinCIDR(this.dstIp(), r.dstIp())); | ||
123 | + } | ||
124 | + | ||
125 | + /** | ||
126 | + * Returns a new ACL rule builder. | ||
127 | + * | ||
128 | + * @return ACL rule builder | ||
129 | + */ | ||
130 | + public static Builder builder() { | ||
131 | + return new Builder(); | ||
132 | + } | ||
133 | + | ||
134 | + /** | ||
135 | + * Builder of an ACL rule. | ||
136 | + */ | ||
137 | + public static final class Builder { | ||
138 | + | ||
139 | + private Ip4Prefix srcIp = null; | ||
140 | + private Ip4Prefix dstIp = null; | ||
141 | + private byte ipProto = 0; | ||
142 | + private short dstTpPort = 0; | ||
143 | + private Action action = Action.DENY; | ||
144 | + | ||
145 | + private Builder() { | ||
146 | + // Hide constructor | ||
147 | + } | ||
148 | + | ||
149 | + /** | ||
150 | + * Sets the source IP address for the ACL rule that will be built. | ||
151 | + * | ||
152 | + * @param srcIp source IP address to use for built ACL rule | ||
153 | + * @return this builder | ||
154 | + */ | ||
155 | + public Builder srcIp(String srcIp) { | ||
156 | + this.srcIp = Ip4Prefix.valueOf(srcIp); | ||
157 | + return this; | ||
158 | + } | ||
159 | + | ||
160 | + /** | ||
161 | + * Sets the destination IP address for the ACL rule that will be built. | ||
162 | + * | ||
163 | + * @param dstIp destination IP address to use for built ACL rule | ||
164 | + * @return this builder | ||
165 | + */ | ||
166 | + public Builder dstIp(String dstIp) { | ||
167 | + this.dstIp = Ip4Prefix.valueOf(dstIp); | ||
168 | + return this; | ||
169 | + } | ||
170 | + | ||
171 | + /** | ||
172 | + * Sets the IP protocol for the ACL rule that will be built. | ||
173 | + * | ||
174 | + * @param ipProto IP protocol to use for built ACL rule | ||
175 | + * @return this builder | ||
176 | + */ | ||
177 | + public Builder ipProto(byte ipProto) { | ||
178 | + this.ipProto = ipProto; | ||
179 | + return this; | ||
180 | + } | ||
181 | + | ||
182 | + /** | ||
183 | + * Sets the destination transport layer port for the ACL rule that will be built. | ||
184 | + * | ||
185 | + * @param dstTpPort destination transport layer port to use for built ACL rule | ||
186 | + * @return this builder | ||
187 | + */ | ||
188 | + public Builder dstTpPort(short dstTpPort) { | ||
189 | + if ((ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP)) { | ||
190 | + this.dstTpPort = dstTpPort; | ||
191 | + } | ||
192 | + return this; | ||
193 | + } | ||
194 | + | ||
195 | + /** | ||
196 | + * Sets the action for the ACL rule that will be built. | ||
197 | + * | ||
198 | + * @param action action to use for built ACL rule | ||
199 | + * @return this builder | ||
200 | + */ | ||
201 | + public Builder action(Action action) { | ||
202 | + this.action = action; | ||
203 | + return this; | ||
204 | + } | ||
205 | + | ||
206 | + /** | ||
207 | + * Builds an ACL rule from the accumulated parameters. | ||
208 | + * @return ACL rule instance | ||
209 | + */ | ||
210 | + public AclRule build() { | ||
211 | + checkState(srcIp != null && dstIp != null, "Either srcIp or dstIp must be assigned."); | ||
212 | + checkState(ipProto == 0 || ipProto == IPv4.PROTOCOL_ICMP | ||
213 | + || ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP, | ||
214 | + "ipProto must be assigned to TCP, UDP, or ICMP."); | ||
215 | + return new AclRule( | ||
216 | + srcIp, | ||
217 | + dstIp, | ||
218 | + ipProto, | ||
219 | + dstTpPort, | ||
220 | + action | ||
221 | + ); | ||
222 | + } | ||
223 | + | ||
224 | + } | ||
225 | + | ||
226 | + /** | ||
227 | + * Binds an id generator for unique ACL rule id generation. | ||
228 | + * | ||
229 | + * Note: A generator cannot be bound if there is already a generator bound. | ||
230 | + * | ||
231 | + * @param newIdGenerator id generator | ||
232 | + */ | ||
233 | + public static void bindIdGenerator(IdGenerator newIdGenerator) { | ||
234 | + checkState(idGenerator == null, "Id generator is already bound."); | ||
235 | + idGenerator = checkNotNull(newIdGenerator); | ||
236 | + } | ||
237 | + | ||
238 | + public RuleId id() { | ||
239 | + return id; | ||
240 | + } | ||
241 | + | ||
242 | + public Ip4Prefix srcIp() { | ||
243 | + return srcIp; | ||
244 | + } | ||
245 | + | ||
246 | + public Ip4Prefix dstIp() { | ||
247 | + return this.dstIp; | ||
248 | + } | ||
249 | + | ||
250 | + public byte ipProto() { | ||
251 | + return ipProto; | ||
252 | + } | ||
253 | + | ||
254 | + public short dstTpPort() { | ||
255 | + return dstTpPort; | ||
256 | + } | ||
257 | + | ||
258 | + public Action action() { | ||
259 | + return action; | ||
260 | + } | ||
261 | + | ||
262 | + @Override | ||
263 | + public int hashCode() { | ||
264 | + return Objects.hash(action, | ||
265 | + id.fingerprint(), | ||
266 | + ipProto, | ||
267 | + srcIp, | ||
268 | + dstIp, | ||
269 | + dstTpPort); | ||
270 | + } | ||
271 | + | ||
272 | + @Override | ||
273 | + public boolean equals(Object obj) { | ||
274 | + if (this == obj) { | ||
275 | + return true; | ||
276 | + } | ||
277 | + if (obj instanceof AclRule) { | ||
278 | + AclRule that = (AclRule) obj; | ||
279 | + return Objects.equals(id, that.id) && | ||
280 | + Objects.equals(srcIp, that.srcIp) && | ||
281 | + Objects.equals(dstIp, that.dstIp) && | ||
282 | + Objects.equals(ipProto, that.ipProto) && | ||
283 | + Objects.equals(dstTpPort, that.dstTpPort) && | ||
284 | + Objects.equals(action, that.action); | ||
285 | + } | ||
286 | + return false; | ||
287 | + } | ||
288 | + | ||
289 | + @Override | ||
290 | + public String toString() { | ||
291 | + return MoreObjects.toStringHelper(this) | ||
292 | + .omitNullValues() | ||
293 | + .add("id", id) | ||
294 | + .add("srcIp", srcIp) | ||
295 | + .add("dstIp", dstIp) | ||
296 | + .add("ipProto", ipProto) | ||
297 | + .add("dstTpPort", dstTpPort) | ||
298 | + .add("action", action) | ||
299 | + .toString(); | ||
300 | + } | ||
301 | + | ||
302 | +} |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | +package org.onos.acl; | ||
21 | + | ||
22 | +import java.util.List; | ||
23 | + | ||
24 | +/** | ||
25 | + * Service interface exported by ACL application. | ||
26 | + */ | ||
27 | +public interface AclService { | ||
28 | + | ||
29 | + /** | ||
30 | + * Gets a list containing all ACL rules. | ||
31 | + * @return a list containing all ACL rules | ||
32 | + */ | ||
33 | + List<AclRule> getAclRules(); | ||
34 | + | ||
35 | + /** | ||
36 | + * Adds a new ACL rule. | ||
37 | + * @param rule ACL rule | ||
38 | + * @return true if successfully added, otherwise false | ||
39 | + */ | ||
40 | + boolean addAclRule(AclRule rule); | ||
41 | + | ||
42 | + /** | ||
43 | + * Removes an exsiting ACL rule by rule id. | ||
44 | + * @param ruleId ACL rule identifier | ||
45 | + */ | ||
46 | + void removeAclRule(RuleId ruleId); | ||
47 | + | ||
48 | + /** | ||
49 | + * Clears ACL and resets all. | ||
50 | + */ | ||
51 | + void clearAcl(); | ||
52 | + | ||
53 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | +package org.onos.acl; | ||
21 | + | ||
22 | +import org.onosproject.net.DeviceId; | ||
23 | +import org.onosproject.net.flow.FlowRule; | ||
24 | +import org.onosproject.store.Store; | ||
25 | + | ||
26 | +import java.util.List; | ||
27 | +import java.util.Set; | ||
28 | + | ||
29 | +/** | ||
30 | + * Service interface exported by ACL distributed store. | ||
31 | + */ | ||
32 | +public interface AclStore extends Store { | ||
33 | + | ||
34 | + /** | ||
35 | + * Gets a list containing all ACL rules. | ||
36 | + * @return a list containing all ACL rules | ||
37 | + */ | ||
38 | + List<AclRule> getAclRules(); | ||
39 | + | ||
40 | + /** | ||
41 | + * Adds a new ACL rule. | ||
42 | + * @param rule new ACL rule | ||
43 | + */ | ||
44 | + void addAclRule(AclRule rule); | ||
45 | + | ||
46 | + /** | ||
47 | + * Gets an existing ACL rule. | ||
48 | + * @param ruleId ACL rule id | ||
49 | + * @return ACL rule with the given id | ||
50 | + */ | ||
51 | + AclRule getAclRule(RuleId ruleId); | ||
52 | + | ||
53 | + /** | ||
54 | + * Removes an existing ACL rule by rule id. | ||
55 | + * @param ruleId ACL rule id | ||
56 | + */ | ||
57 | + void removeAclRule(RuleId ruleId); | ||
58 | + | ||
59 | + /** | ||
60 | + * Clears ACL and reset all. | ||
61 | + */ | ||
62 | + void clearAcl(); | ||
63 | + | ||
64 | + /** | ||
65 | + * Gets the current priority for new ACL flow rule by device id. | ||
66 | + * @param deviceId device id | ||
67 | + * @return new ACL flow rule's priority in the given device | ||
68 | + */ | ||
69 | + int getPriorityByDevice(DeviceId deviceId); | ||
70 | + | ||
71 | + /** | ||
72 | + * Gets a set containing all ACL flow rules belonging to a given ACL rule. | ||
73 | + * @param ruleId ACL rule id | ||
74 | + * @return a set containing all ACL flow rules belonging to the given ACL rule | ||
75 | + */ | ||
76 | + Set<FlowRule> getFlowByRule(RuleId ruleId); | ||
77 | + | ||
78 | + /** | ||
79 | + * Adds a new mapping from ACL rule to ACL flow rule. | ||
80 | + * @param ruleId ACL rule id | ||
81 | + * @param flowRule ACL flow rule | ||
82 | + */ | ||
83 | + void addRuleToFlowMapping(RuleId ruleId, FlowRule flowRule); | ||
84 | + | ||
85 | + /** | ||
86 | + * Removes an existing mapping from ACL rule to ACL flow rule. | ||
87 | + * @param ruleId ACL rule id | ||
88 | + */ | ||
89 | + void removeRuleToFlowMapping(RuleId ruleId); | ||
90 | + | ||
91 | + /** | ||
92 | + * Gets a list containing all allowing ACL rules matching a given denying ACL rule. | ||
93 | + * @param denyingRuleId denying ACL rule id | ||
94 | + * @return a list containing all allowing ACL rules matching the given denying ACL rule | ||
95 | + */ | ||
96 | + List<RuleId> getAllowingRuleByDenyingRule(RuleId denyingRuleId); | ||
97 | + | ||
98 | + /** | ||
99 | + * Adds a new mapping from denying ACL rule to allowing ACL rule. | ||
100 | + * @param denyingRuleId denying ACL rule id | ||
101 | + * @param allowingRuleId allowing ACL rule id | ||
102 | + */ | ||
103 | + void addDenyToAllowMapping(RuleId denyingRuleId, RuleId allowingRuleId); | ||
104 | + | ||
105 | + /** | ||
106 | + * Removes an exsiting mapping from denying ACL rule to allowing ACL rule. | ||
107 | + * @param denyingRuleId denying ACL rule id | ||
108 | + */ | ||
109 | + void removeDenyToAllowMapping(RuleId denyingRuleId); | ||
110 | + | ||
111 | + /** | ||
112 | + * Checks if an existing ACL rule already works in a given device. | ||
113 | + * @param ruleId ACL rule id | ||
114 | + * @param deviceId devide id | ||
115 | + * @return true if the given ACL rule works in the given device | ||
116 | + */ | ||
117 | + boolean checkIfRuleWorksInDevice(RuleId ruleId, DeviceId deviceId); | ||
118 | + | ||
119 | + /** | ||
120 | + * Adds a new mapping from ACL rule to device. | ||
121 | + * @param ruleId ACL rule id | ||
122 | + * @param deviceId device id | ||
123 | + */ | ||
124 | + void addRuleToDeviceMapping(RuleId ruleId, DeviceId deviceId); | ||
125 | + | ||
126 | + /** | ||
127 | + * Removes an existing mapping from ACL rule to device. | ||
128 | + * @param ruleId ACL rule id | ||
129 | + */ | ||
130 | + void removeRuleToDeviceMapping(RuleId ruleId); | ||
131 | + | ||
132 | +} |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | +package org.onos.acl; | ||
21 | + | ||
22 | +import com.fasterxml.jackson.core.JsonParser; | ||
23 | +import com.fasterxml.jackson.core.JsonToken; | ||
24 | +import com.fasterxml.jackson.databind.JsonNode; | ||
25 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
26 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
27 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
28 | +import org.onlab.packet.IPv4; | ||
29 | +import org.onosproject.rest.AbstractWebResource; | ||
30 | +import org.slf4j.Logger; | ||
31 | +import org.slf4j.LoggerFactory; | ||
32 | + | ||
33 | +import javax.ws.rs.GET; | ||
34 | +import javax.ws.rs.POST; | ||
35 | +import javax.ws.rs.Path; | ||
36 | +import javax.ws.rs.PathParam; | ||
37 | +import javax.ws.rs.core.MediaType; | ||
38 | +import javax.ws.rs.core.Response; | ||
39 | +import java.io.IOException; | ||
40 | +import java.io.InputStream; | ||
41 | +import java.util.List; | ||
42 | + | ||
43 | +/** | ||
44 | + * REST resource for interacting with ACL application. | ||
45 | + */ | ||
46 | +@Path("") | ||
47 | +public class AclWebResource extends AbstractWebResource { | ||
48 | + | ||
49 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
50 | + | ||
51 | + /** | ||
52 | + * Processes user's GET HTTP request for querying ACL rules. | ||
53 | + * @return response to the request | ||
54 | + */ | ||
55 | + @GET | ||
56 | + public Response queryAclRule() { | ||
57 | + List<AclRule> rules = get(AclService.class).getAclRules(); | ||
58 | + ObjectMapper mapper = new ObjectMapper(); | ||
59 | + ObjectNode root = mapper.createObjectNode(); | ||
60 | + ArrayNode arrayNode = mapper.createArrayNode(); | ||
61 | + for (AclRule rule : rules) { | ||
62 | + ObjectNode node = mapper.createObjectNode(); | ||
63 | + node.put("id", rule.id().toString()); | ||
64 | + if (rule.srcIp() != null) { | ||
65 | + node.put("srcIp", rule.srcIp().toString()); | ||
66 | + } | ||
67 | + if (rule.dstIp() != null) { | ||
68 | + node.put("dstIp", rule.dstIp().toString()); | ||
69 | + } | ||
70 | + if (rule.ipProto() != 0) { | ||
71 | + switch (rule.ipProto()) { | ||
72 | + case IPv4.PROTOCOL_ICMP: | ||
73 | + node.put("ipProto", "ICMP"); | ||
74 | + break; | ||
75 | + case IPv4.PROTOCOL_TCP: | ||
76 | + node.put("ipProto", "TCP"); | ||
77 | + break; | ||
78 | + case IPv4.PROTOCOL_UDP: | ||
79 | + node.put("ipProto", "UDP"); | ||
80 | + break; | ||
81 | + default: | ||
82 | + break; | ||
83 | + } | ||
84 | + } | ||
85 | + if (rule.dstTpPort() != 0) { | ||
86 | + node.put("dstTpPort", rule.dstTpPort()); | ||
87 | + } | ||
88 | + node.put("action", rule.action().toString()); | ||
89 | + arrayNode.add(node); | ||
90 | + } | ||
91 | + root.set("ACL rules", arrayNode); | ||
92 | + return Response.ok(root.toString(), MediaType.APPLICATION_JSON_TYPE).build(); | ||
93 | + } | ||
94 | + | ||
95 | + /** | ||
96 | + * Processes user's POST HTTP request for add ACL rules. | ||
97 | + * @param stream input stream | ||
98 | + * @return response to the request | ||
99 | + */ | ||
100 | + @POST | ||
101 | + @Path("add") | ||
102 | + public Response addAclRule(InputStream stream) { | ||
103 | + AclRule newRule; | ||
104 | + try { | ||
105 | + newRule = jsonToRule(stream); | ||
106 | + } catch (Exception e) { | ||
107 | + return Response.ok("{\"status\" : \"Failed! " + e.getMessage() + "\"}").build(); | ||
108 | + } | ||
109 | + | ||
110 | + String status; | ||
111 | + if (get(AclService.class).addAclRule(newRule)) { | ||
112 | + status = "Success! New ACL rule is added."; | ||
113 | + } else { | ||
114 | + status = "Failed! New ACL rule matches an existing rule."; | ||
115 | + } | ||
116 | + return Response.ok("{\"status\" : \"" + status + "\"}").build(); | ||
117 | + } | ||
118 | + | ||
119 | + /** | ||
120 | + * Processes user's GET HTTP request for removing ACL rule. | ||
121 | + * @param id ACL rule id (in hex string format) | ||
122 | + * @return response to the request | ||
123 | + */ | ||
124 | + @GET | ||
125 | + @Path("remove/{id}") | ||
126 | + public Response removeAclRule(@PathParam("id") String id) { | ||
127 | + String status; | ||
128 | + RuleId ruleId = new RuleId(Long.parseLong(id.substring(2), 16)); | ||
129 | + if (get(AclStore.class).getAclRule(ruleId) == null) { | ||
130 | + status = "Failed! There is no ACL rule with this id."; | ||
131 | + } else { | ||
132 | + get(AclService.class).removeAclRule(ruleId); | ||
133 | + status = "Success! ACL rule(id:" + id + ") is removed."; | ||
134 | + } | ||
135 | + return Response.ok("{\"status\" : \"" + status + "\"}").build(); | ||
136 | + } | ||
137 | + | ||
138 | + /** | ||
139 | + * Processes user's GET HTTP request for clearing ACL. | ||
140 | + * @return response to the request | ||
141 | + */ | ||
142 | + @GET | ||
143 | + @Path("clear") | ||
144 | + public Response clearACL() { | ||
145 | + get(AclService.class).clearAcl(); | ||
146 | + return Response.ok("{\"status\" : \"ACL is cleared.\"}").build(); | ||
147 | + } | ||
148 | + | ||
149 | + /** | ||
150 | + * Exception class for parsing a invalid ACL rule. | ||
151 | + */ | ||
152 | + private class AclRuleParseException extends Exception { | ||
153 | + public AclRuleParseException(String message) { | ||
154 | + super(message); | ||
155 | + } | ||
156 | + } | ||
157 | + | ||
158 | + /** | ||
159 | + * Turns a JSON string into an ACL rule instance. | ||
160 | + */ | ||
161 | + private AclRule jsonToRule(InputStream stream) throws AclRuleParseException, IOException { | ||
162 | + ObjectMapper mapper = new ObjectMapper(); | ||
163 | + JsonNode jsonNode = mapper.readTree(stream); | ||
164 | + JsonParser jp = jsonNode.traverse(); | ||
165 | + AclRule.Builder rule = AclRule.builder(); | ||
166 | + jp.nextToken(); | ||
167 | + if (jp.getCurrentToken() != JsonToken.START_OBJECT) { | ||
168 | + throw new AclRuleParseException("Expected START_OBJECT"); | ||
169 | + } | ||
170 | + | ||
171 | + while (jp.nextToken() != JsonToken.END_OBJECT) { | ||
172 | + if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { | ||
173 | + throw new AclRuleParseException("Expected FIELD_NAME"); | ||
174 | + } | ||
175 | + | ||
176 | + String key = jp.getCurrentName(); | ||
177 | + jp.nextToken(); | ||
178 | + String value = jp.getText(); | ||
179 | + if ("".equals(value)) { | ||
180 | + continue; | ||
181 | + } | ||
182 | + | ||
183 | + if ("srcIp".equals(key)) { | ||
184 | + rule.srcIp(value); | ||
185 | + } else if ("dstIp".equals(key)) { | ||
186 | + rule.dstIp(value); | ||
187 | + } else if ("ipProto".equals(key)) { | ||
188 | + if ("TCP".equalsIgnoreCase(value)) { | ||
189 | + rule.ipProto(IPv4.PROTOCOL_TCP); | ||
190 | + } else if ("UDP".equalsIgnoreCase(value)) { | ||
191 | + rule.ipProto(IPv4.PROTOCOL_UDP); | ||
192 | + } else if ("ICMP".equalsIgnoreCase(value)) { | ||
193 | + rule.ipProto(IPv4.PROTOCOL_ICMP); | ||
194 | + } else { | ||
195 | + throw new AclRuleParseException("ipProto must be assigned to TCP, UDP, or ICMP."); | ||
196 | + } | ||
197 | + } else if ("dstTpPort".equals(key)) { | ||
198 | + try { | ||
199 | + rule.dstTpPort(Short.parseShort(value)); | ||
200 | + } catch (NumberFormatException e) { | ||
201 | + throw new AclRuleParseException("dstTpPort must be assigned to a numerical value."); | ||
202 | + } | ||
203 | + } else if ("action".equals(key)) { | ||
204 | + if (!"allow".equalsIgnoreCase(value) && !"deny".equalsIgnoreCase(value)) { | ||
205 | + throw new AclRuleParseException("action must be assigned to ALLOW or DENY."); | ||
206 | + } | ||
207 | + if ("allow".equalsIgnoreCase(value)) { | ||
208 | + rule.action(AclRule.Action.ALLOW); | ||
209 | + } | ||
210 | + } | ||
211 | + } | ||
212 | + return rule.build(); | ||
213 | + } | ||
214 | + | ||
215 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | +package org.onos.acl; | ||
21 | + | ||
22 | +/** | ||
23 | + * ACL rule identifier suitable as an external key. | ||
24 | + * <p>This class is immutable.</p> | ||
25 | + */ | ||
26 | +public final class RuleId { | ||
27 | + private final long value; | ||
28 | + | ||
29 | + /** | ||
30 | + * Creates an ACL rule identifier from the specified long value. | ||
31 | + * | ||
32 | + * @param value long value | ||
33 | + * @return ACL rule identifier | ||
34 | + */ | ||
35 | + public static RuleId valueOf(long value) { | ||
36 | + return new RuleId(value); | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * Constructor for serializer. | ||
41 | + */ | ||
42 | + RuleId() { | ||
43 | + this.value = 0; | ||
44 | + } | ||
45 | + | ||
46 | + /** | ||
47 | + * Constructs the ID corresponding to a given long value. | ||
48 | + * | ||
49 | + * @param value the underlying value of this ID | ||
50 | + */ | ||
51 | + RuleId(long value) { | ||
52 | + this.value = value; | ||
53 | + } | ||
54 | + | ||
55 | + /** | ||
56 | + * Returns the backing value. | ||
57 | + * | ||
58 | + * @return the value | ||
59 | + */ | ||
60 | + public long fingerprint() { | ||
61 | + return value; | ||
62 | + } | ||
63 | + | ||
64 | + @Override | ||
65 | + public int hashCode() { | ||
66 | + return Long.hashCode(value); | ||
67 | + } | ||
68 | + | ||
69 | + @Override | ||
70 | + public boolean equals(Object obj) { | ||
71 | + if (obj == this) { | ||
72 | + return true; | ||
73 | + } | ||
74 | + if (!(obj instanceof RuleId)) { | ||
75 | + return false; | ||
76 | + } | ||
77 | + RuleId that = (RuleId) obj; | ||
78 | + return this.value == that.value; | ||
79 | + } | ||
80 | + | ||
81 | + @Override | ||
82 | + public String toString() { | ||
83 | + return "0x" + Long.toHexString(value); | ||
84 | + } | ||
85 | +} |
This diff is collapsed. Click to expand it.
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | +package org.onos.acl.impl; | ||
21 | + | ||
22 | +import com.google.common.collect.Collections2; | ||
23 | +import org.onos.acl.AclRule; | ||
24 | +import org.onos.acl.AclStore; | ||
25 | +import org.apache.felix.scr.annotations.Activate; | ||
26 | +import org.apache.felix.scr.annotations.Component; | ||
27 | +import org.apache.felix.scr.annotations.Deactivate; | ||
28 | +import org.apache.felix.scr.annotations.Reference; | ||
29 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
30 | +import org.apache.felix.scr.annotations.Service; | ||
31 | +import org.onlab.util.KryoNamespace; | ||
32 | +import org.onos.acl.RuleId; | ||
33 | +import org.onosproject.core.ApplicationId; | ||
34 | +import org.onosproject.core.CoreService; | ||
35 | +import org.onosproject.net.DeviceId; | ||
36 | +import org.onosproject.net.flow.FlowRule; | ||
37 | +import org.onosproject.store.AbstractStore; | ||
38 | +import org.onosproject.store.serializers.KryoNamespaces; | ||
39 | +import org.onosproject.store.service.ConsistentMap; | ||
40 | +import org.onosproject.store.service.Serializer; | ||
41 | +import org.onosproject.store.service.StorageService; | ||
42 | +import org.onosproject.store.service.Versioned; | ||
43 | +import org.slf4j.Logger; | ||
44 | + | ||
45 | +import java.util.ArrayList; | ||
46 | +import java.util.HashSet; | ||
47 | +import java.util.List; | ||
48 | +import java.util.Set; | ||
49 | + | ||
50 | +import static org.slf4j.LoggerFactory.getLogger; | ||
51 | + | ||
52 | +/** | ||
53 | + * Implementation of the ACL store service. | ||
54 | + */ | ||
55 | +@Component(immediate = true) | ||
56 | +@Service | ||
57 | +public class DistributedAclStore extends AbstractStore implements AclStore { | ||
58 | + | ||
59 | + private final Logger log = getLogger(getClass()); | ||
60 | + private final int defaultFlowMaxPriority = 30000; | ||
61 | + | ||
62 | + private ConsistentMap<RuleId, AclRule> ruleSet; | ||
63 | + private ConsistentMap<DeviceId, Integer> deviceToPriority; | ||
64 | + private ConsistentMap<RuleId, Set<DeviceId>> ruleToDevice; | ||
65 | + private ConsistentMap<RuleId, Set<FlowRule>> ruleToFlow; | ||
66 | + private ConsistentMap<RuleId, List<RuleId>> denyRuleToAllowRule; | ||
67 | + | ||
68 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
69 | + protected StorageService storageService; | ||
70 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
71 | + protected CoreService coreService; | ||
72 | + | ||
73 | + @Activate | ||
74 | + public void activate() { | ||
75 | + ApplicationId appId = coreService.getAppId("org.onosproject.acl"); | ||
76 | + | ||
77 | + KryoNamespace.Builder serializer = KryoNamespace.newBuilder() | ||
78 | + .register(KryoNamespaces.API) | ||
79 | + .register(AclRule.class) | ||
80 | + .register(AclRule.Action.class) | ||
81 | + .register(RuleId.class); | ||
82 | + | ||
83 | + ruleSet = storageService.<RuleId, AclRule>consistentMapBuilder() | ||
84 | + .withSerializer(Serializer.using(serializer.build())) | ||
85 | + .withName("acl-rule-set") | ||
86 | + .withApplicationId(appId) | ||
87 | + .withPurgeOnUninstall() | ||
88 | + .build(); | ||
89 | + | ||
90 | + deviceToPriority = storageService.<DeviceId, Integer>consistentMapBuilder() | ||
91 | + .withSerializer(Serializer.using(serializer.build())) | ||
92 | + .withName("device-to-priority") | ||
93 | + .withApplicationId(appId) | ||
94 | + .withPurgeOnUninstall() | ||
95 | + .build(); | ||
96 | + | ||
97 | + ruleToFlow = storageService.<RuleId, Set<FlowRule>>consistentMapBuilder() | ||
98 | + .withSerializer(Serializer.using(serializer.build())) | ||
99 | + .withName("rule-to-flow") | ||
100 | + .withApplicationId(appId) | ||
101 | + .withPurgeOnUninstall() | ||
102 | + .build(); | ||
103 | + | ||
104 | + denyRuleToAllowRule = storageService.<RuleId, List<RuleId>>consistentMapBuilder() | ||
105 | + .withSerializer(Serializer.using(serializer.build())) | ||
106 | + .withName("deny-to-allow") | ||
107 | + .withApplicationId(appId) | ||
108 | + .withPurgeOnUninstall() | ||
109 | + .build(); | ||
110 | + | ||
111 | + ruleToDevice = storageService.<RuleId, Set<DeviceId>>consistentMapBuilder() | ||
112 | + .withSerializer(Serializer.using(serializer.build())) | ||
113 | + .withName("rule-to-device") | ||
114 | + .withApplicationId(appId) | ||
115 | + .withPurgeOnUninstall() | ||
116 | + .build(); | ||
117 | + | ||
118 | + log.info("Started"); | ||
119 | + } | ||
120 | + | ||
121 | + @Deactivate | ||
122 | + public void deactive() { | ||
123 | + log.info("Stopped"); | ||
124 | + } | ||
125 | + | ||
126 | + @Override | ||
127 | + public List<AclRule> getAclRules() { | ||
128 | + List<AclRule> aclRules = new ArrayList<>(); | ||
129 | + aclRules.addAll(Collections2.transform(ruleSet.values(), Versioned::value)); | ||
130 | + return aclRules; | ||
131 | + } | ||
132 | + | ||
133 | + @Override | ||
134 | + public void addAclRule(AclRule rule) { | ||
135 | + ruleSet.putIfAbsent(rule.id(), rule); | ||
136 | + } | ||
137 | + | ||
138 | + @Override | ||
139 | + public AclRule getAclRule(RuleId ruleId) { | ||
140 | + Versioned<AclRule> rule = ruleSet.get(ruleId); | ||
141 | + if (rule != null) { | ||
142 | + return rule.value(); | ||
143 | + } else { | ||
144 | + return null; | ||
145 | + } | ||
146 | + } | ||
147 | + | ||
148 | + @Override | ||
149 | + public void removeAclRule(RuleId ruleId) { | ||
150 | + ruleSet.remove(ruleId); | ||
151 | + } | ||
152 | + | ||
153 | + @Override | ||
154 | + public void clearAcl() { | ||
155 | + ruleSet.clear(); | ||
156 | + deviceToPriority.clear(); | ||
157 | + ruleToFlow.clear(); | ||
158 | + denyRuleToAllowRule.clear(); | ||
159 | + ruleToDevice.clear(); | ||
160 | + } | ||
161 | + | ||
162 | + @Override | ||
163 | + public int getPriorityByDevice(DeviceId deviceId) { | ||
164 | + return deviceToPriority.compute(deviceId, | ||
165 | + (id, priority) -> (priority == null) ? defaultFlowMaxPriority : (priority - 1)) | ||
166 | + .value(); | ||
167 | + } | ||
168 | + | ||
169 | + @Override | ||
170 | + public Set<FlowRule> getFlowByRule(RuleId ruleId) { | ||
171 | + Versioned<Set<FlowRule>> flowRuleSet = ruleToFlow.get(ruleId); | ||
172 | + if (flowRuleSet != null) { | ||
173 | + return flowRuleSet.value(); | ||
174 | + } else { | ||
175 | + return null; | ||
176 | + } | ||
177 | + } | ||
178 | + | ||
179 | + @Override | ||
180 | + public void addRuleToFlowMapping(RuleId ruleId, FlowRule flowRule) { | ||
181 | + ruleToFlow.computeIf(ruleId, | ||
182 | + flowRuleSet -> (flowRuleSet == null || !flowRuleSet.contains(flowRule)), | ||
183 | + (id, flowRuleSet) -> { | ||
184 | + Set<FlowRule> newSet = new HashSet<>(); | ||
185 | + if (flowRuleSet != null) { | ||
186 | + newSet.addAll(flowRuleSet); | ||
187 | + } | ||
188 | + newSet.add(flowRule); | ||
189 | + return newSet; | ||
190 | + }); | ||
191 | + } | ||
192 | + | ||
193 | + @Override | ||
194 | + public void removeRuleToFlowMapping(RuleId ruleId) { | ||
195 | + ruleToFlow.remove(ruleId); | ||
196 | + } | ||
197 | + | ||
198 | + @Override | ||
199 | + public List<RuleId> getAllowingRuleByDenyingRule(RuleId denyingRuleId) { | ||
200 | + Versioned<List<RuleId>> allowRuleIdSet = denyRuleToAllowRule.get(denyingRuleId); | ||
201 | + if (allowRuleIdSet != null) { | ||
202 | + return allowRuleIdSet.value(); | ||
203 | + } else { | ||
204 | + return null; | ||
205 | + } | ||
206 | + } | ||
207 | + | ||
208 | + @Override | ||
209 | + public void addDenyToAllowMapping(RuleId denyingRuleId, RuleId allowingRuleId) { | ||
210 | + denyRuleToAllowRule.computeIf(denyingRuleId, | ||
211 | + ruleIdList -> (ruleIdList == null || !ruleIdList.contains(allowingRuleId)), | ||
212 | + (id, ruleIdList) -> { | ||
213 | + ArrayList<RuleId> newList = new ArrayList<>(); | ||
214 | + if (ruleIdList != null) { | ||
215 | + newList.addAll(ruleIdList); | ||
216 | + } | ||
217 | + newList.add(allowingRuleId); | ||
218 | + return newList; | ||
219 | + }); | ||
220 | + } | ||
221 | + | ||
222 | + @Override | ||
223 | + public void removeDenyToAllowMapping(RuleId denyingRuleId) { | ||
224 | + denyRuleToAllowRule.remove(denyingRuleId); | ||
225 | + } | ||
226 | + | ||
227 | + @Override | ||
228 | + public boolean checkIfRuleWorksInDevice(RuleId ruleId, DeviceId deviceId) { | ||
229 | + return ruleToDevice.containsKey(ruleId) && ruleToDevice.get(ruleId).value().contains(deviceId); | ||
230 | + } | ||
231 | + | ||
232 | + @Override | ||
233 | + public void addRuleToDeviceMapping(RuleId ruleId, DeviceId deviceId) { | ||
234 | + ruleToDevice.computeIf(ruleId, | ||
235 | + deviceIdSet -> (deviceIdSet == null || !deviceIdSet.contains(deviceId)), | ||
236 | + (id, deviceIdSet) -> { | ||
237 | + Set<DeviceId> newSet = new HashSet<DeviceId>(); | ||
238 | + if (deviceIdSet != null) { | ||
239 | + newSet.addAll(deviceIdSet); | ||
240 | + } | ||
241 | + newSet.add(deviceId); | ||
242 | + return newSet; | ||
243 | + }); | ||
244 | + } | ||
245 | + | ||
246 | + @Override | ||
247 | + public void removeRuleToDeviceMapping(RuleId ruleId) { | ||
248 | + ruleToDevice.remove(ruleId); | ||
249 | + } | ||
250 | + | ||
251 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
apps/acl/src/main/webapp/WEB-INF/web.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2015 Open Networking Laboratory | ||
4 | + ~ Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
5 | + ~ Advisers: Keqiu Li and Heng Qi | ||
6 | + ~ This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
7 | + ~ and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
8 | + ~ | ||
9 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
10 | + ~ you may not use this file except in compliance with the License. | ||
11 | + ~ You may obtain a copy of the License at | ||
12 | + ~ | ||
13 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
14 | + ~ | ||
15 | + ~ Unless required by applicable law or agreed to in writing, software | ||
16 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
17 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
18 | + ~ See the License for the specific language governing permissions and | ||
19 | + ~ limitations under the License. | ||
20 | + --> | ||
21 | +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" | ||
22 | + xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" | ||
23 | + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" | ||
24 | + id="ONOS" version="2.5"> | ||
25 | + <display-name>ACL application</display-name> | ||
26 | + | ||
27 | + <servlet> | ||
28 | + <servlet-name>JAX-RS Service</servlet-name> | ||
29 | + <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> | ||
30 | + <init-param> | ||
31 | + <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name> | ||
32 | + <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value> | ||
33 | + </init-param> | ||
34 | + <init-param> | ||
35 | + <param-name>com.sun.jersey.config.property.classnames</param-name> | ||
36 | + <param-value>org.onos.acl.AclWebResource</param-value> | ||
37 | + </init-param> | ||
38 | + <load-on-startup>10</load-on-startup> | ||
39 | + </servlet> | ||
40 | + | ||
41 | + <servlet-mapping> | ||
42 | + <servlet-name>JAX-RS Service</servlet-name> | ||
43 | + <url-pattern>/*</url-pattern> | ||
44 | + </servlet-mapping> | ||
45 | + | ||
46 | +</web-app> |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | + | ||
21 | +package org.onos.acl.web; | ||
22 | + | ||
23 | +import com.sun.jersey.api.client.WebResource; | ||
24 | +import org.onos.acl.AclService; | ||
25 | +import org.onos.acl.AclStore; | ||
26 | +import org.junit.After; | ||
27 | +import org.junit.Before; | ||
28 | +import org.junit.Test; | ||
29 | +import org.onlab.osgi.ServiceDirectory; | ||
30 | +import org.onlab.rest.BaseResource; | ||
31 | +import org.onos.acl.AclRule; | ||
32 | +import org.onosproject.core.IdGenerator; | ||
33 | + | ||
34 | +import java.io.IOException; | ||
35 | +import java.util.ArrayList; | ||
36 | +import java.util.List; | ||
37 | +import java.util.concurrent.atomic.AtomicLong; | ||
38 | + | ||
39 | +import static org.easymock.EasyMock.*; | ||
40 | +import static org.hamcrest.Matchers.containsString; | ||
41 | +import static org.junit.Assert.assertThat; | ||
42 | + | ||
43 | +/** | ||
44 | + * Test class for ACL application REST resource. | ||
45 | + */ | ||
46 | +public class AclWebResourceTest extends ResourceTest { | ||
47 | + | ||
48 | + final AclService mockAclService = createMock(AclService.class); | ||
49 | + final AclStore mockAclStore = createMock(AclStore.class); | ||
50 | + final List<AclRule> rules = new ArrayList<>(); | ||
51 | + | ||
52 | + @Before | ||
53 | + public void setUp() { | ||
54 | + expect(mockAclService.getAclRules()).andReturn(rules).anyTimes(); | ||
55 | + ServiceDirectory testDirectory = new TestServiceDirectory().add(AclService.class, mockAclService) | ||
56 | + .add(AclStore.class, mockAclStore); | ||
57 | + BaseResource.setServiceDirectory(testDirectory); | ||
58 | + } | ||
59 | + | ||
60 | + @After | ||
61 | + public void tearDown() { | ||
62 | + verify(mockAclService); | ||
63 | + } | ||
64 | + | ||
65 | + /** | ||
66 | + * Mock id generator for testing. | ||
67 | + */ | ||
68 | + private class MockIdGenerator implements IdGenerator { | ||
69 | + private AtomicLong nextId = new AtomicLong(0); | ||
70 | + | ||
71 | + @Override | ||
72 | + public long getNewId() { | ||
73 | + return nextId.getAndIncrement(); | ||
74 | + } | ||
75 | + } | ||
76 | + | ||
77 | + @Test | ||
78 | + public void testaddRule() throws IOException { | ||
79 | + WebResource rs = resource(); | ||
80 | + String response; | ||
81 | + String json; | ||
82 | + IdGenerator idGenerator = new MockIdGenerator(); | ||
83 | + AclRule.bindIdGenerator(idGenerator); | ||
84 | + | ||
85 | + replay(mockAclService); | ||
86 | + | ||
87 | + // input a invalid JSON string that contains neither nw_src and nw_dst | ||
88 | + json = "{\"ipProto\":\"TCP\",\"dstTpPort\":\"80\"}"; | ||
89 | + response = rs.path("add").post(String.class, json); | ||
90 | + assertThat(response, containsString("Failed! Either srcIp or dstIp must be assigned.")); | ||
91 | + | ||
92 | + // input a invalid JSON string that doesn't contain CIDR mask bits | ||
93 | + json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}"; | ||
94 | + response = rs.path("add").post(String.class, json); | ||
95 | + assertThat(response, containsString("Malformed IPv4 prefix string: 10.0.0.1. " + | ||
96 | + "Address must take form \"x.x.x.x/y\"")); | ||
97 | + | ||
98 | + // input a invalid JSON string that contains a invalid IP address | ||
99 | + json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.256/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}"; | ||
100 | + response = rs.path("add").post(String.class, json); | ||
101 | + assertThat(response, containsString("Invalid IP address string: 10.0.0.256")); | ||
102 | + | ||
103 | + // input a invalid JSON string that contains a invalid IP address | ||
104 | + json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.01/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}"; | ||
105 | + response = rs.path("add").post(String.class, json); | ||
106 | + assertThat(response, containsString("Invalid IP address string: 10.0.01")); | ||
107 | + | ||
108 | + // input a invalid JSON string that contains a invalid CIDR mask bits | ||
109 | + json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/a\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}"; | ||
110 | + response = rs.path("add").post(String.class, json); | ||
111 | + assertThat(response, containsString("Failed! For input string: \"a\"")); | ||
112 | + | ||
113 | + // input a invalid JSON string that contains a invalid CIDR mask bits | ||
114 | + json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/33\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}"; | ||
115 | + response = rs.path("add").post(String.class, json); | ||
116 | + assertThat(response, containsString("Invalid prefix length 33. The value must be in the interval [0, 32]")); | ||
117 | + | ||
118 | + // input a invalid JSON string that contains a invalid ipProto value | ||
119 | + json = "{\"ipProto\":\"ARP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"80\",\"action\":\"DENY\"}"; | ||
120 | + response = rs.path("add").post(String.class, json); | ||
121 | + assertThat(response, containsString("ipProto must be assigned to TCP, UDP, or ICMP.")); | ||
122 | + | ||
123 | + // input a invalid JSON string that contains a invalid dstTpPort value | ||
124 | + json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"a\",\"action\":\"DENY\"}"; | ||
125 | + response = rs.path("add").post(String.class, json); | ||
126 | + assertThat(response, containsString("dstTpPort must be assigned to a numerical value.")); | ||
127 | + | ||
128 | + // input a invalid JSON string that contains a invalid action value | ||
129 | + json = "{\"ipProto\":\"TCP\",\"srcIp\":\"10.0.0.1/32\",\"dstTpPort\":\"80\",\"action\":\"PERMIT\"}"; | ||
130 | + response = rs.path("add").post(String.class, json); | ||
131 | + assertThat(response, containsString("action must be assigned to ALLOW or DENY.")); | ||
132 | + } | ||
133 | +} |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | +package org.onos.acl.web; | ||
21 | + | ||
22 | +import com.sun.jersey.test.framework.AppDescriptor; | ||
23 | +import com.sun.jersey.test.framework.JerseyTest; | ||
24 | +import com.sun.jersey.test.framework.WebAppDescriptor; | ||
25 | + | ||
26 | +import java.io.IOException; | ||
27 | +import java.net.ServerSocket; | ||
28 | + | ||
29 | +/** | ||
30 | + * Base class for REST API tests. Performs common configuration operations. | ||
31 | + */ | ||
32 | +public class ResourceTest extends JerseyTest { | ||
33 | + | ||
34 | + /** | ||
35 | + * Assigns an available port for the test. | ||
36 | + * | ||
37 | + * @param defaultPort If a port cannot be determined, this one is used. | ||
38 | + * @return free port | ||
39 | + */ | ||
40 | + @Override | ||
41 | + public int getPort(int defaultPort) { | ||
42 | + try { | ||
43 | + ServerSocket socket = new ServerSocket(0); | ||
44 | + socket.setReuseAddress(true); | ||
45 | + int port = socket.getLocalPort(); | ||
46 | + socket.close(); | ||
47 | + return port; | ||
48 | + } catch (IOException ioe) { | ||
49 | + return defaultPort; | ||
50 | + } | ||
51 | + } | ||
52 | + | ||
53 | + @Override | ||
54 | + public AppDescriptor configure() { | ||
55 | + return new WebAppDescriptor.Builder("org.onos.acl").build(); | ||
56 | + } | ||
57 | + | ||
58 | +} |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China | ||
4 | + * Advisers: Keqiu Li and Heng Qi | ||
5 | + * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) | ||
6 | + * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. | ||
7 | + * | ||
8 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
9 | + * you may not use this file except in compliance with the License. | ||
10 | + * You may obtain a copy of the License at | ||
11 | + * | ||
12 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
13 | + * | ||
14 | + * Unless required by applicable law or agreed to in writing, software | ||
15 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
16 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
17 | + * See the License for the specific language governing permissions and | ||
18 | + * limitations under the License. | ||
19 | + */ | ||
20 | +package org.onos.acl.web; | ||
21 | + | ||
22 | +import com.google.common.collect.ClassToInstanceMap; | ||
23 | +import com.google.common.collect.MutableClassToInstanceMap; | ||
24 | +import org.onlab.osgi.ServiceDirectory; | ||
25 | + | ||
26 | +/** | ||
27 | + * Service directory implementation suitable for testing. | ||
28 | + */ | ||
29 | +public class TestServiceDirectory implements ServiceDirectory { | ||
30 | + | ||
31 | + | ||
32 | + private ClassToInstanceMap<Object> services = MutableClassToInstanceMap.create(); | ||
33 | + | ||
34 | + @Override | ||
35 | + public <T> T get(Class<T> serviceClass) { | ||
36 | + return services.getInstance(serviceClass); | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * Adds a new service to the directory. | ||
41 | + * | ||
42 | + * @param serviceClass service class | ||
43 | + * @param service service instance | ||
44 | + * @return self | ||
45 | + */ | ||
46 | + public TestServiceDirectory add(Class serviceClass, Object service) { | ||
47 | + services.putInstance(serviceClass, service); | ||
48 | + return this; | ||
49 | + } | ||
50 | + | ||
51 | +} |
... | @@ -33,6 +33,7 @@ | ... | @@ -33,6 +33,7 @@ |
33 | 33 | ||
34 | <modules> | 34 | <modules> |
35 | <module>aaa</module> | 35 | <module>aaa</module> |
36 | + <module>acl</module> | ||
36 | <module>fwd</module> | 37 | <module>fwd</module> |
37 | <module>mobility</module> | 38 | <module>mobility</module> |
38 | <module>proxyarp</module> | 39 | <module>proxyarp</module> | ... | ... |
-
Please register or login to post a comment