Implement basicList IE in exporting process

master
Oliver Gasser 2017-12-15 18:15:57 +01:00
parent 5177babf46
commit 5625fe4ff1
13 changed files with 373 additions and 51 deletions

View File

@ -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

View File

@ -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

View File

@ -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_*/

View File

@ -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");

View File

@ -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);

View File

@ -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); }
};

View File

@ -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
*/

View File

@ -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();

View File

@ -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))) {

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);
};

View File

@ -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;
};