blob: 84babe7dcdcc8e0be3a7c44db485a1d883739d25 [file] [log] [blame]
Pavel Kotucekeb9e6662017-01-24 13:40:26 +01001/*
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>
Jakub Grajciar2f71a882019-10-10 14:21:22 +020022#include <vnet/ip/ip_types_api.h>
Pavel Kotucekeb9e6662017-01-24 13:40:26 +010023
24#include <vnet/interface.h>
25#include <vnet/api_errno.h>
26
27#include <vnet/fib/fib_table.h>
Ole Troana9855ef2018-05-02 12:45:10 +020028#include <vnet/ipfix-export/flow_report.h>
29#include <vnet/ipfix-export/flow_report_classify.h>
Pavel Kotucekeb9e6662017-01-24 13:40:26 +010030
31#include <vnet/vnet_msg_enum.h>
32
33#define vl_typedefs /* define message structures */
34#include <vnet/vnet_all_api_h.h>
35#undef vl_typedefs
36
37#define vl_endianfun /* define message structures */
38#include <vnet/vnet_all_api_h.h>
39#undef vl_endianfun
40
41/* instantiate all the print functions we know about */
42#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
43#define vl_printfun
44#include <vnet/vnet_all_api_h.h>
45#undef vl_printfun
46
47#include <vlibapi/api_helper_macros.h>
48
49#define foreach_vpe_api_msg \
50_(SET_IPFIX_EXPORTER, set_ipfix_exporter) \
51_(IPFIX_EXPORTER_DUMP, ipfix_exporter_dump) \
52_(SET_IPFIX_CLASSIFY_STREAM, set_ipfix_classify_stream) \
53_(IPFIX_CLASSIFY_STREAM_DUMP, ipfix_classify_stream_dump) \
54_(IPFIX_CLASSIFY_TABLE_ADD_DEL, ipfix_classify_table_add_del) \
Paul Vinciguerra21b83e92019-06-24 09:55:46 -040055_(IPFIX_CLASSIFY_TABLE_DUMP, ipfix_classify_table_dump) \
56_(IPFIX_FLUSH, ipfix_flush)
Pavel Kotucekeb9e6662017-01-24 13:40:26 +010057
58static void
59vl_api_set_ipfix_exporter_t_handler (vl_api_set_ipfix_exporter_t * mp)
60{
61 vlib_main_t *vm = vlib_get_main ();
62 flow_report_main_t *frm = &flow_report_main;
Paul Vinciguerra21b83e92019-06-24 09:55:46 -040063 vl_api_registration_t *reg;
Pavel Kotucekeb9e6662017-01-24 13:40:26 +010064 vl_api_set_ipfix_exporter_reply_t *rmp;
65 ip4_address_t collector, src;
66 u16 collector_port = UDP_DST_PORT_ipfix;
67 u32 path_mtu;
68 u32 template_interval;
69 u8 udp_checksum;
70 u32 fib_id;
71 u32 fib_index = ~0;
72 int rv = 0;
73
Paul Vinciguerra21b83e92019-06-24 09:55:46 -040074 reg = vl_api_client_index_to_registration (mp->client_index);
75 if (!reg)
76 return;
77
Jakub Grajciar2f71a882019-10-10 14:21:22 +020078 if (mp->src_address.af == ADDRESS_IP6
79 || mp->collector_address.af == ADDRESS_IP6)
80 {
81 rv = VNET_API_ERROR_UNIMPLEMENTED;
82 goto out;
83 }
84
85 ip4_address_decode (mp->collector_address.un.ip4, &collector);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +010086 collector_port = ntohs (mp->collector_port);
87 if (collector_port == (u16) ~ 0)
88 collector_port = UDP_DST_PORT_ipfix;
Jakub Grajciar2f71a882019-10-10 14:21:22 +020089 ip4_address_decode (mp->src_address.un.ip4, &src);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +010090 fib_id = ntohl (mp->vrf_id);
91
92 ip4_main_t *im = &ip4_main;
93 if (fib_id == ~0)
94 {
95 fib_index = ~0;
96 }
97 else
98 {
99 uword *p = hash_get (im->fib_index_by_table_id, fib_id);
100 if (!p)
101 {
102 rv = VNET_API_ERROR_NO_SUCH_FIB;
103 goto out;
104 }
105 fib_index = p[0];
106 }
107
108 path_mtu = ntohl (mp->path_mtu);
109 if (path_mtu == ~0)
110 path_mtu = 512; // RFC 7011 section 10.3.3.
111 template_interval = ntohl (mp->template_interval);
112 if (template_interval == ~0)
113 template_interval = 20;
114 udp_checksum = mp->udp_checksum;
115
116 if (collector.as_u32 == 0)
117 {
118 rv = VNET_API_ERROR_INVALID_VALUE;
119 goto out;
120 }
121
122 if (src.as_u32 == 0)
123 {
124 rv = VNET_API_ERROR_INVALID_VALUE;
125 goto out;
126 }
127
128 if (path_mtu > 1450 /* vpp does not support fragmentation */ )
129 {
130 rv = VNET_API_ERROR_INVALID_VALUE;
131 goto out;
132 }
133
134 if (path_mtu < 68)
135 {
136 rv = VNET_API_ERROR_INVALID_VALUE;
137 goto out;
138 }
139
140 /* Reset report streams if we are reconfiguring IP addresses */
141 if (frm->ipfix_collector.as_u32 != collector.as_u32 ||
142 frm->src_address.as_u32 != src.as_u32 ||
143 frm->collector_port != collector_port)
144 vnet_flow_reports_reset (frm);
145
146 frm->ipfix_collector.as_u32 = collector.as_u32;
147 frm->collector_port = collector_port;
148 frm->src_address.as_u32 = src.as_u32;
149 frm->fib_index = fib_index;
150 frm->path_mtu = path_mtu;
151 frm->template_interval = template_interval;
152 frm->udp_checksum = udp_checksum;
153
154 /* Turn on the flow reporting process */
155 vlib_process_signal_event (vm, flow_report_process_node.index, 1, 0);
156
157out:
158 REPLY_MACRO (VL_API_SET_IPFIX_EXPORTER_REPLY);
159}
160
161static void
162vl_api_ipfix_exporter_dump_t_handler (vl_api_ipfix_exporter_dump_t * mp)
163{
164 flow_report_main_t *frm = &flow_report_main;
Florin Coras6c4dae22018-01-09 06:39:23 -0800165 vl_api_registration_t *reg;
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100166 vl_api_ipfix_exporter_details_t *rmp;
167 ip4_main_t *im = &ip4_main;
Jakub Grajciar2f71a882019-10-10 14:21:22 +0200168 ip46_address_t collector = {.as_u64[0] = 0,.as_u64[1] = 0 };
169 ip46_address_t src = {.as_u64[0] = 0,.as_u64[1] = 0 };
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100170 u32 vrf_id;
171
Florin Coras6c4dae22018-01-09 06:39:23 -0800172 reg = vl_api_client_index_to_registration (mp->client_index);
173 if (!reg)
Paul Vinciguerra21b83e92019-06-24 09:55:46 -0400174 return;
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100175
176 rmp = vl_msg_api_alloc (sizeof (*rmp));
Dave Barachb7b92992018-10-17 10:38:51 -0400177 clib_memset (rmp, 0, sizeof (*rmp));
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100178 rmp->_vl_msg_id = ntohs (VL_API_IPFIX_EXPORTER_DETAILS);
179 rmp->context = mp->context;
Jakub Grajciar2f71a882019-10-10 14:21:22 +0200180
181 memcpy (&collector.ip4, &frm->ipfix_collector, sizeof (ip4_address_t));
182 ip_address_encode (&collector, IP46_TYPE_IP4, &rmp->collector_address);
183
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100184 rmp->collector_port = htons (frm->collector_port);
Jakub Grajciar2f71a882019-10-10 14:21:22 +0200185
186 memcpy (&src.ip4, &frm->src_address, sizeof (ip4_address_t));
187 ip_address_encode (&src, IP46_TYPE_IP4, &rmp->src_address);
188
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100189 if (frm->fib_index == ~0)
190 vrf_id = ~0;
191 else
192 vrf_id = im->fibs[frm->fib_index].ft_table_id;
193 rmp->vrf_id = htonl (vrf_id);
194 rmp->path_mtu = htonl (frm->path_mtu);
195 rmp->template_interval = htonl (frm->template_interval);
196 rmp->udp_checksum = (frm->udp_checksum != 0);
197
Florin Coras6c4dae22018-01-09 06:39:23 -0800198 vl_api_send_msg (reg, (u8 *) rmp);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100199}
200
201static void
202 vl_api_set_ipfix_classify_stream_t_handler
203 (vl_api_set_ipfix_classify_stream_t * mp)
204{
205 vl_api_set_ipfix_classify_stream_reply_t *rmp;
206 flow_report_classify_main_t *fcm = &flow_report_classify_main;
207 flow_report_main_t *frm = &flow_report_main;
208 u32 domain_id = 0;
209 u32 src_port = UDP_DST_PORT_ipfix;
210 int rv = 0;
211
212 domain_id = ntohl (mp->domain_id);
213 src_port = ntohs (mp->src_port);
214
215 if (fcm->src_port != 0 &&
216 (fcm->domain_id != domain_id || fcm->src_port != (u16) src_port))
217 {
218 int rv = vnet_stream_change (frm, fcm->domain_id, fcm->src_port,
219 domain_id, (u16) src_port);
220 ASSERT (rv == 0);
221 }
222
223 fcm->domain_id = domain_id;
224 fcm->src_port = (u16) src_port;
225
226 REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
227}
228
229static void
230 vl_api_ipfix_classify_stream_dump_t_handler
231 (vl_api_ipfix_classify_stream_dump_t * mp)
232{
233 flow_report_classify_main_t *fcm = &flow_report_classify_main;
Florin Coras6c4dae22018-01-09 06:39:23 -0800234 vl_api_registration_t *reg;
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100235 vl_api_ipfix_classify_stream_details_t *rmp;
236
Florin Coras6c4dae22018-01-09 06:39:23 -0800237 reg = vl_api_client_index_to_registration (mp->client_index);
238 if (!reg)
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100239 return;
240
241 rmp = vl_msg_api_alloc (sizeof (*rmp));
Dave Barachb7b92992018-10-17 10:38:51 -0400242 clib_memset (rmp, 0, sizeof (*rmp));
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100243 rmp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_STREAM_DETAILS);
244 rmp->context = mp->context;
245 rmp->domain_id = htonl (fcm->domain_id);
246 rmp->src_port = htons (fcm->src_port);
247
Florin Coras6c4dae22018-01-09 06:39:23 -0800248 vl_api_send_msg (reg, (u8 *) rmp);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100249}
250
251static void
252 vl_api_ipfix_classify_table_add_del_t_handler
253 (vl_api_ipfix_classify_table_add_del_t * mp)
254{
255 vl_api_ipfix_classify_table_add_del_reply_t *rmp;
Paul Vinciguerra21b83e92019-06-24 09:55:46 -0400256 vl_api_registration_t *reg;
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100257 flow_report_classify_main_t *fcm = &flow_report_classify_main;
258 flow_report_main_t *frm = &flow_report_main;
259 vnet_flow_report_add_del_args_t args;
260 ipfix_classify_table_t *table;
261 int is_add;
262 u32 classify_table_index;
263 u8 ip_version;
264 u8 transport_protocol;
265 int rv = 0;
266
Paul Vinciguerra21b83e92019-06-24 09:55:46 -0400267 reg = vl_api_client_index_to_registration (mp->client_index);
268 if (!reg)
269 return;
270
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100271 classify_table_index = ntohl (mp->table_id);
Jakub Grajciar2f71a882019-10-10 14:21:22 +0200272 ip_version = ntohl (mp->ip_version);
273 transport_protocol = ntohl (mp->transport_protocol);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100274 is_add = mp->is_add;
275
276 if (fcm->src_port == 0)
277 {
278 /* call set_ipfix_classify_stream first */
279 rv = VNET_API_ERROR_UNSPECIFIED;
280 goto out;
281 }
282
Dave Barachb7b92992018-10-17 10:38:51 -0400283 clib_memset (&args, 0, sizeof (args));
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100284
285 table = 0;
286 int i;
287 for (i = 0; i < vec_len (fcm->tables); i++)
288 if (ipfix_classify_table_index_valid (i))
289 if (fcm->tables[i].classify_table_index == classify_table_index)
290 {
291 table = &fcm->tables[i];
292 break;
293 }
294
295 if (is_add)
296 {
297 if (table)
298 {
299 rv = VNET_API_ERROR_VALUE_EXIST;
300 goto out;
301 }
302 table = ipfix_classify_add_table ();
303 table->classify_table_index = classify_table_index;
304 }
305 else
306 {
307 if (!table)
308 {
309 rv = VNET_API_ERROR_NO_SUCH_ENTRY;
310 goto out;
311 }
312 }
313
314 table->ip_version = ip_version;
315 table->transport_protocol = transport_protocol;
316
317 args.opaque.as_uword = table - fcm->tables;
318 args.rewrite_callback = ipfix_classify_template_rewrite;
319 args.flow_data_callback = ipfix_classify_send_flows;
320 args.is_add = is_add;
321 args.domain_id = fcm->domain_id;
322 args.src_port = fcm->src_port;
323
Ole Troan5c749732017-03-13 13:39:52 +0100324 rv = vnet_flow_report_add_del (frm, &args, NULL);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100325
326 /* If deleting, or add failed */
327 if (is_add == 0 || (rv && is_add))
328 ipfix_classify_delete_table (table - fcm->tables);
329
330out:
331 REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
332}
333
334static void
335send_ipfix_classify_table_details (u32 table_index,
Florin Coras6c4dae22018-01-09 06:39:23 -0800336 vl_api_registration_t * reg, u32 context)
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100337{
338 flow_report_classify_main_t *fcm = &flow_report_classify_main;
339 vl_api_ipfix_classify_table_details_t *mp;
340
341 ipfix_classify_table_t *table = &fcm->tables[table_index];
342
343 mp = vl_msg_api_alloc (sizeof (*mp));
Dave Barachb7b92992018-10-17 10:38:51 -0400344 clib_memset (mp, 0, sizeof (*mp));
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100345 mp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_TABLE_DETAILS);
346 mp->context = context;
347 mp->table_id = htonl (table->classify_table_index);
Jakub Grajciar2f71a882019-10-10 14:21:22 +0200348 mp->ip_version = htonl (table->ip_version);
349 mp->transport_protocol = htonl (table->transport_protocol);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100350
Florin Coras6c4dae22018-01-09 06:39:23 -0800351 vl_api_send_msg (reg, (u8 *) mp);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100352}
353
354static void
355 vl_api_ipfix_classify_table_dump_t_handler
356 (vl_api_ipfix_classify_table_dump_t * mp)
357{
358 flow_report_classify_main_t *fcm = &flow_report_classify_main;
Florin Coras6c4dae22018-01-09 06:39:23 -0800359 vl_api_registration_t *reg;
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100360 u32 i;
361
Florin Coras6c4dae22018-01-09 06:39:23 -0800362 reg = vl_api_client_index_to_registration (mp->client_index);
363 if (!reg)
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100364 return;
365
366 for (i = 0; i < vec_len (fcm->tables); i++)
367 if (ipfix_classify_table_index_valid (i))
Florin Coras6c4dae22018-01-09 06:39:23 -0800368 send_ipfix_classify_table_details (i, reg, mp->context);
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100369}
370
Paul Vinciguerra21b83e92019-06-24 09:55:46 -0400371static void
372vl_api_ipfix_flush_t_handler (vl_api_ipfix_flush_t * mp)
373{
374 vl_api_ipfix_flush_reply_t *rmp;
375 vl_api_registration_t *reg;
376 vlib_main_t *vm = vlib_get_main ();
377 int rv = 0;
378
379 reg = vl_api_client_index_to_registration (mp->client_index);
380 if (!reg)
381 return;
382
383 /* poke the flow reporting process */
384 vlib_process_signal_event (vm, flow_report_process_node.index,
385 1 /* type_opaque */ , 0 /* data */ );
386
387 REPLY_MACRO (VL_API_IPFIX_FLUSH_REPLY);
388}
389
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100390/*
391 * flow_api_hookup
392 * Add vpe's API message handlers to the table.
Jim Thompsonf324dec2019-04-08 03:22:21 -0500393 * vlib has already mapped shared memory and
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100394 * added the client registration handlers.
395 * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
396 */
397#define vl_msg_name_crc_list
398#include <vnet/vnet_all_api_h.h>
399#undef vl_msg_name_crc_list
400
401static void
402setup_message_id_table (api_main_t * am)
403{
404#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
Ole Troana9855ef2018-05-02 12:45:10 +0200405 foreach_vl_msg_name_crc_ipfix_export;
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100406#undef _
407}
408
409static clib_error_t *
410flow_api_hookup (vlib_main_t * vm)
411{
Dave Barach39d69112019-11-27 11:42:13 -0500412 api_main_t *am = vlibapi_get_main ();
Pavel Kotucekeb9e6662017-01-24 13:40:26 +0100413
414#define _(N,n) \
415 vl_msg_api_set_handlers(VL_API_##N, #n, \
416 vl_api_##n##_t_handler, \
417 vl_noop_handler, \
418 vl_api_##n##_t_endian, \
419 vl_api_##n##_t_print, \
420 sizeof(vl_api_##n##_t), 1);
421 foreach_vpe_api_msg;
422#undef _
423
424 /*
425 * Set up the (msg_name, crc, message-id) table
426 */
427 setup_message_id_table (am);
428
429 return 0;
430}
431
432VLIB_API_INIT_FUNCTION (flow_api_hookup);
433
434/*
435 * fd.io coding-style-patch-verification: ON
436 *
437 * Local Variables:
438 * eval: (c-set-style "gnu")
439 * End:
440 */