Line data Source code
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 : ipfix_exporter_t *
40 5 : vnet_ipfix_exporter_lookup (const ip_address_t *ipfix_collector)
41 : {
42 5 : flow_report_main_t *frm = &flow_report_main;
43 : ipfix_exporter_t *exp;
44 :
45 11 : pool_foreach (exp, frm->exporters)
46 : {
47 9 : if (ip_address_cmp (&exp->ipfix_collector, ipfix_collector) == 0)
48 3 : return exp;
49 : }
50 :
51 2 : return NULL;
52 : }
53 :
54 : /*
55 : * For backwards compatibility reasons index 0 in the set of exporters
56 : * is alwyas used for the exporter created via the set_ipfix_exporter
57 : * API.
58 : */
59 : #define USE_INDEX_0 true
60 : #define USE_ANY_INDEX false
61 :
62 : static int
63 48 : vl_api_set_ipfix_exporter_t_internal (
64 : u32 client_index, vl_api_address_t *mp_collector_address,
65 : u16 mp_collector_port, vl_api_address_t *mp_src_address, u32 mp_vrf_id,
66 : u32 mp_path_mtu, u32 mp_template_interval, bool mp_udp_checksum,
67 : bool use_index_0, bool is_create)
68 : {
69 48 : vlib_main_t *vm = vlib_get_main ();
70 48 : flow_report_main_t *frm = &flow_report_main;
71 : ipfix_exporter_t *exp;
72 : vl_api_registration_t *reg;
73 : ip_address_t collector, src;
74 48 : u16 collector_port = UDP_DST_PORT_ipfix;
75 : u32 path_mtu;
76 : u32 template_interval;
77 : u8 udp_checksum;
78 : u32 fib_id;
79 48 : u32 fib_index = ~0;
80 : u32 ip_header_size;
81 :
82 48 : reg = vl_api_client_index_to_registration (client_index);
83 48 : if (!reg)
84 0 : return VNET_API_ERROR_UNIMPLEMENTED;
85 :
86 48 : if (use_index_0)
87 : {
88 : /*
89 : * In this case we update the existing exporter. There is no delete
90 : * for exp[0]
91 : */
92 43 : exp = &frm->exporters[0];
93 :
94 : /* Collector address must be IPv4 for exp[0] */
95 43 : collector.version = AF_IP4;
96 43 : ip4_address_decode (mp_collector_address->un.ip4, &collector.ip.ip4);
97 : }
98 : else
99 : {
100 5 : ip_address_decode2 (mp_collector_address, &collector);
101 5 : if (is_create)
102 : {
103 3 : exp = vnet_ipfix_exporter_lookup (&collector);
104 3 : if (!exp)
105 : {
106 : /* Create a new exporter instead of updating an existing one */
107 2 : if (pool_elts (frm->exporters) >= IPFIX_EXPORTERS_MAX)
108 0 : return VNET_API_ERROR_INVALID_VALUE;
109 2 : pool_get (frm->exporters, exp);
110 : }
111 : }
112 : else
113 : {
114 : /* Delete the exporter */
115 2 : exp = vnet_ipfix_exporter_lookup (&collector);
116 2 : if (!exp)
117 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
118 :
119 2 : pool_put (frm->exporters, exp);
120 2 : return 0;
121 : }
122 : }
123 :
124 46 : collector_port = ntohs (mp_collector_port);
125 46 : if (collector_port == (u16) ~ 0)
126 0 : collector_port = UDP_DST_PORT_ipfix;
127 46 : ip_address_decode2 (mp_src_address, &src);
128 46 : fib_id = ntohl (mp_vrf_id);
129 :
130 46 : ip4_main_t *im = &ip4_main;
131 46 : if (fib_id == ~0)
132 : {
133 0 : fib_index = ~0;
134 : }
135 : else
136 : {
137 46 : uword *p = hash_get (im->fib_index_by_table_id, fib_id);
138 46 : if (!p)
139 0 : return VNET_API_ERROR_NO_SUCH_FIB;
140 46 : fib_index = p[0];
141 : }
142 :
143 46 : path_mtu = ntohl (mp_path_mtu);
144 46 : if (path_mtu == ~0)
145 0 : path_mtu = 512; // RFC 7011 section 10.3.3.
146 46 : template_interval = ntohl (mp_template_interval);
147 46 : if (template_interval == ~0)
148 0 : template_interval = 20;
149 46 : udp_checksum = mp_udp_checksum;
150 :
151 : /*
152 : * If the collector address is set then the src must be too.
153 : * Collector address can be set to 0 to disable exporter
154 : */
155 46 : if (!ip_address_is_zero (&collector) && ip_address_is_zero (&src))
156 0 : return VNET_API_ERROR_INVALID_VALUE;
157 46 : if (collector.version != src.version)
158 0 : return VNET_API_ERROR_INVALID_VALUE;
159 :
160 46 : if (path_mtu > 1450 /* vpp does not support fragmentation */ )
161 0 : return VNET_API_ERROR_INVALID_VALUE;
162 :
163 46 : if (path_mtu < 68)
164 0 : return VNET_API_ERROR_INVALID_VALUE;
165 :
166 : /* Calculate how much header data we need. */
167 46 : if (collector.version == AF_IP4)
168 46 : ip_header_size = sizeof (ip4_header_t);
169 : else
170 0 : ip_header_size = sizeof (ip6_header_t);
171 46 : exp->all_headers_size = ip_header_size + sizeof (udp_header_t) +
172 46 : sizeof (ipfix_message_header_t) +
173 : sizeof (ipfix_set_header_t);
174 :
175 : /* Reset report streams if we are reconfiguring IP addresses */
176 52 : if (ip_address_cmp (&exp->ipfix_collector, &collector) ||
177 6 : ip_address_cmp (&exp->src_address, &src) ||
178 6 : exp->collector_port != collector_port)
179 41 : vnet_flow_reports_reset (exp);
180 :
181 46 : exp->ipfix_collector = collector;
182 46 : exp->collector_port = collector_port;
183 46 : exp->src_address = src;
184 46 : exp->fib_index = fib_index;
185 46 : exp->path_mtu = path_mtu;
186 46 : exp->template_interval = template_interval;
187 46 : exp->udp_checksum = udp_checksum;
188 :
189 : /* Turn on the flow reporting process */
190 46 : vlib_process_signal_event (vm, flow_report_process_node.index, 1, 0);
191 :
192 46 : return 0;
193 : }
194 :
195 : static void
196 43 : vl_api_set_ipfix_exporter_t_handler (vl_api_set_ipfix_exporter_t *mp)
197 : {
198 : vl_api_set_ipfix_exporter_reply_t *rmp;
199 43 : flow_report_main_t *frm = &flow_report_main;
200 43 : int rv = vl_api_set_ipfix_exporter_t_internal (
201 43 : mp->client_index, &mp->collector_address, mp->collector_port,
202 : &mp->src_address, mp->vrf_id, mp->path_mtu, mp->template_interval,
203 43 : mp->udp_checksum, USE_INDEX_0, 0);
204 :
205 43 : REPLY_MACRO (VL_API_SET_IPFIX_EXPORTER_REPLY);
206 : }
207 :
208 : static void
209 5 : vl_api_ipfix_exporter_create_delete_t_handler (
210 : vl_api_ipfix_exporter_create_delete_t *mp)
211 : {
212 : vl_api_ipfix_exporter_create_delete_reply_t *rmp;
213 5 : flow_report_main_t *frm = &flow_report_main;
214 5 : int rv = vl_api_set_ipfix_exporter_t_internal (
215 5 : mp->client_index, &mp->collector_address, mp->collector_port,
216 : &mp->src_address, mp->vrf_id, mp->path_mtu, mp->template_interval,
217 5 : mp->udp_checksum, USE_ANY_INDEX, mp->is_create);
218 :
219 5 : REPLY_MACRO (VL_API_IPFIX_EXPORTER_CREATE_DELETE_REPLY);
220 : }
221 :
222 : static void
223 1 : vl_api_ipfix_exporter_dump_t_handler (vl_api_ipfix_exporter_dump_t * mp)
224 : {
225 1 : flow_report_main_t *frm = &flow_report_main;
226 1 : ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
227 : vl_api_registration_t *reg;
228 : vl_api_ipfix_exporter_details_t *rmp;
229 1 : ip4_main_t *im = &ip4_main;
230 : u32 vrf_id;
231 :
232 1 : reg = vl_api_client_index_to_registration (mp->client_index);
233 1 : if (!reg)
234 0 : return;
235 :
236 1 : rmp = vl_msg_api_alloc (sizeof (*rmp));
237 1 : clib_memset (rmp, 0, sizeof (*rmp));
238 1 : rmp->_vl_msg_id =
239 1 : ntohs ((REPLY_MSG_ID_BASE) + VL_API_IPFIX_EXPORTER_DETAILS);
240 1 : rmp->context = mp->context;
241 :
242 1 : ip_address_encode2 (&exp->ipfix_collector, &rmp->collector_address);
243 1 : rmp->collector_port = htons (exp->collector_port);
244 1 : ip_address_encode2 (&exp->src_address, &rmp->src_address);
245 :
246 1 : if (exp->fib_index == ~0)
247 0 : vrf_id = ~0;
248 : else
249 1 : vrf_id = im->fibs[exp->fib_index].ft_table_id;
250 1 : rmp->vrf_id = htonl (vrf_id);
251 1 : rmp->path_mtu = htonl (exp->path_mtu);
252 1 : rmp->template_interval = htonl (exp->template_interval);
253 1 : rmp->udp_checksum = (exp->udp_checksum != 0);
254 :
255 1 : vl_api_send_msg (reg, (u8 *) rmp);
256 : }
257 :
258 : static void
259 12 : ipfix_all_fill_details (vl_api_ipfix_all_exporter_details_t *rmp,
260 : ipfix_exporter_t *exp)
261 : {
262 12 : ip4_main_t *im = &ip4_main;
263 : u32 vrf_id;
264 :
265 12 : ip_address_encode2 (&exp->ipfix_collector, &rmp->collector_address);
266 12 : rmp->collector_port = htons (exp->collector_port);
267 12 : ip_address_encode2 (&exp->src_address, &rmp->src_address);
268 :
269 12 : if (exp->fib_index == ~0)
270 0 : vrf_id = ~0;
271 : else
272 12 : vrf_id = im->fibs[exp->fib_index].ft_table_id;
273 12 : rmp->vrf_id = htonl (vrf_id);
274 12 : rmp->path_mtu = htonl (exp->path_mtu);
275 12 : rmp->template_interval = htonl (exp->template_interval);
276 12 : rmp->udp_checksum = (exp->udp_checksum != 0);
277 12 : }
278 :
279 : static void
280 12 : ipfix_all_exporter_details (flow_report_main_t *frm, u32 index,
281 : vl_api_registration_t *rp, u32 context)
282 : {
283 12 : ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, index);
284 :
285 : vl_api_ipfix_all_exporter_details_t *rmp;
286 :
287 12 : REPLY_MACRO_DETAILS4 (VL_API_IPFIX_ALL_EXPORTER_DETAILS, rp, context,
288 : ({ ipfix_all_fill_details (rmp, exp); }));
289 12 : }
290 :
291 : static void
292 6 : vl_api_ipfix_all_exporter_get_t_handler (vl_api_ipfix_all_exporter_get_t *mp)
293 : {
294 6 : flow_report_main_t *frm = &flow_report_main;
295 : vl_api_ipfix_all_exporter_get_reply_t *rmp;
296 6 : int rv = 0;
297 :
298 18 : REPLY_AND_DETAILS_MACRO (
299 : VL_API_IPFIX_ALL_EXPORTER_GET_REPLY, frm->exporters,
300 : ({ ipfix_all_exporter_details (frm, cursor, rp, mp->context); }));
301 : }
302 :
303 : static void
304 0 : vl_api_set_ipfix_classify_stream_t_handler
305 : (vl_api_set_ipfix_classify_stream_t * mp)
306 : {
307 : vl_api_set_ipfix_classify_stream_reply_t *rmp;
308 0 : flow_report_classify_main_t *fcm = &flow_report_classify_main;
309 0 : flow_report_main_t *frm = &flow_report_main;
310 0 : ipfix_exporter_t *exp = &frm->exporters[0];
311 0 : u32 domain_id = 0;
312 0 : u32 src_port = UDP_DST_PORT_ipfix;
313 0 : int rv = 0;
314 :
315 0 : domain_id = ntohl (mp->domain_id);
316 0 : src_port = ntohs (mp->src_port);
317 :
318 0 : if (fcm->src_port != 0 &&
319 0 : (fcm->domain_id != domain_id || fcm->src_port != (u16) src_port))
320 : {
321 0 : int rv = vnet_stream_change (exp, fcm->domain_id, fcm->src_port,
322 0 : domain_id, (u16) src_port);
323 0 : ASSERT (rv == 0);
324 : }
325 :
326 0 : fcm->domain_id = domain_id;
327 0 : fcm->src_port = (u16) src_port;
328 :
329 0 : REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
330 : }
331 :
332 : static void
333 0 : vl_api_ipfix_classify_stream_dump_t_handler
334 : (vl_api_ipfix_classify_stream_dump_t * mp)
335 : {
336 0 : flow_report_classify_main_t *fcm = &flow_report_classify_main;
337 : vl_api_registration_t *reg;
338 : vl_api_ipfix_classify_stream_details_t *rmp;
339 :
340 0 : reg = vl_api_client_index_to_registration (mp->client_index);
341 0 : if (!reg)
342 0 : return;
343 :
344 0 : rmp = vl_msg_api_alloc (sizeof (*rmp));
345 0 : clib_memset (rmp, 0, sizeof (*rmp));
346 0 : rmp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_STREAM_DETAILS);
347 0 : rmp->context = mp->context;
348 0 : rmp->domain_id = htonl (fcm->domain_id);
349 0 : rmp->src_port = htons (fcm->src_port);
350 :
351 0 : vl_api_send_msg (reg, (u8 *) rmp);
352 : }
353 :
354 : static void
355 0 : vl_api_ipfix_classify_table_add_del_t_handler
356 : (vl_api_ipfix_classify_table_add_del_t * mp)
357 : {
358 : vl_api_ipfix_classify_table_add_del_reply_t *rmp;
359 : vl_api_registration_t *reg;
360 0 : flow_report_classify_main_t *fcm = &flow_report_classify_main;
361 0 : flow_report_main_t *frm = &flow_report_main;
362 0 : ipfix_exporter_t *exp = &frm->exporters[0];
363 : vnet_flow_report_add_del_args_t args;
364 : ipfix_classify_table_t *table;
365 : int is_add;
366 : u32 classify_table_index;
367 : u8 ip_version;
368 : u8 transport_protocol;
369 0 : int rv = 0;
370 :
371 0 : reg = vl_api_client_index_to_registration (mp->client_index);
372 0 : if (!reg)
373 0 : return;
374 :
375 0 : classify_table_index = ntohl (mp->table_id);
376 0 : ip_version = (mp->ip_version == ADDRESS_IP4) ? 4 : 6;
377 0 : transport_protocol = mp->transport_protocol;
378 0 : is_add = mp->is_add;
379 :
380 0 : if (fcm->src_port == 0)
381 : {
382 : /* call set_ipfix_classify_stream first */
383 0 : rv = VNET_API_ERROR_UNSPECIFIED;
384 0 : goto out;
385 : }
386 :
387 0 : clib_memset (&args, 0, sizeof (args));
388 :
389 0 : table = 0;
390 : int i;
391 0 : for (i = 0; i < vec_len (fcm->tables); i++)
392 0 : if (ipfix_classify_table_index_valid (i))
393 0 : if (fcm->tables[i].classify_table_index == classify_table_index)
394 : {
395 0 : table = &fcm->tables[i];
396 0 : break;
397 : }
398 :
399 0 : if (is_add)
400 : {
401 0 : if (table)
402 : {
403 0 : rv = VNET_API_ERROR_VALUE_EXIST;
404 0 : goto out;
405 : }
406 0 : table = ipfix_classify_add_table ();
407 0 : table->classify_table_index = classify_table_index;
408 : }
409 : else
410 : {
411 0 : if (!table)
412 : {
413 0 : rv = VNET_API_ERROR_NO_SUCH_ENTRY;
414 0 : goto out;
415 : }
416 : }
417 :
418 0 : table->ip_version = ip_version;
419 0 : table->transport_protocol = transport_protocol;
420 :
421 0 : args.opaque.as_uword = table - fcm->tables;
422 0 : args.rewrite_callback = ipfix_classify_template_rewrite;
423 0 : args.flow_data_callback = ipfix_classify_send_flows;
424 0 : args.is_add = is_add;
425 0 : args.domain_id = fcm->domain_id;
426 0 : args.src_port = fcm->src_port;
427 :
428 0 : rv = vnet_flow_report_add_del (exp, &args, NULL);
429 :
430 : /* If deleting, or add failed */
431 0 : if (is_add == 0 || (rv && is_add))
432 0 : ipfix_classify_delete_table (table - fcm->tables);
433 :
434 0 : out:
435 0 : REPLY_MACRO (VL_API_SET_IPFIX_CLASSIFY_STREAM_REPLY);
436 : }
437 :
438 : static void
439 0 : send_ipfix_classify_table_details (u32 table_index,
440 : vl_api_registration_t * reg, u32 context)
441 : {
442 0 : flow_report_classify_main_t *fcm = &flow_report_classify_main;
443 : vl_api_ipfix_classify_table_details_t *mp;
444 :
445 0 : ipfix_classify_table_t *table = &fcm->tables[table_index];
446 :
447 0 : mp = vl_msg_api_alloc (sizeof (*mp));
448 0 : clib_memset (mp, 0, sizeof (*mp));
449 0 : mp->_vl_msg_id = ntohs (VL_API_IPFIX_CLASSIFY_TABLE_DETAILS);
450 0 : mp->context = context;
451 0 : mp->table_id = htonl (table->classify_table_index);
452 0 : mp->ip_version = (table->ip_version == 4) ? ADDRESS_IP4 : ADDRESS_IP6;
453 0 : mp->transport_protocol = table->transport_protocol;
454 :
455 0 : vl_api_send_msg (reg, (u8 *) mp);
456 0 : }
457 :
458 : static void
459 0 : vl_api_ipfix_classify_table_dump_t_handler
460 : (vl_api_ipfix_classify_table_dump_t * mp)
461 : {
462 0 : flow_report_classify_main_t *fcm = &flow_report_classify_main;
463 : vl_api_registration_t *reg;
464 : u32 i;
465 :
466 0 : reg = vl_api_client_index_to_registration (mp->client_index);
467 0 : if (!reg)
468 0 : return;
469 :
470 0 : for (i = 0; i < vec_len (fcm->tables); i++)
471 0 : if (ipfix_classify_table_index_valid (i))
472 0 : send_ipfix_classify_table_details (i, reg, mp->context);
473 : }
474 :
475 : static void
476 33 : vl_api_ipfix_flush_t_handler (vl_api_ipfix_flush_t * mp)
477 : {
478 33 : flow_report_main_t *frm = &flow_report_main;
479 : vl_api_ipfix_flush_reply_t *rmp;
480 : vl_api_registration_t *reg;
481 33 : vlib_main_t *vm = vlib_get_main ();
482 33 : int rv = 0;
483 :
484 33 : reg = vl_api_client_index_to_registration (mp->client_index);
485 33 : if (!reg)
486 0 : return;
487 :
488 : /* poke the flow reporting process */
489 33 : vlib_process_signal_event (vm, flow_report_process_node.index,
490 : 1 /* type_opaque */ , 0 /* data */ );
491 :
492 33 : REPLY_MACRO (VL_API_IPFIX_FLUSH_REPLY);
493 : }
494 :
495 : #include <vnet/ipfix-export/ipfix_export.api.c>
496 : static clib_error_t *
497 559 : flow_api_hookup (vlib_main_t * vm)
498 : {
499 559 : flow_report_main_t *frm = &flow_report_main;
500 : /*
501 : * Set up the (msg_name, crc, message-id) table
502 : */
503 559 : REPLY_MSG_ID_BASE = setup_message_id_table ();
504 :
505 559 : return 0;
506 : }
507 :
508 12879 : VLIB_API_INIT_FUNCTION (flow_api_hookup);
509 :
510 : /*
511 : * fd.io coding-style-patch-verification: ON
512 : *
513 : * Local Variables:
514 : * eval: (c-set-style "gnu")
515 : * End:
516 : */
|