Skip to content

Commit 4ccdd42

Browse files
committed
Merge branch 'unirec-exporter-odid-ip' into 'master'
Extend UniRec output with ODID and EXPORTER_IP See merge request monitoring/ipfixcol2!10
2 parents 869c6ce + 6e854a6 commit 4ccdd42

File tree

7 files changed

+197
-12
lines changed

7 files changed

+197
-12
lines changed

extra_plugins/output/unirec/README.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,7 @@ and egress flows. For this reason, the lowest bit of IPFIX field ``iana:ingressI
270270
(PEN: 0, ID: 10) is copied to the particular UniRec field (Nemea modules expects that
271271
1 = ingress flow and 0 = egress flow).
272272

273+
Other UniRec specific fields available are ``ODID`` and ``EXPORTER_IP``. The information for these
274+
fields is extracted from the IPFIX message session. The ``ODID`` contains raw Observation Domain ID
275+
of the exporter and ``EXPORTER_IP`` carries exporter IP address to identify which probe the flow
276+
was observed on.

extra_plugins/output/unirec/config/unirec-elements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ TIME_FIRST time e0id150,e0id152,e0id154,e0id156
3636
TIME_LAST time e0id151,e0id153,e0id155,e0id157 # Time of the last packet of a flow
3737
DIR_BIT_FIELD uint8 _internal_dbf_ # Bit field used for determining incoming/outgoing flow (1 => Incoming, 0 => Outgoing)
3838
LINK_BIT_FIELD uint64 _internal_lbf_ # Bit field of links on which was flow seen
39+
ODID uint32 _internal_odid_ # Observation Domain ID (ODID) of exporter
40+
EXPORTER_IP ipaddr _internal_exporter_ip_ # IP address of exporter from exporting session
3941

4042
SRC_MAC macaddr e0id56
4143
DST_MAC macaddr e0id80

extra_plugins/output/unirec/src/map.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ map_elem_get_internal(const char *elem)
232232
return MAP_SRC_INTERNAL_LBF;
233233
} else if (strcmp(elem, "_internal_dbf_") == 0) {
234234
return MAP_SRC_INTERNAL_DBF;
235+
} else if (strcmp(elem, "_internal_odid_") == 0) {
236+
return MAP_SRC_INTERNAL_ODID;
237+
} else if (strcmp(elem, "_internal_exporter_ip_") == 0) {
238+
return MAP_SRC_INTERNAL_EXPORTER_IP;
235239
} else {
236240
return MAP_SRC_INVALID;
237241
}

extra_plugins/output/unirec/src/map.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ enum MAP_SRC {
5858
/** Internal "link bit field" converter */
5959
MAP_SRC_INTERNAL_LBF,
6060
/** Internal "dir bit field" converter */
61-
MAP_SRC_INTERNAL_DBF
61+
MAP_SRC_INTERNAL_DBF,
62+
/** Internal "odid field" converter */
63+
MAP_SRC_INTERNAL_ODID,
64+
/** Internal "exporter ip field" converter */
65+
MAP_SRC_INTERNAL_EXPORTER_IP
6266
};
6367

6468
enum MAP_FLAGS {

extra_plugins/output/unirec/src/translator.c

Lines changed: 178 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ struct translator_s {
137137
} progress; /**< Auxiliary conversion variables */
138138

139139
struct {
140-
/** IPFIX Message header */
141-
const struct fds_ipfix_msg_hdr *hdr;
140+
/** IPFIX Message context */
141+
const struct ipx_msg_ctx *ctx;
142142
} msg_context; /**< IPFIX context of the record to translate */
143143

144144
struct {
@@ -151,6 +151,18 @@ struct translator_s {
151151
int field_size; /**< UniRec field size */
152152
ur_field_id_t field_id; /**< UniRec field ID */
153153
} lbf; /**< ODID to 'link bit field' converter */
154+
struct
155+
{
156+
bool en; /**< Enabled/disabled */
157+
int req_idx; /**< Index in the template */
158+
ur_field_id_t field_id; /**< UniRec field ID */
159+
} odid; /**< ODID from IPFIX Message header */
160+
struct
161+
{
162+
bool en; /**< Enabled/disabled */
163+
int req_idx; /**< Index in the template */
164+
ur_field_id_t field_id; /**< UniRec field ID */
165+
} exporter_ip; /**< Exporter IP address from message session */
154166
} extra_conv; /**< Special internal conversion functions */
155167
};
156168

@@ -802,12 +814,12 @@ translate_internal_dbf(translator_t *trans, const struct translator_rec *rec,
802814
static int
803815
translate_internal_lbf(translator_t *trans)
804816
{
805-
if (!trans->msg_context.hdr) {
806-
return 1; // Message header is not available!
817+
if (!trans->msg_context.ctx) {
818+
return 1; // Message context is not available!
807819
}
808820

809821
// Get the ODID value
810-
uint32_t odid = ntohl(trans->msg_context.hdr->odid);
822+
uint32_t odid = trans->msg_context.ctx->odid;
811823

812824
// Store the value is 'link bit field'
813825
ur_field_type_t ur_id = trans->extra_conv.lbf.field_id;
@@ -833,6 +845,83 @@ translate_internal_lbf(translator_t *trans)
833845
return 0;
834846
}
835847

848+
/**
849+
* \brief Convert (fill) ODID field
850+
*
851+
* \note This function uses a message context configured by the user. It's independent on the
852+
* content of an IPFIX record.
853+
* \param[in] trans Internal translator structure
854+
* \return On success returns 0. Otherwise returns non-zero value!
855+
*/
856+
static int
857+
translate_internal_odid(translator_t *trans)
858+
{
859+
if (!trans->msg_context.ctx) {
860+
return 1; // Message context is not available!
861+
}
862+
863+
// Get the ODID value
864+
uint32_t odid = trans->msg_context.ctx->odid;
865+
866+
ur_field_type_t ur_id = trans->extra_conv.odid.field_id;
867+
void *field_ptr = ur_get_ptr_by_id(trans->record.ur_tmplt, trans->record.data, ur_id);
868+
869+
*((uint32_t *) field_ptr) = odid;
870+
871+
return 0;
872+
}
873+
874+
/**
875+
* \brief Convert (fill) EXPORTER_IP field with IPv4 or IPv6 address from IPFIX
876+
* message session.
877+
*
878+
* \note This function uses a message context configured by the user. It's independent on the
879+
* content of an IPFIX record.
880+
* \param[in] trans Internal translator structure
881+
* \return On success returns 0. Otherwise returns non-zero value!
882+
*/
883+
static int
884+
translate_internal_exporter_ip(translator_t *trans)
885+
{
886+
if (!trans->msg_context.ctx) {
887+
return 1; // Message context is not available!
888+
}
889+
890+
const struct ipx_session *session = trans->msg_context.ctx->session;
891+
892+
const struct ipx_session_net *session_net;
893+
switch (session->type)
894+
{
895+
case FDS_SESSION_UDP:
896+
session_net = &session->udp.net;
897+
break;
898+
case FDS_SESSION_TCP:
899+
session_net = &session->tcp.net;
900+
break;
901+
case FDS_SESSION_SCTP:
902+
session_net = &session->sctp.net;
903+
break;
904+
default:
905+
// Uncompatible type of message session. E.g. messages from file.
906+
return 1;
907+
}
908+
909+
// Get pointer to save result IP
910+
ur_field_type_t ur_id = trans->extra_conv.exporter_ip.field_id;
911+
void *field_ptr = ur_get_ptr_by_id(trans->record.ur_tmplt, trans->record.data, ur_id);
912+
913+
if (session->udp.net.l3_proto == AF_INET) {
914+
*((ip_addr_t *) field_ptr) = ip_from_4_bytes_be((char *) &session_net->addr_src.ipv4.s_addr);
915+
} else if (session->udp.net.l3_proto == AF_INET6) {
916+
*((ip_addr_t *) field_ptr) = ip_from_16_bytes_be((char *) session_net->addr_src.ipv6.s6_addr);
917+
} else {
918+
// Unknown IP protocol
919+
return 1;
920+
}
921+
922+
return 0;
923+
}
924+
836925
/**
837926
* \brief Get size of UniRec numeric data types
838927
* \param type UniRec data types
@@ -1451,6 +1540,62 @@ translator_table_fill_internal(translator_t *trans, const struct map_rec *map_re
14511540
return IPX_OK;
14521541
}
14531542

1543+
/* Internal "ODID field" function
1544+
* Implemented as a special converter that must be enabled in the translator because
1545+
* ODID is not defined in the IPFIX record but in the IPFIX Message header
1546+
*/
1547+
if (src == MAP_SRC_INTERNAL_ODID) {
1548+
if (trans->extra_conv.odid.en) {
1549+
// The function is already enabled!
1550+
IPX_CTX_ERROR(trans->ctx, "Internal 'odid field' function can be mapped only "
1551+
"to one UniRec field!", '\0');
1552+
return IPX_ERR_DENIED;
1553+
}
1554+
1555+
if (ur_type != UR_TYPE_UINT32) {
1556+
IPX_CTX_ERROR(trans->ctx, "Internal 'odid field' function supports only UniRec "
1557+
"uint32 type but UniRec field '%s' is '%s'!", map_rec->unirec.name,
1558+
map_rec->unirec.type_str);
1559+
return IPX_ERR_DENIED;
1560+
}
1561+
1562+
// Enable the internal converter
1563+
trans->extra_conv.odid.en = true;
1564+
trans->extra_conv.odid.req_idx = field_idx;
1565+
trans->extra_conv.odid.field_id = ur_id;
1566+
IPX_CTX_DEBUG(trans->ctx, "Added conversion from internal 'odid field' to UniRec '%s'",
1567+
map_rec->unirec.name);
1568+
return IPX_ERR_NOTFOUND; // Do NOT add the record!
1569+
}
1570+
1571+
/* Internal "exporter_ip field" function
1572+
* Implemented as a special converter that must be enabled in the translator because
1573+
* IPFIX Message session is not defined in IPFIX record
1574+
*/
1575+
if (src == MAP_SRC_INTERNAL_EXPORTER_IP) {
1576+
if (trans->extra_conv.exporter_ip.en) {
1577+
// The function is already enabled!
1578+
IPX_CTX_ERROR(trans->ctx, "Internal 'exporter_ip field' function can be mapped only "
1579+
"to one UniRec field!", '\0');
1580+
return IPX_ERR_DENIED;
1581+
}
1582+
1583+
if (ur_type != UR_TYPE_IP) {
1584+
IPX_CTX_ERROR(trans->ctx, "Internal 'exporter_ip field' function supports only UniRec "
1585+
"ipaddress type but UniRec field '%s' is '%s'!", map_rec->unirec.name,
1586+
map_rec->unirec.type_str);
1587+
return IPX_ERR_DENIED;
1588+
}
1589+
1590+
// Enable the internal converter
1591+
trans->extra_conv.exporter_ip.en = true;
1592+
trans->extra_conv.exporter_ip.req_idx = field_idx;
1593+
trans->extra_conv.exporter_ip.field_id = ur_id;
1594+
IPX_CTX_DEBUG(trans->ctx, "Added conversion from internal 'exporter_ip field' to UniRec '%s'",
1595+
map_rec->unirec.name);
1596+
return IPX_ERR_NOTFOUND; // Do NOT add the record!
1597+
}
1598+
14541599
IPX_CTX_ERROR(trans->ctx, "Unimplemented internal mapping function!", '\0');
14551600
return IPX_ERR_DENIED;
14561601
}
@@ -1598,6 +1743,32 @@ translator_call_internals(translator_t *trans)
15981743
}
15991744
}
16001745

1746+
if (trans->extra_conv.odid.en) {
1747+
// Call internal 'odid field' converter
1748+
int field_idx = trans->extra_conv.odid.req_idx;
1749+
if (translate_internal_odid(trans) == 0) {
1750+
// Success
1751+
trans->progress.req_fields[field_idx] = 0; // Filled!
1752+
converted_fields++;
1753+
} else {
1754+
IPX_CTX_WARNING(trans->ctx, "Internal function 'odid field' failed to fill "
1755+
"UniRec field '%s'", trans->progress.req_names[field_idx]);
1756+
}
1757+
}
1758+
1759+
if (trans->extra_conv.exporter_ip.en) {
1760+
// Call internal 'exporter_ip field' converter
1761+
int field_idx = trans->extra_conv.exporter_ip.req_idx;
1762+
if (translate_internal_exporter_ip(trans) == 0) {
1763+
// Success
1764+
trans->progress.req_fields[field_idx] = 0; // Filled!
1765+
converted_fields++;
1766+
} else {
1767+
IPX_CTX_WARNING(trans->ctx, "Internal function 'exporter_ip field' failed to fill "
1768+
"UniRec field '%s'", trans->progress.req_names[field_idx]);
1769+
}
1770+
}
1771+
16011772
return converted_fields;
16021773
}
16031774

@@ -1634,9 +1805,9 @@ translator_destroy(translator_t *trans)
16341805
}
16351806

16361807
void
1637-
translator_set_context(translator_t *trans, const struct fds_ipfix_msg_hdr *hdr)
1808+
translator_set_context(translator_t *trans, const struct ipx_msg_ctx *ctx)
16381809
{
1639-
trans->msg_context.hdr = hdr;
1810+
trans->msg_context.ctx = ctx;
16401811
}
16411812

16421813
const void *

extra_plugins/output/unirec/src/translator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ translator_destroy(translator_t *trans);
7878
* This function MUST be called before processing each IPFIX Message to set proper record
7979
* parameters. The message header is required for determine ODID or other parameters.
8080
* \param[in] trans Translator instance
81-
* \param[in] hdr IPFIX message header
81+
* \param[in] ctx IPFIX message context
8282
*/
8383
void
84-
translator_set_context(translator_t *trans, const struct fds_ipfix_msg_hdr *hdr);
84+
translator_set_context(translator_t *trans, const struct ipx_msg_ctx *ctx);
8585

8686
/**
8787
* \brief Convert a IPFIX record to an UniRec message

extra_plugins/output/unirec/src/unirecplugin.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,8 @@ ipx_plugin_process(ipx_ctx_t *ctx, void *cfg, ipx_msg_t *msg)
344344
const void *msg_data = NULL;
345345

346346
ipx_msg_ipfix_t *ipfix = ipx_msg_base2ipfix(msg);
347-
const uint8_t *ipfix_raw_msg = ipx_msg_ipfix_get_packet(ipfix);
348-
translator_set_context(conf->trans, (const struct fds_ipfix_msg_hdr *) ipfix_raw_msg);
347+
const struct ipx_msg_ctx *ipfix_msg_ctx = ipx_msg_ipfix_get_ctx(ipfix);
348+
translator_set_context(conf->trans, ipfix_msg_ctx);
349349

350350
const uint32_t rec_cnt = ipx_msg_ipfix_get_drec_cnt(ipfix);
351351
for (uint32_t i = 0; i < rec_cnt; i++) {

0 commit comments

Comments
 (0)