SNAT: IPFIX logging (VPP-445)
[vpp.git] / src / plugins / snat / snat_ipfix_logging.c
1 /*
2  * snat_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 <snat/snat.h>
21 #include <snat/snat_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
28 #define NAT44_SESSION_CREATE_FIELD_COUNT 8
29 #define NAT_ADDRESSES_EXHAUTED_FIELD_COUNT 3
30
31 typedef struct {
32   u8 nat_event;
33   u32 src_ip;
34   u32 nat_src_ip;
35   snat_protocol_t snat_proto;
36   u16 src_port;
37   u16 nat_src_port;
38   u32 vrf_id;
39 } snat_ipfix_logging_nat44_ses_args_t;
40
41 typedef struct {
42   u32 pool_id;
43 } snat_ipfix_logging_addr_exhausted_args_t;
44
45 /**
46  * @brief Create an IPFIX template packet rewrite string
47  *
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
54  *
55  * @returns template packet
56  */
57 static inline u8 *
58 snat_template_rewrite (flow_report_main_t * frm,
59                        flow_report_t * fr,
60                        ip4_address_t * collector_address,
61                        ip4_address_t * src_address,
62                        u16 collector_port,
63                        nat_event_t event)
64 {
65   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
66   ip4_header_t *ip;
67   udp_header_t *udp;
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;
73   u8 *rewrite = 0;
74   ip4_ipfix_template_packet_t *tp;
75   u32 field_count = 0;
76   flow_report_stream_t *stream;
77
78   stream = &frm->streams[fr->stream_index];
79   silm->stream_index = fr->stream_index;
80
81   if (event == NAT_ADDRESSES_EXHAUTED)
82     {
83       field_count = NAT_ADDRESSES_EXHAUTED_FIELD_COUNT;
84       silm->addr_exhausted_template_id = fr->template_id;
85     }
86   else if (event == NAT44_SESSION_CREATE)
87     {
88       field_count = NAT44_SESSION_CREATE_FIELD_COUNT;
89       silm->nat44_session_template_id = fr->template_id;
90     }
91
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);
97
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);
105
106   ip->ip_version_and_header_length = 0x45;
107   ip->ttl = 254;
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));
114
115   /* FIXUP: message header export_time */
116   h->domain_id = clib_host_to_net_u32 (stream->domain_id);
117
118   /* Add TLVs to the template */
119   if (event == NAT_ADDRESSES_EXHAUTED)
120     {
121       f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
122       f++;
123       f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
124       f++;
125       f->e_id_length = ipfix_e_id_length (0, natPoolId, 4);
126       f++;
127     }
128   else if (event == NAT44_SESSION_CREATE)
129     {
130       f->e_id_length = ipfix_e_id_length (0, observationTimeMilliseconds, 8);
131       f++;
132       f->e_id_length = ipfix_e_id_length (0, natEvent, 1);
133       f++;
134       f->e_id_length = ipfix_e_id_length (0, sourceIPv4Address, 4);
135       f++;
136       f->e_id_length = ipfix_e_id_length (0, postNATSourceIPv4Address, 4);
137       f++;
138       f->e_id_length = ipfix_e_id_length (0, protocolIdentifier, 1);
139       f++;
140       f->e_id_length = ipfix_e_id_length (0, sourceTransportPort, 2);
141       f++;
142       f->e_id_length = ipfix_e_id_length (0, postNAPTSourceTransportPort, 2);
143       f++;
144       f->e_id_length = ipfix_e_id_length (0, ingressVRFID, 4);
145       f++;
146     }
147
148   /* Back to the template packet... */
149   ip = (ip4_header_t *) & tp->ip4;
150   udp = (udp_header_t *) (ip + 1);
151
152   ASSERT (f - first_field);
153   /* Field count in this template */
154   t->id_count = ipfix_id_count (fr->template_id, f - first_field);
155
156   /* set length in octets */
157   s->set_id_length =
158     ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
159
160   /* message length in octets */
161   h->version_length = version_length ((u8 *) f - (u8 *) h);
162
163   ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
164   ip->checksum = ip4_header_checksum (ip);
165
166   return rewrite;
167 }
168
169 u8 *
170 snat_template_rewrite_addr_exhausted (flow_report_main_t * frm,
171                                       flow_report_t * fr,
172                                       ip4_address_t * collector_address,
173                                       ip4_address_t * src_address,
174                                       u16 collector_port)
175 {
176   return snat_template_rewrite (frm, fr, collector_address, src_address,
177                                 collector_port, NAT_ADDRESSES_EXHAUTED);
178 }
179
180 u8 *
181 snat_template_rewrite_nat44_session (flow_report_main_t * frm,
182                                      flow_report_t * fr,
183                                      ip4_address_t * collector_address,
184                                      ip4_address_t * src_address,
185                                      u16 collector_port)
186 {
187   return snat_template_rewrite (frm, fr, collector_address, src_address,
188                                 collector_port, NAT44_SESSION_CREATE);
189 }
190
191 static inline void
192 snat_ipfix_header_create (flow_report_main_t * frm,
193                           vlib_buffer_t * b0,
194                           u32 * offset)
195 {
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;
201   ip4_header_t * ip;
202   udp_header_t * udp;
203  
204   stream = &frm->streams[silm->stream_index];
205
206   b0->current_data = 0;
207   b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) +
208                        sizeof (*s);
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);
217
218   ip->ip_version_and_header_length = 0x45;
219   ip->ttl = 254;
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);
226   udp->checksum = 0;
227
228   h->export_time = clib_host_to_net_u32 (
229     (u32) (((f64)frm->unix_time_0) + (vlib_time_now(frm->vlib_main) -
230     frm->vlib_time_0)));
231   h->sequence_number = clib_host_to_net_u32 (stream->sequence_number++);
232   h->domain_id = clib_host_to_net_u32 (stream->domain_id);
233
234   *offset = (u32) (((u8 *)(s+1)) - (u8 *)tp);
235 }
236
237 static inline void
238 snat_ipfix_send (flow_report_main_t * frm,
239                  vlib_frame_t * f,
240                  vlib_buffer_t * b0,
241                  u16 template_id)
242 {
243   ip4_ipfix_template_packet_t * tp;
244   ipfix_message_header_t * h = 0;
245   ipfix_set_header_t * s = 0;
246   ip4_header_t * ip;
247   udp_header_t * udp;
248   vlib_main_t * vm = frm->vlib_main;
249
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);
255
256   s->set_id_length = ipfix_set_id_length (template_id,
257                                           b0->current_length -
258                                           (sizeof (*ip) + sizeof (*udp) +
259                                            sizeof (*h)));
260   h->version_length = version_length (b0->current_length -
261                                       (sizeof (*ip) + sizeof (*udp)));
262
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));
266
267   if (frm->udp_checksum)
268     {
269       udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
270       if (udp->checksum == 0)
271         udp->checksum = 0xffff;
272     }
273
274   ASSERT (ip->checksum == ip4_header_checksum (ip));
275
276   vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
277 }
278
279 static void
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)
283 {
284   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
285   flow_report_main_t *frm = &flow_report_main;
286   vlib_frame_t *f;
287   vlib_buffer_t *b0 = 0;
288   u32 bi0 = ~0;
289   u32 offset;
290   vlib_main_t * vm = frm->vlib_main;
291   u64 now;
292   vlib_buffer_free_list_t *fl;
293   u8 proto = ~0;
294
295   if (!silm->enabled)
296     return;
297
298   proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : proto;
299   proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : proto;
300   proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : proto;
301
302   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
303   now += silm->milisecond_time_0;
304
305   b0 = silm->nat44_session_buffer;
306
307   if (PREDICT_FALSE (b0 == 0))
308     {
309       if (do_flush)
310         return;
311
312       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
313         {
314           clib_warning ("can't allocate buffer for NAT IPFIX event");
315           return;
316         }
317
318       b0 = silm->nat44_session_buffer =
319         vlib_get_buffer (vm, bi0);
320       fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
321       vlib_buffer_init_for_free_list (b0, fl);
322       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
323       offset = 0;
324     }
325   else
326     {
327       bi0 = vlib_get_buffer_index (vm, b0);
328       offset = silm->nat44_session_next_record_offset;
329     }
330
331   f = silm->nat44_session_frame;
332   if (PREDICT_FALSE (f == 0))
333     {
334       u32 * to_next;
335       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
336       silm->nat44_session_frame = f;
337       to_next = vlib_frame_vector_args (f);
338       to_next[0] = bi0;
339       f->n_vectors = 1;
340     }
341
342   if (PREDICT_FALSE (offset == 0))
343     snat_ipfix_header_create (frm, b0, &offset);
344
345   if (PREDICT_TRUE (do_flush == 0))
346     {
347       u64 time_stamp = clib_host_to_net_u64 (now);
348       clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
349       offset += sizeof (time_stamp);
350
351       clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
352       offset += sizeof (nat_event);
353
354       clib_memcpy (b0->data + offset, &src_ip, sizeof (src_ip));
355       offset += sizeof (src_ip);
356
357       clib_memcpy (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip));
358       offset += sizeof (nat_src_ip);
359
360       clib_memcpy (b0->data + offset, &proto, sizeof (proto));
361       offset += sizeof (proto);
362
363       clib_memcpy (b0->data + offset, &src_port, sizeof (src_port));
364       offset += sizeof (src_port);
365
366       clib_memcpy (b0->data + offset, &nat_src_port, sizeof (nat_src_port));
367       offset += sizeof (nat_src_port);
368
369       clib_memcpy (b0->data + offset, &vrf_id, sizeof(vrf_id));
370       offset += sizeof (vrf_id);
371
372       b0->current_length += NAT44_SESSION_CREATE_LEN;
373     }
374
375   if (PREDICT_FALSE (do_flush || (offset + NAT44_SESSION_CREATE_LEN) > frm->path_mtu))
376     {
377       snat_ipfix_send (frm, f, b0, silm->nat44_session_template_id);
378       silm->nat44_session_frame = 0;
379       silm->nat44_session_buffer = 0;
380       offset = 0;
381     }
382   silm->nat44_session_next_record_offset = offset;
383  }
384
385 static void
386 snat_ipfix_logging_addr_exhausted (u32 pool_id, int do_flush)
387 {
388   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
389   flow_report_main_t *frm = &flow_report_main;
390   vlib_frame_t *f;
391   vlib_buffer_t *b0 = 0;
392   u32 bi0 = ~0;
393   u32 offset;
394   vlib_main_t * vm = frm->vlib_main;
395   u64 now;
396   vlib_buffer_free_list_t *fl;
397   u8 nat_event = NAT_ADDRESSES_EXHAUTED;
398
399   if (!silm->enabled)
400     return;
401
402   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
403   now += silm->milisecond_time_0;
404
405   b0 = silm->addr_exhausted_buffer;
406
407   if (PREDICT_FALSE (b0 == 0))
408     {
409       if (do_flush)
410         return;
411
412       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
413         {
414           clib_warning ("can't allocate buffer for NAT IPFIX event");
415           return;
416         }
417
418       b0 = silm->addr_exhausted_buffer =
419         vlib_get_buffer (vm, bi0);
420       fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
421       vlib_buffer_init_for_free_list (b0, fl);
422       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
423       offset = 0;
424     }
425   else
426     {
427       bi0 = vlib_get_buffer_index (vm, b0);
428       offset = silm->addr_exhausted_next_record_offset;
429     }
430
431   f = silm->addr_exhausted_frame;
432   if (PREDICT_FALSE (f == 0))
433     {
434       u32 * to_next;
435       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
436       silm->addr_exhausted_frame = f;
437       to_next = vlib_frame_vector_args (f);
438       to_next[0] = bi0;
439       f->n_vectors = 1;
440     }
441
442   if (PREDICT_FALSE (offset == 0))
443     snat_ipfix_header_create (frm, b0, &offset);
444
445   if (PREDICT_TRUE (do_flush == 0))
446     {
447       u64 time_stamp = clib_host_to_net_u64 (now);
448       clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
449       offset += sizeof (time_stamp);
450
451       clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
452       offset += sizeof (nat_event);
453
454       clib_memcpy (b0->data + offset, &pool_id, sizeof(pool_id));
455       offset += sizeof (pool_id);
456
457       b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN;
458     }
459
460   if (PREDICT_FALSE (do_flush || (offset + NAT_ADDRESSES_EXHAUTED_LEN) > frm->path_mtu))
461     {
462       snat_ipfix_send (frm, f, b0, silm->addr_exhausted_template_id);
463       silm->addr_exhausted_frame = 0;
464       silm->addr_exhausted_buffer = 0;
465       offset = 0;
466     }
467   silm->addr_exhausted_next_record_offset = offset;
468  }
469
470 static void
471 snat_ipfix_logging_nat44_ses_rpc_cb (snat_ipfix_logging_nat44_ses_args_t *a)
472 {
473   snat_ipfix_logging_nat44_ses(a->nat_event, a->src_ip, a->nat_src_ip,
474                                a->snat_proto, a->src_port, a->nat_src_port,
475                                a->vrf_id, 0);
476 }
477
478 /**
479  * @brief Generate NAT44 session create event
480  *
481  * @param src_ip       source IPv4 address
482  * @param nat_src_ip   transaltes source IPv4 address
483  * @param snat_proto   SNAT transport protocol
484  * @param src_port     source port
485  * @param nat_src_port translated source port
486  * @param vrf_id       VRF ID
487  */
488 void
489 snat_ipfix_logging_nat44_ses_create (u32 src_ip,
490                                      u32 nat_src_ip,
491                                      snat_protocol_t snat_proto,
492                                      u16 src_port,
493                                      u16 nat_src_port,
494                                      u32 vrf_id)
495 {
496   snat_ipfix_logging_nat44_ses_args_t a;
497
498   a.nat_event = NAT44_SESSION_CREATE;
499   a.src_ip = src_ip;
500   a.nat_src_ip = nat_src_ip;
501   a.snat_proto = snat_proto;
502   a.src_port = src_port;
503   a.nat_src_port = nat_src_port;
504   a.vrf_id = vrf_id;
505
506   vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a,
507                                sizeof (a));
508 }
509
510 /**
511  * @brief Generate NAT44 session delete event
512  *
513  * @param src_ip       source IPv4 address
514  * @param nat_src_ip   transaltes source IPv4 address
515  * @param snat_proto   SNAT transport protocol
516  * @param src_port     source port
517  * @param nat_src_port translated source port
518  * @param vrf_id       VRF ID
519  */
520 void
521 snat_ipfix_logging_nat44_ses_delete (u32 src_ip,
522                                      u32 nat_src_ip,
523                                      snat_protocol_t snat_proto,
524                                      u16 src_port,
525                                      u16 nat_src_port,
526                                      u32 vrf_id)
527 {
528   snat_ipfix_logging_nat44_ses_args_t a;
529
530   a.nat_event = NAT44_SESSION_DELETE;
531   a.src_ip = src_ip;
532   a.nat_src_ip = nat_src_ip;
533   a.snat_proto = snat_proto;
534   a.src_port = src_port;
535   a.nat_src_port = nat_src_port;
536   a.vrf_id = vrf_id;
537
538   vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a,
539                                sizeof (a));
540 }
541
542 vlib_frame_t *
543 snat_data_callback_nat44_session (flow_report_main_t * frm,
544                                   flow_report_t * fr,
545                                   vlib_frame_t * f,
546                                   u32 * to_next,
547                                   u32 node_index)
548 {
549   snat_ipfix_logging_nat44_ses(0, 0, 0, 0, 0, 0, 0, 1);
550   return f;
551 }
552
553 static void
554 snat_ipfix_logging_addr_exhausted_rpc_cb
555  (snat_ipfix_logging_addr_exhausted_args_t * a)
556 {
557   snat_ipfix_logging_addr_exhausted(a->pool_id, 0);
558 }
559
560 /**
561  * @brief Generate NAT addresses exhausted event
562  *
563  * @param pool_id NAT pool ID
564  */
565 void
566 snat_ipfix_logging_addresses_exhausted(u32 pool_id)
567 {
568   //TODO: This event SHOULD be rate limited
569   snat_ipfix_logging_addr_exhausted_args_t a;
570
571   a.pool_id = pool_id;
572
573   vl_api_rpc_call_main_thread (snat_ipfix_logging_addr_exhausted_rpc_cb,
574                                (u8 *) &a, sizeof (a));
575 }
576
577 vlib_frame_t *
578 snat_data_callback_addr_exhausted (flow_report_main_t * frm,
579                                    flow_report_t * fr,
580                                    vlib_frame_t * f,
581                                    u32 * to_next,
582                                    u32 node_index)
583 {
584   snat_ipfix_logging_addr_exhausted(0, 1);
585   return f;
586 }
587
588 /**
589  * @brief Enable/disable SNAT IPFIX logging
590  *
591  * @param enable    1 if enable, 0 if disable
592  * @param domain_id observation domain ID
593  * @param src_port  source port number
594  *
595  * @returns 0 if success
596  */
597 int
598 snat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port)
599 {
600   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
601   flow_report_main_t *frm = &flow_report_main;
602   vnet_flow_report_add_del_args_t a;
603   int rv;
604   u8 e = enable ? 1 : 0;
605
606   if (silm->enabled == e)
607     return 0;
608
609   silm->enabled = e;
610
611   memset (&a, 0, sizeof (a));
612   a.rewrite_callback = snat_template_rewrite_nat44_session;
613   a.flow_data_callback = snat_data_callback_nat44_session;
614   a.is_add = enable;
615   a.domain_id = domain_id ? domain_id : 1;
616   a.src_port = src_port ? src_port : UDP_DST_PORT_ipfix;
617
618   rv = vnet_flow_report_add_del (frm, &a);
619   if (rv)
620     {
621       clib_warning ("vnet_flow_report_add_del returned %d", rv);
622       return -1;
623     }
624
625   a.rewrite_callback = snat_template_rewrite_addr_exhausted;
626   a.flow_data_callback = snat_data_callback_addr_exhausted;
627
628   rv = vnet_flow_report_add_del (frm, &a);
629   if (rv)
630     {
631       clib_warning ("vnet_flow_report_add_del returned %d", rv);
632       return -1;
633     }
634
635   return 0;
636 }
637
638 /**
639  * @brief Initialize SNAT IPFIX logging
640  *
641  * @param vm vlib main
642  */
643 void
644 snat_ipfix_logging_init (vlib_main_t * vm)
645 {
646   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
647
648   silm->enabled = 0;
649
650   /* Set up time reference pair */
651   silm->vlib_time_0 = vlib_time_now (vm);
652   silm->milisecond_time_0 = unix_time_now_nsec () * 1e-6;
653 }