misc: fix api in ipfix_classify_table_add/details
[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/vnet_msg_enum.h>
33
34 #define vl_typedefs             /* define message structures */
35 #include <vnet/vnet_all_api_h.h>
36 #undef vl_typedefs
37
38 #define vl_endianfun            /* define message structures */
39 #include <vnet/vnet_all_api_h.h>
40 #undef vl_endianfun
41
42 /* instantiate all the print functions we know about */
43 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44 #define vl_printfun
45 #include <vnet/vnet_all_api_h.h>
46 #undef vl_printfun
47
48 #include <vlibapi/api_helper_macros.h>
49
50 #define foreach_vpe_api_msg                                             \
51 _(SET_IPFIX_EXPORTER, set_ipfix_exporter)                               \
52 _(IPFIX_EXPORTER_DUMP, ipfix_exporter_dump)                             \
53 _(SET_IPFIX_CLASSIFY_STREAM, set_ipfix_classify_stream)                 \
54 _(IPFIX_CLASSIFY_STREAM_DUMP, ipfix_classify_stream_dump)               \
55 _(IPFIX_CLASSIFY_TABLE_ADD_DEL, ipfix_classify_table_add_del)           \
56 _(IPFIX_CLASSIFY_TABLE_DUMP, ipfix_classify_table_dump)                 \
57 _(IPFIX_FLUSH, ipfix_flush)
58
59 static void
60 vl_api_set_ipfix_exporter_t_handler (vl_api_set_ipfix_exporter_t * mp)
61 {
62   vlib_main_t *vm = vlib_get_main ();
63   flow_report_main_t *frm = &flow_report_main;
64   vl_api_registration_t *reg;
65   vl_api_set_ipfix_exporter_reply_t *rmp;
66   ip4_address_t collector, src;
67   u16 collector_port = UDP_DST_PORT_ipfix;
68   u32 path_mtu;
69   u32 template_interval;
70   u8 udp_checksum;
71   u32 fib_id;
72   u32 fib_index = ~0;
73   int rv = 0;
74
75   reg = vl_api_client_index_to_registration (mp->client_index);
76   if (!reg)
77     return;
78
79   if (mp->src_address.af == ADDRESS_IP6
80       || mp->collector_address.af == ADDRESS_IP6)
81     {
82       rv = VNET_API_ERROR_UNIMPLEMENTED;
83       goto out;
84     }
85
86   ip4_address_decode (mp->collector_address.un.ip4, &collector);
87   collector_port = ntohs (mp->collector_port);
88   if (collector_port == (u16) ~ 0)
89     collector_port = UDP_DST_PORT_ipfix;
90   ip4_address_decode (mp->src_address.un.ip4, &src);
91   fib_id = ntohl (mp->vrf_id);
92
93   ip4_main_t *im = &ip4_main;
94   if (fib_id == ~0)
95     {
96       fib_index = ~0;
97     }
98   else
99     {
100       uword *p = hash_get (im->fib_index_by_table_id, fib_id);
101       if (!p)
102         {
103           rv = VNET_API_ERROR_NO_SUCH_FIB;
104           goto out;
105         }
106       fib_index = p[0];
107     }
108
109   path_mtu = ntohl (mp->path_mtu);
110   if (path_mtu == ~0)
111     path_mtu = 512;             // RFC 7011 section 10.3.3.
112   template_interval = ntohl (mp->template_interval);
113   if (template_interval == ~0)
114     template_interval = 20;
115   udp_checksum = mp->udp_checksum;
116
117   if (collector.as_u32 != 0 && src.as_u32 == 0)
118     {
119       rv = VNET_API_ERROR_INVALID_VALUE;
120       goto out;
121     }
122
123   if (path_mtu > 1450 /* vpp does not support fragmentation */ )
124     {
125       rv = VNET_API_ERROR_INVALID_VALUE;
126       goto out;
127     }
128
129   if (path_mtu < 68)
130     {
131       rv = VNET_API_ERROR_INVALID_VALUE;
132       goto out;
133     }
134
135   /* Reset report streams if we are reconfiguring IP addresses */
136   if (frm->ipfix_collector.as_u32 != collector.as_u32 ||
137       frm->src_address.as_u32 != src.as_u32 ||
138       frm->collector_port != collector_port)
139     vnet_flow_reports_reset (frm);
140
141   frm->ipfix_collector.as_u32 = collector.as_u32;
142   frm->collector_port = collector_port;
143   frm->src_address.as_u32 = src.as_u32;
144   frm->fib_index = fib_index;
145   frm->path_mtu = path_mtu;
146   frm->template_interval = template_interval;
147   frm->udp_checksum = udp_checksum;
148
149   /* Turn on the flow reporting process */
150   vlib_process_signal_event (vm, flow_report_process_node.index, 1, 0);
151
152 out:
153   REPLY_MACRO (VL_API_SET_IPFIX_EXPORTER_REPLY);
154 }
155
156 static void
157 vl_api_ipfix_exporter_dump_t_handler (vl_api_ipfix_exporter_dump_t * mp)
158 {
159   flow_report_main_t *frm = &flow_report_main;
160   vl_api_registration_t *reg;
161   vl_api_ipfix_exporter_details_t *rmp;
162   ip4_main_t *im = &ip4_main;
163   ip46_address_t collector = {.as_u64[0] = 0,.as_u64[1] = 0 };
164   ip46_address_t src = {.as_u64[0] = 0,.as_u64[1] = 0 };
165   u32 vrf_id;
166
167   reg = vl_api_client_index_to_registration (mp->client_index);
168   if (!reg)
169     return;
170
171   rmp = vl_msg_api_alloc (sizeof (*rmp));
172   clib_memset (rmp, 0, sizeof (*rmp));
173   rmp->_vl_msg_id = ntohs (VL_API_IPFIX_EXPORTER_DETAILS);
174   rmp->context = mp->context;
175
176   memcpy (&collector.ip4, &frm->ipfix_collector, sizeof (ip4_address_t));
177   ip_address_encode (&collector, IP46_TYPE_IP4, &rmp->collector_address);
178
179   rmp->collector_port = htons (frm->collector_port);
180
181   memcpy (&src.ip4, &frm->src_address, sizeof (ip4_address_t));
182   ip_address_encode (&src, IP46_TYPE_IP4, &rmp->src_address);
183
184   if (frm->fib_index == ~0)
185     vrf_id = ~0;
186   else
187     vrf_id = im->fibs[frm->fib_index].ft_table_id;
188   rmp->vrf_id = htonl (vrf_id);
189   rmp->path_mtu = htonl (frm->path_mtu);
190   rmp->template_interval = htonl (frm->template_interval);
191   rmp->udp_checksum = (frm->udp_checksum != 0);
192
193   vl_api_send_msg (reg, (u8 *) rmp);
194 }
195
196 static void
197   vl_api_set_ipfix_classify_stream_t_handler
198   (vl_api_set_ipfix_classify_stream_t * mp)
199 {
200   vl_api_set_ipfix_classify_stream_reply_t *rmp;
201   flow_report_classify_main_t *fcm = &flow_report_classify_main;
202   flow_report_main_t *frm = &flow_report_main;
203   u32 domain_id = 0;
204   u32 src_port = UDP_DST_PORT_ipfix;
205   int rv = 0;
206
207   domain_id = ntohl (mp->domain_id);
208   src_port = ntohs (mp->src_port);
209
210   if (fcm->src_port != 0 &&
211       (fcm->domain_id != domain_id || fcm->src_port != (u16) src_port))
212     {
213       int rv = vnet_stream_change (frm, fcm->domain_id, fcm->src_port,
214                                    domain_id, (u16) src_port);
215       ASSERT (rv == 0);
216     }
217
218   fcm->domain_id = domain_id;
219   fcm->src_port = (u16) src_port;
220
221   REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
222 }
223
224 static void
225   vl_api_ipfix_classify_stream_dump_t_handler
226   (vl_api_ipfix_classify_stream_dump_t * mp)
227 {
228   flow_report_classify_main_t *fcm = &flow_report_classify_main;
229   vl_api_registration_t *reg;
230   vl_api_ipfix_classify_stream_details_t *rmp;
231
232   reg = vl_api_client_index_to_registration (mp->client_index);
233   if (!reg)
234     return;
235
236   rmp = vl_msg_api_alloc (sizeof (*rmp));
237   clib_memset (rmp, 0, sizeof (*rmp));
238   rmp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_STREAM_DETAILS);
239   rmp->context = mp->context;
240   rmp->domain_id = htonl (fcm->domain_id);
241   rmp->src_port = htons (fcm->src_port);
242
243   vl_api_send_msg (reg, (u8 *) rmp);
244 }
245
246 static void
247   vl_api_ipfix_classify_table_add_del_t_handler
248   (vl_api_ipfix_classify_table_add_del_t * mp)
249 {
250   vl_api_ipfix_classify_table_add_del_reply_t *rmp;
251   vl_api_registration_t *reg;
252   flow_report_classify_main_t *fcm = &flow_report_classify_main;
253   flow_report_main_t *frm = &flow_report_main;
254   vnet_flow_report_add_del_args_t args;
255   ipfix_classify_table_t *table;
256   int is_add;
257   u32 classify_table_index;
258   u8 ip_version;
259   u8 transport_protocol;
260   int rv = 0;
261
262   reg = vl_api_client_index_to_registration (mp->client_index);
263   if (!reg)
264     return;
265
266   classify_table_index = ntohl (mp->table_id);
267   ip_version = (mp->ip_version == ADDRESS_IP4) ? 4 : 6;
268   transport_protocol = mp->transport_protocol;
269   is_add = mp->is_add;
270
271   if (fcm->src_port == 0)
272     {
273       /* call set_ipfix_classify_stream first */
274       rv = VNET_API_ERROR_UNSPECIFIED;
275       goto out;
276     }
277
278   clib_memset (&args, 0, sizeof (args));
279
280   table = 0;
281   int i;
282   for (i = 0; i < vec_len (fcm->tables); i++)
283     if (ipfix_classify_table_index_valid (i))
284       if (fcm->tables[i].classify_table_index == classify_table_index)
285         {
286           table = &fcm->tables[i];
287           break;
288         }
289
290   if (is_add)
291     {
292       if (table)
293         {
294           rv = VNET_API_ERROR_VALUE_EXIST;
295           goto out;
296         }
297       table = ipfix_classify_add_table ();
298       table->classify_table_index = classify_table_index;
299     }
300   else
301     {
302       if (!table)
303         {
304           rv = VNET_API_ERROR_NO_SUCH_ENTRY;
305           goto out;
306         }
307     }
308
309   table->ip_version = ip_version;
310   table->transport_protocol = transport_protocol;
311
312   args.opaque.as_uword = table - fcm->tables;
313   args.rewrite_callback = ipfix_classify_template_rewrite;
314   args.flow_data_callback = ipfix_classify_send_flows;
315   args.is_add = is_add;
316   args.domain_id = fcm->domain_id;
317   args.src_port = fcm->src_port;
318
319   rv = vnet_flow_report_add_del (frm, &args, NULL);
320
321   /* If deleting, or add failed */
322   if (is_add == 0 || (rv && is_add))
323     ipfix_classify_delete_table (table - fcm->tables);
324
325 out:
326   REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
327 }
328
329 static void
330 send_ipfix_classify_table_details (u32 table_index,
331                                    vl_api_registration_t * reg, u32 context)
332 {
333   flow_report_classify_main_t *fcm = &flow_report_classify_main;
334   vl_api_ipfix_classify_table_details_t *mp;
335
336   ipfix_classify_table_t *table = &fcm->tables[table_index];
337
338   mp = vl_msg_api_alloc (sizeof (*mp));
339   clib_memset (mp, 0, sizeof (*mp));
340   mp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_TABLE_DETAILS);
341   mp->context = context;
342   mp->table_id = htonl (table->classify_table_index);
343   mp->ip_version = (table->ip_version == 4) ? ADDRESS_IP4 : ADDRESS_IP6;
344   mp->transport_protocol = table->transport_protocol;
345
346   vl_api_send_msg (reg, (u8 *) mp);
347 }
348
349 static void
350   vl_api_ipfix_classify_table_dump_t_handler
351   (vl_api_ipfix_classify_table_dump_t * mp)
352 {
353   flow_report_classify_main_t *fcm = &flow_report_classify_main;
354   vl_api_registration_t *reg;
355   u32 i;
356
357   reg = vl_api_client_index_to_registration (mp->client_index);
358   if (!reg)
359     return;
360
361   for (i = 0; i < vec_len (fcm->tables); i++)
362     if (ipfix_classify_table_index_valid (i))
363       send_ipfix_classify_table_details (i, reg, mp->context);
364 }
365
366 static void
367 vl_api_ipfix_flush_t_handler (vl_api_ipfix_flush_t * mp)
368 {
369   vl_api_ipfix_flush_reply_t *rmp;
370   vl_api_registration_t *reg;
371   vlib_main_t *vm = vlib_get_main ();
372   int rv = 0;
373
374   reg = vl_api_client_index_to_registration (mp->client_index);
375   if (!reg)
376     return;
377
378   /* poke the flow reporting process */
379   vlib_process_signal_event (vm, flow_report_process_node.index,
380                              1 /* type_opaque */ , 0 /* data */ );
381
382   REPLY_MACRO (VL_API_IPFIX_FLUSH_REPLY);
383 }
384
385 /*
386  * flow_api_hookup
387  * Add vpe's API message handlers to the table.
388  * vlib has already mapped shared memory and
389  * added the client registration handlers.
390  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
391  */
392 #define vl_msg_name_crc_list
393 #include <vnet/vnet_all_api_h.h>
394 #undef vl_msg_name_crc_list
395
396 static void
397 setup_message_id_table (api_main_t * am)
398 {
399 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
400   foreach_vl_msg_name_crc_ipfix_export;
401 #undef _
402 }
403
404 static clib_error_t *
405 flow_api_hookup (vlib_main_t * vm)
406 {
407   api_main_t *am = vlibapi_get_main ();
408
409 #define _(N,n)                                                  \
410     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
411                            vl_api_##n##_t_handler,              \
412                            vl_noop_handler,                     \
413                            vl_api_##n##_t_endian,               \
414                            vl_api_##n##_t_print,                \
415                            sizeof(vl_api_##n##_t), 1);
416   foreach_vpe_api_msg;
417 #undef _
418
419   /*
420    * Set up the (msg_name, crc, message-id) table
421    */
422   setup_message_id_table (am);
423
424   return 0;
425 }
426
427 VLIB_API_INIT_FUNCTION (flow_api_hookup);
428
429 /*
430  * fd.io coding-style-patch-verification: ON
431  *
432  * Local Variables:
433  * eval: (c-set-style "gnu")
434  * End:
435  */