blob: 273c3d12fec58861b1bddc5650e5dfd0b6129bc4 [file] [log] [blame]
Thomas Vachuska83e090e2014-10-22 14:25:35 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska83e090e2014-10-22 14:25:35 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska83e090e2014-10-22 14:25:35 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska83e090e2014-10-22 14:25:35 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.flow;
alshabib7b2748f2014-09-16 20:21:11 -070017
Hyunsun Moon7bfbc1c2016-04-05 16:40:43 -070018import com.google.common.hash.Funnel;
19import com.google.common.hash.HashCode;
20import com.google.common.hash.HashFunction;
21import com.google.common.hash.Hashing;
Brian O'Connorabafb502014-12-02 22:26:20 -080022import org.onosproject.core.ApplicationId;
Brian O'Connorabafb502014-12-02 22:26:20 -080023import org.onosproject.core.GroupId;
24import org.onosproject.net.DeviceId;
alshabib7b2748f2014-09-16 20:21:11 -070025
Jonathan Hart607b1ff2015-05-05 10:55:51 -070026import java.util.Objects;
27
28import static com.google.common.base.MoreObjects.toStringHelper;
29import static com.google.common.base.Preconditions.checkArgument;
30import static com.google.common.base.Preconditions.checkNotNull;
Carmelo Cascone41605742017-06-19 15:46:44 +090031import static org.onosproject.net.flow.TableId.Type.INDEX;
Jonathan Hart607b1ff2015-05-05 10:55:51 -070032
Jonathan Hart2b3e22b2017-02-03 18:31:13 -080033/**
34 * Default flow rule.
35 */
alshabib7b2748f2014-09-16 20:21:11 -070036public class DefaultFlowRule implements FlowRule {
37
Ayaka Koshibed4e53e12014-09-18 14:24:55 -070038 private final DeviceId deviceId;
39 private final int priority;
alshabib7b2748f2014-09-16 20:21:11 -070040 private final TrafficSelector selector;
41 private final TrafficTreatment treatment;
Ayaka Koshibed4e53e12014-09-18 14:24:55 -070042 private final long created;
43
alshabib219ebaa2014-09-22 15:41:24 -070044 private final FlowId id;
Ayaka Koshibed4e53e12014-09-18 14:24:55 -070045
alshabibdb774072015-04-20 13:13:51 -070046 private final Short appId;
alshabiba68eb962014-09-24 20:34:13 -070047
alshabibba5ac482014-10-02 17:15:20 -070048 private final int timeout;
Jonathan Hartbc4a7932014-10-21 11:46:00 -070049 private final boolean permanent;
Murat Parlakisikc6759e82016-06-29 03:22:22 -070050 private final int hardTimeout;
51 private final FlowRemoveReason reason;
Sho SHIMIZU75a5bd92014-11-25 11:22:56 -080052 private final GroupId groupId;
alshabib6eb438a2014-10-01 16:39:37 -070053
Carmelo Cascone41605742017-06-19 15:46:44 +090054 private final TableId tableId;
alshabib1c319ff2014-10-04 20:29:09 -070055
Jonathan Hart2b3e22b2017-02-03 18:31:13 -080056 /**
57 * Creates a new flow rule from an existing rule.
58 *
59 * @param rule new flow rule
60 */
alshabib1c319ff2014-10-04 20:29:09 -070061 public DefaultFlowRule(FlowRule rule) {
62 this.deviceId = rule.deviceId();
63 this.priority = rule.priority();
64 this.selector = rule.selector();
65 this.treatment = rule.treatment();
66 this.appId = rule.appId();
alshabib28204e52014-11-12 18:29:45 -080067 this.groupId = rule.groupId();
alshabib1c319ff2014-10-04 20:29:09 -070068 this.id = rule.id();
69 this.timeout = rule.timeout();
Murat Parlakisikc6759e82016-06-29 03:22:22 -070070 this.hardTimeout = rule.hardTimeout();
71 this.reason = rule.reason();
Jonathan Hartbc4a7932014-10-21 11:46:00 -070072 this.permanent = rule.isPermanent();
alshabib219ebaa2014-09-22 15:41:24 -070073 this.created = System.currentTimeMillis();
Carmelo Cascone41605742017-06-19 15:46:44 +090074 this.tableId = rule.table();
alshabibdb774072015-04-20 13:13:51 -070075 }
76
77 private DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
78 TrafficTreatment treatment, Integer priority,
Murat Parlakisikc6759e82016-06-29 03:22:22 -070079 FlowId flowId, Boolean permanent, Integer timeout, Integer hardTimeout,
Carmelo Cascone41605742017-06-19 15:46:44 +090080 FlowRemoveReason reason, TableId tableId) {
alshabibdb774072015-04-20 13:13:51 -070081
82 this.deviceId = deviceId;
83 this.selector = selector;
84 this.treatment = treatment;
85 this.priority = priority;
86 this.appId = (short) (flowId.value() >>> 48);
87 this.id = flowId;
88 this.permanent = permanent;
89 this.timeout = timeout;
Murat Parlakisikc6759e82016-06-29 03:22:22 -070090 this.hardTimeout = hardTimeout;
91 this.reason = reason;
alshabibdb774072015-04-20 13:13:51 -070092 this.tableId = tableId;
93 this.created = System.currentTimeMillis();
94
95
96 //FIXME: fields below will be removed.
Yi Tsengfa394de2017-02-01 11:26:40 -080097 this.groupId = new GroupId(0);
alshabiba7f7ca82014-09-22 11:41:23 -070098 }
99
Ayaka Koshibed4e53e12014-09-18 14:24:55 -0700100 @Override
101 public FlowId id() {
102 return id;
alshabib7b2748f2014-09-16 20:21:11 -0700103 }
104
105 @Override
alshabib92c65ad2014-10-08 21:56:05 -0700106 public short appId() {
alshabiba68eb962014-09-24 20:34:13 -0700107 return appId;
108 }
109
110 @Override
Sho SHIMIZU75a5bd92014-11-25 11:22:56 -0800111 public GroupId groupId() {
alshabib28204e52014-11-12 18:29:45 -0800112 return groupId;
113 }
114
115 @Override
alshabib7b2748f2014-09-16 20:21:11 -0700116 public int priority() {
Ayaka Koshibed4e53e12014-09-18 14:24:55 -0700117 return priority;
alshabib7b2748f2014-09-16 20:21:11 -0700118 }
119
120 @Override
121 public DeviceId deviceId() {
122 return deviceId;
123 }
124
125 @Override
126 public TrafficSelector selector() {
127 return selector;
128 }
129
130 @Override
131 public TrafficTreatment treatment() {
132 return treatment;
133 }
134
Ayaka Koshibed4e53e12014-09-18 14:24:55 -0700135 /*
136 * The priority and statistics can change on a given treatment and selector
137 *
138 * (non-Javadoc)
jcc3d4e14a2015-04-21 11:32:05 +0800139 *
Ayaka Koshibed4e53e12014-09-18 14:24:55 -0700140 * @see java.lang.Object#equals(java.lang.Object)
141 */
Jonathan Hart2b3e22b2017-02-03 18:31:13 -0800142 @Override
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700143 public int hashCode() {
Ray Milkey47f09c52019-02-08 18:51:34 -0800144 return Objects.hash(deviceId, selector, tableId);
alshabiba68eb962014-09-24 20:34:13 -0700145 }
146
Thomas Vachuska711db552015-06-02 16:35:26 -0700147 //FIXME do we need this method in addition to hashCode()?
148 private int hash() {
Ray Milkey47f09c52019-02-08 18:51:34 -0800149 return Objects.hash(deviceId, selector, tableId);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700150 }
151
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700152 /*
153 * The priority and statistics can change on a given treatment and selector
154 *
155 * (non-Javadoc)
jcc3d4e14a2015-04-21 11:32:05 +0800156 *
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700157 * @see java.lang.Object#equals(java.lang.Object)
158 */
Jonathan Hart2b3e22b2017-02-03 18:31:13 -0800159 @Override
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700160 public boolean equals(Object obj) {
alshabiba7f7ca82014-09-22 11:41:23 -0700161 if (this == obj) {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700162 return true;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700163 }
alshabib54ce5892014-09-23 17:50:51 -0700164 if (obj instanceof DefaultFlowRule) {
alshabib219ebaa2014-09-22 15:41:24 -0700165 DefaultFlowRule that = (DefaultFlowRule) obj;
166 return Objects.equals(deviceId, that.deviceId) &&
alshabibba5ac482014-10-02 17:15:20 -0700167 Objects.equals(priority, that.priority) &&
Saurav Dascbe6de32015-03-01 18:30:46 -0800168 Objects.equals(selector, that.selector) &&
Ray Milkey47f09c52019-02-08 18:51:34 -0800169 Objects.equals(tableId, that.tableId);
alshabiba7f7ca82014-09-22 11:41:23 -0700170 }
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700171 return false;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700172 }
173
Ayaka Koshibed4e53e12014-09-18 14:24:55 -0700174 @Override
Jonathan Hartf44e42c2015-08-04 09:58:46 -0700175 public boolean exactMatch(FlowRule rule) {
176 return this.equals(rule) &&
177 Objects.equals(this.id, rule.id()) &&
178 Objects.equals(this.treatment, rule.treatment());
179 }
180
181 @Override
Ayaka Koshibed4e53e12014-09-18 14:24:55 -0700182 public String toString() {
183 return toStringHelper(this)
alshabib8ca53902014-10-07 13:11:17 -0700184 .add("id", Long.toHexString(id.value()))
Ayaka Koshibed4e53e12014-09-18 14:24:55 -0700185 .add("deviceId", deviceId)
186 .add("priority", priority)
alshabibba5ac482014-10-02 17:15:20 -0700187 .add("selector", selector.criteria())
Jian Lif0325112016-03-03 17:11:25 -0800188 .add("treatment", treatment == null ? "N/A" : treatment)
alshabib08d98982015-04-21 16:25:50 -0700189 .add("tableId", tableId)
Ayaka Koshibed4e53e12014-09-18 14:24:55 -0700190 .add("created", created)
191 .toString();
192 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700193
alshabib6eb438a2014-10-01 16:39:37 -0700194 @Override
alshabibba5ac482014-10-02 17:15:20 -0700195 public int timeout() {
alshabib58747a62014-10-07 11:05:30 -0700196 return timeout;
alshabib6eb438a2014-10-01 16:39:37 -0700197 }
198
Murat Parlakisikc6759e82016-06-29 03:22:22 -0700199 @Override
200 public int hardTimeout() {
201 return hardTimeout;
202 }
203
204 @Override
205 public FlowRemoveReason reason() {
206 return reason;
207 }
208
Jonathan Hartbc4a7932014-10-21 11:46:00 -0700209 @Override
210 public boolean isPermanent() {
211 return permanent;
212 }
213
sangho11c30ac2015-01-22 14:30:55 -0800214 @Override
alshabibdb774072015-04-20 13:13:51 -0700215 public int tableId() {
Carmelo Cascone41605742017-06-19 15:46:44 +0900216 // Workaround until we remove this method. Deprecated in Loon.
217 return tableId.type() == INDEX ? ((IndexTableId) tableId).id() : tableId.hashCode();
218 }
219
220 @Override
221 public TableId table() {
alshabibdb774072015-04-20 13:13:51 -0700222 return tableId;
223 }
224
Jonathan Hart2b3e22b2017-02-03 18:31:13 -0800225 /**
226 * Returns the wallclock time that the flow was created.
227 *
228 * @return creation time in milliseconds since epoch
229 */
Brian O'Connora3e5cd52015-12-05 15:59:19 -0800230 public long created() {
231 return created;
232 }
233
Jonathan Hart2b3e22b2017-02-03 18:31:13 -0800234 /**
235 * Returns a default flow rule builder.
236 *
237 * @return builder
238 */
alshabibdb774072015-04-20 13:13:51 -0700239 public static Builder builder() {
240 return new Builder();
241 }
242
Jonathan Hart2b3e22b2017-02-03 18:31:13 -0800243 /**
244 * Default flow rule builder.
245 */
alshabibd17abc22015-04-21 18:26:35 -0700246 public static final class Builder implements FlowRule.Builder {
alshabibdb774072015-04-20 13:13:51 -0700247
248 private FlowId flowId;
Jonathan Hart65d551b2015-09-22 09:49:09 -0700249 private ApplicationId appId;
alshabibdb774072015-04-20 13:13:51 -0700250 private Integer priority;
251 private DeviceId deviceId;
Carmelo Cascone41605742017-06-19 15:46:44 +0900252 private TableId tableId = DEFAULT_TABLE;
Charles Chancc4754d2015-12-10 15:58:18 -0800253 private TrafficSelector selector = DefaultTrafficSelector.builder().build();
254 private TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
alshabibdb774072015-04-20 13:13:51 -0700255 private Integer timeout;
256 private Boolean permanent;
Murat Parlakisikc6759e82016-06-29 03:22:22 -0700257 private Integer hardTimeout = 0;
258 private FlowRemoveReason reason = FlowRemoveReason.NO_REASON;
alshabibdb774072015-04-20 13:13:51 -0700259
260 @Override
261 public FlowRule.Builder withCookie(long cookie) {
262 this.flowId = FlowId.valueOf(cookie);
263 return this;
264 }
265
266 @Override
267 public FlowRule.Builder fromApp(ApplicationId appId) {
Jonathan Hart65d551b2015-09-22 09:49:09 -0700268 this.appId = appId;
alshabibdb774072015-04-20 13:13:51 -0700269 return this;
270 }
271
272 @Override
273 public FlowRule.Builder withPriority(int priority) {
274 this.priority = priority;
275 return this;
276 }
277
278 @Override
279 public FlowRule.Builder forDevice(DeviceId deviceId) {
280 this.deviceId = deviceId;
281 return this;
282 }
283
284 @Override
285 public FlowRule.Builder forTable(int tableId) {
Carmelo Cascone41605742017-06-19 15:46:44 +0900286 this.tableId = IndexTableId.of(tableId);
287 return this;
288 }
289
290 @Override
291 public FlowRule.Builder forTable(TableId tableId) {
alshabibdb774072015-04-20 13:13:51 -0700292 this.tableId = tableId;
293 return this;
294 }
295
296 @Override
297 public FlowRule.Builder withSelector(TrafficSelector selector) {
298 this.selector = selector;
299 return this;
300 }
301
302 @Override
303 public FlowRule.Builder withTreatment(TrafficTreatment treatment) {
Jonathan Hart24e296b2016-01-12 14:47:07 -0800304 this.treatment = checkNotNull(treatment);
alshabibdb774072015-04-20 13:13:51 -0700305 return this;
306 }
307
308 @Override
309 public FlowRule.Builder makePermanent() {
310 this.timeout = 0;
311 this.permanent = true;
312 return this;
313 }
314
315 @Override
316 public FlowRule.Builder makeTemporary(int timeout) {
317 this.permanent = false;
318 this.timeout = timeout;
319 return this;
320 }
321
322 @Override
Murat Parlakisikc6759e82016-06-29 03:22:22 -0700323 public FlowRule.Builder withHardTimeout(int timeout) {
324 this.permanent = false;
325 this.hardTimeout = timeout;
326 this.timeout = timeout;
327 return this;
328 }
329
330 @Override
331 public FlowRule.Builder withReason(FlowRemoveReason reason) {
332 this.reason = reason;
333 return this;
334 }
335
336 @Override
alshabibdb774072015-04-20 13:13:51 -0700337 public FlowRule build() {
alshabibb05be2d2016-04-11 12:52:36 -0700338 FlowId localFlowId;
Carmelo Cascone41605742017-06-19 15:46:44 +0900339 checkNotNull(tableId, "Table id cannot be null");
Jian Li8bac5762016-02-09 17:23:09 -0800340 checkArgument((flowId != null) ^ (appId != null), "Either an application" +
alshabibdb774072015-04-20 13:13:51 -0700341 " id or a cookie must be supplied");
Jonathan Hart65d551b2015-09-22 09:49:09 -0700342 checkNotNull(selector, "Traffic selector cannot be null");
343 checkArgument(timeout != null || permanent != null, "Must either have " +
alshabibdb774072015-04-20 13:13:51 -0700344 "a timeout or be permanent");
Jonathan Hart65d551b2015-09-22 09:49:09 -0700345 checkNotNull(deviceId, "Must refer to a device");
346 checkNotNull(priority, "Priority cannot be null");
Saurav Das3ea46622015-04-22 14:01:34 -0700347 checkArgument(priority >= MIN_PRIORITY, "Priority cannot be less than " +
alshabibdb774072015-04-20 13:13:51 -0700348 MIN_PRIORITY);
Kavitha Alagesan14dc5132016-06-13 17:25:18 +0530349 checkArgument(priority <= MAX_PRIORITY, "Priority cannot be greater than " +
350 MAX_PRIORITY);
Jonathan Hart65d551b2015-09-22 09:49:09 -0700351 // Computing a flow ID based on appId takes precedence over setting
352 // the flow ID directly
353 if (appId != null) {
alshabibb05be2d2016-04-11 12:52:36 -0700354 localFlowId = computeFlowId(appId);
355 } else {
356 localFlowId = flowId;
Jonathan Hart65d551b2015-09-22 09:49:09 -0700357 }
358
alshabibdb774072015-04-20 13:13:51 -0700359 return new DefaultFlowRule(deviceId, selector, treatment, priority,
Murat Parlakisikc6759e82016-06-29 03:22:22 -0700360 localFlowId, permanent, timeout, hardTimeout, reason, tableId);
alshabibdb774072015-04-20 13:13:51 -0700361 }
362
363 private FlowId computeFlowId(ApplicationId appId) {
364 return FlowId.valueOf((((long) appId.id()) << 48)
365 | (hash() & 0xffffffffL));
366 }
367
368 private int hash() {
Jordan Halterman485da342017-05-31 14:13:53 -0700369 // Guava documentation recommends using putUnencodedChars to hash raw character bytes within any encoding
370 // unless cross-language compatibility is needed. See the Hasher.putString documentation for more info.
Hyunsun Moon7bfbc1c2016-04-05 16:40:43 -0700371 Funnel<TrafficSelector> selectorFunnel = (from, into) -> from.criteria()
Jordan Halterman485da342017-05-31 14:13:53 -0700372 .forEach(c -> into.putUnencodedChars(c.toString()));
alshabibdb774072015-04-20 13:13:51 -0700373
Hyunsun Moon7bfbc1c2016-04-05 16:40:43 -0700374 HashFunction hashFunction = Hashing.murmur3_32();
375 HashCode hashCode = hashFunction.newHasher()
Jordan Halterman485da342017-05-31 14:13:53 -0700376 .putUnencodedChars(deviceId.toString())
Hyunsun Moon7bfbc1c2016-04-05 16:40:43 -0700377 .putObject(selector, selectorFunnel)
378 .putInt(priority)
Carmelo Cascone41605742017-06-19 15:46:44 +0900379 .putUnencodedChars(tableId.toString())
Hyunsun Moon7bfbc1c2016-04-05 16:40:43 -0700380 .hash();
381
382 return hashCode.asInt();
383 }
alshabibdb774072015-04-20 13:13:51 -0700384 }
alshabib7b2748f2014-09-16 20:21:11 -0700385}