84d8ddf9e93da6c50339a1e601f5fe71987c410c
[vpp.git] / src / plugins / ioam / udp-ping / udp_ping_export.c
1 /*
2  * Copyright (c) 2016 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 <vnet/ipfix-export/flow_report.h>
17 #include <ioam/analyse/ioam_summary_export.h>
18 #include <vnet/api_errno.h>
19 #include <vnet/ip/ip4.h>
20 #include <vnet/udp/udp_local.h>
21 #include <ioam/udp-ping/udp_ping.h>
22
23 #define UDP_PING_EXPORT_RECORD_SIZE 400
24
25 static u8 *
26 udp_ping_template_rewrite (flow_report_main_t * frm, flow_report_t * fr,
27                            ip4_address_t * collector_address,
28                            ip4_address_t * src_address, u16 collector_port,
29                            ipfix_report_element_t * elts,
30                            u32 n_elts, u32 * stream_index)
31 {
32   return ioam_template_rewrite (frm, fr, collector_address,
33                                 src_address, collector_port, elts, n_elts,
34                                 stream_index);
35 }
36
37 static vlib_frame_t *
38 udp_ping_send_flows (flow_report_main_t * frm, flow_report_t * fr,
39                      vlib_frame_t * f, u32 * to_next, u32 node_index)
40 {
41   vlib_buffer_t *b0 = NULL;
42   u32 next_offset = 0;
43   u32 bi0 = ~0;
44   int i, j;
45   ip4_ipfix_template_packet_t *tp;
46   ipfix_message_header_t *h;
47   ipfix_set_header_t *s = NULL;
48   ip4_header_t *ip;
49   udp_header_t *udp;
50   u32 records_this_buffer;
51   u16 new_l0, old_l0;
52   ip_csum_t sum0;
53   vlib_main_t *vm = frm->vlib_main;
54   flow_report_stream_t *stream;
55   udp_ping_flow_data *stats;
56   ip46_udp_ping_flow *ip46_flow;
57   u16 src_port, dst_port;
58   u16 data_len;
59   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
60
61   stream = &exp->streams[fr->stream_index];
62   data_len = vec_len (udp_ping_main.ip46_flow);
63
64   for (i = 0; i < data_len; i++)
65     {
66       if (pool_is_free_index (udp_ping_main.ip46_flow, i))
67         continue;
68
69       ip46_flow = pool_elt_at_index (udp_ping_main.ip46_flow, i);
70       j = 0;
71       for (src_port = ip46_flow->udp_data.start_src_port;
72            src_port <= ip46_flow->udp_data.end_src_port; src_port++)
73         {
74           for (dst_port = ip46_flow->udp_data.start_dst_port;
75                dst_port <= ip46_flow->udp_data.end_dst_port; dst_port++, j++)
76             {
77               stats = ip46_flow->udp_data.stats + j;
78               if (PREDICT_FALSE (b0 == NULL))
79                 {
80                   if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
81                     break;
82
83
84                   b0 = vlib_get_buffer (vm, bi0);
85                   memcpy (b0->data, fr->rewrite, vec_len (fr->rewrite));
86                   b0->current_data = 0;
87                   b0->current_length = vec_len (fr->rewrite);
88                   b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
89                   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
90                   vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
91
92                   tp = vlib_buffer_get_current (b0);
93                   ip = &tp->ip4;
94                   h = &tp->ipfix.h;
95                   s = &tp->ipfix.s;
96
97                   /* FIXUP: message header export_time */
98                   h->export_time = clib_host_to_net_u32 (((u32) time (NULL)));
99
100                   /* FIXUP: message header sequence_number */
101                   h->sequence_number = stream->sequence_number++;
102                   h->sequence_number =
103                     clib_host_to_net_u32 (h->sequence_number);
104                   next_offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp);
105                   records_this_buffer = 0;
106                 }
107
108               next_offset = ioam_analyse_add_ipfix_record (fr,
109                                                            &stats->analyse_data,
110                                                            b0, next_offset,
111                                                            &ip46_flow->
112                                                            src.ip6,
113                                                            &ip46_flow->
114                                                            dst.ip6, src_port,
115                                                            dst_port);
116
117               //u32 pak_sent = clib_host_to_net_u32(stats->pak_sent);
118               //memcpy (b0->data + next_offset, &pak_sent, sizeof(u32));
119               //next_offset += sizeof(u32);
120
121               records_this_buffer++;
122
123               /* Flush data if packet len is about to reach path mtu */
124               if (next_offset > (exp->path_mtu - UDP_PING_EXPORT_RECORD_SIZE))
125                 {
126                   b0->current_length = next_offset;
127                   b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
128                   tp = vlib_buffer_get_current (b0);
129                   ip = (ip4_header_t *) & tp->ip4;
130                   udp = (udp_header_t *) (ip + 1);
131                   h = &tp->ipfix.h;
132                   s = &tp->ipfix.s;
133
134                   s->set_id_length =
135                     ipfix_set_id_length (IOAM_FLOW_TEMPLATE_ID,
136                                          next_offset - (sizeof (*ip) +
137                                                         sizeof (*udp) +
138                                                         sizeof (*h)));
139                   h->version_length =
140                     version_length (next_offset -
141                                     (sizeof (*ip) + sizeof (*udp)));
142
143                   sum0 = ip->checksum;
144                   old_l0 = ip->length;
145                   new_l0 = clib_host_to_net_u16 ((u16) next_offset);
146                   sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
147                                          length /* changed member */ );
148
149                   ip->checksum = ip_csum_fold (sum0);
150                   ip->length = new_l0;
151                   udp->length =
152                     clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
153
154                   udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
155                   if (udp->checksum == 0)
156                     udp->checksum = 0xffff;
157
158                   ASSERT (ip4_header_checksum_is_valid (ip));
159
160                   to_next[0] = bi0;
161                   f->n_vectors++;
162                   to_next++;
163
164                   if (f->n_vectors == VLIB_FRAME_SIZE)
165                     {
166                       vlib_put_frame_to_node (vm, node_index, f);
167                       f = vlib_get_frame_to_node (vm, node_index);
168                       f->n_vectors = 0;
169                       to_next = vlib_frame_vector_args (f);
170                     }
171                   b0 = 0;
172                   bi0 = ~0;
173                 }
174             }
175         }
176     }
177
178   if (b0)
179     {
180       b0->current_length = next_offset;
181       b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
182       tp = vlib_buffer_get_current (b0);
183       ip = (ip4_header_t *) & tp->ip4;
184       udp = (udp_header_t *) (ip + 1);
185       h = &tp->ipfix.h;
186       s = &tp->ipfix.s;
187
188       s->set_id_length = ipfix_set_id_length (IOAM_FLOW_TEMPLATE_ID,
189                                               next_offset - (sizeof (*ip) +
190                                                              sizeof (*udp) +
191                                                              sizeof (*h)));
192       h->version_length =
193         version_length (next_offset - (sizeof (*ip) + sizeof (*udp)));
194
195       sum0 = ip->checksum;
196       old_l0 = ip->length;
197       new_l0 = clib_host_to_net_u16 ((u16) next_offset);
198       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
199                              length /* changed member */ );
200
201       ip->checksum = ip_csum_fold (sum0);
202       ip->length = new_l0;
203       udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
204
205       udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
206       if (udp->checksum == 0)
207         udp->checksum = 0xffff;
208
209       ASSERT (ip4_header_checksum_is_valid (ip));
210
211       to_next[0] = bi0;
212       f->n_vectors++;
213       to_next++;
214
215       if (f->n_vectors == VLIB_FRAME_SIZE)
216         {
217           vlib_put_frame_to_node (vm, node_index, f);
218           f = vlib_get_frame_to_node (vm, node_index);
219           f->n_vectors = 0;
220           to_next = vlib_frame_vector_args (f);
221         }
222       b0 = 0;
223       bi0 = ~0;
224     }
225   return f;
226 }
227
228 clib_error_t *
229 udp_ping_flow_create (u8 del)
230 {
231   vnet_flow_report_add_del_args_t args;
232   int rv;
233   u32 domain_id = 0;
234   flow_report_main_t *frm = &flow_report_main;
235   u16 template_id;
236
237   clib_memset (&args, 0, sizeof (args));
238   args.rewrite_callback = udp_ping_template_rewrite;
239   args.flow_data_callback = udp_ping_send_flows;
240   del ? (args.is_add = 0) : (args.is_add = 1);
241   args.domain_id = domain_id;
242   args.src_port = UDP_DST_PORT_ipfix;
243
244   rv = vnet_flow_report_add_del (frm, &args, &template_id);
245
246   switch (rv)
247     {
248     case 0:
249       break;
250     case VNET_API_ERROR_NO_SUCH_ENTRY:
251       return clib_error_return (0, "registration not found...");
252     default:
253       return clib_error_return (0, "vnet_flow_report_add_del returned %d",
254                                 rv);
255     }
256
257   return 0;
258 }
259
260 static clib_error_t *
261 set_udp_ping_export_command_fn (vlib_main_t * vm, unformat_input_t * input,
262                                 vlib_cli_command_t * cmd)
263 {
264   //int rv;
265   int is_add = 1;
266
267   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
268     {
269       if (unformat (input, "export-ipfix"))
270         is_add = 1;
271       else if (unformat (input, "disable"))
272         is_add = 0;
273       else
274         break;
275     }
276
277   if (is_add)
278     (void) udp_ping_flow_create (0);
279   else
280     (void) udp_ping_flow_create (1);
281
282   return 0;
283 }
284
285 /* *INDENT-OFF* */
286 VLIB_CLI_COMMAND (set_udp_ping_export_command, static) = {
287     .path = "set udp-ping export-ipfix",
288     .short_help = "set udp-ping export-ipfix [disable]",
289     .function = set_udp_ping_export_command_fn,
290 };
291 /* *INDENT-ON* */
292
293 clib_error_t *
294 udp_ping_flow_report_init (vlib_main_t * vm)
295 {
296   return 0;
297 }
298
299 /* *INDENT-OFF* */
300 VLIB_INIT_FUNCTION (udp_ping_flow_report_init) =
301 {
302   .runs_after = VLIB_INITS ("flow_report_init"),
303 };
304 /* *INDENT-ON* */
305
306
307 /*
308  * fd.io coding-style-patch-verification: ON
309  *
310  * Local Variables:
311  * eval: (c-set-style "gnu")
312  * End:
313  */