blob: 71839159911a03dc45ecdfbd72bb6c8000d409ff [file] [log] [blame]
karthik1977bc5ea1e2023-01-02 19:25:14 +05301/*
2 * Copyright 2023-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 */
16package org.onosproject.netflow.impl;
17
18import java.nio.ByteBuffer;
19import java.util.LinkedList;
20import java.util.List;
21import java.util.Objects;
22import java.util.function.Function;
23
24import com.google.common.base.MoreObjects;
25
26import org.onlab.packet.DeserializationException;
27import org.onlab.packet.Deserializer;
28
29import static com.google.common.base.Preconditions.checkNotNull;
30import static com.google.common.base.Preconditions.checkState;
31
32/**
33 * A Data FlowSet is one or more records, of the same type, that are
34 * grouped together in an Export Packet. Each record is either a Flow
35 * Data Record or an Options Data Record previously defined by a
36 * Template Record or an Options Template Record.
37 * Ref: https://www.ietf.org/rfc/rfc3954.txt
38 */
39public final class DataFlowSet extends FlowSet {
40
41 /*
42 0 1 2 3
43 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
44 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 | FlowSet ID = Template ID | Length |
46 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 | Record 1 - Field Value 1 | Record 1 - Field Value 2 |
48 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 | Record 1 - Field Value 3 | ... |
50 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 | Record 2 - Field Value 1 | Record 2 - Field Value 2 |
52 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 | Record 2 - Field Value 3 | ... |
54 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 | Record 3 - Field Value 1 | ... |
56 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 | ... | Padding |
58 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 */
60
61 private int flowSetId;
62
63 private int length;
64
65 private byte[] data;
66
67 private DataFlowSet(Builder builder) {
68 this.flowSetId = builder.flowSetId;
69 this.length = builder.length;
70 this.data = builder.data;
71 }
72
73 private List<DataFlowRecord> dataFlow = new LinkedList<>();
74
75 /**
76 * Returns flowset id.
77 * Each Data FlowSet is associated with a FlowSet ID. The FlowSet
78 * ID maps to a (previously generated) Template ID
79 *
80 * @return flowset id
81 */
82 @Override
83 public int getFlowSetId() {
84 return this.flowSetId;
85 }
86
87 /**
88 * Returns length of this FlowSet.
89 * Length is the sum of the lengths
90 * of the FlowSet ID, Length itself, all Flow Records within this
91 * FlowSet, and the padding bytes, if any.
92 *
93 * @return length of the flowset
94 */
95 @Override
96 public int getLength() {
97 return this.length;
98 }
99
100 /**
101 * Returns list of data flow records.
102 *
103 * @return list of data flow records
104 */
105 public List<DataFlowRecord> getDataFlow() {
106 return dataFlow;
107 }
108
109 /**
110 * Set data flow record.
111 *
112 * @param dataFlow data flow record
113 */
114 public void setDataFlow(DataFlowRecord dataFlow) {
115 this.dataFlow.add(dataFlow);
116 }
117
118 /**
119 * Returns type of flowset.
120 *
121 * @return type of flowset
122 */
123 @Override
124 public Type getType() {
125 return Type.DATA_FLOWSET;
126 }
127
128 @Override
129 public int hashCode() {
130 int hash = 3;
131 hash = 79 * hash + this.flowSetId;
132 hash = 79 * hash + this.length;
133 hash = 79 * hash + Objects.hashCode(this.dataFlow);
134 return hash;
135 }
136
137 @Override
138 public boolean equals(Object obj) {
139 if (this == obj) {
140 return true;
141 }
142 if (obj == null) {
143 return false;
144 }
145 if (getClass() != obj.getClass()) {
146 return false;
147 }
148 final DataFlowSet other = (DataFlowSet) obj;
149 if (this.flowSetId != other.flowSetId) {
150 return false;
151 }
152 if (this.length != other.length) {
153 return false;
154 }
155 return Objects.equals(this.dataFlow, other.dataFlow);
156 }
157
158 @Override
159 public String toString() {
160 return MoreObjects.toStringHelper(getClass())
161 .add("flowSetId", flowSetId)
162 .add("length", length)
163 .add("data", data)
164 .toString();
165 }
166
167 /**
168 * Deserializer function for data flow set.
169 *
170 * @return deserializer function
171 */
172 public static Deserializer<DataFlowSet> deserializer() {
173 return (data, offset, length) -> {
174 Function<ByteBuffer, byte[]> readBytes = b -> {
175 if (b.remaining() == b.limit()) {
176 return null;
177 }
178 byte[] bytes = new byte[b.remaining()];
179 b.get(bytes);
180 return bytes;
181 };
182 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
183 return new Builder()
184 .flowSetId(bb.getShort())
185 .length(bb.getShort())
186 .data(readBytes.apply(bb))
187 .build();
188
189 };
190 }
191
192 /**
193 * Data eserializer function for data flow record.
194 *
195 * @param template data template record
196 * @throws DeserializationException if unable to deserialize data
197 */
198 public void dataDeserializer(DataTemplateRecord template) throws DeserializationException {
199 dataFlow = new LinkedList<>();
200 ByteBuffer bb = ByteBuffer.wrap(data, 0, data.length);
201
202 while (bb.hasRemaining()) {
203 if (bb.remaining() < template.getValueLength()) {
204 break;
205 }
206 byte[] dataRecord = new byte[template.getValueLength()];
207 bb.get(dataRecord);
208 this.setDataFlow(DataFlowRecord.deserializer().deserialize(
209 data, 0, template.getValueLength(), template));
210 }
211
212 }
213
214 /**
215 * Builder for data flow set.
216 */
217 private static class Builder {
218
219 private int flowSetId;
220
221 private int length;
222
223 private byte[] data;
224
225 /**
226 * Setter for flowset id.
227 *
228 * @param flowSetId flowset id.
229 * @return this class builder.
230 */
231 public Builder flowSetId(int flowSetId) {
232 this.flowSetId = flowSetId;
233 return this;
234 }
235
236 /**
237 * Setter for length of this FlowSet.
238 *
239 * @param length length of this FlowSet.
240 * @return this class builder.
241 */
242 public Builder length(int length) {
243 this.length = length;
244 return this;
245 }
246
247 /**
248 * Setter for flow data.
249 *
250 * @param data flow data.
251 * @return this class builder.
252 */
253 public Builder data(byte[] data) {
254 this.data = data;
255 return this;
256 }
257
258 /**
259 * Checks arguments for data flow set.
260 */
261 private void checkArguments() {
262 checkState(flowSetId != 0, "Invalid data flowset id.");
263 checkState(length != 0, "Invalid data flowset length.");
264 checkNotNull(data, "Data flow set cannot be null");
265
266 }
267
268 /**
269 * Builds data flowset.
270 *
271 * @return data flowset.
272 */
273 public DataFlowSet build() {
274 checkArguments();
275 return new DataFlowSet(this);
276 }
277
278 }
279
280}