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_to_ip_proto (snat_proto);
300 now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
301 now += silm->milisecond_time_0;
303 b0 = silm->nat44_session_buffer;
305 if (PREDICT_FALSE (b0 == 0))
310 if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
312 clib_warning ("can't allocate buffer for NAT IPFIX event");
316 b0 = silm->nat44_session_buffer =
317 vlib_get_buffer (vm, bi0);
318 fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
319 vlib_buffer_init_for_free_list (b0, fl);
320 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
325 bi0 = vlib_get_buffer_index (vm, b0);
326 offset = silm->nat44_session_next_record_offset;
329 f = silm->nat44_session_frame;
330 if (PREDICT_FALSE (f == 0))
333 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
334 silm->nat44_session_frame = f;
335 to_next = vlib_frame_vector_args (f);
340 if (PREDICT_FALSE (offset == 0))
341 snat_ipfix_header_create (frm, b0, &offset);
343 if (PREDICT_TRUE (do_flush == 0))
345 u64 time_stamp = clib_host_to_net_u64 (now);
346 clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
347 offset += sizeof (time_stamp);
349 clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
350 offset += sizeof (nat_event);
352 clib_memcpy (b0->data + offset, &src_ip, sizeof (src_ip));
353 offset += sizeof (src_ip);
355 clib_memcpy (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip));
356 offset += sizeof (nat_src_ip);
358 clib_memcpy (b0->data + offset, &proto, sizeof (proto));
359 offset += sizeof (proto);
361 clib_memcpy (b0->data + offset, &src_port, sizeof (src_port));
362 offset += sizeof (src_port);
364 clib_memcpy (b0->data + offset, &nat_src_port, sizeof (nat_src_port));
365 offset += sizeof (nat_src_port);
367 clib_memcpy (b0->data + offset, &vrf_id, sizeof(vrf_id));
368 offset += sizeof (vrf_id);
370 b0->current_length += NAT44_SESSION_CREATE_LEN;
373 if (PREDICT_FALSE (do_flush || (offset + NAT44_SESSION_CREATE_LEN) > frm->path_mtu))
375 snat_ipfix_send (frm, f, b0, silm->nat44_session_template_id);
376 silm->nat44_session_frame = 0;
377 silm->nat44_session_buffer = 0;
380 silm->nat44_session_next_record_offset = offset;
384 snat_ipfix_logging_addr_exhausted (u32 pool_id, int do_flush)
386 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
387 flow_report_main_t *frm = &flow_report_main;
389 vlib_buffer_t *b0 = 0;
392 vlib_main_t * vm = frm->vlib_main;
394 vlib_buffer_free_list_t *fl;
395 u8 nat_event = NAT_ADDRESSES_EXHAUTED;
400 now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
401 now += silm->milisecond_time_0;
403 b0 = silm->addr_exhausted_buffer;
405 if (PREDICT_FALSE (b0 == 0))
410 if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
412 clib_warning ("can't allocate buffer for NAT IPFIX event");
416 b0 = silm->addr_exhausted_buffer =
417 vlib_get_buffer (vm, bi0);
418 fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
419 vlib_buffer_init_for_free_list (b0, fl);
420 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
425 bi0 = vlib_get_buffer_index (vm, b0);
426 offset = silm->addr_exhausted_next_record_offset;
429 f = silm->addr_exhausted_frame;
430 if (PREDICT_FALSE (f == 0))
433 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
434 silm->addr_exhausted_frame = f;
435 to_next = vlib_frame_vector_args (f);
440 if (PREDICT_FALSE (offset == 0))
441 snat_ipfix_header_create (frm, b0, &offset);
443 if (PREDICT_TRUE (do_flush == 0))
445 u64 time_stamp = clib_host_to_net_u64 (now);
446 clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
447 offset += sizeof (time_stamp);
449 clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
450 offset += sizeof (nat_event);
452 clib_memcpy (b0->data + offset, &pool_id, sizeof(pool_id));
453 offset += sizeof (pool_id);
455 b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN;
458 if (PREDICT_FALSE (do_flush || (offset + NAT_ADDRESSES_EXHAUTED_LEN) > frm->path_mtu))
460 snat_ipfix_send (frm, f, b0, silm->addr_exhausted_template_id);
461 silm->addr_exhausted_frame = 0;
462 silm->addr_exhausted_buffer = 0;
465 silm->addr_exhausted_next_record_offset = offset;
469 snat_ipfix_logging_nat44_ses_rpc_cb (snat_ipfix_logging_nat44_ses_args_t *a)
471 snat_ipfix_logging_nat44_ses(a->nat_event, a->src_ip, a->nat_src_ip,
472 a->snat_proto, a->src_port, a->nat_src_port,
477 * @brief Generate NAT44 session create event
479 * @param src_ip source IPv4 address
480 * @param nat_src_ip transaltes source IPv4 address
481 * @param snat_proto SNAT transport protocol
482 * @param src_port source port
483 * @param nat_src_port translated source port
484 * @param vrf_id VRF ID
487 snat_ipfix_logging_nat44_ses_create (u32 src_ip,
489 snat_protocol_t snat_proto,
494 snat_ipfix_logging_nat44_ses_args_t a;
496 a.nat_event = NAT44_SESSION_CREATE;
498 a.nat_src_ip = nat_src_ip;
499 a.snat_proto = snat_proto;
500 a.src_port = src_port;
501 a.nat_src_port = nat_src_port;
504 vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a,
509 * @brief Generate NAT44 session delete event
511 * @param src_ip source IPv4 address
512 * @param nat_src_ip transaltes source IPv4 address
513 * @param snat_proto SNAT transport protocol
514 * @param src_port source port
515 * @param nat_src_port translated source port
516 * @param vrf_id VRF ID
519 snat_ipfix_logging_nat44_ses_delete (u32 src_ip,
521 snat_protocol_t snat_proto,
526 snat_ipfix_logging_nat44_ses_args_t a;
528 a.nat_event = NAT44_SESSION_DELETE;
530 a.nat_src_ip = nat_src_ip;
531 a.snat_proto = snat_proto;
532 a.src_port = src_port;
533 a.nat_src_port = nat_src_port;
536 vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a,
541 snat_data_callback_nat44_session (flow_report_main_t * frm,
547 snat_ipfix_logging_nat44_ses(0, 0, 0, 0, 0, 0, 0, 1);
552 snat_ipfix_logging_addr_exhausted_rpc_cb
553 (snat_ipfix_logging_addr_exhausted_args_t * a)
555 snat_ipfix_logging_addr_exhausted(a->pool_id, 0);
559 * @brief Generate NAT addresses exhausted event
561 * @param pool_id NAT pool ID
564 snat_ipfix_logging_addresses_exhausted(u32 pool_id)
566 //TODO: This event SHOULD be rate limited
567 snat_ipfix_logging_addr_exhausted_args_t a;
571 vl_api_rpc_call_main_thread (snat_ipfix_logging_addr_exhausted_rpc_cb,
572 (u8 *) &a, sizeof (a));
576 snat_data_callback_addr_exhausted (flow_report_main_t * frm,
582 snat_ipfix_logging_addr_exhausted(0, 1);
587 * @brief Enable/disable SNAT IPFIX logging
589 * @param enable 1 if enable, 0 if disable
590 * @param domain_id observation domain ID
591 * @param src_port source port number
593 * @returns 0 if success
596 snat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port)
598 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
599 flow_report_main_t *frm = &flow_report_main;
600 vnet_flow_report_add_del_args_t a;
602 u8 e = enable ? 1 : 0;
604 if (silm->enabled == e)
609 memset (&a, 0, sizeof (a));
610 a.rewrite_callback = snat_template_rewrite_nat44_session;
611 a.flow_data_callback = snat_data_callback_nat44_session;
613 a.domain_id = domain_id ? domain_id : 1;
614 a.src_port = src_port ? src_port : UDP_DST_PORT_ipfix;
616 rv = vnet_flow_report_add_del (frm, &a);
619 clib_warning ("vnet_flow_report_add_del returned %d", rv);
623 a.rewrite_callback = snat_template_rewrite_addr_exhausted;
624 a.flow_data_callback = snat_data_callback_addr_exhausted;
626 rv = vnet_flow_report_add_del (frm, &a);
629 clib_warning ("vnet_flow_report_add_del returned %d", rv);
637 * @brief Initialize SNAT IPFIX logging
639 * @param vm vlib main
642 snat_ipfix_logging_init (vlib_main_t * vm)
644 snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
648 /* Set up time reference pair */
649 silm->vlib_time_0 = vlib_time_now (vm);
650 silm->milisecond_time_0 = unix_time_now_nsec () * 1e-6;