NAT: don't call ipfix rpc when disabled (VPP-988)
[vpp.git] / src / plugins / nat / nat_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/flow/flow_report.h>
19 #include <vlibmemory/api.h>
20 #include <nat/nat.h>
21 #include <nat/nat_ipfix_logging.h>
22
23 snat_ipfix_logging_main_t snat_ipfix_logging_main;
24
25 #define NAT44_SESSION_CREATE_LEN 26
26 #define NAT_ADDRESSES_EXHAUTED_LEN 13
27 #define MAX_ENTRIES_PER_USER_LEN 17
28
29 #define NAT44_SESSION_CREATE_FIELD_COUNT 8
30 #define NAT_ADDRESSES_EXHAUTED_FIELD_COUNT 3
31 #define MAX_ENTRIES_PER_USER_FIELD_COUNT 4
32
33 typedef struct
34 {
35   u8 nat_event;
36   u32 src_ip;
37   u32 nat_src_ip;
38   snat_protocol_t snat_proto;
39   u16 src_port;
40   u16 nat_src_port;
41   u32 vrf_id;
42 } snat_ipfix_logging_nat44_ses_args_t;
43
44 typedef struct
45 {
46   u32 pool_id;
47 } snat_ipfix_logging_addr_exhausted_args_t;
48
49 typedef struct
50 {
51   u32 src_ip;
52 } snat_ipfix_logging_max_entries_per_user_args_t;
53
54 #define skip_if_disabled()                                    \
55 do {                                                          \
56   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main; \
57   if (PREDICT_TRUE (!silm->enabled))                          \
58     return;                                                   \
59 } while (0)
60
61 /**
62  * @brief Create an IPFIX template packet rewrite string
63  *
64  * @param frm               flow report main
65  * @param fr                flow report
66  * @param collector_address collector address
67  * @param src_address       source address
68  * @param collector_port    collector
69  * @param event             NAT event ID
70  * @param quota_event       NAT quota exceeded event ID
71  *
72  * @returns template packet
73  */
74 static inline u8 *
75 snat_template_rewrite (flow_report_main_t * frm,
76                        flow_report_t * fr,
77                        ip4_address_t * collector_address,
78                        ip4_address_t * src_address,
79                        u16 collector_port,
80                        nat_event_t event, quota_exceed_event_t quota_event)
81 {
82   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
83   ip4_header_t *ip;
84   udp_header_t *udp;
85   ipfix_message_header_t *h;
86   ipfix_set_header_t *s;
87   ipfix_template_header_t *t;
88   ipfix_field_specifier_t *f;
89   ipfix_field_specifier_t *first_field;
90   u8 *rewrite = 0;
91   ip4_ipfix_template_packet_t *tp;
92   u32 field_count = 0;
93   flow_report_stream_t *stream;
94
95   stream = &frm->streams[fr->stream_index];
96   silm->stream_index = fr->stream_index;
97
98   if (event == NAT_ADDRESSES_EXHAUTED)
99     {
100       field_count = NAT_ADDRESSES_EXHAUTED_FIELD_COUNT;
101       silm->addr_exhausted_template_id = fr->template_id;
102     }
103   else if (event == NAT44_SESSION_CREATE)
104     {
105       field_count = NAT44_SESSION_CREATE_FIELD_COUNT;
106       silm->nat44_session_template_id = fr->template_id;
107     }
108   else if (event == QUOTA_EXCEEDED)
109     {
110       if (quota_event == MAX_ENTRIES_PER_USER)
111         {
112           field_count = MAX_ENTRIES_PER_USER_FIELD_COUNT;
113           silm->max_entries_per_user_template_id = fr->template_id;
114         }
115     }
116
117   /* allocate rewrite space */
118   vec_validate_aligned (rewrite,
119                         sizeof (ip4_ipfix_template_packet_t)
120                         + field_count * sizeof (ipfix_field_specifier_t) - 1,
121                         CLIB_CACHE_LINE_BYTES);
122
123   tp = (ip4_ipfix_template_packet_t *) rewrite;
124   ip = (ip4_header_t *) & tp->ip4;
125   udp = (udp_header_t *) (ip + 1);
126   h = (ipfix_message_header_t *) (udp + 1);
127   s = (ipfix_set_header_t *) (h + 1);
128   t = (ipfix_template_header_t *) (s + 1);
129   first_field = f = (ipfix_field_specifier_t *) (t + 1);
130
131   ip->ip_version_and_header_length = 0x45;
132   ip->ttl = 254;
133   ip->protocol = IP_PROTOCOL_UDP;
134   ip->src_address.as_u32 = src_address->as_u32;
135   ip->dst_address.as_u32 = collector_address->as_u32;
136   udp->src_port = clib_host_to_net_u16 (stream->src_port);
137   udp->dst_port = clib_host_to_net_u16 (collector_port);
138   udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
139
140   /* FIXUP: message header export_time */
141   h->domain_id = clib_host_to_net_u32 (stream->domain_id);
142
143   /* Add TLVs to the template */
144   if (event == NAT_ADDRESSES_EXHAUTED)
145     {
146       f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
147       f++;
148       f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
149       f++;
150       f->e_id_length = ipfix_e_id_length (0, natPoolId, 4);
151       f++;
152     }
153   else if (event == NAT44_SESSION_CREATE)
154     {
155       f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
156       f++;
157       f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
158       f++;
159       f->e_id_length = ipfix_e_id_length (0, sourceIPv4Address, 4);
160       f++;
161       f->e_id_length = ipfix_e_id_length (0, postNATSourceIPv4Address, 4);
162       f++;
163       f->e_id_length = ipfix_e_id_length (0, protocolIdentifier, 1);
164       f++;
165       f->e_id_length = ipfix_e_id_length (0, sourceTransportPort, 2);
166       f++;
167       f->e_id_length = ipfix_e_id_length (0, postNAPTSourceTransportPort, 2);
168       f++;
169       f->e_id_length = ipfix_e_id_length (0, ingressVRFID, 4);
170       f++;
171     }
172   else if (event == QUOTA_EXCEEDED)
173     {
174       if (quota_event == MAX_ENTRIES_PER_USER)
175         {
176           f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds,
177                                               8);
178           f++;
179           f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
180           f++;
181           f->e_id_length = ipfix_e_id_length (0, natQuotaExceededEvent, 4);
182           f++;
183           f->e_id_length = ipfix_e_id_length (0, sourceIPv4Address, 4);
184           f++;
185         }
186     }
187
188   /* Back to the template packet... */
189   ip = (ip4_header_t *) & tp->ip4;
190   udp = (udp_header_t *) (ip + 1);
191
192   ASSERT (f - first_field);
193   /* Field count in this template */
194   t->id_count = ipfix_id_count (fr->template_id, f - first_field);
195
196   /* set length in octets */
197   s->set_id_length =
198     ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
199
200   /* message length in octets */
201   h->version_length = version_length ((u8 *) f - (u8 *) h);
202
203   ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
204   ip->checksum = ip4_header_checksum (ip);
205
206   return rewrite;
207 }
208
209 u8 *
210 snat_template_rewrite_addr_exhausted (flow_report_main_t * frm,
211                                       flow_report_t * fr,
212                                       ip4_address_t * collector_address,
213                                       ip4_address_t * src_address,
214                                       u16 collector_port)
215 {
216   return snat_template_rewrite (frm, fr, collector_address, src_address,
217                                 collector_port, NAT_ADDRESSES_EXHAUTED, 0);
218 }
219
220 u8 *
221 snat_template_rewrite_nat44_session (flow_report_main_t * frm,
222                                      flow_report_t * fr,
223                                      ip4_address_t * collector_address,
224                                      ip4_address_t * src_address,
225                                      u16 collector_port)
226 {
227   return snat_template_rewrite (frm, fr, collector_address, src_address,
228                                 collector_port, NAT44_SESSION_CREATE, 0);
229 }
230
231 u8 *
232 snat_template_rewrite_max_entries_per_usr (flow_report_main_t * frm,
233                                            flow_report_t * fr,
234                                            ip4_address_t * collector_address,
235                                            ip4_address_t * src_address,
236                                            u16 collector_port)
237 {
238   return snat_template_rewrite (frm, fr, collector_address, src_address,
239                                 collector_port, QUOTA_EXCEEDED,
240                                 MAX_ENTRIES_PER_USER);
241 }
242
243 static inline void
244 snat_ipfix_header_create (flow_report_main_t * frm,
245                           vlib_buffer_t * b0, u32 * offset)
246 {
247   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
248   flow_report_stream_t *stream;
249   ip4_ipfix_template_packet_t *tp;
250   ipfix_message_header_t *h = 0;
251   ipfix_set_header_t *s = 0;
252   ip4_header_t *ip;
253   udp_header_t *udp;
254
255   stream = &frm->streams[silm->stream_index];
256
257   b0->current_data = 0;
258   b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) +
259     sizeof (*s);
260   b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT);
261   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
262   vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index;
263   tp = vlib_buffer_get_current (b0);
264   ip = (ip4_header_t *) & tp->ip4;
265   udp = (udp_header_t *) (ip + 1);
266   h = (ipfix_message_header_t *) (udp + 1);
267   s = (ipfix_set_header_t *) (h + 1);
268
269   ip->ip_version_and_header_length = 0x45;
270   ip->ttl = 254;
271   ip->protocol = IP_PROTOCOL_UDP;
272   ip->flags_and_fragment_offset = 0;
273   ip->src_address.as_u32 = frm->src_address.as_u32;
274   ip->dst_address.as_u32 = frm->ipfix_collector.as_u32;
275   udp->src_port = clib_host_to_net_u16 (stream->src_port);
276   udp->dst_port = clib_host_to_net_u16 (frm->collector_port);
277   udp->checksum = 0;
278
279   h->export_time = clib_host_to_net_u32 ((u32)
280                                          (((f64) frm->unix_time_0) +
281                                           (vlib_time_now (frm->vlib_main) -
282                                            frm->vlib_time_0)));
283   h->sequence_number = clib_host_to_net_u32 (stream->sequence_number++);
284   h->domain_id = clib_host_to_net_u32 (stream->domain_id);
285
286   *offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp);
287 }
288
289 static inline void
290 snat_ipfix_send (flow_report_main_t * frm,
291                  vlib_frame_t * f, vlib_buffer_t * b0, u16 template_id)
292 {
293   ip4_ipfix_template_packet_t *tp;
294   ipfix_message_header_t *h = 0;
295   ipfix_set_header_t *s = 0;
296   ip4_header_t *ip;
297   udp_header_t *udp;
298   vlib_main_t *vm = frm->vlib_main;
299
300   tp = vlib_buffer_get_current (b0);
301   ip = (ip4_header_t *) & tp->ip4;
302   udp = (udp_header_t *) (ip + 1);
303   h = (ipfix_message_header_t *) (udp + 1);
304   s = (ipfix_set_header_t *) (h + 1);
305
306   s->set_id_length = ipfix_set_id_length (template_id,
307                                           b0->current_length -
308                                           (sizeof (*ip) + sizeof (*udp) +
309                                            sizeof (*h)));
310   h->version_length = version_length (b0->current_length -
311                                       (sizeof (*ip) + sizeof (*udp)));
312
313   ip->length = clib_host_to_net_u16 (b0->current_length);
314   ip->checksum = ip4_header_checksum (ip);
315   udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
316
317   if (frm->udp_checksum)
318     {
319       udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
320       if (udp->checksum == 0)
321         udp->checksum = 0xffff;
322     }
323
324   ASSERT (ip->checksum == ip4_header_checksum (ip));
325
326   vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
327 }
328
329 static void
330 snat_ipfix_logging_nat44_ses (u8 nat_event, u32 src_ip, u32 nat_src_ip,
331                               snat_protocol_t snat_proto, u16 src_port,
332                               u16 nat_src_port, u32 vrf_id, int do_flush)
333 {
334   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
335   flow_report_main_t *frm = &flow_report_main;
336   vlib_frame_t *f;
337   vlib_buffer_t *b0 = 0;
338   u32 bi0 = ~0;
339   u32 offset;
340   vlib_main_t *vm = frm->vlib_main;
341   u64 now;
342   vlib_buffer_free_list_t *fl;
343   u8 proto = ~0;
344
345   if (!silm->enabled)
346     return;
347
348   proto = snat_proto_to_ip_proto (snat_proto);
349
350   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
351   now += silm->milisecond_time_0;
352
353   b0 = silm->nat44_session_buffer;
354
355   if (PREDICT_FALSE (b0 == 0))
356     {
357       if (do_flush)
358         return;
359
360       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
361         {
362           clib_warning ("can't allocate buffer for NAT IPFIX event");
363           return;
364         }
365
366       b0 = silm->nat44_session_buffer = vlib_get_buffer (vm, bi0);
367       fl =
368         vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
369       vlib_buffer_init_for_free_list (b0, fl);
370       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
371       offset = 0;
372     }
373   else
374     {
375       bi0 = vlib_get_buffer_index (vm, b0);
376       offset = silm->nat44_session_next_record_offset;
377     }
378
379   f = silm->nat44_session_frame;
380   if (PREDICT_FALSE (f == 0))
381     {
382       u32 *to_next;
383       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
384       silm->nat44_session_frame = f;
385       to_next = vlib_frame_vector_args (f);
386       to_next[0] = bi0;
387       f->n_vectors = 1;
388     }
389
390   if (PREDICT_FALSE (offset == 0))
391     snat_ipfix_header_create (frm, b0, &offset);
392
393   if (PREDICT_TRUE (do_flush == 0))
394     {
395       u64 time_stamp = clib_host_to_net_u64 (now);
396       clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
397       offset += sizeof (time_stamp);
398
399       clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
400       offset += sizeof (nat_event);
401
402       clib_memcpy (b0->data + offset, &src_ip, sizeof (src_ip));
403       offset += sizeof (src_ip);
404
405       clib_memcpy (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip));
406       offset += sizeof (nat_src_ip);
407
408       clib_memcpy (b0->data + offset, &proto, sizeof (proto));
409       offset += sizeof (proto);
410
411       clib_memcpy (b0->data + offset, &src_port, sizeof (src_port));
412       offset += sizeof (src_port);
413
414       clib_memcpy (b0->data + offset, &nat_src_port, sizeof (nat_src_port));
415       offset += sizeof (nat_src_port);
416
417       clib_memcpy (b0->data + offset, &vrf_id, sizeof (vrf_id));
418       offset += sizeof (vrf_id);
419
420       b0->current_length += NAT44_SESSION_CREATE_LEN;
421     }
422
423   if (PREDICT_FALSE
424       (do_flush || (offset + NAT44_SESSION_CREATE_LEN) > frm->path_mtu))
425     {
426       snat_ipfix_send (frm, f, b0, silm->nat44_session_template_id);
427       silm->nat44_session_frame = 0;
428       silm->nat44_session_buffer = 0;
429       offset = 0;
430     }
431   silm->nat44_session_next_record_offset = offset;
432 }
433
434 static void
435 snat_ipfix_logging_addr_exhausted (u32 pool_id, int do_flush)
436 {
437   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
438   flow_report_main_t *frm = &flow_report_main;
439   vlib_frame_t *f;
440   vlib_buffer_t *b0 = 0;
441   u32 bi0 = ~0;
442   u32 offset;
443   vlib_main_t *vm = frm->vlib_main;
444   u64 now;
445   vlib_buffer_free_list_t *fl;
446   u8 nat_event = NAT_ADDRESSES_EXHAUTED;
447
448   if (!silm->enabled)
449     return;
450
451   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
452   now += silm->milisecond_time_0;
453
454   b0 = silm->addr_exhausted_buffer;
455
456   if (PREDICT_FALSE (b0 == 0))
457     {
458       if (do_flush)
459         return;
460
461       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
462         {
463           clib_warning ("can't allocate buffer for NAT IPFIX event");
464           return;
465         }
466
467       b0 = silm->addr_exhausted_buffer = vlib_get_buffer (vm, bi0);
468       fl =
469         vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
470       vlib_buffer_init_for_free_list (b0, fl);
471       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
472       offset = 0;
473     }
474   else
475     {
476       bi0 = vlib_get_buffer_index (vm, b0);
477       offset = silm->addr_exhausted_next_record_offset;
478     }
479
480   f = silm->addr_exhausted_frame;
481   if (PREDICT_FALSE (f == 0))
482     {
483       u32 *to_next;
484       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
485       silm->addr_exhausted_frame = f;
486       to_next = vlib_frame_vector_args (f);
487       to_next[0] = bi0;
488       f->n_vectors = 1;
489     }
490
491   if (PREDICT_FALSE (offset == 0))
492     snat_ipfix_header_create (frm, b0, &offset);
493
494   if (PREDICT_TRUE (do_flush == 0))
495     {
496       u64 time_stamp = clib_host_to_net_u64 (now);
497       clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
498       offset += sizeof (time_stamp);
499
500       clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
501       offset += sizeof (nat_event);
502
503       clib_memcpy (b0->data + offset, &pool_id, sizeof (pool_id));
504       offset += sizeof (pool_id);
505
506       b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN;
507     }
508
509   if (PREDICT_FALSE
510       (do_flush || (offset + NAT_ADDRESSES_EXHAUTED_LEN) > frm->path_mtu))
511     {
512       snat_ipfix_send (frm, f, b0, silm->addr_exhausted_template_id);
513       silm->addr_exhausted_frame = 0;
514       silm->addr_exhausted_buffer = 0;
515       offset = 0;
516     }
517   silm->addr_exhausted_next_record_offset = offset;
518 }
519
520 static void
521 snat_ipfix_logging_max_entries_per_usr (u32 src_ip, int do_flush)
522 {
523   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
524   flow_report_main_t *frm = &flow_report_main;
525   vlib_frame_t *f;
526   vlib_buffer_t *b0 = 0;
527   u32 bi0 = ~0;
528   u32 offset;
529   vlib_main_t *vm = frm->vlib_main;
530   u64 now;
531   vlib_buffer_free_list_t *fl;
532   u8 nat_event = QUOTA_EXCEEDED;
533   u32 quota_event = MAX_ENTRIES_PER_USER;
534
535   if (!silm->enabled)
536     return;
537
538   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
539   now += silm->milisecond_time_0;
540
541   b0 = silm->max_entries_per_user_buffer;
542
543   if (PREDICT_FALSE (b0 == 0))
544     {
545       if (do_flush)
546         return;
547
548       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
549         {
550           clib_warning ("can't allocate buffer for NAT IPFIX event");
551           return;
552         }
553
554       b0 = silm->max_entries_per_user_buffer = vlib_get_buffer (vm, bi0);
555       fl =
556         vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
557       vlib_buffer_init_for_free_list (b0, fl);
558       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
559       offset = 0;
560     }
561   else
562     {
563       bi0 = vlib_get_buffer_index (vm, b0);
564       offset = silm->max_entries_per_user_next_record_offset;
565     }
566
567   f = silm->max_entries_per_user_frame;
568   if (PREDICT_FALSE (f == 0))
569     {
570       u32 *to_next;
571       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
572       silm->max_entries_per_user_frame = f;
573       to_next = vlib_frame_vector_args (f);
574       to_next[0] = bi0;
575       f->n_vectors = 1;
576     }
577
578   if (PREDICT_FALSE (offset == 0))
579     snat_ipfix_header_create (frm, b0, &offset);
580
581   if (PREDICT_TRUE (do_flush == 0))
582     {
583       u64 time_stamp = clib_host_to_net_u64 (now);
584       clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
585       offset += sizeof (time_stamp);
586
587       clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
588       offset += sizeof (nat_event);
589
590       clib_memcpy (b0->data + offset, &quota_event, sizeof (quota_event));
591       offset += sizeof (quota_event);
592
593       clib_memcpy (b0->data + offset, &src_ip, sizeof (src_ip));
594       offset += sizeof (src_ip);
595
596       b0->current_length += MAX_ENTRIES_PER_USER_LEN;
597     }
598
599   if (PREDICT_FALSE
600       (do_flush || (offset + MAX_ENTRIES_PER_USER_LEN) > frm->path_mtu))
601     {
602       snat_ipfix_send (frm, f, b0, silm->max_entries_per_user_template_id);
603       silm->max_entries_per_user_frame = 0;
604       silm->max_entries_per_user_buffer = 0;
605       offset = 0;
606     }
607   silm->max_entries_per_user_next_record_offset = offset;
608 }
609
610 static void
611 snat_ipfix_logging_nat44_ses_rpc_cb (snat_ipfix_logging_nat44_ses_args_t * a)
612 {
613   snat_ipfix_logging_nat44_ses (a->nat_event, a->src_ip, a->nat_src_ip,
614                                 a->snat_proto, a->src_port, a->nat_src_port,
615                                 a->vrf_id, 0);
616 }
617
618 /**
619  * @brief Generate NAT44 session create event
620  *
621  * @param src_ip       source IPv4 address
622  * @param nat_src_ip   transaltes source IPv4 address
623  * @param snat_proto   NAT transport protocol
624  * @param src_port     source port
625  * @param nat_src_port translated source port
626  * @param vrf_id       VRF ID
627  */
628 void
629 snat_ipfix_logging_nat44_ses_create (u32 src_ip,
630                                      u32 nat_src_ip,
631                                      snat_protocol_t snat_proto,
632                                      u16 src_port,
633                                      u16 nat_src_port, u32 vrf_id)
634 {
635   snat_ipfix_logging_nat44_ses_args_t a;
636
637   skip_if_disabled ();
638
639   a.nat_event = NAT44_SESSION_CREATE;
640   a.src_ip = src_ip;
641   a.nat_src_ip = nat_src_ip;
642   a.snat_proto = snat_proto;
643   a.src_port = src_port;
644   a.nat_src_port = nat_src_port;
645   a.vrf_id = vrf_id;
646
647   vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb,
648                                (u8 *) & a, sizeof (a));
649 }
650
651 /**
652  * @brief Generate NAT44 session delete event
653  *
654  * @param src_ip       source IPv4 address
655  * @param nat_src_ip   transaltes source IPv4 address
656  * @param snat_proto   NAT transport protocol
657  * @param src_port     source port
658  * @param nat_src_port translated source port
659  * @param vrf_id       VRF ID
660  */
661 void
662 snat_ipfix_logging_nat44_ses_delete (u32 src_ip,
663                                      u32 nat_src_ip,
664                                      snat_protocol_t snat_proto,
665                                      u16 src_port,
666                                      u16 nat_src_port, u32 vrf_id)
667 {
668   snat_ipfix_logging_nat44_ses_args_t a;
669
670   skip_if_disabled ();
671
672   a.nat_event = NAT44_SESSION_DELETE;
673   a.src_ip = src_ip;
674   a.nat_src_ip = nat_src_ip;
675   a.snat_proto = snat_proto;
676   a.src_port = src_port;
677   a.nat_src_port = nat_src_port;
678   a.vrf_id = vrf_id;
679
680   vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb,
681                                (u8 *) & a, sizeof (a));
682 }
683
684 vlib_frame_t *
685 snat_data_callback_nat44_session (flow_report_main_t * frm,
686                                   flow_report_t * fr,
687                                   vlib_frame_t * f,
688                                   u32 * to_next, u32 node_index)
689 {
690   snat_ipfix_logging_nat44_ses (0, 0, 0, 0, 0, 0, 0, 1);
691   return f;
692 }
693
694 static void
695   snat_ipfix_logging_addr_exhausted_rpc_cb
696   (snat_ipfix_logging_addr_exhausted_args_t * a)
697 {
698   snat_ipfix_logging_addr_exhausted (a->pool_id, 0);
699 }
700
701 /**
702  * @brief Generate NAT addresses exhausted event
703  *
704  * @param pool_id NAT pool ID
705  */
706 void
707 snat_ipfix_logging_addresses_exhausted (u32 pool_id)
708 {
709   //TODO: This event SHOULD be rate limited
710   snat_ipfix_logging_addr_exhausted_args_t a;
711
712   skip_if_disabled ();
713
714   a.pool_id = pool_id;
715
716   vl_api_rpc_call_main_thread (snat_ipfix_logging_addr_exhausted_rpc_cb,
717                                (u8 *) & a, sizeof (a));
718 }
719
720 vlib_frame_t *
721 snat_data_callback_addr_exhausted (flow_report_main_t * frm,
722                                    flow_report_t * fr,
723                                    vlib_frame_t * f,
724                                    u32 * to_next, u32 node_index)
725 {
726   snat_ipfix_logging_addr_exhausted (0, 1);
727   return f;
728 }
729
730 static void
731   snat_ipfix_logging_max_entries_per_usr_rpc_cb
732   (snat_ipfix_logging_max_entries_per_user_args_t * a)
733 {
734   snat_ipfix_logging_max_entries_per_usr (a->src_ip, 0);
735 }
736
737 /**
738  * @brief Generate maximum entries per user exceeded event
739  *
740  * @param src_ip source IPv4 address
741  */
742 void
743 snat_ipfix_logging_max_entries_per_user (u32 src_ip)
744 {
745   //TODO: This event SHOULD be rate limited
746   snat_ipfix_logging_max_entries_per_user_args_t a;
747
748   skip_if_disabled ();
749
750   a.src_ip = src_ip;
751
752   vl_api_rpc_call_main_thread (snat_ipfix_logging_max_entries_per_usr_rpc_cb,
753                                (u8 *) & a, sizeof (a));
754 }
755
756 vlib_frame_t *
757 snat_data_callback_max_entries_per_usr (flow_report_main_t * frm,
758                                         flow_report_t * fr,
759                                         vlib_frame_t * f,
760                                         u32 * to_next, u32 node_index)
761 {
762   snat_ipfix_logging_max_entries_per_usr (0, 1);
763   return f;
764 }
765
766 /**
767  * @brief Enable/disable NAT plugin IPFIX logging
768  *
769  * @param enable    1 if enable, 0 if disable
770  * @param domain_id observation domain ID
771  * @param src_port  source port number
772  *
773  * @returns 0 if success
774  */
775 int
776 snat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port)
777 {
778   snat_main_t *sm = &snat_main;
779   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
780   flow_report_main_t *frm = &flow_report_main;
781   vnet_flow_report_add_del_args_t a;
782   int rv;
783   u8 e = enable ? 1 : 0;
784
785   if (silm->enabled == e)
786     return 0;
787
788   silm->enabled = e;
789
790   memset (&a, 0, sizeof (a));
791   a.is_add = enable;
792   a.domain_id = domain_id ? domain_id : 1;
793   a.src_port = src_port ? src_port : UDP_DST_PORT_ipfix;
794
795   if (sm->deterministic)
796     {
797       a.rewrite_callback = snat_template_rewrite_max_entries_per_usr;
798       a.flow_data_callback = snat_data_callback_max_entries_per_usr;
799
800       rv = vnet_flow_report_add_del (frm, &a, NULL);
801       if (rv)
802         {
803           clib_warning ("vnet_flow_report_add_del returned %d", rv);
804           return -1;
805         }
806     }
807   else
808     {
809       a.rewrite_callback = snat_template_rewrite_nat44_session;
810       a.flow_data_callback = snat_data_callback_nat44_session;
811
812       rv = vnet_flow_report_add_del (frm, &a, NULL);
813       if (rv)
814         {
815           clib_warning ("vnet_flow_report_add_del returned %d", rv);
816           return -1;
817         }
818
819       a.rewrite_callback = snat_template_rewrite_addr_exhausted;
820       a.flow_data_callback = snat_data_callback_addr_exhausted;
821
822       rv = vnet_flow_report_add_del (frm, &a, NULL);
823       if (rv)
824         {
825           clib_warning ("vnet_flow_report_add_del returned %d", rv);
826           return -1;
827         }
828     }
829
830   return 0;
831 }
832
833 /**
834  * @brief Initialize NAT plugin IPFIX logging
835  *
836  * @param vm vlib main
837  */
838 void
839 snat_ipfix_logging_init (vlib_main_t * vm)
840 {
841   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
842
843   silm->enabled = 0;
844
845   /* Set up time reference pair */
846   silm->vlib_time_0 = vlib_time_now (vm);
847   silm->milisecond_time_0 = unix_time_now_nsec () * 1e-6;
848 }