ipfix-export: refactor fields in flow_report_main
[vpp.git] / src / vnet / ipfix-export / flow_api.c
1 /*
2  *------------------------------------------------------------------
3  * flow_api.c - flow api
4  *
5  * Copyright (c) 2016 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22 #include <vnet/ip/ip_types_api.h>
23 #include <vnet/udp/udp_local.h>
24
25 #include <vnet/interface.h>
26 #include <vnet/api_errno.h>
27
28 #include <vnet/fib/fib_table.h>
29 #include <vnet/ipfix-export/flow_report.h>
30 #include <vnet/ipfix-export/flow_report_classify.h>
31
32 #include <vnet/format_fns.h>
33 #include <vnet/ipfix-export/ipfix_export.api_enum.h>
34 #include <vnet/ipfix-export/ipfix_export.api_types.h>
35
36 #define REPLY_MSG_ID_BASE frm->msg_id_base
37 #include <vlibapi/api_helper_macros.h>
38
39 static void
40 vl_api_set_ipfix_exporter_t_handler (vl_api_set_ipfix_exporter_t * mp)
41 {
42   vlib_main_t *vm = vlib_get_main ();
43   flow_report_main_t *frm = &flow_report_main;
44   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
45   vl_api_registration_t *reg;
46   vl_api_set_ipfix_exporter_reply_t *rmp;
47   ip4_address_t collector, src;
48   u16 collector_port = UDP_DST_PORT_ipfix;
49   u32 path_mtu;
50   u32 template_interval;
51   u8 udp_checksum;
52   u32 fib_id;
53   u32 fib_index = ~0;
54   int rv = 0;
55
56   reg = vl_api_client_index_to_registration (mp->client_index);
57   if (!reg)
58     return;
59
60   if (mp->src_address.af == ADDRESS_IP6
61       || mp->collector_address.af == ADDRESS_IP6)
62     {
63       rv = VNET_API_ERROR_UNIMPLEMENTED;
64       goto out;
65     }
66
67   ip4_address_decode (mp->collector_address.un.ip4, &collector);
68   collector_port = ntohs (mp->collector_port);
69   if (collector_port == (u16) ~ 0)
70     collector_port = UDP_DST_PORT_ipfix;
71   ip4_address_decode (mp->src_address.un.ip4, &src);
72   fib_id = ntohl (mp->vrf_id);
73
74   ip4_main_t *im = &ip4_main;
75   if (fib_id == ~0)
76     {
77       fib_index = ~0;
78     }
79   else
80     {
81       uword *p = hash_get (im->fib_index_by_table_id, fib_id);
82       if (!p)
83         {
84           rv = VNET_API_ERROR_NO_SUCH_FIB;
85           goto out;
86         }
87       fib_index = p[0];
88     }
89
90   path_mtu = ntohl (mp->path_mtu);
91   if (path_mtu == ~0)
92     path_mtu = 512;             // RFC 7011 section 10.3.3.
93   template_interval = ntohl (mp->template_interval);
94   if (template_interval == ~0)
95     template_interval = 20;
96   udp_checksum = mp->udp_checksum;
97
98   if (collector.as_u32 != 0 && src.as_u32 == 0)
99     {
100       rv = VNET_API_ERROR_INVALID_VALUE;
101       goto out;
102     }
103
104   if (path_mtu > 1450 /* vpp does not support fragmentation */ )
105     {
106       rv = VNET_API_ERROR_INVALID_VALUE;
107       goto out;
108     }
109
110   if (path_mtu < 68)
111     {
112       rv = VNET_API_ERROR_INVALID_VALUE;
113       goto out;
114     }
115
116   /* Reset report streams if we are reconfiguring IP addresses */
117   if (exp->ipfix_collector.as_u32 != collector.as_u32 ||
118       exp->src_address.as_u32 != src.as_u32 ||
119       exp->collector_port != collector_port)
120     vnet_flow_reports_reset (frm);
121
122   exp->ipfix_collector.as_u32 = collector.as_u32;
123   exp->collector_port = collector_port;
124   exp->src_address.as_u32 = src.as_u32;
125   exp->fib_index = fib_index;
126   exp->path_mtu = path_mtu;
127   exp->template_interval = template_interval;
128   exp->udp_checksum = udp_checksum;
129
130   /* Turn on the flow reporting process */
131   vlib_process_signal_event (vm, flow_report_process_node.index, 1, 0);
132
133 out:
134   REPLY_MACRO (VL_API_SET_IPFIX_EXPORTER_REPLY);
135 }
136
137 static void
138 vl_api_ipfix_exporter_dump_t_handler (vl_api_ipfix_exporter_dump_t * mp)
139 {
140   flow_report_main_t *frm = &flow_report_main;
141   ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
142   vl_api_registration_t *reg;
143   vl_api_ipfix_exporter_details_t *rmp;
144   ip4_main_t *im = &ip4_main;
145   ip46_address_t collector = {.as_u64[0] = 0,.as_u64[1] = 0 };
146   ip46_address_t src = {.as_u64[0] = 0,.as_u64[1] = 0 };
147   u32 vrf_id;
148
149   reg = vl_api_client_index_to_registration (mp->client_index);
150   if (!reg)
151     return;
152
153   rmp = vl_msg_api_alloc (sizeof (*rmp));
154   clib_memset (rmp, 0, sizeof (*rmp));
155   rmp->_vl_msg_id =
156     ntohs ((REPLY_MSG_ID_BASE) + VL_API_IPFIX_EXPORTER_DETAILS);
157   rmp->context = mp->context;
158
159   memcpy (&collector.ip4, &exp->ipfix_collector, sizeof (ip4_address_t));
160   ip_address_encode (&collector, IP46_TYPE_IP4, &rmp->collector_address);
161
162   rmp->collector_port = htons (exp->collector_port);
163
164   memcpy (&src.ip4, &exp->src_address, sizeof (ip4_address_t));
165   ip_address_encode (&src, IP46_TYPE_IP4, &rmp->src_address);
166
167   if (exp->fib_index == ~0)
168     vrf_id = ~0;
169   else
170     vrf_id = im->fibs[exp->fib_index].ft_table_id;
171   rmp->vrf_id = htonl (vrf_id);
172   rmp->path_mtu = htonl (exp->path_mtu);
173   rmp->template_interval = htonl (exp->template_interval);
174   rmp->udp_checksum = (exp->udp_checksum != 0);
175
176   vl_api_send_msg (reg, (u8 *) rmp);
177 }
178
179 static void
180   vl_api_set_ipfix_classify_stream_t_handler
181   (vl_api_set_ipfix_classify_stream_t * mp)
182 {
183   vl_api_set_ipfix_classify_stream_reply_t *rmp;
184   flow_report_classify_main_t *fcm = &flow_report_classify_main;
185   flow_report_main_t *frm = &flow_report_main;
186   u32 domain_id = 0;
187   u32 src_port = UDP_DST_PORT_ipfix;
188   int rv = 0;
189
190   domain_id = ntohl (mp->domain_id);
191   src_port = ntohs (mp->src_port);
192
193   if (fcm->src_port != 0 &&
194       (fcm->domain_id != domain_id || fcm->src_port != (u16) src_port))
195     {
196       int rv = vnet_stream_change (frm, fcm->domain_id, fcm->src_port,
197                                    domain_id, (u16) src_port);
198       ASSERT (rv == 0);
199     }
200
201   fcm->domain_id = domain_id;
202   fcm->src_port = (u16) src_port;
203
204   REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
205 }
206
207 static void
208   vl_api_ipfix_classify_stream_dump_t_handler
209   (vl_api_ipfix_classify_stream_dump_t * mp)
210 {
211   flow_report_classify_main_t *fcm = &flow_report_classify_main;
212   vl_api_registration_t *reg;
213   vl_api_ipfix_classify_stream_details_t *rmp;
214
215   reg = vl_api_client_index_to_registration (mp->client_index);
216   if (!reg)
217     return;
218
219   rmp = vl_msg_api_alloc (sizeof (*rmp));
220   clib_memset (rmp, 0, sizeof (*rmp));
221   rmp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_STREAM_DETAILS);
222   rmp->context = mp->context;
223   rmp->domain_id = htonl (fcm->domain_id);
224   rmp->src_port = htons (fcm->src_port);
225
226   vl_api_send_msg (reg, (u8 *) rmp);
227 }
228
229 static void
230   vl_api_ipfix_classify_table_add_del_t_handler
231   (vl_api_ipfix_classify_table_add_del_t * mp)
232 {
233   vl_api_ipfix_classify_table_add_del_reply_t *rmp;
234   vl_api_registration_t *reg;
235   flow_report_classify_main_t *fcm = &flow_report_classify_main;
236   flow_report_main_t *frm = &flow_report_main;
237   vnet_flow_report_add_del_args_t args;
238   ipfix_classify_table_t *table;
239   int is_add;
240   u32 classify_table_index;
241   u8 ip_version;
242   u8 transport_protocol;
243   int rv = 0;
244
245   reg = vl_api_client_index_to_registration (mp->client_index);
246   if (!reg)
247     return;
248
249   classify_table_index = ntohl (mp->table_id);
250   ip_version = (mp->ip_version == ADDRESS_IP4) ? 4 : 6;
251   transport_protocol = mp->transport_protocol;
252   is_add = mp->is_add;
253
254   if (fcm->src_port == 0)
255     {
256       /* call set_ipfix_classify_stream first */
257       rv = VNET_API_ERROR_UNSPECIFIED;
258       goto out;
259     }
260
261   clib_memset (&args, 0, sizeof (args));
262
263   table = 0;
264   int i;
265   for (i = 0; i < vec_len (fcm->tables); i++)
266     if (ipfix_classify_table_index_valid (i))
267       if (fcm->tables[i].classify_table_index == classify_table_index)
268         {
269           table = &fcm->tables[i];
270           break;
271         }
272
273   if (is_add)
274     {
275       if (table)
276         {
277           rv = VNET_API_ERROR_VALUE_EXIST;
278           goto out;
279         }
280       table = ipfix_classify_add_table ();
281       table->classify_table_index = classify_table_index;
282     }
283   else
284     {
285       if (!table)
286         {
287           rv = VNET_API_ERROR_NO_SUCH_ENTRY;
288           goto out;
289         }
290     }
291
292   table->ip_version = ip_version;
293   table->transport_protocol = transport_protocol;
294
295   args.opaque.as_uword = table - fcm->tables;
296   args.rewrite_callback = ipfix_classify_template_rewrite;
297   args.flow_data_callback = ipfix_classify_send_flows;
298   args.is_add = is_add;
299   args.domain_id = fcm->domain_id;
300   args.src_port = fcm->src_port;
301
302   rv = vnet_flow_report_add_del (frm, &args, NULL);
303
304   /* If deleting, or add failed */
305   if (is_add == 0 || (rv && is_add))
306     ipfix_classify_delete_table (table - fcm->tables);
307
308 out:
309   REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
310 }
311
312 static void
313 send_ipfix_classify_table_details (u32 table_index,
314                                    vl_api_registration_t * reg, u32 context)
315 {
316   flow_report_classify_main_t *fcm = &flow_report_classify_main;
317   vl_api_ipfix_classify_table_details_t *mp;
318
319   ipfix_classify_table_t *table = &fcm->tables[table_index];
320
321   mp = vl_msg_api_alloc (sizeof (*mp));
322   clib_memset (mp, 0, sizeof (*mp));
323   mp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_TABLE_DETAILS);
324   mp->context = context;
325   mp->table_id = htonl (table->classify_table_index);
326   mp->ip_version = (table->ip_version == 4) ? ADDRESS_IP4 : ADDRESS_IP6;
327   mp->transport_protocol = table->transport_protocol;
328
329   vl_api_send_msg (reg, (u8 *) mp);
330 }
331
332 static void
333   vl_api_ipfix_classify_table_dump_t_handler
334   (vl_api_ipfix_classify_table_dump_t * mp)
335 {
336   flow_report_classify_main_t *fcm = &flow_report_classify_main;
337   vl_api_registration_t *reg;
338   u32 i;
339
340   reg = vl_api_client_index_to_registration (mp->client_index);
341   if (!reg)
342     return;
343
344   for (i = 0; i < vec_len (fcm->tables); i++)
345     if (ipfix_classify_table_index_valid (i))
346       send_ipfix_classify_table_details (i, reg, mp->context);
347 }
348
349 static void
350 vl_api_ipfix_flush_t_handler (vl_api_ipfix_flush_t * mp)
351 {
352   flow_report_main_t *frm = &flow_report_main;
353   vl_api_ipfix_flush_reply_t *rmp;
354   vl_api_registration_t *reg;
355   vlib_main_t *vm = vlib_get_main ();
356   int rv = 0;
357
358   reg = vl_api_client_index_to_registration (mp->client_index);
359   if (!reg)
360     return;
361
362   /* poke the flow reporting process */
363   vlib_process_signal_event (vm, flow_report_process_node.index,
364                              1 /* type_opaque */ , 0 /* data */ );
365
366   REPLY_MACRO (VL_API_IPFIX_FLUSH_REPLY);
367 }
368
369 #include <vnet/ipfix-export/ipfix_export.api.c>
370 static clib_error_t *
371 flow_api_hookup (vlib_main_t * vm)
372 {
373   flow_report_main_t *frm = &flow_report_main;
374   /*
375    * Set up the (msg_name, crc, message-id) table
376    */
377   REPLY_MSG_ID_BASE = setup_message_id_table ();
378
379   return 0;
380 }
381
382 VLIB_API_INIT_FUNCTION (flow_api_hookup);
383
384 /*
385  * fd.io coding-style-patch-verification: ON
386  *
387  * Local Variables:
388  * eval: (c-set-style "gnu")
389  * End:
390  */