blob: a5cc29709648c637b63d4d61836eb12446f3fc40 [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
46 private static IdGenerator idGenerator;
47
48 /**
49 * Enum type for ACL rule's action.
50 */
51 public enum Action {
52 DENY, ALLOW
53 }
54
55 /**
56 * Constructor for serializer.
57 */
58 private AclRule() {
59 this.id = null;
60 this.srcIp = null;
61 this.dstIp = null;
62 this.ipProto = 0;
63 this.dstTpPort = 0;
64 this.action = null;
65 }
66
67 /**
68 * Create a new ACL rule.
69 *
Thomas Vachuska9bb32352015-09-25 11:31:22 -070070 * @param srcIp source IP address
71 * @param dstIp destination IP address
72 * @param ipProto IP protocol
Pengfei Lue0c02e22015-07-07 15:41:31 +080073 * @param dstTpPort destination transport layer port
Thomas Vachuska9bb32352015-09-25 11:31:22 -070074 * @param action ACL rule's action
Pengfei Lue0c02e22015-07-07 15:41:31 +080075 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -070076 private AclRule(Ip4Prefix srcIp, Ip4Prefix dstIp, byte ipProto,
77 short dstTpPort, Action action) {
Pengfei Lue0c02e22015-07-07 15:41:31 +080078 checkState(idGenerator != null, "Id generator is not bound.");
79 this.id = RuleId.valueOf(idGenerator.getNewId());
80 this.srcIp = srcIp;
81 this.dstIp = dstIp;
82 this.ipProto = ipProto;
83 this.dstTpPort = dstTpPort;
84 this.action = action;
85 }
86
87 /**
88 * Check if the first CIDR address is in (or the same as) the second CIDR address.
89 */
Jonathan Hartd9df7bd2015-11-10 17:10:25 -080090 private boolean checkCidrInCidr(Ip4Prefix cidrAddr1, Ip4Prefix cidrAddr2) {
Pengfei Lue0c02e22015-07-07 15:41:31 +080091 if (cidrAddr2 == null) {
92 return true;
93 } else if (cidrAddr1 == null) {
94 return false;
95 }
96 if (cidrAddr1.prefixLength() < cidrAddr2.prefixLength()) {
97 return false;
98 }
99 int offset = 32 - cidrAddr2.prefixLength();
100
101 int cidr1Prefix = cidrAddr1.address().toInt();
102 int cidr2Prefix = cidrAddr2.address().toInt();
103 cidr1Prefix = cidr1Prefix >> offset;
104 cidr2Prefix = cidr2Prefix >> offset;
105 cidr1Prefix = cidr1Prefix << offset;
106 cidr2Prefix = cidr2Prefix << offset;
107
108 return (cidr1Prefix == cidr2Prefix);
109 }
110
111 /**
112 * Check if this ACL rule match the given ACL rule.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700113 *
Pengfei Lue0c02e22015-07-07 15:41:31 +0800114 * @param r ACL rule to check against
115 * @return true if this ACL rule matches the given ACL ruleule.
116 */
117 public boolean checkMatch(AclRule r) {
118 return (this.dstTpPort == r.dstTpPort || r.dstTpPort == 0)
119 && (this.ipProto == r.ipProto || r.ipProto == 0)
Jonathan Hartd9df7bd2015-11-10 17:10:25 -0800120 && (checkCidrInCidr(this.srcIp(), r.srcIp()))
121 && (checkCidrInCidr(this.dstIp(), r.dstIp()));
Pengfei Lue0c02e22015-07-07 15:41:31 +0800122 }
123
124 /**
125 * Returns a new ACL rule builder.
126 *
127 * @return ACL rule builder
128 */
129 public static Builder builder() {
130 return new Builder();
131 }
132
133 /**
134 * Builder of an ACL rule.
135 */
136 public static final class Builder {
137
138 private Ip4Prefix srcIp = null;
139 private Ip4Prefix dstIp = null;
140 private byte ipProto = 0;
141 private short dstTpPort = 0;
142 private Action action = Action.DENY;
143
144 private Builder() {
145 // Hide constructor
146 }
147
148 /**
149 * Sets the source IP address for the ACL rule that will be built.
150 *
151 * @param srcIp source IP address to use for built ACL rule
152 * @return this builder
153 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700154 public Builder srcIp(Ip4Prefix srcIp) {
155 this.srcIp = srcIp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800156 return this;
157 }
158
159 /**
160 * Sets the destination IP address for the ACL rule that will be built.
161 *
162 * @param dstIp destination IP address to use for built ACL rule
163 * @return this builder
164 */
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700165 public Builder dstIp(Ip4Prefix dstIp) {
166 this.dstIp = dstIp;
Pengfei Lue0c02e22015-07-07 15:41:31 +0800167 return this;
168 }
169
170 /**
171 * Sets the IP protocol for the ACL rule that will be built.
172 *
173 * @param ipProto IP protocol to use for built ACL rule
174 * @return this builder
175 */
176 public Builder ipProto(byte ipProto) {
177 this.ipProto = ipProto;
178 return this;
179 }
180
181 /**
182 * Sets the destination transport layer port for the ACL rule that will be built.
183 *
184 * @param dstTpPort destination transport layer port to use for built ACL rule
185 * @return this builder
186 */
187 public Builder dstTpPort(short dstTpPort) {
188 if ((ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP)) {
189 this.dstTpPort = dstTpPort;
190 }
191 return this;
192 }
193
194 /**
195 * Sets the action for the ACL rule that will be built.
196 *
197 * @param action action to use for built ACL rule
198 * @return this builder
199 */
200 public Builder action(Action action) {
201 this.action = action;
202 return this;
203 }
204
205 /**
206 * Builds an ACL rule from the accumulated parameters.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700207 *
Pengfei Lue0c02e22015-07-07 15:41:31 +0800208 * @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.");
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700215 return new AclRule(srcIp, dstIp, ipProto, dstTpPort, action);
Pengfei Lue0c02e22015-07-07 15:41:31 +0800216 }
217
218 }
219
220 /**
221 * Binds an id generator for unique ACL rule id generation.
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700222 * <p>
Pengfei Lue0c02e22015-07-07 15:41:31 +0800223 * Note: A generator cannot be bound if there is already a generator bound.
224 *
225 * @param newIdGenerator id generator
226 */
227 public static void bindIdGenerator(IdGenerator newIdGenerator) {
228 checkState(idGenerator == null, "Id generator is already bound.");
229 idGenerator = checkNotNull(newIdGenerator);
230 }
231
232 public RuleId id() {
233 return id;
234 }
235
236 public Ip4Prefix srcIp() {
237 return srcIp;
238 }
239
240 public Ip4Prefix dstIp() {
241 return this.dstIp;
242 }
243
244 public byte ipProto() {
245 return ipProto;
246 }
247
248 public short dstTpPort() {
249 return dstTpPort;
250 }
251
252 public Action action() {
253 return action;
254 }
255
256 @Override
257 public int hashCode() {
Thomas Vachuska9bb32352015-09-25 11:31:22 -0700258 return Objects.hash(action, id.fingerprint(), ipProto, srcIp, dstIp, dstTpPort);
Pengfei Lue0c02e22015-07-07 15:41:31 +0800259 }
260
261 @Override
262 public boolean equals(Object obj) {
263 if (this == obj) {
264 return true;
265 }
266 if (obj instanceof AclRule) {
267 AclRule that = (AclRule) obj;
268 return Objects.equals(id, that.id) &&
269 Objects.equals(srcIp, that.srcIp) &&
270 Objects.equals(dstIp, that.dstIp) &&
271 Objects.equals(ipProto, that.ipProto) &&
272 Objects.equals(dstTpPort, that.dstTpPort) &&
273 Objects.equals(action, that.action);
274 }
275 return false;
276 }
277
278 @Override
279 public String toString() {
280 return MoreObjects.toStringHelper(this)
281 .omitNullValues()
282 .add("id", id)
283 .add("srcIp", srcIp)
284 .add("dstIp", dstIp)
285 .add("ipProto", ipProto)
286 .add("dstTpPort", dstTpPort)
287 .add("action", action)
288 .toString();
289 }
290
291}