FD.io VPP  v21.01.1
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>
18 #include <vnet/udp/udp_local.h>
21 
22 u8 *
24  ip4_address_t * collector_address,
25  ip4_address_t * src_address, u16 collector_port,
27  u32 n_elts, u32 * stream_index)
28 {
30  udp_header_t *udp;
35  ipfix_field_specifier_t *first_field;
36  u8 *rewrite = 0;
38  u32 field_count = 0;
39  u32 field_index = 0;
40  flow_report_stream_t *stream;
41 
42  stream = &frm->streams[fr->stream_index];
43 
44  /* Determine field count */
45 #define _(field,mask,item,length) \
46  { \
47  field_count++; \
48  fr->fields_to_send = clib_bitmap_set (fr->fields_to_send, \
49  field_index, 1); \
50  } \
51  field_index++;
52 
54 #undef _
55 
56  /* Add Src address, dest address, src port, dest port
57  * path map, number of paths manually */
58  field_count += 6;
59 
60  /* allocate rewrite space */
61  vec_validate_aligned (rewrite,
63  + field_count * sizeof (ipfix_field_specifier_t) - 1,
65 
66  tp = (ip4_ipfix_template_packet_t *) rewrite;
67  ip = (ip4_header_t *) & tp->ip4;
68  udp = (udp_header_t *) (ip + 1);
69  h = (ipfix_message_header_t *) (udp + 1);
70  s = (ipfix_set_header_t *) (h + 1);
71  t = (ipfix_template_header_t *) (s + 1);
72  first_field = f = (ipfix_field_specifier_t *) (t + 1);
73 
75  ip->ttl = 254;
76  ip->protocol = IP_PROTOCOL_UDP;
77  ip->src_address.as_u32 = src_address->as_u32;
78  ip->dst_address.as_u32 = collector_address->as_u32;
79  udp->src_port = clib_host_to_net_u16 (collector_port);
80  udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
81  udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
82 
83  h->domain_id = clib_host_to_net_u32 (stream->domain_id); //fr->domain_id);
84 
85  /* Add Src address, dest address, src port, dest port
86  * path map, number of paths manually */
87  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
88  sourceIPv6Address,
89  sizeof (ip6_address_t));
90  f++;
91 
92  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
93  destinationIPv6Address,
94  sizeof (ip6_address_t));
95  f++;
96 
97  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
98  sourceTransportPort, 2);
99  f++;
100 
101  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
102  destinationTransportPort, 2);
103  f++;
104 
105 #define _(field,mask,item,length) \
106  { \
107  f->e_id_length = ipfix_e_id_length (0 /* enterprise */, \
108  item, length); \
109  f++; \
110  }
112 #undef _
113 
114  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
115  ioamNumberOfPaths, 2);
116  f++;
117 
118  /* Add ioamPathMap manually */
119  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
120  ioamPathMap,
121  (sizeof (ioam_path) +
122  (sizeof (ioam_path_map_t) *
124  f++;
125 
126  /* Back to the template packet... */
127  ip = (ip4_header_t *) & tp->ip4;
128  udp = (udp_header_t *) (ip + 1);
129 
130  ASSERT (f - first_field);
131  /* Field count in this template */
132  t->id_count = ipfix_id_count (IOAM_FLOW_TEMPLATE_ID, f - first_field);
133 
134  /* set length in octets */
135  s->set_id_length =
136  ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
137 
138  /* message length in octets */
139  h->version_length = version_length ((u8 *) f - (u8 *) h);
140 
141  ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
142  ip->checksum = ip4_header_checksum (ip);
143 
144  return rewrite;
145 }
146 
147 u16
149  ioam_analyser_data_t * record,
150  vlib_buffer_t * b0, u16 offset,
151  ip6_address_t * src, ip6_address_t * dst,
153 {
154  clib_spinlock_lock (&record->writer_lock);
155 
156  int field_index = 0;
157  u16 tmp;
158  int i, j;
159  u16 num_paths = 0;
160  u16 num_paths_offset;
161 
162 
163  /* Add IPv6 source address manually */
164  memcpy (b0->data + offset, &src->as_u64[0], sizeof (u64));
165  offset += sizeof (u64);
166  memcpy (b0->data + offset, &src->as_u64[1], sizeof (u64));
167  offset += sizeof (u64);
168 
169  /* Add IPv6 destination address manually */
170  memcpy (b0->data + offset, &dst->as_u64[0], sizeof (u64));
171  offset += sizeof (u64);
172  memcpy (b0->data + offset, &dst->as_u64[1], sizeof (u64));
173  offset += sizeof (u64);
174 
175  /* Add source port manually */
176  tmp = clib_host_to_net_u16 (src_port);
177  memcpy (b0->data + offset, &tmp, sizeof (u16));
178  offset += sizeof (u16);
179 
180  /* Add dest port manually */
181  tmp = clib_host_to_net_u16 (dst_port);
182  memcpy (b0->data + offset, &tmp, sizeof (u16));
183  offset += sizeof (u16);
184 
185 #define _(field,mask,item,length) \
186  if (clib_bitmap_get (fr->fields_to_send, field_index)) \
187  { \
188  /* Expect only 4 bytes */ \
189  u32 tmp; \
190  tmp = clib_host_to_net_u32((u32)record->field - (u32)record->chached_data_list->field);\
191  memcpy (b0->data + offset, &tmp, length); \
192  offset += length; \
193  }
194  field_index++;
196 #undef _
197 
198  /* Store num_paths_offset here and update later */
199  num_paths_offset = offset;
200  offset += sizeof (u16);
201 
202  /* Add ioamPathMap manually */
203  for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
204  {
206  ioam_analyse_trace_record *trace_cached =
208  ioam_path *path = (ioam_path *) (b0->data + offset);
209 
210  if (!trace->is_free)
211  {
212  num_paths++;
213 
214  path->num_nodes = trace->num_nodes;
215 
216  path->trace_type = trace->trace_type;
217  if (0 < (trace->pkt_counter - trace_cached->pkt_counter))
218  {
219  u64 new_sum = trace->mean_delay * record->seqno_data.rx_packets;
220  u64 old_sum =
221  trace_cached->mean_delay *
223  path->mean_delay =
224  (u32) ((new_sum - old_sum) / (trace->pkt_counter -
225  trace_cached->pkt_counter));
226  path->mean_delay = clib_host_to_net_u32 (path->mean_delay);
227  }
228  else
229  path->mean_delay = 0;
230 
231  path->bytes_counter =
232  trace->bytes_counter - trace_cached->bytes_counter;
233  path->bytes_counter = clib_host_to_net_u32 (path->bytes_counter);
234 
235  path->pkt_counter = trace->pkt_counter - trace_cached->pkt_counter;
236  path->pkt_counter = clib_host_to_net_u32 (path->pkt_counter);
237  offset += sizeof (ioam_path);
238 
239  for (j = 0; j < trace->num_nodes; j++)
240  {
241  path->path[j].node_id =
242  clib_host_to_net_u32 (trace->path[j].node_id);
243  path->path[j].ingress_if =
244  clib_host_to_net_u16 (trace->path[j].ingress_if);
245  path->path[j].egress_if =
246  clib_host_to_net_u16 (trace->path[j].egress_if);
247  path->path[j].state_up = trace->path[j].state_up;
248  }
249 
250  //offset += (sizeof(ioam_path_map_t) * trace->num_nodes);
251  offset += (sizeof (ioam_path_map_t) * IOAM_TRACE_MAX_NODES); //FIXME
252  }
253  }
254 
255  num_paths = clib_host_to_net_u16 (num_paths);
256  memcpy (b0->data + num_paths_offset, &num_paths, sizeof (u16));
257 
258  /* Update cache */
259  *(record->chached_data_list) = *record;
260  record->chached_data_list->chached_data_list = NULL;
261 
263  return offset;
264 }
265 
266 vlib_frame_t *
268  vlib_frame_t * f, u32 * to_next, u32 node_index)
269 {
270  vlib_buffer_t *b0 = NULL;
271  u32 next_offset = 0;
272  u32 bi0 = ~0;
273  int i;
276  ipfix_set_header_t *s = NULL;
277  ip4_header_t *ip;
278  udp_header_t *udp;
279  u32 records_this_buffer;
280  u16 new_l0, old_l0;
281  ip_csum_t sum0;
282  vlib_main_t *vm = frm->vlib_main;
283  ip6_address_t temp;
284  ioam_analyser_data_t *record = NULL;
285  flow_report_stream_t *stream;
286  ioam_analyser_data_t *aggregated_data;
287  u16 data_len;
288 
289  stream = &frm->streams[fr->stream_index];
290 
291  clib_memset (&temp, 0, sizeof (ip6_address_t));
292 
293  aggregated_data = ioam_analyser_main.aggregated_data;
294  data_len = vec_len (aggregated_data);
295 
296  vec_foreach_index (i, aggregated_data)
297  {
298  u8 flush = 0;
299  record = aggregated_data + i;
300 
301  /* Flush if last entry */
302  if (i == (data_len - 1))
303  flush = 1;
304 
305  if (!record->is_free)
306  {
307 
308  if (PREDICT_FALSE (b0 == NULL))
309  {
310  if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
311  break;
312 
313  b0 = vlib_get_buffer (vm, bi0);
314  memcpy (b0->data, fr->rewrite, vec_len (fr->rewrite));
315  b0->current_data = 0;
316  b0->current_length = vec_len (fr->rewrite);
317  b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
318  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
319  vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
320 
321  tp = vlib_buffer_get_current (b0);
322  ip = &tp->ip4;
323  h = &tp->ipfix.h;
324  s = &tp->ipfix.s;
325 
326  /* FIXUP: message header export_time */
327  h->export_time = clib_host_to_net_u32 (((u32) time (NULL)));
328 
329  /* FIXUP: message header sequence_number */
330  h->sequence_number = stream->sequence_number++;
331  h->sequence_number = clib_host_to_net_u32 (h->sequence_number);
332  next_offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp);
333  records_this_buffer = 0;
334  }
335 
336  next_offset = ioam_analyse_add_ipfix_record (fr, record,
337  b0, next_offset,
338  &temp, &temp, 0, 0);
339  records_this_buffer++;
340 
341  /* Flush data if packet len is about to reach path mtu */
342  if (next_offset > (frm->path_mtu - 250))
343  flush = 1;
344  }
345 
346  if (PREDICT_FALSE (flush && b0))
347  {
349  next_offset - (sizeof (*ip) +
350  sizeof (*udp) +
351  sizeof (*h)));
352  b0->current_length = next_offset;
353  b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
354  tp = vlib_buffer_get_current (b0);
355  ip = (ip4_header_t *) & tp->ip4;
356  udp = (udp_header_t *) (ip + 1);
357 
358  sum0 = ip->checksum;
359  old_l0 = ip->length;
360  new_l0 = clib_host_to_net_u16 ((u16) next_offset);
361  sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
362  length /* changed member */ );
363 
364  ip->checksum = ip_csum_fold (sum0);
365  ip->length = new_l0;
366  udp->length =
367  clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
368 
369  if (frm->udp_checksum)
370  {
371  /* RFC 7011 section 10.3.2. */
372  udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
373  if (udp->checksum == 0)
374  udp->checksum = 0xffff;
375  }
376 
377  to_next[0] = bi0;
378  f->n_vectors++;
379  to_next++;
380 
381  if (f->n_vectors == VLIB_FRAME_SIZE)
382  {
383  vlib_put_frame_to_node (vm, node_index, f);
384  f = vlib_get_frame_to_node (vm, node_index);
385  f->n_vectors = 0;
386  to_next = vlib_frame_vector_args (f);
387  }
388  b0 = 0;
389  bi0 = ~0;
390  }
391  }
392 
393  return f;
394 }
395 
396 clib_error_t *
398 {
400  int rv;
401  u32 domain_id = 0;
403  u16 template_id;
404 
405  clib_memset (&args, 0, sizeof (args));
408  del ? (args.is_add = 0) : (args.is_add = 1);
409  args.domain_id = domain_id;
410 
411  rv = vnet_flow_report_add_del (frm, &args, &template_id);
412 
413  switch (rv)
414  {
415  case 0:
416  break;
417  case VNET_API_ERROR_NO_SUCH_ENTRY:
418  return clib_error_return (0, "registration not found...");
419  default:
420  return clib_error_return (0, "vnet_flow_report_add_del returned %d",
421  rv);
422  }
423 
424  return 0;
425 }
426 
427 clib_error_t *
429 {
430  return 0;
431 }
432 
433 /* *INDENT-OFF* */
435 {
436  .runs_after = VLIB_INITS("flow_report_init"),
437 };
438 /* *INDENT-ON* */
439 
440 /*
441  * fd.io coding-style-patch-verification: ON
442  *
443  * Local Variables:
444  * eval: (c-set-style "gnu")
445  * End:
446  */
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:899
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:121
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:82
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:125
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
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
vl_api_ip_port_and_mask_t dst_port
Definition: flow_types.api:92
static u32 ipfix_e_id_length(int e, u16 id, u16 length)
Definition: ipfix_packet.h:77
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:335
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
vl_api_address_t src
Definition: gre.api:54
uword ip_csum_t
Definition: ip_packet.h:246
vlib_main_t * vm
Definition: in2out_ed.c:1580
clib_error_t * ioam_flow_create(u8 del)
vl_api_fib_path_t path
Definition: mfib_types.api:44
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:520
unsigned char u8
Definition: types.h:56
ip6_ioam_analyser_main_t ioam_analyser_main
Definition: node.c:64
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:125
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:182
#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:22
#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
static __clib_warn_unused_result u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:677
u8 * rewrite
Definition: flow_report.h:89
unsigned short u16
Definition: types.h:57
u8 data_len
Definition: ikev2_types.api:24
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:216
vec_header_t h
Definition: buffer.c:322
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:233
#define foreach_ioam_ipfix_field
#define PREDICT_FALSE(x)
Definition: clib.h:121
vl_api_address_union_t src_address
Definition: ip_types.api:122
vl_api_address_t dst
Definition: gre.api:55
static u32 version_length(u16 length)
Definition: ipfix_packet.h:33
vl_api_ip_port_and_mask_t src_port
Definition: flow_types.api:91
ioam_path_map_t path[0]
u16 n_vectors
Definition: node.h:397
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
#define IOAM_FLOW_TEMPLATE_ID
Definition: ioam_analyse.h:27
static u32 ipfix_id_count(u16 id, u16 count)
Definition: ipfix_packet.h:184
u8 data[]
Packet data.
Definition: buffer.h:181
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:1328
clib_spinlock_t writer_lock
Lock to since we use this to export the data in other thread.
Definition: ioam_analyse.h:127
char const int length
Definition: cJSON.h:163
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:501
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:297
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:296
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:417
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
u8 ip_version_and_header_length
Definition: ip4_packet.h:93
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
#define VLIB_INITS(...)
Definition: init.h:357
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:314
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:302
Definition: defs.h:46