9f1abb7d9f47ce16228485a867194c9f1ad0d218
[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_to_ip_proto (snat_proto);
299
300   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
301   now += silm->milisecond_time_0;
302
303   b0 = silm->nat44_session_buffer;
304
305   if (PREDICT_FALSE (b0 == 0))
306     {
307       if (do_flush)
308         return;
309
310       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
311         {
312           clib_warning ("can't allocate buffer for NAT IPFIX event");
313           return;
314         }
315
316       b0 = silm->nat44_session_buffer =
317         vlib_get_buffer (vm, bi0);
318       fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
319       vlib_buffer_init_for_free_list (b0, fl);
320       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
321       offset = 0;
322     }
323   else
324     {
325       bi0 = vlib_get_buffer_index (vm, b0);
326       offset = silm->nat44_session_next_record_offset;
327     }
328
329   f = silm->nat44_session_frame;
330   if (PREDICT_FALSE (f == 0))
331     {
332       u32 * to_next;
333       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
334       silm->nat44_session_frame = f;
335       to_next = vlib_frame_vector_args (f);
336       to_next[0] = bi0;
337       f->n_vectors = 1;
338     }
339
340   if (PREDICT_FALSE (offset == 0))
341     snat_ipfix_header_create (frm, b0, &offset);
342
343   if (PREDICT_TRUE (do_flush == 0))
344     {
345       u64 time_stamp = clib_host_to_net_u64 (now);
346       clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
347       offset += sizeof (time_stamp);
348
349       clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
350       offset += sizeof (nat_event);
351
352       clib_memcpy (b0->data + offset, &src_ip, sizeof (src_ip));
353       offset += sizeof (src_ip);
354
355       clib_memcpy (b0->data + offset, &nat_src_ip, sizeof (nat_src_ip));
356       offset += sizeof (nat_src_ip);
357
358       clib_memcpy (b0->data + offset, &proto, sizeof (proto));
359       offset += sizeof (proto);
360
361       clib_memcpy (b0->data + offset, &src_port, sizeof (src_port));
362       offset += sizeof (src_port);
363
364       clib_memcpy (b0->data + offset, &nat_src_port, sizeof (nat_src_port));
365       offset += sizeof (nat_src_port);
366
367       clib_memcpy (b0->data + offset, &vrf_id, sizeof(vrf_id));
368       offset += sizeof (vrf_id);
369
370       b0->current_length += NAT44_SESSION_CREATE_LEN;
371     }
372
373   if (PREDICT_FALSE (do_flush || (offset + NAT44_SESSION_CREATE_LEN) > frm->path_mtu))
374     {
375       snat_ipfix_send (frm, f, b0, silm->nat44_session_template_id);
376       silm->nat44_session_frame = 0;
377       silm->nat44_session_buffer = 0;
378       offset = 0;
379     }
380   silm->nat44_session_next_record_offset = offset;
381  }
382
383 static void
384 snat_ipfix_logging_addr_exhausted (u32 pool_id, int do_flush)
385 {
386   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
387   flow_report_main_t *frm = &flow_report_main;
388   vlib_frame_t *f;
389   vlib_buffer_t *b0 = 0;
390   u32 bi0 = ~0;
391   u32 offset;
392   vlib_main_t * vm = frm->vlib_main;
393   u64 now;
394   vlib_buffer_free_list_t *fl;
395   u8 nat_event = NAT_ADDRESSES_EXHAUTED;
396
397   if (!silm->enabled)
398     return;
399
400   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
401   now += silm->milisecond_time_0;
402
403   b0 = silm->addr_exhausted_buffer;
404
405   if (PREDICT_FALSE (b0 == 0))
406     {
407       if (do_flush)
408         return;
409
410       if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
411         {
412           clib_warning ("can't allocate buffer for NAT IPFIX event");
413           return;
414         }
415
416       b0 = silm->addr_exhausted_buffer =
417         vlib_get_buffer (vm, bi0);
418       fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
419       vlib_buffer_init_for_free_list (b0, fl);
420       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
421       offset = 0;
422     }
423   else
424     {
425       bi0 = vlib_get_buffer_index (vm, b0);
426       offset = silm->addr_exhausted_next_record_offset;
427     }
428
429   f = silm->addr_exhausted_frame;
430   if (PREDICT_FALSE (f == 0))
431     {
432       u32 * to_next;
433       f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
434       silm->addr_exhausted_frame = f;
435       to_next = vlib_frame_vector_args (f);
436       to_next[0] = bi0;
437       f->n_vectors = 1;
438     }
439
440   if (PREDICT_FALSE (offset == 0))
441     snat_ipfix_header_create (frm, b0, &offset);
442
443   if (PREDICT_TRUE (do_flush == 0))
444     {
445       u64 time_stamp = clib_host_to_net_u64 (now);
446       clib_memcpy (b0->data + offset, &time_stamp, sizeof (time_stamp));
447       offset += sizeof (time_stamp);
448
449       clib_memcpy (b0->data + offset, &nat_event, sizeof (nat_event));
450       offset += sizeof (nat_event);
451
452       clib_memcpy (b0->data + offset, &pool_id, sizeof(pool_id));
453       offset += sizeof (pool_id);
454
455       b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN;
456     }
457
458   if (PREDICT_FALSE (do_flush || (offset + NAT_ADDRESSES_EXHAUTED_LEN) > frm->path_mtu))
459     {
460       snat_ipfix_send (frm, f, b0, silm->addr_exhausted_template_id);
461       silm->addr_exhausted_frame = 0;
462       silm->addr_exhausted_buffer = 0;
463       offset = 0;
464     }
465   silm->addr_exhausted_next_record_offset = offset;
466  }
467
468 static void
469 snat_ipfix_logging_nat44_ses_rpc_cb (snat_ipfix_logging_nat44_ses_args_t *a)
470 {
471   snat_ipfix_logging_nat44_ses(a->nat_event, a->src_ip, a->nat_src_ip,
472                                a->snat_proto, a->src_port, a->nat_src_port,
473                                a->vrf_id, 0);
474 }
475
476 /**
477  * @brief Generate NAT44 session create event
478  *
479  * @param src_ip       source IPv4 address
480  * @param nat_src_ip   transaltes source IPv4 address
481  * @param snat_proto   SNAT transport protocol
482  * @param src_port     source port
483  * @param nat_src_port translated source port
484  * @param vrf_id       VRF ID
485  */
486 void
487 snat_ipfix_logging_nat44_ses_create (u32 src_ip,
488                                      u32 nat_src_ip,
489                                      snat_protocol_t snat_proto,
490                                      u16 src_port,
491                                      u16 nat_src_port,
492                                      u32 vrf_id)
493 {
494   snat_ipfix_logging_nat44_ses_args_t a;
495
496   a.nat_event = NAT44_SESSION_CREATE;
497   a.src_ip = src_ip;
498   a.nat_src_ip = nat_src_ip;
499   a.snat_proto = snat_proto;
500   a.src_port = src_port;
501   a.nat_src_port = nat_src_port;
502   a.vrf_id = vrf_id;
503
504   vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a,
505                                sizeof (a));
506 }
507
508 /**
509  * @brief Generate NAT44 session delete event
510  *
511  * @param src_ip       source IPv4 address
512  * @param nat_src_ip   transaltes source IPv4 address
513  * @param snat_proto   SNAT transport protocol
514  * @param src_port     source port
515  * @param nat_src_port translated source port
516  * @param vrf_id       VRF ID
517  */
518 void
519 snat_ipfix_logging_nat44_ses_delete (u32 src_ip,
520                                      u32 nat_src_ip,
521                                      snat_protocol_t snat_proto,
522                                      u16 src_port,
523                                      u16 nat_src_port,
524                                      u32 vrf_id)
525 {
526   snat_ipfix_logging_nat44_ses_args_t a;
527
528   a.nat_event = NAT44_SESSION_DELETE;
529   a.src_ip = src_ip;
530   a.nat_src_ip = nat_src_ip;
531   a.snat_proto = snat_proto;
532   a.src_port = src_port;
533   a.nat_src_port = nat_src_port;
534   a.vrf_id = vrf_id;
535
536   vl_api_rpc_call_main_thread (snat_ipfix_logging_nat44_ses_rpc_cb, (u8 *) &a,
537                                sizeof (a));
538 }
539
540 vlib_frame_t *
541 snat_data_callback_nat44_session (flow_report_main_t * frm,
542                                   flow_report_t * fr,
543                                   vlib_frame_t * f,
544                                   u32 * to_next,
545                                   u32 node_index)
546 {
547   snat_ipfix_logging_nat44_ses(0, 0, 0, 0, 0, 0, 0, 1);
548   return f;
549 }
550
551 static void
552 snat_ipfix_logging_addr_exhausted_rpc_cb
553  (snat_ipfix_logging_addr_exhausted_args_t * a)
554 {
555   snat_ipfix_logging_addr_exhausted(a->pool_id, 0);
556 }
557
558 /**
559  * @brief Generate NAT addresses exhausted event
560  *
561  * @param pool_id NAT pool ID
562  */
563 void
564 snat_ipfix_logging_addresses_exhausted(u32 pool_id)
565 {
566   //TODO: This event SHOULD be rate limited
567   snat_ipfix_logging_addr_exhausted_args_t a;
568
569   a.pool_id = pool_id;
570
571   vl_api_rpc_call_main_thread (snat_ipfix_logging_addr_exhausted_rpc_cb,
572                                (u8 *) &a, sizeof (a));
573 }
574
575 vlib_frame_t *
576 snat_data_callback_addr_exhausted (flow_report_main_t * frm,
577                                    flow_report_t * fr,
578                                    vlib_frame_t * f,
579                                    u32 * to_next,
580                                    u32 node_index)
581 {
582   snat_ipfix_logging_addr_exhausted(0, 1);
583   return f;
584 }
585
586 /**
587  * @brief Enable/disable SNAT IPFIX logging
588  *
589  * @param enable    1 if enable, 0 if disable
590  * @param domain_id observation domain ID
591  * @param src_port  source port number
592  *
593  * @returns 0 if success
594  */
595 int
596 snat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port)
597 {
598   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
599   flow_report_main_t *frm = &flow_report_main;
600   vnet_flow_report_add_del_args_t a;
601   int rv;
602   u8 e = enable ? 1 : 0;
603
604   if (silm->enabled == e)
605     return 0;
606
607   silm->enabled = e;
608
609   memset (&a, 0, sizeof (a));
610   a.rewrite_callback = snat_template_rewrite_nat44_session;
611   a.flow_data_callback = snat_data_callback_nat44_session;
612   a.is_add = enable;
613   a.domain_id = domain_id ? domain_id : 1;
614   a.src_port = src_port ? src_port : UDP_DST_PORT_ipfix;
615
616   rv = vnet_flow_report_add_del (frm, &a);
617   if (rv)
618     {
619       clib_warning ("vnet_flow_report_add_del returned %d", rv);
620       return -1;
621     }
622
623   a.rewrite_callback = snat_template_rewrite_addr_exhausted;
624   a.flow_data_callback = snat_data_callback_addr_exhausted;
625
626   rv = vnet_flow_report_add_del (frm, &a);
627   if (rv)
628     {
629       clib_warning ("vnet_flow_report_add_del returned %d", rv);
630       return -1;
631     }
632
633   return 0;
634 }
635
636 /**
637  * @brief Initialize SNAT IPFIX logging
638  *
639  * @param vm vlib main
640  */
641 void
642 snat_ipfix_logging_init (vlib_main_t * vm)
643 {
644   snat_ipfix_logging_main_t *silm = &snat_ipfix_logging_main;
645
646   silm->enabled = 0;
647
648   /* Set up time reference pair */
649   silm->vlib_time_0 = vlib_time_now (vm);
650   silm->milisecond_time_0 = unix_time_now_nsec () * 1e-6;
651 }