|
| 1 | +/** |
| 2 | + * @file |
| 3 | + * @author Michal Sedlak <[email protected]> |
| 4 | + * @brief IPFIX field |
| 5 | + * |
| 6 | + * Copyright: (C) 2024 CESNET, z.s.p.o. |
| 7 | + * SPDX-License-Identifier: BSD-3-Clause |
| 8 | + */ |
| 9 | + |
| 10 | +#include <aggregator/ipfixField.hpp> |
| 11 | +#include <common/fieldView.hpp> |
| 12 | + |
| 13 | +#include <cstring> |
| 14 | + |
| 15 | +namespace fdsdump { |
| 16 | +namespace aggregator { |
| 17 | + |
| 18 | +IpfixField::IpfixField(const fds_iemgr_elem &elem) |
| 19 | +{ |
| 20 | + m_pen = elem.scope->pen; |
| 21 | + m_id = elem.id; |
| 22 | + |
| 23 | + DataType data_type = DataType::Unassigned; |
| 24 | + switch (elem.data_type) { |
| 25 | + case FDS_ET_UNSIGNED_8: |
| 26 | + data_type = DataType::Unsigned8; |
| 27 | + break; |
| 28 | + case FDS_ET_UNSIGNED_16: |
| 29 | + data_type = DataType::Unsigned16; |
| 30 | + break; |
| 31 | + case FDS_ET_UNSIGNED_32: |
| 32 | + data_type = DataType::Unsigned32; |
| 33 | + break; |
| 34 | + case FDS_ET_UNSIGNED_64: |
| 35 | + data_type = DataType::Unsigned64; |
| 36 | + break; |
| 37 | + case FDS_ET_SIGNED_8: |
| 38 | + data_type = DataType::Signed8; |
| 39 | + break; |
| 40 | + case FDS_ET_SIGNED_16: |
| 41 | + data_type = DataType::Signed16; |
| 42 | + break; |
| 43 | + case FDS_ET_SIGNED_32: |
| 44 | + data_type = DataType::Signed32; |
| 45 | + break; |
| 46 | + case FDS_ET_SIGNED_64: |
| 47 | + data_type = DataType::Signed64; |
| 48 | + break; |
| 49 | + case FDS_ET_IPV4_ADDRESS: |
| 50 | + data_type = DataType::IPv4Address; |
| 51 | + break; |
| 52 | + case FDS_ET_IPV6_ADDRESS: |
| 53 | + data_type = DataType::IPv6Address; |
| 54 | + break; |
| 55 | + case FDS_ET_STRING: |
| 56 | + data_type = DataType::String128B; |
| 57 | + break; |
| 58 | + case FDS_ET_OCTET_ARRAY: |
| 59 | + data_type = DataType::Octets128B; |
| 60 | + break; |
| 61 | + case FDS_ET_DATE_TIME_MILLISECONDS: |
| 62 | + case FDS_ET_DATE_TIME_MICROSECONDS: |
| 63 | + case FDS_ET_DATE_TIME_NANOSECONDS: |
| 64 | + case FDS_ET_DATE_TIME_SECONDS: |
| 65 | + data_type = DataType::DateTime; |
| 66 | + break; |
| 67 | + case FDS_ET_MAC_ADDRESS: |
| 68 | + data_type = DataType::MacAddress; |
| 69 | + break; |
| 70 | + default: |
| 71 | + throw std::invalid_argument("unsupported IPFIX field data type"); |
| 72 | + } |
| 73 | + |
| 74 | + set_data_type(data_type); |
| 75 | + |
| 76 | + set_name(elem.name); |
| 77 | +} |
| 78 | + |
| 79 | +bool |
| 80 | +IpfixField::load(FlowContext &ctx, Value &value) const |
| 81 | +{ |
| 82 | + fds_drec_field drec_field; |
| 83 | + if (!ctx.find_field(m_pen, m_id, drec_field)) { |
| 84 | + return false; |
| 85 | + } |
| 86 | + |
| 87 | + switch (data_type()) { |
| 88 | + case DataType::Unsigned8: |
| 89 | + value.u8 = FieldView(drec_field).as_uint(); |
| 90 | + break; |
| 91 | + case DataType::Unsigned16: |
| 92 | + value.u16 = FieldView(drec_field).as_uint(); |
| 93 | + break; |
| 94 | + case DataType::Unsigned32: |
| 95 | + value.u32 = FieldView(drec_field).as_uint(); |
| 96 | + break; |
| 97 | + case DataType::Unsigned64: |
| 98 | + value.u64 = FieldView(drec_field).as_uint(); |
| 99 | + break; |
| 100 | + case DataType::Signed8: |
| 101 | + value.i8 = FieldView(drec_field).as_int(); |
| 102 | + break; |
| 103 | + case DataType::Signed16: |
| 104 | + value.i16 = FieldView(drec_field).as_int(); |
| 105 | + break; |
| 106 | + case DataType::Signed32: |
| 107 | + value.i32 = FieldView(drec_field).as_int(); |
| 108 | + break; |
| 109 | + case DataType::Signed64: |
| 110 | + value.i64 = FieldView(drec_field).as_int(); |
| 111 | + break; |
| 112 | + case DataType::String128B: |
| 113 | + case DataType::Octets128B: |
| 114 | + memset(value.str, 0, 128); |
| 115 | + memcpy(value.str, drec_field.data, std::min<int>(drec_field.size, 128)); |
| 116 | + break; |
| 117 | + case DataType::DateTime: |
| 118 | + value.ts_millisecs = FieldView(drec_field).as_datetime_ms(); |
| 119 | + break; |
| 120 | + case DataType::IPv4Address: |
| 121 | + if (drec_field.size != sizeof(value.ipv4)) { |
| 122 | + throw std::runtime_error( |
| 123 | + "Unexpected IPFIX field size when attempting to read IPv4 address:" |
| 124 | + " expected " + std::to_string(sizeof(value.ipv4)) + |
| 125 | + " got: " + std::to_string(drec_field.size) |
| 126 | + ); |
| 127 | + } |
| 128 | + memcpy(&value.ipv4, drec_field.data, sizeof(value.ipv4)); |
| 129 | + break; |
| 130 | + case DataType::IPv6Address: |
| 131 | + if (drec_field.size != sizeof(value.ipv6)) { |
| 132 | + throw std::runtime_error( |
| 133 | + "Unexpected IPFIX field size when attempting to read IPv6 address:" |
| 134 | + " expected " + std::to_string(sizeof(value.ipv6)) + |
| 135 | + " got: " + std::to_string(drec_field.size) |
| 136 | + ); |
| 137 | + } |
| 138 | + memcpy(&value.ipv6, drec_field.data, sizeof(value.ipv6)); |
| 139 | + break; |
| 140 | + case DataType::MacAddress: |
| 141 | + if (drec_field.size != sizeof(value.mac)) { |
| 142 | + throw std::runtime_error( |
| 143 | + "Unexpected IPFIX field size when attempting to read MAC address:" |
| 144 | + " expected " + std::to_string(sizeof(value.mac)) + |
| 145 | + " got: " + std::to_string(drec_field.size) |
| 146 | + ); |
| 147 | + } |
| 148 | + memcpy(value.mac, drec_field.data, sizeof(value.mac)); |
| 149 | + break; |
| 150 | + default: |
| 151 | + throw std::logic_error("unexpected IPFIX field data type"); |
| 152 | + } |
| 153 | + |
| 154 | + return true; |
| 155 | +} |
| 156 | + |
| 157 | +std::string |
| 158 | +IpfixField::repr() const |
| 159 | +{ |
| 160 | + return std::string("IpfixField(") + |
| 161 | + + "name=" + name() + ", data_type=" + data_type_to_str(data_type()) |
| 162 | + + ", size=" + std::to_string(size()) + ", offset=" + std::to_string(offset()) |
| 163 | + + ", pen=" + std::to_string(m_pen) + ", id=" + std::to_string(m_id) + ")"; |
| 164 | +} |
| 165 | + |
| 166 | +uint32_t |
| 167 | +IpfixField::pen() const |
| 168 | +{ |
| 169 | + return m_pen; |
| 170 | +} |
| 171 | + |
| 172 | +uint16_t |
| 173 | +IpfixField::id() const |
| 174 | +{ |
| 175 | + return m_id; |
| 176 | +} |
| 177 | + |
| 178 | +bool |
| 179 | +IpfixField::operator==(const IpfixField &other) const |
| 180 | +{ |
| 181 | + return pen() == other.pen() && id() == other.id(); |
| 182 | +} |
| 183 | + |
| 184 | +bool |
| 185 | +IpfixField::operator==(const Field &other) const |
| 186 | +{ |
| 187 | + if (const auto *other_ipfix = dynamic_cast<const IpfixField *>(&other)) { |
| 188 | + return *this == *other_ipfix; |
| 189 | + } |
| 190 | + return false; |
| 191 | +} |
| 192 | + |
| 193 | +} // aggregator |
| 194 | +} // fdsdump |
0 commit comments