Skip to content

Commit e67a23b

Browse files
committed
fdsdump: add support for strings of variable length
1 parent d39fe27 commit e67a23b

File tree

16 files changed

+244
-37
lines changed

16 files changed

+244
-37
lines changed

src/tools/fdsdump/src/aggregator/aggregator.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ namespace fdsdump {
2525
namespace aggregator {
2626

2727
Aggregator::Aggregator(const View &view) :
28-
m_table(view.key_size(), view.value_size()),
29-
m_key_buffer(view.key_size()),
28+
m_table(view),
29+
m_key_buffer(65535),
3030
m_view(view)
3131
{
3232
}
@@ -65,23 +65,34 @@ void
6565
Aggregator::aggregate(FlowContext &ctx)
6666
{
6767
// build key
68-
for (const auto &pair : m_view.iter_keys(m_key_buffer.data())) {
68+
uint32_t size = 0;
69+
uint8_t *ptr = m_key_buffer.data();
70+
if (!m_view.is_fixed_size()) {
71+
size += sizeof(uint32_t);
72+
}
73+
for (const auto &pair : m_view.iter_keys(ptr)) {
6974
if (!pair.field.load(ctx, pair.value)) {
7075
return;
7176
}
77+
if (!m_view.is_fixed_size()) {
78+
size += pair.field.size(&pair.value);
79+
}
80+
}
81+
if (!m_view.is_fixed_size()) {
82+
*reinterpret_cast<uint32_t *>(m_key_buffer.data()) = size;
7283
}
7384

7485
// find in hash table
7586
uint8_t *rec;
7687
if (!m_table.find_or_create(m_key_buffer.data(), rec)) {
7788
// init fields
78-
for (const auto &pair : m_view.iter_values(rec + m_view.key_size())) {
89+
for (const auto &pair : m_view.iter_values(rec)) {
7990
pair.field.init(pair.value);
8091
}
8192
}
8293

8394
// aggregate
84-
for (const auto &pair : m_view.iter_values(rec + m_view.key_size())) {
95+
for (const auto &pair : m_view.iter_values(rec)) {
8596
pair.field.aggregate(ctx, pair.value);
8697
}
8798
}

src/tools/fdsdump/src/aggregator/fastHashTable.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ static constexpr double EXPAND_WHEN_THIS_FULL = 0.95;
2020
static constexpr unsigned int EXPAND_WITH_FACTOR_OF = 2;
2121
static constexpr uint8_t EMPTY_BIT = 0x80;
2222

23-
FastHashTable::FastHashTable(std::size_t key_size, std::size_t value_size) :
24-
m_key_size(key_size), m_value_size(value_size)
23+
FastHashTable::FastHashTable(const View &view) :
24+
m_view(view)
2525
{
2626
init_blocks();
2727
}
@@ -45,7 +45,8 @@ FastHashTable::init_blocks()
4545
bool
4646
FastHashTable::lookup(uint8_t *key, uint8_t *&item, bool create_if_not_found)
4747
{
48-
uint64_t hash = XXH3_64bits(key, m_key_size); // The hash of the key
48+
auto key_size = m_view.key_size(key);
49+
uint64_t hash = XXH3_64bits(key, key_size); // The hash of the key
4950
uint64_t index = (hash >> 7) & (m_block_count - 1); // The starting block index
5051

5152
for (;;) {
@@ -66,7 +67,7 @@ FastHashTable::lookup(uint8_t *key, uint8_t *&item, bool create_if_not_found)
6667
item_index += one_index;
6768

6869
uint8_t *record = block.items[item_index]; // The record whose item tag matched
69-
if (memcmp(record, key, m_key_size) == 0) { // Does the key match as well or was it just a hash collision?
70+
if (m_view.key_size(record) == key_size && memcmp(record, key, key_size) == 0) { // Does the key match as well or was it just a hash collision?
7071
item = record;
7172
return true; // We found the item
7273
}
@@ -90,12 +91,12 @@ FastHashTable::lookup(uint8_t *key, uint8_t *&item, bool create_if_not_found)
9091
auto empty_index = __builtin_ctz(empty_match);
9192
block.tags[empty_index] = item_tag;
9293

93-
uint8_t *record = m_allocator.allocate(m_key_size + m_value_size);
94+
uint8_t *record = m_allocator.allocate(key_size + m_view.value_size());
9495
block.items[empty_index] = record;
9596
m_items.push_back(record);
9697
m_record_count++;
9798

98-
memcpy(record, key, m_key_size); // Copy the key, leave the value part uninitialized
99+
memcpy(record, key, key_size); // Copy the key, leave the value part uninitialized
99100
item = record;
100101

101102
// If the hash table has reached a specified percentage of fullness, expand the hash table
@@ -121,7 +122,8 @@ FastHashTable::expand()
121122

122123
// Reassign all the items to the newly initialized blocks
123124
for (uint8_t *item : m_items) {
124-
uint64_t hash = XXH3_64bits(item, m_key_size);
125+
auto key_size = m_view.key_size(item);
126+
uint64_t hash = XXH3_64bits(item, key_size);
125127
uint64_t index = (hash >> 7) & (m_block_count - 1);
126128
uint8_t item_tag = (hash & 0xFF) & ~EMPTY_BIT;
127129

src/tools/fdsdump/src/aggregator/fastHashTable.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class FastHashTable {
3636
* @param[in] key_size Number of bytes of the key portion of the record
3737
* @param[in] value_size Number of bytes of the value portion of the record
3838
*/
39-
FastHashTable(std::size_t key_size, std::size_t value_size);
39+
FastHashTable(const View &view);
4040

4141
/**
4242
* @brief Find a record corresponding to the provided key
@@ -70,8 +70,7 @@ class FastHashTable {
7070
private:
7171
std::size_t m_block_count = 4096;
7272
std::size_t m_record_count = 0;
73-
std::size_t m_key_size;
74-
std::size_t m_value_size;
73+
const View &m_view;
7574

7675
std::vector<HashTableBlock> m_blocks;
7776
std::vector<uint8_t *> m_items;

src/tools/fdsdump/src/aggregator/field.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ Field::set_data_type(DataType data_type)
6767
case DataType::Octets128B:
6868
m_size = sizeof(Value::str);
6969
break;
70+
case DataType::VarString:
71+
m_size = 0;
72+
break;
7073
case DataType::Unassigned:
7174
throw std::logic_error("unexpected field data type");
7275
}
@@ -174,6 +177,8 @@ Field::compare(const Value &a, const Value &b) const
174177
case DataType::String128B:
175178
case DataType::Octets128B:
176179
return cmp(reinterpret_cast<const uint8_t *>(a.str), reinterpret_cast<const uint8_t *>(b.str), sizeof(a.str));
180+
case DataType::VarString:
181+
return cmp(a.varstr, b.varstr);
177182
case DataType::Unassigned:
178183
throw std::logic_error("cannot compare fields with unassigned data type");
179184
}

src/tools/fdsdump/src/aggregator/field.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class Field {
4141
/**
4242
* @brief Get the size of the field in bytes
4343
*/
44-
size_t size() const { return m_size; }
44+
virtual size_t size(const Value *value = nullptr) const { (void) value; return m_size; }
4545

4646
/**
4747
* @brief Get the offset of the field from the beginning of the aggregation record

src/tools/fdsdump/src/aggregator/ipfixField.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,5 +190,15 @@ IpfixField::operator==(const Field &other) const
190190
return false;
191191
}
192192

193+
size_t
194+
IpfixField::size(const Value* value) const
195+
{
196+
if (data_type() == DataType::VarString && value != nullptr) {
197+
return sizeof(value->varstr.len) + value->varstr.len;
198+
} else {
199+
return Field::size(value);
200+
}
201+
}
202+
193203
} // aggregator
194204
} // fdsdump

src/tools/fdsdump/src/aggregator/ipfixField.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ class IpfixField : public Field {
6161
*/
6262
bool operator==(const Field &other) const override;
6363

64+
/**
65+
* @brief Get the size the value of this field occupies in the aggregation record
66+
*/
67+
size_t size(const Value* value = nullptr) const override;
68+
6469
private:
6570
uint32_t m_pen;
6671
uint16_t m_id;

src/tools/fdsdump/src/aggregator/jsonPrinter.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ JSONPrinter::append_value(const Field &field, Value *value)
9999
append_octet_value(value);
100100
m_buffer.push_back('"');
101101
return;
102+
case DataType::VarString:
103+
m_buffer.push_back('"');
104+
append_varstring_value(value);
105+
m_buffer.push_back('"');
106+
return;
102107
case DataType::Unassigned:
103108
m_buffer.append("null");
104109
return;
@@ -157,6 +162,50 @@ JSONPrinter::append_string_value(const Value *value)
157162
}
158163
}
159164

165+
void
166+
JSONPrinter::append_varstring_value(const Value *value)
167+
{
168+
for (uint32_t i = 0; i < value->varstr.len; ++i) {
169+
const char byte = value->varstr.text[i];
170+
171+
// Escape characters
172+
switch (byte) {
173+
case '"':
174+
m_buffer.append("\\\"");
175+
continue;
176+
case '\'':
177+
m_buffer.append("\\\\");
178+
continue;
179+
case '/':
180+
m_buffer.append("\\/");
181+
continue;;
182+
case '\b':
183+
m_buffer.append("\\b");
184+
continue;
185+
case '\f':
186+
m_buffer.append("\\f");
187+
continue;
188+
case '\n':
189+
m_buffer.append("\\n");
190+
continue;
191+
case '\r':
192+
m_buffer.append("\\r");
193+
continue;
194+
case '\t':
195+
m_buffer.append("\\t");
196+
continue;
197+
default:
198+
break;
199+
}
200+
201+
if (byte >= '\x00' && byte <= '\x1F') {
202+
m_buffer.append(char2hex(byte));
203+
} else {
204+
m_buffer.append(1, byte);
205+
}
206+
}
207+
}
208+
160209
void
161210
JSONPrinter::append_octet_value(const Value *value)
162211
{

src/tools/fdsdump/src/aggregator/jsonPrinter.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class JSONPrinter : public Printer
3737
void append_value(const Field &field, Value *value);
3838
void append_string_value(const Value *value);
3939
void append_octet_value(const Value *value);
40+
void append_varstring_value(const Value *value);
4041

4142
std::shared_ptr<View> m_view;
4243
std::string m_buffer;

src/tools/fdsdump/src/aggregator/print.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ get_width(const Field &field)
4747
return 30;
4848
case DataType::MacAddress:
4949
return 17;
50+
case DataType::VarString:
51+
return 40;
5052
default:
5153
assert(0);
5254
}
@@ -172,6 +174,26 @@ string_to_str(const char array[128])
172174
return result;
173175
}
174176

177+
static std::string
178+
varstring_to_str(const char *text, uint32_t len)
179+
{
180+
std::string result;
181+
result.reserve(len);
182+
183+
for (uint32_t i = 0; i < len; ++i) {
184+
const char byte = text[i];
185+
186+
if (std::isprint(byte)) {
187+
result.append(1, byte);
188+
} else {
189+
result.append("\\x");
190+
result.append(char2hex(byte));
191+
}
192+
}
193+
194+
return result;
195+
}
196+
175197
void
176198
print_value(const Field &field, Value &value, std::string &buffer)
177199
{
@@ -238,6 +260,9 @@ print_value(const Field &field, Value &value, std::string &buffer)
238260
case DataType::DateTime:
239261
buffer.append(datetime_to_str(value.ts_millisecs));
240262
break;
263+
case DataType::VarString:
264+
buffer.append(varstring_to_str(value.varstr.text, value.varstr.len));
265+
break;
241266
default: assert(0);
242267
}
243268
}

0 commit comments

Comments
 (0)