2 * snat_ipfix_logging.c - NAT Events IPFIX logging
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/flow/flow_report.h>
19 #include <vlibmemory/api.h>
20 #include <snat/snat.h>
21 #include <snat/snat_ipfix_logging.h>
23 snat_ipfix_logging_main_t snat_ipfix_logging_main;
25 #define NAT44_SESSION_CREATE_LEN 26
26 #define NAT_ADDRESSES_EXHAUTED_LEN 13
28 #define NAT44_SESSION_CREATE_FIELD_COUNT 8
29 #define NAT_ADDRESSES_EXHAUTED_FIELD_COUNT 3
35 snat_protocol_t snat_proto;
39 } snat_ipfix_logging_nat44_ses_args_t;
43 } snat_ipfix_logging_addr_exhausted_args_t;
46 * @brief Create an IPFIX template packet rewrite string
48 * @param frm flow report main
49 * @param fr flow report
50 * @param collector_address collector address
51 * @param src_address source address
52 * @param collector_port collector
53 * @param event NAT event ID
55 * @returns template packet
58 snat_template_rewrite (flow_report_main_t * frm,
60 ip4_address_t * collector_address,
61 ip4_address_t * src_address,
65 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
68 ipfix_message_header_t *h;
69 ipfix_set_header_t *s;
70 ipfix_template_header_t *t;
71 ipfix_field_specifier_t *f;
72 ipfix_field_specifier_t *first_field;
74 ip4_ipfix_template_packet_t *tp;
76 flow_report_stream_t *stream;
78 stream = &frm->streams[fr->stream_index];
79 silm->stream_index = fr->stream_index;
81 if (event == NAT_ADDRESSES_EXHAUTED)
83 field_count = NAT_ADDRESSES_EXHAUTED_FIELD_COUNT;
84 silm->addr_exhausted_template_id = fr->template_id;
86 else if (event == NAT44_SESSION_CREATE)
88 field_count = NAT44_SESSION_CREATE_FIELD_COUNT;
89 silm->nat44_session_template_id = fr->template_id;
92 /* allocate rewrite space */
93 vec_validate_aligned (rewrite,
94 sizeof (ip4_ipfix_template_packet_t)
95 + field_count * sizeof (ipfix_field_specifier_t) - 1,
96 CLIB_CACHE_LINE_BYTES);
98 tp = (ip4_ipfix_template_packet_t *) rewrite;
99 ip = (ip4_header_t *) & tp->ip4;
100 udp = (udp_header_t *) (ip + 1);
101 h = (ipfix_message_header_t *) (udp + 1);
102 s = (ipfix_set_header_t *) (h + 1);
103 t = (ipfix_template_header_t *) (s + 1);
104 first_field = f = (ipfix_field_specifier_t *) (t + 1);
106 ip->ip_version_and_header_length = 0x45;
108 ip->protocol = IP_PROTOCOL_UDP;
109 ip->src_address.as_u32 = src_address->as_u32;
110 ip->dst_address.as_u32 = collector_address->as_u32;
111 udp->src_port = clib_host_to_net_u16 (stream->src_port);
112 udp->dst_port = clib_host_to_net_u16 (collector_port);
113 udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
115 /* FIXUP: message header export_time */
116 h->domain_id = clib_host_to_net_u32 (stream->domain_id);
118 /* Add TLVs to the template */
119 if (event == NAT_ADDRESSES_EXHAUTED)
121 f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
123 f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
125 f->e_id_length = ipfix_e_id_length (0, natPoolId, 4);
128 else if (event == NAT44_SESSION_CREATE)
130 f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
132 f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
134 f->e_id_length = ipfix_e_id_length (0, sourceIPv4Address, 4);
136 f->e_id_length = ipfix_e_id_length (0, postNATSourceIPv4Address, 4);
138 f->e_id_length = ipfix_e_id_length (0, protocolIdentifier, 1);
140 f->e_id_length = ipfix_e_id_length (0, sourceTransportPort, 2);
142 f->e_id_length = ipfix_e_id_length (0, postNAPTSourceTransportPort, 2);
144 f->e_id_length = ipfix_e_id_length (0, ingressVRFID, 4);
148 /* Back to the template packet... */
149 ip = (ip4_header_t *) & tp->ip4;
150 udp = (udp_header_t *) (ip + 1);
152 ASSERT (f - first_field);
153 /* Field count in this template */
154 t->id_count = ipfix_id_count (fr->template_id, f - first_field);
156 /* set length in octets */
158 ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
160 /* message length in octets */
161 h->version_length = version_length ((u8 *) f - (u8 *) h);
163 ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
164 ip->checksum = ip4_header_checksum (ip);
170 snat_template_rewrite_addr_exhausted (flow_report_main_t * frm,
172 ip4_address_t * collector_address,
173 ip4_address_t * src_address,
176 return snat_template_rewrite (frm, fr, collector_address, src_address,
177 collector_port, NAT_ADDRESSES_EXHAUTED);
181 snat_template_rewrite_nat44_session (flow_report_main_t * frm,
183 ip4_address_t * collector_address,
184 ip4_address_t * src_address,
187 return snat_template_rewrite (frm, fr, collector_address, src_address,
188 collector_port, NAT44_SESSION_CREATE);
192 snat_ipfix_header_create (flow_report_main_t * frm,
196 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
197 flow_report_stream_t *stream;
198 ip4_ipfix_template_packet_t * tp;
199 ipfix_message_header_t * h = 0;
200 ipfix_set_header_t * s = 0;
204 stream = &frm->streams[silm->stream_index];
206 b0->current_data = 0;
207 b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) +
209 b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT);
210 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
211 vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index;
212 tp = vlib_buffer_get_current (b0);
213 ip = (ip4_header_t *) &tp->ip4;
214 udp = (udp_header_t *) (ip+1);
215 h = (ipfix_message_header_t *)(udp+1);
216 s = (ipfix_set_header_t *)(h+1);
218 ip->ip_version_and_header_length = 0x45;
220 ip->protocol = IP_PROTOCOL_UDP;
221 ip->flags_and_fragment_offset = 0;
222 ip->src_address.as_u32 = frm->src_address.as_u32;
223 ip->dst_address.as_u32 = frm->ipfix_collector.as_u32;
224 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
225 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
228 h->export_time = clib_host_to_net_u32 (
229 (u32) (((f64)frm->unix_time_0) + (vlib_time_now(frm->vlib_main) -
231 h->sequence_number = clib_host_to_net_u32 (stream->sequence_number++);
232 h->domain_id = clib_host_to_net_u32 (stream->domain_id);
234 *offset = (u32) (((u8 *)(s+1)) - (u8 *)tp);
238 snat_ipfix_send (flow_report_main_t * frm,
243 ip4_ipfix_template_packet_t * tp;
244 ipfix_message_header_t * h = 0;
245 ipfix_set_header_t * s = 0;
248 vlib_main_t * vm = frm->vlib_main;
250 tp = vlib_buffer_get_current (b0);
251 ip = (ip4_header_t *) & tp->ip4;
252 udp = (udp_header_t *) (ip + 1);
253 h = (ipfix_message_header_t *) (udp + 1);
254 s = (ipfix_set_header_t *) (h + 1);
256 s->set_id_length = ipfix_set_id_length (template_id,
258 (sizeof (*ip) + sizeof (*udp) +
260 h->version_length = version_length (b0->current_length -
261 (sizeof (*ip) + sizeof (*udp)));
263 ip->length = clib_host_to_net_u16 (b0->current_length);
264 ip->checksum = ip4_header_checksum (ip);
265 udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
267 if (frm->udp_checksum)
269 udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
270 if (udp->checksum == 0)
271 udp->checksum = 0xffff;
274 ASSERT (ip->checksum == ip4_header_checksum (ip));
276 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
280 snat_ipfix_logging_nat44_ses (u8 nat_event, u32 src_ip, u32 nat_src_ip,
281 snat_protocol_t snat_proto, u16 src_port,
282 u16 nat_src_port, u32 vrf_id, int do_flush)
284 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
285 flow_report_main_t *frm = &flow_report_main;
287 vlib_buffer_t *b0 = 0;
290 vlib_main_t * vm = frm->vlib_main;
292 vlib_buffer_free_list_t *fl;
298 proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : proto;
299 proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : proto;
300 proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : proto;
302 now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
303 now += silm->milisecond_time_0;
305 b0 = silm->nat44_session_buffer;
307 if (PREDICT_FALSE (b0 == 0))
312 if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
314 clib_warning ("can't allocate buffer for NAT IPFIX event");
318 b0 = silm->nat44_session_buffer =
319 vlib_get_buffer (vm, bi0);
320 fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
321 vlib_buffer_init_for_free_list (b0, fl);
322 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
327 bi0 = vlib_get_buffer_index (vm, b0);
328 offset = silm->nat44_session_next_record_offset;
331 f = silm->nat44_session_frame;
332 if (PREDICT_FALSE (f == 0))
335 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
336 silm->nat44_session_frame = f;
337 to_next = vlib_frame_vector_args (f);
342 if (PREDICT_FALSE (offset == 0))
343 snat_ipfix_header_create (frm, b0, &offset);
345 if (PREDICT_TRUE (do_flush == 0))
347 u64 time_stamp = clib_host_to_net_u64 (now);
348 clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
349 offset += sizeof (time_stamp);
351 clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
352 offset += sizeof (nat_event);
354 clib_memcpy (b0->data + offset, &src_ip, sizeof (src_ip));
355 offset += sizeof (src_ip);
357 clib_memcpy (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip));
358 offset += sizeof (nat_src_ip);
360 clib_memcpy (b0->data + offset, &proto, sizeof (proto));
361 offset += sizeof (proto);
363 clib_memcpy (b0->data + offset, &src_port, sizeof (src_port));
364 offset += sizeof (src_port);
366 clib_memcpy (b0->data + offset, &nat_src_port, sizeof (nat_src_port));
367 offset += sizeof (nat_src_port);
369 clib_memcpy (b0->data + offset, &vrf_id, sizeof(vrf_id));
370 offset += sizeof (vrf_id);
372 b0->current_length += NAT44_SESSION_CREATE_LEN;
375 if (PREDICT_FALSE (do_flush || (offset + NAT44_SESSION_CREATE_LEN) > frm->path_mtu))
377 snat_ipfix_send (frm, f, b0, silm->nat44_session_template_id);
378 silm->nat44_session_frame = 0;
379 silm->nat44_session_buffer = 0;
382 silm->nat44_session_next_record_offset = offset;
386 snat_ipfix_logging_addr_exhausted (u32 pool_id, int do_flush)
388 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
389 flow_report_main_t *frm = &flow_report_main;
391 vlib_buffer_t *b0 = 0;
394 vlib_main_t * vm = frm->vlib_main;
396 vlib_buffer_free_list_t *fl;
397 u8 nat_event = NAT_ADDRESSES_EXHAUTED;
402 now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
403 now += silm->milisecond_time_0;
405 b0 = silm->addr_exhausted_buffer;
407 if (PREDICT_FALSE (b0 == 0))
412 if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
414 clib_warning ("can't allocate buffer for NAT IPFIX event");
418 b0 = silm->addr_exhausted_buffer =
419 vlib_get_buffer (vm, bi0);
420 fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
421 vlib_buffer_init_for_free_list (b0, fl);
422 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
427 bi0 = vlib_get_buffer_index (vm, b0);
428 offset = silm->addr_exhausted_next_record_offset;
431 f = silm->addr_exhausted_frame;
432 if (PREDICT_FALSE (f == 0))
435 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
436 silm->addr_exhausted_frame = f;
437 to_next = vlib_frame_vector_args (f);
442 if (PREDICT_FALSE (offset == 0))
443 snat_ipfix_header_create (frm, b0, &offset);
445 if (PREDICT_TRUE (do_flush == 0))
447 u64 time_stamp = clib_host_to_net_u64 (now);
448 clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
449 offset += sizeof (time_stamp);
451 clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
452 offset += sizeof (nat_event);
454 clib_memcpy (b0->data + offset, &pool_id, sizeof(pool_id));
455 offset += sizeof (pool_id);
457 b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN;
460 if (PREDICT_FALSE (do_flush || (offset + NAT_ADDRESSES_EXHAUTED_LEN) > frm->path_mtu))
462 snat_ipfix_send (frm, f, b0, silm->addr_exhausted_template_id);
463 silm->addr_exhausted_frame = 0;
464 silm->addr_exhausted_buffer = 0;
467 silm->addr_exhausted_next_record_offset = offset;
471 snat_ipfix_logging_nat44_ses_rpc_cb (snat_ipfix_logging_nat44_ses_args_t *a)
473 snat_ipfix_logging_nat44_ses(a->nat_event, a->src_ip, a->nat_src_ip,
474 a->snat_proto, a->src_port, a->nat_src_port,
479 * @brief Generate NAT44 session create event
481 * @param src_ip source IPv4 address
482 * @param nat_src_ip transaltes source IPv4 address
483 * @param snat_proto SNAT transport protocol
484 * @param src_port source port
485 * @param nat_src_port translated source port
486 * @param vrf_id VRF ID
489 snat_ipfix_logging_nat44_ses_create (u32 src_ip,
491 snat_protocol_t snat_proto,
496 snat_ipfix_logging_nat44_ses_args_t a;
498 a.nat_event = NAT44_SESSION_CREATE;
500 a.nat_src_ip = nat_src_ip;
501 a.snat_proto = snat_proto;
502 a.src_port = src_port;
503 a.nat_src_port = nat_src_port;
506 vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a,
511 * @brief Generate NAT44 session delete event
513 * @param src_ip source IPv4 address
514 * @param nat_src_ip transaltes source IPv4 address
515 * @param snat_proto SNAT transport protocol
516 * @param src_port source port
517 * @param nat_src_port translated source port
518 * @param vrf_id VRF ID
521 snat_ipfix_logging_nat44_ses_delete (u32 src_ip,
523 snat_protocol_t snat_proto,
528 snat_ipfix_logging_nat44_ses_args_t a;
530 a.nat_event = NAT44_SESSION_DELETE;
532 a.nat_src_ip = nat_src_ip;
533 a.snat_proto = snat_proto;
534 a.src_port = src_port;
535 a.nat_src_port = nat_src_port;
538 vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a,
543 snat_data_callback_nat44_session (flow_report_main_t * frm,
549 snat_ipfix_logging_nat44_ses(0, 0, 0, 0, 0, 0, 0, 1);
554 snat_ipfix_logging_addr_exhausted_rpc_cb
555 (snat_ipfix_logging_addr_exhausted_args_t * a)
557 snat_ipfix_logging_addr_exhausted(a->pool_id, 0);
561 * @brief Generate NAT addresses exhausted event
563 * @param pool_id NAT pool ID
566 snat_ipfix_logging_addresses_exhausted(u32 pool_id)
568 //TODO: This event SHOULD be rate limited
569 snat_ipfix_logging_addr_exhausted_args_t a;
573 vl_api_rpc_call_main_thread (snat_ipfix_logging_addr_exhausted_rpc_cb,
574 (u8 *) &a, sizeof (a));
578 snat_data_callback_addr_exhausted (flow_report_main_t * frm,
584 snat_ipfix_logging_addr_exhausted(0, 1);
589 * @brief Enable/disable SNAT IPFIX logging
591 * @param enable 1 if enable, 0 if disable
592 * @param domain_id observation domain ID
593 * @param src_port source port number
595 * @returns 0 if success
598 snat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port)
600 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
601 flow_report_main_t *frm = &flow_report_main;
602 vnet_flow_report_add_del_args_t a;
604 u8 e = enable ? 1 : 0;
606 if (silm->enabled == e)
611 memset (&a, 0, sizeof (a));
612 a.rewrite_callback = snat_template_rewrite_nat44_session;
613 a.flow_data_callback = snat_data_callback_nat44_session;
615 a.domain_id = domain_id ? domain_id : 1;
616 a.src_port = src_port ? src_port : UDP_DST_PORT_ipfix;
618 rv = vnet_flow_report_add_del (frm, &a);
621 clib_warning ("vnet_flow_report_add_del returned %d", rv);
625 a.rewrite_callback = snat_template_rewrite_addr_exhausted;
626 a.flow_data_callback = snat_data_callback_addr_exhausted;
628 rv = vnet_flow_report_add_del (frm, &a);
631 clib_warning ("vnet_flow_report_add_del returned %d", rv);
639 * @brief Initialize SNAT IPFIX logging
641 * @param vm vlib main
644 snat_ipfix_logging_init (vlib_main_t * vm)
646 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
650 /* Set up time reference pair */
651 silm->vlib_time_0 = vlib_time_now (vm);
652 silm->milisecond_time_0 = unix_time_now_nsec () * 1e-6;