blob: 2130ab9d1ccb72c96dbc60c7437a88ee27ef0e92 [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;
pankajthor1431c752018-12-05 19:15:58 +053025import org.onlab.packet.IPv6;
Pengfei Lue0c02e22015-07-07 15:41:31 +080026import org.onlab.packet.Ip4Prefix;
pankajthor1431c752018-12-05 19:15:58 +053027import org.onlab.packet.Ip6Prefix;
Nitin Anandfb22901d2018-05-09 12:16:36 +053028import org.onlab.packet.MacAddress;
Pengfei Lue0c02e22015-07-07 15:41:31 +080029import org.onosproject.core.IdGenerator;
30
31import java.util.Objects;
32
33import static com.google.common.base.Preconditions.checkNotNull;
34import static com.google.common.base.Preconditions.checkState;
35
36/**
37 * ACL rule class.
38 */
39public final class AclRule {
40
41 private final RuleId id;
42
Nitin Anandfb22901d2018-05-09 12:16:36 +053043 private final MacAddress srcMac;
44 private final MacAddress dstMac;
Pengfei Lue0c02e22015-07-07 15:41:31 +080045 private final Ip4Prefix srcIp;
46 private final Ip4Prefix dstIp;
pankajthor1431c752018-12-05 19:15:58 +053047 private final Ip6Prefix srcIp6;
48 private final Ip6Prefix dstIp6;
Pengfei Lue0c02e22015-07-07 15:41:31 +080049 private final byte ipProto;
Nitin Anandfb22901d2018-05-09 12:16:36 +053050 private final short srcTpPort;
Pengfei Lue0c02e22015-07-07 15:41:31 +080051 private final short dstTpPort;
Nitin Anandfb22901d2018-05-09 12:16:36 +053052 private final byte dscp;
Pengfei Lue0c02e22015-07-07 15:41:31 +080053 private final Action action;
54
Ray Milkey06297ed2018-01-22 17:13:41 -080055 protected static IdGenerator idGenerator;
Ray Milkey074ba9b2018-02-06 10:23:41 -080056 private static final Object ID_GENERATOR_LOCK = new Object();
Pengfei Lue0c02e22015-07-07 15:41:31 +080057
58 /**
59 * Enum type for ACL rule's action.
60 */
61 public enum Action {
62 DENY, ALLOW
63 }
64
65 /**
66 * Constructor for serializer.
67 */
68 private AclRule() {
69 this.id = null;
Nitin Anandfb22901d2018-05-09 12:16:36 +053070 this.srcMac = null;
71 this.dstMac = null;
Pengfei Lue0c02e22015-07-07 15:41:31 +080072 this.srcIp = null;
73 this.dstIp = null;
pankajthor1431c752018-12-05 19:15:58 +053074 this.srcIp6 = null;
75 this.dstIp6 = null;
Nitin Anandfb22901d2018-05-09 12:16:36 +053076 this.dscp = 0;
Pengfei Lue0c02e22015-07-07 15:41:31 +080077 this.ipProto = 0;
78 this.dstTpPort = 0;
Nitin Anandfb22901d2018-05-09 12:16:36 +053079 this.srcTpPort = 0;
Pengfei Lue0c02e22015-07-07 15:41:31 +080080 this.action = null;
81 }
82
83 /**
84 * Create a new ACL rule.
85 *
Thomas Vachuska9bb32352015-09-25 11:31:22 -070086 * @param srcIp source IP address
Nitin Anandfb22901d2018-05-09 12:16:36 +053087 * @param srcMac source Mac address
88 * @param dstMac destination Mac address
Thomas Vachuska9bb32352015-09-25 11:31:22 -070089 * @param dstIp destination IP address
90 * @param ipProto IP protocol
Nitin Anandfb22901d2018-05-09 12:16:36 +053091 * @param dscp IP dscp
Pengfei Lue0c02e22015-07-07 15:41:31 +080092 * @param dstTpPort destination transport layer port
Nitin Anandfb22901d2018-05-09 12:16:36 +053093 * @param srcTpPort source transport layer port
Thomas Vachuska9bb32352015-09-25 11:31:22 -070094 * @param action ACL rule's action
Pengfei Lue0c02e22015-07-07 15:41:31 +080095 */
pankajthor1431c752018-12-05 19:15:58 +053096 private AclRule(MacAddress srcMac, MacAddress dstMac, Ip4Prefix srcIp, Ip4Prefix dstIp,
97 Ip6Prefix srcIp6, Ip6Prefix dstIp6, byte ipProto, byte dscp,
98 short dstTpPort, short srcTpPort, Action action) {
Ray Milkey074ba9b2018-02-06 10:23:41 -080099 synchronized (ID_GENERATOR_LOCK) {
100 checkState(idGenerator != null, "Id generator is not bound.");
101 this.id = RuleId.valueOf(idGenerator.getNewId());
102 }
Nitin Anandfb22901d2018-05-09 12:16:36 +0530103 this.srcMac = srcMac;
104 this.dstMac = dstMac;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800105 this.srcIp = srcIp;
106 this.dstIp = dstIp;
pankajthor1431c752018-12-05 19:15:58 +0530107 this.srcIp6 = srcIp6;
108 this.dstIp6 = dstIp6;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800109 this.ipProto = ipProto;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530110 this.dscp = dscp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800111 this.dstTpPort = dstTpPort;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530112 this.srcTpPort = srcTpPort;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800113 this.action = action;
114 }
115
116 /**
117 * Check if the first CIDR address is in (or the same as) the second CIDR address.
118 */
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800119 private boolean checkCidrInCidr(Ip4Prefix cidrAddr1, Ip4Prefix cidrAddr2) {
Pengfei Lue0c02e22015-07-07 15:41:31 +0800120 if (cidrAddr2 == null) {
121 return true;
122 } else if (cidrAddr1 == null) {
123 return false;
124 }
125 if (cidrAddr1.prefixLength() < cidrAddr2.prefixLength()) {
126 return false;
127 }
128 int offset = 32 - cidrAddr2.prefixLength();
129
130 int cidr1Prefix = cidrAddr1.address().toInt();
131 int cidr2Prefix = cidrAddr2.address().toInt();
132 cidr1Prefix = cidr1Prefix >> offset;
133 cidr2Prefix = cidr2Prefix >> offset;
134 cidr1Prefix = cidr1Prefix << offset;
135 cidr2Prefix = cidr2Prefix << offset;
136
137 return (cidr1Prefix == cidr2Prefix);
138 }
139
140 /**
141 * Check if this ACL rule match the given ACL rule.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700142 *
Pengfei Lue0c02e22015-07-07 15:41:31 +0800143 * @param r ACL rule to check against
144 * @return true if this ACL rule matches the given ACL ruleule.
145 */
146 public boolean checkMatch(AclRule r) {
147 return (this.dstTpPort == r.dstTpPort || r.dstTpPort == 0)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530148 && (this.srcTpPort == r.srcTpPort || r.srcTpPort == 0)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800149 && (this.ipProto == r.ipProto || r.ipProto == 0)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530150 && (this.dscp == r.dscp || r.dscp == 0)
151 && (this.srcMac == r.srcMac || r.srcMac == null)
152 && (this.dstMac == r.dstMac || r.dstMac == null)
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800153 && (checkCidrInCidr(this.srcIp(), r.srcIp()))
154 && (checkCidrInCidr(this.dstIp(), r.dstIp()));
Pengfei Lue0c02e22015-07-07 15:41:31 +0800155 }
156
157 /**
158 * Returns a new ACL rule builder.
159 *
160 * @return ACL rule builder
161 */
162 public static Builder builder() {
163 return new Builder();
164 }
165
166 /**
167 * Builder of an ACL rule.
168 */
169 public static final class Builder {
170
171 private Ip4Prefix srcIp = null;
172 private Ip4Prefix dstIp = null;
pankajthor1431c752018-12-05 19:15:58 +0530173 private Ip6Prefix srcIp6 = null;
174 private Ip6Prefix dstIp6 = null;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530175 private MacAddress srcMac = null;
176 private MacAddress dstMac = null;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800177 private byte ipProto = 0;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530178 private byte dscp = 0;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800179 private short dstTpPort = 0;
Nitin Anandfb22901d2018-05-09 12:16:36 +0530180 private short srcTpPort = 0;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800181 private Action action = Action.DENY;
182
183 private Builder() {
184 // Hide constructor
185 }
186
187 /**
Nitin Anandfb22901d2018-05-09 12:16:36 +0530188 * Sets the source Mac address for the ACL rule that will be built.
189 *
190 * @param srcMac source Mac address to use for built ACL rule
191 * @return this builder
192 */
193 public Builder srcMac(MacAddress srcMac) {
194 this.srcMac = srcMac;
195 return this;
196 }
197
198 /**
199 * Sets the destination Mac address for the ACL rule that will be built.
200 *
201 * @param dstMac destination Mac address to use for built ACL rule
202 * @return this builder
203 */
204 public Builder dstMac(MacAddress dstMac) {
205 this.dstMac = dstMac;
206 return this;
207 }
208
209 /**
Pengfei Lue0c02e22015-07-07 15:41:31 +0800210 * Sets the source IP address for the ACL rule that will be built.
211 *
212 * @param srcIp source IP address to use for built ACL rule
213 * @return this builder
214 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700215 public Builder srcIp(Ip4Prefix srcIp) {
216 this.srcIp = srcIp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800217 return this;
218 }
219
220 /**
221 * Sets the destination IP address for the ACL rule that will be built.
222 *
223 * @param dstIp destination IP address to use for built ACL rule
224 * @return this builder
225 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700226 public Builder dstIp(Ip4Prefix dstIp) {
227 this.dstIp = dstIp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800228 return this;
229 }
230
231 /**
pankajthor1431c752018-12-05 19:15:58 +0530232 * Sets the source IP address for the ACL rule that will be built.
233 *
234 * @param srcIp6 source IP address to use for built ACL rule
235 * @return this builder
236 */
237 public Builder srcIp6(Ip6Prefix srcIp6) {
238 this.srcIp6 = srcIp6;
239 return this;
240 }
241
242 /**
243 * Sets the destination IP address for the ACL rule that will be built.
244 *
245 * @param dstIp6 destination IP address to use for built ACL rule
246 * @return this builder
247 */
248 public Builder dstIp6(Ip6Prefix dstIp6) {
249 this.dstIp6 = dstIp6;
250 return this;
251 }
252
253 /**
Pengfei Lue0c02e22015-07-07 15:41:31 +0800254 * Sets the IP protocol for the ACL rule that will be built.
255 *
256 * @param ipProto IP protocol to use for built ACL rule
257 * @return this builder
258 */
259 public Builder ipProto(byte ipProto) {
260 this.ipProto = ipProto;
261 return this;
262 }
263
Nitin Anandfb22901d2018-05-09 12:16:36 +0530264
265 /**
266 * Sets the IP dscp for the ACL rule that will be built.
267 *
268 * @param dscp IP dscp to use for built ACL rule
269 * @return this builder
270 */
271 public Builder dscp(byte dscp) {
272 this.dscp = dscp;
273 return this;
274 }
275
Pengfei Lue0c02e22015-07-07 15:41:31 +0800276 /**
277 * Sets the destination transport layer port for the ACL rule that will be built.
278 *
279 * @param dstTpPort destination transport layer port to use for built ACL rule
280 * @return this builder
281 */
282 public Builder dstTpPort(short dstTpPort) {
pankajthor1431c752018-12-05 19:15:58 +0530283 if (ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP ||
284 ipProto == IPv6.PROTOCOL_TCP || ipProto == IPv6.PROTOCOL_UDP) {
Pengfei Lue0c02e22015-07-07 15:41:31 +0800285 this.dstTpPort = dstTpPort;
286 }
287 return this;
288 }
289
290 /**
Nitin Anandfb22901d2018-05-09 12:16:36 +0530291 * Sets the source transport layer port for the ACL rule that will be built.
292 *
293 * @param srcTpPort destination transport layer port to use for built ACL rule
294 * @return this builder
295 */
296 public Builder srcTpPort(short srcTpPort) {
pankajthor1431c752018-12-05 19:15:58 +0530297 if (ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP ||
298 ipProto == IPv6.PROTOCOL_TCP || ipProto == IPv6.PROTOCOL_UDP) {
Nitin Anandfb22901d2018-05-09 12:16:36 +0530299 this.srcTpPort = srcTpPort;
300 }
301 return this;
302 }
303
304 /**
Pengfei Lue0c02e22015-07-07 15:41:31 +0800305 * Sets the action for the ACL rule that will be built.
306 *
307 * @param action action to use for built ACL rule
308 * @return this builder
309 */
310 public Builder action(Action action) {
311 this.action = action;
312 return this;
313 }
314
315 /**
316 * Builds an ACL rule from the accumulated parameters.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700317 *
Pengfei Lue0c02e22015-07-07 15:41:31 +0800318 * @return ACL rule instance
319 */
320 public AclRule build() {
pankajthor1431c752018-12-05 19:15:58 +0530321 boolean assigned = true, notAssigned = false;
322 checkState(!((srcIp != null || dstIp != null) && (srcIp6 != null || dstIp6 != null)),
323 "Either Ipv4 or Ipv6 must be assigned.");
324 checkState((srcIp != null || dstIp != null) ?
325 assigned : (srcIp6 != null || dstIp6 != null) ? assigned : notAssigned,
326 "Either srcIp or dstIp must be assigned.");
327 checkState(ipProto == 0 || ipProto == IPv4.PROTOCOL_ICMP || ipProto == IPv4.PROTOCOL_TCP ||
328 ipProto == IPv4.PROTOCOL_UDP || ipProto == IPv6.PROTOCOL_ICMP6 ||
329 ipProto == IPv6.PROTOCOL_TCP || ipProto == IPv6.PROTOCOL_UDP,
Pengfei Lue0c02e22015-07-07 15:41:31 +0800330 "ipProto must be assigned to TCP, UDP, or ICMP.");
pankajthor1431c752018-12-05 19:15:58 +0530331 return new AclRule(srcMac, dstMac, srcIp, dstIp, srcIp6, dstIp6,
332 ipProto, dscp, dstTpPort, srcTpPort, action);
Pengfei Lue0c02e22015-07-07 15:41:31 +0800333 }
Pengfei Lue0c02e22015-07-07 15:41:31 +0800334 }
Pengfei Lue0c02e22015-07-07 15:41:31 +0800335 /**
336 * Binds an id generator for unique ACL rule id generation.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700337 * <p>
Pengfei Lue0c02e22015-07-07 15:41:31 +0800338 * Note: A generator cannot be bound if there is already a generator bound.
339 *
340 * @param newIdGenerator id generator
341 */
342 public static void bindIdGenerator(IdGenerator newIdGenerator) {
Ray Milkey074ba9b2018-02-06 10:23:41 -0800343 synchronized (ID_GENERATOR_LOCK) {
344 checkState(idGenerator == null, "Id generator is already bound.");
345 idGenerator = checkNotNull(newIdGenerator);
346 }
Pengfei Lue0c02e22015-07-07 15:41:31 +0800347 }
348
349 public RuleId id() {
350 return id;
351 }
352
Nitin Anandfb22901d2018-05-09 12:16:36 +0530353 public MacAddress srcMac() {
354 return srcMac;
355 }
356
357 public MacAddress dstMac() {
358 return dstMac;
359 }
360
Pengfei Lue0c02e22015-07-07 15:41:31 +0800361 public Ip4Prefix srcIp() {
362 return srcIp;
363 }
364
365 public Ip4Prefix dstIp() {
366 return this.dstIp;
367 }
368
pankajthor1431c752018-12-05 19:15:58 +0530369 public Ip6Prefix srcIp6() {
370 return srcIp6;
371 }
372
373 public Ip6Prefix dstIp6() {
374 return dstIp6;
375 }
Pengfei Lue0c02e22015-07-07 15:41:31 +0800376 public byte ipProto() {
377 return ipProto;
378 }
379
Nitin Anandfb22901d2018-05-09 12:16:36 +0530380 public byte dscp() {
381 return dscp;
382 }
383
Pengfei Lue0c02e22015-07-07 15:41:31 +0800384 public short dstTpPort() {
385 return dstTpPort;
386 }
387
Nitin Anandfb22901d2018-05-09 12:16:36 +0530388 public short srcTpPort() {
389 return srcTpPort;
390 }
391
Pengfei Lue0c02e22015-07-07 15:41:31 +0800392 public Action action() {
393 return action;
394 }
395
396 @Override
397 public int hashCode() {
Nitin Anandfb22901d2018-05-09 12:16:36 +0530398 return Objects.hash(action, id.fingerprint(), srcMac, dstMac, ipProto, dscp,
pankajthor1431c752018-12-05 19:15:58 +0530399 srcIp, dstIp, srcIp6, dstIp6, dstTpPort, srcTpPort);
Pengfei Lue0c02e22015-07-07 15:41:31 +0800400 }
401
402 @Override
403 public boolean equals(Object obj) {
404 if (this == obj) {
405 return true;
406 }
407 if (obj instanceof AclRule) {
408 AclRule that = (AclRule) obj;
409 return Objects.equals(id, that.id) &&
Nitin Anandfb22901d2018-05-09 12:16:36 +0530410 Objects.equals(srcMac, that.srcMac) &&
411 Objects.equals(dstMac, that.dstMac) &&
Pengfei Lue0c02e22015-07-07 15:41:31 +0800412 Objects.equals(srcIp, that.srcIp) &&
413 Objects.equals(dstIp, that.dstIp) &&
pankajthor1431c752018-12-05 19:15:58 +0530414 Objects.equals(srcIp6, that.srcIp6) &&
415 Objects.equals(dstIp6, that.dstIp6) &&
Pengfei Lue0c02e22015-07-07 15:41:31 +0800416 Objects.equals(ipProto, that.ipProto) &&
Nitin Anandfb22901d2018-05-09 12:16:36 +0530417 Objects.equals(dscp, that.dscp) &&
Pengfei Lue0c02e22015-07-07 15:41:31 +0800418 Objects.equals(dstTpPort, that.dstTpPort) &&
Nitin Anandfb22901d2018-05-09 12:16:36 +0530419 Objects.equals(srcTpPort, that.srcTpPort) &&
Pengfei Lue0c02e22015-07-07 15:41:31 +0800420 Objects.equals(action, that.action);
421 }
422 return false;
423 }
424
425 @Override
426 public String toString() {
427 return MoreObjects.toStringHelper(this)
428 .omitNullValues()
429 .add("id", id)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530430 .add("srcMac", srcMac)
431 .add("dstMac", dstMac)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800432 .add("srcIp", srcIp)
433 .add("dstIp", dstIp)
pankajthor1431c752018-12-05 19:15:58 +0530434 .add("srcIp6", srcIp6)
435 .add("dstIp6", dstIp6)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800436 .add("ipProto", ipProto)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530437 .add("dscp", dscp)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800438 .add("dstTpPort", dstTpPort)
Nitin Anandfb22901d2018-05-09 12:16:36 +0530439 .add("srcTpPort", srcTpPort)
Pengfei Lue0c02e22015-07-07 15:41:31 +0800440 .add("action", action)
441 .toString();
442 }
443
444}