blob: 8587d7c481a1bda775f0b9fca1655e63ce7f7765 [file] [log] [blame]
Pengfei Lue0c02e22015-07-07 15:41:31 +08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Pengfei Lue0c02e22015-07-07 15:41:31 +08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Ray Milkey85267002016-11-16 11:06:35 -080015 *
16 * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
17 * Advisers: Keqiu Li, Heng Qi and Haisheng Yu
18 * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
19 * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
Pengfei Lue0c02e22015-07-07 15:41:31 +080020 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -070021package org.onosproject.acl;
Pengfei Lue0c02e22015-07-07 15:41:31 +080022
23import com.google.common.base.MoreObjects;
24import org.onlab.packet.IPv4;
25import org.onlab.packet.Ip4Prefix;
Nitin Anandfb22901d2018-05-09 12:16:36 +053026import org.onlab.packet.MacAddress;
Pengfei Lue0c02e22015-07-07 15:41:31 +080027import org.onosproject.core.IdGenerator;
28
29import java.util.Objects;
30
31import static com.google.common.base.Preconditions.checkNotNull;
32import static com.google.common.base.Preconditions.checkState;
33
34/**
35 * ACL rule class.
36 */
37public final class AclRule {
38
39 private final RuleId id;
40
Nitin Anandfb22901d2018-05-09 12:16:36 +053041 private final MacAddress srcMac;
42 private final MacAddress dstMac;
Pengfei Lue0c02e22015-07-07 15:41:31 +080043 private final Ip4Prefix srcIp;
44 private final Ip4Prefix dstIp;
45 private final byte ipProto;
Nitin Anandfb22901d2018-05-09 12:16:36 +053046 private final short srcTpPort;
Pengfei Lue0c02e22015-07-07 15:41:31 +080047 private final short dstTpPort;
Nitin Anandfb22901d2018-05-09 12:16:36 +053048 private final byte dscp;
Pengfei Lue0c02e22015-07-07 15:41:31 +080049 private final Action action;
50
Ray Milkey06297ed2018-01-22 17:13:41 -080051 protected static IdGenerator idGenerator;
Ray Milkey074ba9b2018-02-06 10:23:41 -080052 private static final Object ID_GENERATOR_LOCK = new Object();
Pengfei Lue0c02e22015-07-07 15:41:31 +080053
54 /**
55 * Enum type for ACL rule's action.
56 */
57 public enum Action {
58 DENY, ALLOW
59 }
60
61 /**
62 * Constructor for serializer.
63 */
64 private AclRule() {
65 this.id = null;
Nitin Anandfb22901d2018-05-09 12:16:36 +053066 this.srcMac = null;
67 this.dstMac = null;
Pengfei Lue0c02e22015-07-07 15:41:31 +080068 this.srcIp = null;
69 this.dstIp = null;
Nitin Anandfb22901d2018-05-09 12:16:36 +053070 this.dscp = 0;
Pengfei Lue0c02e22015-07-07 15:41:31 +080071 this.ipProto = 0;
72 this.dstTpPort = 0;
Nitin Anandfb22901d2018-05-09 12:16:36 +053073 this.srcTpPort = 0;
Pengfei Lue0c02e22015-07-07 15:41:31 +080074 this.action = null;
75 }
76
77 /**
78 * Create a new ACL rule.
79 *
Thomas Vachuska9bb32352015-09-25 11:31:22 -070080 * @param srcIp source IP address
Nitin Anandfb22901d2018-05-09 12:16:36 +053081 * @param srcMac source Mac address
82 * @param dstMac destination Mac address
Thomas Vachuska9bb32352015-09-25 11:31:22 -070083 * @param dstIp destination IP address
84 * @param ipProto IP protocol
Nitin Anandfb22901d2018-05-09 12:16:36 +053085 * @param dscp IP dscp
Pengfei Lue0c02e22015-07-07 15:41:31 +080086 * @param dstTpPort destination transport layer port
Nitin Anandfb22901d2018-05-09 12:16:36 +053087 * @param srcTpPort source transport layer port
Thomas Vachuska9bb32352015-09-25 11:31:22 -070088 * @param action ACL rule's action
Pengfei Lue0c02e22015-07-07 15:41:31 +080089 */
Nitin Anandfb22901d2018-05-09 12:16:36 +053090 private AclRule(MacAddress srcMac, MacAddress dstMac, Ip4Prefix srcIp, Ip4Prefix dstIp, byte ipProto,
91 byte dscp, short dstTpPort, short srcTpPort, Action action) {
Ray Milkey074ba9b2018-02-06 10:23:41 -080092 synchronized (ID_GENERATOR_LOCK) {
93 checkState(idGenerator != null, "Id generator is not bound.");
94 this.id = RuleId.valueOf(idGenerator.getNewId());
95 }
Nitin Anandfb22901d2018-05-09 12:16:36 +053096 this.srcMac = srcMac;
97 this.dstMac = dstMac;
Pengfei Lue0c02e22015-07-07 15:41:31 +080098 this.srcIp = srcIp;
99 this.dstIp = dstIp;
100 this.ipProto = ipProto;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530101 this.dscp = dscp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800102 this.dstTpPort = dstTpPort;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530103 this.srcTpPort = srcTpPort;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800104 this.action = action;
105 }
106
107 /**
108 * Check if the first CIDR address is in (or the same as) the second CIDR address.
109 */
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800110 private boolean checkCidrInCidr(Ip4Prefix cidrAddr1, Ip4Prefix cidrAddr2) {
Pengfei Lue0c02e22015-07-07 15:41:31 +0800111 if (cidrAddr2 == null) {
112 return true;
113 } else if (cidrAddr1 == null) {
114 return false;
115 }
116 if (cidrAddr1.prefixLength() < cidrAddr2.prefixLength()) {
117 return false;
118 }
119 int offset = 32 - cidrAddr2.prefixLength();
120
121 int cidr1Prefix = cidrAddr1.address().toInt();
122 int cidr2Prefix = cidrAddr2.address().toInt();
123 cidr1Prefix = cidr1Prefix >> offset;
124 cidr2Prefix = cidr2Prefix >> offset;
125 cidr1Prefix = cidr1Prefix << offset;
126 cidr2Prefix = cidr2Prefix << offset;
127
128 return (cidr1Prefix == cidr2Prefix);
129 }
130
131 /**
132 * Check if this ACL rule match the given ACL rule.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700133 *
Pengfei Lue0c02e22015-07-07 15:41:31 +0800134 * @param r ACL rule to check against
135 * @return true if this ACL rule matches the given ACL ruleule.
136 */
137 public boolean checkMatch(AclRule r) {
138 return (this.dstTpPort == r.dstTpPort || r.dstTpPort == 0)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530139 && (this.srcTpPort == r.srcTpPort || r.srcTpPort == 0)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800140 && (this.ipProto == r.ipProto || r.ipProto == 0)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530141 && (this.dscp == r.dscp || r.dscp == 0)
142 && (this.srcMac == r.srcMac || r.srcMac == null)
143 && (this.dstMac == r.dstMac || r.dstMac == null)
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800144 && (checkCidrInCidr(this.srcIp(), r.srcIp()))
145 && (checkCidrInCidr(this.dstIp(), r.dstIp()));
Pengfei Lue0c02e22015-07-07 15:41:31 +0800146 }
147
148 /**
149 * Returns a new ACL rule builder.
150 *
151 * @return ACL rule builder
152 */
153 public static Builder builder() {
154 return new Builder();
155 }
156
157 /**
158 * Builder of an ACL rule.
159 */
160 public static final class Builder {
161
162 private Ip4Prefix srcIp = null;
163 private Ip4Prefix dstIp = null;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530164 private MacAddress srcMac = null;
165 private MacAddress dstMac = null;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800166 private byte ipProto = 0;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530167 private byte dscp = 0;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800168 private short dstTpPort = 0;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530169 private short srcTpPort = 0;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800170 private Action action = Action.DENY;
171
172 private Builder() {
173 // Hide constructor
174 }
175
176 /**
Nitin Anandfb22901d2018-05-09 12:16:36 +0530177 * Sets the source Mac address for the ACL rule that will be built.
178 *
179 * @param srcMac source Mac address to use for built ACL rule
180 * @return this builder
181 */
182 public Builder srcMac(MacAddress srcMac) {
183 this.srcMac = srcMac;
184 return this;
185 }
186
187 /**
188 * Sets the destination Mac address for the ACL rule that will be built.
189 *
190 * @param dstMac destination Mac address to use for built ACL rule
191 * @return this builder
192 */
193 public Builder dstMac(MacAddress dstMac) {
194 this.dstMac = dstMac;
195 return this;
196 }
197
198 /**
Pengfei Lue0c02e22015-07-07 15:41:31 +0800199 * Sets the source IP address for the ACL rule that will be built.
200 *
201 * @param srcIp source IP address to use for built ACL rule
202 * @return this builder
203 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700204 public Builder srcIp(Ip4Prefix srcIp) {
205 this.srcIp = srcIp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800206 return this;
207 }
208
209 /**
210 * Sets the destination IP address for the ACL rule that will be built.
211 *
212 * @param dstIp destination IP address to use for built ACL rule
213 * @return this builder
214 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700215 public Builder dstIp(Ip4Prefix dstIp) {
216 this.dstIp = dstIp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800217 return this;
218 }
219
220 /**
221 * Sets the IP protocol for the ACL rule that will be built.
222 *
223 * @param ipProto IP protocol to use for built ACL rule
224 * @return this builder
225 */
226 public Builder ipProto(byte ipProto) {
227 this.ipProto = ipProto;
228 return this;
229 }
230
Nitin Anandfb22901d2018-05-09 12:16:36 +0530231
232 /**
233 * Sets the IP dscp for the ACL rule that will be built.
234 *
235 * @param dscp IP dscp to use for built ACL rule
236 * @return this builder
237 */
238 public Builder dscp(byte dscp) {
239 this.dscp = dscp;
240 return this;
241 }
242
Pengfei Lue0c02e22015-07-07 15:41:31 +0800243 /**
244 * Sets the destination transport layer port for the ACL rule that will be built.
245 *
246 * @param dstTpPort destination transport layer port to use for built ACL rule
247 * @return this builder
248 */
249 public Builder dstTpPort(short dstTpPort) {
250 if ((ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP)) {
251 this.dstTpPort = dstTpPort;
252 }
253 return this;
254 }
255
256 /**
Nitin Anandfb22901d2018-05-09 12:16:36 +0530257 * Sets the source transport layer port for the ACL rule that will be built.
258 *
259 * @param srcTpPort destination transport layer port to use for built ACL rule
260 * @return this builder
261 */
262 public Builder srcTpPort(short srcTpPort) {
263 if ((ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP)) {
264 this.srcTpPort = srcTpPort;
265 }
266 return this;
267 }
268
269 /**
Pengfei Lue0c02e22015-07-07 15:41:31 +0800270 * Sets the action for the ACL rule that will be built.
271 *
272 * @param action action to use for built ACL rule
273 * @return this builder
274 */
275 public Builder action(Action action) {
276 this.action = action;
277 return this;
278 }
279
280 /**
281 * Builds an ACL rule from the accumulated parameters.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700282 *
Pengfei Lue0c02e22015-07-07 15:41:31 +0800283 * @return ACL rule instance
284 */
285 public AclRule build() {
286 checkState(srcIp != null && dstIp != null, "Either srcIp or dstIp must be assigned.");
287 checkState(ipProto == 0 || ipProto == IPv4.PROTOCOL_ICMP
288 || ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP,
289 "ipProto must be assigned to TCP, UDP, or ICMP.");
Nitin Anandfb22901d2018-05-09 12:16:36 +0530290 return new AclRule(srcMac, dstMac, srcIp, dstIp, ipProto, dscp, dstTpPort, srcTpPort, action);
Pengfei Lue0c02e22015-07-07 15:41:31 +0800291 }
292
293 }
294
295 /**
296 * Binds an id generator for unique ACL rule id generation.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700297 * <p>
Pengfei Lue0c02e22015-07-07 15:41:31 +0800298 * Note: A generator cannot be bound if there is already a generator bound.
299 *
300 * @param newIdGenerator id generator
301 */
302 public static void bindIdGenerator(IdGenerator newIdGenerator) {
Ray Milkey074ba9b2018-02-06 10:23:41 -0800303 synchronized (ID_GENERATOR_LOCK) {
304 checkState(idGenerator == null, "Id generator is already bound.");
305 idGenerator = checkNotNull(newIdGenerator);
306 }
Pengfei Lue0c02e22015-07-07 15:41:31 +0800307 }
308
309 public RuleId id() {
310 return id;
311 }
312
Nitin Anandfb22901d2018-05-09 12:16:36 +0530313 public MacAddress srcMac() {
314 return srcMac;
315 }
316
317 public MacAddress dstMac() {
318 return dstMac;
319 }
320
Pengfei Lue0c02e22015-07-07 15:41:31 +0800321 public Ip4Prefix srcIp() {
322 return srcIp;
323 }
324
325 public Ip4Prefix dstIp() {
326 return this.dstIp;
327 }
328
329 public byte ipProto() {
330 return ipProto;
331 }
332
Nitin Anandfb22901d2018-05-09 12:16:36 +0530333 public byte dscp() {
334 return dscp;
335 }
336
Pengfei Lue0c02e22015-07-07 15:41:31 +0800337 public short dstTpPort() {
338 return dstTpPort;
339 }
340
Nitin Anandfb22901d2018-05-09 12:16:36 +0530341 public short srcTpPort() {
342 return srcTpPort;
343 }
344
Pengfei Lue0c02e22015-07-07 15:41:31 +0800345 public Action action() {
346 return action;
347 }
348
349 @Override
350 public int hashCode() {
Nitin Anandfb22901d2018-05-09 12:16:36 +0530351 return Objects.hash(action, id.fingerprint(), srcMac, dstMac, ipProto, dscp,
352 srcIp, dstIp, dstTpPort, srcTpPort);
Pengfei Lue0c02e22015-07-07 15:41:31 +0800353 }
354
355 @Override
356 public boolean equals(Object obj) {
357 if (this == obj) {
358 return true;
359 }
360 if (obj instanceof AclRule) {
361 AclRule that = (AclRule) obj;
362 return Objects.equals(id, that.id) &&
Nitin Anandfb22901d2018-05-09 12:16:36 +0530363 Objects.equals(srcMac, that.srcMac) &&
364 Objects.equals(dstMac, that.dstMac) &&
Pengfei Lue0c02e22015-07-07 15:41:31 +0800365 Objects.equals(srcIp, that.srcIp) &&
366 Objects.equals(dstIp, that.dstIp) &&
367 Objects.equals(ipProto, that.ipProto) &&
Nitin Anandfb22901d2018-05-09 12:16:36 +0530368 Objects.equals(dscp, that.dscp) &&
Pengfei Lue0c02e22015-07-07 15:41:31 +0800369 Objects.equals(dstTpPort, that.dstTpPort) &&
Nitin Anandfb22901d2018-05-09 12:16:36 +0530370 Objects.equals(srcTpPort, that.srcTpPort) &&
Pengfei Lue0c02e22015-07-07 15:41:31 +0800371 Objects.equals(action, that.action);
372 }
373 return false;
374 }
375
376 @Override
377 public String toString() {
378 return MoreObjects.toStringHelper(this)
379 .omitNullValues()
380 .add("id", id)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530381 .add("srcMac", srcMac)
382 .add("dstMac", dstMac)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800383 .add("srcIp", srcIp)
384 .add("dstIp", dstIp)
385 .add("ipProto", ipProto)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530386 .add("dscp", dscp)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800387 .add("dstTpPort", dstTpPort)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530388 .add("srcTpPort", srcTpPort)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800389 .add("action", action)
390 .toString();
391 }
392
393}