@@ -144,17 +144,147 @@ Storage::output_add(Output *output)
144144 m_outputs.push_back (output);
145145}
146146
147+ /* *
148+ * \brief Convert template record to JSON string
149+ *
150+ * \param[in] tset_iter (Options) Template set structure to convert
151+ * \param[in] set_id Id of the set
152+ * \param[in] hdr Message header of IPFIX record
153+ * \throw runtime_error if template parser failed
154+ */
155+
156+ void
157+ Storage::convert_tmplt_rec (struct fds_tset_iter *tset_iter, uint16_t set_id, fds_ipfix_msg_hdr* hdr)
158+ {
159+ enum fds_template_type type;
160+ void *ptr;
161+ if (set_id == FDS_IPFIX_SET_TMPLT) {
162+ buffer_append (" {\" @type\" :\" ipfix.template\" ," );
163+ type = FDS_TYPE_TEMPLATE;
164+ ptr = tset_iter->ptr .trec ;
165+ } else {
166+ assert (set_id == FDS_IPFIX_SET_OPTS_TMPLT);
167+ buffer_append (" {\" @type\" :\" ipfix.optionsTemplate\" ," );
168+ type = FDS_TYPE_TEMPLATE_OPTS;
169+ ptr = tset_iter->ptr .opts_trec ;
170+ }
171+
172+ // Filling the template structure with data from raw packet
173+ uint16_t tmplt_size = tset_iter->size ;
174+ struct fds_template *tmplt;
175+ int rc;
176+ rc = fds_template_parse (type, ptr, &tmplt_size, &tmplt);
177+ if (rc != FDS_OK) {
178+ throw std::runtime_error (" Parsing failed due to memory allocation error or the format of template is invalid!" );
179+ }
180+
181+ // Printing out the header
182+ char field[64 ];
183+ snprintf (field, 64 , " \" ipfix:templateId\" :\" %" PRIu16 " \" " , tmplt->id );
184+ buffer_append (field);
185+ if (set_id == FDS_IPFIX_SET_OPTS_TMPLT) {
186+ snprintf (field, 64 , " ,\" ipfix:scopeCount\" :\" %" PRIu16 " \" " , tmplt->fields_cnt_scope );
187+ buffer_append (field);
188+ }
189+
190+ // Add detailed info to record
191+ if (m_format.detailed_info ) {
192+ addDetailedInfo (hdr);
193+ }
194+
195+ buffer_append (" ,\" ipfix:fields\" :[" );
196+
197+ // Iteration through the fields and converting them to JSON string
198+ for (uint16_t i = 0 ; i < tmplt->fields_cnt_total ; i++) {
199+ struct fds_tfield current = tmplt->fields [i];
200+ if (i != 0 ) { // Not first field
201+ buffer_append (" ," );
202+ }
203+ buffer_append (" {" );
204+ snprintf (field, 64 , " \" ipfix:elementId\" :\" %" PRIu16 " \" " , current.id );
205+ buffer_append (field);
206+ snprintf (field, 64 , " ,\" ipfix:enterpriseId\" :\" %" PRIu32 " \" " , current.en );
207+ buffer_append (field);
208+ snprintf (field, 64 , " ,\" ipfix:fieldLength\" :\" %" PRIu16 " \" " , current.length );
209+ buffer_append (field);
210+ buffer_append (" }" );
211+ }
212+ buffer_append (" ]}\n " );
213+
214+ // Free allocated memory
215+ fds_template_destroy (tmplt);
216+ }
217+
218+ /* *
219+ * \brief Convert Template sets and Options Template sets
220+ *
221+ * From all sets in the Message, try to convert just Template and Options template sets.
222+ * \param[in] set All sets in the Message
223+ * \param[in] hdr Message header of IPFIX record
224+ */
225+ void
226+ Storage::convert_set (struct ipx_ipfix_set *set, fds_ipfix_msg_hdr* hdr)
227+ {
228+
229+ bool flush = false ;
230+ int ret = IPX_OK;
231+ uint16_t set_id = ntohs (set->ptr ->flowset_id );
232+ if (set_id == FDS_IPFIX_SET_TMPLT || set_id == FDS_IPFIX_SET_OPTS_TMPLT) {
233+
234+ // Template set
235+ struct fds_tset_iter tset_iter;
236+ fds_tset_iter_init (&tset_iter, set->ptr );
237+
238+ // Iteration through all templates in the set
239+ while (fds_tset_iter_next (&tset_iter) == FDS_OK) {
240+ flush = true ;
241+
242+ // Read and print single template
243+ convert_tmplt_rec (&tset_iter, set_id, hdr);
244+
245+ // Store it
246+ for (Output *output : m_outputs) {
247+ if (output->process (m_record.buffer , m_record.size_used ) != IPX_OK) {
248+ ret = IPX_ERR_DENIED;
249+ goto endloop;
250+ }
251+ }
252+
253+ // Buffer is empty
254+ m_record.size_used = 0 ;
255+ }
256+ }
257+ endloop:
258+ if (flush) {
259+ for (Output *output : m_outputs) {
260+ output->flush ();
261+ }
262+ }
263+ }
264+
147265int
148266Storage::records_store (ipx_msg_ipfix_t *msg, const fds_iemgr_t *iemgr)
149267{
268+ // Message header
269+ auto hdr = (fds_ipfix_msg_hdr*) ipx_msg_ipfix_get_packet (msg);
270+
271+ // Process template records if enabled
272+ if (m_format.template_info ) {
273+ struct ipx_ipfix_set *sets;
274+ size_t set_cnt;
275+ ipx_msg_ipfix_get_sets (msg, &sets, &set_cnt);
276+
277+ // Iteration through all sets
278+ for (uint32_t i = 0 ; i < set_cnt; i++) {
279+ convert_set (&sets[i], hdr);
280+ }
281+ }
282+
150283 // Process all data records
151284 const uint32_t rec_cnt = ipx_msg_ipfix_get_drec_cnt (msg);
152285 bool flush = false ;
153286 int ret = IPX_OK;
154287
155- // Message header
156- auto hdr = (fds_ipfix_msg_hdr*) ipx_msg_ipfix_get_packet (msg);
157-
158288 for (uint32_t i = 0 ; i < rec_cnt; ++i) {
159289 ipx_ipfix_record *ipfix_rec = ipx_msg_ipfix_get_drec (msg, i);
160290
@@ -204,6 +334,30 @@ Storage::records_store(ipx_msg_ipfix_t *msg, const fds_iemgr_t *iemgr)
204334 return ret;
205335}
206336
337+ /* *
338+ * \brief Add fields with detailed info (export time, sequence number, ODID, message length) to record
339+ *
340+ * For each record, add detailed information if detailedInfo is enabled.
341+ * @param[in] hdr Message header of IPFIX record
342+ */
343+ void
344+ Storage::addDetailedInfo (fds_ipfix_msg_hdr *hdr)
345+ {
346+ // Array for formatting detailed info fields
347+ char field[64 ];
348+ snprintf (field, 64 , " ,\" ipfix:exportTime\" :\" %" PRIu32 " \" " , ntohl (hdr->export_time ));
349+ buffer_append (field);
350+
351+ snprintf (field, 64 , " ,\" ipfix:seqNumber\" :\" %" PRIu32 " \" " , ntohl (hdr->seq_num ));
352+ buffer_append (field);
353+
354+ snprintf (field, 64 , " ,\" ipfix:odid\" :\" %" PRIu32 " \" " , ntohl (hdr->odid ));
355+ buffer_append (field);
356+
357+ snprintf (field, 32 , " ,\" ipfix:msgLength\" :\" %" PRIu16 " \" " , ntohs (hdr->length ));
358+ buffer_append (field);
359+ }
360+
207361/* *
208362 * \brief Convert an IPFIX record to JSON string
209363 *
@@ -228,25 +382,15 @@ Storage::convert(struct fds_drec &rec, const fds_iemgr_t *iemgr, fds_ipfix_msg_h
228382
229383 m_record.size_used = size_t (rc);
230384
231- if (m_format.detailed_info ) {
232-
385+ if (m_format.detailed_info && !m_format.template_info ) {
233386 // Remove '}' parenthesis at the end of the record
234387 m_record.size_used --;
235388
236- // Array for formatting detailed info fields
237- char field[64 ];
238- snprintf (field, 64 , " ,\" ipfix:exportTime\" :\" %" PRIu32 " \" " , ntohl (hdr->export_time ));
239- buffer_append (field);
240-
241- snprintf (field, 64 , " ,\" ipfix:seqNumber\" :\" %" PRIu32 " \" " , ntohl (hdr->seq_num ));
242- buffer_append (field);
243-
244- snprintf (field, 64 , " ,\" ipfix:odid\" :\" %" PRIu32 " \" " , ntohl (hdr->odid ));
245- buffer_append (field);
246-
247- snprintf (field, 32 , " ,\" ipfix:msgLength\" :\" %" PRIu16 " \" " , ntohs (hdr->length ));
248- buffer_append (field);
389+ // Add detailed info to JSON string
390+ addDetailedInfo (hdr);
249391
392+ // Add template ID to JSON string
393+ char field[64 ];
250394 snprintf (field, 32 , " ,\" ipfix:templateId\" :\" %" PRIu16 " \" " , rec.tmplt ->id );
251395 buffer_append (field);
252396
0 commit comments