FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
ioam_summary_export.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <vlib/vlib.h>
17 #include <vnet/ip/ip6_packet.h>
20 
21 u8 *
23  ip4_address_t * collector_address,
24  ip4_address_t * src_address, u16 collector_port,
26  u32 n_elts, u32 * stream_index)
27 {
29  udp_header_t *udp;
34  ipfix_field_specifier_t *first_field;
35  u8 *rewrite = 0;
37  u32 field_count = 0;
38  u32 field_index = 0;
39  flow_report_stream_t *stream;
40 
41  stream = &frm->streams[fr->stream_index];
42 
43  /* Determine field count */
44 #define _(field,mask,item,length) \
45  { \
46  field_count++; \
47  fr->fields_to_send = clib_bitmap_set (fr->fields_to_send, \
48  field_index, 1); \
49  } \
50  field_index++;
51 
53 #undef _
54 
55  /* Add Src address, dest address, src port, dest port
56  * path map, number of paths manually */
57  field_count += 6;
58 
59  /* allocate rewrite space */
60  vec_validate_aligned (rewrite,
62  + field_count * sizeof (ipfix_field_specifier_t) - 1,
64 
65  tp = (ip4_ipfix_template_packet_t *) rewrite;
66  ip = (ip4_header_t *) & tp->ip4;
67  udp = (udp_header_t *) (ip + 1);
68  h = (ipfix_message_header_t *) (udp + 1);
69  s = (ipfix_set_header_t *) (h + 1);
70  t = (ipfix_template_header_t *) (s + 1);
71  first_field = f = (ipfix_field_specifier_t *) (t + 1);
72 
74  ip->ttl = 254;
75  ip->protocol = IP_PROTOCOL_UDP;
76  ip->src_address.as_u32 = src_address->as_u32;
77  ip->dst_address.as_u32 = collector_address->as_u32;
78  udp->src_port = clib_host_to_net_u16 (collector_port);
79  udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
80  udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
81 
82  h->domain_id = clib_host_to_net_u32 (stream->domain_id); //fr->domain_id);
83 
84  /* Add Src address, dest address, src port, dest port
85  * path map, number of paths manually */
86  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
87  sourceIPv6Address,
88  sizeof (ip6_address_t));
89  f++;
90 
91  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
92  destinationIPv6Address,
93  sizeof (ip6_address_t));
94  f++;
95 
96  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
97  sourceTransportPort, 2);
98  f++;
99 
100  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
101  destinationTransportPort, 2);
102  f++;
103 
104 #define _(field,mask,item,length) \
105  { \
106  f->e_id_length = ipfix_e_id_length (0 /* enterprise */, \
107  item, length); \
108  f++; \
109  }
111 #undef _
112 
113  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
114  ioamNumberOfPaths, 2);
115  f++;
116 
117  /* Add ioamPathMap manually */
118  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
119  ioamPathMap,
120  (sizeof (ioam_path) +
121  (sizeof (ioam_path_map_t) *
123  f++;
124 
125  /* Back to the template packet... */
126  ip = (ip4_header_t *) & tp->ip4;
127  udp = (udp_header_t *) (ip + 1);
128 
129  ASSERT (f - first_field);
130  /* Field count in this template */
131  t->id_count = ipfix_id_count (IOAM_FLOW_TEMPLATE_ID, f - first_field);
132 
133  /* set length in octets */
134  s->set_id_length =
135  ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
136 
137  /* message length in octets */
138  h->version_length = version_length ((u8 *) f - (u8 *) h);
139 
140  ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
141  ip->checksum = ip4_header_checksum (ip);
142 
143  return rewrite;
144 }
145 
146 u16
148  ioam_analyser_data_t * record,
149  vlib_buffer_t * b0, u16 offset,
152 {
153  clib_spinlock_lock (&record->writer_lock);
154 
155  int field_index = 0;
156  u16 tmp;
157  int i, j;
158  u16 num_paths = 0;
159  u16 num_paths_offset;
160 
161 
162  /* Add IPv6 source address manually */
163  memcpy (b0->data + offset, &src->as_u64[0], sizeof (u64));
164  offset += sizeof (u64);
165  memcpy (b0->data + offset, &src->as_u64[1], sizeof (u64));
166  offset += sizeof (u64);
167 
168  /* Add IPv6 destination address manually */
169  memcpy (b0->data + offset, &dst->as_u64[0], sizeof (u64));
170  offset += sizeof (u64);
171  memcpy (b0->data + offset, &dst->as_u64[1], sizeof (u64));
172  offset += sizeof (u64);
173 
174  /* Add source port manually */
175  tmp = clib_host_to_net_u16 (src_port);
176  memcpy (b0->data + offset, &tmp, sizeof (u16));
177  offset += sizeof (u16);
178 
179  /* Add dest port manually */
180  tmp = clib_host_to_net_u16 (dst_port);
181  memcpy (b0->data + offset, &tmp, sizeof (u16));
182  offset += sizeof (u16);
183 
184 #define _(field,mask,item,length) \
185  if (clib_bitmap_get (fr->fields_to_send, field_index)) \
186  { \
187  /* Expect only 4 bytes */ \
188  u32 tmp; \
189  tmp = clib_host_to_net_u32((u32)record->field - (u32)record->chached_data_list->field);\
190  memcpy (b0->data + offset, &tmp, length); \
191  offset += length; \
192  }
193  field_index++;
195 #undef _
196 
197  /* Store num_paths_offset here and update later */
198  num_paths_offset = offset;
199  offset += sizeof (u16);
200 
201  /* Add ioamPathMap manually */
202  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
203  {
205  ioam_analyse_trace_record *trace_cached =
207  ioam_path *path = (ioam_path *) (b0->data + offset);
208 
209  if (!trace->is_free)
210  {
211  num_paths++;
212 
213  path->num_nodes = trace->num_nodes;
214 
215  path->trace_type = trace->trace_type;
216  if (0 < (trace->pkt_counter - trace_cached->pkt_counter))
217  {
218  u64 new_sum = trace->mean_delay * record->seqno_data.rx_packets;
219  u64 old_sum =
220  trace_cached->mean_delay *
222  path->mean_delay =
223  (u32) ((new_sum - old_sum) / (trace->pkt_counter -
224  trace_cached->pkt_counter));
225  path->mean_delay = clib_host_to_net_u32 (path->mean_delay);
226  }
227  else
228  path->mean_delay = 0;
229 
230  path->bytes_counter =
231  trace->bytes_counter - trace_cached->bytes_counter;
232  path->bytes_counter = clib_host_to_net_u32 (path->bytes_counter);
233 
234  path->pkt_counter = trace->pkt_counter - trace_cached->pkt_counter;
235  path->pkt_counter = clib_host_to_net_u32 (path->pkt_counter);
236  offset += sizeof (ioam_path);
237 
238  for (j = 0; j < trace->num_nodes; j++)
239  {
240  path->path[j].node_id =
241  clib_host_to_net_u32 (trace->path[j].node_id);
242  path->path[j].ingress_if =
243  clib_host_to_net_u16 (trace->path[j].ingress_if);
244  path->path[j].egress_if =
245  clib_host_to_net_u16 (trace->path[j].egress_if);
246  path->path[j].state_up = trace->path[j].state_up;
247  }
248 
249  //offset += (sizeof(ioam_path_map_t) * trace->num_nodes);
250  offset += (sizeof (ioam_path_map_t) * IOAM_TRACE_MAX_NODES); //FIXME
251  }
252  }
253 
254  num_paths = clib_host_to_net_u16 (num_paths);
255  memcpy (b0->data + num_paths_offset, &num_paths, sizeof (u16));
256 
257  /* Update cache */
258  *(record->chached_data_list) = *record;
260 
262  return offset;
263 }
264 
265 vlib_frame_t *
267  vlib_frame_t * f, u32 * to_next, u32 node_index)
268 {
269  vlib_buffer_t *b0 = NULL;
270  u32 next_offset = 0;
271  u32 bi0 = ~0;
272  int i;
276  ip4_header_t *ip;
277  udp_header_t *udp;
278  u32 records_this_buffer;
279  u16 new_l0, old_l0;
280  ip_csum_t sum0;
281  vlib_main_t *vm = frm->vlib_main;
282  ip6_address_t temp;
283  ioam_analyser_data_t *record = NULL;
284  flow_report_stream_t *stream;
285  ioam_analyser_data_t *aggregated_data;
286  u16 data_len;
287 
288  stream = &frm->streams[fr->stream_index];
289 
290  clib_memset (&temp, 0, sizeof (ip6_address_t));
291 
292  aggregated_data = ioam_analyser_main.aggregated_data;
293  data_len = vec_len (aggregated_data);
294 
295  vec_foreach_index (i, aggregated_data)
296  {
297  u8 flush = 0;
298  record = aggregated_data + i;
299 
300  /* Flush if last entry */
301  if (i == (data_len - 1))
302  flush = 1;
303 
304  if (!record->is_free)
305  {
306 
307  if (PREDICT_FALSE (b0 == NULL))
308  {
309  if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
310  break;
311 
312  b0 = vlib_get_buffer (vm, bi0);
313  memcpy (b0->data, fr->rewrite, vec_len (fr->rewrite));
314  b0->current_data = 0;
315  b0->current_length = vec_len (fr->rewrite);
316  b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
317  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
318  vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
319 
320  tp = vlib_buffer_get_current (b0);
321  ip = &tp->ip4;
322  h = &tp->ipfix.h;
323  s = &tp->ipfix.s;
324 
325  /* FIXUP: message header export_time */
326  h->export_time = clib_host_to_net_u32 (((u32) time (NULL)));
327 
328  /* FIXUP: message header sequence_number */
329  h->sequence_number = stream->sequence_number++;
330  h->sequence_number = clib_host_to_net_u32 (h->sequence_number);
331  next_offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp);
332  records_this_buffer = 0;
333  }
334 
335  next_offset = ioam_analyse_add_ipfix_record (fr, record,
336  b0, next_offset,
337  &temp, &temp, 0, 0);
338  records_this_buffer++;
339 
340  /* Flush data if packet len is about to reach path mtu */
341  if (next_offset > (frm->path_mtu - 250))
342  flush = 1;
343  }
344 
345  if (PREDICT_FALSE (flush && b0))
346  {
348  next_offset - (sizeof (*ip) +
349  sizeof (*udp) +
350  sizeof (*h)));
351  b0->current_length = next_offset;
352  b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
353  tp = vlib_buffer_get_current (b0);
354  ip = (ip4_header_t *) & tp->ip4;
355  udp = (udp_header_t *) (ip + 1);
356 
357  sum0 = ip->checksum;
358  old_l0 = ip->length;
359  new_l0 = clib_host_to_net_u16 ((u16) next_offset);
360  sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
361  length /* changed member */ );
362 
363  ip->checksum = ip_csum_fold (sum0);
364  ip->length = new_l0;
365  udp->length =
366  clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
367 
368  if (frm->udp_checksum)
369  {
370  /* RFC 7011 section 10.3.2. */
371  udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
372  if (udp->checksum == 0)
373  udp->checksum = 0xffff;
374  }
375 
376  to_next[0] = bi0;
377  f->n_vectors++;
378  to_next++;
379 
380  if (f->n_vectors == VLIB_FRAME_SIZE)
381  {
382  vlib_put_frame_to_node (vm, node_index, f);
383  f = vlib_get_frame_to_node (vm, node_index);
384  f->n_vectors = 0;
385  to_next = vlib_frame_vector_args (f);
386  }
387  b0 = 0;
388  bi0 = ~0;
389  }
390  }
391 
392  return f;
393 }
394 
395 clib_error_t *
397 {
399  int rv;
400  u32 domain_id = 0;
402  u16 template_id;
403 
404  clib_memset (&args, 0, sizeof (args));
407  del ? (args.is_add = 0) : (args.is_add = 1);
408  args.domain_id = domain_id;
409 
410  rv = vnet_flow_report_add_del (frm, &args, &template_id);
411 
412  switch (rv)
413  {
414  case 0:
415  break;
416  case VNET_API_ERROR_NO_SUCH_ENTRY:
417  return clib_error_return (0, "registration not found...");
418  default:
419  return clib_error_return (0, "vnet_flow_report_add_del returned %d",
420  rv);
421  }
422 
423  return 0;
424 }
425 
426 clib_error_t *
428 {
429  return 0;
430 }
431 
432 /* *INDENT-OFF* */
434 {
435  .runs_after = VLIB_INITS("flow_report_init"),
436 };
437 /* *INDENT-ON* */
438 
439 /*
440  * fd.io coding-style-patch-verification: ON
441  *
442  * Local Variables:
443  * eval: (c-set-style "gnu")
444  * End:
445  */
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
#define vec_foreach_index(var, v)
Iterate over vector indices.
u32 bytes_counter
Num of bytes in the flow going over path.
Definition: ioam_analyse.h:62
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:898
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:102
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:80
u8 * ioam_template_rewrite(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address, u16 collector_port, ipfix_report_element_t *elts, u32 n_elts, u32 *stream_index)
ip4_address_t src_address
Definition: ip4_packet.h:170
ioam_path_map_t path[IOAM_TRACE_MAX_NODES]
Actual PATH flow has taken.
Definition: ioam_analyse.h:56
seqno_rx_info seqno_data
Analysed iOAM seqno data.
Definition: ioam_analyse.h:121
u64 as_u64[2]
Definition: ip6_packet.h:51
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:110
unsigned long u64
Definition: types.h:89
static u32 ipfix_e_id_length(int e, u16 id, u16 length)
Definition: ipfix_packet.h:77
#define NULL
Definition: clib.h:58
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u32 stream_index
Definition: flow_report.h:91
int vnet_flow_report_add_del(flow_report_main_t *frm, vnet_flow_report_add_del_args_t *a, u16 *template_id)
Definition: flow_report.c:334
clib_error_t * ioam_flow_report_init(vlib_main_t *vm)
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
#define IOAM_TRACE_MAX_NODES
Definition: ioam_analyse.h:28
u8 data[0]
Packet data.
Definition: buffer.h:181
vl_api_address_t src
Definition: gre.api:60
int i
uword ip_csum_t
Definition: ip_packet.h:244
clib_error_t * ioam_flow_create(u8 del)
vl_api_fib_path_t path
Definition: mfib_types.api:34
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:451
unsigned char u8
Definition: types.h:56
ip6_ioam_analyser_main_t ioam_analyser_main
Definition: node.c:64
u16 src_port
Definition: udp.api:41
flow_report_stream_t * streams
Definition: flow_report.h:114
Analysed iOAM trace data.
Definition: ioam_analyse.h:42
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
u32 pkt_counter
Num of pkts in the flow going over path.
Definition: ioam_analyse.h:59
ip4_address_t dst_address
Definition: ip4_packet.h:170
vnet_flow_rewrite_callback_t * rewrite_callback
Definition: flow_report.h:149
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:185
#define clib_error_return(e, args...)
Definition: error.h:99
u16 ioam_analyse_add_ipfix_record(flow_report_t *fr, ioam_analyser_data_t *record, vlib_buffer_t *b0, u16 offset, ip6_address_t *src, ip6_address_t *dst, u16 src_port, u16 dst_port)
unsigned int u32
Definition: types.h:88
#define VLIB_FRAME_SIZE
Definition: node.h:378
flow_report_main_t flow_report_main
Definition: flow_report.c:21
#define IOAM_MAX_PATHS_PER_FLOW
Definition: ioam_analyse.h:29
ioam_analyse_trace_data trace_data
Analysed iOAM trace data.
Definition: ioam_analyse.h:115
u8 * rewrite
Definition: flow_report.h:89
unsigned short u16
Definition: types.h:57
vlib_frame_t * ioam_send_flows(flow_report_main_t *frm, flow_report_t *fr, vlib_frame_t *f, u32 *to_next, u32 node_index)
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:194
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define foreach_ioam_ipfix_field
#define PREDICT_FALSE(x)
Definition: clib.h:111
vl_api_address_union_t src_address
Definition: ip_types.api:98
vl_api_address_t dst
Definition: gre.api:61
static u32 version_length(u16 length)
Definition: ipfix_packet.h:33
vlib_main_t * vm
Definition: in2out_ed.c:1810
ioam_path_map_t path[0]
u16 n_vectors
Definition: node.h:397
#define IOAM_FLOW_TEMPLATE_ID
Definition: ioam_analyse.h:27
static u32 ipfix_id_count(u16 id, u16 count)
Definition: ipfix_packet.h:184
struct ioam_analyser_data_t_ * chached_data_list
Cache of previously analysed data, useful for export.
Definition: ioam_analyse.h:124
ioam_analyser_data_t * aggregated_data
This contains the aggregated data from the time VPP started analysing.
#define ASSERT(truth)
vlib_main_t * vlib_main
Definition: flow_report.h:136
u16 ip4_tcp_udp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip4_header_t *ip0)
Definition: ip4_forward.c:1302
clib_spinlock_t writer_lock
Lock to since we use this to export the data in other thread.
Definition: ioam_analyse.h:127
ipfix_message_header_t h
Definition: ipfix_packet.h:192
template key/value backing page structure
Definition: bihash_doc.h:44
static u32 ipfix_set_id_length(u16 set_id, u16 length)
Definition: ipfix_packet.h:121
Definition: defs.h:47
vl_api_address_t ip
Definition: l2.api:490
u8 trace_type
Data contained in trace - NodeId, TTL, Ingress & Egress Link, Timestamp.
Definition: ioam_analyse.h:48
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Analysed iOAM data.
Definition: ioam_analyse.h:98
ipfix_template_packet_t ipfix
Definition: flow_report.h:46
VLIB buffer representation.
Definition: buffer.h:102
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:294
vnet_flow_data_callback_t * flow_data_callback
Definition: flow_report.h:148
struct clib_bihash_value offset
template key/value backing page structure
#define vnet_buffer(b)
Definition: buffer.h:408
u8 is_free
Flag to indicate whether node is allocated.
Definition: ioam_analyse.h:51
u8 num_nodes
No of nodes in path.
Definition: ioam_analyse.h:45
u32 mean_delay
Average Dealay for the flow.
Definition: ioam_analyse.h:71
u16 dst_port
Definition: udp.api:42
u8 ip_version_and_header_length
Definition: ip4_packet.h:138
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:630
#define VLIB_INITS(...)
Definition: init.h:344
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:247
ipfix_set_header_t s
Definition: ipfix_packet.h:193
ioam_analyse_trace_record path_data[IOAM_MAX_PATHS_PER_FLOW]
Definition: ioam_analyse.h:78
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:300
Definition: defs.h:46