Skip to content

Commit b23d701

Browse files
AdamZvarasedmicha
authored andcommitted
Modifier: option to add empty fields
1 parent 0050655 commit b23d701

File tree

3 files changed

+141
-39
lines changed

3 files changed

+141
-39
lines changed

include/ipfixcol2/modifier.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#include <ipfixcol2/api.h>
1212

13+
#define IPX_MODIFIER_SKIP -20
14+
1315
/** Internal declaration of modifier */
1416
typedef struct ipx_modifier ipx_modifier_t;
1517

@@ -35,8 +37,15 @@ struct ipx_modifier_output {
3537
uint8_t raw[UINT16_MAX];
3638

3739
/** Length of returned data
38-
* If value is not available, length contains negative
39-
* number and represents error code */
40+
*
41+
* If output is not available, length contains negative number and represents error code.
42+
* If length contains value #IPX_MODIFIER_SKIP, this field will not be used in modified record
43+
*
44+
* Example: {.raw = 10, .length = 2} => 2 bits are copied from output buffer with value 10
45+
* {.raw = 10, .length = -1} => no bits are copied, but modified record still
46+
* contains this field
47+
* {.raw = 10, .length = #IPX_MODIFIER_SKIP} => field is not copied to modified record
48+
*/
4049
int length;
4150
};
4251

src/core/modifier.c

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ new_template_size(const struct ipx_modifier_field *fields,
520520
{
521521
size_t new_size = 0;
522522
for (size_t i = 0; i < fields_cnt; i++) {
523-
if (buffers[i].length >= 0) {
523+
if (buffers[i].length != IPX_MODIFIER_SKIP) {
524524
new_size += (fields[i].en ? 8 : 4);
525525
}
526526
}
@@ -530,19 +530,27 @@ new_template_size(const struct ipx_modifier_field *fields,
530530
/**
531531
* \brief Calculate size needed for new data records
532532
*
533+
* \param[in] fields Field defintions
533534
* \param[in] buffers Output buffers
534535
* \param[in] fields_cnt Fields array cnt
535536
* \return Space needed for new data records in output buffers
536537
*/
537538
static inline size_t
538-
get_buffers_size(const struct ipx_modifier_output *buffers, const size_t fields_cnt)
539+
get_buffers_size(const struct ipx_modifier_field *fields, const struct ipx_modifier_output *buffers,
540+
const size_t fields_cnt)
539541
{
540542
size_t new_size = 0;
541543
for (size_t i = 0; i < fields_cnt; i++) {
542-
if (buffers[i].length >= 0) {
544+
if (buffers[i].length == IPX_MODIFIER_SKIP) {
545+
continue;
546+
} else if (buffers[i].length >= 0) {
543547
// Take the worst case scanario where each new record
544548
// has variable length with 3 prefix octets
545549
new_size += buffers[i].length + 3;
550+
} else {
551+
// Invalid length in buffer but keep it ... use length from field defintion
552+
// For variable length fields use smallest possible length (1 because of prefix octet)
553+
new_size += fields[i].length == FDS_IPFIX_VAR_IE_LEN ? 1 : fields[i].length;
546554
}
547555
}
548556
return new_size;
@@ -608,7 +616,7 @@ ipfix_template_add_fields(const struct fds_template *tmplt,
608616

609617
// Iterate through all valid values in output buffers and append their fields
610618
for (size_t i = 0; i < fields_cnt; i++) {
611-
if (buffers[i].length >= 0) {
619+
if (buffers[i].length != IPX_MODIFIER_SKIP) {
612620
field_size = ipfix_template_add_field(fields[i], (uint16_t *) iter);
613621
iter += field_size;
614622
tmplt_length += field_size;
@@ -648,7 +656,7 @@ ipfix_msg_add_drecs(struct fds_drec *rec,
648656
const size_t arr_cnt)
649657
{
650658
// Allocate memory for raw data record, copy previous record
651-
size_t append_size = get_buffers_size(output, arr_cnt);
659+
size_t append_size = get_buffers_size(fields, output, arr_cnt);
652660
uint8_t *new_data = malloc(rec->size + append_size);
653661
if (new_data == NULL) {
654662
return IPX_ERR_NOMEM;
@@ -658,15 +666,31 @@ ipfix_msg_add_drecs(struct fds_drec *rec,
658666
// Iterate through values in output buffer and append them to data record
659667
uint8_t *it = new_data + rec->size;
660668
for (size_t i = 0; i < arr_cnt; i++) {
661-
if (output[i].length < 0) {
662-
// Skip invalid value in buffer
669+
if (output[i].length == IPX_MODIFIER_SKIP) {
670+
// Skip field
671+
continue;
672+
} else if (output[i].length < 0) {
673+
// Dont copy memory from buffer, but keep this field
674+
675+
if (fields[i].length == FDS_IPFIX_VAR_IE_LEN) {
676+
// For variable length field append only prefix octet containing zero
677+
*it = 0;
678+
it++;
679+
rec->size += 1;
680+
} else {
681+
memset(it, 0, fields[i].length);
682+
it += fields[i].length;
683+
rec->size += fields[i].length;
684+
}
663685
continue;
664686
}
665687

666-
if (fields[i].length == FDS_IPFIX_VAR_IE_LEN) {
688+
// Process output with normal length
689+
else if (fields[i].length == FDS_IPFIX_VAR_IE_LEN) {
667690
// Append length octet prefix for variable length record
668691
if (output[i].length < 255) {
669-
memcpy(it++, &(output[i].length), 1);
692+
*it = output[i].length;
693+
it++;
670694
rec->size += 1;
671695
} else {
672696
*it = 0xFF;

tests/unit/core/modifier/modifier_append_and_filter.cpp

Lines changed: 97 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ void all_filter(uint8_t *filter) {
152152
}
153153

154154
// Filter no fields from template
155-
TEST_F(Filter, ZeroTFields) {
155+
TEST_F(Filter, TemplateFields_None) {
156156
ASSERT_EQ(ipx_modifier_filter(&rec, filter), IPX_OK);
157157
fds_template *t = (fds_template *)(rec.tmplt);
158158

@@ -170,7 +170,7 @@ TEST_F(Filter, ZeroTFields) {
170170
}
171171

172172
// Filter out starting fields from template
173-
TEST_F(Filter, StartTFields) {
173+
TEST_F(Filter, TemplateFields_Start) {
174174
// Set filter
175175
start_filter(filter);
176176

@@ -192,7 +192,7 @@ TEST_F(Filter, StartTFields) {
192192
}
193193

194194
// Filter out last 2 fields from template
195-
TEST_F(Filter, EndTFields) {
195+
TEST_F(Filter, TemplateFields_End) {
196196
// Set filter
197197
end_filter(filter);
198198

@@ -216,7 +216,7 @@ TEST_F(Filter, EndTFields) {
216216
}
217217

218218
// Filter out random fields from template (start, middle, end fields)
219-
TEST_F(Filter, MixedTFields) {
219+
TEST_F(Filter, TemplateFields_MixedPosition) {
220220
// Set filter
221221
mixed_filter(filter);
222222

@@ -238,7 +238,7 @@ TEST_F(Filter, MixedTFields) {
238238
}
239239

240240
// Filter out all fields from template
241-
TEST_F(Filter, AllTFields) {
241+
TEST_F(Filter, TemplateFields_All) {
242242
// Set filter
243243
memset(filter, 1, tmplt->fields_cnt_total);
244244

@@ -254,7 +254,7 @@ TEST_F(Filter, AllTFields) {
254254
}
255255

256256
// Filtering zero fields from original data record
257-
TEST_F(Filter, NoneDrecs) {
257+
TEST_F(Filter, DataRecords_None) {
258258
uint16_t rec_prev_size = rec.size;
259259
uint8_t *orig_raw = new uint8_t[rec.size];
260260
memcpy(orig_raw, rec.data, rec.size);
@@ -272,7 +272,7 @@ TEST_F(Filter, NoneDrecs) {
272272

273273
// Filtering out static (non variable length) fields from original data record
274274
// Also tests filtering last data record
275-
TEST_F(Filter, StaticLengthDrecs) {
275+
TEST_F(Filter, DataRecords_StaticLength) {
276276
uint16_t rec_prev_size = rec.size;
277277
static_filter(filter);
278278

@@ -329,7 +329,7 @@ TEST_F(Filter, StaticLengthDrecs) {
329329

330330
// Filtering out dynamic (variable length) fields from original data record
331331
// Also tests filtering first data record
332-
TEST_F(Filter, DynamicLengthDrecs) {
332+
TEST_F(Filter, DataRecords_VariableLength) {
333333
uint16_t rec_prev_size = rec.size;
334334
dynamic_filter(filter);
335335

@@ -388,11 +388,6 @@ TEST_F(Filter, DynamicLengthDrecs) {
388388
fds_template_destroy((fds_template *)rec.tmplt);
389389
}
390390

391-
TEST_F(Filter, InvalidArguments) {
392-
EXPECT_EQ(ipx_modifier_filter(NULL, filter), IPX_ERR_ARG);
393-
EXPECT_EQ(ipx_modifier_filter(&rec, NULL), IPX_ERR_ARG);
394-
}
395-
396391
/** ------------------------- ADDING TESTS ------------------------- **/
397392

398393
#define STATIC_CNT 4
@@ -447,7 +442,7 @@ class Adder : public Modifier {
447442
static_fields[i-1].en = i % 2;
448443
static_fields[i-1].id = i * 10;
449444
static_fields[i-1].length = i * 2;
450-
static_output[i-1].length = -1;
445+
static_output[i-1].length = IPX_MODIFIER_SKIP;
451446
}
452447
}
453448

@@ -540,18 +535,42 @@ class Adder : public Modifier {
540535

541536
};
542537

543-
// Just copy template and drec, do not change anything
538+
// Append zero fields to record
544539
TEST_F(Adder, ZeroFields) {
545-
// "Modify" record
540+
// Modify record
546541
ASSERT_EQ(ipx_modifier_append(&rec, static_fields, static_output, STATIC_CNT), IPX_OK);
547542

548543
// Check template and record
549544
cmp_template_overall(0, 0, 0);
550545
cmp_data_overall(0);
551546
}
552547

548+
// Append zero fields to record but keep them in template and records as 0
549+
TEST_F(Adder, Static_ZeroFields_KeepEmptyOutputs) {
550+
for (struct ipx_modifier_output &i : static_output) {
551+
i.length = -1;
552+
}
553+
// Modify record
554+
ASSERT_EQ(ipx_modifier_append(&rec, static_fields, static_output, STATIC_CNT), IPX_OK);
555+
556+
// Check template
557+
cmp_template_overall(20, 4, 24);
558+
559+
// Check record
560+
cmp_data_overall(20);
561+
562+
uint64_t zero = 0;
563+
int p = 8;
564+
565+
for (auto i : static_fields) {
566+
ASSERT_EQ(fds_drec_find(&rec, i.en, i.id, &field), p++);
567+
cmp_data_record(field, &zero, i.length);
568+
}
569+
570+
}
571+
553572
// Append single value to data record and template
554-
TEST_F(Adder, StaticSingleField) {
573+
TEST_F(Adder, Static_SingleField) {
555574
// Add single value to output buffer
556575
uint8_t pos = 1;
557576
uint32_t value = 422322;
@@ -572,7 +591,7 @@ TEST_F(Adder, StaticSingleField) {
572591
}
573592

574593
// Append single value (EN specific) to data record and template
575-
TEST_F(Adder, StaticSingleFieldEN) {
594+
TEST_F(Adder, Static_SingleField_WithEN) {
576595
// Add single value (with EN) to output buffer
577596
uint8_t pos = 0;
578597
uint16_t value = 15213;
@@ -593,12 +612,11 @@ TEST_F(Adder, StaticSingleFieldEN) {
593612
}
594613

595614
// Append multiple values (EN and non-EN specific) to data record and template
596-
TEST_F(Adder, StaticMultipleFields) {
615+
TEST_F(Adder, Static_MultipleFields) {
597616
// Add all values to output buffer
598617
int used_length = 0;
599-
long value = 0;
618+
long value = 0x123456789ABCDEF;
600619
for (uint8_t pos = 0; pos < STATIC_CNT; pos++) {
601-
value = 0x123456789ABCDEF;
602620
ipx_modifier_field used = static_fields[pos];
603621
set_value(used, static_output[pos], &value, used.length);
604622
used_length += used.length;
@@ -627,8 +645,65 @@ TEST_F(Adder, StaticMultipleFields) {
627645
} while (fds_drec_iter_next(&it) != FDS_EOC);
628646
}
629647

648+
// Append multiple values, some of which are kept in template and records with no values
649+
TEST_F(Adder, Static_MultipleFields_KeepEmptyOutputs) {
650+
long value = 0x123456789ABCDEF;
651+
652+
// Keep first field (length = 2)
653+
static_output[0].length = -1;
654+
// Use second and third field (lengths = {4, 6})
655+
set_value(static_fields[1], static_output[1], &value, 4);
656+
set_value(static_fields[2], static_output[2], &value, 6);
657+
// Do not use fourth field
658+
static_output[3].length = IPX_MODIFIER_SKIP;
659+
660+
// Modify template
661+
ASSERT_EQ(ipx_modifier_append(&rec, static_fields, static_output, STATIC_CNT), IPX_OK);
662+
663+
// Check modified template
664+
cmp_template_overall(12, 3, 20); // 4 (non-EN) + 16 (2x8=EN)
665+
for (int i = 0; i < 3; i++) {
666+
cmp_template_field(rec.tmplt->fields_cnt_total - (3 - i), static_fields[i]);
667+
}
668+
669+
// Check modified record
670+
cmp_data_overall(12);
671+
fds_drec_iter_init(&it, &rec, 0);
672+
// Set iterator to first appended field
673+
ASSERT_EQ(fds_drec_iter_find(&it, static_fields[0].en, static_fields[0].id), 8);
674+
EXPECT_EQ(*(uint16_t *)it.field.data, 0);
675+
ASSERT_EQ(fds_drec_iter_next(&it), 9);
676+
677+
// Iterate through all remaining data records and compare them
678+
int size = 4;
679+
do {
680+
cmp_data_record(it.field, &value, size);
681+
size += 2;
682+
} while (fds_drec_iter_next(&it) != FDS_EOC);
683+
}
684+
685+
// Append zero fields to record but keep them in template and records as 0
686+
TEST_F(Adder, Dynamic_ZeroFields_KeepEmptyOutputs) {
687+
// Modify record
688+
ASSERT_EQ(ipx_modifier_append(&rec, dynamic_fields, dynamic_output, DYNAMIC_CNT), IPX_OK);
689+
690+
// Check template
691+
cmp_template_overall(2, 2, 8);
692+
693+
// Check record
694+
cmp_data_overall(2);
695+
696+
uint64_t zero = 0;
697+
int p = 8;
698+
699+
for (auto i : dynamic_fields) {
700+
ASSERT_EQ(fds_drec_find(&rec, i.en, i.id, &field), p++);
701+
cmp_data_record(field, &zero, 0);
702+
}
703+
}
704+
630705
// Append values with variable length (one with single prefix octet, second with 3 prefix octets)
631-
TEST_F(Adder, DynamicFields) {
706+
TEST_F(Adder, Dynamic_MultipleFields) {
632707
// Add all values to output buffer
633708
uint8_t values[1000] = {0x12, 0x34, 0x56, };
634709
values[678] = 0x78;
@@ -658,10 +733,4 @@ TEST_F(Adder, DynamicFields) {
658733
cmp_data_record(it.field, &values, 1000);
659734

660735
EXPECT_EQ(fds_drec_iter_next(&it), FDS_EOC);
661-
}
662-
663-
TEST_F(Adder, InvalidArguments) {
664-
EXPECT_EQ(ipx_modifier_append(NULL, static_fields, static_output, 0), IPX_ERR_ARG);
665-
EXPECT_EQ(ipx_modifier_append(&rec, NULL, static_output, 0), IPX_ERR_ARG);
666-
EXPECT_EQ(ipx_modifier_append(&rec, static_fields, NULL, 0), IPX_ERR_ARG);
667736
}

0 commit comments

Comments
 (0)