FD.io VPP  v18.07.1-19-g511ce25
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 {
28  ip4_header_t *ip;
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,
150  ip6_address_t * src, ip6_address_t * dst,
151  u16 src_port, u16 dst_port)
152 {
153  while (__sync_lock_test_and_set (record->writer_lock, 1))
154  ;
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;
261 
262  *(record->writer_lock) = 0;
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;
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  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  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  clib_error_t *error;
431 
432  if ((error = vlib_call_init_function (vm, flow_report_init)))
433  return error;
434 
435  return 0;
436 }
437 
439 
440 /*
441  * fd.io coding-style-patch-verification: ON
442  *
443  * Local Variables:
444  * eval: (c-set-style "gnu")
445  * End:
446  */
#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
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:169
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
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:55
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:337
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:181
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:448
unsigned char u8
Definition: types.h:56
ip6_ioam_analyser_main_t ioam_analyser_main
Definition: node.c:63
flow_report_stream_t * streams
Definition: flow_report.h:114
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:104
Analysed iOAM trace data.
Definition: ioam_analyse.h:41
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
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:169
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_call_init_function(vm, x)
Definition: init.h:227
#define VLIB_FRAME_SIZE
Definition: node.h:364
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: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:191
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:202
#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:380
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)
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:1055
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
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)
Analysed iOAM data.
Definition: ioam_analyse.h:97
ipfix_template_packet_t ipfix
Definition: flow_report.h:46
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:231
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:360
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:172
u32 mean_delay
Average Dealay for the flow.
Definition: ioam_analyse.h:70
u8 ip_version_and_header_length
Definition: ip4_packet.h:137
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:62
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:490
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:246
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:600
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:237
Definition: defs.h:46