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