blob: 3cd7c8cd5ce087230825a0be3860665f073806ac [file] [log] [blame]
Daniele Moro5e66f982021-06-11 16:41:48 +02001/*
2 * Copyright 2021-present Open Networking Foundation
3 *
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.
15 */
16
17package org.onosproject.net.behaviour.upf;
18
19import org.onlab.packet.Ip4Address;
20import org.onlab.util.ImmutableByteSequence;
21
22import java.util.Objects;
23
24import static com.google.common.base.Preconditions.checkNotNull;
25
26/**
27 * A single Forwarding Action Rule (FAR), an entity described in the 3GPP
28 * specifications (although that does not mean that this class is 3GPP
29 * compliant). An instance of this class will be generated by a logical switch
30 * write request to the database-style FAR P4 table, and the resulting instance
31 * should contain all the information needed to reproduce that logical switch
32 * FAR in the event of a client read request. The instance should also contain
33 * sufficient information (or expose the means to retrieve such information) to
34 * generate the corresponding dataplane forwarding state that implements the FAR.
35 */
36public final class ForwardingActionRule {
37 // Match Keys
38 private final ImmutableByteSequence sessionId; // The PFCP session identifier that created this FAR
39 private final int farId; // PFCP session-local identifier for this FAR
40 // Action parameters
41 private final boolean notifyFlag; // Should this FAR notify the control plane when it sees a packet?
42 private final boolean dropFlag;
43 private final boolean bufferFlag;
44 private final GtpTunnel tunnel; // The GTP tunnel that this FAR should encapsulate packets with (if downlink)
45
46 private static final int SESSION_ID_BITWIDTH = 96;
47
48 private ForwardingActionRule(ImmutableByteSequence sessionId, Integer farId,
49 boolean notifyFlag, GtpTunnel tunnel, boolean dropFlag, boolean bufferFlag) {
50 this.sessionId = sessionId;
51 this.farId = farId;
52 this.notifyFlag = notifyFlag;
53 this.tunnel = tunnel;
54 this.dropFlag = dropFlag;
55 this.bufferFlag = bufferFlag;
56 }
57
58 /**
59 * Return a new instance of this FAR with the action parameters stripped, leaving only the match keys.
60 *
61 * @return a new FAR with only match keys
62 */
63 public ForwardingActionRule withoutActionParams() {
64 return ForwardingActionRule.builder()
65 .setFarId(farId)
66 .withSessionId(sessionId)
67 .build();
68 }
69
70 public static Builder builder() {
71 return new Builder();
72 }
73
74 /**
75 * Return a string representing the dataplane action applied by this FAR.
76 *
77 * @return a string representing the FAR action
78 */
79 public String actionString() {
80 String actionName;
81 String actionParams = "";
82 if (dropFlag) {
83 actionName = "Drop";
84 } else if (bufferFlag) {
85 actionName = "Buffer";
86 } else if (tunnel != null) {
87 actionName = "Encap";
88 actionParams = String.format("Src=%s, SPort=%d, TEID=%s, Dst=%s",
89 tunnel.src().toString(), tunnel.srcPort(), tunnel.teid().toString(), tunnel.dst().toString());
90 } else {
91 actionName = "Forward";
92 }
93 if (notifyFlag) {
94 actionName += "+NotifyCP";
95 }
96
97 return String.format("%s(%s)", actionName, actionParams);
98 }
99
100 @Override
101 public String toString() {
102 String matchKeys = String.format("ID=%d, SEID=%s", farId, sessionId.toString());
103 String actionString = actionString();
104
105 return String.format("FAR{Match(%s) -> %s}", matchKeys, actionString);
106 }
107
108 @Override
109 public boolean equals(Object obj) {
110 if (obj == this) {
111 return true;
112 }
113 if (obj == null) {
114 return false;
115 }
116 if (getClass() != obj.getClass()) {
117 return false;
118 }
119 ForwardingActionRule that = (ForwardingActionRule) obj;
120
121 // Safe comparisons between potentially null objects
122 return (this.dropFlag == that.dropFlag &&
123 this.bufferFlag == that.bufferFlag &&
124 this.notifyFlag == that.notifyFlag &&
125 this.farId == that.farId &&
126 Objects.equals(this.tunnel, that.tunnel) &&
127 Objects.equals(this.sessionId, that.sessionId));
128 }
129
130 @Override
131 public int hashCode() {
132 return Objects.hash(sessionId, farId, notifyFlag, tunnel, dropFlag, bufferFlag);
133 }
134
135 /**
136 * Get the ID of the PFCP Session that produced this FAR.
137 *
138 * @return PFCP session ID
139 */
140 public ImmutableByteSequence sessionId() {
141 return sessionId;
142 }
143
144 /**
145 * Get the PFCP session-local ID of the FAR that should apply to packets that match this PDR.
146 *
147 * @return PFCP session-local FAR ID
148 */
149 public int farId() {
150 return farId;
151 }
152
153 /**
154 * True if this FAR does not drop packets.
155 *
156 * @return true if FAR is forwards
157 */
158 public boolean forwards() {
159 return !dropFlag;
160 }
161
162 /**
163 * True if this FAR encapsulates packets in a GTP tunnel, and false otherwise.
164 *
165 * @return true is FAR encapsulates
166 */
167 public boolean encaps() {
168 return tunnel != null;
169 }
170
171 /**
172 * Returns true if this FAR drops packets, and false otherwise.
173 *
174 * @return true if this FAR drops
175 */
176 public boolean drops() {
177 return dropFlag;
178 }
179
180 /**
181 * Returns true if this FAR notifies the control plane on receiving a packet, and false otherwise.
182 *
183 * @return true if this FAR notifies the cp
184 */
185 public boolean notifies() {
186 return notifyFlag;
187 }
188
189
190 /**
191 * Returns true if this FAR buffers incoming packets, and false otherwise.
192 *
193 * @return true if this FAR buffers
194 */
195 public boolean buffers() {
196 return bufferFlag;
197 }
198
199 /**
200 * A description of the tunnel that this FAR will encapsulate packets with, if it is a downlink FAR. If the FAR
201 * is uplink, there will be no such tunnel and this method wil return null.
202 *
203 * @return A GtpTunnel instance containing a tunnel sourceIP, destIP, and GTPU TEID, or null if the FAR is uplink.
204 */
205 public GtpTunnel tunnel() {
206 return tunnel;
207 }
208
209 /**
210 * Get the source UDP port of the GTP tunnel that this FAR will encapsulate packets with.
211 *
212 * @return GTP tunnel source UDP port
213 */
214 public Short tunnelSrcPort() {
215 return tunnel != null ? tunnel.srcPort() : null;
216 }
217
218 /**
219 * Get the source IP of the GTP tunnel that this FAR will encapsulate packets with.
220 *
221 * @return GTP tunnel source IP
222 */
223 public Ip4Address tunnelSrc() {
224 if (tunnel == null) {
225 return null;
226 }
227 return tunnel.src();
228 }
229
230 /**
231 * Get the destination IP of the GTP tunnel that this FAR will encapsulate packets with.
232 *
233 * @return GTP tunnel destination IP
234 */
235 public Ip4Address tunnelDst() {
236 if (tunnel == null) {
237 return null;
238 }
239 return tunnel.dst();
240 }
241
242 /**
243 * Get the identifier of the GTP tunnel that this FAR will encapsulate packets with.
244 *
245 * @return GTP tunnel ID
246 */
247 public ImmutableByteSequence teid() {
248 if (tunnel == null) {
249 return null;
250 }
251 return tunnel.teid();
252 }
253
254 public static class Builder {
255 private ImmutableByteSequence sessionId = null;
256 private Integer farId = null;
257 private GtpTunnel tunnel = null;
258 private boolean dropFlag = false;
259 private boolean bufferFlag = false;
260 private boolean notifyCp = false;
261
262 public Builder() {
263 }
264
265 /**
266 * Set the ID of the PFCP session that created this FAR.
267 *
268 * @param sessionId PFC session ID
269 * @return This builder object
270 */
271 public Builder withSessionId(ImmutableByteSequence sessionId) {
272 this.sessionId = sessionId;
273 return this;
274 }
275
276 /**
277 * Set the ID of the PFCP session that created this FAR.
278 *
279 * @param sessionId PFC session ID
280 * @return This builder object
281 */
282 public Builder withSessionId(long sessionId) {
283 try {
284 this.sessionId = ImmutableByteSequence.copyFrom(sessionId).fit(SESSION_ID_BITWIDTH);
285 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
286 // This error is literally impossible
287 }
288 return this;
289 }
290
291 /**
292 * Set the PFCP Session-local ID of this FAR.
293 *
294 * @param farId PFCP session-local FAR ID
295 * @return This builder object
296 */
297 public Builder setFarId(int farId) {
298 this.farId = farId;
299 return this;
300 }
301
302 /**
303 * Make this FAR forward incoming packets.
304 *
305 * @param flag the flag value to set
306 * @return This builder object
307 */
308 public Builder setForwardFlag(boolean flag) {
309 this.dropFlag = !flag;
310 return this;
311 }
312
313 /**
314 * Make this FAR drop incoming packets.
315 *
316 * @param flag the flag value to set
317 * @return This builder object
318 */
319 public Builder setDropFlag(boolean flag) {
320 this.dropFlag = flag;
321 return this;
322 }
323
324 /**
325 * Make this FAR buffer incoming packets.
326 *
327 * @param flag the flag value to set
328 * @return This builder object
329 */
330 public Builder setBufferFlag(boolean flag) {
331 this.bufferFlag = flag;
332 return this;
333 }
334
335 /**
336 * Set a flag specifying if the control plane should be notified when this FAR is hit.
337 *
338 * @param notifyCp true if FAR notifies control plane
339 * @return This builder object
340 */
341 public Builder setNotifyFlag(boolean notifyCp) {
342 this.notifyCp = notifyCp;
343 return this;
344 }
345
346 /**
347 * Set the GTP tunnel that this FAR should encapsulate packets with.
348 *
349 * @param tunnel GTP tunnel
350 * @return This builder object
351 */
352 public Builder setTunnel(GtpTunnel tunnel) {
353 this.tunnel = tunnel;
354 return this;
355 }
356
357 /**
358 * Set the unidirectional GTP tunnel that this FAR should encapsulate packets with.
359 *
360 * @param src GTP tunnel source IP
361 * @param dst GTP tunnel destination IP
362 * @param teid GTP tunnel ID
363 * @return This builder object
364 */
365 public Builder setTunnel(Ip4Address src, Ip4Address dst, ImmutableByteSequence teid) {
366 return this.setTunnel(GtpTunnel.builder()
367 .setSrc(src)
368 .setDst(dst)
369 .setTeid(teid)
370 .build());
371 }
372
373 /**
374 * Set the unidirectional GTP tunnel that this FAR should encapsulate packets with.
375 *
376 * @param src GTP tunnel source IP
377 * @param dst GTP tunnel destination IP
378 * @param teid GTP tunnel ID
379 * @param srcPort GTP tunnel UDP source port (destination port is hardcoded as 2152)
380 * @return This builder object
381 */
382 public Builder setTunnel(Ip4Address src, Ip4Address dst, ImmutableByteSequence teid, short srcPort) {
383 return this.setTunnel(GtpTunnel.builder()
384 .setSrc(src)
385 .setDst(dst)
386 .setTeid(teid)
387 .setSrcPort(srcPort)
388 .build());
389 }
390
391 public ForwardingActionRule build() {
392 // All match keys are required
393 checkNotNull(sessionId, "Session ID is required");
394 checkNotNull(farId, "FAR ID is required");
395 return new ForwardingActionRule(sessionId, farId, notifyCp, tunnel, dropFlag, bufferFlag);
396 }
397 }
398}