misc: fix issues reported by clang-15
[vpp.git] / src / plugins / ioam / analyse / ioam_summary_export.c
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>
19 #include <ioam/analyse/ioam_summary_export.h>
20 #include <ioam/analyse/ip6/ip6_ioam_analyse.h>
21
22 u8 *
23 ioam_template_rewrite (ipfix_exporter_t *exp, flow_report_t *fr,
24                        u16 collector_port, ipfix_report_element_t *elts,
25                        u32 n_elts, u32 *stream_index)
26 {
27   ip4_header_t *ip;
28   udp_header_t *udp;
29   ipfix_message_header_t *h;
30   ipfix_set_header_t *s;
31   ipfix_template_header_t *t;
32   ipfix_field_specifier_t *f;
33   ipfix_field_specifier_t *first_field;
34   u8 *rewrite = 0;
35   ip4_ipfix_template_packet_t *tp;
36   u32 field_count = 0;
37   u32 field_index = 0;
38   flow_report_stream_t *stream;
39
40   stream = &exp->streams[fr->stream_index];
41
42   /* Determine field count */
43 #define _(field,mask,item,length)                                   \
44     {                                                               \
45   field_count++;                                                    \
46   fr->fields_to_send = clib_bitmap_set (fr->fields_to_send,         \
47                                         field_index, 1);            \
48     }                                                               \
49     field_index++;
50
51   foreach_ioam_ipfix_field;
52 #undef _
53
54   /* Add Src address, dest address, src port, dest port
55    * path map,  number of paths manually */
56   field_count += 6;
57
58   /* allocate rewrite space */
59   vec_validate_aligned (rewrite,
60                         sizeof (ip4_ipfix_template_packet_t)
61                         + field_count * sizeof (ipfix_field_specifier_t) - 1,
62                         CLIB_CACHE_LINE_BYTES);
63
64   tp = (ip4_ipfix_template_packet_t *) rewrite;
65   ip = (ip4_header_t *) & tp->ip4;
66   udp = (udp_header_t *) (ip + 1);
67   h = (ipfix_message_header_t *) (udp + 1);
68   s = (ipfix_set_header_t *) (h + 1);
69   t = (ipfix_template_header_t *) (s + 1);
70   first_field = f = (ipfix_field_specifier_t *) (t + 1);
71
72   ip->ip_version_and_header_length = 0x45;
73   ip->ttl = 254;
74   ip->protocol = IP_PROTOCOL_UDP;
75   ip->src_address.as_u32 = exp->src_address.ip.ip4.as_u32;
76   ip->dst_address.as_u32 = exp->ipfix_collector.ip.ip4.as_u32;
77   udp->src_port = clib_host_to_net_u16 (collector_port);
78   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
79   udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
80
81   h->domain_id = clib_host_to_net_u32 (stream->domain_id);      //fr->domain_id);
82
83   /* Add Src address, dest address, src port, dest port
84    * path map,  number of paths manually */
85   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
86                                       sourceIPv6Address,
87                                       sizeof (ip6_address_t));
88   f++;
89
90   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
91                                       destinationIPv6Address,
92                                       sizeof (ip6_address_t));
93   f++;
94
95   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
96                                       sourceTransportPort, 2);
97   f++;
98
99   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
100                                       destinationTransportPort, 2);
101   f++;
102
103 #define _(field,mask,item,length)                               \
104     {                                                           \
105   f->e_id_length = ipfix_e_id_length (0 /* enterprise */,       \
106     item, length);                                              \
107     f++;                                                        \
108     }
109   foreach_ioam_ipfix_field;
110 #undef _
111
112   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
113                                       ioamNumberOfPaths, 2);
114   f++;
115
116   /* Add ioamPathMap manually */
117   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
118                                       ioamPathMap,
119                                       (sizeof (ioam_path) +
120                                        (sizeof (ioam_path_map_t) *
121                                         IOAM_TRACE_MAX_NODES)));
122   f++;
123
124   /* Back to the template packet... */
125   ip = (ip4_header_t *) & tp->ip4;
126   udp = (udp_header_t *) (ip + 1);
127
128   ASSERT (f - first_field);
129   /* Field count in this template */
130   t->id_count = ipfix_id_count (IOAM_FLOW_TEMPLATE_ID, f - first_field);
131
132   /* set length in octets */
133   s->set_id_length =
134     ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
135
136   /* message length in octets */
137   h->version_length = version_length ((u8 *) f - (u8 *) h);
138
139   ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
140   ip->checksum = ip4_header_checksum (ip);
141
142   return rewrite;
143 }
144
145 u16
146 ioam_analyse_add_ipfix_record (flow_report_t * fr,
147                                ioam_analyser_data_t * record,
148                                vlib_buffer_t * b0, u16 offset,
149                                ip6_address_t * src, ip6_address_t * dst,
150                                u16 src_port, u16 dst_port)
151 {
152   clib_spinlock_lock (&record->writer_lock);
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++;
193   foreach_ioam_ipfix_field;
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     {
203       ioam_analyse_trace_record *trace = record->trace_data.path_data + i;
204       ioam_analyse_trace_record *trace_cached =
205         record->chached_data_list->trace_data.path_data + i;
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 *
220                 record->chached_data_list->seqno_data.rx_packets;
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;
258   record->chached_data_list->chached_data_list = NULL;
259
260   clib_spinlock_unlock (&record->writer_lock);
261   return offset;
262 }
263
264 vlib_frame_t *
265 ioam_send_flows (flow_report_main_t *frm, ipfix_exporter_t *exp,
266                  flow_report_t *fr, vlib_frame_t *f, u32 *to_next,
267                  u32 node_index)
268 {
269   vlib_buffer_t *b0 = NULL;
270   u32 next_offset = 0;
271   u32 bi0 = ~0;
272   int i;
273   ip4_ipfix_template_packet_t *tp;
274   ipfix_message_header_t *h;
275   ipfix_set_header_t *s = NULL;
276   ip4_header_t *ip;
277   udp_header_t *udp;
278   u16 new_l0, old_l0;
279   ip_csum_t sum0;
280   vlib_main_t *vm = vlib_get_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 = &exp->streams[fr->stream_index];
288
289   clib_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           }
332
333         next_offset = ioam_analyse_add_ipfix_record (fr, record,
334                                                      b0, next_offset,
335                                                      &temp, &temp, 0, 0);
336
337         /* Flush data if packet len is about to reach path mtu */
338         if (next_offset > (exp->path_mtu - 250))
339           flush = 1;
340       }
341
342     if (PREDICT_FALSE (flush && b0))
343       {
344         s->set_id_length = ipfix_set_id_length (IOAM_FLOW_TEMPLATE_ID,
345                                                 next_offset - (sizeof (*ip) +
346                                                                sizeof (*udp) +
347                                                                sizeof (*h)));
348         b0->current_length = next_offset;
349         b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
350         tp = vlib_buffer_get_current (b0);
351         ip = (ip4_header_t *) & tp->ip4;
352         udp = (udp_header_t *) (ip + 1);
353
354         sum0 = ip->checksum;
355         old_l0 = ip->length;
356         new_l0 = clib_host_to_net_u16 ((u16) next_offset);
357         sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
358                                length /* changed member */ );
359
360         ip->checksum = ip_csum_fold (sum0);
361         ip->length = new_l0;
362         udp->length =
363           clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
364
365         if (exp->udp_checksum)
366           {
367             /* RFC 7011 section 10.3.2. */
368             udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
369             if (udp->checksum == 0)
370               udp->checksum = 0xffff;
371           }
372
373         to_next[0] = bi0;
374         f->n_vectors++;
375         to_next++;
376
377         if (f->n_vectors == VLIB_FRAME_SIZE)
378           {
379             vlib_put_frame_to_node (vm, node_index, f);
380             f = vlib_get_frame_to_node (vm, node_index);
381             f->n_vectors = 0;
382             to_next = vlib_frame_vector_args (f);
383           }
384         b0 = 0;
385         bi0 = ~0;
386       }
387   }
388
389   return f;
390 }
391
392 clib_error_t *
393 ioam_flow_create (u8 del)
394 {
395   vnet_flow_report_add_del_args_t args;
396   int rv;
397   u32 domain_id = 0;
398   ipfix_exporter_t *exp = &flow_report_main.exporters[0];
399   u16 template_id;
400
401   clib_memset (&args, 0, sizeof (args));
402   args.rewrite_callback = ioam_template_rewrite;
403   args.flow_data_callback = ioam_send_flows;
404   del ? (args.is_add = 0) : (args.is_add = 1);
405   args.domain_id = domain_id;
406
407   rv = vnet_flow_report_add_del (exp, &args, &template_id);
408
409   switch (rv)
410     {
411     case 0:
412       break;
413     case VNET_API_ERROR_NO_SUCH_ENTRY:
414       return clib_error_return (0, "registration not found...");
415     default:
416       return clib_error_return (0, "vnet_flow_report_add_del returned %d",
417                                 rv);
418     }
419
420   return 0;
421 }
422
423 clib_error_t *
424 ioam_flow_report_init (vlib_main_t * vm)
425 {
426   return 0;
427 }
428
429 /* *INDENT-OFF* */
430 VLIB_INIT_FUNCTION (ioam_flow_report_init) =
431 {
432   .runs_after = VLIB_INITS("flow_report_init"),
433 };
434 /* *INDENT-ON* */
435
436 /*
437  * fd.io coding-style-patch-verification: ON
438  *
439  * Local Variables:
440  * eval: (c-set-style "gnu")
441  * End:
442  */