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