NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
telemetry_exporter.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021-2023 NVIDIA CORPORATION AND AFFILIATES. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are permitted
5  * provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice, this list of
7  * conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright notice, this list of
9  * conditions and the following disclaimer in the documentation and/or other materials
10  * provided with the distribution.
11  * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
12  * to endorse or promote products derived from this software without specific prior written
13  * permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21  * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  */
25 
26 #include <netdb.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <ctype.h>
30 #include <sys/queue.h>
31 #include <unistd.h>
32 #include <linux/types.h>
33 
34 #include <rte_string_fns.h>
35 
36 #include <doca_log.h>
37 
38 #include "telemetry_exporter.h"
39 #include "utils.h"
40 
41 DOCA_LOG_REGISTER(NETFLOW_TELEMETRY);
42 
43 /* Queues to hold the telemetry data until sent */
44 static struct rte_ring *netflow_pending_ring, *netflow_freelist_ring;
45 
46 /* Netflow records queues */
47 static struct doca_telemetry_exporter_netflow_record data_to_send[NETFLOW_QUEUE_SIZE];
48 static struct doca_telemetry_exporter_netflow_record *data_to_send_ptr[NETFLOW_QUEUE_SIZE];
49 
50 static struct doca_telemetry_exporter_netflow_template *netflow_template; /* Netflow template */
51 
52 /*
53  * Add new Netflow field to the Netflow template
54  *
55  * @type [in]: Netflow field type
56  * @length [in]: Netflow field length
57  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
58  */
59 static doca_error_t add_netflow_field(uint16_t type, uint16_t length)
60 {
61  struct doca_telemetry_exporter_netflow_flowset_field *field;
63 
65  if (result != DOCA_SUCCESS)
66  return result;
69 
71  if (result != DOCA_SUCCESS)
73  return result;
74 }
75 
76 /*
77  * Initialize Netflow template by adding all fields
78  *
79  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
80  */
82 {
84 
131  if (result != DOCA_SUCCESS)
132  return DOCA_ERROR_NO_MEMORY;
133 
134  return DOCA_SUCCESS;
135 }
136 
137 /*
138  * Get host name to be tagged with the telemetry data
139  *
140  * @host_name [out]: host name
141  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
142  */
143 static doca_error_t get_hostname_ip(char *host_name)
144 {
146  char host[256];
147  struct hostent *host_entry = NULL;
148 
149  /* Find the host name */
150  if (gethostname(host, sizeof(host)) < 0) {
151  switch (errno) {
152  case EPERM:
154  break;
155  default:
157  break;
158  }
159  DOCA_LOG_ERR("Gethostname failed");
160  return result;
161  }
162  /* Find host information */
163  host_entry = gethostbyname(host);
164  if (host_entry == NULL)
165  strlcpy(host_name, host, 64);
166  else
167  strlcpy(host_name, host_entry->h_name, 64);
168 
169  DOCA_LOG_TRC("Host name: %s", host_name);
170  return result;
171 }
172 
174 {
176  size_t records_to_send = 0;
177  size_t records_sent = 0;
178  size_t records_successfully_sent;
179  int ring_count = rte_ring_count(netflow_pending_ring);
180  static struct doca_telemetry_exporter_netflow_record *records[NETFLOW_QUEUE_SIZE];
181  /*
182  * Sending the record array
183  * The while loop ensure that all records have been sent, in case just some are sent.
184  * This section should happen periodically with updated the flows.
185  */
186  if (ring_count == 0)
187  return 0;
188  /* We need to dequeue only the records that were enqueued with the allocated memory */
189  records_to_send = rte_ring_dequeue_bulk(netflow_pending_ring, (void **)records, ring_count, NULL);
190  while (records_sent < records_to_send) {
192  (const void **)(records + records_sent),
193  records_to_send - records_sent,
194  &records_successfully_sent);
195  if (result != DOCA_SUCCESS) {
196  DOCA_LOG_ERR("Failed to send Netflow, error=%d", result);
197  return result;
198  }
199  records_sent += records_successfully_sent;
200  }
201  /* Flushing the buffer sends it to the collector */
203  DOCA_LOG_TRC("Successfully sent %lu netflow records with default template", records_sent);
204  if ((size_t)rte_ring_enqueue_bulk(netflow_freelist_ring, (void **)records, records_sent, NULL) !=
205  records_sent) {
206  DOCA_LOG_ERR("Placeholder queue mismatch");
207  return DOCA_ERROR_DRIVER;
208  }
209  return DOCA_SUCCESS;
210 }
211 
212 void enqueue_netflow_record_to_ring(const struct doca_telemetry_exporter_netflow_record *record)
213 {
214  struct doca_telemetry_exporter_netflow_record *tmp_record;
215  /* To avoid memory corruption when flows are destroyed, we copy the pointers to a
216  * preallocated pointer inside freelist ring and enqueue it so the main thread
217  * can send them.
218  */
219  if (rte_ring_mc_dequeue(netflow_freelist_ring, (void **)&tmp_record) != 0) {
220  DOCA_LOG_DBG("Placeholder queue is empty");
221  return;
222  }
223  *tmp_record = *record;
224  if (rte_ring_mp_enqueue(netflow_pending_ring, tmp_record) != 0) {
225  DOCA_LOG_DBG("Netflow queue is full");
226  return;
227  }
228 }
229 
231 {
232  rte_ring_free(netflow_pending_ring);
233  rte_ring_free(netflow_freelist_ring);
234 
236 }
237 
238 doca_error_t init_netflow_schema_and_source(uint8_t id, char *source_tag)
239 {
241  int i;
242  char hostname[64];
243  char *bluefield_rshim = "192.168.100.1";
244 
246  if (result != DOCA_SUCCESS)
247  return result;
248 
250  if (result != DOCA_SUCCESS)
251  return result;
252 
254  if (result != DOCA_SUCCESS) {
255  DOCA_LOG_ERR("Cannot init DOCA netflow");
256  return result;
257  }
258 
260 
261  /* Setting the Netflow collector is recommended for debugging only - use DTS otherwise,
262  * Default PORT is 2055
263  */
265 
266  result = get_hostname_ip(hostname);
267  if (result != DOCA_SUCCESS) {
268  DOCA_LOG_ERR("Getting hostname failed");
270  return result;
271  }
272 
275 
277  if (result != DOCA_SUCCESS) {
278  DOCA_LOG_ERR("Cannot start DOCA netflow");
280  return result;
281  }
282  /* In the Netflow ring scenario, a producer-consumer solution is given where the dpi_worker threads produce
283  * records and enqueues them to a rings struct. The records are consumed by the main thread that dequeues
284  * the records and sends them. This allows avoiding collisions between thread and memory corruption issues.
285  */
286  netflow_pending_ring = rte_ring_create("netflow_queue", NETFLOW_QUEUE_SIZE, SOCKET_ID_ANY, RING_F_SC_DEQ);
288  rte_ring_create("placeholder_netflow_queue", NETFLOW_QUEUE_SIZE, SOCKET_ID_ANY, RING_F_SP_ENQ);
291  return DOCA_ERROR_NO_MEMORY;
292  }
293  for (i = 0; i < NETFLOW_QUEUE_SIZE; i++)
295  if (rte_ring_enqueue_bulk(netflow_freelist_ring, (void **)data_to_send_ptr, NETFLOW_QUEUE_SIZE - 1, NULL) !=
296  NETFLOW_QUEUE_SIZE - 1) {
298  return DOCA_ERROR_NO_MEMORY;
299  }
300 
301  return DOCA_SUCCESS;
302 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IN_BYTES
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_L4_DST_PORT_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_LAST_SWITCHED_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV6_SRC_ADDR_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_DST_AS
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_PROTOCOL
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV6_DST_ADDR
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_SRC_TOS
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IN_BYTES_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_INPUT_SNMP_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_OUTPUT_SNMP_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_FIRST_SWITCHED
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_SRC_AS
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_L4_SRC_PORT
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_APPLICATION_NAME_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_APPLICATION_NAME
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_FIRST_SWITCHED_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_DST_MASK_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV4_SRC_ADDR
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV4_SRC_ADDR_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_CONNECTION_TRANSACTION_ID
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IN_PKTS_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_L4_DST_PORT
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_DST_MASK
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV4_NEXT_HOP
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_PROTOCOL_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV6_NEXT_HOP
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_SRC_MASK_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_SRC_MASK
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV6_NEXT_HOP_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_TCP_FLAGS_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_OUTPUT_SNMP
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_CONNECTION_TRANSACTION_ID_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV4_DST_ADDR_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_INPUT_SNMP
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV4_DST_ADDR
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV6_DST_ADDR_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_LAST_SWITCHED
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_SRC_TOS_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV6_SRC_ADDR
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_DST_AS_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_SRC_AS_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_L4_SRC_PORT_DEFAULT_LENGTH
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IN_PKTS
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_TCP_FLAGS
#define DOCA_TELEMETRY_EXPORTER_NETFLOW_IPV4_NEXT_HOP_DEFAULT_LENGTH
enum doca_error doca_error_t
DOCA API return codes.
@ DOCA_ERROR_INVALID_VALUE
Definition: doca_error.h:44
@ DOCA_SUCCESS
Definition: doca_error.h:38
@ DOCA_ERROR_NO_MEMORY
Definition: doca_error.h:45
@ DOCA_ERROR_NOT_PERMITTED
Definition: doca_error.h:40
@ DOCA_ERROR_DRIVER
Definition: doca_error.h:59
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_TRC(format,...)
Generates a TRACE application log message.
Definition: doca_log.h:513
#define DOCA_LOG_DBG(format,...)
Generates a DEBUG application log message.
Definition: doca_log.h:496
DOCA_EXPERIMENTAL void doca_telemetry_exporter_netflow_source_set_id(const char *source_id)
Set source id.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_destroy(void)
Free the exporter memory and close the connection.
DOCA_EXPERIMENTAL void doca_telemetry_exporter_netflow_source_set_tag(const char *source_tag)
Set source tag.
DOCA_EXPERIMENTAL void doca_telemetry_exporter_netflow_field_set_len(struct doca_telemetry_exporter_netflow_flowset_field *field, uint16_t length)
Set doca telemetry netflow field length.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_send(const struct doca_telemetry_exporter_netflow_template *netflow_template, const void **records, size_t nof_records, size_t *nof_records_sent)
Sending netflow records. Need to init first.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_start(void)
Finalizes netflow setup.
DOCA_EXPERIMENTAL void doca_telemetry_exporter_netflow_set_ipc_enabled(void)
Enable IPC IPC is disabled by default.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_field_destroy(struct doca_telemetry_exporter_netflow_flowset_field *field)
Destructor for DOCA netflow field.
DOCA_EXPERIMENTAL void doca_telemetry_exporter_netflow_set_collector_addr(const char *collector_addr)
Set collector address.
DOCA_EXPERIMENTAL void doca_telemetry_exporter_netflow_field_set_type(struct doca_telemetry_exporter_netflow_flowset_field *field, uint16_t type)
Set doca telemetry netflow field type.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_template_create(struct doca_telemetry_exporter_netflow_template **netflow_template)
Create new telemetry netflow template.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_init(uint16_t source_id)
Init exporter memory, set configs and open connection.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_template_add_field(struct doca_telemetry_exporter_netflow_template *netflow_template, struct doca_telemetry_exporter_netflow_flowset_field *field)
Add DOCA telemetry netflow field to netflow_template. The user loses the ownership of the field after...
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_flush(void)
Immediately flush the data of the DOCA internal Netflow source.
DOCA_EXPERIMENTAL doca_error_t doca_telemetry_exporter_netflow_field_create(struct doca_telemetry_exporter_netflow_flowset_field **field)
Create new telemetry netflow field.
uint8_t type
Definition: packets.h:0
static struct doca_telemetry_exporter_netflow_record data_to_send[NETFLOW_QUEUE_SIZE]
doca_error_t send_netflow_record(void)
DOCA_LOG_REGISTER(NETFLOW_TELEMETRY)
void enqueue_netflow_record_to_ring(const struct doca_telemetry_exporter_netflow_record *record)
static struct doca_telemetry_exporter_netflow_template * netflow_template
static doca_error_t get_hostname_ip(char *host_name)
void destroy_netflow_schema_and_source(void)
static doca_error_t add_netflow_field(uint16_t type, uint16_t length)
static struct doca_telemetry_exporter_netflow_record * data_to_send_ptr[NETFLOW_QUEUE_SIZE]
static struct rte_ring * netflow_pending_ring
static struct rte_ring * netflow_freelist_ring
static doca_error_t init_template_fields(void)
doca_error_t init_netflow_schema_and_source(uint8_t id, char *source_tag)
#define NETFLOW_QUEUE_SIZE
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: utils.c:123