blob: b6bc51eb7b0b3fafb21891c3458803c493e994d8 [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.function.Predicate;
22import java.util.Objects;
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.checkState;
30
31/**
32 * One of the essential elements in the NetFlow format is the Template
33 * FlowSet. Templates greatly enhance the flexibility of the Flow
34 * Record format because they allow the NetFlow Collector to process
35 * Flow Records without necessarily knowing the interpretation of all
36 * the data in the Flow Record.
37 * Ref: https://www.ietf.org/rfc/rfc3954.txt
38 */
39public final class TemplateFlowSet 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 = 0 | Length |
46 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 | Template ID 256 | Field Count |
48 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 | Field Type 1 | Field Length 1 |
50 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 | Field Type 2 | Field Length 2 |
52 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 | ... | ... |
54 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 | Field Type N | Field Length N |
56 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 | Template ID 257 | Field Count |
58 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 | Field Type 1 | Field Length 1 |
60 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 | Field Type 2 | Field Length 2 |
62 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 | ... | ... |
64 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 | Field Type M | Field Length M |
66 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 | ... | ... |
68 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 | Template ID K | Field Count |
70 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 | ... | ... |
72 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 */
74
75 private int flowSetId;
76
77 private int length;
78
79 private List<DataTemplateRecord> records;
80
81 private TemplateFlowSet(Builder builder) {
82 this.records = builder.records;
83 this.length = builder.length;
84 this.flowSetId = builder.flowSetId;
85 }
86
87 /**
88 * Return template flow set id.
89 * FlowSet ID value of 0 is reserved for the Template FlowSet.
90 *
91 * @return flow set ID
92 */
93 @Override
94 public int getFlowSetId() {
95 return this.flowSetId;
96 }
97
98 /**
99 * Returns total length of this flowSet.
100 *
101 * @return length of flowset
102 */
103 @Override
104 public int getLength() {
105 return this.length;
106 }
107
108 /**
109 * Returns list of flow records.
110 *
111 * @return list of flow records
112 */
113 public List<DataTemplateRecord> getRecords() {
114 return records;
115 }
116
117 /**
118 * Returns type of the flowset.
119 *
120 * @return type of the flowset
121 */
122 @Override
123 public Type getType() {
124 return Type.TEMPLATE_FLOWSET;
125 }
126
127 @Override
128 public int hashCode() {
129 int hash = 7;
130 hash = 53 * hash + this.flowSetId;
131 hash = 53 * hash + this.length;
132 hash = 53 * hash + Objects.hashCode(this.records);
133 return hash;
134 }
135
136 @Override
137 public boolean equals(Object obj) {
138 if (this == obj) {
139 return true;
140 }
141 if (obj == null) {
142 return false;
143 }
144 if (getClass() != obj.getClass()) {
145 return false;
146 }
147 final TemplateFlowSet other = (TemplateFlowSet) obj;
148 if (this.flowSetId != other.flowSetId) {
149 return false;
150 }
151 if (this.length != other.length) {
152 return false;
153 }
154 return Objects.equals(this.records, other.records);
155 }
156
157 @Override
158 public String toString() {
159 return MoreObjects.toStringHelper(getClass())
160 .add("flowSetId", flowSetId)
161 .add("length", length)
162 .add("records", records)
163 .toString();
164 }
165
166 /**
167 * Data deserializer function for template flow set.
168 *
169 * @return data deserializer function
170 */
171 public static Deserializer<TemplateFlowSet> deserializer() {
172 return (data, offset, length) -> {
173
174 Predicate<ByteBuffer> isValidBuffer = b -> b.remaining() < FlowSet.FIELD_LENTH;
175
176 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
177 if (isValidBuffer.test(bb)) {
178 throw new DeserializationException("Invalid buffer size");
179 }
180 Builder builder = new Builder()
181 .flowSetId(bb.getShort())
182 .length(bb.getShort());
183 while (bb.hasRemaining()) {
184 if (isValidBuffer.test(bb)) {
185 break;
186 }
187 int templateId = bb.getShort();
188 int fieldCount = bb.getShort();
189 int bufferLength = (fieldCount * FlowSet.FIELD_LENTH) + FlowSet.FIELD_LENTH;
190 byte[] record = new byte[bufferLength];
191 bb.position(bb.position() - FlowSet.FIELD_LENTH);
192 if (bb.remaining() < bufferLength) {
193 break;
194 }
195 bb.get(record);
196 builder.templateRecord(DataTemplateRecord.deserializer().deserialize(record, 0, bufferLength));
197
198 }
199 return builder.build();
200 };
201 }
202
203 /**
204 * Builder for template flow set.
205 */
206 private static class Builder {
207
208 private int flowSetId;
209
210 private int length;
211
212 private List<DataTemplateRecord> records = new LinkedList<>();
213
214 /**
215 * Setter for template flow set id.
216 *
217 * @param flowSetId template flow set id.
218 * @return this class builder.
219 */
220 public Builder flowSetId(int flowSetId) {
221 this.flowSetId = flowSetId;
222 return this;
223 }
224
225 /**
226 * Setter for total length of this flowSet.
227 *
228 * @param length total length of this flowSet.
229 * @return this class builder.
230 */
231 public Builder length(int length) {
232 this.length = length;
233 return this;
234 }
235
236 /**
237 * Setter for list of flow records.
238 *
239 * @param records list of flow records.
240 * @return this class builder.
241 */
242 public Builder templateRecords(List<DataTemplateRecord> records) {
243 this.records = records;
244 return this;
245 }
246
247 /**
248 * Setter for flow records.
249 *
250 * @param record flow records.
251 * @return this class builder.
252 */
253 public Builder templateRecord(DataTemplateRecord record) {
254 this.records.add(record);
255 return this;
256 }
257
258 /**
259 * Checks arguments for template flow set.
260 */
261 private void checkArguments() {
262 checkState(flowSetId == 0, "Invalid flow set id.");
263 checkState(length == 0, "Invalid flow set length.");
264
265 }
266
267 /**
268 * Builds template flow set.
269 *
270 * @return template flow set.
271 */
272 public TemplateFlowSet build() {
273 checkArguments();
274 return new TemplateFlowSet(this);
275 }
276
277 }
278
279}