Implement basicList IE in exporting process
parent
5177babf46
commit
5625fe4ff1
|
@ -103,6 +103,24 @@ const struct ipfix_identifier* ipfix_name_lookup(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* lookup an ipfix semantic by name
|
||||
*/
|
||||
const uint8_t* ipfix_semantic_lookup(const char *name)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
// Search IANA semantic IDs
|
||||
for (i = 0; i<sizeof(ipfixsemantic_iana)/sizeof(struct ipfix_semantic); i++) {
|
||||
if (strcasecmp(name, ipfixsemantic_iana[i].name)==0) {
|
||||
return &(ipfixsemantic_iana[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -37,13 +37,14 @@ struct ipfix_identifier {
|
|||
};
|
||||
|
||||
struct ipfix_semantic {
|
||||
uint16_t id;
|
||||
uint8_t id;
|
||||
char *name;
|
||||
};
|
||||
|
||||
int ipfix_id_rangecheck(int id);
|
||||
const struct ipfix_identifier* ipfix_id_lookup(uint16_t id, uint32_t pen);
|
||||
const struct ipfix_identifier* ipfix_name_lookup(const char *name);
|
||||
const uint8_t* ipfix_semantic_lookup(const char *name);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "core/Cfg.h"
|
||||
#include "common/ipfixlolib/ipfix_names.h"
|
||||
#include "common/ipfixlolib/ipfix_iana.h"
|
||||
|
||||
|
||||
class InfoElementCfg
|
||||
|
@ -22,6 +23,8 @@ public:
|
|||
modifier = getOptional("modifier");
|
||||
match = getOptional("match");
|
||||
autoAddV4PrefixLength = getBool("autoAddV4PrefixLength", true);
|
||||
semanticName = getOptional("semantic");
|
||||
fieldName = getOptional("fieldIeName");
|
||||
|
||||
|
||||
if (ieId>0) {
|
||||
|
@ -66,6 +69,29 @@ public:
|
|||
const ipfix_identifier* ipfixid = ipfix_id_lookup(ieId, enterpriseNumber);
|
||||
if (ipfixid) ieLength = ipfixid->length;
|
||||
}
|
||||
|
||||
// basicList specific
|
||||
if (ieId == IPFIX_TYPEID_basicList && enterpriseNumber == 0) {
|
||||
|
||||
if (semanticName.size() == 0) {
|
||||
semantic = IPFIX_STRUCTURED_TYPE_SEMANTIC_undefined;
|
||||
} else {
|
||||
const uint8_t *semanticPtr = ipfix_semantic_lookup(semanticName.c_str());
|
||||
if (semanticPtr == NULL) {
|
||||
THROWEXCEPTION("InfoElementCfg: semantic \"%s\" could not be mapped to IANA-standardized semantic", semanticName.c_str());
|
||||
}
|
||||
semantic = *semanticPtr;
|
||||
}
|
||||
|
||||
if (fieldName.size() == 0) {
|
||||
THROWEXCEPTION("InfoElementCfg: fieldIeName element is missing for basicList");
|
||||
} else {
|
||||
fieldIe = ipfix_name_lookup(fieldName.c_str());
|
||||
if (fieldIe == NULL) {
|
||||
THROWEXCEPTION("InfoElementCfg: given fieldIeName \"%s\" could not be mapped to IANA-standardized IE", fieldName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string getName() { return "IE"; }
|
||||
|
@ -86,6 +112,10 @@ public:
|
|||
|
||||
bool getAutoAddV4PrefixLength() { return autoAddV4PrefixLength; }
|
||||
|
||||
uint8_t getSemantic() { return semantic; }
|
||||
|
||||
const ipfix_identifier* getFieldIe() { return fieldIe; }
|
||||
|
||||
bool operator==(const InfoElementCfg &other) const {
|
||||
if (other.ieLength != ieLength) return false;
|
||||
if (other.ieId != ieId) return true;
|
||||
|
@ -108,6 +138,12 @@ private:
|
|||
|
||||
bool knownIE;
|
||||
bool autoAddV4PrefixLength;
|
||||
|
||||
// basicList specific
|
||||
std::string semanticName;
|
||||
uint8_t semantic;
|
||||
std::string fieldName;
|
||||
const ipfix_identifier* fieldIe;
|
||||
};
|
||||
|
||||
#endif /*INFOELEMENTCFG_H_*/
|
||||
|
|
|
@ -228,8 +228,13 @@ void PrintHelpers::printUint(char* buf, InformationElement::IeInfo type, IpfixRe
|
|||
*/
|
||||
void PrintHelpers::printFieldData(InformationElement::IeInfo type, IpfixRecord::Data* pattern) {
|
||||
|
||||
timeval t;
|
||||
uint64_t hbnum;
|
||||
printFieldDataType(type);
|
||||
|
||||
printFieldDataValue(type, pattern);
|
||||
}
|
||||
|
||||
void PrintHelpers::printFieldDataType(InformationElement::IeInfo type) {
|
||||
|
||||
string typeStr = type.toString();
|
||||
|
||||
// try to get the values aligned
|
||||
|
@ -237,6 +242,12 @@ void PrintHelpers::printFieldData(InformationElement::IeInfo type, IpfixRecord::
|
|||
fprintf(fh, "%-60s: ", type.toString().c_str());
|
||||
else
|
||||
fprintf(fh, "%s: ", type.toString().c_str());
|
||||
}
|
||||
|
||||
void PrintHelpers::printFieldDataValue(InformationElement::IeInfo type, IpfixRecord::Data* pattern) {
|
||||
|
||||
timeval t;
|
||||
uint64_t hbnum;
|
||||
|
||||
switch (type.enterprise) {
|
||||
case 0:
|
||||
|
@ -669,7 +680,25 @@ void IpfixPrinter::printTreeRecord(IpfixDataRecord* record)
|
|||
fprintf(fh, " `- variable data\n");
|
||||
for (i = 0; i < record->templateInfo->fieldCount; i++) {
|
||||
fprintf(fh, " ' `- ");
|
||||
printFieldData(record->templateInfo->fieldInfo[i].type, (record->data + record->templateInfo->fieldInfo[i].offset));
|
||||
if (record->templateInfo->fieldInfo[i].type == InformationElement::IeInfo(IPFIX_TYPEID_basicList, 0)) {
|
||||
printFieldDataType(record->templateInfo->fieldInfo[i].type);
|
||||
|
||||
fprintf(fh, "semantic=%hu, %s [", record->templateInfo->fieldInfo[i].basicListData.semantic, record->templateInfo->fieldInfo[i].basicListData.fieldIe->toString().c_str());
|
||||
|
||||
vector<void*>** listPtr = (vector<void*>**) (record->data + record->templateInfo->fieldInfo[i].offset);
|
||||
for (vector<void*>::const_iterator iter = (*listPtr)->begin(); iter != (*listPtr)->end(); iter++) {
|
||||
|
||||
printFieldDataValue(*record->templateInfo->fieldInfo[i].basicListData.fieldIe, reinterpret_cast<IpfixRecord::Data*>(*iter));
|
||||
|
||||
// No comma for last element in the list
|
||||
if (iter+1 != (*listPtr)->end()) {
|
||||
fprintf(fh, ", ");
|
||||
}
|
||||
}
|
||||
fprintf(fh, "]");
|
||||
} else {
|
||||
printFieldData(record->templateInfo->fieldInfo[i].type, (record->data + record->templateInfo->fieldInfo[i].offset));
|
||||
}
|
||||
fprintf(fh, "\n");
|
||||
}
|
||||
fprintf(fh, " `---\n\n");
|
||||
|
|
|
@ -31,6 +31,8 @@ class PrintHelpers
|
|||
PrintHelpers() : fh(stdout) {}
|
||||
|
||||
void printFieldData(InformationElement::IeInfo type, IpfixRecord::Data* pattern);
|
||||
void printFieldDataType(InformationElement::IeInfo type);
|
||||
void printFieldDataValue(InformationElement::IeInfo type, IpfixRecord::Data* pattern);
|
||||
void printIPv4(uint32_t data);
|
||||
void printIPv4(InformationElement::IeInfo type, IpfixRecord::Data* data);
|
||||
void printPort(InformationElement::IeInfo type, IpfixRecord::Data* data);
|
||||
|
|
|
@ -208,13 +208,26 @@ class IpfixRecord
|
|||
boost::shared_ptr<IpfixRecord::SourceID> sourceID;
|
||||
|
||||
IpfixRecord() {}
|
||||
virtual ~IpfixRecord() {}
|
||||
|
||||
virtual ~IpfixRecord() {
|
||||
if (variableLenData != NULL) {
|
||||
free(variableLenData);
|
||||
variableLenData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* all subclasses *MUST* inherit ManagedInstance, which implements these methods
|
||||
*/
|
||||
virtual void removeReference() = 0;
|
||||
virtual void addReference(int count = 1) = 0;
|
||||
|
||||
// We can not use local variables on the stack for variable length IEs as the record memory is copied only later in the sending process
|
||||
// We therefore need malloc'ed memory for encoding variable length IEs such as basicList
|
||||
uint8_t threeByteIndicator = 255;
|
||||
IpfixRecord::Data* variableLenData = NULL;
|
||||
unsigned int variableLenDataTotalBytes = 100;
|
||||
unsigned int variableLenDataCurrBytes = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -225,6 +238,11 @@ class TemplateInfo {
|
|||
public:
|
||||
typedef uint16_t TemplateId;
|
||||
|
||||
struct BasicListData {
|
||||
uint8_t semantic;
|
||||
InformationElement::IeInfo* fieldIe;
|
||||
};
|
||||
|
||||
enum SetId {
|
||||
UnknownSetId = -1,
|
||||
NetflowTemplate = 0,
|
||||
|
@ -241,6 +259,7 @@ class TemplateInfo {
|
|||
int32_t offset; /**< offset in bytes from a data start pointer. For internal purposes 0xFFFFFFFF is defined as yet unknown */
|
||||
int32_t privDataOffset; /**< offset in bytes from data start pointer for internal private data which is not exported via IPFIX */
|
||||
bool isVariableLength; /**< true if this field's length might change from record to record, false otherwise */
|
||||
struct BasicListData basicListData; /**< additional information for basic list IE */
|
||||
};
|
||||
|
||||
TemplateInfo();
|
||||
|
@ -324,7 +343,36 @@ class IpfixDataRecord : public IpfixRecord, public ManagedInstance<IpfixDataReco
|
|||
IpfixRecord::Data* data; /**< pointer to start of field data in @c message. Undefined after @c message goes out of scope. */
|
||||
|
||||
// redirector to reference remover of ManagedInstance
|
||||
virtual void removeReference() { ManagedInstance<IpfixDataRecord>::removeReference(); }
|
||||
virtual void removeReference() {
|
||||
|
||||
// Remove allocated vector data for basicList elements
|
||||
// NOTE: This can not be done in BaseHashtable::destroyBucket() as this leads to corrupted memory when sending in IpfixSender
|
||||
for (int i = 0; i < templateInfo->fieldCount; i++) {
|
||||
|
||||
// Free basicList memory
|
||||
if (templateInfo->fieldInfo[i].type == InformationElement::IeInfo(IPFIX_TYPEID_basicList, 0)) {
|
||||
IpfixRecord::Data* dst = (data + templateInfo->fieldInfo[i].offset);
|
||||
vector<void*>** listPtr = (vector<void*>**) dst;
|
||||
|
||||
if (*listPtr != NULL) {
|
||||
for (vector<void*>::const_iterator iter = (*listPtr)->begin(); iter != (*listPtr)->end(); iter++) {
|
||||
free(reinterpret_cast<IpfixRecord::Data*>(*iter));
|
||||
}
|
||||
|
||||
delete *listPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean previously used variable length data
|
||||
if (variableLenData != NULL) {
|
||||
variableLenDataCurrBytes = 0;
|
||||
free(variableLenData);
|
||||
variableLenData = NULL;
|
||||
}
|
||||
|
||||
ManagedInstance<IpfixDataRecord>::removeReference();
|
||||
}
|
||||
virtual void addReference(int count = 1) { ManagedInstance<IpfixDataRecord>::addReference(count); }
|
||||
};
|
||||
|
||||
|
|
|
@ -567,37 +567,13 @@ void IpfixSender::onDataRecord(IpfixDataRecord* record)
|
|||
|
||||
setTemplateId(my_template_id, record->dataLength);
|
||||
|
||||
// Set variable length data based on template estimation to avoid realloc
|
||||
initVarLenData(record, data);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < dataTemplateInfo->fieldCount; i++) {
|
||||
TemplateInfo::FieldInfo* fi = &dataTemplateInfo->fieldInfo[i];
|
||||
|
||||
/* Split IPv4 fields with length 5, i.e. fields with network mask attached */
|
||||
if ((fi->type.id == IPFIX_TYPEID_sourceIPv4Address) && (fi->type.length == 5)) {
|
||||
uint8_t* mask = &conversionRingbuffer[ringbufferPos++];
|
||||
*mask = 32 - *(uint8_t*)(data + fi->offset + 4);
|
||||
ipfix_put_data_field(ipfixExporter, data + fi->offset, 4);
|
||||
ipfix_put_data_field(ipfixExporter, mask, 1);
|
||||
}
|
||||
else if ((fi->type.id == IPFIX_TYPEID_destinationIPv4Address) && (fi->type.length == 5)) {
|
||||
uint8_t* mask = &conversionRingbuffer[ringbufferPos++];
|
||||
*mask = 32 - *(uint8_t*)(data + fi->offset + 4);
|
||||
ipfix_put_data_field(ipfixExporter, data + fi->offset, 4);
|
||||
ipfix_put_data_field(ipfixExporter, mask, 1);
|
||||
}
|
||||
else if ((export_protocol == NFV9_PROTOCOL) &&
|
||||
(fi->type.id == IPFIX_TYPEID_tcpControlBits) &&
|
||||
(fi->type.length != 1)) {
|
||||
// data is in network order, we want just the second byte as per RFC
|
||||
ipfix_put_data_field(ipfixExporter, data + fi->offset + 1, 1);
|
||||
}
|
||||
else {
|
||||
if (fi->type.id == IPFIX_TYPEID_packetDeltaCount && fi->type.length<=8) {
|
||||
uint64_t p = 0;
|
||||
memcpy(&p, data+fi->offset, fi->type.length);
|
||||
statPacketsInFlows += ntohll(p);
|
||||
}
|
||||
ipfix_put_data_field(ipfixExporter, data + fi->offset, fi->type.length);
|
||||
}
|
||||
TemplateInfo::FieldInfo* fi = &(dataTemplateInfo->fieldInfo[i]);
|
||||
addDataRecordValue(fi, data, record);
|
||||
}
|
||||
remainingSpace -= record->dataLength;
|
||||
statSentDataRecords++;
|
||||
|
@ -613,6 +589,122 @@ void IpfixSender::onDataRecord(IpfixDataRecord* record)
|
|||
ipfixMessageLock.unlock();
|
||||
}
|
||||
|
||||
void IpfixSender::addDataRecordValue(TemplateInfo::FieldInfo* fi, IpfixRecord::Data* data)
|
||||
{
|
||||
addDataRecordValue(fi, data, NULL);
|
||||
}
|
||||
|
||||
void IpfixSender::sendDataFromVarLenDataBuff(IpfixDataRecord* record, void* data, size_t len)
|
||||
{
|
||||
if (record->variableLenDataCurrBytes + len > record->variableLenDataTotalBytes) {
|
||||
THROWEXCEPTION("Not enough bytes allocated: %zu allocated, %zu needed", record->variableLenDataTotalBytes, record->variableLenDataCurrBytes + len);
|
||||
}
|
||||
|
||||
memcpy(&(record->variableLenData[record->variableLenDataCurrBytes]), data, len);
|
||||
ipfix_put_data_field(ipfixExporter, &record->variableLenData[record->variableLenDataCurrBytes], len);
|
||||
record->variableLenDataCurrBytes += len;
|
||||
}
|
||||
|
||||
void IpfixSender::initVarLenData(IpfixDataRecord* record, IpfixRecord::Data* data)
|
||||
{
|
||||
size_t varLenDataTotalSize = 0;
|
||||
|
||||
for (int i = 0; i < record->templateInfo->fieldCount; i++) {
|
||||
TemplateInfo::FieldInfo* fi = &(record->templateInfo->fieldInfo[i]);
|
||||
if (fi->type.id == IPFIX_TYPEID_basicList) {
|
||||
vector<void*>** listPtr = (vector<void*>**) (data + fi->offset);
|
||||
// Variable length IE length field (2B) + Semantic (1B) + Field ID (2B) + Element Length (2B) + (optional: Enterprise Number (3B)) + basicList Content (variable)
|
||||
// NOTE: Even though some of these fields are not copied to the variableLenData, we include them in the varLenDataTotalSize estimation
|
||||
varLenDataTotalSize += 2 + 1 + 2 + 2;
|
||||
varLenDataTotalSize += (fi->basicListData.fieldIe->enterprise == 0) ? 0 : 3;
|
||||
varLenDataTotalSize += ((*listPtr)->size()) * fi->basicListData.fieldIe->length;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory if variable length is present
|
||||
if (varLenDataTotalSize > 0) {
|
||||
if (record->variableLenData != NULL) {
|
||||
free(record->variableLenData);
|
||||
record->variableLenData = NULL;
|
||||
record->variableLenDataCurrBytes = 0;
|
||||
}
|
||||
record->variableLenDataTotalBytes = varLenDataTotalSize;
|
||||
record->variableLenData = (IpfixRecord::Data*) malloc(record->variableLenDataTotalBytes);
|
||||
}
|
||||
}
|
||||
|
||||
void IpfixSender::addDataRecordValue(TemplateInfo::FieldInfo* fi, IpfixRecord::Data* data, IpfixDataRecord* record)
|
||||
{
|
||||
|
||||
/* Split IPv4 fields with length 5, i.e. fields with network mask attached */
|
||||
if ((fi->type.id == IPFIX_TYPEID_sourceIPv4Address) && (fi->type.length == 5)) {
|
||||
uint8_t* mask = &conversionRingbuffer[ringbufferPos++];
|
||||
*mask = 32 - *(uint8_t*)(data + fi->offset + 4);
|
||||
ipfix_put_data_field(ipfixExporter, data + fi->offset, 4);
|
||||
ipfix_put_data_field(ipfixExporter, mask, 1);
|
||||
}
|
||||
else if ((fi->type.id == IPFIX_TYPEID_destinationIPv4Address) && (fi->type.length == 5)) {
|
||||
uint8_t* mask = &conversionRingbuffer[ringbufferPos++];
|
||||
*mask = 32 - *(uint8_t*)(data + fi->offset + 4); // TODO FIXME Valgrind complains due to uninitialized memory!!!
|
||||
ipfix_put_data_field(ipfixExporter, data + fi->offset, 4);
|
||||
ipfix_put_data_field(ipfixExporter, mask, 1);
|
||||
}
|
||||
else if ((export_protocol == NFV9_PROTOCOL) &&
|
||||
(fi->type.id == IPFIX_TYPEID_tcpControlBits) &&
|
||||
(fi->type.length != 1)) {
|
||||
// data is in network order, we want just the second byte as per RFC
|
||||
ipfix_put_data_field(ipfixExporter, data + fi->offset + 1, 1);
|
||||
}
|
||||
else if (fi->type.id == IPFIX_TYPEID_basicList) {
|
||||
vector<void*>** listPtr = (vector<void*>**) (data + fi->offset);
|
||||
|
||||
// Always use three-byte length encoding as RECOMMENDED in RFC 6313
|
||||
ipfix_put_data_field(ipfixExporter, &record->threeByteIndicator, 1);
|
||||
|
||||
// Need to allocate memory to store length etc. as they are not immediately sent over the wire
|
||||
// Is deallocated in IpfixRecord destructor
|
||||
if (record->variableLenData == NULL) {
|
||||
msg(MSG_ERROR, "Variable length data present but variableLenData not allocated.");
|
||||
}
|
||||
|
||||
// Semantic (1B) + Field ID (2B) + Element Length (2B) + (optional: Enterprise Number (3B)) + basicList Content (variable)
|
||||
uint16_t varLen = 1 + 2 + 2;
|
||||
varLen += (fi->basicListData.fieldIe->enterprise == 0) ? 0 : 3;
|
||||
varLen += ((*listPtr)->size()) * fi->basicListData.fieldIe->length;
|
||||
varLen = htons(varLen);
|
||||
|
||||
sendDataFromVarLenDataBuff(record, &varLen, sizeof(varLen));
|
||||
|
||||
|
||||
// Var length field
|
||||
// Semantic
|
||||
ipfix_put_data_field(ipfixExporter, (void *) &fi->basicListData.semantic, 1);
|
||||
|
||||
// Field ID
|
||||
// TODO: Distinguish between enterprise=0
|
||||
uint16_t fieldId = htons(fi->basicListData.fieldIe->id);
|
||||
sendDataFromVarLenDataBuff(record, &fieldId, sizeof(fieldId));
|
||||
|
||||
// Field length
|
||||
uint16_t fieldLen = htons(fi->basicListData.fieldIe->length);
|
||||
sendDataFromVarLenDataBuff(record, &fieldLen, sizeof(fieldLen));
|
||||
|
||||
// Add basicList content
|
||||
for (vector<void*>::const_iterator iter = (*listPtr)->begin(); iter != (*listPtr)->end(); iter++) {
|
||||
IpfixRecord::Data* elem = reinterpret_cast<IpfixRecord::Data*>(*iter);
|
||||
sendDataFromVarLenDataBuff(record, elem, ntohs(fieldLen));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (fi->type.id == IPFIX_TYPEID_packetDeltaCount && fi->type.length<=8) {
|
||||
uint64_t p = 0;
|
||||
memcpy(&p, data+fi->offset, fi->type.length);
|
||||
statPacketsInFlows += ntohll(p);
|
||||
}
|
||||
ipfix_put_data_field(ipfixExporter, data + fi->offset, fi->type.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks registered Templates if those are to be destroyed and destroys them if needed
|
||||
*/
|
||||
|
|
|
@ -96,6 +96,10 @@ private:
|
|||
void registerTimeout();
|
||||
void onSendRecordsTimeout(void);
|
||||
void registerBeatTimeout();
|
||||
void addDataRecordValue(TemplateInfo::FieldInfo*, IpfixRecord::Data*);
|
||||
void addDataRecordValue(TemplateInfo::FieldInfo*, IpfixRecord::Data*, IpfixDataRecord*);
|
||||
void sendDataFromVarLenDataBuff(IpfixDataRecord*, void*, size_t);
|
||||
void initVarLenData(IpfixDataRecord*, IpfixRecord::Data*);
|
||||
|
||||
TemplateInfo::TemplateId getUnusedTemplateId();
|
||||
|
||||
|
|
|
@ -120,6 +120,9 @@ Rule::Field* AggregatorBaseCfg::readNonFlowKeyRule(XMLElement* e)
|
|||
ruleField->type.enterprise = ie.getEnterpriseNumber();
|
||||
ruleField->type.length = ie.getIeLength();
|
||||
|
||||
ruleField->semantic = ie.getSemantic();
|
||||
ruleField->fieldIe = ie.getFieldIe();
|
||||
|
||||
if (ie.getAutoAddV4PrefixLength() &&
|
||||
(ruleField->type == InformationElement::IeInfo(IPFIX_TYPEID_sourceIPv4Address, 0) ||
|
||||
ruleField->type == InformationElement::IeInfo(IPFIX_TYPEID_destinationIPv4Address, 0))) {
|
||||
|
|
|
@ -122,7 +122,19 @@ void BaseHashtable::createDataTemplate(Rule* rule)
|
|||
fi->type = rf->type;
|
||||
fi->offset = fieldLength;
|
||||
fi->privDataOffset = 0;
|
||||
fieldLength += fi->type.length;
|
||||
fi->isVariableLength = (fi->type.length == 65535);
|
||||
|
||||
if (!fi->isVariableLength) {
|
||||
fieldLength += fi->type.length;
|
||||
}
|
||||
// Variable length fields: Extract real length information
|
||||
else if (fi->type == InformationElement::IeInfo(IPFIX_TYPEID_basicList, 0)) {
|
||||
fi->basicListData.semantic = rf->semantic;
|
||||
fi->basicListData.fieldIe = new InformationElement::IeInfo(rf->fieldIe);
|
||||
|
||||
// Length is one pointer, as we are storing data in dynamically allocated vector (i.e. pointer to vector)
|
||||
fieldLength += sizeof(vector<void*>*);
|
||||
}
|
||||
fieldModifier[dataTemplate->fieldCount - 1] = rf->modifier;
|
||||
}
|
||||
}
|
||||
|
@ -234,6 +246,9 @@ void BaseHashtable::exportBucket(HashtableBucket* bucket)
|
|||
*/
|
||||
void BaseHashtable::destroyBucket(HashtableBucket* bucket)
|
||||
{
|
||||
// NOTE: If we free basicList elements here we do get incorrect pointers in IpfixSender!
|
||||
// Therefore we free basicList memory in IpfixDataRecord::removeReference()
|
||||
|
||||
delete bucket;
|
||||
}
|
||||
|
||||
|
@ -335,6 +350,7 @@ int BaseHashtable::isToBeAggregated(InformationElement::IeInfo& type)
|
|||
case IPFIX_TYPEID_droppedOctetDeltaCount:
|
||||
case IPFIX_TYPEID_droppedPacketDeltaCount:
|
||||
case IPFIX_TYPEID_tcpControlBits:
|
||||
case IPFIX_TYPEID_basicList:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -126,6 +126,26 @@ void PacketHashtable::copyDataNanoseconds(CopyFuncParameters* cfp)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
void PacketHashtable::copyDataBasicList(CopyFuncParameters* cfp)
|
||||
{
|
||||
ExpFieldData* efd = cfp->efd;
|
||||
IpfixRecord::Data* dst = cfp->dst+efd->dstIndex;
|
||||
vector<void*>** listPtr = (vector<void*>**) dst;
|
||||
size_t len = efd->typeSpecData.basicList->fieldIe->length;
|
||||
|
||||
// Initialize vector
|
||||
if (*listPtr == NULL) {
|
||||
*listPtr = new vector<void*>;
|
||||
} else {
|
||||
THROWEXCEPTION("basicList vector was initially not NULL.");
|
||||
}
|
||||
|
||||
// Is called to insert first element
|
||||
void* toInsert = malloc(len);
|
||||
memcpy(toInsert, cfp->src, len);
|
||||
|
||||
(*listPtr)->push_back((void*) toInsert);
|
||||
}
|
||||
void PacketHashtable::copyDataTransportOctets(CopyFuncParameters* cfp)
|
||||
{
|
||||
const Packet* p = cfp->packet;
|
||||
|
@ -349,6 +369,9 @@ void (*PacketHashtable::getCopyDataFunction(const ExpFieldData* efd))(CopyFuncPa
|
|||
}
|
||||
break;
|
||||
|
||||
case IPFIX_TYPEID_basicList:
|
||||
break;
|
||||
|
||||
default:
|
||||
THROWEXCEPTION("type unhandled by Packet Aggregator: %s", efd->typeId.toString().c_str());
|
||||
break;
|
||||
|
@ -416,6 +439,8 @@ void (*PacketHashtable::getCopyDataFunction(const ExpFieldData* efd))(CopyFuncPa
|
|||
} else if (efd->typeId == IeInfo(IPFIX_TYPEID_flowStartNanoseconds, 0) ||
|
||||
efd->typeId == IeInfo(IPFIX_TYPEID_flowEndNanoseconds, 0)) {
|
||||
return copyDataNanoseconds;
|
||||
} else if (efd->typeId == IeInfo(IPFIX_TYPEID_basicList, 0)) {
|
||||
return copyDataBasicList;
|
||||
} else if (efd->typeId.enterprise & IPFIX_PEN_reverse) {
|
||||
// ATTENTION: we treat all reverse elements the same: we set them to zero
|
||||
return copyDataSetZero;
|
||||
|
@ -440,7 +465,7 @@ void (*PacketHashtable::getCopyDataFunction(const ExpFieldData* efd))(CopyFuncPa
|
|||
return copyDataGreaterLengthNoMod;
|
||||
}
|
||||
} else {
|
||||
THROWEXCEPTION("target buffer too small. Expected buffer %s of length %d", efd->typeId.toString().c_str(), efd->srcLength);
|
||||
THROWEXCEPTION("target buffer too small. Expected buffer %s of length %d, but got %d", efd->typeId.toString().c_str(), efd->srcLength, efd->dstLength);
|
||||
}
|
||||
|
||||
THROWEXCEPTION("this line should never be reached");
|
||||
|
@ -538,7 +563,12 @@ uint8_t PacketHashtable::getRawPacketFieldLength(const IeInfo& type)
|
|||
* @param p pointer to raw packet
|
||||
* @returns offset (in bytes) at which the data for the given field is located in the raw packet
|
||||
*/
|
||||
int32_t PacketHashtable::getRawPacketFieldOffset(const IeInfo& type, const Packet* p)
|
||||
int32_t PacketHashtable::getRawPacketFieldOffset(const IeInfo& type, const Packet* p)
|
||||
{
|
||||
return getRawPacketFieldOffset(type, p, NULL);
|
||||
}
|
||||
|
||||
int32_t PacketHashtable::getRawPacketFieldOffset(const IeInfo& type, const Packet* p, const ExpFieldData::TypeSpecificData* typeSpecData)
|
||||
{
|
||||
if (type.enterprise==0 || type.enterprise==IPFIX_PEN_reverse) {
|
||||
switch (type.id) {
|
||||
|
@ -627,6 +657,12 @@ int32_t PacketHashtable::getRawPacketFieldOffset(const IeInfo& type, const Packe
|
|||
DPRINTFL(MSG_VDEBUG, "given id is %s, protocol is %d, but expected was %d", type.toString().c_str(), p->ipProtocolType, Packet::TCP);
|
||||
}
|
||||
break;
|
||||
|
||||
case IPFIX_TYPEID_basicList:
|
||||
// Find offset for field inside basicList
|
||||
return getRawPacketFieldOffset(*typeSpecData->basicList->fieldIe, p);
|
||||
break;
|
||||
|
||||
default:
|
||||
THROWEXCEPTION("PacketHashtable: raw id offset into packet header for typeid %s is unkown, failed to determine raw packet offset", type.toString().c_str());
|
||||
break;
|
||||
|
@ -681,6 +717,7 @@ bool PacketHashtable::isRawPacketPtrVariable(const IeInfo& type)
|
|||
case IPFIX_TYPEID_tcpControlBits:
|
||||
case IPFIX_TYPEID_sourceMacAddress:
|
||||
case IPFIX_TYPEID_destinationMacAddress:
|
||||
case IPFIX_TYPEID_basicList:
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -717,16 +754,23 @@ void PacketHashtable::fillExpFieldData(ExpFieldData* efd, TemplateInfo::FieldInf
|
|||
DPRINTFL(MSG_VDEBUG, "called for type id %s", hfi->type.toString().c_str());
|
||||
efd->typeId = hfi->type;
|
||||
efd->dstIndex = hfi->offset;
|
||||
efd->dstLength = hfi->type.length;
|
||||
efd->srcLength = getRawPacketFieldLength(hfi->type);
|
||||
efd->modifier = fieldModifier;
|
||||
efd->varSrcIdx = isRawPacketPtrVariable(hfi->type);
|
||||
|
||||
IeInfo ie = hfi->type;
|
||||
if (hfi->type == IeInfo(IPFIX_TYPEID_basicList, 0)) {
|
||||
efd->typeSpecData.basicList = &hfi->basicListData;
|
||||
ie = *efd->typeSpecData.basicList->fieldIe;
|
||||
}
|
||||
|
||||
efd->dstLength = ie.length;
|
||||
efd->srcLength = getRawPacketFieldLength(ie);
|
||||
efd->varSrcIdx = isRawPacketPtrVariable(ie);
|
||||
efd->privDataOffset = hfi->privDataOffset;
|
||||
|
||||
// initialize static source index, if current field does not have a variable pointer
|
||||
if (!efd->varSrcIdx) {
|
||||
Packet p; // not good: create temporary packet just for initializing our optimization structure
|
||||
efd->srcIndex = getRawPacketFieldOffset(hfi->type, &p);
|
||||
efd->srcIndex = getRawPacketFieldOffset(ie, &p, &efd->typeSpecData);
|
||||
}
|
||||
|
||||
// special case for masked IPs: those contain variable pointers, if they are masked
|
||||
|
@ -806,6 +850,7 @@ bool PacketHashtable::typeAvailable(const IeInfo& type)
|
|||
case IPFIX_TYPEID_bgpSourceAsNumber:
|
||||
case IPFIX_TYPEID_bgpDestinationAsNumber:
|
||||
case IPFIX_TYPEID_totalLengthIPv4:
|
||||
case IPFIX_TYPEID_basicList:
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -1192,6 +1237,21 @@ void PacketHashtable::aggregateField(const ExpFieldData* efd, HashtableBucket* h
|
|||
}
|
||||
break;
|
||||
|
||||
case IPFIX_TYPEID_basicList:
|
||||
// Is called to insert all but first elements
|
||||
size_t len;
|
||||
void* toInsert;
|
||||
vector<void*>** listPtr;
|
||||
|
||||
len = efd->typeSpecData.basicList->fieldIe->length;
|
||||
toInsert = malloc(len);
|
||||
listPtr = (vector<void*>**) baseData;
|
||||
|
||||
memcpy(toInsert, deltaData, len);
|
||||
(*listPtr)->push_back((void*) toInsert);
|
||||
|
||||
break;
|
||||
|
||||
// no other types needed, as this is only for raw field input
|
||||
default:
|
||||
DPRINTF("non-aggregatable type: %s", efd->typeId.toString().c_str());
|
||||
|
@ -1483,7 +1543,7 @@ void PacketHashtable::updatePointers(const Packet* p)
|
|||
}
|
||||
if (dodefault) {
|
||||
// standard procedure for transport header fields
|
||||
efd->srcIndex = getRawPacketFieldOffset(efd->typeId, p);
|
||||
efd->srcIndex = getRawPacketFieldOffset(efd->typeId, p, &efd->typeSpecData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,15 +34,7 @@
|
|||
|
||||
class PacketHashtable : public BaseHashtable
|
||||
{
|
||||
public:
|
||||
PacketHashtable(Source<IpfixRecord*>* recordsource, Rule* rule,
|
||||
uint16_t inactiveTimeout, uint16_t activeTimeout, uint8_t hashbits);
|
||||
virtual ~PacketHashtable();
|
||||
|
||||
void aggregatePacket(Packet* p);
|
||||
|
||||
static uint8_t getRawPacketFieldLength(const InformationElement::IeInfo& type);
|
||||
static int32_t getRawPacketFieldOffset(const InformationElement::IeInfo& type, const Packet* p);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -104,6 +96,7 @@ private:
|
|||
uint32_t fpaLenOffset; /**< offset from start of record data to IPFIX_ETYPE_FRONTPAYLOADLEN, 0xFFFFFFFF if not used */
|
||||
bool dpa; /**< set to true, if DPA was activated */
|
||||
} frontPayload;
|
||||
TemplateInfo::BasicListData *basicList;
|
||||
} typeSpecData;
|
||||
|
||||
};
|
||||
|
@ -147,6 +140,7 @@ private:
|
|||
static void copyDataSetZero(CopyFuncParameters* cfp);
|
||||
static void copyDataMaxPacketGap(CopyFuncParameters* cfp);
|
||||
static void copyDataNanoseconds(CopyFuncParameters* cfp);
|
||||
static void copyDataBasicList(CopyFuncParameters* cfp);
|
||||
static void copyDataDummy(CopyFuncParameters* cfp);
|
||||
static void copyDataTransportOctets(CopyFuncParameters* cfp);
|
||||
static void aggregateFrontPayload(IpfixRecord::Data* bucket, HashtableBucket* hbucket, const Packet* src,
|
||||
|
@ -169,6 +163,18 @@ private:
|
|||
void updateBucketData(HashtableBucket* bucket);
|
||||
uint32_t getDstOffset(const InformationElement::IeInfo& ietype);
|
||||
bool mustExpireBucket(const HashtableBucket* bucket, const Packet* p);
|
||||
void destroyExpFieldData(ExpFieldData* efd, int numFields); // TODO: Do we need this?
|
||||
|
||||
public:
|
||||
PacketHashtable(Source<IpfixRecord*>* recordsource, Rule* rule,
|
||||
uint16_t inactiveTimeout, uint16_t activeTimeout, uint8_t hashbits);
|
||||
virtual ~PacketHashtable();
|
||||
|
||||
void aggregatePacket(Packet* p);
|
||||
|
||||
static uint8_t getRawPacketFieldLength(const InformationElement::IeInfo& type);
|
||||
static int32_t getRawPacketFieldOffset(const InformationElement::IeInfo& type, const Packet* p);
|
||||
static int32_t getRawPacketFieldOffset(const InformationElement::IeInfo& type, const Packet* p, const ExpFieldData::TypeSpecificData* typeSpecData);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -49,6 +49,9 @@ class Rule : private PrintHelpers {
|
|||
type.enterprise = 0;
|
||||
pattern = NULL;
|
||||
modifier = Rule::Field::DISCARD;
|
||||
|
||||
semantic = IPFIX_STRUCTURED_TYPE_SEMANTIC_undefined;
|
||||
fieldIe = NULL;
|
||||
}
|
||||
|
||||
~Field() {
|
||||
|
@ -66,6 +69,10 @@ class Rule : private PrintHelpers {
|
|||
InformationElement::IeInfo type; /**< field type this Rule::Field refers to */
|
||||
IpfixRecord::Data* pattern; /**< pattern to match fields against to determine applicability of a rule. A pattern of NULL means no pattern needs to be matched for this field */
|
||||
Rule::Field::Modifier modifier; /**< modifier to apply to the corresponding field if this rule is matched */
|
||||
|
||||
// basicList specific
|
||||
uint8_t semantic;
|
||||
const ipfix_identifier* fieldIe;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue