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