11#if DETWS_ENABLE_FLOW_EXPORT
17static size_t put16(uint8_t *p, uint16_t v)
19 p[0] = (uint8_t)(v >> 8);
24static size_t put32(uint8_t *p, uint32_t v)
26 p[0] = (uint8_t)(v >> 24);
27 p[1] = (uint8_t)(v >> 16);
28 p[2] = (uint8_t)(v >> 8);
33size_t flow_v5_write_header(uint8_t *buf,
size_t cap,
const FlowV5Header *h)
35 if (!buf || !h || cap < FLOW_V5_HEADER_SIZE)
38 p += put16(buf + p, 5);
39 p += put16(buf + p, h->count);
40 p += put32(buf + p, h->sys_uptime);
41 p += put32(buf + p, h->unix_secs);
42 p += put32(buf + p, h->unix_nsecs);
43 p += put32(buf + p, h->flow_sequence);
44 buf[p++] = h->engine_type;
45 buf[p++] = h->engine_id;
46 p += put16(buf + p, h->sampling_interval);
50size_t flow_v5_write_record(uint8_t *buf,
size_t cap,
const FlowV5Record *r)
52 if (!buf || !r || cap < FLOW_V5_RECORD_SIZE)
55 p += put32(buf + p, r->src_addr);
56 p += put32(buf + p, r->dst_addr);
57 p += put32(buf + p, r->next_hop);
58 p += put16(buf + p, r->input);
59 p += put16(buf + p, r->output);
60 p += put32(buf + p, r->d_pkts);
61 p += put32(buf + p, r->d_octets);
62 p += put32(buf + p, r->first);
63 p += put32(buf + p, r->last);
64 p += put16(buf + p, r->src_port);
65 p += put16(buf + p, r->dst_port);
67 buf[p++] = r->tcp_flags;
70 p += put16(buf + p, r->src_as);
71 p += put16(buf + p, r->dst_as);
72 buf[p++] = r->src_mask;
73 buf[p++] = r->dst_mask;
81static void w_u16(FlowWriter *w, uint16_t v)
85 if (w->pos + 2 > w->cap)
90 w->pos += put16(w->buf + w->pos, v);
93static void w_u32(FlowWriter *w, uint32_t v)
97 if (w->pos + 4 > w->cap)
102 w->pos += put32(w->buf + w->pos, v);
105static void w_bytes(FlowWriter *w,
const uint8_t *p,
size_t n)
109 if (w->pos + n > w->cap)
114 memcpy(w->buf + w->pos, p, n);
119static void w_zero(FlowWriter *w,
size_t n)
123 if (w->pos + n > w->cap)
128 memset(w->buf + w->pos, 0, n);
132static void patch16(FlowWriter *w,
size_t off, uint16_t v)
134 put16(w->buf + off, v);
137bool flow_ipfix_begin(FlowWriter *w, uint8_t *buf,
size_t cap, uint32_t export_time, uint32_t seq, uint32_t domain_id)
150 w_u32(w, export_time);
156bool flow_v9_begin(FlowWriter *w, uint8_t *buf,
size_t cap, uint32_t sys_uptime, uint32_t unix_secs, uint32_t seq,
170 w_u32(w, sys_uptime);
177bool flow_export_template(FlowWriter *w, uint16_t template_id,
const FlowField *fields,
size_t field_count)
179 if (!w || !fields || field_count == 0)
182 flow_export_data_end(w);
183 size_t set_off = w->pos;
184 w_u16(w, w->version == 9 ? 0 : 2);
186 w_u16(w, template_id);
187 w_u16(w, (uint16_t)field_count);
188 for (
size_t i = 0; i < field_count; i++)
190 w_u16(w, fields[i].type);
191 w_u16(w, fields[i].length);
194 patch16(w, set_off + 2, (uint16_t)(w->pos - set_off));
199bool flow_export_data_begin(FlowWriter *w, uint16_t template_id)
201 if (!w || template_id < 256)
204 flow_export_data_end(w);
205 w->set_start = w->pos;
206 w_u16(w, template_id);
211bool flow_export_data_record(FlowWriter *w,
const uint8_t *record,
size_t len)
213 if (!w || !w->set_start || !record || len == 0)
215 w_bytes(w, record, len);
221bool flow_export_data_end(FlowWriter *w)
223 if (!w || !w->set_start)
227 size_t set_len = w->pos - w->set_start;
228 w_zero(w, (4 - (set_len & 3)) & 3);
231 patch16(w, w->set_start + 2, (uint16_t)(w->pos - w->set_start));
236size_t flow_export_finish(FlowWriter *w)
241 flow_export_data_end(w);
245 patch16(w, 2, w->records);
250 patch16(w, 2, (uint16_t)w->pos);
Flow-record export codec (DETWS_ENABLE_FLOW_EXPORT) - zero-heap exporter-side builders for NetFlow v5...