LCOV - code coverage report
Current view: top level - plugins/ioam/analyse - ioam_summary_export.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 3 198 1.5 %
Date: 2023-10-26 01:39:38 Functions: 3 7 42.9 %

          Line data    Source code
       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           0 : 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           0 :   u8 *rewrite = 0;
      35             :   ip4_ipfix_template_packet_t *tp;
      36           0 :   u32 field_count = 0;
      37           0 :   u32 field_index = 0;
      38             :   flow_report_stream_t *stream;
      39             : 
      40           0 :   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           0 :   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           0 :   field_count += 6;
      57             : 
      58             :   /* allocate rewrite space */
      59           0 :   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           0 :   tp = (ip4_ipfix_template_packet_t *) rewrite;
      65           0 :   ip = (ip4_header_t *) & tp->ip4;
      66           0 :   udp = (udp_header_t *) (ip + 1);
      67           0 :   h = (ipfix_message_header_t *) (udp + 1);
      68           0 :   s = (ipfix_set_header_t *) (h + 1);
      69           0 :   t = (ipfix_template_header_t *) (s + 1);
      70           0 :   first_field = f = (ipfix_field_specifier_t *) (t + 1);
      71             : 
      72           0 :   ip->ip_version_and_header_length = 0x45;
      73           0 :   ip->ttl = 254;
      74           0 :   ip->protocol = IP_PROTOCOL_UDP;
      75           0 :   ip->src_address.as_u32 = exp->src_address.ip.ip4.as_u32;
      76           0 :   ip->dst_address.as_u32 = exp->ipfix_collector.ip.ip4.as_u32;
      77           0 :   udp->src_port = clib_host_to_net_u16 (collector_port);
      78           0 :   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
      79           0 :   udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
      80             : 
      81           0 :   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           0 :   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
      86             :                                       sourceIPv6Address,
      87             :                                       sizeof (ip6_address_t));
      88           0 :   f++;
      89             : 
      90           0 :   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
      91             :                                       destinationIPv6Address,
      92             :                                       sizeof (ip6_address_t));
      93           0 :   f++;
      94             : 
      95           0 :   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
      96             :                                       sourceTransportPort, 2);
      97           0 :   f++;
      98             : 
      99           0 :   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
     100             :                                       destinationTransportPort, 2);
     101           0 :   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           0 :   foreach_ioam_ipfix_field;
     110             : #undef _
     111             : 
     112           0 :   f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
     113             :                                       ioamNumberOfPaths, 2);
     114           0 :   f++;
     115             : 
     116             :   /* Add ioamPathMap manually */
     117           0 :   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           0 :   f++;
     123             : 
     124             :   /* Back to the template packet... */
     125           0 :   ip = (ip4_header_t *) & tp->ip4;
     126           0 :   udp = (udp_header_t *) (ip + 1);
     127             : 
     128           0 :   ASSERT (f - first_field);
     129             :   /* Field count in this template */
     130           0 :   t->id_count = ipfix_id_count (IOAM_FLOW_TEMPLATE_ID, f - first_field);
     131             : 
     132             :   /* set length in octets */
     133           0 :   s->set_id_length =
     134           0 :     ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
     135             : 
     136             :   /* message length in octets */
     137           0 :   h->version_length = version_length ((u8 *) f - (u8 *) h);
     138             : 
     139           0 :   ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
     140           0 :   ip->checksum = ip4_header_checksum (ip);
     141             : 
     142           0 :   return rewrite;
     143             : }
     144             : 
     145             : u16
     146           0 : 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           0 :   clib_spinlock_lock (&record->writer_lock);
     153             : 
     154           0 :   int field_index = 0;
     155             :   u16 tmp;
     156             :   int i, j;
     157           0 :   u16 num_paths = 0;
     158             :   u16 num_paths_offset;
     159             : 
     160             : 
     161             :   /* Add IPv6 source address manually */
     162           0 :   memcpy (b0->data + offset, &src->as_u64[0], sizeof (u64));
     163           0 :   offset += sizeof (u64);
     164           0 :   memcpy (b0->data + offset, &src->as_u64[1], sizeof (u64));
     165           0 :   offset += sizeof (u64);
     166             : 
     167             :   /* Add IPv6 destination address manually */
     168           0 :   memcpy (b0->data + offset, &dst->as_u64[0], sizeof (u64));
     169           0 :   offset += sizeof (u64);
     170           0 :   memcpy (b0->data + offset, &dst->as_u64[1], sizeof (u64));
     171           0 :   offset += sizeof (u64);
     172             : 
     173             :   /* Add source port manually */
     174           0 :   tmp = clib_host_to_net_u16 (src_port);
     175           0 :   memcpy (b0->data + offset, &tmp, sizeof (u16));
     176           0 :   offset += sizeof (u16);
     177             : 
     178             :   /* Add dest port manually */
     179           0 :   tmp = clib_host_to_net_u16 (dst_port);
     180           0 :   memcpy (b0->data + offset, &tmp, sizeof (u16));
     181           0 :   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           0 :   field_index++;
     193           0 :   foreach_ioam_ipfix_field;
     194             : #undef _
     195             : 
     196             :   /* Store num_paths_offset here and update later */
     197           0 :   num_paths_offset = offset;
     198           0 :   offset += sizeof (u16);
     199             : 
     200             :   /* Add ioamPathMap manually */
     201           0 :   for (i = 0; i < IOAM_MAX_PATHS_PER_FLOW; i++)
     202             :     {
     203           0 :       ioam_analyse_trace_record *trace = record->trace_data.path_data + i;
     204           0 :       ioam_analyse_trace_record *trace_cached =
     205           0 :         record->chached_data_list->trace_data.path_data + i;
     206           0 :       ioam_path *path = (ioam_path *) (b0->data + offset);
     207             : 
     208           0 :       if (!trace->is_free)
     209             :         {
     210           0 :           num_paths++;
     211             : 
     212           0 :           path->num_nodes = trace->num_nodes;
     213             : 
     214           0 :           path->trace_type = trace->trace_type;
     215           0 :           if (0 < (trace->pkt_counter - trace_cached->pkt_counter))
     216             :             {
     217           0 :               u64 new_sum = trace->mean_delay * record->seqno_data.rx_packets;
     218           0 :               u64 old_sum =
     219           0 :                 trace_cached->mean_delay *
     220           0 :                 record->chached_data_list->seqno_data.rx_packets;
     221           0 :               path->mean_delay =
     222           0 :                 (u32) ((new_sum - old_sum) / (trace->pkt_counter -
     223           0 :                                               trace_cached->pkt_counter));
     224           0 :               path->mean_delay = clib_host_to_net_u32 (path->mean_delay);
     225             :             }
     226             :           else
     227           0 :             path->mean_delay = 0;
     228             : 
     229           0 :           path->bytes_counter =
     230           0 :             trace->bytes_counter - trace_cached->bytes_counter;
     231           0 :           path->bytes_counter = clib_host_to_net_u32 (path->bytes_counter);
     232             : 
     233           0 :           path->pkt_counter = trace->pkt_counter - trace_cached->pkt_counter;
     234           0 :           path->pkt_counter = clib_host_to_net_u32 (path->pkt_counter);
     235           0 :           offset += sizeof (ioam_path);
     236             : 
     237           0 :           for (j = 0; j < trace->num_nodes; j++)
     238             :             {
     239           0 :               path->path[j].node_id =
     240           0 :                 clib_host_to_net_u32 (trace->path[j].node_id);
     241           0 :               path->path[j].ingress_if =
     242           0 :                 clib_host_to_net_u16 (trace->path[j].ingress_if);
     243           0 :               path->path[j].egress_if =
     244           0 :                 clib_host_to_net_u16 (trace->path[j].egress_if);
     245           0 :               path->path[j].state_up = trace->path[j].state_up;
     246             :             }
     247             : 
     248             :           //offset += (sizeof(ioam_path_map_t) * trace->num_nodes);
     249           0 :           offset += (sizeof (ioam_path_map_t) * IOAM_TRACE_MAX_NODES);  //FIXME
     250             :         }
     251             :     }
     252             : 
     253           0 :   num_paths = clib_host_to_net_u16 (num_paths);
     254           0 :   memcpy (b0->data + num_paths_offset, &num_paths, sizeof (u16));
     255             : 
     256             :   /* Update cache */
     257           0 :   *(record->chached_data_list) = *record;
     258           0 :   record->chached_data_list->chached_data_list = NULL;
     259             : 
     260           0 :   clib_spinlock_unlock (&record->writer_lock);
     261           0 :   return offset;
     262             : }
     263             : 
     264             : vlib_frame_t *
     265           0 : 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           0 :   vlib_buffer_t *b0 = NULL;
     270           0 :   u32 next_offset = 0;
     271           0 :   u32 bi0 = ~0;
     272             :   int i;
     273             :   ip4_ipfix_template_packet_t *tp;
     274             :   ipfix_message_header_t *h;
     275           0 :   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           0 :   vlib_main_t *vm = vlib_get_main ();
     281             :   ip6_address_t temp;
     282           0 :   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           0 :   stream = &exp->streams[fr->stream_index];
     288             : 
     289           0 :   clib_memset (&temp, 0, sizeof (ip6_address_t));
     290             : 
     291           0 :   aggregated_data = ioam_analyser_main.aggregated_data;
     292           0 :   data_len = vec_len (aggregated_data);
     293             : 
     294           0 :   vec_foreach_index (i, aggregated_data)
     295             :   {
     296           0 :     u8 flush = 0;
     297           0 :     record = aggregated_data + i;
     298             : 
     299             :     /* Flush if last entry */
     300           0 :     if (i == (data_len - 1))
     301           0 :       flush = 1;
     302             : 
     303           0 :     if (!record->is_free)
     304             :       {
     305             : 
     306           0 :         if (PREDICT_FALSE (b0 == NULL))
     307             :           {
     308           0 :             if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
     309           0 :               break;
     310             : 
     311           0 :             b0 = vlib_get_buffer (vm, bi0);
     312           0 :             memcpy (b0->data, fr->rewrite, vec_len (fr->rewrite));
     313           0 :             b0->current_data = 0;
     314           0 :             b0->current_length = vec_len (fr->rewrite);
     315           0 :             b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
     316           0 :             vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
     317           0 :             vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
     318             : 
     319           0 :             tp = vlib_buffer_get_current (b0);
     320           0 :             ip = &tp->ip4;
     321           0 :             h = &tp->ipfix.h;
     322           0 :             s = &tp->ipfix.s;
     323             : 
     324             :             /* FIXUP: message header export_time */
     325           0 :             h->export_time = clib_host_to_net_u32 (((u32) time (NULL)));
     326             : 
     327             :             /* FIXUP: message header sequence_number */
     328           0 :             h->sequence_number = stream->sequence_number++;
     329           0 :             h->sequence_number = clib_host_to_net_u32 (h->sequence_number);
     330           0 :             next_offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp);
     331             :           }
     332             : 
     333           0 :         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           0 :         if (next_offset > (exp->path_mtu - 250))
     339           0 :           flush = 1;
     340             :       }
     341             : 
     342           0 :     if (PREDICT_FALSE (flush && b0))
     343             :       {
     344           0 :         s->set_id_length = ipfix_set_id_length (IOAM_FLOW_TEMPLATE_ID,
     345           0 :                                                 next_offset - (sizeof (*ip) +
     346             :                                                                sizeof (*udp) +
     347             :                                                                sizeof (*h)));
     348           0 :         b0->current_length = next_offset;
     349           0 :         b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
     350           0 :         tp = vlib_buffer_get_current (b0);
     351           0 :         ip = (ip4_header_t *) & tp->ip4;
     352           0 :         udp = (udp_header_t *) (ip + 1);
     353             : 
     354           0 :         sum0 = ip->checksum;
     355           0 :         old_l0 = ip->length;
     356           0 :         new_l0 = clib_host_to_net_u16 ((u16) next_offset);
     357           0 :         sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
     358             :                                length /* changed member */ );
     359             : 
     360           0 :         ip->checksum = ip_csum_fold (sum0);
     361           0 :         ip->length = new_l0;
     362           0 :         udp->length =
     363           0 :           clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
     364             : 
     365           0 :         if (exp->udp_checksum)
     366             :           {
     367             :             /* RFC 7011 section 10.3.2. */
     368           0 :             udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
     369           0 :             if (udp->checksum == 0)
     370           0 :               udp->checksum = 0xffff;
     371             :           }
     372             : 
     373           0 :         to_next[0] = bi0;
     374           0 :         f->n_vectors++;
     375           0 :         to_next++;
     376             : 
     377           0 :         if (f->n_vectors == VLIB_FRAME_SIZE)
     378             :           {
     379           0 :             vlib_put_frame_to_node (vm, node_index, f);
     380           0 :             f = vlib_get_frame_to_node (vm, node_index);
     381           0 :             f->n_vectors = 0;
     382           0 :             to_next = vlib_frame_vector_args (f);
     383             :           }
     384           0 :         b0 = 0;
     385           0 :         bi0 = ~0;
     386             :       }
     387             :   }
     388             : 
     389           0 :   return f;
     390             : }
     391             : 
     392             : clib_error_t *
     393           0 : ioam_flow_create (u8 del)
     394             : {
     395             :   vnet_flow_report_add_del_args_t args;
     396             :   int rv;
     397           0 :   u32 domain_id = 0;
     398           0 :   ipfix_exporter_t *exp = &flow_report_main.exporters[0];
     399             :   u16 template_id;
     400             : 
     401           0 :   clib_memset (&args, 0, sizeof (args));
     402           0 :   args.rewrite_callback = ioam_template_rewrite;
     403           0 :   args.flow_data_callback = ioam_send_flows;
     404           0 :   del ? (args.is_add = 0) : (args.is_add = 1);
     405           0 :   args.domain_id = domain_id;
     406             : 
     407           0 :   rv = vnet_flow_report_add_del (exp, &args, &template_id);
     408             : 
     409           0 :   switch (rv)
     410             :     {
     411           0 :     case 0:
     412           0 :       break;
     413           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     414           0 :       return clib_error_return (0, "registration not found...");
     415           0 :     default:
     416           0 :       return clib_error_return (0, "vnet_flow_report_add_del returned %d",
     417             :                                 rv);
     418             :     }
     419             : 
     420           0 :   return 0;
     421             : }
     422             : 
     423             : clib_error_t *
     424         575 : ioam_flow_report_init (vlib_main_t * vm)
     425             : {
     426         575 :   return 0;
     427             : }
     428             : 
     429             : /* *INDENT-OFF* */
     430        6911 : 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             :  */

Generated by: LCOV version 1.14