|
8 | 8 | * SPDX-License-Identifier: BSD-3-Clause |
9 | 9 | */ |
10 | 10 |
|
| 11 | +#include <algorithm> |
| 12 | +#include <cinttypes> |
11 | 13 | #include <cstdio> |
12 | 14 | #include <cstring> |
13 | 15 | #include <sys/stat.h> |
@@ -69,9 +71,9 @@ Storage::window_new(time_t ts) |
69 | 71 | } |
70 | 72 |
|
71 | 73 | if (fds_file_open(m_file.get(), new_file.c_str(), m_flags) != FDS_OK) { |
| 74 | + std::string err_msg = fds_file_error(m_file.get()); |
72 | 75 | m_file.reset(); |
73 | | - const char *err_msg = "something"; //fds_file_error(m_file.get()); |
74 | | - throw FDS_exception("Failed to create file '" + new_file + "': " + err_msg); |
| 76 | + throw FDS_exception("Failed to create/append file '" + new_file + "': " + err_msg); |
75 | 77 | } |
76 | 78 | } |
77 | 79 |
|
@@ -100,51 +102,188 @@ Storage::process_msg(ipx_msg_ipfix_t *msg) |
100 | 102 |
|
101 | 103 | if (fds_file_write_ctx(m_file.get(), file_ctx.id, msg_ctx->odid, exp_time) != FDS_OK) { |
102 | 104 | const char *err_msg = fds_file_error(m_file.get()); |
103 | | - throw FDS_exception("Failed to configure file writer: " + std::string(err_msg)); |
| 105 | + throw FDS_exception("Failed to configure the writer: " + std::string(err_msg)); |
104 | 106 | } |
105 | 107 |
|
| 108 | + // Get info about the last seen Template snapshot |
| 109 | + struct snap_info &snap_last = file_ctx.odid2snap[msg_ctx->odid]; |
| 110 | + |
106 | 111 | // For each Data Record in the file |
107 | 112 | const uint32_t rec_cnt = ipx_msg_ipfix_get_drec_cnt(msg); |
108 | 113 | for (uint32_t i = 0; i < rec_cnt; ++i) { |
109 | 114 | ipx_ipfix_record *rec_ptr = ipx_msg_ipfix_get_drec(msg, i); |
110 | 115 |
|
111 | | - // Insert the record // TODO: improve me! |
112 | | - const struct fds_template *rec_tmplt = rec_ptr->rec.tmplt; |
113 | | - uint16_t tmplt_id = rec_tmplt->id; |
114 | | - enum fds_template_type t_type; |
115 | | - const uint8_t *t_data; |
116 | | - uint16_t t_size; |
| 116 | + // Check if the templates has been changed (detected by change of template snapshots) |
| 117 | + if (rec_ptr->rec.snap != snap_last.ptr) { |
| 118 | + const char *session_name = msg_ctx->session->ident; |
| 119 | + uint32_t session_odid = msg_ctx->odid; |
| 120 | + IPX_CTX_DEBUG(m_ctx, "Template snapshot of '%s' [ODID %" PRIu32 "] has been changed. " |
| 121 | + "Updating template definitions...", session_name, session_odid); |
117 | 122 |
|
118 | | - int rc = fds_file_write_tmplt_get(m_file.get(), tmplt_id, &t_type, &t_data, &t_size); |
119 | | - if (rc != FDS_OK && rc != FDS_ERR_NOTFOUND) { |
120 | | - // Something bad happened |
| 123 | + tmplts_update(snap_last, rec_ptr->rec.snap); |
| 124 | + } |
| 125 | + |
| 126 | + // Write the Data Record |
| 127 | + const uint8_t *rec_data = rec_ptr->rec.data; |
| 128 | + uint16_t rec_size = rec_ptr->rec.size; |
| 129 | + uint16_t tmplt_id = rec_ptr->rec.tmplt->id; |
| 130 | + |
| 131 | + if (fds_file_write_rec(m_file.get(), tmplt_id, rec_data, rec_size) != FDS_OK) { |
121 | 132 | const char *err_msg = fds_file_error(m_file.get()); |
| 133 | + throw FDS_exception("Failed to add a Data Record: " + std::string(err_msg)); |
| 134 | + } |
| 135 | + } |
| 136 | +} |
| 137 | + |
| 138 | +/// Auxiliary data structure used in the snapshot iterator |
| 139 | +struct tmplt_update_data { |
| 140 | + /// Status of template processing |
| 141 | + bool is_ok; |
| 142 | + /// Plugin context (only for log!) |
| 143 | + ipx_ctx_t *ctx; |
| 144 | + |
| 145 | + /// FDS file with specified context |
| 146 | + fds_file_t *file; |
| 147 | + /// Set of processed Templates in the snapshot |
| 148 | + std::set<uint16_t> ids; |
| 149 | +}; |
| 150 | + |
| 151 | +/** |
| 152 | + * @brief Callback function for updating definition of an IPFIX (Options) Template |
| 153 | + * |
| 154 | + * The function checks if the same Template is already defined in the current context of the file. |
| 155 | + * If the Template is not present or it's different, the new Template definition is added to the |
| 156 | + * file. |
| 157 | + * @param[in] tmplt Template to process |
| 158 | + * @param[in] data Auxiliary data structure \ref tmplt_update_data |
| 159 | + * @return On success returns true. Otherwise returns false. |
| 160 | + */ |
| 161 | +static bool |
| 162 | +tmplt_update_cb(const struct fds_template *tmplt, void *data) |
| 163 | +{ |
| 164 | + // Template type, raw data and size |
| 165 | + enum fds_template_type t_type; |
| 166 | + const uint8_t *t_data; |
| 167 | + uint16_t t_size; |
| 168 | + |
| 169 | + auto info = reinterpret_cast<tmplt_update_data *>(data); |
| 170 | + |
| 171 | + // No exceptions can be thrown in the C callback! |
| 172 | + try { |
| 173 | + uint16_t t_id = tmplt->id; |
| 174 | + info->ids.emplace(t_id); |
| 175 | + |
| 176 | + // Get definition of the Template specified in the file |
| 177 | + int res = fds_file_write_tmplt_get(info->file, t_id, &t_type, &t_data, &t_size); |
| 178 | + |
| 179 | + if (res != FDS_OK && res != FDS_ERR_NOTFOUND) { |
| 180 | + // Something bad happened |
| 181 | + const char *err_msg = fds_file_error(info->file); |
122 | 182 | throw FDS_exception("fds_file_write_tmplt_get() failed: " + std::string(err_msg)); |
123 | 183 | } |
124 | 184 |
|
125 | | - if (rc == FDS_ERR_NOTFOUND || t_type != rec_tmplt->type || t_size != rec_tmplt->raw.length |
126 | | - || memcmp(t_data, rec_tmplt->raw.data, rec_tmplt->raw.length) != 0) { |
127 | | - // Template not defined or the template are different |
128 | | - t_type = rec_tmplt->type; |
129 | | - t_data = rec_tmplt->raw.data; |
130 | | - t_size = rec_tmplt->raw.length; |
131 | | - |
132 | | - if (fds_file_write_tmplt_add(m_file.get(), t_type, t_data, t_size) != FDS_OK) { |
133 | | - const char *err_msg = fds_file_error(m_file.get()); |
134 | | - throw FDS_exception("Failed to add a template: " + std::string(err_msg)); |
135 | | - } |
| 185 | + // Should we add/redefine the definition of the Template |
| 186 | + if (res == FDS_OK |
| 187 | + && tmplt->type == t_type |
| 188 | + && tmplt->raw.length == t_size |
| 189 | + && memcmp(tmplt->raw.data, t_data, t_size) == 0) { |
| 190 | + // The same -> nothing to do |
| 191 | + return info->is_ok; |
136 | 192 | } |
137 | 193 |
|
138 | | - // FIXME: check subTemplateList & subTemplateMultiList templates |
| 194 | + // Add the definition (i.e. templates are different or the template hasn't been defined) |
| 195 | + IPX_CTX_DEBUG(info->ctx, "Adding/updating definition of Template ID %" PRIu16, t_id); |
139 | 196 |
|
140 | | - // Write the Data record |
141 | | - const uint8_t *rec_data = rec_ptr->rec.data; |
142 | | - const uint16_t rec_size = rec_ptr->rec.size; |
143 | | - if (fds_file_write_rec(m_file.get(), tmplt_id, rec_data, rec_size) != FDS_OK) { |
144 | | - const char *err_msg = fds_file_error(m_file.get()); |
145 | | - throw FDS_exception("Failed to add a Data Record: " + std::string(err_msg)); |
| 197 | + t_type = tmplt->type; |
| 198 | + t_data = tmplt->raw.data; |
| 199 | + t_size = tmplt->raw.length; |
| 200 | + |
| 201 | + if (fds_file_write_tmplt_add(info->file, t_type, t_data, t_size) != FDS_OK) { |
| 202 | + const char *err_msg = fds_file_error(info->file); |
| 203 | + throw FDS_exception("fds_file_write_tmplt_add() failed: " + std::string(err_msg)); |
| 204 | + } |
| 205 | + |
| 206 | + } catch (std::exception &ex) { |
| 207 | + // Exceptions |
| 208 | + IPX_CTX_ERROR(info->ctx, "Failure during update of Template ID %" PRIu16 ": %s", tmplt->id, |
| 209 | + ex.what()); |
| 210 | + info->is_ok = false; |
| 211 | + } catch (...) { |
| 212 | + // Other exceptions |
| 213 | + IPX_CTX_ERROR(info->ctx, "Unknown exception thrown during template definition update", '\0'); |
| 214 | + info->is_ok = false; |
| 215 | + } |
| 216 | + |
| 217 | + return info->is_ok; |
| 218 | +} |
| 219 | + |
| 220 | +/** |
| 221 | + * @brief Update Template definitions for the current Transport Session and ODID |
| 222 | + * |
| 223 | + * The function compares Templates in the \p snap with Template definitions previously defined |
| 224 | + * for the currently selected combination of Transport Session and ODID. For each different or |
| 225 | + * previously undefined Template, its definition is added or updated. Definitions of Templates |
| 226 | + * that were available in the previous snapshot but not available in the new one are removed. |
| 227 | + * |
| 228 | + * Finally, information (pointer, IDs) in \p info are updated to reflect the performed update. |
| 229 | + * @warning |
| 230 | + * Template definitions are always unique for a combination of Transport Session and ODID, |
| 231 | + * therefore, appropriate file writer context MUST already set using fds_file_writer_ctx(). |
| 232 | + * Parameters \p info and \p snap MUST also belong the same unique combination. |
| 233 | + * @param[in] info Information about the last update of Templates (old snapshot ref. + list of IDs) |
| 234 | + * @param[in] snap New Template snapshot with all valid Template definitions |
| 235 | + */ |
| 236 | +void |
| 237 | +Storage::tmplts_update(struct snap_info &info, const fds_tsnapshot_t *snap) |
| 238 | +{ |
| 239 | + assert(info.ptr != snap && "Snapshots should be different"); |
| 240 | + |
| 241 | + // Prepare data for the callback function |
| 242 | + struct tmplt_update_data data; |
| 243 | + data.is_ok = true; |
| 244 | + data.ctx = m_ctx; |
| 245 | + data.file = m_file.get(); |
| 246 | + data.ids.clear(); |
| 247 | + |
| 248 | + // Update templates |
| 249 | + fds_tsnapshot_for(snap, &tmplt_update_cb, &data); |
| 250 | + |
| 251 | + // Check if the update failed |
| 252 | + if (!data.is_ok) { |
| 253 | + throw FDS_exception("Failed to update Template definitions"); |
| 254 | + } |
| 255 | + |
| 256 | + // Check if there are any Template IDs that have been removed |
| 257 | + std::set<uint16_t> &ids_old = info.tmplt_ids; |
| 258 | + std::set<uint16_t> &ids_new = data.ids; |
| 259 | + std::set<uint16_t> ids2remove; |
| 260 | + // Old Template IDs - New Templates IDs = Template IDs to remove |
| 261 | + std::set_difference(ids_old.begin(), ids_old.end(), ids_new.begin(), ids_new.end(), |
| 262 | + std::inserter(ids2remove, ids2remove.begin())); |
| 263 | + |
| 264 | + // Remove old templates that are not available in the new snapshot |
| 265 | + for (uint16_t tid : ids2remove) { |
| 266 | + IPX_CTX_DEBUG(m_ctx, "Removing definition of Template ID %" PRIu16, tid); |
| 267 | + |
| 268 | + int rc = fds_file_write_tmplt_remove(m_file.get(), tid); |
| 269 | + if (rc == FDS_OK) { |
| 270 | + continue; |
| 271 | + } |
| 272 | + |
| 273 | + // Something bad happened |
| 274 | + if (rc != FDS_ERR_NOTFOUND) { |
| 275 | + std::string err_msg = fds_file_error(m_file.get()); |
| 276 | + throw FDS_exception("fds_file_write_tmplt_remove() failed: " + err_msg); |
146 | 277 | } |
| 278 | + |
| 279 | + // Weird, but not critical |
| 280 | + IPX_CTX_WARNING(m_ctx, "Failed to remove undefined Template ID %" PRIu16 ". " |
| 281 | + "Weird, this should not happen.", tid); |
147 | 282 | } |
| 283 | + |
| 284 | + // Update information about the last update of Templates |
| 285 | + info.ptr = snap; |
| 286 | + std::swap(info.tmplt_ids, data.ids); |
148 | 287 | } |
149 | 288 |
|
150 | 289 | /** |
|
0 commit comments