ipfix-export: refactor fields in flow_report_main
[vpp.git] / src / plugins / nat / lib / ipfix_logging.c
1 /*
2  * nat_ipfix_logging.c - NAT Events IPFIX logging
3  *
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:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #include <vnet/fib/fib_table.h>
19 #include <vnet/ipfix-export/flow_report.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/udp/udp_local.h>
22 #include <vlibmemory/api.h>
23 #include <vppinfra/atomics.h>
24 #include <nat/lib/ipfix_logging.h>
25 #include <nat/lib/inlines.h>
26
27 vlib_node_registration_t nat_ipfix_flush_node;
28 nat_ipfix_logging_main_t nat_ipfix_logging_main;
29
30 #define NAT44_SESSION_CREATE_LEN 26
31 #define NAT_ADDRESSES_EXHAUTED_LEN 13
32 #define MAX_ENTRIES_PER_USER_LEN 21
33 #define MAX_SESSIONS_LEN 17
34 #define MAX_BIBS_LEN 17
35 #define MAX_FRAGMENTS_IP4_LEN 21
36 #define MAX_FRAGMENTS_IP6_LEN 33
37 #define NAT64_BIB_LEN 38
38 #define NAT64_SES_LEN 62
39
40 #define NAT44_SESSION_CREATE_FIELD_COUNT 8
41 #define NAT_ADDRESSES_EXHAUTED_FIELD_COUNT 3
42 #define MAX_ENTRIES_PER_USER_FIELD_COUNT 5
43 #define MAX_SESSIONS_FIELD_COUNT 4
44 #define MAX_BIBS_FIELD_COUNT 4
45 #define MAX_FRAGMENTS_FIELD_COUNT 5
46 #define NAT64_BIB_FIELD_COUNT 8
47 #define NAT64_SES_FIELD_COUNT 12
48
49 typedef struct
50 {
51   u8 nat_event;
52   u32 src_ip;
53   u32 nat_src_ip;
54   ip_protocol_t proto;
55   u16 src_port;
56   u16 nat_src_port;
57   u32 vrf_id;
58 } nat_ipfix_logging_nat44_ses_args_t;
59
60 typedef struct
61 {
62   u32 pool_id;
63 } nat_ipfix_logging_addr_exhausted_args_t;
64
65 typedef struct
66 {
67   u32 limit;
68   u32 src_ip;
69 } nat_ipfix_logging_max_entries_per_user_args_t;
70
71 typedef struct
72 {
73   u32 limit;
74 } nat_ipfix_logging_max_sessions_args_t;
75
76 typedef struct
77 {
78   u32 limit;
79 } nat_ipfix_logging_max_bibs_args_t;
80
81 typedef struct
82 {
83   u32 limit;
84   u32 src;
85 } nat_ipfix_logging_max_frags_ip4_args_t;
86
87 typedef struct
88 {
89   u32 limit;
90   u64 src[2];
91 } nat_ipfix_logging_max_frags_ip6_args_t;
92
93 typedef struct
94 {
95   u8 nat_event;
96   u64 src_ip[2];
97   u32 nat_src_ip;
98   u8 proto;
99   u16 src_port;
100   u16 nat_src_port;
101   u64 dst_ip[2];
102   u32 nat_dst_ip;
103   u32 vrf_id;
104   u16 dst_port;
105   u16 nat_dst_port;
106 } nat_ipfix_logging_nat64_ses_args_t;
107
108 typedef struct
109 {
110   u8 nat_event;
111   u64 src_ip[2];
112   u32 nat_src_ip;
113   u8 proto;
114   u16 src_port;
115   u16 nat_src_port;
116   u32 vrf_id;
117 } nat_ipfix_logging_nat64_bib_args_t;
118
119 #define skip_if_disabled()                                        \
120 do {                                                              \
121   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;     \
122   if (PREDICT_TRUE (!clib_atomic_fetch_or(&silm->enabled, 0)))    \
123     return;                                                       \
124 } while (0)
125
126 #define update_template_id(old_id, new_id)                \
127 do {                                                      \
128   u16 template_id = clib_atomic_fetch_or(old_id, 0);      \
129   clib_atomic_cmp_and_swap(old_id, template_id, new_id);  \
130 } while (0)
131
132 /**
133  * @brief Create an IPFIX template packet rewrite string
134  *
135  * @param frm               flow report main
136  * @param fr                flow report
137  * @param collector_address collector address
138  * @param src_address       source address
139  * @param collector_port    collector
140  * @param event             NAT event ID
141  * @param quota_event       NAT quota exceeded event ID
142  *
143  * @returns template packet
144  */
145 static inline u8 *
146 nat_template_rewrite (flow_report_main_t * frm,
147                        flow_report_t * fr,
148                        ip4_address_t * collector_address,
149                        ip4_address_t * src_address,
150                        u16 collector_port,
151                        nat_event_t event, quota_exceed_event_t quota_event)
152 {
153   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
154   ip4_header_t *ip;
155   udp_header_t *udp;
156   ipfix_message_header_t *h;
157   ipfix_set_header_t *s;
158   ipfix_template_header_t *t;
159   ipfix_field_specifier_t *f;
160   ipfix_field_specifier_t *first_field;
161   u8 *rewrite = 0;
162   ip4_ipfix_template_packet_t *tp;
163   u32 field_count = 0;
164   flow_report_stream_t *stream;
165   u32 stream_index;
166   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
167
168   stream = &exp->streams[fr->stream_index];
169
170   stream_index = clib_atomic_fetch_or(&silm->stream_index, 0);
171   clib_atomic_cmp_and_swap (&silm->stream_index,
172                             stream_index, fr->stream_index);
173
174   if (event == NAT_ADDRESSES_EXHAUTED)
175     {
176       field_count = NAT_ADDRESSES_EXHAUTED_FIELD_COUNT;
177
178       update_template_id(&silm->addr_exhausted_template_id,
179                          fr->template_id);
180     }
181   else if (event == NAT44_SESSION_CREATE)
182     {
183       field_count = NAT44_SESSION_CREATE_FIELD_COUNT;
184
185       update_template_id(&silm->nat44_session_template_id,
186                          fr->template_id);
187     }
188   else if (event == NAT64_BIB_CREATE)
189     {
190       field_count = NAT64_BIB_FIELD_COUNT;
191
192       update_template_id(&silm->nat64_bib_template_id,
193                          fr->template_id);
194     }
195   else if (event == NAT64_SESSION_CREATE)
196     {
197       field_count = NAT64_SES_FIELD_COUNT;
198
199       update_template_id(&silm->nat64_ses_template_id,
200                          fr->template_id);
201     }
202   else if (event == QUOTA_EXCEEDED)
203     {
204       if (quota_event == MAX_ENTRIES_PER_USER)
205         {
206           field_count = MAX_ENTRIES_PER_USER_FIELD_COUNT;
207
208           update_template_id(&silm->max_entries_per_user_template_id,
209                              fr->template_id);
210
211         }
212       else if (quota_event == MAX_SESSION_ENTRIES)
213         {
214           field_count = MAX_SESSIONS_FIELD_COUNT;
215
216           update_template_id(&silm->max_sessions_template_id,
217                              fr->template_id);
218         }
219       else if (quota_event == MAX_BIB_ENTRIES)
220         {
221           field_count = MAX_BIBS_FIELD_COUNT;
222
223           update_template_id(&silm->max_bibs_template_id,
224                              fr->template_id);
225         }
226     }
227
228   /* allocate rewrite space */
229   vec_validate_aligned (rewrite,
230                         sizeof (ip4_ipfix_template_packet_t)
231                         + field_count * sizeof (ipfix_field_specifier_t) - 1,
232                         CLIB_CACHE_LINE_BYTES);
233
234   tp = (ip4_ipfix_template_packet_t *) rewrite;
235   ip = (ip4_header_t *) & tp->ip4;
236   udp = (udp_header_t *) (ip + 1);
237   h = (ipfix_message_header_t *) (udp + 1);
238   s = (ipfix_set_header_t *) (h + 1);
239   t = (ipfix_template_header_t *) (s + 1);
240   first_field = f = (ipfix_field_specifier_t *) (t + 1);
241
242   ip->ip_version_and_header_length = 0x45;
243   ip->ttl = 254;
244   ip->protocol = IP_PROTOCOL_UDP;
245   ip->src_address.as_u32 = src_address->as_u32;
246   ip->dst_address.as_u32 = collector_address->as_u32;
247   udp->src_port = clib_host_to_net_u16 (stream->src_port);
248   udp->dst_port = clib_host_to_net_u16 (collector_port);
249   udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
250
251   /* FIXUP: message header export_time */
252   h->domain_id = clib_host_to_net_u32 (stream->domain_id);
253
254   /* Add TLVs to the template */
255   if (event == NAT_ADDRESSES_EXHAUTED)
256     {
257       f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
258       f++;
259       f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
260       f++;
261       f->e_id_length = ipfix_e_id_length (0, natPoolId, 4);
262       f++;
263     }
264   else if (event == NAT44_SESSION_CREATE)
265     {
266       f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
267       f++;
268       f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
269       f++;
270       f->e_id_length = ipfix_e_id_length (0, sourceIPv4Address, 4);
271       f++;
272       f->e_id_length = ipfix_e_id_length (0, postNATSourceIPv4Address, 4);
273       f++;
274       f->e_id_length = ipfix_e_id_length (0, protocolIdentifier, 1);
275       f++;
276       f->e_id_length = ipfix_e_id_length (0, sourceTransportPort, 2);
277       f++;
278       f->e_id_length = ipfix_e_id_length (0, postNAPTSourceTransportPort, 2);
279       f++;
280       f->e_id_length = ipfix_e_id_length (0, ingressVRFID, 4);
281       f++;
282     }
283   else if (event == NAT64_BIB_CREATE)
284     {
285       f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
286       f++;
287       f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
288       f++;
289       f->e_id_length = ipfix_e_id_length (0, sourceIPv6Address, 16);
290       f++;
291       f->e_id_length = ipfix_e_id_length (0, postNATSourceIPv4Address, 4);
292       f++;
293       f->e_id_length = ipfix_e_id_length (0, protocolIdentifier, 1);
294       f++;
295       f->e_id_length = ipfix_e_id_length (0, sourceTransportPort, 2);
296       f++;
297       f->e_id_length = ipfix_e_id_length (0, postNAPTSourceTransportPort, 2);
298       f++;
299       f->e_id_length = ipfix_e_id_length (0, ingressVRFID, 4);
300       f++;
301     }
302   else if (event == NAT64_SESSION_CREATE)
303     {
304       f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
305       f++;
306       f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
307       f++;
308       f->e_id_length = ipfix_e_id_length (0, sourceIPv6Address, 16);
309       f++;
310       f->e_id_length = ipfix_e_id_length (0, postNATSourceIPv4Address, 4);
311       f++;
312       f->e_id_length = ipfix_e_id_length (0, protocolIdentifier, 1);
313       f++;
314       f->e_id_length = ipfix_e_id_length (0, sourceTransportPort, 2);
315       f++;
316       f->e_id_length = ipfix_e_id_length (0, postNAPTSourceTransportPort, 2);
317       f++;
318       f->e_id_length = ipfix_e_id_length (0, destinationIPv6Address, 16);
319       f++;
320       f->e_id_length = ipfix_e_id_length (0, postNATDestinationIPv4Address, 4);
321       f++;
322       f->e_id_length = ipfix_e_id_length (0, destinationTransportPort, 2);
323       f++;
324       f->e_id_length = ipfix_e_id_length (0, postNAPTDestinationTransportPort,
325                                           2);
326       f++;
327       f->e_id_length = ipfix_e_id_length (0, ingressVRFID, 4);
328       f++;
329     }
330   else if (event == QUOTA_EXCEEDED)
331     {
332       if (quota_event == MAX_ENTRIES_PER_USER)
333         {
334           f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds,
335                                               8);
336           f++;
337           f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
338           f++;
339           f->e_id_length = ipfix_e_id_length (0, natQuotaExceededEvent, 4);
340           f++;
341           f->e_id_length = ipfix_e_id_length (0, maxEntriesPerUser, 4);
342           f++;
343           f->e_id_length = ipfix_e_id_length (0, sourceIPv4Address, 4);
344           f++;
345         }
346       else if (quota_event == MAX_SESSION_ENTRIES)
347         {
348           f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds,
349                                               8);
350           f++;
351           f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
352           f++;
353           f->e_id_length = ipfix_e_id_length (0, natQuotaExceededEvent, 4);
354           f++;
355           f->e_id_length = ipfix_e_id_length (0, maxSessionEntries, 4);
356           f++;
357         }
358       else if (quota_event == MAX_BIB_ENTRIES)
359         {
360           f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds,
361                                               8);
362           f++;
363           f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
364           f++;
365           f->e_id_length = ipfix_e_id_length (0, natQuotaExceededEvent, 4);
366           f++;
367           f->e_id_length = ipfix_e_id_length (0, maxBIBEntries, 4);
368           f++;
369         }
370     }
371
372   /* Back to the template packet... */
373   ip = (ip4_header_t *) & tp->ip4;
374   udp = (udp_header_t *) (ip + 1);
375
376   ASSERT (f - first_field);
377   /* Field count in this template */
378   t->id_count = ipfix_id_count (fr->template_id, f - first_field);
379
380   /* set length in octets */
381   s->set_id_length =
382     ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
383
384   /* message length in octets */
385   h->version_length = version_length ((u8 *) f - (u8 *) h);
386
387   ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
388   ip->checksum = ip4_header_checksum (ip);
389
390   return rewrite;
391 }
392
393 u8 *
394 nat_template_rewrite_addr_exhausted (flow_report_main_t * frm,
395                                       flow_report_t * fr,
396                                       ip4_address_t * collector_address,
397                                       ip4_address_t * src_address,
398                                       u16 collector_port,
399                                       ipfix_report_element_t *elts,
400                                       u32 n_elts, u32 *stream_index)
401 {
402   return nat_template_rewrite (frm, fr, collector_address, src_address,
403                                 collector_port, NAT_ADDRESSES_EXHAUTED, 0);
404 }
405
406 u8 *
407 nat_template_rewrite_nat44_session (flow_report_main_t * frm,
408                                      flow_report_t * fr,
409                                      ip4_address_t * collector_address,
410                                      ip4_address_t * src_address,
411                                      u16 collector_port,
412                                      ipfix_report_element_t *elts,
413                                      u32 n_elts, u32 *stream_index)
414 {
415   return nat_template_rewrite (frm, fr, collector_address, src_address,
416                                 collector_port, NAT44_SESSION_CREATE, 0);
417 }
418
419 u8 *
420 nat_template_rewrite_max_entries_per_usr (flow_report_main_t * frm,
421                                            flow_report_t * fr,
422                                            ip4_address_t * collector_address,
423                                            ip4_address_t * src_address,
424                                            u16 collector_port,
425                                            ipfix_report_element_t *elts,
426                                            u32 n_elts, u32 *stream_index)
427 {
428   return nat_template_rewrite (frm, fr, collector_address, src_address,
429                                 collector_port, QUOTA_EXCEEDED,
430                                 MAX_ENTRIES_PER_USER);
431 }
432
433 u8 *
434 nat_template_rewrite_max_sessions (flow_report_main_t * frm,
435                                    flow_report_t * fr,
436                                    ip4_address_t * collector_address,
437                                    ip4_address_t * src_address,
438                                    u16 collector_port,
439                                    ipfix_report_element_t *elts,
440                                    u32 n_elts, u32 *stream_index)
441 {
442   return nat_template_rewrite (frm, fr, collector_address, src_address,
443                                 collector_port, QUOTA_EXCEEDED,
444                                 MAX_SESSION_ENTRIES);
445 }
446
447 u8 *
448 nat_template_rewrite_max_bibs (flow_report_main_t * frm,
449                                flow_report_t * fr,
450                                ip4_address_t * collector_address,
451                                ip4_address_t * src_address,
452                                u16 collector_port,
453                                ipfix_report_element_t *elts,
454                                u32 n_elts, u32 *stream_index)
455 {
456   return nat_template_rewrite (frm, fr, collector_address, src_address,
457                                 collector_port, QUOTA_EXCEEDED,
458                                 MAX_BIB_ENTRIES);
459 }
460
461 u8 *
462 nat_template_rewrite_nat64_bib (flow_report_main_t * frm,
463                                 flow_report_t * fr,
464                                 ip4_address_t * collector_address,
465                                 ip4_address_t * src_address,
466                                 u16 collector_port,
467                                 ipfix_report_element_t *elts,
468                                 u32 n_elts, u32 *stream_index)
469 {
470   return nat_template_rewrite (frm, fr, collector_address, src_address,
471                                 collector_port, NAT64_BIB_CREATE, 0);
472 }
473
474 u8 *
475 nat_template_rewrite_nat64_session (flow_report_main_t * frm,
476                                     flow_report_t * fr,
477                                     ip4_address_t * collector_address,
478                                     ip4_address_t * src_address,
479                                     u16 collector_port,
480                                     ipfix_report_element_t *elts,
481                                     u32 n_elts, u32 *stream_index)
482 {
483   return nat_template_rewrite (frm, fr, collector_address, src_address,
484                                 collector_port, NAT64_SESSION_CREATE, 0);
485 }
486
487 static inline void
488 nat_ipfix_header_create (flow_report_main_t * frm,
489                           vlib_buffer_t * b0, u32 * offset)
490 {
491   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
492   flow_report_stream_t *stream;
493   ip4_ipfix_template_packet_t *tp;
494   ipfix_message_header_t *h = 0;
495   ipfix_set_header_t *s = 0;
496   u32 sequence_number;
497   u32 stream_index;
498   ip4_header_t *ip;
499   udp_header_t *udp;
500   vlib_main_t *vm = vlib_get_main ();
501   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
502
503   stream_index = clib_atomic_fetch_or(&silm->stream_index, 0);
504   stream = &exp->streams[stream_index];
505
506   b0->current_data = 0;
507   b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) +
508     sizeof (*s);
509   b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_FLOW_REPORT);
510   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
511   vnet_buffer (b0)->sw_if_index[VLIB_TX] = exp->fib_index;
512   tp = vlib_buffer_get_current (b0);
513   ip = (ip4_header_t *) & tp->ip4;
514   udp = (udp_header_t *) (ip + 1);
515   h = (ipfix_message_header_t *) (udp + 1);
516   s = (ipfix_set_header_t *) (h + 1);
517
518   ip->ip_version_and_header_length = 0x45;
519   ip->ttl = 254;
520   ip->protocol = IP_PROTOCOL_UDP;
521   ip->flags_and_fragment_offset = 0;
522   ip->src_address.as_u32 = exp->src_address.as_u32;
523   ip->dst_address.as_u32 = exp->ipfix_collector.as_u32;
524   udp->src_port = clib_host_to_net_u16 (stream->src_port);
525   udp->dst_port = clib_host_to_net_u16 (exp->collector_port);
526   udp->checksum = 0;
527
528   h->export_time = clib_host_to_net_u32 ((u32)
529                                          (((f64) frm->unix_time_0) +
530                                           (vlib_time_now (vm) -
531                                            frm->vlib_time_0)));
532
533   sequence_number = clib_atomic_fetch_add (&stream->sequence_number, 1);
534   h->sequence_number = clib_host_to_net_u32 (sequence_number);
535   h->domain_id = clib_host_to_net_u32 (stream->domain_id);
536
537   *offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp);
538 }
539
540 static inline void
541 nat_ipfix_send (flow_report_main_t *frm, vlib_frame_t *f, vlib_buffer_t *b0,
542                 u16 template_id)
543 {
544   ip4_ipfix_template_packet_t *tp;
545   ipfix_message_header_t *h = 0;
546   ipfix_set_header_t *s = 0;
547   ip4_header_t *ip;
548   udp_header_t *udp;
549   vlib_main_t *vm = vlib_get_main ();
550   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
551
552   tp = vlib_buffer_get_current (b0);
553   ip = (ip4_header_t *) & tp->ip4;
554   udp = (udp_header_t *) (ip + 1);
555   h = (ipfix_message_header_t *) (udp + 1);
556   s = (ipfix_set_header_t *) (h + 1);
557
558   s->set_id_length = ipfix_set_id_length (template_id,
559                                           b0->current_length -
560                                           (sizeof (*ip) + sizeof (*udp) +
561                                            sizeof (*h)));
562   h->version_length = version_length (b0->current_length -
563                                       (sizeof (*ip) + sizeof (*udp)));
564
565   ip->length = clib_host_to_net_u16 (b0->current_length);
566   ip->checksum = ip4_header_checksum (ip);
567   udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
568
569   if (exp->udp_checksum)
570     {
571       udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
572       if (udp->checksum == 0)
573         udp->checksum = 0xffff;
574     }
575
576   ASSERT (ip4_header_checksum_is_valid (ip));
577
578   vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
579 }
580
581 static void
582 nat_ipfix_logging_nat44_ses (u32 thread_index, u8 nat_event, u32 src_ip,
583                              u32 nat_src_ip, ip_protocol_t proto, u16 src_port,
584                              u16 nat_src_port, u32 fib_index, int do_flush)
585 {
586   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
587   nat_ipfix_per_thread_data_t *sitd = &silm->per_thread_data[thread_index];
588   flow_report_main_t *frm = &flow_report_main;
589   vlib_frame_t *f;
590   vlib_buffer_t *b0 = 0;
591   u32 bi0 = ~0;
592   u32 offset;
593   vlib_main_t *vm = vlib_get_main ();
594   u64 now;
595   u16 template_id;
596   u32 vrf_id;
597   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
598
599   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
600   now += silm->milisecond_time_0;
601
602   b0 = sitd->nat44_session_buffer;
603
604   if (PREDICT_FALSE (b0 == 0))
605     {
606       if (do_flush)
607         return;
608
609       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
610         {
611           //nat_elog_err ("can't allocate buffer for NAT IPFIX event");
612           return;
613         }
614
615       b0 = sitd->nat44_session_buffer = vlib_get_buffer (vm, bi0);
616       offset = 0;
617     }
618   else
619     {
620       bi0 = vlib_get_buffer_index (vm, b0);
621       offset = sitd->nat44_session_next_record_offset;
622     }
623
624   f = sitd->nat44_session_frame;
625   if (PREDICT_FALSE (f == 0))
626     {
627       u32 *to_next;
628       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
629       sitd->nat44_session_frame = f;
630       to_next = vlib_frame_vector_args (f);
631       to_next[0] = bi0;
632       f->n_vectors = 1;
633     }
634
635   if (PREDICT_FALSE (offset == 0))
636     nat_ipfix_header_create (frm, b0, &offset);
637
638   if (PREDICT_TRUE (do_flush == 0))
639     {
640       u64 time_stamp = clib_host_to_net_u64 (now);
641       clib_memcpy_fast (b0->data + offset, &time_stamp, sizeof (time_stamp));
642       offset += sizeof (time_stamp);
643
644       clib_memcpy_fast (b0->data + offset, &nat_event, sizeof (nat_event));
645       offset += sizeof (nat_event);
646
647       clib_memcpy_fast (b0->data + offset, &src_ip, sizeof (src_ip));
648       offset += sizeof (src_ip);
649
650       clib_memcpy_fast (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip));
651       offset += sizeof (nat_src_ip);
652
653       clib_memcpy_fast (b0->data + offset, &proto, sizeof (proto));
654       offset += sizeof (proto);
655
656       clib_memcpy_fast (b0->data + offset, &src_port, sizeof (src_port));
657       offset += sizeof (src_port);
658
659       clib_memcpy_fast (b0->data + offset, &nat_src_port, sizeof (nat_src_port));
660       offset += sizeof (nat_src_port);
661
662       vrf_id = fib_table_get_table_id (fib_index, FIB_PROTOCOL_IP4);
663       vrf_id = clib_host_to_net_u32 (vrf_id);
664       clib_memcpy_fast (b0->data + offset, &vrf_id, sizeof (vrf_id));
665       offset += sizeof (vrf_id);
666
667       b0->current_length += NAT44_SESSION_CREATE_LEN;
668     }
669
670   if (PREDICT_FALSE (do_flush ||
671                      (offset + NAT44_SESSION_CREATE_LEN) > exp->path_mtu))
672     {
673       template_id = clib_atomic_fetch_or (
674         &silm->nat44_session_template_id,
675         0);
676       nat_ipfix_send (frm, f, b0, template_id);
677       sitd->nat44_session_frame = 0;
678       sitd->nat44_session_buffer = 0;
679       offset = 0;
680     }
681   sitd->nat44_session_next_record_offset = offset;
682 }
683
684 static void
685 nat_ipfix_logging_addr_exhausted (u32 thread_index, u32 pool_id, int do_flush)
686 {
687   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
688   nat_ipfix_per_thread_data_t *sitd = &silm->per_thread_data[thread_index];
689   flow_report_main_t *frm = &flow_report_main;
690   vlib_frame_t *f;
691   vlib_buffer_t *b0 = 0;
692   u32 bi0 = ~0;
693   u32 offset;
694   vlib_main_t *vm = vlib_get_main ();
695   u64 now;
696   u8 nat_event = NAT_ADDRESSES_EXHAUTED;
697   u16 template_id;
698   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
699
700   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
701   now += silm->milisecond_time_0;
702
703   b0 = sitd->addr_exhausted_buffer;
704
705   if (PREDICT_FALSE (b0 == 0))
706     {
707       if (do_flush)
708         return;
709
710       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
711         {
712           //nat_elog_err ("can't allocate buffer for NAT IPFIX event");
713           return;
714         }
715
716       b0 = sitd->addr_exhausted_buffer = vlib_get_buffer (vm, bi0);
717       offset = 0;
718     }
719   else
720     {
721       bi0 = vlib_get_buffer_index (vm, b0);
722       offset = sitd->addr_exhausted_next_record_offset;
723     }
724
725   f = sitd->addr_exhausted_frame;
726   if (PREDICT_FALSE (f == 0))
727     {
728       u32 *to_next;
729       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
730       sitd->addr_exhausted_frame = f;
731       to_next = vlib_frame_vector_args (f);
732       to_next[0] = bi0;
733       f->n_vectors = 1;
734     }
735
736   if (PREDICT_FALSE (offset == 0))
737     nat_ipfix_header_create (frm, b0, &offset);
738
739   if (PREDICT_TRUE (do_flush == 0))
740     {
741       u64 time_stamp = clib_host_to_net_u64 (now);
742       clib_memcpy_fast (b0->data + offset, &time_stamp, sizeof (time_stamp));
743       offset += sizeof (time_stamp);
744
745       clib_memcpy_fast (b0->data + offset, &nat_event, sizeof (nat_event));
746       offset += sizeof (nat_event);
747
748       clib_memcpy_fast (b0->data + offset, &pool_id, sizeof (pool_id));
749       offset += sizeof (pool_id);
750
751       b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN;
752     }
753
754   if (PREDICT_FALSE (do_flush ||
755                      (offset + NAT_ADDRESSES_EXHAUTED_LEN) > exp->path_mtu))
756     {
757       template_id = clib_atomic_fetch_or (
758           &silm->addr_exhausted_template_id,
759           0);
760       nat_ipfix_send (frm, f, b0, template_id);
761       sitd->addr_exhausted_frame = 0;
762       sitd->addr_exhausted_buffer = 0;
763       offset = 0;
764     }
765   sitd->addr_exhausted_next_record_offset = offset;
766 }
767
768 static void
769 nat_ipfix_logging_max_entries_per_usr (u32 thread_index,
770                                         u32 limit, u32 src_ip, int do_flush)
771 {
772   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
773   nat_ipfix_per_thread_data_t *sitd = &silm->per_thread_data[thread_index];
774   flow_report_main_t *frm = &flow_report_main;
775   vlib_frame_t *f;
776   vlib_buffer_t *b0 = 0;
777   u32 bi0 = ~0;
778   u32 offset;
779   vlib_main_t *vm = vlib_get_main ();
780   u64 now;
781   u8 nat_event = QUOTA_EXCEEDED;
782   u32 quota_event = clib_host_to_net_u32 (MAX_ENTRIES_PER_USER);
783   u16 template_id;
784   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
785
786   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
787   now += silm->milisecond_time_0;
788
789   b0 = sitd->max_entries_per_user_buffer;
790
791   if (PREDICT_FALSE (b0 == 0))
792     {
793       if (do_flush)
794         return;
795
796       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
797         {
798           //nat_elog_err ("can't allocate buffer for NAT IPFIX event");
799           return;
800         }
801
802       b0 = sitd->max_entries_per_user_buffer = vlib_get_buffer (vm, bi0);
803       offset = 0;
804     }
805   else
806     {
807       bi0 = vlib_get_buffer_index (vm, b0);
808       offset = sitd->max_entries_per_user_next_record_offset;
809     }
810
811   f = sitd->max_entries_per_user_frame;
812   if (PREDICT_FALSE (f == 0))
813     {
814       u32 *to_next;
815       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
816       sitd->max_entries_per_user_frame = f;
817       to_next = vlib_frame_vector_args (f);
818       to_next[0] = bi0;
819       f->n_vectors = 1;
820     }
821
822   if (PREDICT_FALSE (offset == 0))
823     nat_ipfix_header_create (frm, b0, &offset);
824
825   if (PREDICT_TRUE (do_flush == 0))
826     {
827       u64 time_stamp = clib_host_to_net_u64 (now);
828       clib_memcpy_fast (b0->data + offset, &time_stamp, sizeof (time_stamp));
829       offset += sizeof (time_stamp);
830
831       clib_memcpy_fast (b0->data + offset, &nat_event, sizeof (nat_event));
832       offset += sizeof (nat_event);
833
834       clib_memcpy_fast (b0->data + offset, &quota_event, sizeof (quota_event));
835       offset += sizeof (quota_event);
836
837       limit = clib_host_to_net_u32 (limit);
838       clib_memcpy_fast (b0->data + offset, &limit, sizeof (limit));
839       offset += sizeof (limit);
840
841       clib_memcpy_fast (b0->data + offset, &src_ip, sizeof (src_ip));
842       offset += sizeof (src_ip);
843
844       b0->current_length += MAX_ENTRIES_PER_USER_LEN;
845     }
846
847   if (PREDICT_FALSE (do_flush ||
848                      (offset + MAX_ENTRIES_PER_USER_LEN) > exp->path_mtu))
849     {
850       template_id = clib_atomic_fetch_or (
851           &silm->max_entries_per_user_template_id,
852           0);
853       nat_ipfix_send (frm, f, b0, template_id);
854       sitd->max_entries_per_user_frame = 0;
855       sitd->max_entries_per_user_buffer = 0;
856       offset = 0;
857     }
858   sitd->max_entries_per_user_next_record_offset = offset;
859 }
860
861 static void
862 nat_ipfix_logging_max_ses (u32 thread_index, u32 limit, int do_flush)
863 {
864   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
865   nat_ipfix_per_thread_data_t *sitd = &silm->per_thread_data[thread_index];
866   flow_report_main_t *frm = &flow_report_main;
867   vlib_frame_t *f;
868   vlib_buffer_t *b0 = 0;
869   u32 bi0 = ~0;
870   u32 offset;
871   vlib_main_t *vm = vlib_get_main ();
872   u64 now;
873   u8 nat_event = QUOTA_EXCEEDED;
874   u32 quota_event = clib_host_to_net_u32 (MAX_SESSION_ENTRIES);
875   u16 template_id;
876   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
877
878   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
879   now += silm->milisecond_time_0;
880
881   b0 = sitd->max_sessions_buffer;
882
883   if (PREDICT_FALSE (b0 == 0))
884     {
885       if (do_flush)
886         return;
887
888       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
889         {
890           //nat_elog_err ("can't allocate buffer for NAT IPFIX event");
891           return;
892         }
893
894       b0 = sitd->max_sessions_buffer = vlib_get_buffer (vm, bi0);
895       offset = 0;
896     }
897   else
898     {
899       bi0 = vlib_get_buffer_index (vm, b0);
900       offset = sitd->max_sessions_next_record_offset;
901     }
902
903   f = sitd->max_sessions_frame;
904   if (PREDICT_FALSE (f == 0))
905     {
906       u32 *to_next;
907       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
908       sitd->max_sessions_frame = f;
909       to_next = vlib_frame_vector_args (f);
910       to_next[0] = bi0;
911       f->n_vectors = 1;
912     }
913
914   if (PREDICT_FALSE (offset == 0))
915     nat_ipfix_header_create (frm, b0, &offset);
916
917   if (PREDICT_TRUE (do_flush == 0))
918     {
919       u64 time_stamp = clib_host_to_net_u64 (now);
920       clib_memcpy_fast (b0->data + offset, &time_stamp, sizeof (time_stamp));
921       offset += sizeof (time_stamp);
922
923       clib_memcpy_fast (b0->data + offset, &nat_event, sizeof (nat_event));
924       offset += sizeof (nat_event);
925
926       clib_memcpy_fast (b0->data + offset, &quota_event, sizeof (quota_event));
927       offset += sizeof (quota_event);
928
929       limit = clib_host_to_net_u32 (limit);
930       clib_memcpy_fast (b0->data + offset, &limit, sizeof (limit));
931       offset += sizeof (limit);
932
933       b0->current_length += MAX_SESSIONS_LEN;
934     }
935
936   if (PREDICT_FALSE (do_flush || (offset + MAX_SESSIONS_LEN) > exp->path_mtu))
937     {
938       template_id = clib_atomic_fetch_or (
939         &silm->max_sessions_template_id,
940         0);
941       nat_ipfix_send (frm, f, b0, template_id);
942       sitd->max_sessions_frame = 0;
943       sitd->max_sessions_buffer = 0;
944       offset = 0;
945     }
946   sitd->max_sessions_next_record_offset = offset;
947 }
948
949 static void
950 nat_ipfix_logging_max_bib (u32 thread_index, u32 limit, int do_flush)
951 {
952   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
953   nat_ipfix_per_thread_data_t *sitd = &silm->per_thread_data[thread_index];
954   flow_report_main_t *frm = &flow_report_main;
955   vlib_frame_t *f;
956   vlib_buffer_t *b0 = 0;
957   u32 bi0 = ~0;
958   u32 offset;
959   vlib_main_t *vm = vlib_get_main ();
960   u64 now;
961   u8 nat_event = QUOTA_EXCEEDED;
962   u32 quota_event = clib_host_to_net_u32 (MAX_BIB_ENTRIES);
963   u16 template_id;
964   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
965
966   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
967   now += silm->milisecond_time_0;
968
969   b0 = sitd->max_bibs_buffer;
970
971   if (PREDICT_FALSE (b0 == 0))
972     {
973       if (do_flush)
974         return;
975
976       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
977         {
978           //nat_elog_err ("can't allocate buffer for NAT IPFIX event");
979           return;
980         }
981
982       b0 = sitd->max_bibs_buffer = vlib_get_buffer (vm, bi0);
983       offset = 0;
984     }
985   else
986     {
987       bi0 = vlib_get_buffer_index (vm, b0);
988       offset = sitd->max_bibs_next_record_offset;
989     }
990
991   f = sitd->max_bibs_frame;
992   if (PREDICT_FALSE (f == 0))
993     {
994       u32 *to_next;
995       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
996       sitd->max_bibs_frame = f;
997       to_next = vlib_frame_vector_args (f);
998       to_next[0] = bi0;
999       f->n_vectors = 1;
1000     }
1001
1002   if (PREDICT_FALSE (offset == 0))
1003     nat_ipfix_header_create (frm, b0, &offset);
1004
1005   if (PREDICT_TRUE (do_flush == 0))
1006     {
1007       u64 time_stamp = clib_host_to_net_u64 (now);
1008       clib_memcpy_fast (b0->data + offset, &time_stamp, sizeof (time_stamp));
1009       offset += sizeof (time_stamp);
1010
1011       clib_memcpy_fast (b0->data + offset, &nat_event, sizeof (nat_event));
1012       offset += sizeof (nat_event);
1013
1014       clib_memcpy_fast (b0->data + offset, &quota_event, sizeof (quota_event));
1015       offset += sizeof (quota_event);
1016
1017       limit = clib_host_to_net_u32 (limit);
1018       clib_memcpy_fast (b0->data + offset, &limit, sizeof (limit));
1019       offset += sizeof (limit);
1020
1021       b0->current_length += MAX_BIBS_LEN;
1022     }
1023
1024   if (PREDICT_FALSE (do_flush || (offset + MAX_BIBS_LEN) > exp->path_mtu))
1025     {
1026       template_id = clib_atomic_fetch_or (
1027         &silm->max_bibs_template_id,
1028         0);
1029       nat_ipfix_send (frm, f, b0, template_id);
1030       sitd->max_bibs_frame = 0;
1031       sitd->max_bibs_buffer = 0;
1032       offset = 0;
1033     }
1034   sitd->max_bibs_next_record_offset = offset;
1035 }
1036
1037 static void
1038 nat_ipfix_logging_nat64_bibe (u32 thread_index, u8 nat_event,
1039                               ip6_address_t * src_ip, u32 nat_src_ip,
1040                               u8 proto, u16 src_port, u16 nat_src_port,
1041                               u32 vrf_id, int do_flush)
1042 {
1043   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
1044   nat_ipfix_per_thread_data_t *sitd = &silm->per_thread_data[thread_index];
1045   flow_report_main_t *frm = &flow_report_main;
1046   vlib_frame_t *f;
1047   vlib_buffer_t *b0 = 0;
1048   u32 bi0 = ~0;
1049   u32 offset;
1050   vlib_main_t *vm = vlib_get_main ();
1051   u64 now;
1052   u16 template_id;
1053   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
1054
1055   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
1056   now += silm->milisecond_time_0;
1057
1058   b0 = sitd->nat64_bib_buffer;
1059
1060   if (PREDICT_FALSE (b0 == 0))
1061     {
1062       if (do_flush)
1063         return;
1064
1065       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
1066         {
1067           //nat_elog_err ("can't allocate buffer for NAT IPFIX event");
1068           return;
1069         }
1070
1071       b0 = sitd->nat64_bib_buffer = vlib_get_buffer (vm, bi0);
1072       offset = 0;
1073     }
1074   else
1075     {
1076       bi0 = vlib_get_buffer_index (vm, b0);
1077       offset = sitd->nat64_bib_next_record_offset;
1078     }
1079
1080   f = sitd->nat64_bib_frame;
1081   if (PREDICT_FALSE (f == 0))
1082     {
1083       u32 *to_next;
1084       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
1085       sitd->nat64_bib_frame = f;
1086       to_next = vlib_frame_vector_args (f);
1087       to_next[0] = bi0;
1088       f->n_vectors = 1;
1089     }
1090
1091   if (PREDICT_FALSE (offset == 0))
1092     nat_ipfix_header_create (frm, b0, &offset);
1093
1094   if (PREDICT_TRUE (do_flush == 0))
1095     {
1096       u64 time_stamp = clib_host_to_net_u64 (now);
1097       clib_memcpy_fast (b0->data + offset, &time_stamp, sizeof (time_stamp));
1098       offset += sizeof (time_stamp);
1099
1100       clib_memcpy_fast (b0->data + offset, &nat_event, sizeof (nat_event));
1101       offset += sizeof (nat_event);
1102
1103       clib_memcpy_fast (b0->data + offset, src_ip, sizeof (ip6_address_t));
1104       offset += sizeof (ip6_address_t);
1105
1106       clib_memcpy_fast (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip));
1107       offset += sizeof (nat_src_ip);
1108
1109       clib_memcpy_fast (b0->data + offset, &proto, sizeof (proto));
1110       offset += sizeof (proto);
1111
1112       clib_memcpy_fast (b0->data + offset, &src_port, sizeof (src_port));
1113       offset += sizeof (src_port);
1114
1115       clib_memcpy_fast (b0->data + offset, &nat_src_port, sizeof (nat_src_port));
1116       offset += sizeof (nat_src_port);
1117
1118       vrf_id = clib_host_to_net_u32 (vrf_id);
1119       clib_memcpy_fast (b0->data + offset, &vrf_id, sizeof (vrf_id));
1120       offset += sizeof (vrf_id);
1121
1122       b0->current_length += NAT64_BIB_LEN;
1123     }
1124
1125   if (PREDICT_FALSE (do_flush || (offset + NAT64_BIB_LEN) > exp->path_mtu))
1126     {
1127       template_id = clib_atomic_fetch_or (
1128         &silm->nat64_bib_template_id,
1129         0);
1130       nat_ipfix_send (frm, f, b0, template_id);
1131       sitd->nat64_bib_frame = 0;
1132       sitd->nat64_bib_buffer = 0;
1133       offset = 0;
1134     }
1135   sitd->nat64_bib_next_record_offset = offset;
1136 }
1137
1138 static void
1139 nat_ipfix_logging_nat64_ses (u32 thread_index, u8 nat_event,
1140                              ip6_address_t * src_ip, u32 nat_src_ip,
1141                              u8 proto, u16 src_port, u16 nat_src_port,
1142                              ip6_address_t * dst_ip, u32 nat_dst_ip,
1143                              u16 dst_port, u16 nat_dst_port,
1144                              u32 vrf_id, int do_flush)
1145 {
1146   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
1147   nat_ipfix_per_thread_data_t *sitd = &silm->per_thread_data[thread_index];
1148   flow_report_main_t *frm = &flow_report_main;
1149   vlib_frame_t *f;
1150   vlib_buffer_t *b0 = 0;
1151   u32 bi0 = ~0;
1152   u32 offset;
1153   vlib_main_t *vm = vlib_get_main ();
1154   u64 now;
1155   u16 template_id;
1156   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
1157
1158   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
1159   now += silm->milisecond_time_0;
1160
1161   b0 = sitd->nat64_ses_buffer;
1162
1163   if (PREDICT_FALSE (b0 == 0))
1164     {
1165       if (do_flush)
1166         return;
1167
1168       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
1169         {
1170           //nat_elog_err ("can't allocate buffer for NAT IPFIX event");
1171           return;
1172         }
1173
1174       b0 = sitd->nat64_ses_buffer = vlib_get_buffer (vm, bi0);
1175       offset = 0;
1176     }
1177   else
1178     {
1179       bi0 = vlib_get_buffer_index (vm, b0);
1180       offset = sitd->nat64_ses_next_record_offset;
1181     }
1182
1183   f = sitd->nat64_ses_frame;
1184   if (PREDICT_FALSE (f == 0))
1185     {
1186       u32 *to_next;
1187       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
1188       sitd->nat64_ses_frame = f;
1189       to_next = vlib_frame_vector_args (f);
1190       to_next[0] = bi0;
1191       f->n_vectors = 1;
1192     }
1193
1194   if (PREDICT_FALSE (offset == 0))
1195     nat_ipfix_header_create (frm, b0, &offset);
1196
1197   if (PREDICT_TRUE (do_flush == 0))
1198     {
1199       u64 time_stamp = clib_host_to_net_u64 (now);
1200       clib_memcpy_fast (b0->data + offset, &time_stamp, sizeof (time_stamp));
1201       offset += sizeof (time_stamp);
1202
1203       clib_memcpy_fast (b0->data + offset, &nat_event, sizeof (nat_event));
1204       offset += sizeof (nat_event);
1205
1206       clib_memcpy_fast (b0->data + offset, src_ip, sizeof (ip6_address_t));
1207       offset += sizeof (ip6_address_t);
1208
1209       clib_memcpy_fast (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip));
1210       offset += sizeof (nat_src_ip);
1211
1212       clib_memcpy_fast (b0->data + offset, &proto, sizeof (proto));
1213       offset += sizeof (proto);
1214
1215       clib_memcpy_fast (b0->data + offset, &src_port, sizeof (src_port));
1216       offset += sizeof (src_port);
1217
1218       clib_memcpy_fast (b0->data + offset, &nat_src_port, sizeof (nat_src_port));
1219       offset += sizeof (nat_src_port);
1220
1221       clib_memcpy_fast (b0->data + offset, dst_ip, sizeof (ip6_address_t));
1222       offset += sizeof (ip6_address_t);
1223
1224       clib_memcpy_fast (b0->data + offset, &nat_dst_ip, sizeof (nat_dst_ip));
1225       offset += sizeof (nat_dst_ip);
1226
1227       clib_memcpy_fast (b0->data + offset, &dst_port, sizeof (dst_port));
1228       offset += sizeof (dst_port);
1229
1230       clib_memcpy_fast (b0->data + offset, &nat_dst_port, sizeof (nat_dst_port));
1231       offset += sizeof (nat_dst_port);
1232
1233       vrf_id = clib_host_to_net_u32 (vrf_id);
1234       clib_memcpy_fast (b0->data + offset, &vrf_id, sizeof (vrf_id));
1235       offset += sizeof (vrf_id);
1236
1237       b0->current_length += NAT64_SES_LEN;
1238     }
1239
1240   if (PREDICT_FALSE (do_flush || (offset + NAT64_SES_LEN) > exp->path_mtu))
1241     {
1242       template_id = clib_atomic_fetch_or (
1243         &silm->nat64_ses_template_id,
1244         0);
1245       nat_ipfix_send (frm, f, b0, template_id);
1246       sitd->nat64_ses_frame = 0;
1247       sitd->nat64_ses_buffer = 0;
1248       offset = 0;
1249     }
1250   sitd->nat64_ses_next_record_offset = offset;
1251 }
1252
1253 void
1254 nat_ipfix_flush (u32 thread_index)
1255 {
1256   int do_flush = 1;
1257
1258   nat_ipfix_logging_nat44_ses (thread_index,
1259                                 0, 0, 0, 0, 0, 0, 0, do_flush);
1260   nat_ipfix_logging_addr_exhausted (thread_index, 0, do_flush);
1261   nat_ipfix_logging_max_entries_per_usr (thread_index, 0, 0, do_flush);
1262   nat_ipfix_logging_max_ses (thread_index, 0, do_flush);
1263   nat_ipfix_logging_max_bib (thread_index, 0, do_flush);
1264   nat_ipfix_logging_nat64_bibe (thread_index,
1265                                 0, 0, 0, 0, 0, 0, 0, do_flush);
1266   nat_ipfix_logging_nat64_ses (thread_index,
1267                                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, do_flush);
1268 }
1269
1270 int
1271 nat_ipfix_logging_enabled ()
1272 {
1273   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
1274   return !clib_atomic_fetch_or(&silm->enabled, 0);
1275 }
1276
1277 void
1278 nat_ipfix_flush_from_main (void)
1279 {
1280   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
1281   vlib_main_t *worker_vm;
1282   int i;
1283
1284   if (PREDICT_TRUE (!clib_atomic_fetch_or(&silm->enabled, 0)))
1285     return;
1286
1287   if (PREDICT_FALSE (!silm->worker_vms))
1288     {
1289       for (i = 1; i < vlib_get_n_threads (); i++)
1290         {
1291           worker_vm = vlib_get_main_by_index (i);
1292           if (worker_vm)
1293             vec_add1 (silm->worker_vms, worker_vm);
1294         }
1295     }
1296
1297   /* Trigger flush for each worker thread */
1298   for (i = 0; i < vec_len (silm->worker_vms); i++)
1299     {
1300       worker_vm = silm->worker_vms[i];
1301       if (worker_vm)
1302         vlib_node_set_interrupt_pending (worker_vm,
1303                                          nat_ipfix_flush_node.index);
1304     }
1305
1306   /* Finally flush main thread */
1307   nat_ipfix_flush (0);
1308 }
1309
1310 /**
1311  * @brief Generate NAT44 session create event
1312  */
1313 void
1314 nat_ipfix_logging_nat44_ses_create (u32 thread_index, u32 src_ip,
1315                                     u32 nat_src_ip, ip_protocol_t proto,
1316                                     u16 src_port, u16 nat_src_port,
1317                                     u32 fib_index)
1318 {
1319   skip_if_disabled ();
1320
1321   nat_ipfix_logging_nat44_ses (thread_index, NAT44_SESSION_CREATE, src_ip,
1322                                nat_src_ip, proto, src_port, nat_src_port,
1323                                fib_index, 0);
1324 }
1325
1326 /**
1327  * @brief Generate NAT44 session delete event
1328  */
1329 void
1330 nat_ipfix_logging_nat44_ses_delete (u32 thread_index, u32 src_ip,
1331                                     u32 nat_src_ip, ip_protocol_t proto,
1332                                     u16 src_port, u16 nat_src_port,
1333                                     u32 fib_index)
1334 {
1335   skip_if_disabled ();
1336
1337   nat_ipfix_logging_nat44_ses (thread_index, NAT44_SESSION_DELETE, src_ip,
1338                                nat_src_ip, proto, src_port, nat_src_port,
1339                                fib_index, 0);
1340 }
1341
1342 /**
1343  * @brief Generate NAT addresses exhausted event
1344  *
1345  * @param thread_index thread index
1346  * @param pool_id NAT pool ID
1347  */
1348 void
1349 nat_ipfix_logging_addresses_exhausted (u32 thread_index, u32 pool_id)
1350 {
1351   //TODO: This event SHOULD be rate limited
1352   skip_if_disabled ();
1353
1354   nat_ipfix_logging_addr_exhausted (thread_index, pool_id, 0);
1355 }
1356
1357 /**
1358  * @brief Generate maximum entries per user exceeded event
1359  *
1360  * @param thread_index thread index
1361  * @param limit maximum NAT entries that can be created per user
1362  * @param src_ip source IPv4 address
1363  */
1364 void
1365 nat_ipfix_logging_max_entries_per_user (u32 thread_index, u32 limit, u32 src_ip)
1366 {
1367   //TODO: This event SHOULD be rate limited
1368   skip_if_disabled ();
1369
1370   nat_ipfix_logging_max_entries_per_usr (thread_index, limit, src_ip, 0);
1371 }
1372
1373 vlib_frame_t *
1374 deterministic_nat_data_callback
1375 (flow_report_main_t * frm,
1376                                         flow_report_t * fr,
1377                                         vlib_frame_t * f,
1378                                         u32 * to_next, u32 node_index)
1379 {
1380   nat_ipfix_flush_from_main();
1381
1382   return f;
1383 }
1384
1385 /**
1386  * @brief Generate maximum session entries exceeded event
1387  *
1388  * @param thread_index thread index
1389  * @param limit configured limit
1390  */
1391 void
1392 nat_ipfix_logging_max_sessions (u32 thread_index, u32 limit)
1393 {
1394   //TODO: This event SHOULD be rate limited
1395   skip_if_disabled ();
1396
1397   nat_ipfix_logging_max_ses (thread_index, limit, 0);
1398 }
1399
1400 /**
1401  * @brief Generate maximum BIB entries exceeded event
1402  *
1403  * @param thread_index thread index
1404  * @param limit configured limit
1405  */
1406 void
1407 nat_ipfix_logging_max_bibs (u32 thread_index, u32 limit)
1408 {
1409   //TODO: This event SHOULD be rate limited
1410   skip_if_disabled ();
1411
1412   nat_ipfix_logging_max_bib (thread_index, limit, 0);
1413 }
1414
1415 /**
1416  * @brief Generate NAT64 BIB create and delete events
1417  *
1418  * @param thread_index thread index
1419  * @param src_ip       source IPv6 address
1420  * @param nat_src_ip   transaltes source IPv4 address
1421  * @param proto        L4 protocol
1422  * @param src_port     source port
1423  * @param nat_src_port translated source port
1424  * @param vrf_id       VRF ID
1425  * @param is_create    non-zero value if create event otherwise delete event
1426  */
1427 void
1428 nat_ipfix_logging_nat64_bib (u32 thread_index, ip6_address_t * src_ip,
1429                              ip4_address_t * nat_src_ip, u8 proto,
1430                              u16 src_port, u16 nat_src_port, u32 vrf_id,
1431                              u8 is_create)
1432 {
1433   u8 nat_event;
1434
1435   skip_if_disabled ();
1436
1437   nat_event = is_create ? NAT64_BIB_CREATE : NAT64_BIB_DELETE;
1438
1439   nat_ipfix_logging_nat64_bibe (thread_index, nat_event, src_ip,
1440                                 nat_src_ip->as_u32, proto, src_port,
1441                                 nat_src_port, vrf_id, 0);
1442 }
1443
1444 /**
1445  * @brief Generate NAT64 session create and delete events
1446  *
1447  * @param thread_index thread index
1448  * @param src_ip       source IPv6 address
1449  * @param nat_src_ip   transaltes source IPv4 address
1450  * @param proto        L4 protocol
1451  * @param src_port     source port
1452  * @param nat_src_port translated source port
1453  * @param dst_ip       destination IPv6 address
1454  * @param nat_dst_ip   destination IPv4 address
1455  * @param dst_port     destination port
1456  * @param nat_dst_port translated destination port
1457  * @param vrf_id       VRF ID
1458  * @param is_create    non-zero value if create event otherwise delete event
1459  */
1460 void
1461 nat_ipfix_logging_nat64_session (u32 thread_index,
1462                                  ip6_address_t * src_ip,
1463                                  ip4_address_t * nat_src_ip, u8 proto,
1464                                  u16 src_port, u16 nat_src_port,
1465                                  ip6_address_t * dst_ip,
1466                                  ip4_address_t * nat_dst_ip, u16 dst_port,
1467                                  u16 nat_dst_port, u32 vrf_id, u8 is_create)
1468 {
1469   u8 nat_event;
1470
1471   skip_if_disabled ();
1472
1473   nat_event = is_create ? NAT64_SESSION_CREATE : NAT64_SESSION_DELETE;
1474
1475   nat_ipfix_logging_nat64_ses (thread_index, nat_event, src_ip,
1476                                nat_src_ip->as_u32, proto, src_port,
1477                                nat_src_port, dst_ip, nat_dst_ip->as_u32,
1478                                dst_port, nat_dst_port, vrf_id, 0);
1479 }
1480
1481 vlib_frame_t *
1482 data_callback (flow_report_main_t * frm, flow_report_t * fr,
1483                vlib_frame_t * f, u32 * to_next, u32 node_index)
1484 {
1485   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
1486   ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
1487
1488   if (PREDICT_FALSE (++silm->call_counter >= vec_len (exp->reports)))
1489     {
1490       nat_ipfix_flush_from_main();
1491       silm->call_counter = 0;
1492     }
1493
1494   return f;
1495 }
1496
1497 /**
1498  * @brief Enable/disable NAT plugin IPFIX logging
1499  *
1500  * @param enable    1 if enable, 0 if disable
1501  * @param domain_id observation domain ID
1502  * @param src_port  source port number
1503  *
1504  * @returns 0 if success
1505  */
1506 int
1507 nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port)
1508 {
1509   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
1510   flow_report_main_t *frm = &flow_report_main;
1511   vnet_flow_report_add_del_args_t a;
1512   int rv;
1513   u8 e = enable ? 1 : 0;
1514
1515   if (clib_atomic_cmp_and_swap (&silm->enabled, e ^ 1, e) == e)
1516     return 0;
1517
1518   clib_memset (&a, 0, sizeof (a));
1519   a.is_add = enable;
1520   a.domain_id = domain_id ? domain_id : 1;
1521   a.src_port = src_port ? src_port : UDP_DST_PORT_ipfix;
1522   a.flow_data_callback = data_callback;
1523
1524   a.rewrite_callback = nat_template_rewrite_nat44_session;
1525   rv = vnet_flow_report_add_del (frm, &a, NULL);
1526   if (rv)
1527     {
1528       //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv);
1529       return -1;
1530     }
1531
1532   a.rewrite_callback = nat_template_rewrite_addr_exhausted;
1533   rv = vnet_flow_report_add_del (frm, &a, NULL);
1534   if (rv)
1535     {
1536       //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv);
1537       return -1;
1538     }
1539
1540   a.rewrite_callback = nat_template_rewrite_max_sessions;
1541   rv = vnet_flow_report_add_del (frm, &a, NULL);
1542   if (rv)
1543     {
1544       //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv);
1545       return -1;
1546     }
1547
1548   a.rewrite_callback = nat_template_rewrite_max_bibs;
1549   rv = vnet_flow_report_add_del (frm, &a, NULL);
1550   if (rv)
1551     {
1552       //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv);
1553       return -1;
1554     }
1555
1556   a.rewrite_callback = nat_template_rewrite_nat64_bib;
1557   rv = vnet_flow_report_add_del (frm, &a, NULL);
1558   if (rv)
1559     {
1560       //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv);
1561       return -1;
1562     }
1563
1564   a.rewrite_callback = nat_template_rewrite_nat64_session;
1565   rv = vnet_flow_report_add_del (frm, &a, NULL);
1566   if (rv)
1567     {
1568       //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv);
1569       return -1;
1570     }
1571
1572   // if endpoint dependent per user max entries is also required
1573   /*
1574   a.rewrite_callback = nat_template_rewrite_max_entries_per_usr;
1575   rv = vnet_flow_report_add_del (frm, &a, NULL);
1576   if (rv)
1577     {
1578       //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv);
1579       return -1;
1580     }
1581   */
1582
1583   return 0;
1584 }
1585
1586 /**
1587  * @brief Initialize NAT plugin IPFIX logging
1588  *
1589  * @param vm vlib main
1590  */
1591 void
1592 nat_ipfix_logging_init (vlib_main_t * vm)
1593 {
1594   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
1595   vlib_thread_main_t *tm = vlib_get_thread_main ();
1596
1597   silm->enabled = 0;
1598   silm->worker_vms = 0;
1599   silm->call_counter = 0;
1600
1601   /* Set up time reference pair */
1602   silm->vlib_time_0 = vlib_time_now (vm);
1603   silm->milisecond_time_0 = unix_time_now_nsec () * 1e-6;
1604
1605   vec_validate (silm->per_thread_data, tm->n_vlib_mains - 1);
1606 }
1607
1608 static uword
1609 ipfix_flush_process (vlib_main_t *vm,
1610                      vlib_node_runtime_t *rt,
1611                      vlib_frame_t *f)
1612 {
1613   nat_ipfix_flush(vm->thread_index);
1614   return 0;
1615 }
1616
1617 /* *INDENT-OFF* */
1618 VLIB_REGISTER_NODE (nat_ipfix_flush_node) = {
1619   .function = ipfix_flush_process,
1620   .name = "nat-ipfix-flush",
1621   .type = VLIB_NODE_TYPE_INPUT,
1622   .state = VLIB_NODE_STATE_INTERRUPT,
1623 };
1624 /* *INDENT-ON* */