blob: bfed1ce26fdc2a48830254598cd7a30cf1935a60 [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",
Daniele Moro08c9e7f2021-07-28 18:53:34 +020089 tunnel.src().toString(), tunnel.srcPort(),
90 tunnel.teid().toString(), tunnel.dst().toString());
Daniele Moro5e66f982021-06-11 16:41:48 +020091 } else {
92 actionName = "Forward";
93 }
94 if (notifyFlag) {
95 actionName += "+NotifyCP";
96 }
97
98 return String.format("%s(%s)", actionName, actionParams);
99 }
100
101 @Override
102 public String toString() {
103 String matchKeys = String.format("ID=%d, SEID=%s", farId, sessionId.toString());
104 String actionString = actionString();
105
106 return String.format("FAR{Match(%s) -> %s}", matchKeys, actionString);
107 }
108
109 @Override
110 public boolean equals(Object obj) {
111 if (obj == this) {
112 return true;
113 }
114 if (obj == null) {
115 return false;
116 }
117 if (getClass() != obj.getClass()) {
118 return false;
119 }
120 ForwardingActionRule that = (ForwardingActionRule) obj;
121
122 // Safe comparisons between potentially null objects
123 return (this.dropFlag == that.dropFlag &&
124 this.bufferFlag == that.bufferFlag &&
125 this.notifyFlag == that.notifyFlag &&
126 this.farId == that.farId &&
127 Objects.equals(this.tunnel, that.tunnel) &&
128 Objects.equals(this.sessionId, that.sessionId));
129 }
130
131 @Override
132 public int hashCode() {
133 return Objects.hash(sessionId, farId, notifyFlag, tunnel, dropFlag, bufferFlag);
134 }
135
136 /**
137 * Get the ID of the PFCP Session that produced this FAR.
138 *
139 * @return PFCP session ID
140 */
141 public ImmutableByteSequence sessionId() {
142 return sessionId;
143 }
144
145 /**
146 * Get the PFCP session-local ID of the FAR that should apply to packets that match this PDR.
147 *
148 * @return PFCP session-local FAR ID
149 */
150 public int farId() {
151 return farId;
152 }
153
154 /**
155 * True if this FAR does not drop packets.
156 *
157 * @return true if FAR is forwards
158 */
159 public boolean forwards() {
160 return !dropFlag;
161 }
162
163 /**
164 * True if this FAR encapsulates packets in a GTP tunnel, and false otherwise.
165 *
166 * @return true is FAR encapsulates
167 */
168 public boolean encaps() {
169 return tunnel != null;
170 }
171
172 /**
173 * Returns true if this FAR drops packets, and false otherwise.
174 *
175 * @return true if this FAR drops
176 */
177 public boolean drops() {
178 return dropFlag;
179 }
180
181 /**
182 * Returns true if this FAR notifies the control plane on receiving a packet, and false otherwise.
183 *
184 * @return true if this FAR notifies the cp
185 */
186 public boolean notifies() {
187 return notifyFlag;
188 }
189
190
191 /**
192 * Returns true if this FAR buffers incoming packets, and false otherwise.
193 *
194 * @return true if this FAR buffers
195 */
196 public boolean buffers() {
197 return bufferFlag;
198 }
199
200 /**
201 * A description of the tunnel that this FAR will encapsulate packets with, if it is a downlink FAR. If the FAR
202 * is uplink, there will be no such tunnel and this method wil return null.
203 *
204 * @return A GtpTunnel instance containing a tunnel sourceIP, destIP, and GTPU TEID, or null if the FAR is uplink.
205 */
206 public GtpTunnel tunnel() {
207 return tunnel;
208 }
209
210 /**
211 * Get the source UDP port of the GTP tunnel that this FAR will encapsulate packets with.
212 *
213 * @return GTP tunnel source UDP port
214 */
215 public Short tunnelSrcPort() {
216 return tunnel != null ? tunnel.srcPort() : null;
217 }
218
219 /**
220 * Get the source IP of the GTP tunnel that this FAR will encapsulate packets with.
221 *
222 * @return GTP tunnel source IP
223 */
224 public Ip4Address tunnelSrc() {
225 if (tunnel == null) {
226 return null;
227 }
228 return tunnel.src();
229 }
230
231 /**
232 * Get the destination IP of the GTP tunnel that this FAR will encapsulate packets with.
233 *
234 * @return GTP tunnel destination IP
235 */
236 public Ip4Address tunnelDst() {
237 if (tunnel == null) {
238 return null;
239 }
240 return tunnel.dst();
241 }
242
243 /**
244 * Get the identifier of the GTP tunnel that this FAR will encapsulate packets with.
245 *
246 * @return GTP tunnel ID
247 */
248 public ImmutableByteSequence teid() {
249 if (tunnel == null) {
250 return null;
251 }
252 return tunnel.teid();
253 }
254
255 public static class Builder {
256 private ImmutableByteSequence sessionId = null;
257 private Integer farId = null;
258 private GtpTunnel tunnel = null;
259 private boolean dropFlag = false;
260 private boolean bufferFlag = false;
261 private boolean notifyCp = false;
262
263 public Builder() {
264 }
265
266 /**
267 * Set the ID of the PFCP session that created this FAR.
268 *
269 * @param sessionId PFC session ID
270 * @return This builder object
271 */
272 public Builder withSessionId(ImmutableByteSequence sessionId) {
273 this.sessionId = sessionId;
274 return this;
275 }
276
277 /**
278 * Set the ID of the PFCP session that created this FAR.
279 *
280 * @param sessionId PFC session ID
281 * @return This builder object
282 */
283 public Builder withSessionId(long sessionId) {
284 try {
285 this.sessionId = ImmutableByteSequence.copyFrom(sessionId).fit(SESSION_ID_BITWIDTH);
286 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
287 // This error is literally impossible
288 }
289 return this;
290 }
291
292 /**
293 * Set the PFCP Session-local ID of this FAR.
294 *
295 * @param farId PFCP session-local FAR ID
296 * @return This builder object
297 */
298 public Builder setFarId(int farId) {
299 this.farId = farId;
300 return this;
301 }
302
303 /**
304 * Make this FAR forward incoming packets.
305 *
306 * @param flag the flag value to set
307 * @return This builder object
308 */
309 public Builder setForwardFlag(boolean flag) {
310 this.dropFlag = !flag;
311 return this;
312 }
313
314 /**
315 * Make this FAR drop incoming packets.
316 *
317 * @param flag the flag value to set
318 * @return This builder object
319 */
320 public Builder setDropFlag(boolean flag) {
321 this.dropFlag = flag;
322 return this;
323 }
324
325 /**
326 * Make this FAR buffer incoming packets.
327 *
328 * @param flag the flag value to set
329 * @return This builder object
330 */
331 public Builder setBufferFlag(boolean flag) {
332 this.bufferFlag = flag;
333 return this;
334 }
335
336 /**
337 * Set a flag specifying if the control plane should be notified when this FAR is hit.
338 *
339 * @param notifyCp true if FAR notifies control plane
340 * @return This builder object
341 */
342 public Builder setNotifyFlag(boolean notifyCp) {
343 this.notifyCp = notifyCp;
344 return this;
345 }
346
347 /**
348 * Set the GTP tunnel that this FAR should encapsulate packets with.
349 *
350 * @param tunnel GTP tunnel
351 * @return This builder object
352 */
353 public Builder setTunnel(GtpTunnel tunnel) {
354 this.tunnel = tunnel;
355 return this;
356 }
357
358 /**
359 * Set the unidirectional GTP tunnel that this FAR should encapsulate packets with.
360 *
361 * @param src GTP tunnel source IP
362 * @param dst GTP tunnel destination IP
363 * @param teid GTP tunnel ID
364 * @return This builder object
365 */
366 public Builder setTunnel(Ip4Address src, Ip4Address dst, ImmutableByteSequence teid) {
367 return this.setTunnel(GtpTunnel.builder()
368 .setSrc(src)
369 .setDst(dst)
370 .setTeid(teid)
371 .build());
372 }
373
374 /**
375 * Set the unidirectional GTP tunnel that this FAR should encapsulate packets with.
376 *
377 * @param src GTP tunnel source IP
378 * @param dst GTP tunnel destination IP
379 * @param teid GTP tunnel ID
380 * @param srcPort GTP tunnel UDP source port (destination port is hardcoded as 2152)
381 * @return This builder object
382 */
383 public Builder setTunnel(Ip4Address src, Ip4Address dst, ImmutableByteSequence teid, short srcPort) {
384 return this.setTunnel(GtpTunnel.builder()
385 .setSrc(src)
386 .setDst(dst)
387 .setTeid(teid)
388 .setSrcPort(srcPort)
389 .build());
390 }
391
392 public ForwardingActionRule build() {
393 // All match keys are required
394 checkNotNull(sessionId, "Session ID is required");
395 checkNotNull(farId, "FAR ID is required");
396 return new ForwardingActionRule(sessionId, farId, notifyCp, tunnel, dropFlag, bufferFlag);
397 }
398 }
399}