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