blob: 02b7025245326545458b91d736a63c34af89ac8e [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;
26import org.onosproject.core.IdGenerator;
27
28import java.util.Objects;
29
30import static com.google.common.base.Preconditions.checkNotNull;
31import static com.google.common.base.Preconditions.checkState;
32
33/**
34 * ACL rule class.
35 */
36public final class AclRule {
37
38 private final RuleId id;
39
40 private final Ip4Prefix srcIp;
41 private final Ip4Prefix dstIp;
42 private final byte ipProto;
43 private final short dstTpPort;
44 private final Action action;
45
Ray Milkey06297ed2018-01-22 17:13:41 -080046 protected static IdGenerator idGenerator;
Ray Milkey074ba9b2018-02-06 10:23:41 -080047 private static final Object ID_GENERATOR_LOCK = new Object();
Pengfei Lue0c02e22015-07-07 15:41:31 +080048
49 /**
50 * Enum type for ACL rule's action.
51 */
52 public enum Action {
53 DENY, ALLOW
54 }
55
56 /**
57 * Constructor for serializer.
58 */
59 private AclRule() {
60 this.id = null;
61 this.srcIp = null;
62 this.dstIp = null;
63 this.ipProto = 0;
64 this.dstTpPort = 0;
65 this.action = null;
66 }
67
68 /**
69 * Create a new ACL rule.
70 *
Thomas Vachuska9bb32352015-09-25 11:31:22 -070071 * @param srcIp source IP address
72 * @param dstIp destination IP address
73 * @param ipProto IP protocol
Pengfei Lue0c02e22015-07-07 15:41:31 +080074 * @param dstTpPort destination transport layer port
Thomas Vachuska9bb32352015-09-25 11:31:22 -070075 * @param action ACL rule's action
Pengfei Lue0c02e22015-07-07 15:41:31 +080076 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -070077 private AclRule(Ip4Prefix srcIp, Ip4Prefix dstIp, byte ipProto,
78 short dstTpPort, Action action) {
Ray Milkey074ba9b2018-02-06 10:23:41 -080079 synchronized (ID_GENERATOR_LOCK) {
80 checkState(idGenerator != null, "Id generator is not bound.");
81 this.id = RuleId.valueOf(idGenerator.getNewId());
82 }
Pengfei Lue0c02e22015-07-07 15:41:31 +080083 this.srcIp = srcIp;
84 this.dstIp = dstIp;
85 this.ipProto = ipProto;
86 this.dstTpPort = dstTpPort;
87 this.action = action;
88 }
89
90 /**
91 * Check if the first CIDR address is in (or the same as) the second CIDR address.
92 */
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080093 private boolean checkCidrInCidr(Ip4Prefix cidrAddr1, Ip4Prefix cidrAddr2) {
Pengfei Lue0c02e22015-07-07 15:41:31 +080094 if (cidrAddr2 == null) {
95 return true;
96 } else if (cidrAddr1 == null) {
97 return false;
98 }
99 if (cidrAddr1.prefixLength() < cidrAddr2.prefixLength()) {
100 return false;
101 }
102 int offset = 32 - cidrAddr2.prefixLength();
103
104 int cidr1Prefix = cidrAddr1.address().toInt();
105 int cidr2Prefix = cidrAddr2.address().toInt();
106 cidr1Prefix = cidr1Prefix >> offset;
107 cidr2Prefix = cidr2Prefix >> offset;
108 cidr1Prefix = cidr1Prefix << offset;
109 cidr2Prefix = cidr2Prefix << offset;
110
111 return (cidr1Prefix == cidr2Prefix);
112 }
113
114 /**
115 * Check if this ACL rule match the given ACL rule.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700116 *
Pengfei Lue0c02e22015-07-07 15:41:31 +0800117 * @param r ACL rule to check against
118 * @return true if this ACL rule matches the given ACL ruleule.
119 */
120 public boolean checkMatch(AclRule r) {
121 return (this.dstTpPort == r.dstTpPort || r.dstTpPort == 0)
122 && (this.ipProto == r.ipProto || r.ipProto == 0)
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800123 && (checkCidrInCidr(this.srcIp(), r.srcIp()))
124 && (checkCidrInCidr(this.dstIp(), r.dstIp()));
Pengfei Lue0c02e22015-07-07 15:41:31 +0800125 }
126
127 /**
128 * Returns a new ACL rule builder.
129 *
130 * @return ACL rule builder
131 */
132 public static Builder builder() {
133 return new Builder();
134 }
135
136 /**
137 * Builder of an ACL rule.
138 */
139 public static final class Builder {
140
141 private Ip4Prefix srcIp = null;
142 private Ip4Prefix dstIp = null;
143 private byte ipProto = 0;
144 private short dstTpPort = 0;
145 private Action action = Action.DENY;
146
147 private Builder() {
148 // Hide constructor
149 }
150
151 /**
152 * Sets the source IP address for the ACL rule that will be built.
153 *
154 * @param srcIp source IP address to use for built ACL rule
155 * @return this builder
156 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700157 public Builder srcIp(Ip4Prefix srcIp) {
158 this.srcIp = srcIp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800159 return this;
160 }
161
162 /**
163 * Sets the destination IP address for the ACL rule that will be built.
164 *
165 * @param dstIp destination IP address to use for built ACL rule
166 * @return this builder
167 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700168 public Builder dstIp(Ip4Prefix dstIp) {
169 this.dstIp = dstIp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800170 return this;
171 }
172
173 /**
174 * Sets the IP protocol for the ACL rule that will be built.
175 *
176 * @param ipProto IP protocol to use for built ACL rule
177 * @return this builder
178 */
179 public Builder ipProto(byte ipProto) {
180 this.ipProto = ipProto;
181 return this;
182 }
183
184 /**
185 * Sets the destination transport layer port for the ACL rule that will be built.
186 *
187 * @param dstTpPort destination transport layer port to use for built ACL rule
188 * @return this builder
189 */
190 public Builder dstTpPort(short dstTpPort) {
191 if ((ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP)) {
192 this.dstTpPort = dstTpPort;
193 }
194 return this;
195 }
196
197 /**
198 * Sets the action for the ACL rule that will be built.
199 *
200 * @param action action to use for built ACL rule
201 * @return this builder
202 */
203 public Builder action(Action action) {
204 this.action = action;
205 return this;
206 }
207
208 /**
209 * Builds an ACL rule from the accumulated parameters.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700210 *
Pengfei Lue0c02e22015-07-07 15:41:31 +0800211 * @return ACL rule instance
212 */
213 public AclRule build() {
214 checkState(srcIp != null && dstIp != null, "Either srcIp or dstIp must be assigned.");
215 checkState(ipProto == 0 || ipProto == IPv4.PROTOCOL_ICMP
216 || ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP,
217 "ipProto must be assigned to TCP, UDP, or ICMP.");
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700218 return new AclRule(srcIp, dstIp, ipProto, dstTpPort, action);
Pengfei Lue0c02e22015-07-07 15:41:31 +0800219 }
220
221 }
222
223 /**
224 * Binds an id generator for unique ACL rule id generation.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700225 * <p>
Pengfei Lue0c02e22015-07-07 15:41:31 +0800226 * Note: A generator cannot be bound if there is already a generator bound.
227 *
228 * @param newIdGenerator id generator
229 */
230 public static void bindIdGenerator(IdGenerator newIdGenerator) {
Ray Milkey074ba9b2018-02-06 10:23:41 -0800231 synchronized (ID_GENERATOR_LOCK) {
232 checkState(idGenerator == null, "Id generator is already bound.");
233 idGenerator = checkNotNull(newIdGenerator);
234 }
Pengfei Lue0c02e22015-07-07 15:41:31 +0800235 }
236
237 public RuleId id() {
238 return id;
239 }
240
241 public Ip4Prefix srcIp() {
242 return srcIp;
243 }
244
245 public Ip4Prefix dstIp() {
246 return this.dstIp;
247 }
248
249 public byte ipProto() {
250 return ipProto;
251 }
252
253 public short dstTpPort() {
254 return dstTpPort;
255 }
256
257 public Action action() {
258 return action;
259 }
260
261 @Override
262 public int hashCode() {
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700263 return Objects.hash(action, id.fingerprint(), ipProto, srcIp, dstIp, dstTpPort);
Pengfei Lue0c02e22015-07-07 15:41:31 +0800264 }
265
266 @Override
267 public boolean equals(Object obj) {
268 if (this == obj) {
269 return true;
270 }
271 if (obj instanceof AclRule) {
272 AclRule that = (AclRule) obj;
273 return Objects.equals(id, that.id) &&
274 Objects.equals(srcIp, that.srcIp) &&
275 Objects.equals(dstIp, that.dstIp) &&
276 Objects.equals(ipProto, that.ipProto) &&
277 Objects.equals(dstTpPort, that.dstTpPort) &&
278 Objects.equals(action, that.action);
279 }
280 return false;
281 }
282
283 @Override
284 public String toString() {
285 return MoreObjects.toStringHelper(this)
286 .omitNullValues()
287 .add("id", id)
288 .add("srcIp", srcIp)
289 .add("dstIp", dstIp)
290 .add("ipProto", ipProto)
291 .add("dstTpPort", dstTpPort)
292 .add("action", action)
293 .toString();
294 }
295
296}